update credits
[LibreOffice.git] / sw / source / core / doc / docfld.cxx
blob941e79b03cd9ee9ac4d6847464b8ddec2a2b86d1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
22 #include <string.h>
23 #include <float.h>
24 #include <comphelper/string.hxx>
25 #include <tools/datetime.hxx>
26 #include <vcl/svapp.hxx>
27 #include <unotools/charclass.hxx>
28 #include <unotools/transliterationwrapper.hxx>
29 #include <doc.hxx>
30 #include <IDocumentUndoRedo.hxx>
31 #include <cntfrm.hxx>
32 #include <pam.hxx>
33 #include <ndtxt.hxx>
34 #include <swtable.hxx>
35 #include <calc.hxx>
36 #include <txtfld.hxx>
37 #include <fmtfld.hxx>
38 #include <tox.hxx>
39 #include <txttxmrk.hxx>
40 #include <docfld.hxx> // for expression fields
41 #include <docufld.hxx>
42 #include <ddefld.hxx>
43 #include <usrfld.hxx>
44 #include <expfld.hxx>
45 #include <dbfld.hxx>
46 #include <flddat.hxx>
47 #include <chpfld.hxx>
48 #include <reffld.hxx>
49 #include <flddropdown.hxx>
50 #include <dbmgr.hxx>
51 #include <section.hxx>
52 #include <cellatr.hxx>
53 #include <docary.hxx>
54 #include <authfld.hxx>
55 #include <txtinet.hxx>
56 #include <fmtcntnt.hxx>
57 #include <poolfmt.hrc> // for InitFldTypes
59 #include <SwUndoField.hxx>
60 #include "switerator.hxx"
62 using namespace ::com::sun::star::uno;
64 extern bool IsFrameBehind( const SwTxtNode& rMyNd, sal_uInt16 nMySttPos,
65 const SwTxtNode& rBehindNd, sal_uInt16 nSttPos );
67 /** Insert field types
69 * @param rFldTyp ???
70 * @return Always returns a pointer to the type, if it's new or already added.
72 SwFieldType* SwDoc::InsertFldType(const SwFieldType &rFldTyp)
74 sal_uInt16 nSize = mpFldTypes->size(),
75 nFldWhich = rFldTyp.Which();
77 sal_uInt16 i = INIT_FLDTYPES;
79 switch( nFldWhich )
81 case RES_SETEXPFLD:
82 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
83 // Or we get doubble number circles!!
84 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
85 //constructing string pools and when reading SetExp fields
86 if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType&)rFldTyp).GetType() )
87 i -= INIT_SEQ_FLDTYPES;
88 // no break;
89 case RES_DBFLD:
90 case RES_USERFLD:
91 case RES_DDEFLD:
93 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
94 String sFldNm( rFldTyp.GetName() );
95 for( ; i < nSize; ++i )
96 if( nFldWhich == (*mpFldTypes)[i]->Which() &&
97 rSCmp.isEqual( sFldNm, (*mpFldTypes)[i]->GetName() ))
98 return (*mpFldTypes)[i];
100 break;
102 case RES_AUTHORITY:
103 for( ; i < nSize; ++i )
104 if( nFldWhich == (*mpFldTypes)[i]->Which() )
105 return (*mpFldTypes)[i];
106 break;
108 default:
109 for( i = 0; i < nSize; ++i )
110 if( nFldWhich == (*mpFldTypes)[i]->Which() )
111 return (*mpFldTypes)[i];
114 SwFieldType* pNew = rFldTyp.Copy();
115 switch( nFldWhich )
117 case RES_DDEFLD:
118 ((SwDDEFieldType*)pNew)->SetDoc( this );
119 break;
121 case RES_DBFLD:
122 case RES_TABLEFLD:
123 case RES_DATETIMEFLD:
124 case RES_GETEXPFLD:
125 ((SwValueFieldType*)pNew)->SetDoc( this );
126 break;
128 case RES_USERFLD:
129 case RES_SETEXPFLD:
130 ((SwValueFieldType*)pNew)->SetDoc( this );
131 // JP 29.07.96: Optionally prepare FieldList for Calculator:
132 mpUpdtFlds->InsertFldType( *pNew );
133 break;
134 case RES_AUTHORITY :
135 ((SwAuthorityFieldType*)pNew)->SetDoc( this );
136 break;
139 mpFldTypes->insert( mpFldTypes->begin() + nSize, pNew );
140 SetModified();
142 return (*mpFldTypes)[ nSize ];
145 /// Insert field type that was marked as deleted
146 void SwDoc::InsDeletedFldType( SwFieldType& rFldTyp )
148 // The FldType was marked as deleted and removed from the array.
149 // One has to look this up again, now.
150 // - If it's not present, it can be re-inserted.
151 // - If the same type is found, the deleted one has to be renamed.
153 sal_uInt16 nSize = mpFldTypes->size(), nFldWhich = rFldTyp.Which();
154 sal_uInt16 i = INIT_FLDTYPES;
156 OSL_ENSURE( RES_SETEXPFLD == nFldWhich ||
157 RES_USERFLD == nFldWhich ||
158 RES_DDEFLD == nFldWhich, "Wrong FldType" );
160 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
161 const String& rFldNm = rFldTyp.GetName();
162 SwFieldType* pFnd;
164 for( ; i < nSize; ++i )
165 if( nFldWhich == (pFnd = (*mpFldTypes)[i])->Which() &&
166 rSCmp.isEqual( rFldNm, pFnd->GetName() ) )
168 // find new name
169 sal_uInt16 nNum = 1;
170 do {
171 String sSrch( rFldNm );
172 sSrch.Append( OUString::number( nNum ));
173 for( i = INIT_FLDTYPES; i < nSize; ++i )
174 if( nFldWhich == (pFnd = (*mpFldTypes)[i])->Which() &&
175 rSCmp.isEqual( sSrch, pFnd->GetName() ) )
176 break;
178 if( i >= nSize ) // not found
180 ((String&)rFldNm) = sSrch;
181 break; // exit while loop
183 ++nNum;
184 } while( true );
185 break;
188 // not found, so insert and delete flag
189 mpFldTypes->insert( mpFldTypes->begin() + nSize, &rFldTyp );
190 switch( nFldWhich )
192 case RES_SETEXPFLD:
193 ((SwSetExpFieldType&)rFldTyp).SetDeleted( sal_False );
194 break;
195 case RES_USERFLD:
196 ((SwUserFieldType&)rFldTyp).SetDeleted( sal_False );
197 break;
198 case RES_DDEFLD:
199 ((SwDDEFieldType&)rFldTyp).SetDeleted( sal_False );
200 break;
204 /// Remove field type
205 void SwDoc::RemoveFldType(sal_uInt16 nFld)
207 OSL_ENSURE( INIT_FLDTYPES <= nFld, "don't remove InitFlds" );
209 * Dependent fields present -> ErrRaise
211 sal_uInt16 nSize = mpFldTypes->size();
212 if(nFld < nSize)
214 SwFieldType* pTmp = (*mpFldTypes)[nFld];
216 // JP 29.07.96: Optionally prepare FldLst for Calculator
217 sal_uInt16 nWhich = pTmp->Which();
218 switch( nWhich )
220 case RES_SETEXPFLD:
221 case RES_USERFLD:
222 mpUpdtFlds->RemoveFldType( *pTmp );
223 // no break;
224 case RES_DDEFLD:
225 if( pTmp->GetDepends() && !IsUsed( *pTmp ) )
227 if( RES_SETEXPFLD == nWhich )
228 ((SwSetExpFieldType*)pTmp)->SetDeleted( sal_True );
229 else if( RES_USERFLD == nWhich )
230 ((SwUserFieldType*)pTmp)->SetDeleted( sal_True );
231 else
232 ((SwDDEFieldType*)pTmp)->SetDeleted( sal_True );
233 nWhich = 0;
235 break;
238 if( nWhich )
240 OSL_ENSURE( !pTmp->GetDepends(), "Dependent fields present!" );
241 // delete field type
242 delete pTmp;
244 mpFldTypes->erase( mpFldTypes->begin() + nFld );
245 SetModified();
249 const SwFldTypes* SwDoc::GetFldTypes() const
251 return mpFldTypes;
254 /// Find first type with ResId and name
255 SwFieldType* SwDoc::GetFldType( sal_uInt16 nResId, const String& rName,
256 bool bDbFieldMatching // used in some UNO calls for RES_DBFLD
257 // to use different string matching code
258 // #i51815#
259 ) const
261 sal_uInt16 nSize = mpFldTypes->size(), i = 0;
262 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
264 switch( nResId )
266 case RES_SETEXPFLD:
267 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
268 // Or we get doubble number circles!!
269 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
270 //constructing string pools and when reading SetExp fields
271 i = INIT_FLDTYPES - INIT_SEQ_FLDTYPES;
272 break;
274 case RES_DBFLD:
275 case RES_USERFLD:
276 case RES_DDEFLD:
277 case RES_AUTHORITY:
278 i = INIT_FLDTYPES;
279 break;
282 SwFieldType* pRet = 0;
283 for( ; i < nSize; ++i )
285 SwFieldType* pFldType = (*mpFldTypes)[i];
287 String aFldName( pFldType->GetName() );
288 if (bDbFieldMatching && nResId == RES_DBFLD) // #i51815#
289 aFldName.SearchAndReplaceAll(DB_DELIM, '.');
291 if( nResId == pFldType->Which() &&
292 rSCmp.isEqual( rName, aFldName ))
294 pRet = pFldType;
295 break;
298 return pRet;
301 // All have to be re-evaluated.
302 void SwDoc::UpdateFlds( SfxPoolItem *pNewHt, bool bCloseDB )
304 // Call Modify() for every field type,
305 // dependent SwTxtFld get notified ...
307 for( sal_uInt16 i=0; i < mpFldTypes->size(); ++i)
309 switch( (*mpFldTypes)[i]->Which() )
311 // Update table fields second to last
312 // Update references last
313 case RES_GETREFFLD:
314 case RES_TABLEFLD:
315 case RES_DBFLD:
316 case RES_JUMPEDITFLD:
317 case RES_REFPAGESETFLD: // are never expanded!
318 break;
320 case RES_DDEFLD:
322 if( !pNewHt )
324 SwMsgPoolItem aUpdateDDE( RES_UPDATEDDETBL );
325 (*mpFldTypes)[i]->ModifyNotification( 0, &aUpdateDDE );
327 else
328 (*mpFldTypes)[i]->ModifyNotification( 0, pNewHt );
329 break;
331 case RES_GETEXPFLD:
332 case RES_SETEXPFLD:
333 case RES_HIDDENTXTFLD:
334 case RES_HIDDENPARAFLD:
335 // Expression fields are treated separately
336 if( !pNewHt )
337 break;
338 default:
339 (*mpFldTypes)[i]->ModifyNotification ( 0, pNewHt );
343 if( !IsExpFldsLocked() )
344 UpdateExpFlds( 0, sal_False ); // update expression fields
346 // Tables
347 UpdateTblFlds(pNewHt);
349 // References
350 UpdateRefFlds(pNewHt);
352 if( bCloseDB )
353 GetNewDBMgr()->CloseAll();
355 // Only evaluate on full update
356 SetModified();
359 void SwDoc::UpdateUsrFlds()
361 SwCalc* pCalc = 0;
362 const SwFieldType* pFldType;
363 for( sal_uInt16 i = INIT_FLDTYPES; i < mpFldTypes->size(); ++i )
364 if( RES_USERFLD == ( pFldType = (*mpFldTypes)[i] )->Which() )
366 if( !pCalc )
367 pCalc = new SwCalc( *this );
368 ((SwUserFieldType*)pFldType)->GetValue( *pCalc );
371 if( pCalc )
373 delete pCalc;
374 SetModified();
378 /// Update reference and table fields
379 void SwDoc::UpdateRefFlds( SfxPoolItem* pHt )
381 SwFieldType* pFldType;
382 for( sal_uInt16 i = 0; i < mpFldTypes->size(); ++i )
383 if( RES_GETREFFLD == ( pFldType = (*mpFldTypes)[i] )->Which() )
384 pFldType->ModifyNotification( 0, pHt );
387 /// @note For simplicity assume that all field types have updatable contents so
388 /// optimization currently only available when no fields exist.
389 bool SwDoc::containsUpdatableFields()
391 for (sal_uInt16 i = 0; i < mpFldTypes->size(); ++i)
393 SwFieldType* pFldType = (*mpFldTypes)[i];
394 SwIterator<SwFmtFld,SwFieldType> aIter(*pFldType);
395 if (aIter.First())
396 return true;
398 return false;
401 void SwDoc::UpdateTblFlds( SfxPoolItem* pHt )
403 OSL_ENSURE( !pHt || RES_TABLEFML_UPDATE == pHt->Which(),
404 "What MessageItem is this?" );
406 SwFieldType* pFldType(0);
408 for (sal_uInt16 i = 0; i < mpFldTypes->size(); ++i)
410 if( RES_TABLEFLD == ( pFldType = (*mpFldTypes)[i] )->Which() )
412 SwTableFmlUpdate* pUpdtFld = 0;
413 if( pHt && RES_TABLEFML_UPDATE == pHt->Which() )
414 pUpdtFld = (SwTableFmlUpdate*)pHt;
416 SwIterator<SwFmtFld,SwFieldType> aIter( *pFldType );
417 for( SwFmtFld* pFmtFld = aIter.First(); pFmtFld; pFmtFld = aIter.Next() )
419 if( pFmtFld->GetTxtFld() )
421 SwTblField* pFld = (SwTblField*)pFmtFld->GetFld();
423 if( pUpdtFld )
425 // table where this field is located
426 const SwTableNode* pTblNd;
427 const SwTxtNode& rTxtNd = pFmtFld->GetTxtFld()->GetTxtNode();
428 if( !rTxtNd.GetNodes().IsDocNodes() ||
429 0 == ( pTblNd = rTxtNd.FindTableNode() ) )
430 continue;
432 switch( pUpdtFld->eFlags )
434 case TBL_CALC:
435 // re-set the value flag
436 // JP 17.06.96: internal representation of all formulas
437 // (reference to other table!!!)
438 if( nsSwExtendedSubType::SUB_CMD & pFld->GetSubType() )
439 pFld->PtrToBoxNm( pUpdtFld->pTbl );
440 else
441 pFld->ChgValid( sal_False );
442 break;
443 case TBL_BOXNAME:
444 // is this the wanted table?
445 if( &pTblNd->GetTable() == pUpdtFld->pTbl )
446 // to the external representation
447 pFld->PtrToBoxNm( pUpdtFld->pTbl );
448 break;
449 case TBL_BOXPTR:
450 // to the internal representation
451 // JP 17.06.96: internal representation on all formulas
452 // (reference to other table!!!)
453 pFld->BoxNmToPtr( pUpdtFld->pTbl );
454 break;
455 case TBL_RELBOXNAME:
456 // is this the wanted table?
457 if( &pTblNd->GetTable() == pUpdtFld->pTbl )
458 // to the relative representation
459 pFld->ToRelBoxNm( pUpdtFld->pTbl );
460 break;
461 default:
462 break;
465 else
466 // reset the value flag for all
467 pFld->ChgValid( sal_False );
471 break;
473 pFldType = 0;
476 // process all table box formuals
477 const SfxPoolItem* pItem;
478 sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_BOXATR_FORMULA );
479 for (sal_uInt32 i = 0; i < nMaxItems; ++i)
481 if( 0 != (pItem = GetAttrPool().GetItem2( RES_BOXATR_FORMULA, i ) ) &&
482 ((SwTblBoxFormula*)pItem)->GetDefinedIn() )
484 ((SwTblBoxFormula*)pItem)->ChangeState( pHt );
489 // all fields/boxes are now invalid, so we can start to calculate
490 if( pHt && ( RES_TABLEFML_UPDATE != pHt->Which() ||
491 TBL_CALC != ((SwTableFmlUpdate*)pHt)->eFlags ))
492 return ;
494 SwCalc* pCalc = 0;
496 if( pFldType )
498 SwIterator<SwFmtFld,SwFieldType> aIter( *pFldType );
499 for( SwFmtFld* pFmtFld = aIter.Last(); pFmtFld; pFmtFld = aIter.Previous() )
501 // start calculation at the end
502 // new fields are inserted at the beginning of the modify chain
503 // that gives faster calculation on import
504 // mba: do we really need this "optimization"? Is it still valid?
505 SwTblField* pFld;
506 if( !pFmtFld->GetTxtFld() || (nsSwExtendedSubType::SUB_CMD &
507 (pFld = (SwTblField*)pFmtFld->GetFld())->GetSubType() ))
508 continue;
510 // needs to be recalculated
511 if( !pFld->IsValid() )
513 // table where this field is located
514 const SwTxtNode& rTxtNd = pFmtFld->GetTxtFld()->GetTxtNode();
515 if( !rTxtNd.GetNodes().IsDocNodes() )
516 continue;
517 const SwTableNode* pTblNd = rTxtNd.FindTableNode();
518 if( !pTblNd )
519 continue;
521 // if this field is not in the to-be-updated table, skip it
522 if( pHt && &pTblNd->GetTable() !=
523 ((SwTableFmlUpdate*)pHt)->pTbl )
524 continue;
526 if( !pCalc )
527 pCalc = new SwCalc( *this );
529 // get the values of all SetExpression fields that are valid
530 // until the table
531 SwFrm* pFrm = 0;
532 if( pTblNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() )
534 // is in the special section, that's expensive!
535 Point aPt; // return the first frame of the layout - Tab.Headline!!
536 pFrm = rTxtNd.getLayoutFrm( GetCurrentLayout(), &aPt );
537 if( pFrm )
539 SwPosition aPos( *pTblNd );
540 if( GetBodyTxtNode( *this, aPos, *pFrm ) )
541 FldsToCalc( *pCalc, _SetGetExpFld(
542 aPos.nNode, pFmtFld->GetTxtFld(),
543 &aPos.nContent ));
544 else
545 pFrm = 0;
548 if( !pFrm )
550 // create index to determine the TextNode
551 SwNodeIndex aIdx( rTxtNd );
552 FldsToCalc( *pCalc,
553 _SetGetExpFld( aIdx, pFmtFld->GetTxtFld() ));
556 SwTblCalcPara aPara( *pCalc, pTblNd->GetTable() );
557 pFld->CalcField( aPara );
558 if( aPara.IsStackOverFlow() )
560 bool const bResult = aPara.CalcWithStackOverflow();
561 if (bResult)
563 pFld->CalcField( aPara );
565 OSL_ENSURE(bResult,
566 "the chained formula could no be calculated");
568 pCalc->SetCalcError( CALC_NOERR );
570 pFmtFld->ModifyNotification( 0, pHt );
574 // calculate the formula at the boxes
575 for (sal_uInt32 i = 0; i < nMaxItems; ++i )
577 if( 0 != (pItem = GetAttrPool().GetItem2( RES_BOXATR_FORMULA, i ) ) &&
578 ((SwTblBoxFormula*)pItem)->GetDefinedIn() &&
579 !((SwTblBoxFormula*)pItem)->IsValid() )
581 SwTblBoxFormula* pFml = (SwTblBoxFormula*)pItem;
582 SwTableBox* pBox = pFml->GetTableBox();
583 if( pBox && pBox->GetSttNd() &&
584 pBox->GetSttNd()->GetNodes().IsDocNodes() )
586 const SwTableNode* pTblNd = pBox->GetSttNd()->FindTableNode();
587 if( !pHt || &pTblNd->GetTable() ==
588 ((SwTableFmlUpdate*)pHt)->pTbl )
590 double nValue;
591 if( !pCalc )
592 pCalc = new SwCalc( *this );
594 // get the values of all SetExpression fields that are valid
595 // until the table
596 SwFrm* pFrm = 0;
597 if( pTblNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() )
599 // is in the special section, that's expensive!
600 Point aPt; // return the first frame of the layout - Tab.Headline!!
601 SwNodeIndex aCNdIdx( *pTblNd, +2 );
602 SwCntntNode* pCNd = aCNdIdx.GetNode().GetCntntNode();
603 if( !pCNd )
604 pCNd = GetNodes().GoNext( &aCNdIdx );
606 if( pCNd && 0 != (pFrm = pCNd->getLayoutFrm( GetCurrentLayout(), &aPt )) )
608 SwPosition aPos( *pCNd );
609 if( GetBodyTxtNode( *this, aPos, *pFrm ) )
610 FldsToCalc( *pCalc, _SetGetExpFld( aPos.nNode ));
611 else
612 pFrm = 0;
615 if( !pFrm )
617 // create index to determine the TextNode
618 SwNodeIndex aIdx( *pTblNd );
619 FldsToCalc( *pCalc, _SetGetExpFld( aIdx ));
622 SwTblCalcPara aPara( *pCalc, pTblNd->GetTable() );
623 pFml->Calc( aPara, nValue );
625 if( aPara.IsStackOverFlow() )
627 bool const bResult = aPara.CalcWithStackOverflow();
628 if (bResult)
630 pFml->Calc( aPara, nValue );
632 OSL_ENSURE(bResult,
633 "the chained formula could no be calculated");
636 SwFrmFmt* pFmt = pBox->ClaimFrmFmt();
637 SfxItemSet aTmp( GetAttrPool(),
638 RES_BOXATR_BEGIN,RES_BOXATR_END-1 );
640 if( pCalc->IsCalcError() )
641 nValue = DBL_MAX;
642 aTmp.Put( SwTblBoxValue( nValue ));
643 if( SFX_ITEM_SET != pFmt->GetItemState( RES_BOXATR_FORMAT ))
644 aTmp.Put( SwTblBoxNumFormat( 0 ));
645 pFmt->SetFmtAttr( aTmp );
647 pCalc->SetCalcError( CALC_NOERR );
653 delete pCalc;
656 void SwDoc::UpdatePageFlds( SfxPoolItem* pMsgHnt )
658 SwFieldType* pFldType;
659 for( sal_uInt16 i = 0; i < INIT_FLDTYPES; ++i )
660 switch( ( pFldType = (*mpFldTypes)[ i ] )->Which() )
662 case RES_PAGENUMBERFLD:
663 case RES_CHAPTERFLD:
664 case RES_GETEXPFLD:
665 case RES_REFPAGEGETFLD:
666 pFldType->ModifyNotification( 0, pMsgHnt );
667 break;
668 case RES_DOCSTATFLD:
669 pFldType->ModifyNotification( 0, 0 );
670 break;
672 SetNewFldLst(true);
675 /// Remove all unreferenced field types of a document
676 void SwDoc::GCFieldTypes()
678 for( sal_uInt16 n = mpFldTypes->size(); n > INIT_FLDTYPES; )
679 if( !(*mpFldTypes)[ --n ]->GetDepends() )
680 RemoveFldType( n );
683 void SwDoc::LockExpFlds()
685 ++mnLockExpFld;
688 void SwDoc::UnlockExpFlds()
690 if( mnLockExpFld )
691 --mnLockExpFld;
694 bool SwDoc::IsExpFldsLocked() const
696 return 0 != mnLockExpFld;
699 SwDocUpdtFld& SwDoc::GetUpdtFlds() const
701 return *mpUpdtFlds;
704 bool SwDoc::IsNewFldLst() const
706 return mbNewFldLst;
709 void SwDoc::SetNewFldLst(bool bFlag)
711 mbNewFldLst = bFlag;
714 // the StartIndex can be supplied optionally (e.g. if it was queried before - is a virtual
715 // method otherwise!)
716 _SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx, const SwTxtFld* pFld,
717 const SwIndex* pIdx )
719 eSetGetExpFldType = TEXTFIELD;
720 CNTNT.pTxtFld = pFld;
721 nNode = rNdIdx.GetIndex();
722 if( pIdx )
723 nCntnt = pIdx->GetIndex();
724 else if( pFld )
725 nCntnt = *pFld->GetStart();
726 else
727 nCntnt = 0;
730 _SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx,
731 const SwTxtINetFmt& rINet, const SwIndex* pIdx )
733 eSetGetExpFldType = TEXTINET;
734 CNTNT.pTxtINet = &rINet;
735 nNode = rNdIdx.GetIndex();
736 if( pIdx )
737 nCntnt = pIdx->GetIndex();
738 else
739 nCntnt = *rINet.GetStart();
742 // Extension for Sections:
743 // these always have content position 0xffff!
744 // There is never a field on this, only up to STRING_MAXLEN possible
745 _SetGetExpFld::_SetGetExpFld( const SwSectionNode& rSectNd,
746 const SwPosition* pPos )
748 eSetGetExpFldType = SECTIONNODE;
749 CNTNT.pSection = &rSectNd.GetSection();
751 if( pPos )
753 nNode = pPos->nNode.GetIndex();
754 nCntnt = pPos->nContent.GetIndex();
756 else
758 nNode = rSectNd.GetIndex();
759 nCntnt = 0;
763 _SetGetExpFld::_SetGetExpFld( const SwTableBox& rTBox, const SwPosition* pPos )
765 eSetGetExpFldType = TABLEBOX;
766 CNTNT.pTBox = &rTBox;
768 if( pPos )
770 nNode = pPos->nNode.GetIndex();
771 nCntnt = pPos->nContent.GetIndex();
773 else
775 nNode = 0;
776 nCntnt = 0;
777 if( rTBox.GetSttNd() )
779 SwNodeIndex aIdx( *rTBox.GetSttNd() );
780 const SwCntntNode* pNd = aIdx.GetNode().GetNodes().GoNext( &aIdx );
781 if( pNd )
782 nNode = pNd->GetIndex();
787 _SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx,
788 const SwTxtTOXMark& rTOX,
789 const SwIndex* pIdx )
791 eSetGetExpFldType = TEXTTOXMARK;
792 CNTNT.pTxtTOX = &rTOX;
793 nNode = rNdIdx.GetIndex();
794 if( pIdx )
795 nCntnt = pIdx->GetIndex();
796 else
797 nCntnt = *rTOX.GetStart();
800 _SetGetExpFld::_SetGetExpFld( const SwPosition& rPos )
802 eSetGetExpFldType = CRSRPOS;
803 CNTNT.pPos = &rPos;
804 nNode = rPos.nNode.GetIndex();
805 nCntnt = rPos.nContent.GetIndex();
808 _SetGetExpFld::_SetGetExpFld( const SwFlyFrmFmt& rFlyFmt,
809 const SwPosition* pPos )
811 eSetGetExpFldType = FLYFRAME;
812 CNTNT.pFlyFmt = &rFlyFmt;
813 if( pPos )
815 nNode = pPos->nNode.GetIndex();
816 nCntnt = pPos->nContent.GetIndex();
818 else
820 const SwFmtCntnt& rCntnt = rFlyFmt.GetCntnt();
821 nNode = rCntnt.GetCntntIdx()->GetIndex() + 1;
822 nCntnt = 0;
826 void _SetGetExpFld::GetPos( SwPosition& rPos ) const
828 rPos.nNode = nNode;
829 rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), nCntnt );
832 void _SetGetExpFld::GetPosOfContent( SwPosition& rPos ) const
834 const SwNode* pNd = GetNodeFromCntnt();
835 if( pNd )
836 pNd = pNd->GetCntntNode();
838 if( pNd )
840 rPos.nNode = *pNd;
841 rPos.nContent.Assign( (SwCntntNode*)pNd,GetCntPosFromCntnt() );
843 else
845 rPos.nNode = nNode;
846 rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), nCntnt );
850 void _SetGetExpFld::SetBodyPos( const SwCntntFrm& rFrm )
852 if( !rFrm.IsInDocBody() )
854 SwNodeIndex aIdx( *rFrm.GetNode() );
855 SwDoc& rDoc = *aIdx.GetNodes().GetDoc();
856 SwPosition aPos( aIdx );
857 bool const bResult = ::GetBodyTxtNode( rDoc, aPos, rFrm );
858 OSL_ENSURE(bResult, "Where is the field?");
859 (void) bResult; // unused in non-debug
860 nNode = aPos.nNode.GetIndex();
861 nCntnt = aPos.nContent.GetIndex();
865 bool _SetGetExpFld::operator<( const _SetGetExpFld& rFld ) const
867 if( nNode < rFld.nNode || ( nNode == rFld.nNode && nCntnt < rFld.nCntnt ))
868 return true;
869 else if( nNode != rFld.nNode || nCntnt != rFld.nCntnt )
870 return false;
872 const SwNode *pFirst = GetNodeFromCntnt(),
873 *pNext = rFld.GetNodeFromCntnt();
875 // Position is the same: continue only if both field pointers are set!
876 if( !pFirst || !pNext )
877 return false;
879 // same Section?
880 if( pFirst->StartOfSectionNode() != pNext->StartOfSectionNode() )
882 // is one in the table?
883 const SwNode *pFirstStt, *pNextStt;
884 const SwTableNode* pTblNd = pFirst->FindTableNode();
885 if( pTblNd )
886 pFirstStt = pTblNd->StartOfSectionNode();
887 else
888 pFirstStt = pFirst->StartOfSectionNode();
890 if( 0 != ( pTblNd = pNext->FindTableNode() ) )
891 pNextStt = pTblNd->StartOfSectionNode();
892 else
893 pNextStt = pNext->StartOfSectionNode();
895 if( pFirstStt != pNextStt )
897 if( pFirst->IsTxtNode() && pNext->IsTxtNode() &&
898 ( pFirst->FindFlyStartNode() || pNext->FindFlyStartNode() ))
900 return ::IsFrameBehind( *(SwTxtNode*)pNext, nCntnt,
901 *(SwTxtNode*)pFirst, nCntnt );
903 return pFirstStt->GetIndex() < pNextStt->GetIndex();
907 // same Section: is the field in the same Node?
908 if( pFirst != pNext )
909 return pFirst->GetIndex() < pNext->GetIndex();
911 // same Node in the Section, check Position in the Node
912 return GetCntPosFromCntnt() < rFld.GetCntPosFromCntnt();
915 const SwNode* _SetGetExpFld::GetNodeFromCntnt() const
917 const SwNode* pRet = 0;
918 if( CNTNT.pTxtFld )
919 switch( eSetGetExpFldType )
921 case TEXTFIELD:
922 pRet = &CNTNT.pTxtFld->GetTxtNode();
923 break;
925 case TEXTINET:
926 pRet = &CNTNT.pTxtINet->GetTxtNode();
927 break;
929 case SECTIONNODE:
930 pRet = CNTNT.pSection->GetFmt()->GetSectionNode();
931 break;
933 case CRSRPOS:
934 pRet = &CNTNT.pPos->nNode.GetNode();
935 break;
937 case TEXTTOXMARK:
938 pRet = &CNTNT.pTxtTOX->GetTxtNode();
939 break;
941 case TABLEBOX:
942 if( CNTNT.pTBox->GetSttNd() )
944 SwNodeIndex aIdx( *CNTNT.pTBox->GetSttNd() );
945 pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
947 break;
949 case FLYFRAME:
951 SwNodeIndex aIdx( *CNTNT.pFlyFmt->GetCntnt().GetCntntIdx() );
952 pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
954 break;
956 return pRet;
959 xub_StrLen _SetGetExpFld::GetCntPosFromCntnt() const
961 sal_uInt16 nRet = 0;
962 if( CNTNT.pTxtFld )
963 switch( eSetGetExpFldType )
965 case TEXTFIELD:
966 case TEXTINET:
967 case TEXTTOXMARK:
968 nRet = *CNTNT.pTxtFld->GetStart();
969 break;
970 case CRSRPOS:
971 nRet = CNTNT.pPos->nContent.GetIndex();
972 break;
973 default:
974 break;
976 return nRet;
979 _HashStr::_HashStr( const String& rName, const String& rText,
980 _HashStr* pNxt )
981 : SwHash( rName ), aSetStr( rText )
983 pNext = pNxt;
986 /// Look up the Name, if it is present, return it's String, otherwise return an empty String
987 void LookString( SwHash** ppTbl, sal_uInt16 nSize, const String& rName,
988 String& rRet, sal_uInt16* pPos )
990 rRet = comphelper::string::strip(rName, ' ');
991 SwHash* pFnd = Find( rRet, ppTbl, nSize, pPos );
992 if( pFnd )
993 rRet = ((_HashStr*)pFnd)->aSetStr;
994 else
995 rRet.Erase();
998 static String lcl_GetDBVarName( SwDoc& rDoc, SwDBNameInfField& rDBFld )
1000 SwDBData aDBData( rDBFld.GetDBData( &rDoc ));
1001 String sDBNumNm;
1002 SwDBData aDocData = rDoc.GetDBData();
1004 if( aDBData != aDocData )
1006 sDBNumNm = aDBData.sDataSource;
1007 sDBNumNm += DB_DELIM;
1008 sDBNumNm += String(aDBData.sCommand);
1009 sDBNumNm += DB_DELIM;
1011 sDBNumNm += SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD);
1013 return sDBNumNm;
1016 static void lcl_CalcFld( SwDoc& rDoc, SwCalc& rCalc, const _SetGetExpFld& rSGEFld,
1017 SwNewDBMgr* pMgr )
1019 const SwTxtFld* pTxtFld = rSGEFld.GetFld();
1020 if( !pTxtFld )
1021 return ;
1023 const SwField* pFld = pTxtFld->GetFld().GetFld();
1024 const sal_uInt16 nFldWhich = pFld->GetTyp()->Which();
1026 if( RES_SETEXPFLD == nFldWhich )
1028 SwSbxValue aValue;
1029 if( nsSwGetSetExpType::GSE_EXPR & pFld->GetSubType() )
1030 aValue.PutDouble( ((SwSetExpField*)pFld)->GetValue() );
1031 else
1032 // Extension to calculate with Strings
1033 aValue.PutString( ((SwSetExpField*)pFld)->GetExpStr() );
1035 // set the new value in Calculator
1036 rCalc.VarChange( pFld->GetTyp()->GetName(), aValue );
1038 else if( pMgr )
1040 switch( nFldWhich )
1042 case RES_DBNUMSETFLD:
1044 SwDBNumSetField* pDBFld = (SwDBNumSetField*)pFld;
1046 SwDBData aDBData(pDBFld->GetDBData(&rDoc));
1048 if( pDBFld->IsCondValid() &&
1049 pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
1050 rCalc.VarChange( lcl_GetDBVarName( rDoc, *pDBFld),
1051 pDBFld->GetFormat() );
1053 break;
1054 case RES_DBNEXTSETFLD:
1056 SwDBNextSetField* pDBFld = (SwDBNextSetField*)pFld;
1057 SwDBData aDBData(pDBFld->GetDBData(&rDoc));
1058 if( !pDBFld->IsCondValid() ||
1059 !pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
1060 break;
1062 String sDBNumNm(lcl_GetDBVarName( rDoc, *pDBFld));
1063 SwCalcExp* pExp = rCalc.VarLook( sDBNumNm );
1064 if( pExp )
1065 rCalc.VarChange( sDBNumNm, pExp->nValue.GetLong() + 1 );
1067 break;
1073 void SwDoc::FldsToCalc( SwCalc& rCalc, const _SetGetExpFld& rToThisFld )
1075 // create the sorted list of all SetFields
1076 mpUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_CALC );
1077 mbNewFldLst = sal_False;
1079 SwNewDBMgr* pMgr = GetNewDBMgr();
1080 pMgr->CloseAll(sal_False);
1082 if( !mpUpdtFlds->GetSortLst()->empty() )
1084 _SetGetExpFlds::const_iterator const itLast =
1085 mpUpdtFlds->GetSortLst()->upper_bound(
1086 const_cast<_SetGetExpFld*>(&rToThisFld));
1087 for( _SetGetExpFlds::const_iterator it = mpUpdtFlds->GetSortLst()->begin(); it != itLast; ++it )
1088 lcl_CalcFld( *this, rCalc, **it, pMgr );
1091 pMgr->CloseAll(sal_False);
1094 void SwDoc::FldsToCalc( SwCalc& rCalc, sal_uLong nLastNd, sal_uInt16 nLastCnt )
1096 // create the sorted list of all SetFields
1097 mpUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_CALC );
1098 mbNewFldLst = sal_False;
1100 SwNewDBMgr* pMgr = GetNewDBMgr();
1101 pMgr->CloseAll(sal_False);
1103 for( _SetGetExpFlds::const_iterator it = mpUpdtFlds->GetSortLst()->begin();
1104 it != mpUpdtFlds->GetSortLst()->end() &&
1105 ( (*it)->GetNode() < nLastNd ||
1106 ( (*it)->GetNode() == nLastNd && (*it)->GetCntnt() <= nLastCnt )
1108 ++it )
1110 lcl_CalcFld( *this, rCalc, **it, pMgr );
1113 pMgr->CloseAll(sal_False);
1116 void SwDoc::FldsToExpand( SwHash**& ppHashTbl, sal_uInt16& rTblSize,
1117 const _SetGetExpFld& rToThisFld )
1119 // create the sorted list of all SetFields
1120 mpUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_EXPAND );
1121 mbNewFldLst = sal_False;
1123 // Hash table for all string replacements is filled on-the-fly.
1124 // Try to fabricate an uneven number.
1125 rTblSize = (( mpUpdtFlds->GetSortLst()->size() / 7 ) + 1 ) * 7;
1126 ppHashTbl = new SwHash*[ rTblSize ];
1127 memset( ppHashTbl, 0, sizeof( _HashStr* ) * rTblSize );
1129 _SetGetExpFlds::const_iterator const itLast =
1130 mpUpdtFlds->GetSortLst()->upper_bound(
1131 const_cast<_SetGetExpFld*>(&rToThisFld));
1133 for( _SetGetExpFlds::const_iterator it = mpUpdtFlds->GetSortLst()->begin(); it != itLast; ++it )
1135 const SwTxtFld* pTxtFld = (*it)->GetFld();
1136 if( !pTxtFld )
1137 continue;
1139 const SwField* pFld = pTxtFld->GetFld().GetFld();
1140 switch( pFld->GetTyp()->Which() )
1142 case RES_SETEXPFLD:
1143 if( nsSwGetSetExpType::GSE_STRING & pFld->GetSubType() )
1145 // set the new value in the hash table
1146 // is the formula a field?
1147 SwSetExpField* pSFld = (SwSetExpField*)pFld;
1148 String aNew;
1149 LookString( ppHashTbl, rTblSize, pSFld->GetFormula(), aNew );
1151 if( !aNew.Len() ) // nothing found, then the formula is
1152 aNew = pSFld->GetFormula(); // the new value
1154 // #i3141# - update expression of field as in method
1155 // <SwDoc::UpdateExpFlds(..)> for string/text fields
1156 pSFld->ChgExpStr( aNew );
1158 // look up the field's name
1159 aNew = ((SwSetExpFieldType*)pSFld->GetTyp())->GetSetRefName();
1160 // Entry present?
1161 sal_uInt16 nPos;
1162 SwHash* pFnd = Find( aNew, ppHashTbl, rTblSize, &nPos );
1163 if( pFnd )
1164 // modify entry in the hash table
1165 ((_HashStr*)pFnd)->aSetStr = pSFld->GetExpStr();
1166 else
1167 // insert the new entry
1168 *(ppHashTbl + nPos ) = new _HashStr( aNew,
1169 pSFld->GetExpStr(), (_HashStr*)*(ppHashTbl + nPos) );
1171 break;
1172 case RES_DBFLD:
1174 const String& rName = pFld->GetTyp()->GetName();
1176 // Insert entry in the hash table
1177 // Entry present?
1178 sal_uInt16 nPos;
1179 SwHash* pFnd = Find( rName, ppHashTbl, rTblSize, &nPos );
1180 String const value(pFld->ExpandField(IsClipBoard()));
1181 if( pFnd )
1183 // modify entry in the hash table
1184 static_cast<_HashStr*>(pFnd)->aSetStr = value;
1186 else
1188 // insert the new entry
1189 *(ppHashTbl + nPos ) = new _HashStr( rName,
1190 value, static_cast<_HashStr *>(*(ppHashTbl + nPos)));
1193 break;
1198 void SwDoc::UpdateExpFlds( SwTxtFld* pUpdtFld, bool bUpdRefFlds )
1200 if( IsExpFldsLocked() || IsInReading() )
1201 return;
1203 bool bOldInUpdateFlds = mpUpdtFlds->IsInUpdateFlds();
1204 mpUpdtFlds->SetInUpdateFlds( true );
1206 mpUpdtFlds->MakeFldList( *this, sal_True, GETFLD_ALL );
1207 mbNewFldLst = sal_False;
1209 if( mpUpdtFlds->GetSortLst()->empty() )
1211 if( bUpdRefFlds )
1212 UpdateRefFlds(NULL);
1214 mpUpdtFlds->SetInUpdateFlds( bOldInUpdateFlds );
1215 mpUpdtFlds->SetFieldsDirty( false );
1216 return ;
1219 sal_uInt16 nWhich, n;
1221 // Hash table for all string replacements is filled on-the-fly.
1222 // Try to fabricate an uneven number.
1223 sal_uInt16 nStrFmtCnt = (( mpFldTypes->size() / 7 ) + 1 ) * 7;
1224 SwHash** pHashStrTbl = new SwHash*[ nStrFmtCnt ];
1225 memset( pHashStrTbl, 0, sizeof( _HashStr* ) * nStrFmtCnt );
1228 const SwFieldType* pFldType;
1229 // process separately:
1230 for( n = mpFldTypes->size(); n; )
1231 switch( ( pFldType = (*mpFldTypes)[ --n ] )->Which() )
1233 case RES_USERFLD:
1235 // Entry present?
1236 sal_uInt16 nPos;
1237 const String& rNm = pFldType->GetName();
1238 String sExpand(((SwUserFieldType*)pFldType)->Expand(nsSwGetSetExpType::GSE_STRING, 0, 0));
1239 SwHash* pFnd = Find( rNm, pHashStrTbl, nStrFmtCnt, &nPos );
1240 if( pFnd )
1241 // modify entry in the hash table
1242 ((_HashStr*)pFnd)->aSetStr = sExpand;
1243 else
1244 // insert the new entry
1245 *(pHashStrTbl + nPos ) = new _HashStr( rNm, sExpand,
1246 (_HashStr*)*(pHashStrTbl + nPos) );
1248 break;
1249 case RES_SETEXPFLD:
1250 ((SwSetExpFieldType*)pFldType)->SetOutlineChgNd( 0 );
1251 break;
1255 // The array is filled with all fields; start calculation.
1256 SwCalc aCalc( *this );
1258 String sDBNumNm( SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) );
1260 // already set the current record number
1261 SwNewDBMgr* pMgr = GetNewDBMgr();
1262 pMgr->CloseAll(sal_False);
1264 // Make sure we don't hide all sections, which would lead to a crash. First, count how many of them do we have.
1265 int nShownSections = 0;
1266 for( _SetGetExpFlds::const_iterator it = mpUpdtFlds->GetSortLst()->begin(); it != mpUpdtFlds->GetSortLst()->end(); ++it )
1268 SwSection* pSect = (SwSection*)(*it)->GetSection();
1269 if ( pSect && !pSect->IsCondHidden())
1270 nShownSections++;
1273 String aNew;
1274 for( _SetGetExpFlds::const_iterator it = mpUpdtFlds->GetSortLst()->begin(); it != mpUpdtFlds->GetSortLst()->end(); ++it )
1276 SwSection* pSect = (SwSection*)(*it)->GetSection();
1277 if( pSect )
1280 SwSbxValue aValue = aCalc.Calculate(
1281 pSect->GetCondition() );
1282 if(!aValue.IsVoidValue())
1284 // Do we want to hide this one?
1285 bool bHide = aValue.GetBool();
1286 if (bHide && !pSect->IsCondHidden())
1288 // This section will be hidden, but it wasn't before
1289 if (nShownSections == 1)
1291 // Is the last node part of a section?
1292 SwPaM aPam(GetNodes());
1293 aPam.Move(fnMoveForward, fnGoDoc);
1294 if (aPam.Start()->nNode.GetNode().StartOfSectionNode()->IsSectionNode())
1296 // This would be the last section, so set its condition to false, and avoid hiding it.
1297 OUString aCond("0");
1298 pSect->SetCondition(aCond);
1299 bHide = false;
1302 nShownSections--;
1304 pSect->SetCondHidden( bHide );
1306 continue;
1309 SwTxtFld* pTxtFld = (SwTxtFld*)(*it)->GetFld();
1310 if( !pTxtFld )
1312 OSL_ENSURE( !this, "what's wrong now'" );
1313 continue;
1316 SwFmtFld* pFmtFld = (SwFmtFld*)&pTxtFld->GetFld();
1317 SwField* pFld = pFmtFld->GetFld();
1319 switch( nWhich = pFld->GetTyp()->Which() )
1321 case RES_HIDDENTXTFLD:
1323 SwHiddenTxtField* pHFld = (SwHiddenTxtField*)pFld;
1324 SwSbxValue aValue = aCalc.Calculate( pHFld->GetPar1() );
1325 sal_Bool bValue = !aValue.GetBool();
1326 if(!aValue.IsVoidValue())
1328 pHFld->SetValue( bValue );
1329 // evaluate field
1330 pHFld->Evaluate(this);
1333 break;
1334 case RES_HIDDENPARAFLD:
1336 SwHiddenParaField* pHPFld = (SwHiddenParaField*)pFld;
1337 SwSbxValue aValue = aCalc.Calculate( pHPFld->GetPar1() );
1338 sal_Bool bValue = aValue.GetBool();
1339 if(!aValue.IsVoidValue())
1340 pHPFld->SetHidden( bValue );
1342 break;
1343 case RES_DBSETNUMBERFLD:
1345 ((SwDBSetNumberField*)pFld)->Evaluate(this);
1346 aCalc.VarChange( sDBNumNm, ((SwDBSetNumberField*)pFld)->GetSetNumber());
1348 break;
1349 case RES_DBNEXTSETFLD:
1350 case RES_DBNUMSETFLD:
1351 UpdateDBNumFlds( *(SwDBNameInfField*)pFld, aCalc );
1352 break;
1353 case RES_DBFLD:
1355 // evaluate field
1356 ((SwDBField*)pFld)->Evaluate();
1358 SwDBData aTmpDBData(((SwDBField*)pFld)->GetDBData());
1360 if( pMgr->IsDataSourceOpen(aTmpDBData.sDataSource, aTmpDBData.sCommand, sal_False))
1361 aCalc.VarChange( sDBNumNm, pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType));
1363 const String& rName = pFld->GetTyp()->GetName();
1365 // Add entry to hash table
1366 // Entry present?
1367 sal_uInt16 nPos;
1368 SwHash* pFnd = Find( rName, pHashStrTbl, nStrFmtCnt, &nPos );
1369 String const value(pFld->ExpandField(IsClipBoard()));
1370 if( pFnd )
1372 // Modify entry in the hash table
1373 static_cast<_HashStr*>(pFnd)->aSetStr = value;
1375 else
1377 // insert new entry
1378 *(pHashStrTbl + nPos ) = new _HashStr( rName,
1379 value, static_cast<_HashStr *>(*(pHashStrTbl + nPos)));
1382 break;
1383 case RES_GETEXPFLD:
1384 case RES_SETEXPFLD:
1386 if( nsSwGetSetExpType::GSE_STRING & pFld->GetSubType() ) // replace String
1388 if( RES_GETEXPFLD == nWhich )
1390 SwGetExpField* pGFld = (SwGetExpField*)pFld;
1392 if( (!pUpdtFld || pUpdtFld == pTxtFld )
1393 && pGFld->IsInBodyTxt() )
1395 LookString( pHashStrTbl, nStrFmtCnt,
1396 pGFld->GetFormula(), aNew );
1397 pGFld->ChgExpStr( aNew );
1400 else
1402 SwSetExpField* pSFld = (SwSetExpField*)pFld;
1403 // is the "formula" a field?
1404 LookString( pHashStrTbl, nStrFmtCnt,
1405 pSFld->GetFormula(), aNew );
1407 if( !aNew.Len() ) // nothing found then the formula is the new value
1408 aNew = pSFld->GetFormula();
1410 // only update one field
1411 if( !pUpdtFld || pUpdtFld == pTxtFld )
1412 pSFld->ChgExpStr( aNew );
1414 // lookup the field's name
1415 aNew = ((SwSetExpFieldType*)pSFld->GetTyp())->GetSetRefName();
1416 // Entry present?
1417 sal_uInt16 nPos;
1418 SwHash* pFnd = Find( aNew, pHashStrTbl, nStrFmtCnt, &nPos );
1419 if( pFnd )
1420 // Modify entry in the hash table
1421 ((_HashStr*)pFnd)->aSetStr = pSFld->GetExpStr();
1422 else
1423 // insert new entry
1424 *(pHashStrTbl + nPos ) = pFnd = new _HashStr( aNew,
1425 pSFld->GetExpStr(),
1426 (_HashStr*)*(pHashStrTbl + nPos) );
1428 // Extension for calculation with Strings
1429 SwSbxValue aValue;
1430 aValue.PutString( ((_HashStr*)pFnd)->aSetStr );
1431 aCalc.VarChange( aNew, aValue );
1434 else // recalculate formula
1436 if( RES_GETEXPFLD == nWhich )
1438 SwGetExpField* pGFld = (SwGetExpField*)pFld;
1440 if( (!pUpdtFld || pUpdtFld == pTxtFld )
1441 && pGFld->IsInBodyTxt() )
1443 SwSbxValue aValue = aCalc.Calculate(
1444 pGFld->GetFormula());
1445 if(!aValue.IsVoidValue())
1446 pGFld->SetValue(aValue.GetDouble() );
1449 else
1451 SwSetExpField* pSFld = (SwSetExpField*)pFld;
1452 SwSetExpFieldType* pSFldTyp = (SwSetExpFieldType*)pFld->GetTyp();
1453 aNew = pSFldTyp->GetName();
1455 SwNode* pSeqNd = 0;
1457 if( pSFld->IsSequenceFld() )
1459 const sal_uInt8 nLvl = pSFldTyp->GetOutlineLvl();
1460 if( MAXLEVEL > nLvl )
1462 // test if the Number needs to be updated
1463 pSeqNd = GetNodes()[ (*it)->GetNode() ];
1465 const SwTxtNode* pOutlNd = pSeqNd->
1466 FindOutlineNodeOfLevel( nLvl );
1467 if( pSFldTyp->GetOutlineChgNd() != pOutlNd )
1469 pSFldTyp->SetOutlineChgNd( pOutlNd );
1470 aCalc.VarChange( aNew, 0 );
1475 aNew += '=';
1476 aNew += pSFld->GetFormula();
1478 SwSbxValue aValue = aCalc.Calculate( aNew );
1479 double nErg = aValue.GetDouble();
1480 // only update one field
1481 if( !aValue.IsVoidValue() && (!pUpdtFld || pUpdtFld == pTxtFld) )
1483 pSFld->SetValue( nErg );
1485 if( pSeqNd )
1486 pSFldTyp->SetChapter( *pSFld, *pSeqNd );
1491 } // switch
1493 pFmtFld->ModifyNotification( 0, 0 ); // trigger formatting
1495 if( pUpdtFld == pTxtFld ) // if only this one is updated
1497 if( RES_GETEXPFLD == nWhich || // only GetField or
1498 RES_HIDDENTXTFLD == nWhich || // HiddenTxt?
1499 RES_HIDDENPARAFLD == nWhich) // HiddenParaFld?
1500 break; // quit
1501 pUpdtFld = 0; // update all from here on
1505 pMgr->CloseAll(sal_False);
1506 // delete hash table
1507 ::DeleteHashTable( pHashStrTbl, nStrFmtCnt );
1509 // update reference fields
1510 if( bUpdRefFlds )
1511 UpdateRefFlds(NULL);
1513 mpUpdtFlds->SetInUpdateFlds( bOldInUpdateFlds );
1514 mpUpdtFlds->SetFieldsDirty( false );
1517 void SwDoc::UpdateDBNumFlds( SwDBNameInfField& rDBFld, SwCalc& rCalc )
1519 SwNewDBMgr* pMgr = GetNewDBMgr();
1521 sal_uInt16 nFldType = rDBFld.Which();
1523 sal_Bool bPar1 = rCalc.Calculate( rDBFld.GetPar1() ).GetBool();
1525 if( RES_DBNEXTSETFLD == nFldType )
1526 ((SwDBNextSetField&)rDBFld).SetCondValid( bPar1 );
1527 else
1528 ((SwDBNumSetField&)rDBFld).SetCondValid( bPar1 );
1530 if( !rDBFld.GetRealDBData().sDataSource.isEmpty() )
1532 // Edit a certain database
1533 if( RES_DBNEXTSETFLD == nFldType )
1534 ((SwDBNextSetField&)rDBFld).Evaluate(this);
1535 else
1536 ((SwDBNumSetField&)rDBFld).Evaluate(this);
1538 SwDBData aTmpDBData( rDBFld.GetDBData(this) );
1540 if( pMgr->OpenDataSource( aTmpDBData.sDataSource, aTmpDBData.sCommand, -1, false ))
1541 rCalc.VarChange( lcl_GetDBVarName( *this, rDBFld),
1542 pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType) );
1544 else
1546 OSL_FAIL("TODO: what should happen with unnamed DBFields?");
1550 void SwDoc::_InitFieldTypes() // is being called by the CTOR
1552 // Field types
1553 mpFldTypes->push_back( new SwDateTimeFieldType(this) );
1554 mpFldTypes->push_back( new SwChapterFieldType );
1555 mpFldTypes->push_back( new SwPageNumberFieldType );
1556 mpFldTypes->push_back( new SwAuthorFieldType );
1557 mpFldTypes->push_back( new SwFileNameFieldType(this) );
1558 mpFldTypes->push_back( new SwDBNameFieldType(this) );
1559 mpFldTypes->push_back( new SwGetExpFieldType(this) );
1560 mpFldTypes->push_back( new SwGetRefFieldType( this ) );
1561 mpFldTypes->push_back( new SwHiddenTxtFieldType );
1562 mpFldTypes->push_back( new SwPostItFieldType(this) );
1563 mpFldTypes->push_back( new SwDocStatFieldType(this) );
1564 mpFldTypes->push_back( new SwDocInfoFieldType(this) );
1565 mpFldTypes->push_back( new SwInputFieldType( this ) );
1566 mpFldTypes->push_back( new SwTblFieldType( this ) );
1567 mpFldTypes->push_back( new SwMacroFieldType(this) );
1568 mpFldTypes->push_back( new SwHiddenParaFieldType );
1569 mpFldTypes->push_back( new SwDBNextSetFieldType );
1570 mpFldTypes->push_back( new SwDBNumSetFieldType );
1571 mpFldTypes->push_back( new SwDBSetNumberFieldType );
1572 mpFldTypes->push_back( new SwTemplNameFieldType(this) );
1573 mpFldTypes->push_back( new SwTemplNameFieldType(this) );
1574 mpFldTypes->push_back( new SwExtUserFieldType );
1575 mpFldTypes->push_back( new SwRefPageSetFieldType );
1576 mpFldTypes->push_back( new SwRefPageGetFieldType( this ) );
1577 mpFldTypes->push_back( new SwJumpEditFieldType( this ) );
1578 mpFldTypes->push_back( new SwScriptFieldType( this ) );
1579 mpFldTypes->push_back( new SwCombinedCharFieldType );
1580 mpFldTypes->push_back( new SwDropDownFieldType );
1582 // Types have to be at the end!
1583 // We expect this in the InsertFldType!
1584 // MIB 14.04.95: In Sw3StringPool::Setup (sw3imp.cxx) and
1585 // lcl_sw3io_InSetExpField (sw3field.cxx) now also
1586 mpFldTypes->push_back( new SwSetExpFieldType(this,
1587 SW_RESSTR(STR_POOLCOLL_LABEL_ABB), nsSwGetSetExpType::GSE_SEQ) );
1588 mpFldTypes->push_back( new SwSetExpFieldType(this,
1589 SW_RESSTR(STR_POOLCOLL_LABEL_TABLE), nsSwGetSetExpType::GSE_SEQ) );
1590 mpFldTypes->push_back( new SwSetExpFieldType(this,
1591 SW_RESSTR(STR_POOLCOLL_LABEL_FRAME), nsSwGetSetExpType::GSE_SEQ) );
1592 mpFldTypes->push_back( new SwSetExpFieldType(this,
1593 SW_RESSTR(STR_POOLCOLL_LABEL_DRAWING), nsSwGetSetExpType::GSE_SEQ) );
1595 OSL_ENSURE( mpFldTypes->size() == INIT_FLDTYPES, "Bad initsize: SwFldTypes" );
1598 void SwDoc::InsDelFldInFldLst( bool bIns, const SwTxtFld& rFld )
1600 if( !mbNewFldLst || !IsInDtor() )
1601 mpUpdtFlds->InsDelFldInFldLst( bIns, rFld );
1604 SwDBData SwDoc::GetDBData()
1606 return GetDBDesc();
1609 const SwDBData& SwDoc::GetDBDesc()
1611 if(maDBData.sDataSource.isEmpty())
1613 const sal_uInt16 nSize = mpFldTypes->size();
1614 for(sal_uInt16 i = 0; i < nSize && maDBData.sDataSource.isEmpty(); ++i)
1616 SwFieldType& rFldType = *((*mpFldTypes)[i]);
1617 sal_uInt16 nWhich = rFldType.Which();
1618 if(IsUsed(rFldType))
1620 switch(nWhich)
1622 case RES_DBFLD:
1623 case RES_DBNEXTSETFLD:
1624 case RES_DBNUMSETFLD:
1625 case RES_DBSETNUMBERFLD:
1627 SwIterator<SwFmtFld,SwFieldType> aIter( rFldType );
1628 for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
1630 if(pFld->IsFldInDoc())
1632 if(RES_DBFLD == nWhich)
1633 maDBData =
1634 (static_cast < SwDBFieldType * > (pFld->GetFld()->GetTyp()))
1635 ->GetDBData();
1636 else
1637 maDBData = (static_cast < SwDBNameInfField* > (pFld->GetFld()))->GetRealDBData();
1638 break;
1642 break;
1647 if(maDBData.sDataSource.isEmpty())
1648 maDBData = GetNewDBMgr()->GetAddressDBName();
1649 return maDBData;
1652 void SwDoc::SetInitDBFields( sal_Bool b )
1654 GetNewDBMgr()->SetInitDBFields( b );
1657 /// Get all databases that are used by fields
1658 static String lcl_DBDataToString(const SwDBData& rData)
1660 String sRet = rData.sDataSource;
1661 sRet += DB_DELIM;
1662 sRet += (String)rData.sCommand;
1663 sRet += DB_DELIM;
1664 sRet += OUString::number(rData.nCommandType);
1665 return sRet;
1668 void SwDoc::GetAllUsedDB( std::vector<String>& rDBNameList,
1669 const std::vector<String>* pAllDBNames )
1671 std::vector<String> aUsedDBNames;
1672 std::vector<String> aAllDBNames;
1674 if( !pAllDBNames )
1676 GetAllDBNames( aAllDBNames );
1677 pAllDBNames = &aAllDBNames;
1680 SwSectionFmts& rArr = GetSections();
1681 for (sal_uInt16 n = rArr.size(); n; )
1683 SwSection* pSect = rArr[ --n ]->GetSection();
1685 if( pSect )
1687 String aCond( pSect->GetCondition() );
1688 AddUsedDBToList( rDBNameList, FindUsedDBs( *pAllDBNames,
1689 aCond, aUsedDBNames ) );
1690 aUsedDBNames.clear();
1694 const SfxPoolItem* pItem;
1695 sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD );
1696 for (sal_uInt32 n = 0; n < nMaxItems; ++n)
1698 if( 0 == (pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) ))
1699 continue;
1701 const SwFmtFld* pFmtFld = (SwFmtFld*)pItem;
1702 const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld();
1703 if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() )
1704 continue;
1706 const SwField* pFld = pFmtFld->GetFld();
1707 switch( pFld->GetTyp()->Which() )
1709 case RES_DBFLD:
1710 AddUsedDBToList( rDBNameList,
1711 lcl_DBDataToString(((SwDBField*)pFld)->GetDBData() ));
1712 break;
1714 case RES_DBSETNUMBERFLD:
1715 case RES_DBNAMEFLD:
1716 AddUsedDBToList( rDBNameList,
1717 lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData() ));
1718 break;
1720 case RES_DBNUMSETFLD:
1721 case RES_DBNEXTSETFLD:
1722 AddUsedDBToList( rDBNameList,
1723 lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData() ));
1724 // no break // JP: is that right like that?
1726 case RES_HIDDENTXTFLD:
1727 case RES_HIDDENPARAFLD:
1728 AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames,
1729 pFld->GetPar1(), aUsedDBNames ));
1730 aUsedDBNames.clear();
1731 break;
1733 case RES_SETEXPFLD:
1734 case RES_GETEXPFLD:
1735 case RES_TABLEFLD:
1736 AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames,
1737 pFld->GetFormula(), aUsedDBNames ));
1738 aUsedDBNames.clear();
1739 break;
1744 void SwDoc::GetAllDBNames( std::vector<String>& rAllDBNames )
1746 SwNewDBMgr* pMgr = GetNewDBMgr();
1748 const SwDSParamArr& rArr = pMgr->GetDSParamArray();
1749 for(sal_uInt16 i = 0; i < rArr.size(); i++)
1751 const SwDSParam* pParam = &rArr[i];
1752 OUStringBuffer sStr(pParam->sDataSource.getLength() + pParam->sCommand.getLength() + 2);
1753 sStr.append(pParam->sDataSource );
1754 sStr.append(DB_DELIM);
1755 sStr.append(pParam->sCommand);
1756 rAllDBNames.push_back(sStr.makeStringAndClear());
1760 std::vector<String>& SwDoc::FindUsedDBs( const std::vector<String>& rAllDBNames,
1761 const String& rFormel,
1762 std::vector<String>& rUsedDBNames )
1764 const CharClass& rCC = GetAppCharClass();
1765 String sFormel( rFormel);
1766 #ifndef UNX
1767 sFormel = rCC.uppercase( sFormel );
1768 #endif
1770 xub_StrLen nPos;
1771 for (sal_uInt16 i = 0; i < rAllDBNames.size(); ++i )
1773 String pStr(rAllDBNames[i]);
1775 if( STRING_NOTFOUND != (nPos = sFormel.Search( pStr )) &&
1776 sFormel.GetChar( nPos + pStr.Len() ) == '.' &&
1777 (!nPos || !rCC.isLetterNumeric( sFormel, nPos - 1 )))
1779 // Look up table name
1780 xub_StrLen nEndPos;
1781 nPos += pStr.Len() + 1;
1782 if( STRING_NOTFOUND != (nEndPos = sFormel.Search('.', nPos)) )
1784 pStr.Append( DB_DELIM );
1785 pStr.Append( sFormel.Copy( nPos, nEndPos - nPos ));
1786 rUsedDBNames.push_back(pStr);
1790 return rUsedDBNames;
1793 void SwDoc::AddUsedDBToList( std::vector<String>& rDBNameList,
1794 const std::vector<String>& rUsedDBNames )
1796 for (sal_uInt16 i = 0; i < rUsedDBNames.size(); ++i)
1797 AddUsedDBToList( rDBNameList, rUsedDBNames[i] );
1800 void SwDoc::AddUsedDBToList( std::vector<String>& rDBNameList, const String& rDBName)
1802 if( !rDBName.Len() )
1803 return;
1805 #ifdef UNX
1806 for( sal_uInt16 i = 0; i < rDBNameList.size(); ++i )
1807 if( rDBName == rDBNameList[i].GetToken(0) )
1808 return;
1809 #else
1810 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
1811 for( sal_uInt16 i = 0; i < rDBNameList.size(); ++i )
1812 if( rSCmp.isEqual( rDBName, rDBNameList[i].GetToken(0) ) )
1813 return;
1814 #endif
1816 SwDBData aData;
1817 aData.sDataSource = rDBName.GetToken(0, DB_DELIM);
1818 aData.sCommand = rDBName.GetToken(1, DB_DELIM);
1819 aData.nCommandType = -1;
1820 GetNewDBMgr()->CreateDSData(aData);
1821 rDBNameList.push_back(rDBName);
1824 void SwDoc::ChangeDBFields( const std::vector<String>& rOldNames,
1825 const String& rNewName )
1827 SwDBData aNewDBData;
1828 aNewDBData.sDataSource = rNewName.GetToken(0, DB_DELIM);
1829 aNewDBData.sCommand = rNewName.GetToken(1, DB_DELIM);
1830 aNewDBData.nCommandType = (short)rNewName.GetToken(2, DB_DELIM).ToInt32();
1832 String sFormel;
1834 SwSectionFmts& rArr = GetSections();
1835 for (sal_uInt16 n = rArr.size(); n; )
1837 SwSection* pSect = rArr[ --n ]->GetSection();
1839 if( pSect )
1841 sFormel = pSect->GetCondition();
1842 ReplaceUsedDBs( rOldNames, rNewName, sFormel);
1843 pSect->SetCondition(sFormel);
1847 const SfxPoolItem* pItem;
1848 sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD );
1850 for (sal_uInt32 n = 0; n < nMaxItems; ++n )
1852 if( 0 == (pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) ))
1853 continue;
1855 SwFmtFld* pFmtFld = (SwFmtFld*)pItem;
1856 SwTxtFld* pTxtFld = pFmtFld->GetTxtFld();
1857 if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() )
1858 continue;
1860 SwField* pFld = pFmtFld->GetFld();
1861 bool bExpand = false;
1863 switch( pFld->GetTyp()->Which() )
1865 case RES_DBFLD:
1866 if( IsNameInArray( rOldNames, lcl_DBDataToString(((SwDBField*)pFld)->GetDBData())))
1868 SwDBFieldType* pOldTyp = (SwDBFieldType*)pFld->GetTyp();
1870 SwDBFieldType* pTyp = (SwDBFieldType*)InsertFldType(
1871 SwDBFieldType(this, pOldTyp->GetColumnName(), aNewDBData));
1873 pFmtFld->RegisterToFieldType( *pTyp );
1874 pFld->ChgTyp(pTyp);
1876 ((SwDBField*)pFld)->ClearInitialized();
1877 ((SwDBField*)pFld)->InitContent();
1879 bExpand = true;
1881 break;
1883 case RES_DBSETNUMBERFLD:
1884 case RES_DBNAMEFLD:
1885 if( IsNameInArray( rOldNames,
1886 lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData())))
1888 ((SwDBNameInfField*)pFld)->SetDBData(aNewDBData);
1889 bExpand = true;
1891 break;
1893 case RES_DBNUMSETFLD:
1894 case RES_DBNEXTSETFLD:
1895 if( IsNameInArray( rOldNames,
1896 lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData())))
1898 ((SwDBNameInfField*)pFld)->SetDBData(aNewDBData);
1899 bExpand = true;
1901 // no break;
1902 case RES_HIDDENTXTFLD:
1903 case RES_HIDDENPARAFLD:
1904 sFormel = pFld->GetPar1();
1905 ReplaceUsedDBs( rOldNames, rNewName, sFormel);
1906 pFld->SetPar1( sFormel );
1907 bExpand = true;
1908 break;
1910 case RES_SETEXPFLD:
1911 case RES_GETEXPFLD:
1912 case RES_TABLEFLD:
1913 sFormel = pFld->GetFormula();
1914 ReplaceUsedDBs( rOldNames, rNewName, sFormel);
1915 pFld->SetPar2( sFormel );
1916 bExpand = true;
1917 break;
1920 if (bExpand)
1921 pTxtFld->ExpandAlways();
1923 SetModified();
1926 void SwDoc::ReplaceUsedDBs( const std::vector<String>& rUsedDBNames,
1927 const String& rNewName, String& rFormel )
1929 const CharClass& rCC = GetAppCharClass();
1930 String sFormel(rFormel);
1931 String sNewName( rNewName );
1932 sNewName.SearchAndReplace( DB_DELIM, '.');
1933 //the command type is not part of the condition
1934 sNewName = sNewName.GetToken(0, DB_DELIM);
1935 String sUpperNewNm( sNewName );
1937 for( sal_uInt16 i = 0; i < rUsedDBNames.size(); ++i )
1939 String sDBName( rUsedDBNames[i] );
1941 sDBName.SearchAndReplace( DB_DELIM, '.');
1942 //cut off command type
1943 sDBName = sDBName.GetToken(0, DB_DELIM);
1944 if( !sDBName.Equals( sUpperNewNm ))
1946 xub_StrLen nPos = 0;
1948 while ((nPos = sFormel.Search(sDBName, nPos)) != STRING_NOTFOUND)
1950 if( sFormel.GetChar( nPos + sDBName.Len() ) == '.' &&
1951 (!nPos || !rCC.isLetterNumeric( sFormel, nPos - 1 )))
1953 rFormel.Erase( nPos, sDBName.Len() );
1954 rFormel.Insert( sNewName, nPos );
1955 //prevent re-searching - this is useless and provokes
1956 //endless loops when names containing each other and numbers are exchanged
1957 //e.g.: old ?12345.12345 new: i12345.12345
1958 nPos = nPos + sNewName.Len();
1959 sFormel = rFormel;
1966 bool SwDoc::IsNameInArray( const std::vector<String>& rArr, const String& rName )
1968 #ifdef UNX
1969 for( sal_uInt16 i = 0; i < rArr.size(); ++i )
1970 if( rName == rArr[ i ] )
1971 return true;
1972 #else
1973 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
1974 for( sal_uInt16 i = 0; i < rArr.size(); ++i )
1975 if( rSCmp.isEqual( rName, rArr[ i] ))
1976 return true;
1977 #endif
1978 return false;
1981 void SwDoc::SetFixFields( bool bOnlyTimeDate, const DateTime* pNewDateTime )
1983 sal_Bool bIsModified = IsModified();
1985 sal_Int32 nDate;
1986 sal_Int64 nTime;
1987 if( pNewDateTime )
1989 nDate = pNewDateTime->GetDate();
1990 nTime = pNewDateTime->GetTime();
1992 else
1994 nDate = Date( Date::SYSTEM ).GetDate();
1995 nTime = Time( Time::SYSTEM ).GetTime();
1998 sal_uInt16 aTypes[5] = {
1999 /*0*/ RES_DOCINFOFLD,
2000 /*1*/ RES_AUTHORFLD,
2001 /*2*/ RES_EXTUSERFLD,
2002 /*3*/ RES_FILENAMEFLD,
2003 /*4*/ RES_DATETIMEFLD }; // MUST be at the end!
2005 sal_uInt16 nStt = bOnlyTimeDate ? 4 : 0;
2007 for( ; nStt < 5; ++nStt )
2009 SwFieldType* pFldType = GetSysFldType( aTypes[ nStt ] );
2010 SwIterator<SwFmtFld,SwFieldType> aIter( *pFldType );
2011 for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
2013 if( pFld && pFld->GetTxtFld() )
2015 bool bChgd = false;
2016 switch( aTypes[ nStt ] )
2018 case RES_DOCINFOFLD:
2019 if( ((SwDocInfoField*)pFld->GetFld())->IsFixed() )
2021 bChgd = true;
2022 SwDocInfoField* pDocInfFld = (SwDocInfoField*)pFld->GetFld();
2023 pDocInfFld->SetExpansion( ((SwDocInfoFieldType*)
2024 pDocInfFld->GetTyp())->Expand(
2025 pDocInfFld->GetSubType(),
2026 pDocInfFld->GetFormat(),
2027 pDocInfFld->GetLanguage(),
2028 pDocInfFld->GetName() ) );
2030 break;
2032 case RES_AUTHORFLD:
2033 if( ((SwAuthorField*)pFld->GetFld())->IsFixed() )
2035 bChgd = true;
2036 SwAuthorField* pAuthorFld = (SwAuthorField*)pFld->GetFld();
2037 pAuthorFld->SetExpansion( ((SwAuthorFieldType*)
2038 pAuthorFld->GetTyp())->Expand(
2039 pAuthorFld->GetFormat() ) );
2041 break;
2043 case RES_EXTUSERFLD:
2044 if( ((SwExtUserField*)pFld->GetFld())->IsFixed() )
2046 bChgd = true;
2047 SwExtUserField* pExtUserFld = (SwExtUserField*)pFld->GetFld();
2048 pExtUserFld->SetExpansion( ((SwExtUserFieldType*)
2049 pExtUserFld->GetTyp())->Expand(
2050 pExtUserFld->GetSubType(),
2051 pExtUserFld->GetFormat()));
2053 break;
2055 case RES_DATETIMEFLD:
2056 if( ((SwDateTimeField*)pFld->GetFld())->IsFixed() )
2058 bChgd = true;
2059 ((SwDateTimeField*)pFld->GetFld())->SetDateTime(
2060 DateTime(Date(nDate), Time(nTime)) );
2062 break;
2064 case RES_FILENAMEFLD:
2065 if( ((SwFileNameField*)pFld->GetFld())->IsFixed() )
2067 bChgd = true;
2068 SwFileNameField* pFileNameFld =
2069 (SwFileNameField*)pFld->GetFld();
2070 pFileNameFld->SetExpansion( ((SwFileNameFieldType*)
2071 pFileNameFld->GetTyp())->Expand(
2072 pFileNameFld->GetFormat() ) );
2074 break;
2077 // Trigger formatting
2078 if( bChgd )
2079 pFld->ModifyNotification( 0, 0 );
2084 if( !bIsModified )
2085 ResetModified();
2088 bool SwDoc::SetFieldsDirty( bool b, const SwNode* pChk, sal_uLong nLen )
2090 // See if the supplied nodes actually contain fields.
2091 // If they don't, the flag doesn't need to be changed.
2092 bool bFldsFnd = false;
2093 if( b && pChk && !GetUpdtFlds().IsFieldsDirty() && !IsInDtor()
2094 // ?? what's up with Undo, this is also wanted there!
2095 /*&& &pChk->GetNodes() == &GetNodes()*/ )
2097 b = false;
2098 if( !nLen )
2099 ++nLen;
2100 sal_uLong nStt = pChk->GetIndex();
2101 const SwNodes& rNds = pChk->GetNodes();
2102 while( nLen-- )
2104 const SwTxtNode* pTNd = rNds[ nStt++ ]->GetTxtNode();
2105 if( pTNd )
2107 if( pTNd->GetAttrOutlineLevel() != 0 )
2108 // update chapter fields
2109 b = true;
2110 else if( pTNd->GetpSwpHints() && pTNd->GetSwpHints().Count() )
2111 for( sal_uInt16 n = 0, nEnd = pTNd->GetSwpHints().Count();
2112 n < nEnd; ++n )
2114 const SwTxtAttr* pAttr = pTNd->GetSwpHints()[ n ];
2115 if( RES_TXTATR_FIELD == pAttr->Which() )
2117 b = true;
2118 break;
2122 if( b )
2123 break;
2126 bFldsFnd = b;
2128 GetUpdtFlds().SetFieldsDirty( b );
2129 return bFldsFnd;
2132 void SwDoc::ChangeAuthorityData( const SwAuthEntry* pNewData )
2134 const sal_uInt16 nSize = mpFldTypes->size();
2136 for( sal_uInt16 i = INIT_FLDTYPES; i < nSize; ++i )
2138 SwFieldType* pFldType = (*mpFldTypes)[i];
2139 if( RES_AUTHORITY == pFldType->Which() )
2141 SwAuthorityFieldType* pAuthType = (SwAuthorityFieldType*)pFldType;
2142 pAuthType->ChangeEntryContent(pNewData);
2143 break;
2149 void SwDocUpdtFld::InsDelFldInFldLst( bool bIns, const SwTxtFld& rFld )
2151 sal_uInt16 nWhich = rFld.GetFld().GetFld()->GetTyp()->Which();
2152 switch( nWhich )
2154 case RES_DBFLD:
2155 case RES_SETEXPFLD:
2156 case RES_HIDDENPARAFLD:
2157 case RES_HIDDENTXTFLD:
2158 case RES_DBNUMSETFLD:
2159 case RES_DBNEXTSETFLD:
2160 case RES_DBSETNUMBERFLD:
2161 case RES_GETEXPFLD:
2162 break; // these have to be added/removed!
2164 default:
2165 return;
2168 SetFieldsDirty( true );
2169 if( !pFldSortLst )
2171 if( !bIns ) // if list is present and deleted
2172 return; // don't do a thing
2173 pFldSortLst = new _SetGetExpFlds;
2176 if( bIns ) // insert anew:
2177 GetBodyNode( rFld, nWhich );
2178 else
2180 // look up via the pTxtFld pointer. It is a sorted list, but it's sorted by node
2181 // position. Until this is found, the search for the pointer is already done.
2182 for( sal_uInt16 n = 0; n < pFldSortLst->size(); ++n )
2183 if( &rFld == (*pFldSortLst)[ n ]->GetPointer() )
2185 delete (*pFldSortLst)[n];
2186 pFldSortLst->erase(n);
2187 n--; // one field can occur multiple times
2192 void SwDocUpdtFld::MakeFldList( SwDoc& rDoc, int bAll, int eGetMode )
2194 if( !pFldSortLst || bAll || !( eGetMode & nFldLstGetMode ) ||
2195 rDoc.GetNodes().Count() != nNodes )
2196 _MakeFldList( rDoc, eGetMode );
2199 void SwDocUpdtFld::_MakeFldList( SwDoc& rDoc, int eGetMode )
2201 // new version: walk all fields of the attribute pool
2202 delete pFldSortLst;
2203 pFldSortLst = new _SetGetExpFlds;
2205 // consider and unhide sections
2206 // with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>)
2207 // notes by OD:
2208 // eGetMode == GETFLD_CALC in call from methods SwDoc::FldsToCalc
2209 // eGetMode == GETFLD_EXPAND in call from method SwDoc::FldsToExpand
2210 // eGetMode == GETFLD_ALL in call from method SwDoc::UpdateExpFlds
2211 // I figured out that hidden section only have to be shown,
2212 // if fields have updated (call by SwDoc::UpdateExpFlds) and thus
2213 // the hide conditions of section have to be updated.
2214 // For correct updating the hide condition of a section, its position
2215 // have to be known in order to insert the hide condition as a new
2216 // expression field into the sorted field list (<pFldSortLst>).
2217 if ( eGetMode == GETFLD_ALL )
2218 // Collect the sections first. Supply sections that are hidden by condition
2219 // with frames so that the contained fields are sorted properly.
2221 // In order for the frames to be created the right way, they have to be expanded
2222 // from top to bottom
2223 std::vector<sal_uLong> aTmpArr;
2224 SwSectionFmts& rArr = rDoc.GetSections();
2225 SwSectionNode* pSectNd;
2226 sal_uInt16 nArrStt = 0;
2227 sal_uLong nSttCntnt = rDoc.GetNodes().GetEndOfExtras().GetIndex();
2229 for (sal_uInt16 n = rArr.size(); n; )
2231 SwSection* pSect = rArr[ --n ]->GetSection();
2232 if( pSect && pSect->IsHidden() && pSect->GetCondition().Len() &&
2233 0 != ( pSectNd = pSect->GetFmt()->GetSectionNode() ))
2235 sal_uLong nIdx = pSectNd->GetIndex();
2236 aTmpArr.push_back( nIdx );
2237 if( nIdx < nSttCntnt )
2238 ++nArrStt;
2241 std::sort(aTmpArr.begin(), aTmpArr.end());
2243 // Display all first so that we have frames. The BodyAnchor is defined by that.
2244 // First the ContentArea, then the special areas!
2245 for (sal_uInt16 n = nArrStt; n < aTmpArr.size(); ++n)
2247 pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
2248 OSL_ENSURE( pSectNd, "Where is my SectionNode" );
2249 pSectNd->GetSection().SetCondHidden( sal_False );
2251 for (sal_uInt16 n = 0; n < nArrStt; ++n)
2253 pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
2254 OSL_ENSURE( pSectNd, "Where is my SectionNode" );
2255 pSectNd->GetSection().SetCondHidden( sal_False );
2258 // add all to the list so that they are sorted
2259 for (sal_uInt16 n = 0; n < aTmpArr.size(); ++n)
2261 GetBodyNode( *rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode() );
2265 OUString sTrue("TRUE"), sFalse("FALSE");
2267 bool bIsDBMgr = 0 != rDoc.GetNewDBMgr();
2268 sal_uInt16 nWhich, n;
2269 const OUString* pFormel = 0;
2270 const SfxPoolItem* pItem;
2271 sal_uInt32 nMaxItems = rDoc.GetAttrPool().GetItemCount2( RES_TXTATR_FIELD );
2272 for( n = 0; n < nMaxItems; ++n )
2274 if( 0 == (pItem = rDoc.GetAttrPool().GetItem2( RES_TXTATR_FIELD, n )) )
2275 continue;
2277 const SwFmtFld* pFmtFld = (SwFmtFld*)pItem;
2278 const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld();
2279 if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() )
2280 continue;
2282 const SwField* pFld = pFmtFld->GetFld();
2283 switch( nWhich = pFld->GetTyp()->Which() )
2285 case RES_DBSETNUMBERFLD:
2286 case RES_GETEXPFLD:
2287 if( GETFLD_ALL == eGetMode )
2288 pFormel = &sTrue;
2289 break;
2291 case RES_DBFLD:
2292 if( GETFLD_EXPAND & eGetMode )
2293 pFormel = &sTrue;
2294 break;
2296 case RES_SETEXPFLD:
2297 if ( !(eGetMode == GETFLD_EXPAND) ||
2298 (nsSwGetSetExpType::GSE_STRING & pFld->GetSubType()) )
2300 pFormel = &sTrue;
2302 break;
2304 case RES_HIDDENPARAFLD:
2305 if( GETFLD_ALL == eGetMode )
2307 pFormel = &pFld->GetPar1();
2308 if (pFormel->isEmpty() || pFormel->equals(sFalse))
2309 ((SwHiddenParaField*)pFld)->SetHidden( sal_False );
2310 else if (pFormel->equals(sTrue))
2311 ((SwHiddenParaField*)pFld)->SetHidden( sal_True );
2312 else
2313 break;
2315 pFormel = 0;
2316 // trigger formatting
2317 ((SwFmtFld*)pFmtFld)->ModifyNotification( 0, 0 );
2319 break;
2321 case RES_HIDDENTXTFLD:
2322 if( GETFLD_ALL == eGetMode )
2324 pFormel = &pFld->GetPar1();
2325 if (pFormel->isEmpty() || pFormel->equals(sFalse))
2326 ((SwHiddenTxtField*)pFld)->SetValue( sal_True );
2327 else if (pFormel->equals(sTrue))
2328 ((SwHiddenTxtField*)pFld)->SetValue( sal_False );
2329 else
2330 break;
2332 pFormel = 0;
2334 // evaluate field
2335 ((SwHiddenTxtField*)pFld)->Evaluate(&rDoc);
2336 // trigger formatting
2337 ((SwFmtFld*)pFmtFld)->ModifyNotification( 0, 0 );
2339 break;
2341 case RES_DBNUMSETFLD:
2343 SwDBData aDBData(((SwDBNumSetField*)pFld)->GetDBData(&rDoc));
2345 if (
2346 (bIsDBMgr && rDoc.GetNewDBMgr()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) &&
2347 (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && ((SwDBNumSetField*)pFld)->IsCondValid()))
2350 pFormel = &pFld->GetPar1();
2353 break;
2354 case RES_DBNEXTSETFLD:
2356 SwDBData aDBData(((SwDBNextSetField*)pFld)->GetDBData(&rDoc));
2358 if (
2359 (bIsDBMgr && rDoc.GetNewDBMgr()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) &&
2360 (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && ((SwDBNextSetField*)pFld)->IsCondValid()))
2363 pFormel = &pFld->GetPar1();
2366 break;
2369 if (pFormel && !pFormel->isEmpty())
2371 GetBodyNode( *pTxtFld, nWhich );
2372 pFormel = 0;
2375 nFldLstGetMode = static_cast<sal_uInt8>( eGetMode );
2376 nNodes = rDoc.GetNodes().Count();
2379 void SwDocUpdtFld::GetBodyNode( const SwTxtFld& rTFld, sal_uInt16 nFldWhich )
2381 const SwTxtNode& rTxtNd = rTFld.GetTxtNode();
2382 const SwDoc& rDoc = *rTxtNd.GetDoc();
2384 // always the first! (in tab headline, header-/footer)
2385 Point aPt;
2386 const SwCntntFrm* pFrm = rTxtNd.getLayoutFrm( rDoc.GetCurrentLayout(), &aPt, 0, sal_False );
2388 _SetGetExpFld* pNew = NULL;
2389 sal_Bool bIsInBody = sal_False;
2391 if( !pFrm || pFrm->IsInDocBody() )
2393 // create index to determine the TextNode
2394 SwNodeIndex aIdx( rTxtNd );
2395 bIsInBody = rDoc.GetNodes().GetEndOfExtras().GetIndex() < aIdx.GetIndex();
2397 // We don't want to update fields in redlines, or those
2398 // in frames whose anchor is in redline. However, we do want to update
2399 // fields in hidden sections. So: In order to be updated, a field 1)
2400 // must have a frame, or 2) it must be in the document body.
2401 if( (pFrm != NULL) || bIsInBody )
2402 pNew = new _SetGetExpFld( aIdx, &rTFld );
2404 else
2406 // create index to determine the TextNode
2407 SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() );
2408 bool const bResult = GetBodyTxtNode( rDoc, aPos, *pFrm );
2409 OSL_ENSURE(bResult, "where is the Field");
2410 (void) bResult; // unused in non-debug
2411 pNew = new _SetGetExpFld( aPos.nNode, &rTFld, &aPos.nContent );
2414 // always set the BodyTxtFlag in GetExp or DB fields
2415 if( RES_GETEXPFLD == nFldWhich )
2417 SwGetExpField* pGetFld = (SwGetExpField*)rTFld.GetFld().GetFld();
2418 pGetFld->ChgBodyTxtFlag( bIsInBody );
2420 else if( RES_DBFLD == nFldWhich )
2422 SwDBField* pDBFld = (SwDBField*)rTFld.GetFld().GetFld();
2423 pDBFld->ChgBodyTxtFlag( bIsInBody );
2426 if( pNew != NULL )
2427 if( !pFldSortLst->insert( pNew ).second )
2428 delete pNew;
2431 void SwDocUpdtFld::GetBodyNode( const SwSectionNode& rSectNd )
2433 const SwDoc& rDoc = *rSectNd.GetDoc();
2434 _SetGetExpFld* pNew = 0;
2436 if( rSectNd.GetIndex() < rDoc.GetNodes().GetEndOfExtras().GetIndex() )
2438 do { // middle check loop
2440 // we need to get the anchor first
2441 // create index to determine the TextNode
2442 SwPosition aPos( rSectNd );
2443 SwCntntNode* pCNd = rDoc.GetNodes().GoNext( &aPos.nNode ); // to the next ContentNode
2445 if( !pCNd || !pCNd->IsTxtNode() )
2446 break;
2448 // always the first! (in tab headline, header-/footer)
2449 Point aPt;
2450 const SwCntntFrm* pFrm = pCNd->getLayoutFrm( rDoc.GetCurrentLayout(), &aPt, 0, sal_False );
2451 if( !pFrm )
2452 break;
2454 bool const bResult = GetBodyTxtNode( rDoc, aPos, *pFrm );
2455 OSL_ENSURE(bResult, "where is the Field");
2456 (void) bResult; // unused in non-debug
2457 pNew = new _SetGetExpFld( rSectNd, &aPos );
2459 } while( false );
2462 if( !pNew )
2463 pNew = new _SetGetExpFld( rSectNd );
2465 if( !pFldSortLst->insert( pNew ).second )
2466 delete pNew;
2469 void SwDocUpdtFld::InsertFldType( const SwFieldType& rType )
2471 String sFldName;
2472 switch( rType.Which() )
2474 case RES_USERFLD :
2475 sFldName = ((SwUserFieldType&)rType).GetName();
2476 break;
2477 case RES_SETEXPFLD:
2478 sFldName = ((SwSetExpFieldType&)rType).GetName();
2479 break;
2480 default:
2481 OSL_ENSURE( !this, "kein gueltiger FeldTyp" );
2484 if( sFldName.Len() )
2486 SetFieldsDirty( true );
2487 // look up and remove from the hash table
2488 sFldName = GetAppCharClass().lowercase( sFldName );
2489 sal_uInt16 n;
2491 SwHash* pFnd = Find( sFldName, GetFldTypeTable(), TBLSZ, &n );
2493 if( !pFnd )
2495 SwCalcFldType* pNew = new SwCalcFldType( sFldName, &rType );
2496 pNew->pNext = aFldTypeTable[ n ];
2497 aFldTypeTable[ n ] = pNew;
2502 void SwDocUpdtFld::RemoveFldType( const SwFieldType& rType )
2504 String sFldName;
2505 switch( rType.Which() )
2507 case RES_USERFLD :
2508 sFldName = ((SwUserFieldType&)rType).GetName();
2509 break;
2510 case RES_SETEXPFLD:
2511 sFldName = ((SwSetExpFieldType&)rType).GetName();
2512 break;
2515 if( sFldName.Len() )
2517 SetFieldsDirty( true );
2518 // look up and remove from the hash table
2519 sFldName = GetAppCharClass().lowercase( sFldName );
2520 sal_uInt16 n;
2522 SwHash* pFnd = Find( sFldName, GetFldTypeTable(), TBLSZ, &n );
2523 if( pFnd )
2525 if( aFldTypeTable[ n ] == pFnd )
2526 aFldTypeTable[ n ] = (SwCalcFldType*)pFnd->pNext;
2527 else
2529 SwHash* pPrev = aFldTypeTable[ n ];
2530 while( pPrev->pNext != pFnd )
2531 pPrev = pPrev->pNext;
2532 pPrev->pNext = pFnd->pNext;
2534 pFnd->pNext = 0;
2535 delete pFnd;
2540 SwDocUpdtFld::SwDocUpdtFld(SwDoc* pDoc)
2541 : pFldSortLst(0), nFldLstGetMode(0), pDocument(pDoc)
2543 bInUpdateFlds = bFldsDirty = sal_False;
2544 memset( aFldTypeTable, 0, sizeof( aFldTypeTable ) );
2547 SwDocUpdtFld::~SwDocUpdtFld()
2549 delete pFldSortLst;
2551 for( sal_uInt16 n = 0; n < TBLSZ; ++n )
2552 delete aFldTypeTable[n];
2555 bool SwDoc::UpdateFld(SwTxtFld * pDstTxtFld, SwField & rSrcFld,
2556 SwMsgPoolItem * pMsgHnt,
2557 bool bUpdateFlds)
2559 OSL_ENSURE(pDstTxtFld, "no field to update!");
2561 bool bTblSelBreak = false;
2563 SwFmtFld * pDstFmtFld = (SwFmtFld*)&pDstTxtFld->GetFld();
2564 SwField * pDstFld = pDstFmtFld->GetFld();
2565 sal_uInt16 nFldWhich = rSrcFld.GetTyp()->Which();
2566 SwNodeIndex aTblNdIdx(pDstTxtFld->GetTxtNode());
2568 if (pDstFld->GetTyp()->Which() ==
2569 rSrcFld.GetTyp()->Which())
2571 if (GetIDocumentUndoRedo().DoesUndo())
2573 SwPosition aPosition( pDstTxtFld->GetTxtNode() );
2574 aPosition.nContent = *pDstTxtFld->GetStart();
2576 SwUndo *const pUndo( new SwUndoFieldFromDoc(
2577 aPosition, *pDstFld, rSrcFld, pMsgHnt, bUpdateFlds) );
2578 GetIDocumentUndoRedo().AppendUndo(pUndo);
2581 SwField * pNewFld = rSrcFld.CopyField();
2582 pDstFmtFld->SetFld(pNewFld);
2584 switch( nFldWhich )
2586 case RES_SETEXPFLD:
2587 case RES_GETEXPFLD:
2588 case RES_HIDDENTXTFLD:
2589 case RES_HIDDENPARAFLD:
2590 UpdateExpFlds( pDstTxtFld, true );
2591 break;
2593 case RES_TABLEFLD:
2595 const SwTableNode* pTblNd =
2596 IsIdxInTbl(aTblNdIdx);
2597 if( pTblNd )
2599 SwTableFmlUpdate aTblUpdate( &pTblNd->
2600 GetTable() );
2601 if (bUpdateFlds)
2602 UpdateTblFlds( &aTblUpdate );
2603 else
2604 pNewFld->GetTyp()->ModifyNotification(0, &aTblUpdate);
2606 if (! bUpdateFlds)
2607 bTblSelBreak = true;
2610 break;
2612 case RES_MACROFLD:
2613 if( bUpdateFlds && pDstTxtFld->GetpTxtNode() )
2614 (pDstTxtFld->GetpTxtNode())->
2615 ModifyNotification( 0, pDstFmtFld );
2616 break;
2618 case RES_DBNAMEFLD:
2619 case RES_DBNEXTSETFLD:
2620 case RES_DBNUMSETFLD:
2621 case RES_DBSETNUMBERFLD:
2622 ChgDBData(((SwDBNameInfField*) pNewFld)->GetRealDBData());
2623 pNewFld->GetTyp()->UpdateFlds();
2625 break;
2627 case RES_DBFLD:
2629 // JP 10.02.96: call ChgValue, so that the style change sets the
2630 // ContentString correctly
2631 SwDBField* pDBFld = (SwDBField*)pNewFld;
2632 if (pDBFld->IsInitialized())
2633 pDBFld->ChgValue( pDBFld->GetValue(), sal_True );
2635 pDBFld->ClearInitialized();
2636 pDBFld->InitContent();
2638 // no break;
2640 default:
2641 pDstFmtFld->ModifyNotification( 0, pMsgHnt );
2644 // The fields we can calculate here are being triggered for an update
2645 // here explicitly.
2646 if( nFldWhich == RES_USERFLD )
2647 UpdateUsrFlds();
2650 return bTblSelBreak;
2653 bool SwDoc::PutValueToField(const SwPosition & rPos,
2654 const Any& rVal, sal_uInt16 nWhich)
2656 Any aOldVal;
2657 SwField * pField = GetField(rPos);
2660 if (GetIDocumentUndoRedo().DoesUndo() &&
2661 pField->QueryValue(aOldVal, nWhich))
2663 SwUndo *const pUndo(new SwUndoFieldFromAPI(rPos, aOldVal, rVal, nWhich));
2664 GetIDocumentUndoRedo().AppendUndo(pUndo);
2667 return pField->PutValue(rVal, nWhich);
2670 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */