xref: /AOO41X/main/sw/source/core/txtnode/fmtatr2.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 "hintids.hxx"
28 #include "unomid.h"
29 
30 #include <basic/sbxvar.hxx>
31 #include <svl/macitem.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/stylepool.hxx>
34 #include <fmtautofmt.hxx>
35 #include <fchrfmt.hxx>
36 #include <fmtinfmt.hxx>
37 #include <txtatr.hxx>
38 #include <fmtruby.hxx>
39 #include <charfmt.hxx>
40 #include <hints.hxx>        // SwUpdateAttr
41 #include <unostyle.hxx>
42 #include <unoevent.hxx>     // SwHyperlinkEventDescriptor
43 #include <com/sun/star/text/RubyAdjust.hdl>
44 
45 #include <cmdid.h>
46 #include <com/sun/star/uno/Any.h>
47 #include <SwStyleNameMapper.hxx>
48 
49 #include <fmtmeta.hxx>
50 #include <ndtxt.hxx> // for meta
51 #include <doc.hxx> // for meta
52 #include <unometa.hxx>
53 #include <docsh.hxx>
54 #include <svl/zforlist.hxx> // GetNumberFormat
55 
56 #include <boost/bind.hpp>
57 #include <algorithm>
58 
59 
60 using namespace ::com::sun::star;
61 using ::rtl::OUString;
62 
63 TYPEINIT1_AUTOFACTORY(SwFmtINetFmt, SfxPoolItem);
64 TYPEINIT1_AUTOFACTORY(SwFmtAutoFmt, SfxPoolItem);
65 
66 /*************************************************************************
67 |*
68 |*    class SwFmtCharFmt
69 |*    Beschreibung
70 |*    Ersterstellung    JP 23.11.90
71 |*    Letzte Aenderung  JP 09.08.94
72 |*
73 *************************************************************************/
74 
75 SwFmtCharFmt::SwFmtCharFmt( SwCharFmt *pFmt )
76     : SfxPoolItem( RES_TXTATR_CHARFMT ),
77     SwClient(pFmt),
78     pTxtAttr( 0 )
79 {
80 }
81 
82 
83 
84 SwFmtCharFmt::SwFmtCharFmt( const SwFmtCharFmt& rAttr )
85     : SfxPoolItem( RES_TXTATR_CHARFMT ),
86     SwClient( rAttr.GetCharFmt() ),
87     pTxtAttr( 0 )
88 {
89 }
90 
91 
92 
93 SwFmtCharFmt::~SwFmtCharFmt() {}
94 
95 
96 
97 int SwFmtCharFmt::operator==( const SfxPoolItem& rAttr ) const
98 {
99     ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
100     return GetCharFmt() == ((SwFmtCharFmt&)rAttr).GetCharFmt();
101 }
102 
103 
104 
105 SfxPoolItem* SwFmtCharFmt::Clone( SfxItemPool* ) const
106 {
107     return new SwFmtCharFmt( *this );
108 }
109 
110 
111 
112 // weiterleiten an das TextAttribut
113 void SwFmtCharFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
114 {
115     if( pTxtAttr )
116         pTxtAttr->ModifyNotification( pOld, pNew );
117 }
118 
119 
120 
121 // weiterleiten an das TextAttribut
122 sal_Bool SwFmtCharFmt::GetInfo( SfxPoolItem& rInfo ) const
123 {
124     return pTxtAttr ? pTxtAttr->GetInfo( rInfo ) : sal_False;
125 }
126 sal_Bool SwFmtCharFmt::QueryValue( uno::Any& rVal, sal_uInt8 ) const
127 {
128     String sCharFmtName;
129     if(GetCharFmt())
130         SwStyleNameMapper::FillProgName(GetCharFmt()->GetName(), sCharFmtName,  nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
131     rVal <<= OUString( sCharFmtName );
132     return sal_True;
133 }
134 sal_Bool SwFmtCharFmt::PutValue( const uno::Any& , sal_uInt8   )
135 {
136     DBG_ERROR("Zeichenvorlage kann mit PutValue nicht gesetzt werden!");
137     return sal_False;
138 }
139 
140 /*************************************************************************
141 |*
142 |*    class SwFmtAutoFmt
143 |*    Beschreibung
144 |*    Ersterstellung    AMA 12.05.06
145 |*    Letzte Aenderung  AMA 12.05.06
146 |*
147 *************************************************************************/
148 
149 SwFmtAutoFmt::SwFmtAutoFmt( sal_uInt16 nInitWhich )
150     : SfxPoolItem( nInitWhich )
151 {
152 }
153 
154 SwFmtAutoFmt::SwFmtAutoFmt( const SwFmtAutoFmt& rAttr )
155     : SfxPoolItem( rAttr.Which() ), mpHandle( rAttr.mpHandle )
156 {
157 }
158 
159 SwFmtAutoFmt::~SwFmtAutoFmt()
160 {
161 }
162 
163 int SwFmtAutoFmt::operator==( const SfxPoolItem& rAttr ) const
164 {
165     ASSERT( SfxPoolItem::operator==( rAttr ), "different attributes" );
166     return mpHandle == ((SwFmtAutoFmt&)rAttr).mpHandle;
167 }
168 
169 SfxPoolItem* SwFmtAutoFmt::Clone( SfxItemPool* ) const
170 {
171     return new SwFmtAutoFmt( *this );
172 }
173 
174 sal_Bool SwFmtAutoFmt::QueryValue( uno::Any& rVal, sal_uInt8 ) const
175 {
176     String sCharFmtName = StylePool::nameOf( mpHandle );
177     rVal <<= OUString( sCharFmtName );
178     return sal_True;
179 }
180 
181 sal_Bool SwFmtAutoFmt::PutValue( const uno::Any& , sal_uInt8 )
182 {
183     //the format is not renameable via API
184     return sal_False;
185 }
186 
187 /*************************************************************************
188 |*
189 |*    class SwFmtINetFmt
190 |*    Beschreibung
191 |*    Ersterstellung    AMA 02.08.96
192 |*    Letzte Aenderung  AMA 02.08.96
193 |*
194 *************************************************************************/
195 
196 SwFmtINetFmt::SwFmtINetFmt()
197     : SfxPoolItem( RES_TXTATR_INETFMT ),
198     pMacroTbl( 0 ),
199     pTxtAttr( 0 ),
200     nINetId( 0 ),
201     nVisitedId( 0 )
202 {}
203 
204 SwFmtINetFmt::SwFmtINetFmt( const XubString& rURL, const XubString& rTarget )
205     : SfxPoolItem( RES_TXTATR_INETFMT ),
206     aURL( rURL ),
207     aTargetFrame( rTarget ),
208     pMacroTbl( 0 ),
209     pTxtAttr( 0 ),
210     nINetId( 0 ),
211     nVisitedId( 0 )
212 {
213 }
214 
215 SwFmtINetFmt::SwFmtINetFmt( const SwFmtINetFmt& rAttr )
216     : SfxPoolItem( RES_TXTATR_INETFMT ),
217     aURL( rAttr.GetValue() ),
218     aTargetFrame( rAttr.aTargetFrame ),
219     aINetFmt( rAttr.aINetFmt ),
220     aVisitedFmt( rAttr.aVisitedFmt ),
221     aName( rAttr.aName ),
222     pMacroTbl( 0 ),
223     pTxtAttr( 0 ),
224     nINetId( rAttr.nINetId ),
225     nVisitedId( rAttr.nVisitedId )
226 {
227     if( rAttr.GetMacroTbl() )
228         pMacroTbl = new SvxMacroTableDtor( *rAttr.GetMacroTbl() );
229 }
230 
231 SwFmtINetFmt::~SwFmtINetFmt()
232 {
233     delete pMacroTbl;
234 }
235 
236 
237 
238 int SwFmtINetFmt::operator==( const SfxPoolItem& rAttr ) const
239 {
240     ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
241     sal_Bool bRet = SfxPoolItem::operator==( (SfxPoolItem&) rAttr )
242                 && aURL == ((SwFmtINetFmt&)rAttr).aURL
243                 && aName == ((SwFmtINetFmt&)rAttr).aName
244                 && aTargetFrame == ((SwFmtINetFmt&)rAttr).aTargetFrame
245                 && aINetFmt == ((SwFmtINetFmt&)rAttr).aINetFmt
246                 && aVisitedFmt == ((SwFmtINetFmt&)rAttr).aVisitedFmt
247                 && nINetId == ((SwFmtINetFmt&)rAttr).nINetId
248                 && nVisitedId == ((SwFmtINetFmt&)rAttr).nVisitedId;
249 
250     if( !bRet )
251         return sal_False;
252 
253     const SvxMacroTableDtor* pOther = ((SwFmtINetFmt&)rAttr).pMacroTbl;
254     if( !pMacroTbl )
255         return ( !pOther || !pOther->Count() );
256     if( !pOther )
257         return 0 == pMacroTbl->Count();
258 
259     const SvxMacroTableDtor& rOwn = *pMacroTbl;
260     const SvxMacroTableDtor& rOther = *pOther;
261 
262     // Anzahl unterschiedlich => auf jeden Fall ungleich
263     if( rOwn.Count() != rOther.Count() )
264         return sal_False;
265 
266     // einzeln vergleichen; wegen Performance ist die Reihenfolge wichtig
267     for( sal_uInt16 nNo = 0; nNo < rOwn.Count(); ++nNo )
268     {
269         const SvxMacro *pOwnMac = rOwn.GetObject(nNo);
270         const SvxMacro *pOtherMac = rOther.GetObject(nNo);
271         if (    rOwn.GetKey(pOwnMac) != rOther.GetKey(pOtherMac)  ||
272                 pOwnMac->GetLibName() != pOtherMac->GetLibName() ||
273                 pOwnMac->GetMacName() != pOtherMac->GetMacName() )
274             return sal_False;
275     }
276     return sal_True;
277 }
278 
279 
280 
281 SfxPoolItem* SwFmtINetFmt::Clone( SfxItemPool* ) const
282 {
283     return new SwFmtINetFmt( *this );
284 }
285 
286 
287 
288 void SwFmtINetFmt::SetMacroTbl( const SvxMacroTableDtor* pNewTbl )
289 {
290     if( pNewTbl )
291     {
292         if( pMacroTbl )
293             *pMacroTbl = *pNewTbl;
294         else
295             pMacroTbl = new SvxMacroTableDtor( *pNewTbl );
296     }
297     else if( pMacroTbl )
298         delete pMacroTbl, pMacroTbl = 0;
299 }
300 
301 
302 
303 void SwFmtINetFmt::SetMacro( sal_uInt16 nEvent, const SvxMacro& rMacro )
304 {
305     if( !pMacroTbl )
306         pMacroTbl = new SvxMacroTableDtor;
307 
308     SvxMacro *pOldMacro;
309     if( 0 != ( pOldMacro = pMacroTbl->Get( nEvent )) )
310     {
311         delete pOldMacro;
312         pMacroTbl->Replace( nEvent, new SvxMacro( rMacro ) );
313     }
314     else
315         pMacroTbl->Insert( nEvent, new SvxMacro( rMacro ) );
316 }
317 
318 
319 
320 const SvxMacro* SwFmtINetFmt::GetMacro( sal_uInt16 nEvent ) const
321 {
322     const SvxMacro* pRet = 0;
323     if( pMacroTbl && pMacroTbl->IsKeyValid( nEvent ) )
324         pRet = pMacroTbl->Get( nEvent );
325     return pRet;
326 }
327 
328 
329 
330 sal_Bool SwFmtINetFmt::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
331 {
332     sal_Bool bRet = sal_True;
333     XubString sVal;
334     nMemberId &= ~CONVERT_TWIPS;
335     switch(nMemberId)
336     {
337         case MID_URL_URL:
338             sVal = aURL;
339         break;
340         case MID_URL_TARGET:
341             sVal = aTargetFrame;
342         break;
343         case MID_URL_HYPERLINKNAME:
344             sVal = aName;
345         break;
346         case MID_URL_VISITED_FMT:
347             sVal = aVisitedFmt;
348             if( !sVal.Len() && nVisitedId != 0 )
349                 SwStyleNameMapper::FillUIName( nVisitedId, sVal );
350             if( sVal.Len() )
351                 SwStyleNameMapper::FillProgName( sVal, sVal, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
352         break;
353         case MID_URL_UNVISITED_FMT:
354             sVal = aINetFmt;
355             if( !sVal.Len() && nINetId != 0 )
356                 SwStyleNameMapper::FillUIName( nINetId, sVal );
357             if( sVal.Len() )
358                 SwStyleNameMapper::FillProgName( sVal, sVal, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
359         break;
360         case MID_URL_HYPERLINKEVENTS:
361         {
362             // create (and return) event descriptor
363             SwHyperlinkEventDescriptor* pEvents =
364                 new SwHyperlinkEventDescriptor();
365             pEvents->copyMacrosFromINetFmt(*this);
366             uno::Reference<container::XNameReplace> xNameReplace(pEvents);
367 
368             // all others return a string; so we just set rVal here and exit
369             rVal <<= xNameReplace;
370             return bRet;
371         }
372         default:
373         break;
374     }
375     rVal <<= OUString(sVal);
376     return bRet;
377 }
378 sal_Bool SwFmtINetFmt::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId  )
379 {
380     sal_Bool bRet = sal_True;
381     nMemberId &= ~CONVERT_TWIPS;
382 
383     // all properties except HyperlinkEvents are of type string, hence
384     // we treat HyperlinkEvents specially
385     if (MID_URL_HYPERLINKEVENTS == nMemberId)
386     {
387         uno::Reference<container::XNameReplace> xReplace;
388         rVal >>= xReplace;
389         if (xReplace.is())
390         {
391             // Create hyperlink event descriptor. Then copy events
392             // from argument into descriptor. Then copy events from
393             // the descriptor into the format.
394             SwHyperlinkEventDescriptor* pEvents = new SwHyperlinkEventDescriptor();
395             uno::Reference< lang::XServiceInfo> xHold = pEvents;
396             pEvents->copyMacrosFromNameReplace(xReplace);
397             pEvents->copyMacrosIntoINetFmt(*this);
398         }
399         else
400         {
401             // wrong type!
402             bRet = sal_False;
403         }
404     }
405     else
406     {
407         // all string properties:
408         if(rVal.getValueType() != ::getCppuType((rtl::OUString*)0))
409             return sal_False;
410         XubString sVal = *(rtl::OUString*)rVal.getValue();
411         switch(nMemberId)
412         {
413             case MID_URL_URL:
414                 aURL = sVal;
415                 break;
416             case MID_URL_TARGET:
417                 aTargetFrame = sVal;
418                 break;
419             case MID_URL_HYPERLINKNAME:
420                 aName = sVal;
421                 break;
422             case MID_URL_VISITED_FMT:
423             {
424                 String aString;
425                 SwStyleNameMapper::FillUIName( sVal, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
426                 aVisitedFmt = OUString ( aString );
427                 nVisitedId = SwStyleNameMapper::GetPoolIdFromUIName( aVisitedFmt,
428                                                nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
429             }
430             break;
431             case MID_URL_UNVISITED_FMT:
432             {
433                 String aString;
434                 SwStyleNameMapper::FillUIName( sVal, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
435                 aINetFmt = OUString ( aString );
436                 nINetId = SwStyleNameMapper::GetPoolIdFromUIName( aINetFmt, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
437             }
438             break;
439             default:
440                 bRet = sal_False;
441         }
442     }
443     return bRet;
444 }
445 
446 
447 /*************************************************************************
448 |*    class SwFmtRuby
449 *************************************************************************/
450 
451 SwFmtRuby::SwFmtRuby( const String& rRubyTxt )
452     : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
453     sRubyTxt( rRubyTxt ),
454     pTxtAttr( 0 ),
455     nCharFmtId( 0 ),
456     nPosition( 0 ),
457     nAdjustment( 0 )
458 {
459 }
460 
461 SwFmtRuby::SwFmtRuby( const SwFmtRuby& rAttr )
462     : SfxPoolItem( RES_TXTATR_CJK_RUBY ),
463     sRubyTxt( rAttr.sRubyTxt ),
464     sCharFmtName( rAttr.sCharFmtName ),
465     pTxtAttr( 0 ),
466     nCharFmtId( rAttr.nCharFmtId),
467     nPosition( rAttr.nPosition ),
468     nAdjustment( rAttr.nAdjustment )
469 {
470 }
471 
472 SwFmtRuby::~SwFmtRuby()
473 {
474 }
475 
476 SwFmtRuby& SwFmtRuby::operator=( const SwFmtRuby& rAttr )
477 {
478     sRubyTxt = rAttr.sRubyTxt;
479     sCharFmtName = rAttr.sCharFmtName;
480     nCharFmtId = rAttr.nCharFmtId;
481     nPosition = rAttr.nPosition;
482     nAdjustment = rAttr.nAdjustment;
483     pTxtAttr =  0;
484     return *this;
485 }
486 
487 int SwFmtRuby::operator==( const SfxPoolItem& rAttr ) const
488 {
489     ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
490     return sRubyTxt == ((SwFmtRuby&)rAttr).sRubyTxt &&
491            sCharFmtName == ((SwFmtRuby&)rAttr).sCharFmtName &&
492            nCharFmtId == ((SwFmtRuby&)rAttr).nCharFmtId &&
493            nPosition == ((SwFmtRuby&)rAttr).nPosition &&
494            nAdjustment == ((SwFmtRuby&)rAttr).nAdjustment;
495 }
496 
497 SfxPoolItem* SwFmtRuby::Clone( SfxItemPool* ) const
498 {
499     return new SwFmtRuby( *this );
500 }
501 
502 sal_Bool SwFmtRuby::QueryValue( uno::Any& rVal,
503                             sal_uInt8 nMemberId ) const
504 {
505     sal_Bool bRet = sal_True;
506     nMemberId &= ~CONVERT_TWIPS;
507     switch( nMemberId )
508     {
509         case MID_RUBY_TEXT: rVal <<= (OUString)sRubyTxt;                    break;
510         case MID_RUBY_ADJUST:   rVal <<= (sal_Int16)nAdjustment;    break;
511         case MID_RUBY_CHARSTYLE:
512         {
513             String aString;
514             SwStyleNameMapper::FillProgName(sCharFmtName, aString, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT, sal_True );
515             rVal <<= OUString ( aString );
516         }
517         break;
518         case MID_RUBY_ABOVE:
519         {
520             sal_Bool bAbove = !nPosition;
521             rVal.setValue(&bAbove, ::getBooleanCppuType());
522         }
523         break;
524         default:
525             bRet = sal_False;
526     }
527     return bRet;
528 }
529 sal_Bool SwFmtRuby::PutValue( const uno::Any& rVal,
530                             sal_uInt8 nMemberId  )
531 {
532     sal_Bool bRet = sal_True;
533     nMemberId &= ~CONVERT_TWIPS;
534     switch( nMemberId )
535     {
536         case MID_RUBY_TEXT:
537         {
538             OUString sTmp;
539             bRet = rVal >>= sTmp;
540             sRubyTxt = sTmp;
541         }
542         break;
543         case MID_RUBY_ADJUST:
544         {
545             sal_Int16 nSet = 0;
546             rVal >>= nSet;
547             if(nSet >= 0 && nSet <= text::RubyAdjust_INDENT_BLOCK)
548                 nAdjustment = nSet;
549             else
550                 bRet = sal_False;
551         }
552         break;
553         case MID_RUBY_ABOVE:
554         {
555             const uno::Type& rType = ::getBooleanCppuType();
556             if(rVal.hasValue() && rVal.getValueType() == rType)
557             {
558                 sal_Bool bAbove = *(sal_Bool*)rVal.getValue();
559                 nPosition = bAbove ? 0 : 1;
560             }
561         }
562         break;
563         case MID_RUBY_CHARSTYLE:
564         {
565             OUString sTmp;
566             bRet = rVal >>= sTmp;
567             if(bRet)
568                 sCharFmtName = SwStyleNameMapper::GetUIName(sTmp, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT );
569         }
570         break;
571         default:
572             bRet = sal_False;
573     }
574     return bRet;
575 }
576 
577 
578 /*************************************************************************
579  class SwFmtMeta
580  ************************************************************************/
581 
582 SwFmtMeta * SwFmtMeta::CreatePoolDefault(const sal_uInt16 i_nWhich)
583 {
584     return new SwFmtMeta(i_nWhich);
585 }
586 
587 SwFmtMeta::SwFmtMeta(const sal_uInt16 i_nWhich)
588     : SfxPoolItem( i_nWhich )
589     , m_pMeta()
590     , m_pTxtAttr( 0 )
591 {
592     ASSERT((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
593             "ERROR: SwFmtMeta: invalid which id!");
594 }
595 
596 SwFmtMeta::SwFmtMeta( ::boost::shared_ptr< ::sw::Meta > const & i_pMeta,
597                         const sal_uInt16 i_nWhich )
598     : SfxPoolItem( i_nWhich )
599     , m_pMeta( i_pMeta )
600     , m_pTxtAttr( 0 )
601 {
602     ASSERT((RES_TXTATR_META == i_nWhich) || (RES_TXTATR_METAFIELD == i_nWhich),
603             "ERROR: SwFmtMeta: invalid which id!");
604     ASSERT(m_pMeta, "SwFmtMeta: no Meta ?");
605     // DO NOT call m_pMeta->SetFmtMeta(this) here; only from SetTxtAttr!
606 }
607 
608 SwFmtMeta::~SwFmtMeta()
609 {
610     if (m_pMeta && (m_pMeta->GetFmtMeta() == this))
611     {
612         NotifyChangeTxtNode(0);
613         m_pMeta->SetFmtMeta(0);
614     }
615 }
616 
617 int SwFmtMeta::operator==( const SfxPoolItem & i_rOther ) const
618 {
619     ASSERT( SfxPoolItem::operator==( i_rOther ), "i just copied this assert" );
620     return SfxPoolItem::operator==( i_rOther )
621         && (m_pMeta == static_cast<SwFmtMeta const &>( i_rOther ).m_pMeta);
622 }
623 
624 SfxPoolItem * SwFmtMeta::Clone( SfxItemPool * /*pPool*/ ) const
625 {
626     // if this is indeed a copy, then DoCopy must be called later!
627     return (m_pMeta) // #i105148# pool default may be cloned also!
628         ? new SwFmtMeta( m_pMeta, Which() ) : new SwFmtMeta( Which() );
629 }
630 
631 void SwFmtMeta::SetTxtAttr(SwTxtMeta * const i_pTxtAttr)
632 {
633     OSL_ENSURE(!(m_pTxtAttr && i_pTxtAttr),
634         "SwFmtMeta::SetTxtAttr: already has text attribute?");
635     OSL_ENSURE(  m_pTxtAttr || i_pTxtAttr ,
636         "SwFmtMeta::SetTxtAttr: no attribute to remove?");
637     m_pTxtAttr = i_pTxtAttr;
638     OSL_ENSURE(m_pMeta, "inserted SwFmtMeta has no sw::Meta?");
639     // the sw::Meta must be able to find the current text attribute!
640     if (m_pMeta)
641     {
642         if (i_pTxtAttr)
643         {
644             m_pMeta->SetFmtMeta(this);
645         }
646         else if (m_pMeta->GetFmtMeta() == this)
647         {   // text attribute gone => de-register from text node!
648             NotifyChangeTxtNode(0);
649             m_pMeta->SetFmtMeta(0);
650         }
651     }
652 }
653 
654 void SwFmtMeta::NotifyChangeTxtNode(SwTxtNode *const pTxtNode)
655 {
656     // N.B.: do not reset m_pTxtAttr here: see call in nodes.cxx,
657     // where the hint is not deleted!
658     OSL_ENSURE(m_pMeta, "SwFmtMeta::NotifyChangeTxtNode: no Meta?");
659     if (m_pMeta && (m_pMeta->GetFmtMeta() == this))
660     {   // do not call Modify, that would call SwXMeta::Modify!
661         m_pMeta->NotifyChangeTxtNode(pTxtNode);
662     }
663 }
664 
665 // this SwFmtMeta has been cloned and points at the same sw::Meta as the source
666 // this method copies the sw::Meta
667 void SwFmtMeta::DoCopy(::sw::MetaFieldManager & i_rTargetDocManager,
668         SwTxtNode & i_rTargetTxtNode)
669 {
670     OSL_ENSURE(m_pMeta, "DoCopy called for SwFmtMeta with no sw::Meta?");
671     if (m_pMeta)
672     {
673         const ::boost::shared_ptr< ::sw::Meta> pOriginal( m_pMeta );
674         if (RES_TXTATR_META == Which())
675         {
676             m_pMeta.reset( new ::sw::Meta(this) );
677         }
678         else
679         {
680             ::sw::MetaField *const pMetaField(
681                 static_cast< ::sw::MetaField* >(pOriginal.get()));
682             m_pMeta = i_rTargetDocManager.makeMetaField( this,
683                 pMetaField->m_nNumberFormat, pMetaField->IsFixedLanguage() );
684         }
685         // Meta must have a text node before calling RegisterAsCopyOf
686         m_pMeta->NotifyChangeTxtNode(& i_rTargetTxtNode);
687         // this cannot be done in Clone: a Clone is not necessarily a copy!
688         m_pMeta->RegisterAsCopyOf(*pOriginal);
689     }
690 }
691 
692 
693 namespace sw {
694 
695 /*************************************************************************
696  class sw::Meta
697  ************************************************************************/
698 
699 Meta::Meta(SwFmtMeta * const i_pFmt)
700     : ::sfx2::Metadatable()
701     , SwModify()
702     , m_pFmt( i_pFmt )
703 {
704 }
705 
706 Meta::~Meta()
707 {
708 }
709 
710 SwTxtMeta * Meta::GetTxtAttr() const
711 {
712     return (m_pFmt) ? m_pFmt->GetTxtAttr() : 0;
713 }
714 
715 SwTxtNode * Meta::GetTxtNode() const
716 {
717     return m_pTxtNode;
718 }
719 
720 void Meta::NotifyChangeTxtNodeImpl()
721 {
722     if (m_pTxtNode && (GetRegisteredIn() != m_pTxtNode))
723     {
724         m_pTxtNode->Add(this);
725     }
726     else if (!m_pTxtNode && GetRegisteredIn())
727     {
728         GetRegisteredInNonConst()->Remove(this);
729     }
730 }
731 
732 void Meta::NotifyChangeTxtNode(SwTxtNode *const pTxtNode)
733 {
734     m_pTxtNode = pTxtNode;
735     NotifyChangeTxtNodeImpl();
736     if (!pTxtNode) // text node gone? invalidate UNO object!
737     {
738         SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
739             &static_cast<SwModify&>(*this) ); // cast to base class!
740         this->Modify(&aMsgHint, &aMsgHint);
741     }
742 }
743 
744 // SwClient
745 void Meta::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
746 {
747     NotifyClients(pOld, pNew);
748     if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
749     {   // invalidate cached uno object
750         SetXMeta(uno::Reference<rdf::XMetadatable>(0));
751     }
752 }
753 
754 // sfx2::Metadatable
755 ::sfx2::IXmlIdRegistry& Meta::GetRegistry()
756 {
757     SwTxtNode * const pTxtNode( GetTxtNode() );
758     // GetRegistry may only be called on a meta that is actually in the
759     // document, which means it has a pointer to its text node
760     OSL_ENSURE(pTxtNode, "ERROR: GetRegistry: no text node?");
761     if (!pTxtNode)
762         throw uno::RuntimeException();
763     return pTxtNode->GetRegistry();
764 }
765 
766 bool Meta::IsInClipboard() const
767 {
768     const SwTxtNode * const pTxtNode( GetTxtNode() );
769 // no text node: in UNDO  OSL_ENSURE(pTxtNode, "IsInClipboard: no text node?");
770     return (pTxtNode) ? pTxtNode->IsInClipboard() : false;
771 }
772 
773 bool Meta::IsInUndo() const
774 {
775     const SwTxtNode * const pTxtNode( GetTxtNode() );
776 // no text node: in UNDO  OSL_ENSURE(pTxtNode, "IsInUndo: no text node?");
777     return (pTxtNode) ? pTxtNode->IsInUndo() : true;
778 }
779 
780 bool Meta::IsInContent() const
781 {
782     const SwTxtNode * const pTxtNode( GetTxtNode() );
783     OSL_ENSURE(pTxtNode, "IsInContent: no text node?");
784     return (pTxtNode) ? pTxtNode->IsInContent() : true;
785 }
786 
787 ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XMetadatable >
788 Meta::MakeUnoObject()
789 {
790     return SwXMeta::CreateXMeta(*this);
791 }
792 
793 /*************************************************************************
794  class sw::MetaField
795  ************************************************************************/
796 
797 MetaField::MetaField(SwFmtMeta * const i_pFmt,
798             const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
799     : Meta(i_pFmt)
800     , m_nNumberFormat( nNumberFormat )
801     , m_bIsFixedLanguage( bIsFixedLanguage )
802 {
803 }
804 
805 void MetaField::GetPrefixAndSuffix(
806         ::rtl::OUString *const o_pPrefix, ::rtl::OUString *const o_pSuffix)
807 {
808     try
809     {
810         const uno::Reference<rdf::XMetadatable> xMetaField( MakeUnoObject() );
811         OSL_ENSURE(dynamic_cast<SwXMetaField*>(xMetaField.get()),
812                 "GetPrefixAndSuffix: no SwXMetaField?");
813         if (xMetaField.is())
814         {
815             SwTxtNode * const pTxtNode( GetTxtNode() );
816             SwDocShell const * const pShell(pTxtNode->GetDoc()->GetDocShell());
817             const uno::Reference<frame::XModel> xModel(
818                 (pShell) ? pShell->GetModel() : 0,  uno::UNO_SET_THROW);
819             getPrefixAndSuffix(xModel, xMetaField, o_pPrefix, o_pSuffix);
820         }
821     } catch (uno::Exception) {
822         OSL_ENSURE(false, "exception?");
823     }
824 }
825 
826 sal_uInt32 MetaField::GetNumberFormat(::rtl::OUString const & rContent) const
827 {
828     //TODO: this probably lacks treatment for some special cases
829     sal_uInt32 nNumberFormat( m_nNumberFormat );
830     SwTxtNode * const pTxtNode( GetTxtNode() );
831     if (pTxtNode)
832     {
833         SvNumberFormatter *const pNumberFormatter(
834                 pTxtNode->GetDoc()->GetNumberFormatter() );
835         double number;
836         (void) pNumberFormatter->IsNumberFormat(
837                 rContent, nNumberFormat, number );
838     }
839     return nNumberFormat;
840 }
841 
842 void MetaField::SetNumberFormat(sal_uInt32 nNumberFormat)
843 {
844     // effectively, the member is only a default:
845     // GetNumberFormat checks if the text actually conforms
846     m_nNumberFormat = nNumberFormat;
847 }
848 
849 
850 /*************************************************************************
851  class sw::MetaFieldManager
852  ************************************************************************/
853 
854 
855 MetaFieldManager::MetaFieldManager()
856 {
857 }
858 
859 ::boost::shared_ptr<MetaField>
860 MetaFieldManager::makeMetaField(SwFmtMeta * const i_pFmt,
861         const sal_uInt32 nNumberFormat, const bool bIsFixedLanguage)
862 {
863     const ::boost::shared_ptr<MetaField> pMetaField(
864         new MetaField(i_pFmt, nNumberFormat, bIsFixedLanguage) );
865     m_MetaFields.push_back(pMetaField);
866     return pMetaField;
867 }
868 
869 struct IsInUndo
870 {
871     bool operator()(::boost::weak_ptr<MetaField> const & pMetaField) {
872         return pMetaField.lock()->IsInUndo();
873     }
874 };
875 
876 struct MakeUnoObject
877 {
878     uno::Reference<text::XTextField>
879     operator()(::boost::weak_ptr<MetaField> const & pMetaField) {
880         return uno::Reference<text::XTextField>(
881                 pMetaField.lock()->MakeUnoObject(), uno::UNO_QUERY);
882     }
883 };
884 
885 ::std::vector< uno::Reference<text::XTextField> >
886 MetaFieldManager::getMetaFields()
887 {
888     // erase deleted fields
889     const MetaFieldList_t::iterator iter(
890         ::std::remove_if(m_MetaFields.begin(), m_MetaFields.end(),
891             ::boost::bind(&::boost::weak_ptr<MetaField>::expired, _1)));
892     m_MetaFields.erase(iter, m_MetaFields.end());
893     // filter out fields in UNDO
894     MetaFieldList_t filtered(m_MetaFields.size());
895     const MetaFieldList_t::iterator iter2(
896     ::std::remove_copy_if(m_MetaFields.begin(), m_MetaFields.end(),
897         filtered.begin(), IsInUndo()));
898     filtered.erase(iter2, filtered.end());
899     // create uno objects
900     ::std::vector< uno::Reference<text::XTextField> > ret(filtered.size());
901     ::std::transform(filtered.begin(), filtered.end(), ret.begin(),
902             MakeUnoObject());
903     return ret;
904 }
905 
906 } // namespace sw
907 
908 
909