xref: /aoo41x/main/sw/source/core/txtnode/atrfld.cxx (revision 69a74367)
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 "fldbas.hxx"          // fuer FieldType
28 #include <fmtfld.hxx>
29 #include <txtfld.hxx>
30 #include <docufld.hxx>
31 #include <doc.hxx>
32 
33 #include "reffld.hxx"
34 #include "ddefld.hxx"
35 #include "usrfld.hxx"
36 #include "expfld.hxx"
37 #include "swfont.hxx"       // fuer GetFldsColor
38 #include "ndtxt.hxx"        // SwTxtNode
39 #include "calc.hxx"         // Update fuer UserFields
40 #include "hints.hxx"
41 #include <IDocumentFieldsAccess.hxx>
42 #include <fieldhint.hxx>
43 #include <svl/smplhint.hxx>
44 
45 TYPEINIT3( SwFmtFld, SfxPoolItem, SwClient,SfxBroadcaster)
46 TYPEINIT1(SwFmtFldHint, SfxHint);
47 
48 /****************************************************************************
49  *
50  *  class SwFmtFld
51  *
52  ****************************************************************************/
53 
54 // constructor for default item in attribute-pool
55 SwFmtFld::SwFmtFld( sal_uInt16 nWhich )
56     : SfxPoolItem( nWhich )
57     , SwClient()
58     , SfxBroadcaster()
59     , mpField( NULL )
60     , mpTxtFld( NULL )
61 {
62 }
63 
64 SwFmtFld::SwFmtFld( const SwField &rFld )
65     : SfxPoolItem( RES_TXTATR_FIELD )
66     , SwClient( rFld.GetTyp() )
67     , SfxBroadcaster()
68     , mpField( rFld.CopyField() )
69     , mpTxtFld( NULL )
70 {
71     // input field in-place editing
72     if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
73     {
74         SetWhich( RES_TXTATR_INPUTFIELD );
75         dynamic_cast<SwInputField*>(GetField())->SetFmtFld( *this );
76     }
77 }
78 
79 // #i24434#
80 // Since Items are used in ItemPool and in default constructed ItemSets with
81 // full pool range, all items need to be clonable. Thus, this one needed to be
82 // corrected
83 SwFmtFld::SwFmtFld( const SwFmtFld& rAttr )
84     : SfxPoolItem( RES_TXTATR_FIELD )
85     , SwClient()
86     , SfxBroadcaster()
87     , mpField( NULL )
88     , mpTxtFld( NULL )
89 {
90     if ( rAttr.GetField() )
91     {
92         rAttr.GetField()->GetTyp()->Add(this);
93         mpField = rAttr.GetField()->CopyField();
94         // input field in-place editing
95         if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
96         {
97             SetWhich( RES_TXTATR_INPUTFIELD );
98             dynamic_cast<SwInputField*>(GetField())->SetFmtFld( *this );
99         }
100     }
101 }
102 
103 SwFmtFld::~SwFmtFld()
104 {
105 	SwFieldType* pType = mpField ? mpField->GetTyp() : 0;
106 
107 	if (pType && pType->Which() == RES_DBFLD)
108 		pType = 0;	// DB-Feldtypen zerstoeren sich selbst
109 
110 	Broadcast( SwFmtFldHint( this, SWFMTFLD_REMOVED ) );
111 	delete mpField;
112 
113 	// bei einige FeldTypen muessen wir den FeldTypen noch loeschen
114 	if( pType && pType->IsLastDepend() )
115 	{
116 		sal_Bool bDel = sal_False;
117 		switch( pType->Which() )
118 		{
119 		case RES_USERFLD:
120 			bDel = ((SwUserFieldType*)pType)->IsDeleted();
121 			break;
122 
123 		case RES_SETEXPFLD:
124 			bDel = ((SwSetExpFieldType*)pType)->IsDeleted();
125 			break;
126 
127 		case RES_DDEFLD:
128 			bDel = ((SwDDEFieldType*)pType)->IsDeleted();
129 			break;
130 		}
131 
132 		if( bDel )
133 		{
134 			// vorm loeschen erstmal austragen
135 			pType->Remove( this );
136 			delete pType;
137 		}
138 	}
139 }
140 
141 void SwFmtFld::RegisterToFieldType( SwFieldType& rType )
142 {
143     rType.Add(this);
144 }
145 
146 
147 // #111840#
148 void SwFmtFld::SetField(SwField * _pField)
149 {
150     if (NULL != mpField)
151         delete mpField;
152 
153     mpField = _pField;
154     if ( GetField()->GetTyp()->Which() == RES_INPUTFLD )
155     {
156         dynamic_cast<SwInputField* >(GetField())->SetFmtFld( *this );
157     }
158     Broadcast( SwFmtFldHint( this, SWFMTFLD_CHANGED ) );
159 }
160 
161 void SwFmtFld::SetTxtFld( SwTxtFld& rTxtFld )
162 {
163     mpTxtFld = &rTxtFld;
164 }
165 
166 void SwFmtFld::ClearTxtFld()
167 {
168     mpTxtFld = NULL;
169 }
170 
171 int SwFmtFld::operator==( const SfxPoolItem& rAttr ) const
172 {
173 	ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
174     return ( ( mpField && ((SwFmtFld&)rAttr).GetField()
175                && mpField->GetTyp() == ((SwFmtFld&)rAttr).GetField()->GetTyp()
176                && mpField->GetFormat() == ((SwFmtFld&)rAttr).GetField()->GetFormat() ) )
177              || ( !mpField && !((SwFmtFld&)rAttr).GetField() );
178 }
179 
180 SfxPoolItem* SwFmtFld::Clone( SfxItemPool* ) const
181 {
182 	return new SwFmtFld( *this );
183 }
184 
185 void SwFmtFld::SwClientNotify( const SwModify&, const SfxHint& rHint )
186 {
187     if( !mpTxtFld )
188         return;
189 
190     const SwFieldHint* pHint = dynamic_cast<const SwFieldHint*>( &rHint );
191     if ( pHint )
192     {
193         // replace field content by text
194         SwPaM* pPaM = pHint->GetPaM();
195         SwDoc* pDoc = pPaM->GetDoc();
196         const SwTxtNode& rTxtNode = mpTxtFld->GetTxtNode();
197         pPaM->GetPoint()->nNode = rTxtNode;
198         pPaM->GetPoint()->nContent.Assign( (SwTxtNode*)&rTxtNode, *mpTxtFld->GetStart() );
199 
200         String const aEntry( GetField()->ExpandField( pDoc->IsClipBoard() ) );
201         pPaM->SetMark();
202         pPaM->Move( fnMoveForward );
203         pDoc->DeleteRange( *pPaM );
204         pDoc->InsertString( *pPaM, aEntry );
205     }
206 }
207 
208 void SwFmtFld::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
209 {
210 	if( !mpTxtFld )
211 		return;
212 
213     // don't do anything, especially not expand!
214     if( pNew && pNew->Which() == RES_OBJECTDYING )
215         return;
216 
217 	SwTxtNode* pTxtNd = (SwTxtNode*)&mpTxtFld->GetTxtNode();
218 	ASSERT( pTxtNd, "wo ist denn mein Node?" );
219 	if( pNew )
220 	{
221 		switch( pNew->Which() )
222 		{
223 		case RES_TXTATR_FLDCHG:
224 				// "Farbe hat sich geaendert !"
225 				// this, this fuer "nur Painten"
226 				pTxtNd->ModifyNotification( this, this );
227 				return;
228 		case RES_REFMARKFLD_UPDATE:
229 				// GetReferenz-Felder aktualisieren
230 				if( RES_GETREFFLD == GetField()->GetTyp()->Which() )
231                 {
232                     // --> OD 2007-09-06 #i81002#
233 //                    ((SwGetRefField*)GetFld())->UpdateField();
234                     dynamic_cast<SwGetRefField*>(GetField())->UpdateField( mpTxtFld );
235                     // <--
236                 }
237 				break;
238 		case RES_DOCPOS_UPDATE:
239 				// Je nach DocPos aktualisieren (SwTxtFrm::Modify())
240 				pTxtNd->ModifyNotification( pNew, this );
241 				return;
242 
243 		case RES_ATTRSET_CHG:
244 		case RES_FMT_CHG:
245 				pTxtNd->ModifyNotification( pOld, pNew );
246 				return;
247         default:
248                 break;
249 		}
250 	}
251 
252 	switch (GetField()->GetTyp()->Which())
253 	{
254 		case RES_HIDDENPARAFLD:
255 			if( !pOld || RES_HIDDENPARA_PRINT != pOld->Which() )
256 				break;
257 		case RES_DBSETNUMBERFLD:
258 		case RES_DBNUMSETFLD:
259 		case RES_DBNEXTSETFLD:
260 		case RES_DBNAMEFLD:
261 			pTxtNd->ModifyNotification( 0, pNew);
262 			return;
263 	}
264 
265 	if( RES_USERFLD == GetField()->GetTyp()->Which() )
266 	{
267 		SwUserFieldType* pType = (SwUserFieldType*)GetField()->GetTyp();
268 		if(!pType->IsValid())
269 		{
270 			SwCalc aCalc( *pTxtNd->GetDoc() );
271 			pType->GetValue( aCalc );
272 		}
273 	}
274 	mpTxtFld->ExpandTxtFld();
275 }
276 
277 sal_Bool SwFmtFld::GetInfo( SfxPoolItem& rInfo ) const
278 {
279 	const SwTxtNode* pTxtNd;
280 	if( RES_AUTOFMT_DOCNODE != rInfo.Which() ||
281 		!mpTxtFld || 0 == ( pTxtNd = mpTxtFld->GetpTxtNode() ) ||
282 		&pTxtNd->GetNodes() != ((SwAutoFmtGetDocNode&)rInfo).pNodes )
283 		return sal_True;
284 
285 	((SwAutoFmtGetDocNode&)rInfo).pCntntNode = pTxtNd;
286 	return sal_False;
287 }
288 
289 
290 bool SwFmtFld::IsFldInDoc() const
291 {
292     return mpTxtFld != NULL
293            && mpTxtFld->IsFldInDoc();
294 }
295 
296 sal_Bool SwFmtFld::IsProtect() const
297 {
298     return mpTxtFld != NULL
299            && mpTxtFld->GetpTxtNode() != NULL
300            && mpTxtFld->GetpTxtNode()->IsProtect();
301 }
302 
303 
304 
305 
306 SwTxtFld::SwTxtFld(
307     SwFmtFld & rAttr,
308     xub_StrLen const nStartPos )
309     : SwTxtAttr( rAttr, nStartPos )
310     , m_aExpand( rAttr.GetField()->ExpandField(true) )
311     , m_pTxtNode( NULL )
312 {
313     rAttr.SetTxtFld( *this );
314     SetHasDummyChar(true);
315 }
316 
317 SwTxtFld::~SwTxtFld( )
318 {
319     SwFmtFld & rFmtFld( static_cast<SwFmtFld &>(GetAttr()) );
320     if ( this == rFmtFld.GetTxtFld() )
321     {
322         rFmtFld.ClearTxtFld();
323     }
324 }
325 
326 
327 bool SwTxtFld::IsFldInDoc() const
328 {
329     return GetpTxtNode() != NULL
330            && GetpTxtNode()->GetNodes().IsDocNodes();
331 }
332 
333 void SwTxtFld::ExpandTxtFld() const
334 {
335     ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
336 
337     const SwField* pFld = GetFmtFld().GetField();
338     const XubString aNewExpand( pFld->ExpandField(m_pTxtNode->GetDoc()->IsClipBoard()) );
339 
340     if( aNewExpand == m_aExpand )
341     {
342         // Bei Seitennummernfeldern
343         const sal_uInt16 nWhich = pFld->GetTyp()->Which();
344         if ( RES_CHAPTERFLD != nWhich
345              && RES_PAGENUMBERFLD != nWhich
346              && RES_REFPAGEGETFLD != nWhich
347              // Page count fields to not use aExpand during formatting,
348              // therefore an invalidation of the text frame has to be triggered even if aNewExpand == aExpand:
349              && ( RES_DOCSTATFLD != nWhich || DS_PAGE != static_cast<const SwDocStatField*>(pFld)->GetSubType() )
350              && ( RES_GETEXPFLD != nWhich || ((SwGetExpField*)pFld)->IsInBodyTxt() ) )
351         {
352             if( m_pTxtNode->CalcHiddenParaField() )
353             {
354                 m_pTxtNode->ModifyNotification( 0, 0 );
355             }
356             return;
357         }
358     }
359 
360     m_aExpand = aNewExpand;
361 
362     const_cast<SwTxtFld*>(this)->NotifyContentChange( const_cast<SwFmtFld&>(GetFmtFld()) );
363 }
364 
365 
366 void SwTxtFld::CopyTxtFld( SwTxtFld *pDest ) const
367 {
368     ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" );
369     ASSERT( pDest->m_pTxtNode, "SwTxtFld: where is pDest's TxtNode?" );
370 
371     IDocumentFieldsAccess* pIDFA = m_pTxtNode->getIDocumentFieldsAccess();
372     IDocumentFieldsAccess* pDestIDFA = pDest->m_pTxtNode->getIDocumentFieldsAccess();
373 
374     SwFmtFld& rDestFmtFld = (SwFmtFld&)pDest->GetFmtFld();
375     const sal_uInt16 nFldWhich = rDestFmtFld.GetField()->GetTyp()->Which();
376 
377     if( pIDFA != pDestIDFA )
378     {
379         // Die Hints stehen in unterschiedlichen Dokumenten,
380         // der Feldtyp muss im neuen Dokument angemeldet werden.
381         // Z.B: Kopieren ins ClipBoard.
382         SwFieldType* pFldType;
383         if( nFldWhich != RES_DBFLD
384             && nFldWhich != RES_USERFLD
385             && nFldWhich != RES_SETEXPFLD
386             && nFldWhich != RES_DDEFLD
387             && RES_AUTHORITY != nFldWhich )
388         {
389             pFldType = pDestIDFA->GetSysFldType( nFldWhich );
390         }
391         else
392         {
393             pFldType = pDestIDFA->InsertFldType( *rDestFmtFld.GetField()->GetTyp() );
394         }
395 
396         // Sonderbehandlung fuer DDE-Felder
397         if( RES_DDEFLD == nFldWhich )
398         {
399             if( rDestFmtFld.GetTxtFld() )
400             {
401                 ((SwDDEFieldType*)rDestFmtFld.GetField()->GetTyp())->DecRefCnt();
402             }
403             ((SwDDEFieldType*)pFldType)->IncRefCnt();
404         }
405 
406         ASSERT( pFldType, "unbekannter FieldType" );
407         pFldType->Add( &rDestFmtFld );          // ummelden
408         rDestFmtFld.GetField()->ChgTyp( pFldType );
409     }
410 
411     // Expressionfelder Updaten
412     if( nFldWhich == RES_SETEXPFLD
413         || nFldWhich == RES_GETEXPFLD
414         || nFldWhich == RES_HIDDENTXTFLD )
415     {
416         SwTxtFld* pFld = (SwTxtFld*)this;
417         pDestIDFA->UpdateExpFlds( pFld, true );
418     }
419     // Tabellenfelder auf externe Darstellung
420     else if( RES_TABLEFLD == nFldWhich
421              && ((SwTblField*)rDestFmtFld.GetField())->IsIntrnlName() )
422     {
423         // erzeuge aus der internen (fuer CORE) die externe (fuer UI) Formel
424         const SwTableNode* pTblNd = m_pTxtNode->FindTableNode();
425         if( pTblNd )		// steht in einer Tabelle
426             ((SwTblField*)rDestFmtFld.GetField())->PtrToBoxNm( &pTblNd->GetTable() );
427     }
428 }
429 
430 
431 void SwTxtFld::NotifyContentChange(SwFmtFld& rFmtFld)
432 {
433     //if not in undo section notify the change
434     if (m_pTxtNode && m_pTxtNode->GetNodes().IsDocNodes())
435     {
436         m_pTxtNode->ModifyNotification(0, &rFmtFld);
437     }
438 }
439 
440 
441 // input field in-place editing
442 SwTxtInputFld::SwTxtInputFld(
443     SwFmtFld & rAttr,
444     xub_StrLen const nStart,
445     xub_StrLen const nEnd )
446 
447     : SwTxtFld( rAttr, nStart )
448     , m_nEnd( nEnd )
449 {
450     SetHasDummyChar( false );
451     SetHasContent( true );
452 
453     SetDontExpand( true );
454     SetLockExpandFlag( true );
455     SetDontExpandStartAttr( true );
456 
457     SetNesting( true );
458 }
459 
460 SwTxtInputFld::~SwTxtInputFld()
461 {
462 }
463 
464 xub_StrLen* SwTxtInputFld::GetEnd()
465 {
466     return &m_nEnd;
467 }
468 
469 void SwTxtInputFld::NotifyContentChange( SwFmtFld& rFmtFld )
470 {
471     SwTxtFld::NotifyContentChange( rFmtFld );
472 
473     UpdateTextNodeContent( GetFieldContent() );
474 }
475 
476 const String SwTxtInputFld::GetFieldContent() const
477 {
478     return GetFmtFld().GetField()->ExpandField(false);
479 }
480 
481 void SwTxtInputFld::UpdateFieldContent()
482 {
483     if ( IsFldInDoc()
484          && (*GetStart()) != (*End()) )
485     {
486         ASSERT( (*End()) - (*GetStart()) >= 2,
487                 "<SwTxtInputFld::UpdateFieldContent()> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
488         // skip CH_TXT_ATR_INPUTFIELDSTART character
489         const xub_StrLen nIdx = (*GetStart()) + 1;
490         // skip CH_TXT_ATR_INPUTFIELDEND character
491         const xub_StrLen nLen = static_cast<xub_StrLen>(std::max( 0, ( (*End()) - 1 - nIdx ) ));
492         const String aNewFieldContent = GetTxtNode().GetExpandTxt( nIdx, nLen );
493 
494         const SwInputField* pInputFld = dynamic_cast<const SwInputField*>(GetFmtFld().GetField());
495         ASSERT( pInputFld != NULL,
496                 "<SwTxtInputFld::GetContent()> - Missing <SwInputFld> instance!" );
497         if ( pInputFld != NULL )
498         {
499             const_cast<SwInputField*>(pInputFld)->applyFieldContent( aNewFieldContent );
500         }
501     }
502 }
503 
504 void SwTxtInputFld::UpdateTextNodeContent( const String& rNewContent )
505 {
506     if ( !IsFldInDoc() )
507     {
508         ASSERT( false, "<SwTxtInputFld::UpdateTextNodeContent(..)> - misusage as Input Field is not in document content." );
509         return;
510     }
511 
512     ASSERT( (*End()) - (*GetStart()) >= 2,
513             "<SwTxtInputFld::UpdateTextNodeContent(..)> - Are CH_TXT_ATR_INPUTFIELDSTART and/or CH_TXT_ATR_INPUTFIELDEND missing?" );
514     // skip CH_TXT_ATR_INPUTFIELDSTART character
515     const xub_StrLen nIdx = (*GetStart()) + 1;
516     // skip CH_TXT_ATR_INPUTFIELDEND character
517     const xub_StrLen nDelLen = static_cast<xub_StrLen>(std::max( 0, ( (*End()) - 1 - nIdx ) ));
518     SwIndex aIdx( &GetTxtNode(), nIdx );
519     GetTxtNode().ReplaceText( aIdx, nDelLen, rNewContent );
520 }
521