1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 #include <DocumentFieldsManager.hxx>
20 #include <config_features.h>
21 #include <doc.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <IDocumentState.hxx>
24 #include <IDocumentRedlineAccess.hxx>
25 #include <redline.hxx>
26 #include <rootfrm.hxx>
27 #include <dbmgr.hxx>
28 #include <chpfld.hxx>
29 #include <dbfld.hxx>
30 #include <reffld.hxx>
31 #include <flddropdown.hxx>
32 #include <strings.hrc>
33 #include <SwUndoField.hxx>
34 #include <flddat.hxx>
35 #include <cntfrm.hxx>
36 #include <section.hxx>
37 #include <docufld.hxx>
38 #include <calbck.hxx>
39 #include <cellatr.hxx>
40 #include <swtable.hxx>
41 #include <frmfmt.hxx>
42 #include <fmtfld.hxx>
43 #include <ndtxt.hxx>
44 #include <txtfld.hxx>
45 #include <docfld.hxx>
46 #include <hints.hxx>
47 #include <docary.hxx>
48 #include <fldbas.hxx>
49 #include <expfld.hxx>
50 #include <ddefld.hxx>
51 #include <authfld.hxx>
52 #include <usrfld.hxx>
53 #include <ndindex.hxx>
54 #include <pam.hxx>
55 #include <o3tl/deleter.hxx>
56 #include <osl/diagnose.h>
57 #include <unotools/transliterationwrapper.hxx>
58 #include <comphelper/scopeguard.hxx>
59 #include <com/sun/star/uno/Any.hxx>
60 
61 using namespace ::com::sun::star::uno;
62 
63 namespace sw
64 {
IsFieldDeletedInModel(IDocumentRedlineAccess const & rIDRA,SwTextField const & rTextField)65     bool IsFieldDeletedInModel(IDocumentRedlineAccess const& rIDRA,
66             SwTextField const& rTextField)
67     {
68         SwRedlineTable::size_type tmp;
69         SwPosition const pos(rTextField.GetTextNode(),
70                 rTextField.GetStart());
71         SwRangeRedline const*const pRedline(rIDRA.GetRedline(pos, &tmp));
72         return (pRedline
73             && pRedline->GetType() == RedlineType::Delete
74             && *pRedline->GetPoint() != *pRedline->GetMark());
75     }
76 }
77 
78 namespace
79 {
80     #if HAVE_FEATURE_DBCONNECTIVITY
81 
lcl_GetDBVarName(SwDoc & rDoc,SwDBNameInfField & rDBField)82     OUString lcl_GetDBVarName( SwDoc& rDoc, SwDBNameInfField& rDBField )
83     {
84         SwDBData aDBData( rDBField.GetDBData( &rDoc ));
85         OUString sDBNumNm;
86         SwDBData aDocData = rDoc.GetDBData();
87 
88         if( aDBData != aDocData )
89         {
90             sDBNumNm = aDBData.sDataSource + OUStringChar(DB_DELIM)
91                 + aDBData.sCommand + OUStringChar(DB_DELIM);
92         }
93         sDBNumNm += SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber);
94 
95         return sDBNumNm;
96     }
97 
98     #endif
99 
IsFieldDeleted(IDocumentRedlineAccess const & rIDRA,SwRootFrame const & rLayout,SwTextField const & rTextField)100     bool IsFieldDeleted(IDocumentRedlineAccess const& rIDRA,
101             SwRootFrame const& rLayout, SwTextField const& rTextField)
102     {
103         SwTextNode const& rNode(rTextField.GetTextNode());
104         bool const isInBody(
105             rNode.GetNodes().GetEndOfExtras().GetIndex() < rNode.GetIndex());
106         if (!isInBody && nullptr == rNode.getLayoutFrame(&rLayout))
107         {   // see SwDocUpdateField::GetBodyNode() - fields in hidden sections
108             // don't have layout frames but must be updated, so use the same
109             // check as there, but do it again because GetBodyNode() checks
110             // for *any* layout...
111             return true;
112         }
113         return sw::IsFieldDeletedInModel(rIDRA, rTextField);
114     }
115 
lcl_CalcField(SwDoc & rDoc,SwCalc & rCalc,const SetGetExpField & rSGEField,SwDBManager * pMgr,SwRootFrame const * const pLayout)116     void lcl_CalcField( SwDoc& rDoc, SwCalc& rCalc, const SetGetExpField& rSGEField,
117             SwDBManager* pMgr, SwRootFrame const*const pLayout)
118     {
119         const SwTextField* pTextField = rSGEField.GetTextField();
120         if( !pTextField )
121             return ;
122 
123         if (pLayout && pLayout->IsHideRedlines()
124             && IsFieldDeleted(rDoc.getIDocumentRedlineAccess(), *pLayout, *pTextField))
125         {
126             return;
127         }
128 
129         const SwField* pField = pTextField->GetFormatField().GetField();
130         const SwFieldIds nFieldWhich = pField->GetTyp()->Which();
131 
132         if( SwFieldIds::SetExp == nFieldWhich )
133         {
134             SwSbxValue aValue;
135             if( nsSwGetSetExpType::GSE_EXPR & pField->GetSubType() )
136                 aValue.PutDouble( static_cast<const SwSetExpField*>(pField)->GetValue(pLayout) );
137             else
138                 // Extension to calculate with Strings
139                 aValue.PutString( static_cast<const SwSetExpField*>(pField)->GetExpStr(pLayout) );
140 
141             // set the new value in Calculator
142             rCalc.VarChange( pField->GetTyp()->GetName(), aValue );
143         }
144         else if( pMgr )
145         {
146     #if !HAVE_FEATURE_DBCONNECTIVITY
147             (void) rDoc;
148     #else
149             switch( nFieldWhich )
150             {
151             case SwFieldIds::DbNumSet:
152                 {
153                     SwDBNumSetField* pDBField = const_cast<SwDBNumSetField*>(static_cast<const SwDBNumSetField*>(pField));
154 
155                     SwDBData aDBData(pDBField->GetDBData(&rDoc));
156 
157                     if( pDBField->IsCondValid() &&
158                         pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
159                         rCalc.VarChange( lcl_GetDBVarName( rDoc, *pDBField),
160                                         pDBField->GetFormat() );
161                 }
162                 break;
163             case SwFieldIds::DbNextSet:
164                 {
165                     SwDBNextSetField* pDBField = const_cast<SwDBNextSetField*>(static_cast<const SwDBNextSetField*>(pField));
166                     SwDBData aDBData(pDBField->GetDBData(&rDoc));
167                     if( !pDBField->IsCondValid() ||
168                         !pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
169                         break;
170 
171                     OUString sDBNumNm(lcl_GetDBVarName( rDoc, *pDBField));
172                     SwCalcExp* pExp = rCalc.VarLook( sDBNumNm );
173                     if( pExp )
174                         rCalc.VarChange( sDBNumNm, pExp->nValue.GetLong() + 1 );
175                 }
176                 break;
177 
178             default: break;
179             }
180     #endif
181         }
182     }
183 }
184 
185 namespace sw
186 {
187 
DocumentFieldsManager(SwDoc & i_rSwdoc)188 DocumentFieldsManager::DocumentFieldsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ),
189                                                                   mbNewFieldLst(true),
190                                                                   mpUpdateFields(new SwDocUpdateField(m_rDoc)),
191                                                                   mpFieldTypes( new SwFieldTypes ),
192                                                                   mnLockExpField( 0 )
193 {
194 }
195 
GetFieldTypes() const196 const SwFieldTypes* DocumentFieldsManager::GetFieldTypes() const
197 {
198     return mpFieldTypes.get();
199 }
200 
201 /** Insert field types
202  *
203  * @param rFieldTyp ???
204  * @return Always returns a pointer to the type, if it's new or already added.
205  */
InsertFieldType(const SwFieldType & rFieldTyp)206 SwFieldType* DocumentFieldsManager::InsertFieldType(const SwFieldType &rFieldTyp)
207 {
208     const SwFieldTypes::size_type nSize = mpFieldTypes->size();
209     const SwFieldIds nFieldWhich = rFieldTyp.Which();
210 
211     SwFieldTypes::size_type i = INIT_FLDTYPES;
212 
213     switch( nFieldWhich )
214     {
215     case SwFieldIds::SetExp:
216             //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
217             //             Or we get doubble number circles!!
218             //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
219             //constructing string pools and when reading SetExp fields
220             if( nsSwGetSetExpType::GSE_SEQ & static_cast<const SwSetExpFieldType&>(rFieldTyp).GetType() )
221                 i -= INIT_SEQ_FLDTYPES;
222             [[fallthrough]];
223     case SwFieldIds::Database:
224     case SwFieldIds::User:
225     case SwFieldIds::Dde:
226         {
227             const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
228             OUString sFieldNm( rFieldTyp.GetName() );
229             for( ; i < nSize; ++i )
230                 if( nFieldWhich == (*mpFieldTypes)[i]->Which() &&
231                     rSCmp.isEqual( sFieldNm, (*mpFieldTypes)[i]->GetName() ))
232                         return (*mpFieldTypes)[i].get();
233         }
234         break;
235 
236     case SwFieldIds::TableOfAuthorities:
237         for( ; i < nSize; ++i )
238             if( nFieldWhich == (*mpFieldTypes)[i]->Which() )
239                 return (*mpFieldTypes)[i].get();
240         break;
241 
242     default:
243         for( i = 0; i < nSize; ++i )
244             if( nFieldWhich == (*mpFieldTypes)[i]->Which() )
245                 return (*mpFieldTypes)[i].get();
246     }
247 
248     std::unique_ptr<SwFieldType> pNew = rFieldTyp.Copy();
249     switch( nFieldWhich )
250     {
251     case SwFieldIds::Dde:
252         static_cast<SwDDEFieldType*>(pNew.get())->SetDoc( &m_rDoc );
253         break;
254 
255     case SwFieldIds::Database:
256     case SwFieldIds::Table:
257     case SwFieldIds::DateTime:
258     case SwFieldIds::GetExp:
259         static_cast<SwValueFieldType*>(pNew.get())->SetDoc( &m_rDoc );
260         break;
261 
262     case SwFieldIds::User:
263     case SwFieldIds::SetExp:
264         static_cast<SwValueFieldType*>(pNew.get())->SetDoc( &m_rDoc );
265         // JP 29.07.96: Optionally prepare FieldList for Calculator:
266         mpUpdateFields->InsertFieldType( *pNew );
267         break;
268     case SwFieldIds::TableOfAuthorities :
269         static_cast<SwAuthorityFieldType*>(pNew.get())->SetDoc( &m_rDoc );
270         break;
271     default: break;
272     }
273 
274     mpFieldTypes->insert( mpFieldTypes->begin() + nSize, std::move(pNew) );
275     m_rDoc.getIDocumentState().SetModified();
276 
277     return (*mpFieldTypes)[ nSize ].get();
278 }
279 
280 /// @returns the field type of the Doc
GetSysFieldType(const SwFieldIds eWhich) const281 SwFieldType *DocumentFieldsManager::GetSysFieldType( const SwFieldIds eWhich ) const
282 {
283     for( SwFieldTypes::size_type i = 0; i < INIT_FLDTYPES; ++i )
284         if( eWhich == (*mpFieldTypes)[i]->Which() )
285             return (*mpFieldTypes)[i].get();
286     return nullptr;
287 }
288 
289 /// Find first type with ResId and name
GetFieldType(SwFieldIds nResId,const OUString & rName,bool bDbFieldMatching) const290 SwFieldType* DocumentFieldsManager::GetFieldType(
291     SwFieldIds nResId,
292     const OUString& rName,
293     bool bDbFieldMatching // used in some UNO calls for SwFieldIds::Database to use different string matching code #i51815#
294     ) const
295 {
296     const SwFieldTypes::size_type nSize = mpFieldTypes->size();
297     SwFieldTypes::size_type i {0};
298     const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
299 
300     switch( nResId )
301     {
302     case SwFieldIds::SetExp:
303             //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
304             //             Or we get doubble number circles!!
305             //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
306             //constructing string pools and when reading SetExp fields
307         i = INIT_FLDTYPES - INIT_SEQ_FLDTYPES;
308         break;
309 
310     case SwFieldIds::Database:
311     case SwFieldIds::User:
312     case SwFieldIds::Dde:
313     case SwFieldIds::TableOfAuthorities:
314         i = INIT_FLDTYPES;
315         break;
316     default: break;
317     }
318 
319     SwFieldType* pRet = nullptr;
320     for( ; i < nSize; ++i )
321     {
322         SwFieldType* pFieldType = (*mpFieldTypes)[i].get();
323 
324         if (nResId == pFieldType->Which())
325         {
326             OUString aFieldName( pFieldType->GetName() );
327             if (bDbFieldMatching && nResId == SwFieldIds::Database)    // #i51815#
328                 aFieldName = aFieldName.replace(DB_DELIM, '.');
329 
330             if (rSCmp.isEqual( rName, aFieldName ))
331             {
332                 pRet = pFieldType;
333                 break;
334             }
335         }
336     }
337     return pRet;
338 }
339 
340 /// Remove field type
RemoveFieldType(size_t nField)341 void DocumentFieldsManager::RemoveFieldType(size_t nField)
342 {
343     OSL_ENSURE( INIT_FLDTYPES <= nField,  "don't remove InitFields" );
344     /*
345      * Dependent fields present -> ErrRaise
346      */
347     if(nField >= mpFieldTypes->size())
348         return;
349 
350     SwFieldType* pTmp = (*mpFieldTypes)[nField].get();
351 
352     // JP 29.07.96: Optionally prepare FieldList for Calculator
353     SwFieldIds nWhich = pTmp->Which();
354     switch( nWhich )
355     {
356     case SwFieldIds::SetExp:
357     case SwFieldIds::User:
358         mpUpdateFields->RemoveFieldType( *pTmp );
359         [[fallthrough]];
360     case SwFieldIds::Dde:
361         if( pTmp->HasWriterListeners() && !m_rDoc.IsUsed( *pTmp ) )
362         {
363             if( SwFieldIds::SetExp == nWhich )
364                 static_cast<SwSetExpFieldType*>(pTmp)->SetDeleted( true );
365             else if( SwFieldIds::User == nWhich )
366                 static_cast<SwUserFieldType*>(pTmp)->SetDeleted( true );
367             else
368                 static_cast<SwDDEFieldType*>(pTmp)->SetDeleted( true );
369             nWhich = SwFieldIds::Database;
370         }
371         break;
372     default: break;
373     }
374 
375     if( nWhich != SwFieldIds::Database )
376     {
377         OSL_ENSURE( !pTmp->HasWriterListeners(), "Dependent fields present!" );
378     }
379     else
380         (*mpFieldTypes)[nField].release(); // DB fields are ref-counted and delete themselves
381 
382     mpFieldTypes->erase( mpFieldTypes->begin() + nField );
383     m_rDoc.getIDocumentState().SetModified();
384 }
385 
386 // All have to be re-evaluated.
UpdateFields(bool bCloseDB)387 void DocumentFieldsManager::UpdateFields( bool bCloseDB )
388 {
389     // Call Modify() for every field type,
390     // dependent SwTextField get notified ...
391 
392     for( auto const & pFieldType : *mpFieldTypes )
393     {
394         switch( pFieldType->Which() )
395         {
396             // Update table fields second to last
397             // Update references last
398         case SwFieldIds::GetRef:
399         case SwFieldIds::Table:
400         case SwFieldIds::Database:
401         case SwFieldIds::JumpEdit:
402         case SwFieldIds::RefPageSet:     // are never expanded!
403             break;
404 
405         case SwFieldIds::Dde:
406         {
407             SwMsgPoolItem aUpdateDDE( RES_UPDATEDDETBL );
408             pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aUpdateDDE));
409             break;
410         }
411         case SwFieldIds::GetExp:
412         case SwFieldIds::SetExp:
413         case SwFieldIds::HiddenText:
414         case SwFieldIds::HiddenPara:
415             // Expression fields are treated separately
416             break;
417         default:
418             pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
419         }
420     }
421 
422     if( !IsExpFieldsLocked() )
423         UpdateExpFields( nullptr, false );      // update expression fields
424 
425     // Tables
426     UpdateTableFields(nullptr);
427 
428     // References
429     UpdateRefFields();
430     if( bCloseDB )
431     {
432 #if HAVE_FEATURE_DBCONNECTIVITY
433         m_rDoc.GetDBManager()->CloseAll();
434 #endif
435     }
436     // Only evaluate on full update
437     m_rDoc.getIDocumentState().SetModified();
438 }
439 
InsDeletedFieldType(SwFieldType & rFieldTyp)440 void DocumentFieldsManager::InsDeletedFieldType( SwFieldType& rFieldTyp )
441 {
442     // The FieldType was marked as deleted and removed from the array.
443     // One has to look this up again, now.
444     // - If it's not present, it can be re-inserted.
445     // - If the same type is found, the deleted one has to be renamed.
446 
447     const SwFieldTypes::size_type nSize = mpFieldTypes->size();
448     const SwFieldIds nFieldWhich = rFieldTyp.Which();
449 
450     OSL_ENSURE( SwFieldIds::SetExp == nFieldWhich ||
451             SwFieldIds::User == nFieldWhich ||
452             SwFieldIds::Dde == nFieldWhich, "Wrong FieldType" );
453 
454     const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
455     const OUString& rFieldNm = rFieldTyp.GetName();
456 
457     for( SwFieldTypes::size_type i = INIT_FLDTYPES; i < nSize; ++i )
458     {
459         SwFieldType* pFnd = (*mpFieldTypes)[i].get();
460         if( nFieldWhich == pFnd->Which() &&
461             rSCmp.isEqual( rFieldNm, pFnd->GetName() ) )
462         {
463             // find new name
464             SwFieldTypes::size_type nNum = 1;
465             do {
466                 OUString sSrch = rFieldNm + OUString::number( nNum );
467                 for( i = INIT_FLDTYPES; i < nSize; ++i )
468                 {
469                     pFnd = (*mpFieldTypes)[i].get();
470                     if( nFieldWhich == pFnd->Which() &&
471                         rSCmp.isEqual( sSrch, pFnd->GetName() ) )
472                         break;
473                 }
474                 if( i >= nSize )        // not found
475                 {
476                     const_cast<OUString&>(rFieldNm) = sSrch;
477                     break;      // exit while loop
478                 }
479                 ++nNum;
480             } while( true );
481             break;
482         }
483     }
484 
485     // not found, so insert, and updated deleted flag
486     mpFieldTypes->insert( mpFieldTypes->begin() + nSize, std::unique_ptr<SwFieldType>(&rFieldTyp) );
487     switch( nFieldWhich )
488     {
489     case SwFieldIds::SetExp:
490         static_cast<SwSetExpFieldType&>(rFieldTyp).SetDeleted( false );
491         break;
492     case SwFieldIds::User:
493         static_cast<SwUserFieldType&>(rFieldTyp).SetDeleted( false );
494         break;
495     case SwFieldIds::Dde:
496         static_cast<SwDDEFieldType&>(rFieldTyp).SetDeleted( false );
497         break;
498     default: break;
499     }
500 }
501 
PutValueToField(const SwPosition & rPos,const Any & rVal,sal_uInt16 nWhich)502 void DocumentFieldsManager::PutValueToField(const SwPosition & rPos,
503                             const Any& rVal, sal_uInt16 nWhich)
504 {
505     Any aOldVal;
506     SwField * pField = GetFieldAtPos(rPos);
507 
508     if (m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
509         pField->QueryValue(aOldVal, nWhich))
510     {
511         m_rDoc.GetIDocumentUndoRedo().AppendUndo(
512             std::make_unique<SwUndoFieldFromAPI>(rPos, aOldVal, rVal, nWhich));
513     }
514 
515     pField->PutValue(rVal, nWhich);
516 }
517 
UpdateField(SwTextField * pDstTextField,SwField & rSrcField,SwMsgPoolItem * pMsgHint,bool bUpdateFields)518 bool DocumentFieldsManager::UpdateField(SwTextField * pDstTextField, SwField & rSrcField,
519                       SwMsgPoolItem * pMsgHint,
520                       bool bUpdateFields)
521 {
522     OSL_ENSURE(pDstTextField, "no field to update!");
523 
524     bool bTableSelBreak = false;
525 
526     SwFormatField * pDstFormatField = const_cast<SwFormatField*>(&pDstTextField->GetFormatField());
527     SwField * pDstField = pDstFormatField->GetField();
528     SwFieldIds nFieldWhich = rSrcField.GetTyp()->Which();
529     SwNodeIndex aTableNdIdx(pDstTextField->GetTextNode());
530 
531     if (pDstField->GetTyp()->Which() ==
532         rSrcField.GetTyp()->Which())
533     {
534         if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
535         {
536             SwPosition aPosition( pDstTextField->GetTextNode() );
537             aPosition.nContent = pDstTextField->GetStart();
538 
539             m_rDoc.GetIDocumentUndoRedo().AppendUndo(
540                 std::make_unique<SwUndoFieldFromDoc>( aPosition, *pDstField, rSrcField, pMsgHint, bUpdateFields) );
541         }
542 
543         pDstFormatField->SetField(rSrcField.CopyField());
544         SwField* pNewField = pDstFormatField->GetField();
545 
546         switch( nFieldWhich )
547         {
548         case SwFieldIds::SetExp:
549         case SwFieldIds::GetExp:
550         case SwFieldIds::HiddenText:
551         case SwFieldIds::HiddenPara:
552             UpdateExpFields( pDstTextField, true );
553             break;
554 
555         case SwFieldIds::Table:
556             {
557                 const SwTableNode* pTableNd =
558                     m_rDoc.IsIdxInTable(aTableNdIdx);
559                 if( pTableNd )
560                 {
561                     SwTableFormulaUpdate aTableUpdate( &pTableNd->
562                                                  GetTable() );
563                     if (bUpdateFields)
564                         UpdateTableFields( &aTableUpdate );
565                     else
566                         pNewField->GetTyp()->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aTableUpdate));
567 
568                     if (! bUpdateFields)
569                         bTableSelBreak = true;
570                 }
571             }
572             break;
573 
574         case SwFieldIds::Macro:
575             if( bUpdateFields && pDstTextField->GetpTextNode() )
576                 pDstTextField->GetpTextNode()->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, pDstFormatField));
577             break;
578 
579         case SwFieldIds::DatabaseName:
580         case SwFieldIds::DbNextSet:
581         case SwFieldIds::DbNumSet:
582         case SwFieldIds::DbSetNumber:
583             m_rDoc.ChgDBData(static_cast<SwDBNameInfField*>( pNewField)->GetRealDBData());
584             pNewField->GetTyp()->UpdateFields();
585 
586             break;
587 
588         case SwFieldIds::Database:
589 #if HAVE_FEATURE_DBCONNECTIVITY
590             {
591                 // JP 10.02.96: call ChgValue, so that the style change sets the
592                 // ContentString correctly
593                 SwDBField* pDBField = static_cast<SwDBField*>(pNewField);
594                 if (pDBField->IsInitialized())
595                     pDBField->ChgValue( pDBField->GetValue(), true );
596 
597                 pDBField->ClearInitialized();
598                 pDBField->InitContent();
599             }
600 #endif
601             [[fallthrough]];
602 
603         default:
604             pDstFormatField->UpdateTextNode(nullptr, pMsgHint);
605         }
606 
607         // The fields we can calculate here are being triggered for an update
608         // here explicitly.
609         if( nFieldWhich == SwFieldIds::User )
610             UpdateUsrFields();
611     }
612 
613     return bTableSelBreak;
614 }
615 
616 /// Update reference and table fields
UpdateRefFields()617 void DocumentFieldsManager::UpdateRefFields()
618 {
619     for(auto const& pFieldType: *mpFieldTypes)
620         if(SwFieldIds::GetRef == pFieldType->Which())
621             static_cast<SwGetRefFieldType*>(pFieldType.get())->UpdateGetReferences();
622 }
623 
UpdateTableFields(SfxPoolItem * pHt)624 void DocumentFieldsManager::UpdateTableFields( SfxPoolItem* pHt )
625 {
626     OSL_ENSURE( !pHt || RES_TABLEFML_UPDATE  == pHt->Which(),
627             "What MessageItem is this?" );
628 
629     auto pFieldType = GetFieldType( SwFieldIds::Table, OUString(), false );
630     if(pFieldType)
631     {
632         std::vector<SwFormatField*> vFields;
633         pFieldType->GatherFields(vFields);
634         SwTableFormulaUpdate* pUpdateField = nullptr;
635         if( pHt && RES_TABLEFML_UPDATE == pHt->Which() )
636             pUpdateField = static_cast<SwTableFormulaUpdate*>(pHt);
637         for(auto pFormatField : vFields)
638         {
639             SwTableField* pField = static_cast<SwTableField*>(pFormatField->GetField());
640             if( pUpdateField )
641             {
642                 // table where this field is located
643                 const SwTableNode* pTableNd;
644                 const SwTextNode& rTextNd = pFormatField->GetTextField()->GetTextNode();
645                 pTableNd = rTextNd.FindTableNode();
646                 if (pTableNd == nullptr)
647                     continue;
648 
649                 switch( pUpdateField->m_eFlags )
650                 {
651                 case TBL_CALC:
652                     // re-set the value flag
653                     // JP 17.06.96: internal representation of all formulas
654                     //              (reference to other table!!!)
655                     if( nsSwExtendedSubType::SUB_CMD & pField->GetSubType() )
656                         pField->PtrToBoxNm( pUpdateField->m_pTable );
657                     else
658                         pField->ChgValid( false );
659                     break;
660                 case TBL_BOXNAME:
661                     // is this the wanted table?
662                     if( &pTableNd->GetTable() == pUpdateField->m_pTable )
663                         // to the external representation
664                         pField->PtrToBoxNm( pUpdateField->m_pTable );
665                     break;
666                 case TBL_BOXPTR:
667                     // to the internal representation
668                     // JP 17.06.96: internal representation on all formulas
669                     //              (reference to other table!!!)
670                     pField->BoxNmToPtr( &pTableNd->GetTable() );
671                     break;
672                 case TBL_RELBOXNAME:
673                     // is this the wanted table?
674                     if( &pTableNd->GetTable() == pUpdateField->m_pTable )
675                         // to the relative representation
676                         pField->ToRelBoxNm( pUpdateField->m_pTable );
677                     break;
678                 default:
679                     break;
680                 }
681             }
682             else
683                 // reset the value flag for all
684                 pField->ChgValid( false );
685         }
686     }
687     // process all table box formulas
688     for (const SfxPoolItem* pItem : m_rDoc.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
689     {
690         auto pBoxFormula = dynamic_cast<const SwTableBoxFormula*>(pItem);
691         if( pBoxFormula && pBoxFormula->GetDefinedIn() )
692         {
693             const_cast<SwTableBoxFormula*>(pBoxFormula)->ChangeState( pHt );
694         }
695     }
696 
697     SwRootFrame const* pLayout(nullptr);
698     for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
699     {
700         assert(!pLayout || pLay->IsHideRedlines() == pLayout->IsHideRedlines()); // TODO
701         pLayout = pLay;
702     }
703 
704     // all fields/boxes are now invalid, so we can start to calculate
705     if( pHt && ( RES_TABLEFML_UPDATE != pHt->Which() ||
706                 TBL_CALC != static_cast<SwTableFormulaUpdate*>(pHt)->m_eFlags ))
707         return ;
708 
709     std::unique_ptr<SwCalc, o3tl::default_delete<SwCalc>> pCalc;
710 
711     if( pFieldType )
712     {
713         std::vector<SwFormatField*> vFields;
714         pFieldType->GatherFields(vFields);
715         for(SwFormatField* pFormatField: vFields)
716         {
717                 // start calculation at the end
718                 // new fields are inserted at the beginning of the modify chain
719                 // that gives faster calculation on import
720                 // mba: do we really need this "optimization"? Is it still valid?
721                 SwTableField *const pField(static_cast<SwTableField*>(pFormatField->GetField()));
722                 if (nsSwExtendedSubType::SUB_CMD & pField->GetSubType())
723                     continue;
724 
725                 // needs to be recalculated
726                 if( !pField->IsValid() )
727                 {
728                     // table where this field is located
729                     const SwTextNode& rTextNd = pFormatField->GetTextField()->GetTextNode();
730                     const SwTableNode* pTableNd = rTextNd.FindTableNode();
731                     if( !pTableNd )
732                         continue;
733 
734                     // if this field is not in the to-be-updated table, skip it
735                     if( pHt && &pTableNd->GetTable() !=
736                                             static_cast<SwTableFormulaUpdate*>(pHt)->m_pTable )
737                         continue;
738 
739                     if( !pCalc )
740                         pCalc.reset(new SwCalc( m_rDoc ));
741 
742                     // get the values of all SetExpression fields that are valid
743                     // until the table
744                     SwFrame* pFrame = nullptr;
745                     if( pTableNd->GetIndex() < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
746                     {
747                         // is in the special section, that's expensive!
748                         Point aPt;      // return the first frame of the layout - Tab.Headline!!
749                         std::pair<Point, bool> const tmp(aPt, true);
750                         pFrame = rTextNd.getLayoutFrame(pLayout, nullptr, &tmp);
751                         if( pFrame )
752                         {
753                             SwPosition aPos( *pTableNd );
754                             if( GetBodyTextNode( m_rDoc, aPos, *pFrame ) )
755                                 FieldsToCalc( *pCalc, SetGetExpField(
756                                     aPos.nNode, pFormatField->GetTextField(),
757                                     &aPos.nContent), pLayout);
758                             else
759                                 pFrame = nullptr;
760                         }
761                     }
762                     if( !pFrame )
763                     {
764                         // create index to determine the TextNode
765                         SwNodeIndex aIdx( rTextNd );
766                         FieldsToCalc( *pCalc,
767                             SetGetExpField(aIdx, pFormatField->GetTextField()),
768                             pLayout);
769                     }
770 
771                     SwTableCalcPara aPara(*pCalc, pTableNd->GetTable(), pLayout);
772                     pField->CalcField( aPara );
773                     if( aPara.IsStackOverflow() )
774                     {
775                         bool const bResult = aPara.CalcWithStackOverflow();
776                         if (bResult)
777                         {
778                             pField->CalcField( aPara );
779                         }
780                         OSL_ENSURE(bResult,
781                                 "the chained formula could no be calculated");
782                     }
783                     pCalc->SetCalcError( SwCalcError::NONE );
784                 }
785                 pFormatField->UpdateTextNode(nullptr, pHt);
786         }
787     }
788 
789     // calculate the formula at the boxes
790     for (const SfxPoolItem* pItem : m_rDoc.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
791     {
792         auto pFormula = const_cast<SwTableBoxFormula*>(dynamic_cast<const SwTableBoxFormula*>(pItem));
793         if( pFormula && pFormula->GetDefinedIn() && !pFormula->IsValid() )
794         {
795             SwTableBox* pBox = pFormula->GetTableBox();
796             if( pBox && pBox->GetSttNd() &&
797                 pBox->GetSttNd()->GetNodes().IsDocNodes() )
798             {
799                 const SwTableNode* pTableNd = pBox->GetSttNd()->FindTableNode();
800                 if( !pHt || &pTableNd->GetTable() ==
801                                             static_cast<SwTableFormulaUpdate*>(pHt)->m_pTable )
802                 {
803                     double nValue;
804                     if( !pCalc )
805                         pCalc.reset(new SwCalc( m_rDoc ));
806 
807                     // get the values of all SetExpression fields that are valid
808                     // until the table
809                     SwFrame* pFrame = nullptr;
810                     if( pTableNd->GetIndex() < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
811                     {
812                         // is in the special section, that's expensive!
813                         SwNodeIndex aCNdIdx( *pTableNd, +2 );
814                         SwContentNode* pCNd = aCNdIdx.GetNode().GetContentNode();
815                         if( !pCNd )
816                             pCNd = m_rDoc.GetNodes().GoNext( &aCNdIdx );
817 
818                         if (pCNd)
819                         {
820                             Point aPt;      // return the first frame of the layout - Tab.Headline!!
821                             std::pair<Point, bool> const tmp(aPt, true);
822                             pFrame = pCNd->getLayoutFrame(pLayout, nullptr, &tmp);
823                             if( pFrame )
824                             {
825                                 SwPosition aPos( *pCNd );
826                                 if( GetBodyTextNode( m_rDoc, aPos, *pFrame ) )
827                                     FieldsToCalc(*pCalc, SetGetExpField(aPos.nNode),
828                                             pLayout);
829                                 else
830                                     pFrame = nullptr;
831                             }
832                         }
833                     }
834                     if( !pFrame )
835                     {
836                         // create index to determine the TextNode
837                         SwNodeIndex aIdx( *pTableNd );
838                         FieldsToCalc(*pCalc, SetGetExpField(aIdx), pLayout);
839                     }
840 
841                     SwTableCalcPara aPara(*pCalc, pTableNd->GetTable(), pLayout);
842                     pFormula->Calc( aPara, nValue );
843 
844                     if( aPara.IsStackOverflow() )
845                     {
846                         bool const bResult = aPara.CalcWithStackOverflow();
847                         if (bResult)
848                         {
849                             pFormula->Calc( aPara, nValue );
850                         }
851                         OSL_ENSURE(bResult,
852                                 "the chained formula could no be calculated");
853                     }
854 
855                     SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
856                     SfxItemSet aTmp( m_rDoc.GetAttrPool(),
857                                     svl::Items<RES_BOXATR_BEGIN,RES_BOXATR_END-1>{} );
858 
859                     if( pCalc->IsCalcError() )
860                         nValue = DBL_MAX;
861                     aTmp.Put( SwTableBoxValue( nValue ));
862                     if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT ))
863                         aTmp.Put( SwTableBoxNumFormat( 0 ));
864                     pFormat->SetFormatAttr( aTmp );
865 
866                     pCalc->SetCalcError( SwCalcError::NONE );
867                 }
868             }
869         }
870     }
871 }
872 
UpdateExpFields(SwTextField * pUpdateField,bool bUpdRefFields)873 void DocumentFieldsManager::UpdateExpFields( SwTextField* pUpdateField, bool bUpdRefFields )
874 {
875     if( IsExpFieldsLocked() || m_rDoc.IsInReading() )
876         return;
877 
878     bool bOldInUpdateFields = mpUpdateFields->IsInUpdateFields();
879     mpUpdateFields->SetInUpdateFields( true );
880 
881     mpUpdateFields->MakeFieldList( m_rDoc, true, GETFLD_ALL );
882     mbNewFieldLst = false;
883 
884     if (mpUpdateFields->GetSortList()->empty())
885     {
886         if( bUpdRefFields )
887             UpdateRefFields();
888 
889         mpUpdateFields->SetInUpdateFields( bOldInUpdateFields );
890         mpUpdateFields->SetFieldsDirty( false );
891         return ;
892     }
893 
894     SwRootFrame const* pLayout(nullptr);
895     SwRootFrame const* pLayoutRLHidden(nullptr);
896     for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
897     {
898         if (pLay->IsHideRedlines())
899         {
900             pLayoutRLHidden = pLay;
901         }
902         else
903         {
904             pLayout = pLay;
905         }
906     }
907     if (pLayout || !pLayoutRLHidden) // always calc *something*...
908     {
909         UpdateExpFieldsImpl(pUpdateField, pLayout);
910     }
911     if (pLayoutRLHidden)
912     {
913         UpdateExpFieldsImpl(pUpdateField, pLayoutRLHidden);
914     }
915 
916     // update reference fields
917     if( bUpdRefFields )
918         UpdateRefFields();
919 
920     mpUpdateFields->SetInUpdateFields( bOldInUpdateFields );
921     mpUpdateFields->SetFieldsDirty( false );
922 }
923 
UpdateExpFieldsImpl(SwTextField * pUpdateField,SwRootFrame const * const pLayout)924 void DocumentFieldsManager::UpdateExpFieldsImpl(
925         SwTextField * pUpdateField, SwRootFrame const*const pLayout)
926 {
927     SwFieldIds nWhich;
928 
929     // Hash table for all string replacements is filled on-the-fly.
930     // Try to fabricate an uneven number.
931     const SwFieldTypes::size_type nHashSize {(( mpFieldTypes->size() / 7 ) + 1 ) * 7};
932     const sal_uInt16 nStrFormatCnt = o3tl::narrowing<sal_uInt16>(nHashSize);
933     OSL_ENSURE( nStrFormatCnt == nHashSize, "Downcasting to sal_uInt16 lost information!" );
934     SwHashTable<HashStr> aHashStrTable(nStrFormatCnt);
935 
936     {
937         const SwFieldType* pFieldType;
938         // process separately:
939         for( auto n = mpFieldTypes->size(); n; )
940         {
941             pFieldType = (*mpFieldTypes)[ --n ].get();
942             switch( pFieldType->Which() )
943             {
944             case SwFieldIds::User:
945                 {
946                     // Entry present?
947                     sal_uInt16 nPos;
948                     const OUString& rNm = pFieldType->GetName();
949                     OUString sExpand(const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFieldType))->Expand(nsSwGetSetExpType::GSE_STRING, 0, LANGUAGE_SYSTEM));
950                     SwHash* pFnd = aHashStrTable.Find( rNm, &nPos );
951                     if( pFnd )
952                         // modify entry in the hash table
953                         static_cast<HashStr*>(pFnd)->aSetStr = sExpand;
954                     else
955                         // insert the new entry
956                         aHashStrTable[nPos].reset( new HashStr( rNm, sExpand,
957                                                                 aHashStrTable[nPos].release() ) );
958                 }
959                 break;
960             default: break;
961             }
962         }
963     }
964 
965     // The array is filled with all fields; start calculation.
966     SwCalc aCalc( m_rDoc );
967 
968 #if HAVE_FEATURE_DBCONNECTIVITY
969     OUString sDBNumNm( SwFieldType::GetTypeStr( SwFieldTypesEnum::DatabaseSetNumber ) );
970 
971     // already set the current record number
972     SwDBManager* pMgr = m_rDoc.GetDBManager();
973     pMgr->CloseAll( false );
974 
975     SvtSysLocale aSysLocale;
976     const LocaleDataWrapper* pLclData = &aSysLocale.GetLocaleData();
977     const LanguageType nLang = pLclData->getLanguageTag().getLanguageType();
978     bool bCanFill = pMgr->FillCalcWithMergeData( m_rDoc.GetNumberFormatter(), nLang, aCalc );
979 #endif
980 
981     // Make sure we don't hide all content, which would lead to a crash. First, count how many visible sections we have.
982     int nShownSections = 0;
983     sal_uLong nContentStart = m_rDoc.GetNodes().GetEndOfContent().StartOfSectionIndex() + 1;
984     sal_uLong nContentEnd = m_rDoc.GetNodes().GetEndOfContent().GetIndex();
985     SwSectionFormats& rSectFormats = m_rDoc.GetSections();
986     for( SwSectionFormats::size_type n = 0; n<rSectFormats.size(); ++n )
987     {
988         SwSectionFormat& rSectFormat = *rSectFormats[ n ];
989         SwSectionNode* pSectionNode = rSectFormat.GetSectionNode();
990         SwSection* pSect = rSectFormat.GetSection();
991 
992         // Usually some of the content is not in a section: count that as a virtual section, so that all real sections can be hidden.
993         // Only look for section gaps at the lowest level, ignoring sub-sections.
994         if ( pSectionNode && !rSectFormat.GetParent() )
995         {
996             SwNodeIndex aNextIdx( *pSectionNode->EndOfSectionNode(), 1 );
997             if ( n == 0 && pSectionNode->GetIndex() != nContentStart )
998                 nShownSections++;  //document does not start with a section
999             if ( n == rSectFormats.size() - 1 )
1000             {
1001                 if ( aNextIdx.GetIndex() != nContentEnd )
1002                     nShownSections++;  //document does not end in a section
1003             }
1004             else if ( !aNextIdx.GetNode().IsSectionNode() )
1005                     nShownSections++; //section is not immediately followed by another section
1006         }
1007 
1008         // count only visible sections
1009         if ( pSect && !pSect->CalcHiddenFlag())
1010             nShownSections++;
1011     }
1012 
1013     IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
1014     std::unordered_map<SwSetExpFieldType const*, SwTextNode const*> SetExpOutlineNodeMap;
1015 
1016     for (std::unique_ptr<SetGetExpField> const& it : *mpUpdateFields->GetSortList())
1017     {
1018         SwSection* pSect = const_cast<SwSection*>(it->GetSection());
1019         if( pSect )
1020         {
1021             SwSbxValue aValue = aCalc.Calculate(
1022                                         pSect->GetCondition() );
1023             if(!aValue.IsVoidValue())
1024             {
1025                 // Do we want to hide this one?
1026                 bool bHide = aValue.GetBool();
1027                 if (bHide && !pSect->IsCondHidden())
1028                 {
1029                     // This section will be hidden, but it wasn't before
1030                     if (nShownSections == 1)
1031                     {
1032                         // This would be the last section, so set its condition to false, and avoid hiding it.
1033                         pSect->SetCondition("0");
1034                         bHide = false;
1035                     }
1036                     nShownSections--;
1037                 }
1038                 pSect->SetCondHidden( bHide );
1039             }
1040             continue;
1041         }
1042 
1043         SwTextField* pTextField = const_cast<SwTextField*>(it->GetTextField());
1044         if( !pTextField )
1045         {
1046             OSL_ENSURE( false, "what's wrong now'" );
1047             continue;
1048         }
1049 
1050         if (pLayout && pLayout->IsHideRedlines()
1051             && IsFieldDeleted(rIDRA, *pLayout, *pTextField))
1052         {
1053             continue;
1054         }
1055 
1056         SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
1057         const SwField* pField = pFormatField->GetField();
1058 
1059         nWhich = pField->GetTyp()->Which();
1060         switch( nWhich )
1061         {
1062         case SwFieldIds::HiddenText:
1063         {
1064             SwHiddenTextField* pHField = const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField));
1065             SwSbxValue aValue = aCalc.Calculate( pHField->GetPar1() );
1066             bool bValue = !aValue.GetBool();
1067             if(!aValue.IsVoidValue())
1068             {
1069                 pHField->SetValue( bValue );
1070                 // evaluate field
1071                 pHField->Evaluate(m_rDoc);
1072             }
1073         }
1074         break;
1075         case SwFieldIds::HiddenPara:
1076         {
1077             SwHiddenParaField* pHPField = const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField));
1078             SwSbxValue aValue = aCalc.Calculate( pHPField->GetPar1() );
1079             bool bValue = aValue.GetBool();
1080             if(!aValue.IsVoidValue())
1081                 pHPField->SetHidden( bValue );
1082         }
1083         break;
1084         case SwFieldIds::DbSetNumber:
1085 #if HAVE_FEATURE_DBCONNECTIVITY
1086         {
1087             const_cast<SwDBSetNumberField*>(static_cast<const SwDBSetNumberField*>(pField))->Evaluate(m_rDoc);
1088             aCalc.VarChange( sDBNumNm, static_cast<const SwDBSetNumberField*>(pField)->GetSetNumber());
1089             pField->ExpandField(m_rDoc.IsClipBoard(), nullptr);
1090         }
1091 #endif
1092         break;
1093         case SwFieldIds::DbNextSet:
1094         case SwFieldIds::DbNumSet:
1095 #if HAVE_FEATURE_DBCONNECTIVITY
1096         {
1097             UpdateDBNumFields( *const_cast<SwDBNameInfField*>(static_cast<const SwDBNameInfField*>(pField)), aCalc );
1098             if( bCanFill )
1099                 bCanFill = pMgr->FillCalcWithMergeData( m_rDoc.GetNumberFormatter(), nLang, aCalc );
1100         }
1101 #endif
1102         break;
1103         case SwFieldIds::Database:
1104         {
1105 #if HAVE_FEATURE_DBCONNECTIVITY
1106             // evaluate field
1107             const_cast<SwDBField*>(static_cast<const SwDBField*>(pField))->Evaluate();
1108 
1109             SwDBData aTmpDBData(static_cast<const SwDBField*>(pField)->GetDBData());
1110 
1111             if( pMgr->IsDataSourceOpen(aTmpDBData.sDataSource, aTmpDBData.sCommand, false))
1112                 aCalc.VarChange( sDBNumNm, pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType));
1113 
1114             const OUString& rName = pField->GetTyp()->GetName();
1115 
1116             // Add entry to hash table
1117             // Entry present?
1118             sal_uInt16 nPos;
1119             HashStr* pFnd = aHashStrTable.Find( rName, &nPos );
1120             OUString const value(pField->ExpandField(m_rDoc.IsClipBoard(), nullptr));
1121             if( pFnd )
1122             {
1123                 // Modify entry in the hash table
1124                 pFnd->aSetStr = value;
1125             }
1126             else
1127             {
1128                 // insert new entry
1129                aHashStrTable[nPos].reset( new HashStr( rName,
1130                     value, aHashStrTable[nPos].release()) );
1131             }
1132 #endif
1133         }
1134         break;
1135         case SwFieldIds::GetExp:
1136         case SwFieldIds::SetExp:
1137         {
1138             if( nsSwGetSetExpType::GSE_STRING & pField->GetSubType() )        // replace String
1139             {
1140                 if( SwFieldIds::GetExp == nWhich )
1141                 {
1142                     SwGetExpField* pGField = const_cast<SwGetExpField*>(static_cast<const SwGetExpField*>(pField));
1143 
1144                     if( (!pUpdateField || pUpdateField == pTextField )
1145                         && pGField->IsInBodyText() )
1146                     {
1147                         OUString aNew = LookString( aHashStrTable, pGField->GetFormula() );
1148                         pGField->ChgExpStr( aNew, pLayout );
1149                     }
1150                 }
1151                 else
1152                 {
1153                     SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1154                     // is the "formula" a field?
1155                     OUString aNew = LookString( aHashStrTable, pSField->GetFormula() );
1156 
1157                     if( aNew.isEmpty() )               // nothing found then the formula is the new value
1158                         aNew = pSField->GetFormula();
1159 
1160                     // only update one field
1161                     if( !pUpdateField || pUpdateField == pTextField )
1162                         pSField->ChgExpStr( aNew, pLayout );
1163 
1164                     // lookup the field's name
1165                     aNew = static_cast<SwSetExpFieldType*>(pSField->GetTyp())->GetSetRefName();
1166                     // Entry present?
1167                     sal_uInt16 nPos;
1168                     HashStr* pFnd = aHashStrTable.Find( aNew, &nPos );
1169                     if( pFnd )
1170                         // Modify entry in the hash table
1171                         pFnd->aSetStr = pSField->GetExpStr(pLayout);
1172                     else
1173                     {
1174                         // insert new entry
1175                         aHashStrTable[nPos].reset( new HashStr( aNew,
1176                                         pSField->GetExpStr(pLayout),
1177                                         aHashStrTable[nPos].release() ) );
1178                         pFnd = aHashStrTable[nPos].get();
1179                     }
1180 
1181                     // Extension for calculation with Strings
1182                     SwSbxValue aValue;
1183                     aValue.PutString( pFnd->aSetStr );
1184                     aCalc.VarChange( aNew, aValue );
1185                 }
1186             }
1187             else            // recalculate formula
1188             {
1189                 if( SwFieldIds::GetExp == nWhich )
1190                 {
1191                     SwGetExpField* pGField = const_cast<SwGetExpField*>(static_cast<const SwGetExpField*>(pField));
1192 
1193                     if( (!pUpdateField || pUpdateField == pTextField )
1194                         && pGField->IsInBodyText() )
1195                     {
1196                         SwSbxValue aValue = aCalc.Calculate(
1197                                         pGField->GetFormula());
1198                         if(!aValue.IsVoidValue())
1199                             pGField->SetValue(aValue.GetDouble(), pLayout);
1200                     }
1201                 }
1202                 else
1203                 {
1204                     SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1205                     SwSetExpFieldType* pSFieldTyp = static_cast<SwSetExpFieldType*>(pField->GetTyp());
1206                     OUString aNew = pSFieldTyp->GetName();
1207 
1208                     SwNode* pSeqNd = nullptr;
1209 
1210                     if( pSField->IsSequenceField() )
1211                     {
1212                         const sal_uInt8 nLvl = pSFieldTyp->GetOutlineLvl();
1213                         if( MAXLEVEL > nLvl )
1214                         {
1215                             // test if the Number needs to be updated
1216                             pSeqNd = m_rDoc.GetNodes()[ it->GetNode() ];
1217 
1218                             const SwTextNode* pOutlNd = pSeqNd->
1219                                     FindOutlineNodeOfLevel(nLvl, pLayout);
1220                             auto const iter(SetExpOutlineNodeMap.find(pSFieldTyp));
1221                             if (iter == SetExpOutlineNodeMap.end()
1222                                 || iter->second != pOutlNd)
1223                             {
1224                                 SetExpOutlineNodeMap[pSFieldTyp] = pOutlNd;
1225                                 aCalc.VarChange( aNew, 0 );
1226                             }
1227                         }
1228                     }
1229 
1230                     aNew += "=" + pSField->GetFormula();
1231 
1232                     SwSbxValue aValue = aCalc.Calculate( aNew );
1233                     if (!aCalc.IsCalcError())
1234                     {
1235                         double nErg = aValue.GetDouble();
1236                         // only update one field
1237                         if( !aValue.IsVoidValue() && (!pUpdateField || pUpdateField == pTextField) )
1238                         {
1239                             pSField->SetValue(nErg, pLayout);
1240 
1241                             if( pSeqNd )
1242                                 pSFieldTyp->SetChapter(*pSField, *pSeqNd, pLayout);
1243                         }
1244                     }
1245                 }
1246             }
1247         }
1248         break;
1249         default: break;
1250         } // switch
1251 
1252         {
1253             // avoid calling ReplaceText() for input fields, it is pointless
1254             // here and moves the cursor if it's inside the field ...
1255             SwTextInputField *const pInputField(
1256                 pUpdateField == pTextField // ... except once, when the dialog
1257                     ? nullptr // is used to change content via UpdateOneField()
1258                     : dynamic_cast<SwTextInputField *>(pTextField));
1259             if (pInputField)
1260             {
1261                 bool const tmp = pInputField->LockNotifyContentChange();
1262                 (void) tmp;
1263                 assert(tmp && "should not be locked here?");
1264             }
1265             ::comphelper::ScopeGuard g([pInputField]()
1266                 {
1267                     if (pInputField)
1268                     {
1269                         pInputField->UnlockNotifyContentChange();
1270                     }
1271                 });
1272             pFormatField->UpdateTextNode(nullptr, nullptr); // trigger formatting
1273         }
1274 
1275         if (pUpdateField == pTextField) // if only this one is updated
1276         {
1277             if( SwFieldIds::GetExp == nWhich ||      // only GetField or
1278                 SwFieldIds::HiddenText == nWhich ||   // HiddenText?
1279                 SwFieldIds::HiddenPara == nWhich)    // HiddenParaField?
1280                 break;                          // quit
1281             pUpdateField = nullptr;                       // update all from here on
1282         }
1283     }
1284 
1285 #if HAVE_FEATURE_DBCONNECTIVITY
1286     pMgr->CloseAll(false);
1287 #endif
1288 }
1289 
1290 /// Insert field type that was marked as deleted
UpdateUsrFields()1291 void DocumentFieldsManager::UpdateUsrFields()
1292 {
1293     SwCalc* pCalc = nullptr;
1294     for( SwFieldTypes::size_type i = INIT_FLDTYPES; i < mpFieldTypes->size(); ++i )
1295     {
1296         const SwFieldType* pFieldType = (*mpFieldTypes)[i].get();
1297         if( SwFieldIds::User == pFieldType->Which() )
1298         {
1299             if( !pCalc )
1300                 pCalc = new SwCalc( m_rDoc );
1301             const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFieldType))->GetValue( *pCalc );
1302         }
1303     }
1304 
1305     if( pCalc )
1306     {
1307         delete pCalc;
1308         m_rDoc.getIDocumentState().SetModified();
1309     }
1310 }
1311 
GetRecordsPerDocument() const1312 sal_Int32 DocumentFieldsManager::GetRecordsPerDocument() const
1313 {
1314     sal_Int32 nRecords = 1;
1315 
1316     mpUpdateFields->MakeFieldList( m_rDoc, true, GETFLD_ALL );
1317     if (mpUpdateFields->GetSortList()->empty())
1318         return nRecords;
1319 
1320     for (std::unique_ptr<SetGetExpField> const& it : *mpUpdateFields->GetSortList())
1321     {
1322         const SwTextField *pTextField = it->GetTextField();
1323         if( !pTextField )
1324             continue;
1325 
1326         const SwFormatField &pFormatField = pTextField->GetFormatField();
1327         const SwField* pField = pFormatField.GetField();
1328 
1329         switch( pField->GetTyp()->Which() )
1330         {
1331         case SwFieldIds::DbNextSet:
1332         case SwFieldIds::DbNumSet:
1333             nRecords++;
1334             break;
1335         default:
1336             break;
1337         }
1338     }
1339 
1340     return nRecords;
1341 }
1342 
UpdatePageFields(SfxPoolItem * pMsgHint)1343 void DocumentFieldsManager::UpdatePageFields( SfxPoolItem* pMsgHint )
1344 {
1345     for( SwFieldTypes::size_type i = 0; i < INIT_FLDTYPES; ++i )
1346     {
1347         SwFieldType* pFieldType = (*mpFieldTypes)[ i ].get();
1348         switch( pFieldType->Which() )
1349         {
1350         case SwFieldIds::PageNumber:
1351         case SwFieldIds::Chapter:
1352         case SwFieldIds::GetExp:
1353         case SwFieldIds::RefPageGet:
1354             pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, pMsgHint));
1355             break;
1356         case SwFieldIds::DocStat:
1357             pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1358             break;
1359         default: break;
1360         }
1361     }
1362     SetNewFieldLst(true);
1363 }
1364 
LockExpFields()1365 void DocumentFieldsManager::LockExpFields()
1366 {
1367     ++mnLockExpField;
1368 }
1369 
UnlockExpFields()1370 void DocumentFieldsManager::UnlockExpFields()
1371 {
1372     assert(mnLockExpField != 0);
1373     if( mnLockExpField )
1374         --mnLockExpField;
1375 }
1376 
IsExpFieldsLocked() const1377 bool DocumentFieldsManager::IsExpFieldsLocked() const
1378 {
1379     return 0 != mnLockExpField;
1380 }
1381 
GetUpdateFields() const1382 SwDocUpdateField& DocumentFieldsManager::GetUpdateFields() const
1383 {
1384     return *mpUpdateFields;
1385 }
1386 
SetFieldsDirty(bool b,const SwNode * pChk,sal_uLong nLen)1387 bool DocumentFieldsManager::SetFieldsDirty( bool b, const SwNode* pChk, sal_uLong nLen )
1388 {
1389     // See if the supplied nodes actually contain fields.
1390     // If they don't, the flag doesn't need to be changed.
1391     bool bFieldsFnd = false;
1392     if( b && pChk && !GetUpdateFields().IsFieldsDirty() && !m_rDoc.IsInDtor()
1393         // ?? what's up with Undo, this is also wanted there!
1394         /*&& &pChk->GetNodes() == &GetNodes()*/ )
1395     {
1396         b = false;
1397         if( !nLen )
1398             ++nLen;
1399         sal_uLong nStt = pChk->GetIndex();
1400         const SwNodes& rNds = pChk->GetNodes();
1401         while( nLen-- )
1402         {
1403             const SwTextNode* pTNd = rNds[ nStt++ ]->GetTextNode();
1404             if( pTNd )
1405             {
1406                 if( pTNd->GetAttrOutlineLevel() != 0 )
1407                     // update chapter fields
1408                     b = true;
1409                 else if( pTNd->GetpSwpHints() && pTNd->GetSwpHints().Count() )
1410                 {
1411                     const size_t nEnd = pTNd->GetSwpHints().Count();
1412                     for( size_t n = 0 ; n < nEnd; ++n )
1413                     {
1414                         const SwTextAttr* pAttr = pTNd->GetSwpHints().Get(n);
1415                         if (   pAttr->Which() == RES_TXTATR_FIELD
1416                             || pAttr->Which() == RES_TXTATR_INPUTFIELD)
1417                         {
1418                             b = true;
1419                             break;
1420                         }
1421                     }
1422                 }
1423 
1424                 if( b )
1425                     break;
1426             }
1427         }
1428         bFieldsFnd = b;
1429     }
1430     GetUpdateFields().SetFieldsDirty( b );
1431     return bFieldsFnd;
1432 }
1433 
SetFixFields(const DateTime * pNewDateTime)1434 void DocumentFieldsManager::SetFixFields( const DateTime* pNewDateTime )
1435 {
1436     bool bIsModified = m_rDoc.getIDocumentState().IsModified();
1437 
1438     sal_Int32 nDate;
1439     sal_Int64 nTime;
1440     if( pNewDateTime )
1441     {
1442         nDate = pNewDateTime->GetDate();
1443         nTime = pNewDateTime->GetTime();
1444     }
1445     else
1446     {
1447         DateTime aDateTime( DateTime::SYSTEM );
1448         nDate = aDateTime.GetDate();
1449         nTime = aDateTime.GetTime();
1450     }
1451 
1452     SwFieldIds const aTypes[] {
1453         /*0*/   SwFieldIds::DocInfo,
1454         /*1*/   SwFieldIds::Author,
1455         /*2*/   SwFieldIds::ExtUser,
1456         /*3*/   SwFieldIds::Filename,
1457         /*4*/   SwFieldIds::DateTime };  // MUST be at the end!
1458 
1459     for(SwFieldIds aType : aTypes)
1460     {
1461         std::vector<SwFormatField*> vFields;
1462         GetSysFieldType(aType)->GatherFields(vFields);
1463         for(auto pFormatField: vFields)
1464         {
1465             if (pFormatField->GetTextField())
1466             {
1467                 bool bChgd = false;
1468                 switch( aType )
1469                 {
1470                 case SwFieldIds::DocInfo:
1471                     if( static_cast<SwDocInfoField*>(pFormatField->GetField())->IsFixed() )
1472                     {
1473                         bChgd = true;
1474                         SwDocInfoField* pDocInfField = static_cast<SwDocInfoField*>(pFormatField->GetField());
1475                         pDocInfField->SetExpansion( static_cast<SwDocInfoFieldType*>(
1476                                     pDocInfField->GetTyp())->Expand(
1477                                         pDocInfField->GetSubType(),
1478                                         pDocInfField->GetFormat(),
1479                                         pDocInfField->GetLanguage(),
1480                                         pDocInfField->GetName() ) );
1481                     }
1482                     break;
1483 
1484                 case SwFieldIds::Author:
1485                     if( static_cast<SwAuthorField*>(pFormatField->GetField())->IsFixed() )
1486                     {
1487                         bChgd = true;
1488                         SwAuthorField* pAuthorField = static_cast<SwAuthorField*>(pFormatField->GetField());
1489                         pAuthorField->SetExpansion( SwAuthorFieldType::Expand( pAuthorField->GetFormat() ) );
1490                     }
1491                     break;
1492 
1493                 case SwFieldIds::ExtUser:
1494                     if( static_cast<SwExtUserField*>(pFormatField->GetField())->IsFixed() )
1495                     {
1496                         bChgd = true;
1497                         SwExtUserField* pExtUserField = static_cast<SwExtUserField*>(pFormatField->GetField());
1498                         pExtUserField->SetExpansion( SwExtUserFieldType::Expand(pExtUserField->GetSubType()) );
1499                     }
1500                     break;
1501 
1502                 case SwFieldIds::DateTime:
1503                     if( static_cast<SwDateTimeField*>(pFormatField->GetField())->IsFixed() )
1504                     {
1505                         bChgd = true;
1506                         static_cast<SwDateTimeField*>(pFormatField->GetField())->SetDateTime(
1507                                                     DateTime(Date(nDate), tools::Time(nTime)) );
1508                     }
1509                     break;
1510 
1511                 case SwFieldIds::Filename:
1512                     if( static_cast<SwFileNameField*>(pFormatField->GetField())->IsFixed() )
1513                     {
1514                         bChgd = true;
1515                         SwFileNameField* pFileNameField =
1516                             static_cast<SwFileNameField*>(pFormatField->GetField());
1517                         pFileNameField->SetExpansion( static_cast<SwFileNameFieldType*>(
1518                                     pFileNameField->GetTyp())->Expand(
1519                                             pFileNameField->GetFormat() ) );
1520                     }
1521                     break;
1522                 default: break;
1523                 }
1524 
1525                 // Trigger formatting
1526                 if( bChgd )
1527                     pFormatField->UpdateTextNode(nullptr, nullptr);
1528             }
1529         }
1530     }
1531 
1532     if( !bIsModified )
1533         m_rDoc.getIDocumentState().ResetModified();
1534 }
1535 
FieldsToCalc(SwCalc & rCalc,const SetGetExpField & rToThisField,SwRootFrame const * const pLayout)1536 void DocumentFieldsManager::FieldsToCalc(SwCalc& rCalc,
1537         const SetGetExpField& rToThisField, SwRootFrame const*const pLayout)
1538 {
1539     // create the sorted list of all SetFields
1540     mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_CALC );
1541     mbNewFieldLst = false;
1542 
1543 #if !HAVE_FEATURE_DBCONNECTIVITY
1544     SwDBManager* pMgr = NULL;
1545 #else
1546     SwDBManager* pMgr = m_rDoc.GetDBManager();
1547     pMgr->CloseAll(false);
1548 #endif
1549 
1550     if (!mpUpdateFields->GetSortList()->empty())
1551     {
1552         SetGetExpFields::const_iterator const itLast =
1553             mpUpdateFields->GetSortList()->upper_bound(
1554                 &rToThisField);
1555         for (auto it = mpUpdateFields->GetSortList()->begin(); it != itLast; ++it)
1556         {
1557             lcl_CalcField(m_rDoc, rCalc, **it, pMgr, pLayout);
1558         }
1559     }
1560 #if HAVE_FEATURE_DBCONNECTIVITY
1561     pMgr->CloseAll(false);
1562 #endif
1563 }
1564 
FieldsToCalc(SwCalc & rCalc,sal_uLong const nLastNd,sal_Int32 const nLastCnt)1565 void DocumentFieldsManager::FieldsToCalc(SwCalc& rCalc,
1566         sal_uLong const nLastNd, sal_Int32 const nLastCnt)
1567 {
1568     // create the sorted list of all SetFields
1569     mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_CALC );
1570     mbNewFieldLst = false;
1571 
1572 #if !HAVE_FEATURE_DBCONNECTIVITY
1573     SwDBManager* pMgr = NULL;
1574 #else
1575     SwDBManager* pMgr = m_rDoc.GetDBManager();
1576     pMgr->CloseAll(false);
1577 #endif
1578 
1579     SwRootFrame const* pLayout(nullptr);
1580     SwRootFrame const* pLayoutRLHidden(nullptr);
1581     for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
1582     {
1583         if (pLay->IsHideRedlines())
1584         {
1585             pLayoutRLHidden = pLay;
1586         }
1587         else
1588         {
1589             pLayout = pLay;
1590         }
1591     }
1592 
1593     // note this is not duplicate of the other FieldsToCalc because there is
1594     // (currently) no SetGetExpField that compares only a position
1595     for(auto it = mpUpdateFields->GetSortList()->begin();
1596         it != mpUpdateFields->GetSortList()->end() &&
1597         ( (*it)->GetNode() < nLastNd ||
1598           ( (*it)->GetNode() == nLastNd && (*it)->GetContent() <= nLastCnt )
1599         );
1600         ++it )
1601     {
1602         if (pLayout || !pLayoutRLHidden) // always calc *something*...
1603         {
1604             lcl_CalcField( m_rDoc, rCalc, **it, pMgr, pLayout );
1605         }
1606         if (pLayoutRLHidden)
1607         {
1608             lcl_CalcField( m_rDoc, rCalc, **it, pMgr, pLayoutRLHidden );
1609         }
1610     }
1611 
1612 #if HAVE_FEATURE_DBCONNECTIVITY
1613     pMgr->CloseAll(false);
1614 #endif
1615 }
1616 
FieldsToExpand(SwHashTable<HashStr> & rHashTable,const SetGetExpField & rToThisField,SwRootFrame const & rLayout)1617 void DocumentFieldsManager::FieldsToExpand( SwHashTable<HashStr> & rHashTable,
1618         const SetGetExpField& rToThisField, SwRootFrame const& rLayout)
1619 {
1620     // create the sorted list of all SetFields
1621     mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_EXPAND );
1622     mbNewFieldLst = false;
1623 
1624     IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
1625 
1626     // Hash table for all string replacements is filled on-the-fly.
1627     // Try to fabricate an uneven number.
1628     sal_uInt16 nTableSize = ((mpUpdateFields->GetSortList()->size() / 7) + 1) * 7;
1629     rHashTable.resize(nTableSize);
1630 
1631     SetGetExpFields::const_iterator const itLast =
1632         mpUpdateFields->GetSortList()->upper_bound(&rToThisField);
1633 
1634     for (auto it = mpUpdateFields->GetSortList()->begin(); it != itLast; ++it)
1635     {
1636         const SwTextField* pTextField = (*it)->GetTextField();
1637         if( !pTextField )
1638             continue;
1639 
1640         if (rLayout.IsHideRedlines()
1641             && IsFieldDeleted(rIDRA, rLayout, *pTextField))
1642         {
1643             continue;
1644         }
1645 
1646         const SwField* pField = pTextField->GetFormatField().GetField();
1647         switch( pField->GetTyp()->Which() )
1648         {
1649         case SwFieldIds::SetExp:
1650             if( nsSwGetSetExpType::GSE_STRING & pField->GetSubType() )
1651             {
1652                 // set the new value in the hash table
1653                 // is the formula a field?
1654                 SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1655                 OUString aNew = LookString( rHashTable, pSField->GetFormula() );
1656 
1657                 if( aNew.isEmpty() )               // nothing found, then the formula is
1658                     aNew = pSField->GetFormula(); // the new value
1659 
1660                 // #i3141# - update expression of field as in method
1661                 // <SwDoc::UpdateExpFields(..)> for string/text fields
1662                 pSField->ChgExpStr(aNew, &rLayout);
1663 
1664                 // look up the field's name
1665                 aNew = static_cast<SwSetExpFieldType*>(pSField->GetTyp())->GetSetRefName();
1666                 // Entry present?
1667                 sal_uInt16 nPos;
1668                 SwHash* pFnd = rHashTable.Find( aNew, &nPos );
1669                 if( pFnd )
1670                     // modify entry in the hash table
1671                     static_cast<HashStr*>(pFnd)->aSetStr = pSField->GetExpStr(&rLayout);
1672                 else
1673                     // insert the new entry
1674                     rHashTable[nPos].reset( new HashStr( aNew,
1675                             pSField->GetExpStr(&rLayout), rHashTable[nPos].release()));
1676             }
1677             break;
1678         case SwFieldIds::Database:
1679             {
1680                 const OUString& rName = pField->GetTyp()->GetName();
1681 
1682                 // Insert entry in the hash table
1683                 // Entry present?
1684                 sal_uInt16 nPos;
1685                 HashStr* pFnd = rHashTable.Find( rName, &nPos );
1686                 OUString const value(pField->ExpandField(m_rDoc.IsClipBoard(), nullptr));
1687                 if( pFnd )
1688                 {
1689                     // modify entry in the hash table
1690                     pFnd->aSetStr = value;
1691                 }
1692                 else
1693                 {
1694                     // insert the new entry
1695                     rHashTable[nPos].reset( new HashStr( rName,
1696                         value, rHashTable[nPos].release()) );
1697                 }
1698             }
1699             break;
1700         default: break;
1701         }
1702     }
1703 }
1704 
1705 
IsNewFieldLst() const1706 bool DocumentFieldsManager::IsNewFieldLst() const
1707 {
1708     return mbNewFieldLst;
1709 }
1710 
SetNewFieldLst(bool bFlag)1711 void DocumentFieldsManager::SetNewFieldLst(bool bFlag)
1712 {
1713     mbNewFieldLst = bFlag;
1714 }
1715 
InsDelFieldInFieldLst(bool bIns,const SwTextField & rField)1716 void DocumentFieldsManager::InsDelFieldInFieldLst( bool bIns, const SwTextField& rField )
1717 {
1718     if (!mbNewFieldLst && !m_rDoc.IsInDtor())
1719         mpUpdateFields->InsDelFieldInFieldLst( bIns, rField );
1720 }
1721 
GetFieldAtPos(const SwPosition & rPos)1722 SwField * DocumentFieldsManager::GetFieldAtPos(const SwPosition & rPos)
1723 {
1724     SwTextField * const pAttr = GetTextFieldAtPos(rPos);
1725 
1726     return pAttr ? const_cast<SwField *>( pAttr->GetFormatField().GetField() ) : nullptr;
1727 }
1728 
GetTextFieldAtPos(const SwPosition & rPos)1729 SwTextField * DocumentFieldsManager::GetTextFieldAtPos(const SwPosition & rPos)
1730 {
1731     SwTextNode * const pNode = rPos.nNode.GetNode().GetTextNode();
1732 
1733     return (pNode != nullptr)
1734         ? pNode->GetFieldTextAttrAt( rPos.nContent.GetIndex(), true )
1735         : nullptr;
1736 }
1737 
1738 /// @note For simplicity assume that all field types have updatable contents so
1739 ///       optimization currently only available when no fields exist.
containsUpdatableFields()1740 bool DocumentFieldsManager::containsUpdatableFields()
1741 {
1742     std::vector<SwFormatField*> vFields;
1743     for (auto const& pFieldType: *mpFieldTypes)
1744     {
1745         pFieldType->GatherFields(vFields);
1746         if(vFields.size()>0)
1747             return true;
1748     }
1749     return false;
1750 }
1751 
1752 /// Remove all unreferenced field types of a document
GCFieldTypes()1753 void DocumentFieldsManager::GCFieldTypes()
1754 {
1755     for( auto n = mpFieldTypes->size(); n > INIT_FLDTYPES; )
1756         if( !(*mpFieldTypes)[ --n ]->HasWriterListeners() )
1757             RemoveFieldType( n );
1758 }
1759 
InitFieldTypes()1760 void DocumentFieldsManager::InitFieldTypes()       // is being called by the CTOR
1761 {
1762     // Field types
1763     mpFieldTypes->emplace_back( new SwDateTimeFieldType(&m_rDoc) );
1764     mpFieldTypes->emplace_back( new SwChapterFieldType );
1765     mpFieldTypes->emplace_back( new SwPageNumberFieldType );
1766     mpFieldTypes->emplace_back( new SwAuthorFieldType );
1767     mpFieldTypes->emplace_back( new SwFileNameFieldType(m_rDoc) );
1768     mpFieldTypes->emplace_back( new SwDBNameFieldType(&m_rDoc) );
1769     mpFieldTypes->emplace_back( new SwGetExpFieldType(&m_rDoc) );
1770     mpFieldTypes->emplace_back( new SwGetRefFieldType(m_rDoc) );
1771     mpFieldTypes->emplace_back( new SwHiddenTextFieldType );
1772     mpFieldTypes->emplace_back( new SwPostItFieldType(m_rDoc) );
1773     mpFieldTypes->emplace_back( new SwDocStatFieldType(m_rDoc) );
1774     mpFieldTypes->emplace_back( new SwDocInfoFieldType(&m_rDoc) );
1775     mpFieldTypes->emplace_back( new SwInputFieldType( &m_rDoc ) );
1776     mpFieldTypes->emplace_back( new SwTableFieldType( &m_rDoc ) );
1777     mpFieldTypes->emplace_back( new SwMacroFieldType(m_rDoc) );
1778     mpFieldTypes->emplace_back( new SwHiddenParaFieldType );
1779     mpFieldTypes->emplace_back( new SwDBNextSetFieldType );
1780     mpFieldTypes->emplace_back( new SwDBNumSetFieldType );
1781     mpFieldTypes->emplace_back( new SwDBSetNumberFieldType );
1782     mpFieldTypes->emplace_back( new SwTemplNameFieldType(m_rDoc) );
1783     mpFieldTypes->emplace_back( new SwTemplNameFieldType(m_rDoc) );
1784     mpFieldTypes->emplace_back( new SwExtUserFieldType );
1785     mpFieldTypes->emplace_back( new SwRefPageSetFieldType );
1786     mpFieldTypes->emplace_back( new SwRefPageGetFieldType(m_rDoc) );
1787     mpFieldTypes->emplace_back( new SwJumpEditFieldType(m_rDoc) );
1788     mpFieldTypes->emplace_back( new SwScriptFieldType(m_rDoc) );
1789     mpFieldTypes->emplace_back( new SwCombinedCharFieldType );
1790     mpFieldTypes->emplace_back( new SwDropDownFieldType );
1791 
1792     // Types have to be at the end!
1793     // We expect this in the InsertFieldType!
1794     // MIB 14.04.95: In Sw3StringPool::Setup (sw3imp.cxx) and
1795     //               lcl_sw3io_InSetExpField (sw3field.cxx) now also
1796     mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1797                 SwResId(STR_POOLCOLL_LABEL_ABB), nsSwGetSetExpType::GSE_SEQ) );
1798     mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1799                 SwResId(STR_POOLCOLL_LABEL_TABLE), nsSwGetSetExpType::GSE_SEQ) );
1800     mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1801                 SwResId(STR_POOLCOLL_LABEL_FRAME), nsSwGetSetExpType::GSE_SEQ) );
1802     mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1803                 SwResId(STR_POOLCOLL_LABEL_DRAWING), nsSwGetSetExpType::GSE_SEQ) );
1804     mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1805                 SwResId(STR_POOLCOLL_LABEL_FIGURE), nsSwGetSetExpType::GSE_SEQ) );
1806 
1807     assert( mpFieldTypes->size() == INIT_FLDTYPES );
1808 }
1809 
ClearFieldTypes()1810 void DocumentFieldsManager::ClearFieldTypes()
1811 {
1812     mpFieldTypes->erase( mpFieldTypes->begin() + INIT_FLDTYPES, mpFieldTypes->end() );
1813 }
1814 
UpdateDBNumFields(SwDBNameInfField & rDBField,SwCalc & rCalc)1815 void DocumentFieldsManager::UpdateDBNumFields( SwDBNameInfField& rDBField, SwCalc& rCalc )
1816 {
1817 #if !HAVE_FEATURE_DBCONNECTIVITY
1818     (void) rDBField;
1819     (void) rCalc;
1820 #else
1821     SwDBManager* pMgr = m_rDoc.GetDBManager();
1822 
1823     SwFieldIds nFieldType = rDBField.Which();
1824 
1825     bool bPar1 = rCalc.Calculate( rDBField.GetPar1() ).GetBool();
1826 
1827     if( SwFieldIds::DbNextSet == nFieldType )
1828         static_cast<SwDBNextSetField&>(rDBField).SetCondValid( bPar1 );
1829     else
1830         static_cast<SwDBNumSetField&>(rDBField).SetCondValid( bPar1 );
1831 
1832     if( !rDBField.GetRealDBData().sDataSource.isEmpty() )
1833     {
1834         // Edit a certain database
1835         if( SwFieldIds::DbNextSet == nFieldType )
1836             static_cast<SwDBNextSetField&>(rDBField).Evaluate(m_rDoc);
1837         else
1838             static_cast<SwDBNumSetField&>(rDBField).Evaluate(m_rDoc);
1839 
1840         SwDBData aTmpDBData( rDBField.GetDBData(&m_rDoc) );
1841 
1842         if( pMgr->OpenDataSource( aTmpDBData.sDataSource, aTmpDBData.sCommand ))
1843             rCalc.VarChange( lcl_GetDBVarName( m_rDoc, rDBField),
1844                         pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType) );
1845     }
1846     else
1847     {
1848         OSL_FAIL("TODO: what should happen with unnamed DBFields?");
1849     }
1850 #endif
1851 }
1852 
~DocumentFieldsManager()1853 DocumentFieldsManager::~DocumentFieldsManager()
1854 {
1855     mpUpdateFields.reset();
1856     mpFieldTypes.reset();
1857 }
1858 
1859 }
1860 
1861 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1862