xref: /trunk/main/sw/source/core/unocore/unorefmk.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <vos/mutex.hxx>
28 #include <vcl/svapp.hxx>
29 
30 #include <unomid.h>
31 #include <unotextrange.hxx>
32 #include <unorefmark.hxx>
33 #include <unotextcursor.hxx>
34 #include <unomap.hxx>
35 #include <unocrsr.hxx>
36 #include <unoevtlstnr.hxx>
37 #include <unocrsrhelper.hxx>
38 #include <doc.hxx>
39 #include <ndtxt.hxx>
40 #include <fmtrfmrk.hxx>
41 #include <txtrfmrk.hxx>
42 #include <hints.hxx>
43 
44 
45 using namespace ::com::sun::star;
46 using ::rtl::OUString;
47 
48 /******************************************************************
49  * SwXReferenceMark
50  ******************************************************************/
51 
52 class SwXReferenceMark::Impl
53     : public SwClient
54 {
55 
56 public:
57     SwEventListenerContainer    m_ListenerContainer;
58     bool                        m_bIsDescriptor;
59     SwDoc *                     m_pDoc;
60     const SwFmtRefMark *        m_pMarkFmt;
61     ::rtl::OUString             m_sMarkName;
62 
Impl(SwXReferenceMark & rThis,SwDoc * const pDoc,SwFmtRefMark const * const pRefMark)63     Impl(   SwXReferenceMark & rThis,
64             SwDoc *const pDoc, SwFmtRefMark const*const pRefMark)
65         : SwClient((pDoc) ? pDoc->GetUnoCallBack() : 0)
66         , m_ListenerContainer(static_cast< ::cppu::OWeakObject* >(&rThis))
67         // #i111177# unxsols4 (Sun C++ 5.9 SunOS_sparc) may generate wrong code
68         , m_bIsDescriptor((0 == pRefMark) ? true : false)
69         , m_pDoc(pDoc)
70         , m_pMarkFmt(pRefMark)
71     {
72         if (pRefMark)
73         {
74             m_sMarkName = pRefMark->GetRefName();
75         }
76     }
77 
IsValid() const78     bool    IsValid() const { return 0 != GetRegisteredIn(); }
79     void    InsertRefMark( SwPaM & rPam, SwXTextCursor const*const pCursor );
80     void    Invalidate();
81 protected:
82     // SwClient
83     virtual void    Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
84 
85 };
86 
87 /* -----------------------------07.01.00 12:51--------------------------------
88 
89  ---------------------------------------------------------------------------*/
Invalidate()90 void SwXReferenceMark::Impl::Invalidate()
91 {
92     if (IsValid())
93     {
94         const_cast<SwModify*>(GetRegisteredIn())->Remove(this);
95     }
96     m_ListenerContainer.Disposing();
97     m_pDoc = 0;
98     m_pMarkFmt = 0;
99 }
100 
101 /*-- 11.12.98 10:28:37---------------------------------------------------
102 
103   -----------------------------------------------------------------------*/
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)104 void SwXReferenceMark::Impl::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
105 {
106     ClientModify(this, pOld, pNew);
107 
108     if (!GetRegisteredIn()) // removed => dispose
109     {
110         Invalidate();
111     }
112     else if (pOld)
113     {
114         switch (pOld->Which())
115         {
116             case RES_REFMARK_DELETED:
117                 if (static_cast<const void*>(m_pMarkFmt) ==
118                         static_cast<const SwPtrMsgPoolItem *>(pOld)->pObject)
119                 {
120                     Invalidate();
121                 }
122                 break;
123         }
124     }
125 }
126 
127 
128 /*-- 11.12.98 10:28:32---------------------------------------------------
129 
130   -----------------------------------------------------------------------*/
SwXReferenceMark(SwDoc * const pDoc,SwFmtRefMark const * const pRefMark)131 SwXReferenceMark::SwXReferenceMark(
132         SwDoc *const pDoc, SwFmtRefMark const*const pRefMark)
133     : m_pImpl( new SwXReferenceMark::Impl(*this, pDoc, pRefMark) )
134 {
135 }
136 
137 /*-- 11.12.98 10:28:33---------------------------------------------------
138 
139   -----------------------------------------------------------------------*/
~SwXReferenceMark()140 SwXReferenceMark::~SwXReferenceMark()
141 {
142 }
143 
144 SwXReferenceMark *
GetReferenceMark(SwModify const &,SwFmtRefMark const &)145 SwXReferenceMark::GetReferenceMark(
146         SwModify const& /*rUnoCB*/, SwFmtRefMark const& /*rMarkFmt*/)
147 {
148     // #i105557#: do not iterate over the registered clients: race condition
149     // to do this properly requires the SwXReferenceMark to register at the
150     // SwFmtRefMark directly, not at the unocallback
151     return 0;
152 }
153 
154 SwXReferenceMark *
CreateXReferenceMark(SwDoc & rDoc,SwFmtRefMark const & rMarkFmt)155 SwXReferenceMark::CreateXReferenceMark(
156         SwDoc & rDoc, SwFmtRefMark const& rMarkFmt)
157 {
158     SwXReferenceMark *const pXMark(
159         GetReferenceMark(*rDoc.GetUnoCallBack(), rMarkFmt) );
160     return (pXMark)
161         ?   pXMark
162         :   new SwXReferenceMark(&rDoc, &rMarkFmt);
163 }
164 
165 /* -----------------------------13.03.00 12:15--------------------------------
166 
167  ---------------------------------------------------------------------------*/
getUnoTunnelId()168 const uno::Sequence< sal_Int8 > & SwXReferenceMark::getUnoTunnelId()
169 {
170     static uno::Sequence< sal_Int8 > aSeq = ::CreateUnoTunnelId();
171     return aSeq;
172 }
173 /* -----------------------------10.03.00 18:04--------------------------------
174 
175  ---------------------------------------------------------------------------*/
176 sal_Int64 SAL_CALL
getSomething(const uno::Sequence<sal_Int8> & rId)177 SwXReferenceMark::getSomething(const uno::Sequence< sal_Int8 >& rId)
178 {
179     return ::sw::UnoTunnelImpl<SwXReferenceMark>(rId, this);
180 }
181 /* -----------------------------06.04.00 16:41--------------------------------
182 
183  ---------------------------------------------------------------------------*/
getImplementationName()184 OUString SAL_CALL SwXReferenceMark::getImplementationName()
185 {
186     return C2U("SwXReferenceMark");
187 }
188 /* -----------------------------06.04.00 16:41--------------------------------
189 
190  ---------------------------------------------------------------------------*/
191 static char const*const g_ServicesReferenceMark[] =
192 {
193     "com.sun.star.text.TextContent",
194     "com.sun.star.text.ReferenceMark",
195 };
196 static const size_t g_nServicesReferenceMark(
197     sizeof(g_ServicesReferenceMark)/sizeof(g_ServicesReferenceMark[0]));
198 
199 sal_Bool SAL_CALL
supportsService(const OUString & rServiceName)200 SwXReferenceMark::supportsService(const OUString& rServiceName)
201 {
202     return ::sw::SupportsServiceImpl(
203             g_nServicesReferenceMark, g_ServicesReferenceMark, rServiceName);
204 }
205 /* -----------------------------06.04.00 16:41--------------------------------
206 
207  ---------------------------------------------------------------------------*/
208 uno::Sequence< OUString > SAL_CALL
getSupportedServiceNames()209 SwXReferenceMark::getSupportedServiceNames()
210 {
211     return ::sw::GetSupportedServiceNamesImpl(
212             g_nServicesReferenceMark, g_ServicesReferenceMark);
213 }
214 
215 /* -----------------03.11.99 14:14-------------------
216 
217  --------------------------------------------------*/
218 template<typename T> struct NotContainedIn
219 {
220     ::std::vector<T> const& m_rVector;
NotContainedInNotContainedIn221     explicit NotContainedIn(::std::vector<T> const& rVector)
222         : m_rVector(rVector) { }
operator ()NotContainedIn223     bool operator() (T const& rT) {
224         return ::std::find(m_rVector.begin(), m_rVector.end(), rT)
225                     == m_rVector.end();
226     }
227 };
228 
InsertRefMark(SwPaM & rPam,SwXTextCursor const * const pCursor)229 void SwXReferenceMark::Impl::InsertRefMark(SwPaM& rPam,
230         SwXTextCursor const*const pCursor)
231 {
232     //! in some cases when this function is called the pDoc pointer member may have become
233     //! invalid/deleted thus we obtain the document pointer from rPaM where it should always
234     //! be valid.
235     SwDoc *pDoc2 = rPam.GetDoc();
236 
237     UnoActionContext aCont(pDoc2);
238     SwFmtRefMark aRefMark(m_sMarkName);
239     sal_Bool bMark = *rPam.GetPoint() != *rPam.GetMark();
240 
241     const bool bForceExpandHints( (!bMark && pCursor)
242             ? pCursor->IsAtEndOfMeta() : false );
243     const SetAttrMode nInsertFlags = (bForceExpandHints)
244         ?   ( nsSetAttrMode::SETATTR_FORCEHINTEXPAND
245             | nsSetAttrMode::SETATTR_DONTEXPAND)
246         : nsSetAttrMode::SETATTR_DONTEXPAND;
247 
248     ::std::vector<SwTxtAttr *> oldMarks;
249     if (bMark)
250     {
251         oldMarks = rPam.GetNode()->GetTxtNode()->GetTxtAttrsAt(
252             rPam.GetPoint()->nContent.GetIndex(), RES_TXTATR_REFMARK);
253     }
254 
255     pDoc2->InsertPoolItem( rPam, aRefMark, nInsertFlags );
256 
257     if( bMark && *rPam.GetPoint() > *rPam.GetMark())
258     {
259         rPam.Exchange();
260     }
261 
262     // aRefMark was copied into the document pool; now retrieve real format...
263     SwTxtAttr * pTxtAttr(0);
264     if (bMark)
265     {
266         // #i107672#
267         // ensure that we do not retrieve a different mark at the same position
268         ::std::vector<SwTxtAttr *> const newMarks(
269             rPam.GetNode()->GetTxtNode()->GetTxtAttrsAt(
270                 rPam.GetPoint()->nContent.GetIndex(), RES_TXTATR_REFMARK));
271         ::std::vector<SwTxtAttr *>::const_iterator const iter(
272             ::std::find_if(newMarks.begin(), newMarks.end(),
273                 NotContainedIn<SwTxtAttr *>(oldMarks)));
274         OSL_ASSERT(newMarks.end() != iter);
275         if (newMarks.end() != iter)
276         {
277             pTxtAttr = *iter;
278         }
279     }
280     else
281     {
282         pTxtAttr = rPam.GetNode()->GetTxtNode()->GetTxtAttrForCharAt(
283                 rPam.GetPoint()->nContent.GetIndex() - 1, RES_TXTATR_REFMARK);
284     }
285 
286     if (!pTxtAttr)
287     {
288         throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
289             "SwXReferenceMark::InsertRefMark(): cannot insert attribute")), 0);
290     }
291 
292     m_pMarkFmt = &pTxtAttr->GetRefMark();
293 
294     pDoc2->GetUnoCallBack()->Add(this);
295 }
296 
297 /*-- 11.12.98 10:28:34---------------------------------------------------
298 
299   -----------------------------------------------------------------------*/
300 void SAL_CALL
attach(const uno::Reference<text::XTextRange> & xTextRange)301 SwXReferenceMark::attach(const uno::Reference< text::XTextRange > & xTextRange)
302 {
303     vos::OGuard aGuard(Application::GetSolarMutex());
304 
305     if (!m_pImpl->m_bIsDescriptor)
306     {
307         throw uno::RuntimeException();
308     }
309     uno::Reference<lang::XUnoTunnel> xRangeTunnel( xTextRange, uno::UNO_QUERY);
310     SwXTextRange* pRange = 0;
311     OTextCursorHelper* pCursor = 0;
312     if(xRangeTunnel.is())
313     {
314         pRange = ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel);
315         pCursor =
316             ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel);
317     }
318     SwDoc *const pDocument =
319         (pRange) ? pRange->GetDoc() : ((pCursor) ? pCursor->GetDoc() : 0);
320     if (!pDocument)
321     {
322         throw lang::IllegalArgumentException();
323     }
324 
325     SwUnoInternalPaM aPam(*pDocument);
326     //das muss jetzt sal_True liefern
327     ::sw::XTextRangeToSwPaM(aPam, xTextRange);
328     m_pImpl->InsertRefMark(aPam, dynamic_cast<SwXTextCursor*>(pCursor));
329     m_pImpl->m_bIsDescriptor = sal_False;
330     m_pImpl->m_pDoc = pDocument;
331 }
332 
333 /*-- 11.12.98 10:28:34---------------------------------------------------
334 
335   -----------------------------------------------------------------------*/
336 uno::Reference< text::XTextRange > SAL_CALL
getAnchor()337 SwXReferenceMark::getAnchor()
338 {
339     vos::OGuard aGuard(Application::GetSolarMutex());
340 
341     if (m_pImpl->IsValid())
342     {
343         SwFmtRefMark const*const pNewMark =
344             m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
345         if (pNewMark && (pNewMark == m_pImpl->m_pMarkFmt))
346         {
347             SwTxtRefMark const*const pTxtMark =
348                 m_pImpl->m_pMarkFmt->GetTxtRefMark();
349             if (pTxtMark &&
350                 (&pTxtMark->GetTxtNode().GetNodes() ==
351                     &m_pImpl->m_pDoc->GetNodes()))
352             {
353                 SwTxtNode const& rTxtNode = pTxtMark->GetTxtNode();
354                 const ::std::auto_ptr<SwPaM> pPam( (pTxtMark->End())
355                     ?   new SwPaM( rTxtNode, *pTxtMark->End(),
356                                    rTxtNode, *pTxtMark->GetStart())
357                     :   new SwPaM( rTxtNode, *pTxtMark->GetStart()) );
358 
359                 return SwXTextRange::CreateXTextRange(
360                             *m_pImpl->m_pDoc, *pPam->Start(), pPam->End());
361             }
362         }
363     }
364     return 0;
365 }
366 /*-- 11.12.98 10:28:35---------------------------------------------------
367 
368   -----------------------------------------------------------------------*/
dispose()369 void SAL_CALL SwXReferenceMark::dispose()
370 {
371     vos::OGuard aGuard(Application::GetSolarMutex());
372     if (m_pImpl->IsValid())
373     {
374         SwFmtRefMark const*const pNewMark =
375             m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
376         if (pNewMark && (pNewMark == m_pImpl->m_pMarkFmt))
377         {
378             SwTxtRefMark const*const pTxtMark =
379                 m_pImpl->m_pMarkFmt->GetTxtRefMark();
380             if (pTxtMark &&
381                 (&pTxtMark->GetTxtNode().GetNodes() ==
382                     &m_pImpl->m_pDoc->GetNodes()))
383             {
384                 SwTxtNode const& rTxtNode = pTxtMark->GetTxtNode();
385                 const xub_StrLen nStt = *pTxtMark->GetStart();
386                 const xub_StrLen nEnd = pTxtMark->End()
387                                   ? *pTxtMark->End()
388                                   : nStt + 1;
389 
390                 SwPaM aPam( rTxtNode, nStt, rTxtNode, nEnd );
391                 m_pImpl->m_pDoc->DeleteAndJoin( aPam );
392             }
393         }
394     }
395     else if (m_pImpl->m_bIsDescriptor)
396     {
397         m_pImpl->Invalidate();
398     }
399 }
400 /*-- 11.12.98 10:28:35---------------------------------------------------
401 
402   -----------------------------------------------------------------------*/
addEventListener(const uno::Reference<lang::XEventListener> & xListener)403 void SAL_CALL SwXReferenceMark::addEventListener(
404         const uno::Reference< lang::XEventListener > & xListener)
405 {
406     vos::OGuard g(Application::GetSolarMutex());
407 
408     if (!m_pImpl->IsValid())
409     {
410         throw uno::RuntimeException();
411     }
412     m_pImpl->m_ListenerContainer.AddListener(xListener);
413 }
414 /*-- 11.12.98 10:28:35---------------------------------------------------
415 
416   -----------------------------------------------------------------------*/
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)417 void SAL_CALL SwXReferenceMark::removeEventListener(
418         const uno::Reference< lang::XEventListener > & xListener)
419 {
420     vos::OGuard g(Application::GetSolarMutex());
421 
422     if (!m_pImpl->IsValid() ||
423         !m_pImpl->m_ListenerContainer.RemoveListener(xListener))
424     {
425         throw uno::RuntimeException();
426     }
427 }
428 /*-- 11.12.98 10:28:36---------------------------------------------------
429 
430   -----------------------------------------------------------------------*/
getName()431 OUString SAL_CALL SwXReferenceMark::getName()
432 {
433     vos::OGuard aGuard(Application::GetSolarMutex());
434     if (!m_pImpl->IsValid() ||
435         !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName))
436     {
437         throw uno::RuntimeException();
438     }
439     return m_pImpl->m_sMarkName;
440 }
441 /*-- 11.12.98 10:28:36---------------------------------------------------
442 
443   -----------------------------------------------------------------------*/
setName(const OUString & rName)444 void SAL_CALL SwXReferenceMark::setName(const OUString& rName)
445 {
446     vos::OGuard aGuard(Application::GetSolarMutex());
447     if (m_pImpl->m_bIsDescriptor)
448     {
449         m_pImpl->m_sMarkName = rName;
450     }
451     else
452     {
453         if (!m_pImpl->IsValid()
454             || !m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName)
455             || m_pImpl->m_pDoc->GetRefMark(rName))
456         {
457             throw uno::RuntimeException();
458         }
459         SwFmtRefMark const*const pCurMark =
460             m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
461         if ((rName != m_pImpl->m_sMarkName)
462             && pCurMark && (pCurMark == m_pImpl->m_pMarkFmt))
463         {
464             const UnoActionContext aCont(m_pImpl->m_pDoc);
465             SwTxtRefMark const*const pTxtMark =
466                 m_pImpl->m_pMarkFmt->GetTxtRefMark();
467             if (pTxtMark &&
468                 (&pTxtMark->GetTxtNode().GetNodes() ==
469                      &m_pImpl->m_pDoc->GetNodes()))
470             {
471                 SwTxtNode const& rTxtNode = pTxtMark->GetTxtNode();
472                 const xub_StrLen nStt = *pTxtMark->GetStart();
473                 const xub_StrLen nEnd = pTxtMark->End()
474                                         ? *pTxtMark->End()
475                                         : nStt + 1;
476 
477                 SwPaM aPam( rTxtNode, nStt, rTxtNode, nEnd );
478                 // deletes the m_pImpl->m_pDoc member in the SwXReferenceMark!
479                 m_pImpl->m_pDoc->DeleteAndJoin( aPam );
480                 // The aPam will keep the correct and functional doc though
481 
482                 m_pImpl->m_sMarkName = rName;
483                 //create a new one
484                 m_pImpl->InsertRefMark( aPam, 0 );
485                 m_pImpl->m_pDoc = aPam.GetDoc();
486             }
487         }
488     }
489 }
490 
491 /*-- 12.09.00 12:58:20---------------------------------------------------
492 
493   -----------------------------------------------------------------------*/
494 uno::Reference< beans::XPropertySetInfo > SAL_CALL
getPropertySetInfo()495 SwXReferenceMark::getPropertySetInfo()
496 {
497     vos::OGuard g(Application::GetSolarMutex());
498 
499     static uno::Reference< beans::XPropertySetInfo >  xRef =
500         aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH_EXTENSIONS)
501             ->getPropertySetInfo();
502     return xRef;
503 }
504 /*-- 12.09.00 12:58:20---------------------------------------------------
505 
506   -----------------------------------------------------------------------*/
setPropertyValue(const OUString &,const uno::Any &)507 void SAL_CALL SwXReferenceMark::setPropertyValue(
508     const OUString& /*rPropertyName*/, const uno::Any& /*rValue*/ )
509 {
510     throw lang::IllegalArgumentException();
511 }
512 /*-- 12.09.00 12:58:20---------------------------------------------------
513 
514   -----------------------------------------------------------------------*/
515 uno::Any SAL_CALL
getPropertyValue(const OUString & rPropertyName)516 SwXReferenceMark::getPropertyValue(const OUString& rPropertyName)
517 {
518     // does not seem to need SolarMutex
519     uno::Any aRet;
520     if (! ::sw::GetDefaultTextContentValue(aRet, rPropertyName))
521     {
522         throw beans::UnknownPropertyException();
523     }
524     return aRet;
525 }
526 /*-- 12.09.00 12:58:20---------------------------------------------------
527 
528   -----------------------------------------------------------------------*/
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)529 void SAL_CALL SwXReferenceMark::addPropertyChangeListener(
530         const OUString& /*rPropertyName*/,
531         const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
532 {
533     OSL_ENSURE(false,
534         "SwXReferenceMark::addPropertyChangeListener(): not implemented");
535 }
536 /*-- 12.09.00 12:58:20---------------------------------------------------
537 
538   -----------------------------------------------------------------------*/
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)539 void SAL_CALL SwXReferenceMark::removePropertyChangeListener(
540         const OUString& /*rPropertyName*/,
541         const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
542 {
543     OSL_ENSURE(false,
544         "SwXReferenceMark::removePropertyChangeListener(): not implemented");
545 }
546 /*-- 12.09.00 12:58:20---------------------------------------------------
547 
548   -----------------------------------------------------------------------*/
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)549 void SAL_CALL SwXReferenceMark::addVetoableChangeListener(
550         const OUString& /*rPropertyName*/,
551         const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
552 {
553     OSL_ENSURE(false,
554         "SwXReferenceMark::addVetoableChangeListener(): not implemented");
555 }
556 /*-- 12.09.00 12:58:21---------------------------------------------------
557 
558   -----------------------------------------------------------------------*/
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)559 void SAL_CALL SwXReferenceMark::removeVetoableChangeListener(
560     const OUString& /*rPropertyName*/,
561     const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
562 {
563     OSL_ENSURE(false,
564         "SwXReferenceMark::removeVetoableChangeListener(): not implemented");
565 }
566 
567 #include <com/sun/star/lang/DisposedException.hpp>
568 #include <unometa.hxx>
569 #include <unotext.hxx>
570 #include <unoport.hxx>
571 #include <txtatr.hxx>
572 #include <fmtmeta.hxx>
573 #include <docsh.hxx>
574 
575 //=============================================================================
576 
577 /******************************************************************
578  * SwXMetaText
579  ******************************************************************/
580 
581 class SwXMetaText
582     : public SwXText
583 {
584 private:
585     SwXMeta & m_rMeta;
586 
587     virtual void PrepareForAttach(uno::Reference< text::XTextRange > & xRange,
588             const SwPaM & rPam);
589 
590     virtual bool CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb);
591 
592 protected:
593     virtual const SwStartNode *GetStartNode() const;
594     virtual uno::Reference< text::XTextCursor >
595         CreateCursor();
596 
597 public:
598     SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta);
599 
600     /// make available for SwXMeta
Invalidate()601     void Invalidate() { SwXText::Invalidate(); };
602 
603     // XInterface
acquire()604     virtual void SAL_CALL acquire() throw()
605         { OSL_ENSURE(false, "ERROR: SwXMetaText::acquire"); }
release()606     virtual void SAL_CALL release() throw()
607         { OSL_ENSURE(false, "ERROR: SwXMetaText::release"); }
608 
609     // XTypeProvider
610     virtual uno::Sequence< sal_Int8 > SAL_CALL
611         getImplementationId();
612 
613     // XText
614     virtual uno::Reference< text::XTextCursor >  SAL_CALL
615         createTextCursor();
616     virtual uno::Reference< text::XTextCursor >  SAL_CALL
617         createTextCursorByRange(
618             const uno::Reference< text::XTextRange > & xTextPosition);
619 
GetXMeta()620     SwXMeta & GetXMeta() { return m_rMeta; }
621 
622 };
623 
SwXMetaText(SwDoc & rDoc,SwXMeta & rMeta)624 SwXMetaText::SwXMetaText(SwDoc & rDoc, SwXMeta & rMeta)
625     : SwXText(&rDoc, CURSOR_META)
626     , m_rMeta(rMeta)
627 {
628 }
629 
GetStartNode() const630 const SwStartNode *SwXMetaText::GetStartNode() const
631 {
632     SwXText const * const pParent(
633             dynamic_cast<SwXText*>(m_rMeta.GetParentText().get()));
634     return (pParent) ? pParent->GetStartNode() : 0;
635 }
636 
PrepareForAttach(uno::Reference<text::XTextRange> & xRange,const SwPaM & rPam)637 void SwXMetaText::PrepareForAttach( uno::Reference<text::XTextRange> & xRange,
638         const SwPaM & rPam)
639 {
640     // create a new cursor to prevent modifying SwXTextRange
641     xRange = static_cast<text::XWordCursor*>(
642         new SwXTextCursor(*GetDoc(), &m_rMeta, CURSOR_META, *rPam.GetPoint(),
643                 (rPam.HasMark()) ? rPam.GetMark() : 0));
644 }
645 
CheckForOwnMemberMeta(const SwPaM & rPam,const bool bAbsorb)646 bool SwXMetaText::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb)
647 {
648     return m_rMeta.CheckForOwnMemberMeta(rPam, bAbsorb);
649 }
650 
CreateCursor()651 uno::Reference< text::XTextCursor > SwXMetaText::CreateCursor()
652 {
653     uno::Reference< text::XTextCursor > xRet;
654     if (IsValid())
655     {
656         SwTxtNode * pTxtNode;
657         xub_StrLen nMetaStart;
658         xub_StrLen nMetaEnd;
659         const bool bSuccess(
660                 m_rMeta.SetContentRange(pTxtNode, nMetaStart, nMetaEnd) );
661         if (bSuccess)
662         {
663             SwPosition aPos(*pTxtNode, nMetaStart);
664             xRet = static_cast<text::XWordCursor*>(
665                     new SwXTextCursor(*GetDoc(), &m_rMeta, CURSOR_META, aPos));
666         }
667     }
668     return xRet;
669 }
670 
671 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId()672 SwXMetaText::getImplementationId()
673 {
674     return m_rMeta.getImplementationId();
675 }
676 
677 // XText
678 uno::Reference< text::XTextCursor > SAL_CALL
createTextCursor()679 SwXMetaText::createTextCursor()
680 {
681     return CreateCursor();
682 }
683 
684 uno::Reference< text::XTextCursor > SAL_CALL
createTextCursorByRange(const uno::Reference<text::XTextRange> & xTextPosition)685 SwXMetaText::createTextCursorByRange(
686         const uno::Reference<text::XTextRange> & xTextPosition)
687 {
688     const uno::Reference<text::XTextCursor> xCursor( CreateCursor() );
689     xCursor->gotoRange(xTextPosition, sal_False);
690     return xCursor;
691 }
692 
693 /******************************************************************
694  * SwXMeta
695  ******************************************************************/
696 
697 // the Meta has a cached list of text portions for its contents
698 // this list is created by SwXTextPortionEnumeration
699 // the Meta listens at the SwTxtNode and throws away the cache when it changes
700 
701 class SwXMeta::Impl
702     : public SwClient
703 {
704 
705 public:
706 
707     SwEventListenerContainer m_ListenerContainer;
708     ::std::auto_ptr<const TextRangeList_t> m_pTextPortions;
709     // 3 possible states: not attached, attached, disposed
710     bool m_bIsDisposed;
711     bool m_bIsDescriptor;
712     uno::Reference<text::XText> m_xParentText;
713     SwXMetaText m_Text;
714 
Impl(SwXMeta & rThis,SwDoc & rDoc,::sw::Meta * const pMeta,uno::Reference<text::XText> const & xParentText,TextRangeList_t const * const pPortions)715     Impl(   SwXMeta & rThis, SwDoc & rDoc,
716             ::sw::Meta * const pMeta,
717             uno::Reference<text::XText> const& xParentText,
718             TextRangeList_t const * const pPortions)
719         : SwClient(pMeta)
720         , m_ListenerContainer(static_cast< ::cppu::OWeakObject* >(&rThis))
721         , m_pTextPortions( pPortions )
722         , m_bIsDisposed( false )
723         // #i111177# unxsols4 (Sun C++ 5.9 SunOS_sparc) may generate wrong code
724         , m_bIsDescriptor((0 == pMeta) ? true : false)
725         , m_xParentText(xParentText)
726         , m_Text(rDoc, rThis)
727     {
728     }
729 
730     inline const ::sw::Meta * GetMeta() const;
731     // only for SwXMetaField!
732     inline const ::sw::MetaField * GetMetaField() const;
733 protected:
734     // SwClient
735     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
736 
737 };
738 
GetMeta() const739 inline const ::sw::Meta * SwXMeta::Impl::GetMeta() const
740 {
741     return static_cast< const ::sw::Meta * >(GetRegisteredIn());
742 }
743 
744 // SwModify
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)745 void SwXMeta::Impl::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
746 {
747     m_pTextPortions.reset(); // throw away cache (SwTxtNode changed)
748 
749     ClientModify(this, pOld, pNew);
750 
751     if (!GetRegisteredIn()) // removed => dispose
752     {
753         m_ListenerContainer.Disposing();
754         m_bIsDisposed = true;
755         m_Text.Invalidate();
756     }
757 }
758 
GetParentText() const759 uno::Reference<text::XText> SwXMeta::GetParentText() const
760 {
761     return m_pImpl->m_xParentText;
762 }
763 
SwXMeta(SwDoc * const pDoc,::sw::Meta * const pMeta,uno::Reference<text::XText> const & xParentText,TextRangeList_t const * const pPortions)764 SwXMeta::SwXMeta(SwDoc *const pDoc, ::sw::Meta *const pMeta,
765         uno::Reference<text::XText> const& xParentText,
766         TextRangeList_t const*const pPortions)
767     : m_pImpl( new SwXMeta::Impl(*this, *pDoc, pMeta, xParentText, pPortions) )
768 {
769 }
770 
SwXMeta(SwDoc * const pDoc)771 SwXMeta::SwXMeta(SwDoc *const pDoc)
772     : m_pImpl( new SwXMeta::Impl(*this, *pDoc, 0, 0, 0) )
773 {
774 }
775 
~SwXMeta()776 SwXMeta::~SwXMeta()
777 {
778 }
779 
780 uno::Reference<rdf::XMetadatable>
CreateXMeta(::sw::Meta & rMeta,uno::Reference<text::XText> const & i_xParent,::std::auto_ptr<TextRangeList_t const> pPortions)781 SwXMeta::CreateXMeta(::sw::Meta & rMeta,
782             uno::Reference<text::XText> const& i_xParent,
783             ::std::auto_ptr<TextRangeList_t const> pPortions)
784 {
785     // re-use existing SwXMeta
786     // #i105557#: do not iterate over the registered clients: race condition
787     uno::Reference<rdf::XMetadatable> xMeta(rMeta.GetXMeta());
788     if (xMeta.is())
789     {
790         if (pPortions.get()) // set cache in the XMeta to the given portions
791         {
792             const uno::Reference<lang::XUnoTunnel> xUT(xMeta, uno::UNO_QUERY);
793             SwXMeta *const pXMeta(
794                 ::sw::UnoTunnelGetImplementation<SwXMeta>(xUT));
795             OSL_ENSURE(pXMeta, "no pXMeta?");
796             // NB: the meta must always be created with the complete content
797             // if SwXTextPortionEnumeration is created for a selection,
798             // it must be checked that the Meta is contained in the selection!
799             pXMeta->m_pImpl->m_pTextPortions = pPortions;
800             // ??? is this necessary?
801             if (pXMeta->m_pImpl->m_xParentText.get() != i_xParent.get())
802             {
803                 OSL_ENSURE(false, "SwXMeta with different parent?");
804                 pXMeta->m_pImpl->m_xParentText.set(i_xParent);
805             }
806         }
807         return xMeta;
808     }
809 
810     // create new SwXMeta
811     SwTxtNode * const pTxtNode( rMeta.GetTxtNode() );
812     OSL_ENSURE(pTxtNode, "CreateXMeta: no text node?");
813     if (!pTxtNode) { return 0; }
814     uno::Reference<text::XText> xParentText(i_xParent);
815     if (!xParentText.is())
816     {
817         SwTxtMeta * const pTxtAttr( rMeta.GetTxtAttr() );
818         OSL_ENSURE(pTxtAttr, "CreateXMeta: no text attr?");
819         if (!pTxtAttr) { return 0; }
820         const SwPosition aPos(*pTxtNode, *pTxtAttr->GetStart());
821         xParentText.set( ::sw::CreateParentXText(*pTxtNode->GetDoc(), aPos) );
822     }
823     if (!xParentText.is()) { return 0; }
824     SwXMeta *const pXMeta( (RES_TXTATR_META == rMeta.GetFmtMeta()->Which())
825         ? new SwXMeta     (pTxtNode->GetDoc(), &rMeta, xParentText,
826                             pPortions.release()) // temporarily un-auto_ptr :-(
827         : new SwXMetaField(pTxtNode->GetDoc(), &rMeta, xParentText,
828                             pPortions.release()));
829     // this is why the constructor is private: need to acquire pXMeta here
830     xMeta.set(pXMeta);
831     // in order to initialize the weak pointer cache in the core object
832     rMeta.SetXMeta(xMeta);
833     return xMeta;
834 }
835 
836 
SetContentRange(SwTxtNode * & rpNode,xub_StrLen & rStart,xub_StrLen & rEnd) const837 bool SwXMeta::SetContentRange(
838         SwTxtNode *& rpNode, xub_StrLen & rStart, xub_StrLen & rEnd ) const
839 {
840     ::sw::Meta const * const pMeta( m_pImpl->GetMeta() );
841     if (pMeta)
842     {
843         SwTxtMeta const * const pTxtAttr( pMeta->GetTxtAttr() );
844         if (pTxtAttr)
845         {
846             rpNode = pMeta->GetTxtNode();
847             if (rpNode)
848             {
849                 // rStart points at the first position _within_ the meta!
850                 rStart = *pTxtAttr->GetStart() + 1;
851                 rEnd = *pTxtAttr->End();
852                 return true;
853             }
854         }
855     }
856     return false;
857 }
858 
CheckForOwnMemberMeta(const SwPaM & rPam,const bool bAbsorb)859 bool SwXMeta::CheckForOwnMemberMeta(const SwPaM & rPam, const bool bAbsorb)
860 {
861     SwTxtNode * pTxtNode;
862     xub_StrLen nMetaStart;
863     xub_StrLen nMetaEnd;
864     const bool bSuccess( SetContentRange(pTxtNode, nMetaStart, nMetaEnd) );
865     ASSERT(bSuccess, "no pam?");
866     if (!bSuccess)
867         throw lang::DisposedException();
868 
869     SwPosition const * const pStartPos( rPam.Start() );
870     if (&pStartPos->nNode.GetNode() != pTxtNode)
871     {
872         throw lang::IllegalArgumentException(
873             C2U("trying to insert into a nesting text content, but start "
874                 "of text range not in same paragraph as text content"),
875                 0, 0);
876     }
877     bool bForceExpandHints(false);
878     const xub_StrLen nStartPos(pStartPos->nContent.GetIndex());
879     // not <= but < because nMetaStart is behind dummy char!
880     // not >= but > because == means insert at end!
881     if ((nStartPos < nMetaStart) || (nStartPos > nMetaEnd))
882     {
883         throw lang::IllegalArgumentException(
884             C2U("trying to insert into a nesting text content, but start "
885                 "of text range not inside text content"),
886                 0, 0);
887     }
888     else if (nStartPos == nMetaEnd)
889     {
890         bForceExpandHints = true;
891     }
892     if (rPam.HasMark() && bAbsorb)
893     {
894         SwPosition const * const pEndPos( rPam.End() );
895         if (&pEndPos->nNode.GetNode() != pTxtNode)
896         {
897             throw lang::IllegalArgumentException(
898                 C2U("trying to insert into a nesting text content, but end "
899                     "of text range not in same paragraph as text content"),
900                     0, 0);
901         }
902         const xub_StrLen nEndPos(pEndPos->nContent.GetIndex());
903         // not <= but < because nMetaStart is behind dummy char!
904         // not >= but > because == means insert at end!
905         if ((nEndPos < nMetaStart) || (nEndPos > nMetaEnd))
906         {
907             throw lang::IllegalArgumentException(
908                 C2U("trying to insert into a nesting text content, but end "
909                     "of text range not inside text content"),
910                     0, 0);
911         }
912         else if (nEndPos == nMetaEnd)
913         {
914             bForceExpandHints = true;
915         }
916     }
917     return bForceExpandHints;
918 }
919 
getUnoTunnelId()920 const uno::Sequence< sal_Int8 > & SwXMeta::getUnoTunnelId()
921 {
922     static uno::Sequence< sal_Int8 > aSeq( ::CreateUnoTunnelId() );
923     return aSeq;
924 }
925 
926 // XUnoTunnel
927 sal_Int64 SAL_CALL
getSomething(const uno::Sequence<sal_Int8> & i_rId)928 SwXMeta::getSomething( const uno::Sequence< sal_Int8 > & i_rId )
929 {
930     return ::sw::UnoTunnelImpl<SwXMeta>(i_rId, this);
931 }
932 
933 // XServiceInfo
934 ::rtl::OUString SAL_CALL
getImplementationName()935 SwXMeta::getImplementationName()
936 {
937     return C2U("SwXMeta");
938 }
939 
940 static char const*const g_ServicesMeta[] =
941 {
942     "com.sun.star.text.TextContent",
943     "com.sun.star.text.InContentMetadata",
944 };
945 static const size_t g_nServicesMeta(
946     sizeof(g_ServicesMeta)/sizeof(g_ServicesMeta[0]));
947 
948 sal_Bool SAL_CALL
supportsService(const::rtl::OUString & rServiceName)949 SwXMeta::supportsService(const ::rtl::OUString& rServiceName)
950 {
951     return ::sw::SupportsServiceImpl(
952             g_nServicesMeta, g_ServicesMeta, rServiceName);
953 }
954 
955 uno::Sequence< ::rtl::OUString > SAL_CALL
getSupportedServiceNames()956 SwXMeta::getSupportedServiceNames()
957 {
958     return ::sw::GetSupportedServiceNamesImpl(g_nServicesMeta, g_ServicesMeta);
959 }
960 
961 
962 // XComponent
963 void SAL_CALL
addEventListener(uno::Reference<lang::XEventListener> const & xListener)964 SwXMeta::addEventListener(
965         uno::Reference< lang::XEventListener> const & xListener )
966 {
967     vos::OGuard g(Application::GetSolarMutex());
968 
969     m_pImpl->m_ListenerContainer.AddListener(xListener);
970     if (m_pImpl->m_bIsDisposed)
971     {
972         m_pImpl->m_ListenerContainer.Disposing();
973     }
974 }
975 
976 void SAL_CALL
removeEventListener(uno::Reference<lang::XEventListener> const & xListener)977 SwXMeta::removeEventListener(
978         uno::Reference< lang::XEventListener> const & xListener )
979 {
980     vos::OGuard g(Application::GetSolarMutex());
981 
982     if (!m_pImpl->m_bIsDisposed)
983     {
984         m_pImpl->m_ListenerContainer.RemoveListener(xListener);
985     }
986 }
987 
988 void SAL_CALL
dispose()989 SwXMeta::dispose()
990 {
991     vos::OGuard g(Application::GetSolarMutex());
992 
993     if (m_pImpl->m_bIsDescriptor)
994     {
995         m_pImpl->m_pTextPortions.reset();
996         m_pImpl->m_ListenerContainer.Disposing();
997         m_pImpl->m_bIsDisposed = true;
998         m_pImpl->m_Text.Invalidate();
999     }
1000     else if (!m_pImpl->m_bIsDisposed)
1001     {
1002         SwTxtNode * pTxtNode;
1003         xub_StrLen nMetaStart;
1004         xub_StrLen nMetaEnd;
1005         const bool bSuccess(SetContentRange(pTxtNode, nMetaStart, nMetaEnd));
1006         ASSERT(bSuccess, "no pam?");
1007         if (bSuccess)
1008         {
1009             // -1 because of CH_TXTATR
1010             SwPaM aPam( *pTxtNode, nMetaStart - 1, *pTxtNode, nMetaEnd );
1011             SwDoc * const pDoc( pTxtNode->GetDoc() );
1012             pDoc->DeleteAndJoin( aPam );
1013 
1014             // removal should call Modify and do the dispose
1015             OSL_ENSURE(m_pImpl->m_bIsDisposed, "zombie meta");
1016         }
1017     }
1018 }
1019 
1020 
1021 void SAL_CALL
AttachImpl(const uno::Reference<text::XTextRange> & i_xTextRange,const sal_uInt16 i_nWhich)1022 SwXMeta::AttachImpl(const uno::Reference< text::XTextRange > & i_xTextRange,
1023         const sal_uInt16 i_nWhich)
1024 {
1025     vos::OGuard g(Application::GetSolarMutex());
1026 
1027     if (m_pImpl->m_bIsDisposed)
1028     {
1029         throw lang::DisposedException();
1030     }
1031     if (!m_pImpl->m_bIsDescriptor)
1032     {
1033         throw uno::RuntimeException(
1034             C2S("SwXMeta::attach(): already attached"),
1035                 static_cast< ::cppu::OWeakObject* >(this));
1036     }
1037 
1038     uno::Reference<lang::XUnoTunnel> xRangeTunnel(i_xTextRange, uno::UNO_QUERY);
1039     if (!xRangeTunnel.is())
1040     {
1041         throw lang::IllegalArgumentException(
1042             C2S("SwXMeta::attach(): argument is no XUnoTunnel"),
1043                 static_cast< ::cppu::OWeakObject* >(this), 0);
1044     }
1045     SwXTextRange *const pRange(
1046             ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel));
1047     OTextCursorHelper *const pCursor( (pRange) ? 0 :
1048             ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel));
1049     if (!pRange && !pCursor)
1050     {
1051         throw lang::IllegalArgumentException(
1052             C2S("SwXMeta::attach(): argument not supported type"),
1053                 static_cast< ::cppu::OWeakObject* >(this), 0);
1054     }
1055 
1056     SwDoc * const pDoc(
1057             pRange ? pRange->GetDoc() : pCursor ? pCursor->GetDoc() : 0 );
1058     if (!pDoc)
1059     {
1060         throw lang::IllegalArgumentException(
1061             C2S("SwXMeta::attach(): argument has no SwDoc"),
1062                 static_cast< ::cppu::OWeakObject* >(this), 0);
1063     }
1064 
1065     SwUnoInternalPaM aPam(*pDoc);
1066     ::sw::XTextRangeToSwPaM(aPam, i_xTextRange);
1067 
1068     UnoActionContext aContext(pDoc);
1069 
1070     SwXTextCursor const*const pTextCursor(
1071             dynamic_cast<SwXTextCursor*>(pCursor));
1072     const bool bForceExpandHints((pTextCursor)
1073             ? pTextCursor->IsAtEndOfMeta() : false);
1074     const SetAttrMode nInsertFlags( (bForceExpandHints)
1075         ?   ( nsSetAttrMode::SETATTR_FORCEHINTEXPAND
1076             | nsSetAttrMode::SETATTR_DONTEXPAND)
1077         : nsSetAttrMode::SETATTR_DONTEXPAND );
1078 
1079     const ::boost::shared_ptr< ::sw::Meta> pMeta( (RES_TXTATR_META == i_nWhich)
1080         ? ::boost::shared_ptr< ::sw::Meta>( new ::sw::Meta() )
1081         : ::boost::shared_ptr< ::sw::Meta>(
1082             pDoc->GetMetaFieldManager().makeMetaField()) );
1083     SwFmtMeta meta(pMeta, i_nWhich); // this is cloned by Insert!
1084     const bool bSuccess( pDoc->InsertPoolItem( aPam, meta, nInsertFlags ) );
1085     SwTxtAttr * const pTxtAttr( pMeta->GetTxtAttr() );
1086     if (!bSuccess)
1087     {
1088         throw lang::IllegalArgumentException(
1089             C2S("SwXMeta::attach(): cannot create meta: range invalid?"),
1090                 static_cast< ::cppu::OWeakObject* >(this), 1);
1091     }
1092     if (!pTxtAttr)
1093     {
1094         ASSERT(false, "meta inserted, but has no text attribute?");
1095         throw uno::RuntimeException(
1096             C2S("SwXMeta::attach(): cannot create meta"),
1097                 static_cast< ::cppu::OWeakObject* >(this));
1098     }
1099 
1100     pMeta->Add(m_pImpl.get());
1101     pMeta->SetXMeta(uno::Reference<rdf::XMetadatable>(this));
1102 
1103     m_pImpl->m_xParentText = ::sw::CreateParentXText(*pDoc, *aPam.GetPoint());
1104 
1105     m_pImpl->m_bIsDescriptor = false;
1106 }
1107 
1108 // XTextContent
1109 void SAL_CALL
attach(const uno::Reference<text::XTextRange> & i_xTextRange)1110 SwXMeta::attach(const uno::Reference< text::XTextRange > & i_xTextRange)
1111 {
1112     return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_META);
1113 }
1114 
1115 uno::Reference< text::XTextRange > SAL_CALL
getAnchor()1116 SwXMeta::getAnchor()
1117 {
1118     vos::OGuard g(Application::GetSolarMutex());
1119 
1120     if (m_pImpl->m_bIsDisposed)
1121     {
1122         throw lang::DisposedException();
1123     }
1124     if (m_pImpl->m_bIsDescriptor)
1125     {
1126         throw uno::RuntimeException(
1127                 C2S("SwXMeta::getAnchor(): not inserted"),
1128                 static_cast< ::cppu::OWeakObject* >(this));
1129     }
1130 
1131     SwTxtNode * pTxtNode;
1132     xub_StrLen nMetaStart;
1133     xub_StrLen nMetaEnd;
1134     const bool bSuccess(SetContentRange(pTxtNode, nMetaStart, nMetaEnd));
1135     ASSERT(bSuccess, "no pam?");
1136     if (!bSuccess)
1137     {
1138         throw lang::DisposedException(
1139                 C2S("SwXMeta::getAnchor(): not attached"),
1140                 static_cast< ::cppu::OWeakObject* >(this));
1141     }
1142 
1143     const SwPosition start(*pTxtNode, nMetaStart - 1); // -1 due to CH_TXTATR
1144     const SwPosition end(*pTxtNode, nMetaEnd);
1145     return SwXTextRange::CreateXTextRange(*pTxtNode->GetDoc(), start, &end);
1146 }
1147 
1148 // XTextRange
1149 uno::Reference< text::XText > SAL_CALL
getText()1150 SwXMeta::getText()
1151 {
1152     vos::OGuard g(Application::GetSolarMutex());
1153     return this;
1154 }
1155 
1156 uno::Reference< text::XTextRange > SAL_CALL
getStart()1157 SwXMeta::getStart()
1158 {
1159     vos::OGuard g(Application::GetSolarMutex());
1160     return m_pImpl->m_Text.getStart();
1161 }
1162 
1163 uno::Reference< text::XTextRange > SAL_CALL
getEnd()1164 SwXMeta::getEnd()
1165 {
1166     vos::OGuard g(Application::GetSolarMutex());
1167     return m_pImpl->m_Text.getEnd();
1168 }
1169 
1170 rtl::OUString SAL_CALL
getString()1171 SwXMeta::getString()
1172 {
1173     vos::OGuard g(Application::GetSolarMutex());
1174     return m_pImpl->m_Text.getString();
1175 }
1176 
1177 void SAL_CALL
setString(const rtl::OUString & rString)1178 SwXMeta::setString(const rtl::OUString& rString)
1179 {
1180     vos::OGuard g(Application::GetSolarMutex());
1181     return m_pImpl->m_Text.setString(rString);
1182 }
1183 
1184 // XSimpleText
1185 uno::Reference< text::XTextCursor > SAL_CALL
createTextCursor()1186 SwXMeta::createTextCursor()
1187 {
1188     vos::OGuard g(Application::GetSolarMutex());
1189     return m_pImpl->m_Text.createTextCursor();
1190 }
1191 
1192 uno::Reference< text::XTextCursor > SAL_CALL
createTextCursorByRange(const uno::Reference<text::XTextRange> & xTextPosition)1193 SwXMeta::createTextCursorByRange(
1194         const uno::Reference<text::XTextRange> & xTextPosition)
1195 {
1196     vos::OGuard g(Application::GetSolarMutex());
1197     return m_pImpl->m_Text.createTextCursorByRange(xTextPosition);
1198 }
1199 
1200 void SAL_CALL
insertString(const uno::Reference<text::XTextRange> & xRange,const rtl::OUString & rString,sal_Bool bAbsorb)1201 SwXMeta::insertString(const uno::Reference<text::XTextRange> & xRange,
1202         const rtl::OUString& rString, sal_Bool bAbsorb)
1203 {
1204     vos::OGuard g(Application::GetSolarMutex());
1205     return m_pImpl->m_Text.insertString(xRange, rString, bAbsorb);
1206 }
1207 
1208 void SAL_CALL
insertControlCharacter(const uno::Reference<text::XTextRange> & xRange,sal_Int16 nControlCharacter,sal_Bool bAbsorb)1209 SwXMeta::insertControlCharacter(const uno::Reference<text::XTextRange> & xRange,
1210         sal_Int16 nControlCharacter, sal_Bool bAbsorb)
1211 {
1212     vos::OGuard g(Application::GetSolarMutex());
1213     return m_pImpl->m_Text.insertControlCharacter(xRange, nControlCharacter,
1214                 bAbsorb);
1215 }
1216 
1217 // XText
1218 void SAL_CALL
insertTextContent(const uno::Reference<text::XTextRange> & xRange,const uno::Reference<text::XTextContent> & xContent,sal_Bool bAbsorb)1219 SwXMeta::insertTextContent( const uno::Reference<text::XTextRange> & xRange,
1220         const uno::Reference<text::XTextContent> & xContent, sal_Bool bAbsorb)
1221 {
1222     vos::OGuard g(Application::GetSolarMutex());
1223     return m_pImpl->m_Text.insertTextContent(xRange, xContent, bAbsorb);
1224 }
1225 
1226 void SAL_CALL
removeTextContent(const uno::Reference<text::XTextContent> & xContent)1227 SwXMeta::removeTextContent(
1228         const uno::Reference< text::XTextContent > & xContent)
1229 {
1230     vos::OGuard g(Application::GetSolarMutex());
1231     return m_pImpl->m_Text.removeTextContent(xContent);
1232 }
1233 
1234 // XChild
1235 uno::Reference< uno::XInterface > SAL_CALL
getParent()1236 SwXMeta::getParent()
1237 {
1238     vos::OGuard g(Application::GetSolarMutex());
1239     SwTxtNode * pTxtNode;
1240     xub_StrLen nMetaStart;
1241     xub_StrLen nMetaEnd;
1242     bool const bSuccess( SetContentRange(pTxtNode, nMetaStart, nMetaEnd) );
1243     OSL_ENSURE(bSuccess, "no pam?");
1244     if (!bSuccess) { throw lang::DisposedException(); }
1245     // in order to prevent getting this meta, subtract 1 from nMetaStart;
1246     // so we get the index of the dummy character, and we exclude it
1247     // by calling GetTxtAttrAt(_, _, PARENT) in GetNestedTextContent
1248     uno::Reference<text::XTextContent> const xRet(
1249         SwUnoCursorHelper::GetNestedTextContent(*pTxtNode, nMetaStart - 1,
1250             true) );
1251     return xRet;
1252 }
1253 
1254 void SAL_CALL
setParent(uno::Reference<uno::XInterface> const &)1255 SwXMeta::setParent(uno::Reference< uno::XInterface > const& /*xParent*/)
1256 {
1257     throw lang::NoSupportException(C2S("setting parent not supported"), *this);
1258 }
1259 
1260 // XElementAccess
1261 uno::Type SAL_CALL
getElementType()1262 SwXMeta::getElementType()
1263 {
1264     return text::XTextRange::static_type();
1265 }
1266 
1267 sal_Bool SAL_CALL
hasElements()1268 SwXMeta::hasElements()
1269 {
1270     vos::OGuard g(Application::GetSolarMutex());
1271 
1272     return m_pImpl->GetRegisteredIn() ? sal_True : sal_False;
1273 }
1274 
1275 // XEnumerationAccess
1276 uno::Reference< container::XEnumeration > SAL_CALL
createEnumeration()1277 SwXMeta::createEnumeration()
1278 {
1279     vos::OGuard g(Application::GetSolarMutex());
1280 
1281     if (m_pImpl->m_bIsDisposed)
1282     {
1283         throw lang::DisposedException();
1284     }
1285     if (m_pImpl->m_bIsDescriptor)
1286     {
1287         throw uno::RuntimeException(
1288                 C2S("createEnumeration(): not inserted"),
1289                 static_cast< ::cppu::OWeakObject* >(this));
1290     }
1291 
1292     SwTxtNode * pTxtNode;
1293     xub_StrLen nMetaStart;
1294     xub_StrLen nMetaEnd;
1295     const bool bSuccess(SetContentRange(pTxtNode, nMetaStart, nMetaEnd));
1296     ASSERT(bSuccess, "no pam?");
1297     if (!bSuccess)
1298         throw lang::DisposedException();
1299 
1300     SwPaM aPam(*pTxtNode, nMetaStart);
1301 
1302     if (!m_pImpl->m_pTextPortions.get())
1303     {
1304         return new SwXTextPortionEnumeration(
1305                     aPam, GetParentText(), nMetaStart, nMetaEnd);
1306     }
1307     else // cached!
1308     {
1309         return new SwXTextPortionEnumeration(aPam, *m_pImpl->m_pTextPortions);
1310     }
1311 }
1312 
1313 
1314 // MetadatableMixin
GetCoreObject()1315 ::sfx2::Metadatable* SwXMeta::GetCoreObject()
1316 {
1317     return const_cast< ::sw::Meta * >(m_pImpl->GetMeta());
1318 }
1319 
GetModel()1320 uno::Reference<frame::XModel> SwXMeta::GetModel()
1321 {
1322     ::sw::Meta const * const pMeta( m_pImpl->GetMeta() );
1323     if (pMeta)
1324     {
1325         SwTxtNode const * const pTxtNode( pMeta->GetTxtNode() );
1326         if (pTxtNode)
1327         {
1328             SwDocShell const * const pShell(pTxtNode->GetDoc()->GetDocShell());
1329             return (pShell) ? pShell->GetModel() : 0;
1330         }
1331     }
1332     return 0;
1333 }
1334 
1335 
1336 /******************************************************************
1337  * SwXMetaField
1338  ******************************************************************/
1339 
GetMetaField() const1340 inline const ::sw::MetaField * SwXMeta::Impl::GetMetaField() const
1341 {
1342     return static_cast< const ::sw::MetaField * >(GetRegisteredIn());
1343 }
1344 
SwXMetaField(SwDoc * const pDoc,::sw::Meta * const pMeta,uno::Reference<text::XText> const & xParentText,TextRangeList_t const * const pPortions)1345 SwXMetaField::SwXMetaField(SwDoc *const pDoc, ::sw::Meta *const pMeta,
1346         uno::Reference<text::XText> const& xParentText,
1347         TextRangeList_t const*const pPortions)
1348     : SwXMetaField_Base(pDoc, pMeta, xParentText, pPortions)
1349 {
1350     ASSERT(pMeta && dynamic_cast< ::sw::MetaField* >(pMeta),
1351         "SwXMetaField created for wrong hint!");
1352 }
1353 
SwXMetaField(SwDoc * const pDoc)1354 SwXMetaField::SwXMetaField(SwDoc *const pDoc)
1355     :  SwXMetaField_Base(pDoc)
1356 {
1357 }
1358 
~SwXMetaField()1359 SwXMetaField::~SwXMetaField()
1360 {
1361 }
1362 
1363 // XServiceInfo
1364 ::rtl::OUString SAL_CALL
getImplementationName()1365 SwXMetaField::getImplementationName()
1366 {
1367     return C2U("SwXMetaField");
1368 }
1369 
1370 static char const*const g_ServicesMetaField[] =
1371 {
1372     "com.sun.star.text.TextContent",
1373     "com.sun.star.text.TextField",
1374     "com.sun.star.text.textfield.MetadataField",
1375 };
1376 static const size_t g_nServicesMetaField(
1377     sizeof(g_ServicesMetaField)/sizeof(g_ServicesMetaField[0]));
1378 
1379 sal_Bool SAL_CALL
supportsService(const::rtl::OUString & rServiceName)1380 SwXMetaField::supportsService(const ::rtl::OUString& rServiceName)
1381 {
1382     return ::sw::SupportsServiceImpl(
1383             g_nServicesMetaField, g_ServicesMetaField, rServiceName);
1384 }
1385 
1386 uno::Sequence< ::rtl::OUString > SAL_CALL
getSupportedServiceNames()1387 SwXMetaField::getSupportedServiceNames()
1388 {
1389     return ::sw::GetSupportedServiceNamesImpl(
1390             g_nServicesMetaField, g_ServicesMetaField);
1391 }
1392 
1393 // XComponent
1394 void SAL_CALL
addEventListener(uno::Reference<lang::XEventListener> const & xListener)1395 SwXMetaField::addEventListener(
1396         uno::Reference< lang::XEventListener> const & xListener )
1397 {
1398     return SwXMeta::addEventListener(xListener);
1399 }
1400 
1401 void SAL_CALL
removeEventListener(uno::Reference<lang::XEventListener> const & xListener)1402 SwXMetaField::removeEventListener(
1403         uno::Reference< lang::XEventListener> const & xListener )
1404 {
1405     return SwXMeta::removeEventListener(xListener);
1406 }
1407 
1408 void SAL_CALL
dispose()1409 SwXMetaField::dispose()
1410 {
1411     return SwXMeta::dispose();
1412 }
1413 
1414 // XTextContent
1415 void SAL_CALL
attach(const uno::Reference<text::XTextRange> & i_xTextRange)1416 SwXMetaField::attach(const uno::Reference< text::XTextRange > & i_xTextRange)
1417 {
1418     return SwXMeta::AttachImpl(i_xTextRange, RES_TXTATR_METAFIELD);
1419 }
1420 
1421 uno::Reference< text::XTextRange > SAL_CALL
getAnchor()1422 SwXMetaField::getAnchor()
1423 {
1424     return SwXMeta::getAnchor();
1425 }
1426 
1427 // XPropertySet
1428 uno::Reference< beans::XPropertySetInfo > SAL_CALL
getPropertySetInfo()1429 SwXMetaField::getPropertySetInfo()
1430 {
1431     vos::OGuard g(Application::GetSolarMutex());
1432 
1433     static uno::Reference< beans::XPropertySetInfo > xRef(
1434         aSwMapProvider.GetPropertySet(PROPERTY_MAP_METAFIELD)
1435             ->getPropertySetInfo() );
1436     return xRef;
1437 }
1438 
1439 void SAL_CALL
setPropertyValue(const::rtl::OUString & rPropertyName,const uno::Any & rValue)1440 SwXMetaField::setPropertyValue(
1441         const ::rtl::OUString& rPropertyName, const uno::Any& rValue)
1442 {
1443     vos::OGuard g(Application::GetSolarMutex());
1444 
1445     ::sw::MetaField * const pMeta(
1446             const_cast< ::sw::MetaField * >(m_pImpl->GetMetaField()) );
1447     if (!pMeta)
1448         throw lang::DisposedException();
1449 
1450     if (rPropertyName.equalsAscii("NumberFormat"))
1451     {
1452         sal_Int32 nNumberFormat(0);
1453         if (rValue >>= nNumberFormat)
1454         {
1455             pMeta->SetNumberFormat(static_cast<sal_uInt32>(nNumberFormat));
1456         }
1457     }
1458     else if (rPropertyName.equalsAscii("IsFixedLanguage"))
1459     {
1460         bool b(false);
1461         if (rValue >>= b)
1462         {
1463             pMeta->SetIsFixedLanguage(b);
1464         }
1465     }
1466     else
1467     {
1468         throw beans::UnknownPropertyException();
1469     }
1470 }
1471 
1472 uno::Any SAL_CALL
getPropertyValue(const::rtl::OUString & rPropertyName)1473 SwXMetaField::getPropertyValue(const ::rtl::OUString& rPropertyName)
1474 {
1475     vos::OGuard g(Application::GetSolarMutex());
1476 
1477     ::sw::MetaField const * const pMeta( m_pImpl->GetMetaField() );
1478     if (!pMeta)
1479         throw lang::DisposedException();
1480 
1481     uno::Any any;
1482 
1483     if (rPropertyName.equalsAscii("NumberFormat"))
1484     {
1485         const ::rtl::OUString text( getPresentation(sal_False) );
1486         any <<= static_cast<sal_Int32>(pMeta->GetNumberFormat(text));
1487     }
1488     else if (rPropertyName.equalsAscii("IsFixedLanguage"))
1489     {
1490         any <<= pMeta->IsFixedLanguage();
1491     }
1492     else
1493     {
1494         throw beans::UnknownPropertyException();
1495     }
1496 
1497     return any;
1498 }
1499 
1500 void SAL_CALL
addPropertyChangeListener(const::rtl::OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1501 SwXMetaField::addPropertyChangeListener(
1502         const ::rtl::OUString& /*rPropertyName*/,
1503         const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
1504 {
1505     OSL_ENSURE(false,
1506         "SwXMetaField::addPropertyChangeListener(): not implemented");
1507 }
1508 
1509 void SAL_CALL
removePropertyChangeListener(const::rtl::OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1510 SwXMetaField::removePropertyChangeListener(
1511         const ::rtl::OUString& /*rPropertyName*/,
1512         const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
1513 {
1514     OSL_ENSURE(false,
1515         "SwXMetaField::removePropertyChangeListener(): not implemented");
1516 }
1517 
1518 void SAL_CALL
addVetoableChangeListener(const::rtl::OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1519 SwXMetaField::addVetoableChangeListener(
1520         const ::rtl::OUString& /*rPropertyName*/,
1521         const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
1522 {
1523     OSL_ENSURE(false,
1524         "SwXMetaField::addVetoableChangeListener(): not implemented");
1525 }
1526 
1527 void SAL_CALL
removeVetoableChangeListener(const::rtl::OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1528 SwXMetaField::removeVetoableChangeListener(
1529         const ::rtl::OUString& /*rPropertyName*/,
1530         const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
1531 {
1532     OSL_ENSURE(false,
1533         "SwXMetaField::removeVetoableChangeListener(): not implemented");
1534 }
1535 
1536 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
1537 #include <com/sun/star/rdf/Statement.hpp>
1538 #include <com/sun/star/rdf/URI.hpp>
1539 #include <com/sun/star/rdf/URIs.hpp>
1540 #include <com/sun/star/rdf/XLiteral.hpp>
1541 #include <com/sun/star/rdf/XRepositorySupplier.hpp>
1542 #include <comphelper/processfactory.hxx>
1543 
1544 static uno::Reference<rdf::XURI> const&
lcl_getURI(const bool bPrefix)1545 lcl_getURI(const bool bPrefix)
1546 {
1547     static uno::Reference< uno::XComponentContext > xContext(
1548         ::comphelper::getProcessComponentContext());
1549     static uno::Reference< rdf::XURI > xOdfPrefix(
1550         rdf::URI::createKnown(xContext, rdf::URIs::ODF_PREFIX),
1551         uno::UNO_SET_THROW);
1552     static uno::Reference< rdf::XURI > xOdfSuffix(
1553         rdf::URI::createKnown(xContext, rdf::URIs::ODF_SUFFIX),
1554         uno::UNO_SET_THROW);
1555     return (bPrefix) ? xOdfPrefix : xOdfSuffix;
1556 }
1557 
1558 static ::rtl::OUString
lcl_getPrefixOrSuffix(uno::Reference<rdf::XRepository> const & xRepository,uno::Reference<rdf::XResource> const & xMetaField,uno::Reference<rdf::XURI> const & xPredicate)1559 lcl_getPrefixOrSuffix(
1560     uno::Reference<rdf::XRepository> const & xRepository,
1561     uno::Reference<rdf::XResource> const & xMetaField,
1562     uno::Reference<rdf::XURI> const & xPredicate)
1563 {
1564     const uno::Reference<container::XEnumeration> xEnum(
1565         xRepository->getStatements(xMetaField, xPredicate, 0),
1566         uno::UNO_SET_THROW);
1567     while (xEnum->hasMoreElements()) {
1568         rdf::Statement stmt;
1569         if (!(xEnum->nextElement() >>= stmt)) {
1570             throw uno::RuntimeException();
1571         }
1572         const uno::Reference<rdf::XLiteral> xObject(stmt.Object,
1573             uno::UNO_QUERY);
1574         if (!xObject.is()) continue;
1575         if (xEnum->hasMoreElements()) {
1576             OSL_TRACE("ignoring other odf:Prefix/odf:Suffix statements");
1577         }
1578         return xObject->getValue();
1579     }
1580     return ::rtl::OUString();
1581 }
1582 
1583 void
getPrefixAndSuffix(const uno::Reference<frame::XModel> & xModel,const uno::Reference<rdf::XMetadatable> & xMetaField,::rtl::OUString * const o_pPrefix,::rtl::OUString * const o_pSuffix)1584 getPrefixAndSuffix(
1585         const uno::Reference<frame::XModel>& xModel,
1586         const uno::Reference<rdf::XMetadatable>& xMetaField,
1587         ::rtl::OUString *const o_pPrefix, ::rtl::OUString *const o_pSuffix)
1588 {
1589     try {
1590         const uno::Reference<rdf::XRepositorySupplier> xRS(
1591                 xModel, uno::UNO_QUERY_THROW);
1592         const uno::Reference<rdf::XRepository> xRepo(
1593                 xRS->getRDFRepository(), uno::UNO_SET_THROW);
1594         const uno::Reference<rdf::XResource> xMeta(
1595                 xMetaField, uno::UNO_QUERY_THROW);
1596         if (o_pPrefix)
1597         {
1598             *o_pPrefix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(true));
1599         }
1600         if (o_pSuffix)
1601         {
1602             *o_pSuffix = lcl_getPrefixOrSuffix(xRepo, xMeta, lcl_getURI(false));
1603         }
1604     } catch (uno::RuntimeException &) {
1605         throw;
1606     } catch (uno::Exception & e) {
1607         throw lang::WrappedTargetRuntimeException(
1608             ::rtl::OUString::createFromAscii("getPrefixAndSuffix: exception"),
1609             0, uno::makeAny(e));
1610     }
1611 }
1612 
1613 // XTextField
1614 ::rtl::OUString SAL_CALL
getPresentation(sal_Bool bShowCommand)1615 SwXMetaField::getPresentation(sal_Bool bShowCommand)
1616 {
1617     vos::OGuard g(Application::GetSolarMutex());
1618 
1619     if (bShowCommand)
1620     {
1621 //FIXME ?
1622         return ::rtl::OUString();
1623     }
1624     else
1625     {
1626         // getString should check if this is invalid
1627         const ::rtl::OUString content( this->getString() );
1628         ::rtl::OUString prefix;
1629         ::rtl::OUString suffix;
1630         getPrefixAndSuffix(GetModel(), this, &prefix, &suffix);
1631         return prefix + content + suffix;
1632     }
1633 }
1634