1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 #include "fldbas.hxx" // fuer FieldType 32 #include <fmtfld.hxx> 33 #include <txtfld.hxx> 34 #include <docufld.hxx> 35 #include <doc.hxx> 36 37 #include "reffld.hxx" 38 #include "ddefld.hxx" 39 #include "usrfld.hxx" 40 #include "expfld.hxx" 41 #include "swfont.hxx" // fuer GetFldsColor 42 #include "ndtxt.hxx" // SwTxtNode 43 #include "calc.hxx" // Update fuer UserFields 44 #include "hints.hxx" 45 #include <IDocumentFieldsAccess.hxx> 46 #include <fieldhint.hxx> 47 #include <svl/smplhint.hxx> 48 49 TYPEINIT3( SwFmtFld, SfxPoolItem, SwClient,SfxBroadcaster) 50 TYPEINIT1(SwFmtFldHint, SfxHint); 51 52 /**************************************************************************** 53 * 54 * class SwFmtFld 55 * 56 ****************************************************************************/ 57 58 // Konstruktor fuers Default vom Attribut-Pool 59 SwFmtFld::SwFmtFld() 60 : SfxPoolItem( RES_TXTATR_FIELD ), 61 SwClient( 0 ), 62 pField( 0 ), 63 pTxtAttr( 0 ) 64 { 65 } 66 67 SwFmtFld::SwFmtFld( const SwField &rFld ) 68 : SfxPoolItem( RES_TXTATR_FIELD ), 69 SwClient( rFld.GetTyp() ), 70 pTxtAttr( 0 ) 71 { 72 pField = rFld.CopyField(); 73 } 74 75 // #i24434# 76 // Since Items are used in ItemPool and in default constructed ItemSets with 77 // full pool range, all items need to be clonable. Thus, this one needed to be 78 // corrected 79 SwFmtFld::SwFmtFld( const SwFmtFld& rAttr ) 80 : SfxPoolItem( RES_TXTATR_FIELD ), SwClient(), SfxBroadcaster(), 81 pField( 0 ), 82 pTxtAttr( 0 ) 83 { 84 if(rAttr.GetFld()) 85 { 86 rAttr.GetFld()->GetTyp()->Add(this); 87 pField = rAttr.GetFld()->CopyField(); 88 } 89 } 90 91 SwFmtFld::~SwFmtFld() 92 { 93 SwFieldType* pType = pField ? pField->GetTyp() : 0; 94 95 if (pType && pType->Which() == RES_DBFLD) 96 pType = 0; // DB-Feldtypen zerstoeren sich selbst 97 98 Broadcast( SwFmtFldHint( this, SWFMTFLD_REMOVED ) ); 99 delete pField; 100 101 // bei einige FeldTypen muessen wir den FeldTypen noch loeschen 102 if( pType && pType->IsLastDepend() ) 103 { 104 sal_Bool bDel = sal_False; 105 switch( pType->Which() ) 106 { 107 case RES_USERFLD: 108 bDel = ((SwUserFieldType*)pType)->IsDeleted(); 109 break; 110 111 case RES_SETEXPFLD: 112 bDel = ((SwSetExpFieldType*)pType)->IsDeleted(); 113 break; 114 115 case RES_DDEFLD: 116 bDel = ((SwDDEFieldType*)pType)->IsDeleted(); 117 break; 118 } 119 120 if( bDel ) 121 { 122 // vorm loeschen erstmal austragen 123 pType->Remove( this ); 124 delete pType; 125 } 126 } 127 } 128 129 void SwFmtFld::RegisterToFieldType( SwFieldType& rType ) 130 { 131 rType.Add(this); 132 } 133 134 135 // #111840# 136 void SwFmtFld::SetFld(SwField * _pField) 137 { 138 if (NULL != pField) 139 delete pField; 140 141 pField = _pField; 142 Broadcast( SwFmtFldHint( this, SWFMTFLD_CHANGED ) ); 143 } 144 145 int SwFmtFld::operator==( const SfxPoolItem& rAttr ) const 146 { 147 ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); 148 // OD 2004-05-14 #i29146# - correction: check, if <pField> and 149 // <((SwFmtFld&)rAttr).GetFld()> are set. 150 // OD 2004-05-14 #i29146# - items are equal, if both fields aren't set. 151 return ( pField && ((SwFmtFld&)rAttr).GetFld() && 152 pField->GetTyp() == ((SwFmtFld&)rAttr).GetFld()->GetTyp() && 153 pField->GetFormat() == ((SwFmtFld&)rAttr).GetFld()->GetFormat() ) || 154 ( !pField && !((SwFmtFld&)rAttr).GetFld() ); 155 } 156 157 SfxPoolItem* SwFmtFld::Clone( SfxItemPool* ) const 158 { 159 return new SwFmtFld( *this ); 160 } 161 162 void SwFmtFld::SwClientNotify( const SwModify&, const SfxHint& rHint ) 163 { 164 if( !pTxtAttr ) 165 return; 166 167 const SwFieldHint* pHint = dynamic_cast<const SwFieldHint*>( &rHint ); 168 if ( pHint ) 169 { 170 // replace field content by text 171 SwPaM* pPaM = pHint->GetPaM(); 172 SwDoc* pDoc = pPaM->GetDoc(); 173 const SwTxtNode& rTxtNode = pTxtAttr->GetTxtNode(); 174 pPaM->GetPoint()->nNode = rTxtNode; 175 pPaM->GetPoint()->nContent.Assign( (SwTxtNode*)&rTxtNode, *pTxtAttr->GetStart() ); 176 177 String const aEntry( GetFld()->ExpandField( pDoc->IsClipBoard() ) ); 178 pPaM->SetMark(); 179 pPaM->Move( fnMoveForward ); 180 pDoc->DeleteRange( *pPaM ); 181 pDoc->InsertString( *pPaM, aEntry ); 182 } 183 } 184 185 void SwFmtFld::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) 186 { 187 if( !pTxtAttr ) 188 return; 189 190 // don't do anything, especially not expand! 191 if( pNew && pNew->Which() == RES_OBJECTDYING ) 192 return; 193 194 SwTxtNode* pTxtNd = (SwTxtNode*)&pTxtAttr->GetTxtNode(); 195 ASSERT( pTxtNd, "wo ist denn mein Node?" ); 196 if( pNew ) 197 { 198 switch( pNew->Which() ) 199 { 200 case RES_TXTATR_FLDCHG: 201 // "Farbe hat sich geaendert !" 202 // this, this fuer "nur Painten" 203 pTxtNd->ModifyNotification( this, this ); 204 return; 205 case RES_REFMARKFLD_UPDATE: 206 // GetReferenz-Felder aktualisieren 207 if( RES_GETREFFLD == GetFld()->GetTyp()->Which() ) 208 { 209 // --> OD 2007-09-06 #i81002# 210 // ((SwGetRefField*)GetFld())->UpdateField(); 211 dynamic_cast<SwGetRefField*>(GetFld())->UpdateField( pTxtAttr ); 212 // <-- 213 } 214 break; 215 case RES_DOCPOS_UPDATE: 216 // Je nach DocPos aktualisieren (SwTxtFrm::Modify()) 217 pTxtNd->ModifyNotification( pNew, this ); 218 return; 219 220 case RES_ATTRSET_CHG: 221 case RES_FMT_CHG: 222 pTxtNd->ModifyNotification( pOld, pNew ); 223 return; 224 default: 225 break; 226 } 227 } 228 229 switch (GetFld()->GetTyp()->Which()) 230 { 231 case RES_HIDDENPARAFLD: 232 if( !pOld || RES_HIDDENPARA_PRINT != pOld->Which() ) 233 break; 234 case RES_DBSETNUMBERFLD: 235 case RES_DBNUMSETFLD: 236 case RES_DBNEXTSETFLD: 237 case RES_DBNAMEFLD: 238 pTxtNd->ModifyNotification( 0, pNew); 239 return; 240 } 241 242 if( RES_USERFLD == GetFld()->GetTyp()->Which() ) 243 { 244 SwUserFieldType* pType = (SwUserFieldType*)GetFld()->GetTyp(); 245 if(!pType->IsValid()) 246 { 247 SwCalc aCalc( *pTxtNd->GetDoc() ); 248 pType->GetValue( aCalc ); 249 } 250 } 251 pTxtAttr->Expand(); 252 } 253 254 sal_Bool SwFmtFld::GetInfo( SfxPoolItem& rInfo ) const 255 { 256 const SwTxtNode* pTxtNd; 257 if( RES_AUTOFMT_DOCNODE != rInfo.Which() || 258 !pTxtAttr || 0 == ( pTxtNd = pTxtAttr->GetpTxtNode() ) || 259 &pTxtNd->GetNodes() != ((SwAutoFmtGetDocNode&)rInfo).pNodes ) 260 return sal_True; 261 262 ((SwAutoFmtGetDocNode&)rInfo).pCntntNode = pTxtNd; 263 return sal_False; 264 } 265 266 267 sal_Bool SwFmtFld::IsFldInDoc() const 268 { 269 const SwTxtNode* pTxtNd; 270 return pTxtAttr && 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) && 271 pTxtNd->GetNodes().IsDocNodes(); 272 } 273 274 sal_Bool SwFmtFld::IsProtect() const 275 { 276 const SwTxtNode* pTxtNd; 277 return pTxtAttr && 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) && 278 pTxtNd->IsProtect(); 279 } 280 281 /************************************************************************* 282 |* 283 |* SwTxtFld::SwTxtFld() 284 |* 285 |* Beschreibung Attribut fuer automatischen Text, Ctor 286 |* Ersterstellung BP 30.04.92 287 |* Letzte Aenderung JP 15.08.94 288 |* 289 *************************************************************************/ 290 291 SwTxtFld::SwTxtFld(SwFmtFld & rAttr, xub_StrLen const nStartPos) 292 : SwTxtAttr( rAttr, nStartPos ) 293 , m_aExpand( rAttr.GetFld()->ExpandField(true) ) 294 , m_pTxtNode( 0 ) 295 { 296 rAttr.pTxtAttr = this; 297 SetHasDummyChar(true); 298 } 299 300 SwTxtFld::~SwTxtFld( ) 301 { 302 SwFmtFld & rFmtFld( static_cast<SwFmtFld &>(GetAttr()) ); 303 if (this == rFmtFld.pTxtAttr) 304 { 305 rFmtFld.pTxtAttr = 0; // #i110140# invalidate! 306 } 307 } 308 309 /************************************************************************* 310 |* 311 |* SwTxtFld::Expand() 312 |* 313 |* Beschreibung exandiert das Feld und tauscht den Text im Node 314 |* Ersterstellung BP 30.04.92 315 |* Letzte Aenderung JP 15.08.94 316 |* 317 *************************************************************************/ 318 319 void SwTxtFld::Expand() const 320 { 321 // Wenn das expandierte Feld sich nicht veraendert hat, wird returnt 322 ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" ); 323 324 const SwField* pFld = GetFld().GetFld(); 325 XubString aNewExpand( 326 pFld->ExpandField(m_pTxtNode->GetDoc()->IsClipBoard()) ); 327 328 if( aNewExpand == m_aExpand ) 329 { 330 // Bei Seitennummernfeldern 331 const sal_uInt16 nWhich = pFld->GetTyp()->Which(); 332 if( RES_CHAPTERFLD != nWhich && RES_PAGENUMBERFLD != nWhich && 333 RES_REFPAGEGETFLD != nWhich && 334 // --> FME 2005-05-23 #122919# Page count fields to not use aExpand 335 // during formatting, therefore an invalidation of the text frame 336 // has to be triggered even if aNewExpand == aExpand: 337 ( RES_DOCSTATFLD != nWhich || DS_PAGE != static_cast<const SwDocStatField*>(pFld)->GetSubType() ) && 338 // <-- 339 ( RES_GETEXPFLD != nWhich || ((SwGetExpField*)pFld)->IsInBodyTxt() ) ) 340 { 341 // BP: das muesste man noch optimieren! 342 //JP 12.06.97: stimmt, man sollte auf jedenfall eine Status- 343 // aenderung an die Frames posten 344 if( m_pTxtNode->CalcHiddenParaField() ) 345 { 346 m_pTxtNode->ModifyNotification( 0, 0 ); 347 } 348 return; 349 } 350 } 351 352 m_aExpand = aNewExpand; 353 354 // 0, this for formatting 355 m_pTxtNode->ModifyNotification( 0, const_cast<SwFmtFld*>( &GetFld() ) ); 356 } 357 358 /************************************************************************* 359 * SwTxtFld::CopyFld() 360 *************************************************************************/ 361 362 void SwTxtFld::CopyFld( SwTxtFld *pDest ) const 363 { 364 ASSERT( m_pTxtNode, "SwTxtFld: where is my TxtNode?" ); 365 ASSERT( pDest->m_pTxtNode, "SwTxtFld: where is pDest's TxtNode?" ); 366 367 IDocumentFieldsAccess* pIDFA = m_pTxtNode->getIDocumentFieldsAccess(); 368 IDocumentFieldsAccess* pDestIDFA = pDest->m_pTxtNode->getIDocumentFieldsAccess(); 369 370 SwFmtFld& rFmtFld = (SwFmtFld&)pDest->GetFld(); 371 const sal_uInt16 nFldWhich = rFmtFld.GetFld()->GetTyp()->Which(); 372 373 if( pIDFA != pDestIDFA ) 374 { 375 // Die Hints stehen in unterschiedlichen Dokumenten, 376 // der Feldtyp muss im neuen Dokument angemeldet werden. 377 // Z.B: Kopieren ins ClipBoard. 378 SwFieldType* pFldType; 379 if( nFldWhich != RES_DBFLD && nFldWhich != RES_USERFLD && 380 nFldWhich != RES_SETEXPFLD && nFldWhich != RES_DDEFLD && 381 RES_AUTHORITY != nFldWhich ) 382 pFldType = pDestIDFA->GetSysFldType( nFldWhich ); 383 else 384 pFldType = pDestIDFA->InsertFldType( *rFmtFld.GetFld()->GetTyp() ); 385 386 // Sonderbehandlung fuer DDE-Felder 387 if( RES_DDEFLD == nFldWhich ) 388 { 389 if( rFmtFld.GetTxtFld() ) 390 ((SwDDEFieldType*)rFmtFld.GetFld()->GetTyp())->DecRefCnt(); 391 ((SwDDEFieldType*)pFldType)->IncRefCnt(); 392 } 393 394 ASSERT( pFldType, "unbekannter FieldType" ); 395 pFldType->Add( &rFmtFld ); // ummelden 396 rFmtFld.GetFld()->ChgTyp( pFldType ); 397 } 398 399 // Expressionfelder Updaten 400 if( nFldWhich == RES_SETEXPFLD || nFldWhich == RES_GETEXPFLD || 401 nFldWhich == RES_HIDDENTXTFLD ) 402 { 403 SwTxtFld* pFld = (SwTxtFld*)this; 404 pDestIDFA->UpdateExpFlds( pFld, true ); 405 } 406 // Tabellenfelder auf externe Darstellung 407 else if( RES_TABLEFLD == nFldWhich && 408 ((SwTblField*)rFmtFld.GetFld())->IsIntrnlName() ) 409 { 410 // erzeuge aus der internen (fuer CORE) die externe (fuer UI) Formel 411 const SwTableNode* pTblNd = m_pTxtNode->FindTableNode(); 412 if( pTblNd ) // steht in einer Tabelle 413 ((SwTblField*)rFmtFld.GetFld())->PtrToBoxNm( &pTblNd->GetTable() ); 414 } 415 } 416 417 /* -----------------26.06.2003 13:54----------------- 418 419 --------------------------------------------------*/ 420 void SwTxtFld::NotifyContentChange(SwFmtFld& rFmtFld) 421 { 422 //if not in undo section notify the change 423 if (m_pTxtNode && m_pTxtNode->GetNodes().IsDocNodes()) 424 { 425 m_pTxtNode->ModifyNotification(0, &rFmtFld); 426 } 427 } 428 429 430