1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
19 #include <DocumentFieldsManager.hxx>
20 #include <config_features.h>
21 #include <config_fuzzers.h>
23 #include <IDocumentUndoRedo.hxx>
24 #include <IDocumentState.hxx>
25 #include <IDocumentRedlineAccess.hxx>
26 #include <redline.hxx>
27 #include <rootfrm.hxx>
32 #include <flddropdown.hxx>
33 #include <strings.hrc>
34 #include <SwUndoField.hxx>
37 #include <node2lay.hxx>
38 #include <section.hxx>
39 #include <docufld.hxx>
41 #include <cellatr.hxx>
42 #include <swtable.hxx>
53 #include <authfld.hxx>
55 #include <ndindex.hxx>
57 #include <o3tl/deleter.hxx>
58 #include <osl/diagnose.h>
59 #include <unotools/transliterationwrapper.hxx>
60 #include <comphelper/scopeguard.hxx>
61 #include <com/sun/star/uno/Any.hxx>
63 using namespace ::com::sun::star::uno
;
67 bool IsFieldDeletedInModel(IDocumentRedlineAccess
const& rIDRA
,
68 SwTextField
const& rTextField
)
70 SwRedlineTable::size_type tmp
;
71 SwPosition
const pos(rTextField
.GetTextNode(),
72 rTextField
.GetStart());
73 SwRangeRedline
const*const pRedline(rIDRA
.GetRedline(pos
, &tmp
));
75 && pRedline
->GetType() == RedlineType::Delete
76 && *pRedline
->GetPoint() != *pRedline
->GetMark());
82 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
84 OUString
lcl_GetDBVarName( SwDoc
& rDoc
, SwDBNameInfField
& rDBField
)
86 SwDBData
aDBData( rDBField
.GetDBData( &rDoc
));
88 SwDBData aDocData
= rDoc
.GetDBData();
90 if( aDBData
!= aDocData
)
92 sDBNumNm
= aDBData
.sDataSource
+ OUStringChar(DB_DELIM
)
93 + aDBData
.sCommand
+ OUStringChar(DB_DELIM
);
95 sDBNumNm
+= SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber
);
102 bool IsFieldDeleted(IDocumentRedlineAccess
const& rIDRA
,
103 SwRootFrame
const& rLayout
, SwTextField
const& rTextField
)
105 SwTextNode
const& rNode(rTextField
.GetTextNode());
107 rNode
.GetNodes().GetEndOfExtras().GetIndex() < rNode
.GetIndex());
108 if (!isInBody
&& nullptr == rNode
.getLayoutFrame(&rLayout
))
109 { // see SwDocUpdateField::GetBodyNode() - fields in hidden sections
110 // don't have layout frames but must be updated, so use the same
111 // check as there, but do it again because GetBodyNode() checks
112 // for *any* layout...
115 return sw::IsFieldDeletedInModel(rIDRA
, rTextField
);
118 void lcl_CalcField( SwDoc
& rDoc
, SwCalc
& rCalc
, const SetGetExpField
& rSGEField
,
119 SwDBManager
* pMgr
, SwRootFrame
const*const pLayout
)
121 const SwTextField
* pTextField
= rSGEField
.GetTextField();
125 if (pLayout
&& pLayout
->IsHideRedlines()
126 && IsFieldDeleted(rDoc
.getIDocumentRedlineAccess(), *pLayout
, *pTextField
))
131 const SwField
* pField
= pTextField
->GetFormatField().GetField();
132 const SwFieldIds nFieldWhich
= pField
->GetTyp()->Which();
134 if( SwFieldIds::SetExp
== nFieldWhich
)
137 if( nsSwGetSetExpType::GSE_EXPR
& pField
->GetSubType() )
138 aValue
.PutDouble( static_cast<const SwSetExpField
*>(pField
)->GetValue(pLayout
) );
140 // Extension to calculate with Strings
141 aValue
.PutString( static_cast<const SwSetExpField
*>(pField
)->GetExpStr(pLayout
) );
143 // set the new value in Calculator
144 rCalc
.VarChange( pField
->GetTyp()->GetName(), aValue
);
148 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
151 switch( nFieldWhich
)
153 case SwFieldIds::DbNumSet
:
155 SwDBNumSetField
* pDBField
= const_cast<SwDBNumSetField
*>(static_cast<const SwDBNumSetField
*>(pField
));
157 SwDBData
aDBData(pDBField
->GetDBData(&rDoc
));
159 if( pDBField
->IsCondValid() &&
160 pMgr
->OpenDataSource( aDBData
.sDataSource
, aDBData
.sCommand
))
161 rCalc
.VarChange( lcl_GetDBVarName( rDoc
, *pDBField
),
162 pDBField
->GetFormat() );
165 case SwFieldIds::DbNextSet
:
167 SwDBNextSetField
* pDBField
= const_cast<SwDBNextSetField
*>(static_cast<const SwDBNextSetField
*>(pField
));
168 SwDBData
aDBData(pDBField
->GetDBData(&rDoc
));
169 if( !pDBField
->IsCondValid() ||
170 !pMgr
->OpenDataSource( aDBData
.sDataSource
, aDBData
.sCommand
))
173 OUString
sDBNumNm(lcl_GetDBVarName( rDoc
, *pDBField
));
174 SwCalcExp
* pExp
= rCalc
.VarLook( sDBNumNm
);
176 rCalc
.VarChange( sDBNumNm
, pExp
->nValue
.GetLong() + 1 );
190 DocumentFieldsManager::DocumentFieldsManager( SwDoc
& i_rSwdoc
) : m_rDoc( i_rSwdoc
),
192 mpUpdateFields(new SwDocUpdateField(m_rDoc
)),
193 mpFieldTypes( new SwFieldTypes
),
198 const SwFieldTypes
* DocumentFieldsManager::GetFieldTypes() const
200 return mpFieldTypes
.get();
203 /** Insert field types
205 * @param rFieldTyp ???
206 * @return Always returns a pointer to the type, if it's new or already added.
208 SwFieldType
* DocumentFieldsManager::InsertFieldType(const SwFieldType
&rFieldTyp
)
210 const SwFieldTypes::size_type nSize
= mpFieldTypes
->size();
211 const SwFieldIds nFieldWhich
= rFieldTyp
.Which();
213 SwFieldTypes::size_type i
= INIT_FLDTYPES
;
215 switch( nFieldWhich
)
217 case SwFieldIds::SetExp
:
218 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
219 // Or we get doubble number circles!!
220 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
221 //constructing string pools and when reading SetExp fields
222 if( nsSwGetSetExpType::GSE_SEQ
& static_cast<const SwSetExpFieldType
&>(rFieldTyp
).GetType() )
223 i
-= INIT_SEQ_FLDTYPES
;
225 case SwFieldIds::Database
:
226 case SwFieldIds::User
:
227 case SwFieldIds::Dde
:
229 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
230 OUString
sFieldNm( rFieldTyp
.GetName() );
231 for( ; i
< nSize
; ++i
)
232 if( nFieldWhich
== (*mpFieldTypes
)[i
]->Which() &&
233 rSCmp
.isEqual( sFieldNm
, (*mpFieldTypes
)[i
]->GetName() ))
234 return (*mpFieldTypes
)[i
].get();
238 case SwFieldIds::TableOfAuthorities
:
239 for( ; i
< nSize
; ++i
)
240 if( nFieldWhich
== (*mpFieldTypes
)[i
]->Which() )
241 return (*mpFieldTypes
)[i
].get();
245 for( i
= 0; i
< nSize
; ++i
)
246 if( nFieldWhich
== (*mpFieldTypes
)[i
]->Which() )
247 return (*mpFieldTypes
)[i
].get();
250 std::unique_ptr
<SwFieldType
> pNew
= rFieldTyp
.Copy();
251 switch( nFieldWhich
)
253 case SwFieldIds::Dde
:
254 static_cast<SwDDEFieldType
*>(pNew
.get())->SetDoc( &m_rDoc
);
257 case SwFieldIds::Database
:
258 case SwFieldIds::Table
:
259 case SwFieldIds::DateTime
:
260 case SwFieldIds::GetExp
:
261 static_cast<SwValueFieldType
*>(pNew
.get())->SetDoc( &m_rDoc
);
264 case SwFieldIds::User
:
265 case SwFieldIds::SetExp
:
266 static_cast<SwValueFieldType
*>(pNew
.get())->SetDoc( &m_rDoc
);
267 // JP 29.07.96: Optionally prepare FieldList for Calculator:
268 mpUpdateFields
->InsertFieldType( *pNew
);
270 case SwFieldIds::TableOfAuthorities
:
271 static_cast<SwAuthorityFieldType
*>(pNew
.get())->SetDoc( &m_rDoc
);
276 mpFieldTypes
->insert( mpFieldTypes
->begin() + nSize
, std::move(pNew
) );
277 m_rDoc
.getIDocumentState().SetModified();
279 return (*mpFieldTypes
)[ nSize
].get();
282 /// @returns the field type of the Doc
283 SwFieldType
*DocumentFieldsManager::GetSysFieldType( const SwFieldIds eWhich
) const
285 for( SwFieldTypes::size_type i
= 0; i
< INIT_FLDTYPES
; ++i
)
286 if( eWhich
== (*mpFieldTypes
)[i
]->Which() )
287 return (*mpFieldTypes
)[i
].get();
291 /// Find first type with ResId and name
292 SwFieldType
* DocumentFieldsManager::GetFieldType(
294 const OUString
& rName
,
295 bool bDbFieldMatching
// used in some UNO calls for SwFieldIds::Database to use different string matching code #i51815#
298 const SwFieldTypes::size_type nSize
= mpFieldTypes
->size();
299 SwFieldTypes::size_type i
{0};
300 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
304 case SwFieldIds::SetExp
:
305 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
306 // Or we get doubble number circles!!
307 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
308 //constructing string pools and when reading SetExp fields
309 i
= INIT_FLDTYPES
- INIT_SEQ_FLDTYPES
;
312 case SwFieldIds::Database
:
313 case SwFieldIds::User
:
314 case SwFieldIds::Dde
:
315 case SwFieldIds::TableOfAuthorities
:
321 SwFieldType
* pRet
= nullptr;
322 for( ; i
< nSize
; ++i
)
324 SwFieldType
* pFieldType
= (*mpFieldTypes
)[i
].get();
326 if (nResId
== pFieldType
->Which())
328 OUString
aFieldName( pFieldType
->GetName() );
329 if (bDbFieldMatching
&& nResId
== SwFieldIds::Database
) // #i51815#
330 aFieldName
= aFieldName
.replace(DB_DELIM
, '.');
332 if (rSCmp
.isEqual( rName
, aFieldName
))
342 /// Remove field type
343 void DocumentFieldsManager::RemoveFieldType(size_t nField
)
345 OSL_ENSURE( INIT_FLDTYPES
<= nField
, "don't remove InitFields" );
347 * Dependent fields present -> ErrRaise
349 if(nField
>= mpFieldTypes
->size())
352 SwFieldType
* pTmp
= (*mpFieldTypes
)[nField
].get();
354 // JP 29.07.96: Optionally prepare FieldList for Calculator
355 SwFieldIds nWhich
= pTmp
->Which();
358 case SwFieldIds::SetExp
:
359 case SwFieldIds::User
:
360 mpUpdateFields
->RemoveFieldType( *pTmp
);
362 case SwFieldIds::Dde
:
363 if( pTmp
->HasWriterListeners() && !m_rDoc
.IsUsed( *pTmp
) )
365 if( SwFieldIds::SetExp
== nWhich
)
366 static_cast<SwSetExpFieldType
*>(pTmp
)->SetDeleted( true );
367 else if( SwFieldIds::User
== nWhich
)
368 static_cast<SwUserFieldType
*>(pTmp
)->SetDeleted( true );
370 static_cast<SwDDEFieldType
*>(pTmp
)->SetDeleted( true );
371 nWhich
= SwFieldIds::Database
;
377 if( nWhich
!= SwFieldIds::Database
)
379 OSL_ENSURE( !pTmp
->HasWriterListeners(), "Dependent fields present!" );
383 // coverity[leaked_storage] - at this point DB fields are ref-counted and delete themselves
384 (*mpFieldTypes
)[nField
].release();
387 mpFieldTypes
->erase( mpFieldTypes
->begin() + nField
);
388 m_rDoc
.getIDocumentState().SetModified();
391 // All have to be re-evaluated.
392 void DocumentFieldsManager::UpdateFields(bool bCloseDB
)
394 // Tell all types to update their fields
395 for(auto const& pFieldType
: *mpFieldTypes
)
396 pFieldType
->UpdateFields();
398 if(!IsExpFieldsLocked())
399 UpdateExpFields(nullptr, false); // update expression fields
402 UpdateTableFields(nullptr);
408 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
409 m_rDoc
.GetDBManager()->CloseAll();
412 // Only evaluate on full update
413 m_rDoc
.getIDocumentState().SetModified();
416 void DocumentFieldsManager::InsDeletedFieldType( SwFieldType
& rFieldTyp
)
418 // The FieldType was marked as deleted and removed from the array.
419 // One has to look this up again, now.
420 // - If it's not present, it can be re-inserted.
421 // - If the same type is found, the deleted one has to be renamed.
423 const SwFieldTypes::size_type nSize
= mpFieldTypes
->size();
424 const SwFieldIds nFieldWhich
= rFieldTyp
.Which();
426 OSL_ENSURE( SwFieldIds::SetExp
== nFieldWhich
||
427 SwFieldIds::User
== nFieldWhich
||
428 SwFieldIds::Dde
== nFieldWhich
, "Wrong FieldType" );
430 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
431 const OUString
& rFieldNm
= rFieldTyp
.GetName();
433 for( SwFieldTypes::size_type i
= INIT_FLDTYPES
; i
< nSize
; ++i
)
435 SwFieldType
* pFnd
= (*mpFieldTypes
)[i
].get();
436 if( nFieldWhich
== pFnd
->Which() &&
437 rSCmp
.isEqual( rFieldNm
, pFnd
->GetName() ) )
440 SwFieldTypes::size_type nNum
= 1;
442 OUString sSrch
= rFieldNm
+ OUString::number( nNum
);
443 for( i
= INIT_FLDTYPES
; i
< nSize
; ++i
)
445 pFnd
= (*mpFieldTypes
)[i
].get();
446 if( nFieldWhich
== pFnd
->Which() &&
447 rSCmp
.isEqual( sSrch
, pFnd
->GetName() ) )
450 if( i
>= nSize
) // not found
452 const_cast<OUString
&>(rFieldNm
) = sSrch
;
453 break; // exit while loop
461 // not found, so insert, and updated deleted flag
462 mpFieldTypes
->insert( mpFieldTypes
->begin() + nSize
, std::unique_ptr
<SwFieldType
>(&rFieldTyp
) );
463 switch( nFieldWhich
)
465 case SwFieldIds::SetExp
:
466 static_cast<SwSetExpFieldType
&>(rFieldTyp
).SetDeleted( false );
468 case SwFieldIds::User
:
469 static_cast<SwUserFieldType
&>(rFieldTyp
).SetDeleted( false );
471 case SwFieldIds::Dde
:
472 static_cast<SwDDEFieldType
&>(rFieldTyp
).SetDeleted( false );
478 void DocumentFieldsManager::PutValueToField(const SwPosition
& rPos
,
479 const Any
& rVal
, sal_uInt16 nWhich
)
482 SwField
* pField
= GetFieldAtPos(rPos
);
484 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo() &&
485 pField
->QueryValue(aOldVal
, nWhich
))
487 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(
488 std::make_unique
<SwUndoFieldFromAPI
>(rPos
, aOldVal
, rVal
, nWhich
));
491 pField
->PutValue(rVal
, nWhich
);
494 bool DocumentFieldsManager::UpdateField(SwTextField
* pDstTextField
, SwField
& rSrcField
, bool bUpdateFields
)
496 //static const sw::RefmarkFieldUpdate aRefMarkHint;
497 OSL_ENSURE(pDstTextField
, "no field to update!");
499 bool bTableSelBreak
= false;
501 SwFormatField
* pDstFormatField
= const_cast<SwFormatField
*>(&pDstTextField
->GetFormatField());
502 SwField
* pDstField
= pDstFormatField
->GetField();
503 SwFieldIds nFieldWhich
= rSrcField
.GetTyp()->Which();
504 SwNodeIndex
aTableNdIdx(pDstTextField
->GetTextNode());
506 if (pDstField
->GetTyp()->Which() ==
507 rSrcField
.GetTyp()->Which())
509 if (m_rDoc
.GetIDocumentUndoRedo().DoesUndo())
511 SwPosition
aPosition( pDstTextField
->GetTextNode(), pDstTextField
->GetStart() );
512 m_rDoc
.GetIDocumentUndoRedo().AppendUndo(std::make_unique
<SwUndoFieldFromDoc
>(aPosition
, *pDstField
, rSrcField
, bUpdateFields
));
515 pDstFormatField
->SetField(rSrcField
.CopyField());
516 SwField
* pNewField
= pDstFormatField
->GetField();
518 switch( nFieldWhich
)
520 case SwFieldIds::SetExp
:
521 case SwFieldIds::GetExp
:
522 case SwFieldIds::HiddenText
:
523 case SwFieldIds::HiddenPara
:
524 UpdateExpFields( pDstTextField
, true );
527 case SwFieldIds::Table
:
529 const SwTableNode
* pTableNd
=
530 SwDoc::IsIdxInTable(aTableNdIdx
);
534 UpdateTableFields(&pTableNd
->GetTable());
536 pNewField
->GetTyp()->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
539 bTableSelBreak
= true;
544 case SwFieldIds::Macro
:
545 if( bUpdateFields
&& pDstTextField
->GetpTextNode() )
546 pDstTextField
->GetpTextNode()->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, pDstFormatField
));
549 case SwFieldIds::DatabaseName
:
550 case SwFieldIds::DbNextSet
:
551 case SwFieldIds::DbNumSet
:
552 case SwFieldIds::DbSetNumber
:
553 m_rDoc
.ChgDBData(static_cast<SwDBNameInfField
*>( pNewField
)->GetRealDBData());
554 pNewField
->GetTyp()->UpdateFields();
558 case SwFieldIds::Database
:
559 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
561 // JP 10.02.96: call ChgValue, so that the style change sets the
562 // ContentString correctly
563 SwDBField
* pDBField
= static_cast<SwDBField
*>(pNewField
);
564 if (pDBField
->IsInitialized())
565 pDBField
->ChgValue( pDBField
->GetValue(), true );
567 pDBField
->ClearInitialized();
568 pDBField
->InitContent();
574 pDstFormatField
->ForceUpdateTextNode();
577 // The fields we can calculate here are being triggered for an update
579 if( nFieldWhich
== SwFieldIds::User
)
583 return bTableSelBreak
;
586 /// Update reference and table fields
587 void DocumentFieldsManager::UpdateRefFields()
589 for(auto const& pFieldType
: *mpFieldTypes
)
590 if(SwFieldIds::GetRef
== pFieldType
->Which())
591 static_cast<SwGetRefFieldType
*>(pFieldType
.get())->UpdateGetReferences();
594 void DocumentFieldsManager::UpdateTableFields(const SwTable
* pTable
)
596 auto pFieldType
= GetFieldType( SwFieldIds::Table
, OUString(), false );
599 std::vector
<SwFormatField
*> vFields
;
600 pFieldType
->GatherFields(vFields
);
601 for(auto pFormatField
: vFields
)
603 if(!pFormatField
->GetTextField()->GetTextNode().FindTableNode())
605 SwTableField
* pField
= static_cast<SwTableField
*>(pFormatField
->GetField());
606 // re-set the value flag
607 // JP 17.06.96: internal representation of all formulas
608 // (reference to other table!!!)
609 if(pTable
&& nsSwExtendedSubType::SUB_CMD
& pField
->GetSubType())
610 pField
->PtrToBoxNm(pTable
);
612 // reset the value flag for all
613 pField
->ChgValid(false);
616 // process all table box formulas
617 for (const SfxPoolItem
* pItem
: m_rDoc
.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA
))
619 auto pBoxFormula
= const_cast<SwTableBoxFormula
*>(pItem
->DynamicWhichCast(RES_BOXATR_FORMULA
));
620 if(pBoxFormula
&& pBoxFormula
->GetDefinedIn())
621 pBoxFormula
->ChangeState();
624 SwRootFrame
const* pLayout(nullptr);
625 for (SwRootFrame
const*const pLay
: m_rDoc
.GetAllLayouts())
627 assert(!pLayout
|| pLay
->IsHideRedlines() == pLayout
->IsHideRedlines()); // TODO
631 std::optional
<SwCalc
> oCalc
;
635 std::vector
<SwFormatField
*> vFields
;
636 pFieldType
->GatherFields(vFields
);
637 for(SwFormatField
* pFormatField
: vFields
)
639 // start calculation at the end
640 // new fields are inserted at the beginning of the modify chain
641 // that gives faster calculation on import
642 // mba: do we really need this "optimization"? Is it still valid?
643 SwTableField
*const pField(static_cast<SwTableField
*>(pFormatField
->GetField()));
644 if (nsSwExtendedSubType::SUB_CMD
& pField
->GetSubType())
647 // needs to be recalculated
648 if( !pField
->IsValid() )
650 // table where this field is located
651 const SwTextNode
& rTextNd
= pFormatField
->GetTextField()->GetTextNode();
652 const SwTableNode
* pTableNd
= rTextNd
.FindTableNode();
656 // if this field is not in the to-be-updated table, skip it
657 if(pTable
&& &pTableNd
->GetTable() != pTable
)
661 oCalc
.emplace( m_rDoc
);
663 // get the values of all SetExpression fields that are valid
665 SwFrame
* pFrame
= nullptr;
666 if( pTableNd
->GetIndex() < m_rDoc
.GetNodes().GetEndOfExtras().GetIndex() )
668 // is in the special section, that's expensive!
669 Point aPt
; // return the first frame of the layout - Tab.Headline!!
670 std::pair
<Point
, bool> const tmp(aPt
, true);
671 pFrame
= rTextNd
.getLayoutFrame(pLayout
, nullptr, &tmp
);
674 SwPosition
aPos( *pTableNd
);
675 if( GetBodyTextNode( m_rDoc
, aPos
, *pFrame
) )
677 FieldsToCalc( *oCalc
, SetGetExpField(
678 aPos
.GetNode(), pFormatField
->GetTextField(),
679 aPos
.GetContentIndex(), pFrame
->GetPhyPageNum()),
688 // create index to determine the TextNode
689 SwFrame
const*const pFrame2
= ::sw::FindNeighbourFrameForNode(rTextNd
);
690 FieldsToCalc( *oCalc
,
691 SetGetExpField(rTextNd
, pFormatField
->GetTextField(),
693 pFrame2
? pFrame2
->GetPhyPageNum() : 0),
697 SwTableCalcPara
aPara(*oCalc
, pTableNd
->GetTable(), pLayout
);
698 pField
->CalcField( aPara
);
699 if( aPara
.IsStackOverflow() )
701 bool const bResult
= aPara
.CalcWithStackOverflow();
704 pField
->CalcField( aPara
);
707 "the chained formula could no be calculated");
709 oCalc
->SetCalcError( SwCalcError::NONE
);
711 pFormatField
->ForceUpdateTextNode();
715 // calculate the formula at the boxes
716 for (const SfxPoolItem
* pItem
: m_rDoc
.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA
))
718 auto pFormula
= const_cast<SwTableBoxFormula
*>(pItem
->DynamicWhichCast(RES_BOXATR_FORMULA
));
719 if(!pFormula
|| !pFormula
->GetDefinedIn() || pFormula
->IsValid())
721 SwTableBox
* pBox
= pFormula
->GetTableBox();
722 if(!pBox
|| !pBox
->GetSttNd() || !pBox
->GetSttNd()->GetNodes().IsDocNodes())
724 const SwTableNode
* pTableNd
= pBox
->GetSttNd()->FindTableNode();
725 if(pTable
&& &pTableNd
->GetTable() != pTable
)
729 oCalc
.emplace( m_rDoc
);
731 // get the values of all SetExpression fields that are valid
733 SwFrame
* pFrame
= nullptr;
734 if( pTableNd
->GetIndex() < m_rDoc
.GetNodes().GetEndOfExtras().GetIndex() )
736 // is in the special section, that's expensive!
737 SwNodeIndex
aCNdIdx( *pTableNd
, +2 );
738 SwContentNode
* pCNd
= aCNdIdx
.GetNode().GetContentNode();
740 pCNd
= m_rDoc
.GetNodes().GoNext( &aCNdIdx
);
744 Point aPt
; // return the first frame of the layout - Tab.Headline!!
745 std::pair
<Point
, bool> const tmp(aPt
, true);
746 pFrame
= pCNd
->getLayoutFrame(pLayout
, nullptr, &tmp
);
749 SwPosition
aPos( *pCNd
);
750 if( GetBodyTextNode( m_rDoc
, aPos
, *pFrame
) )
752 FieldsToCalc(*oCalc
, SetGetExpField(aPos
.GetNode(),
753 nullptr, std::nullopt
, pFrame
->GetPhyPageNum()),
763 // create index to determine the TextNode
764 SwFrame
const*const pFrame2
= ::sw::FindNeighbourFrameForNode(*pTableNd
);
765 FieldsToCalc(*oCalc
, SetGetExpField(*pTableNd
, nullptr, std::nullopt
,
766 pFrame2
? pFrame2
->GetPhyPageNum() : 0),
770 SwTableCalcPara
aPara(*oCalc
, pTableNd
->GetTable(), pLayout
);
771 pFormula
->Calc( aPara
, nValue
);
773 if( aPara
.IsStackOverflow() )
775 bool const bResult
= aPara
.CalcWithStackOverflow();
778 pFormula
->Calc( aPara
, nValue
);
781 "the chained formula could no be calculated");
784 SwFrameFormat
* pFormat
= pBox
->ClaimFrameFormat();
785 SfxItemSetFixed
<RES_BOXATR_BEGIN
,RES_BOXATR_END
-1> aTmp( m_rDoc
.GetAttrPool() );
787 if( oCalc
->IsCalcError() )
789 aTmp
.Put( SwTableBoxValue( nValue
));
790 if( SfxItemState::SET
!= pFormat
->GetItemState( RES_BOXATR_FORMAT
))
791 aTmp
.Put( SwTableBoxNumFormat( 0 ));
792 pFormat
->SetFormatAttr( aTmp
);
794 oCalc
->SetCalcError( SwCalcError::NONE
);
798 void DocumentFieldsManager::UpdateExpFields( SwTextField
* pUpdateField
, bool bUpdRefFields
)
800 if( IsExpFieldsLocked() || m_rDoc
.IsInReading() )
803 bool bOldInUpdateFields
= mpUpdateFields
->IsInUpdateFields();
804 mpUpdateFields
->SetInUpdateFields( true );
806 mpUpdateFields
->MakeFieldList( m_rDoc
, true, GETFLD_ALL
);
807 mbNewFieldLst
= false;
809 if (mpUpdateFields
->GetSortList()->empty())
814 mpUpdateFields
->SetInUpdateFields( bOldInUpdateFields
);
815 mpUpdateFields
->SetFieldsDirty( false );
819 SwRootFrame
const* pLayout(nullptr);
820 SwRootFrame
const* pLayoutRLHidden(nullptr);
821 for (SwRootFrame
const*const pLay
: m_rDoc
.GetAllLayouts())
823 if (pLay
->IsHideRedlines())
825 pLayoutRLHidden
= pLay
;
832 if (pLayout
|| !pLayoutRLHidden
) // always calc *something*...
834 UpdateExpFieldsImpl(pUpdateField
, pLayout
);
838 UpdateExpFieldsImpl(pUpdateField
, pLayoutRLHidden
);
841 // update reference fields
845 mpUpdateFields
->SetInUpdateFields( bOldInUpdateFields
);
846 mpUpdateFields
->SetFieldsDirty( false );
849 void DocumentFieldsManager::UpdateExpFieldsImpl(
850 SwTextField
* pUpdateField
, SwRootFrame
const*const pLayout
)
854 // Hash table for all string replacements is filled on-the-fly.
855 // Try to fabricate an uneven number.
856 const SwFieldTypes::size_type nHashSize
{(( mpFieldTypes
->size() / 7 ) + 1 ) * 7};
857 const sal_uInt16 nStrFormatCnt
= o3tl::narrowing
<sal_uInt16
>(nHashSize
);
858 OSL_ENSURE( nStrFormatCnt
== nHashSize
, "Downcasting to sal_uInt16 lost information!" );
859 SwHashTable
<HashStr
> aHashStrTable(nStrFormatCnt
);
862 const SwFieldType
* pFieldType
;
863 // process separately:
864 for( auto n
= mpFieldTypes
->size(); n
; )
866 pFieldType
= (*mpFieldTypes
)[ --n
].get();
867 switch( pFieldType
->Which() )
869 case SwFieldIds::User
:
873 const OUString
& rNm
= pFieldType
->GetName();
874 OUString
sExpand(const_cast<SwUserFieldType
*>(static_cast<const SwUserFieldType
*>(pFieldType
))->Expand(nsSwGetSetExpType::GSE_STRING
, 0, LANGUAGE_SYSTEM
));
875 SwHash
* pFnd
= aHashStrTable
.Find( rNm
, &nPos
);
877 // modify entry in the hash table
878 static_cast<HashStr
*>(pFnd
)->aSetStr
= sExpand
;
880 // insert the new entry
881 aHashStrTable
[nPos
].reset( new HashStr( rNm
, sExpand
,
882 aHashStrTable
[nPos
].release() ) );
890 // The array is filled with all fields; start calculation.
891 SwCalc
aCalc( m_rDoc
);
893 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
894 OUString
sDBNumNm( SwFieldType::GetTypeStr( SwFieldTypesEnum::DatabaseSetNumber
) );
896 // already set the current record number
897 SwDBManager
* pMgr
= m_rDoc
.GetDBManager();
898 pMgr
->CloseAll( false );
900 SvtSysLocale aSysLocale
;
901 const LocaleDataWrapper
* pLclData
= &aSysLocale
.GetLocaleData();
902 const LanguageType nLang
= pLclData
->getLanguageTag().getLanguageType();
903 bool bCanFill
= pMgr
->FillCalcWithMergeData( m_rDoc
.GetNumberFormatter(), nLang
, aCalc
);
906 // Make sure we don't hide all content, which would lead to a crash. First, count how many visible sections we have.
907 int nShownSections
= 0;
908 SwNodeOffset nContentStart
= m_rDoc
.GetNodes().GetEndOfContent().StartOfSectionIndex() + 1;
909 SwNodeOffset nContentEnd
= m_rDoc
.GetNodes().GetEndOfContent().GetIndex();
910 SwSectionFormats
& rSectFormats
= m_rDoc
.GetSections();
911 for( SwSectionFormats::size_type n
= 0; n
<rSectFormats
.size(); ++n
)
913 SwSectionFormat
& rSectFormat
= *rSectFormats
[ n
];
914 SwSectionNode
* pSectionNode
= rSectFormat
.GetSectionNode();
915 SwSection
* pSect
= rSectFormat
.GetSection();
917 // Usually some of the content is not in a section: count that as a virtual section, so that all real sections can be hidden.
918 // Only look for section gaps at the lowest level, ignoring sub-sections.
919 if ( pSectionNode
&& !rSectFormat
.GetParent() )
921 SwNodeIndex
aNextIdx( *pSectionNode
->EndOfSectionNode(), 1 );
922 if ( n
== 0 && pSectionNode
->GetIndex() != nContentStart
)
923 nShownSections
++; //document does not start with a section
924 if ( n
== rSectFormats
.size() - 1 )
926 if ( aNextIdx
.GetIndex() != nContentEnd
)
927 nShownSections
++; //document does not end in a section
929 else if ( !aNextIdx
.GetNode().IsSectionNode() )
930 nShownSections
++; //section is not immediately followed by another section
933 // count only visible sections
934 if ( pSect
&& !pSect
->CalcHiddenFlag())
938 IDocumentRedlineAccess
const& rIDRA(m_rDoc
.getIDocumentRedlineAccess());
939 std::unordered_map
<SwSetExpFieldType
const*, SwTextNode
const*> SetExpOutlineNodeMap
;
941 for (std::unique_ptr
<SetGetExpField
> const& it
: *mpUpdateFields
->GetSortList())
943 SwSection
* pSect
= const_cast<SwSection
*>(it
->GetSection());
946 SwSbxValue aValue
= aCalc
.Calculate(
947 pSect
->GetCondition() );
948 if(!aValue
.IsVoidValue())
950 // Do we want to hide this one?
951 bool bHide
= aValue
.GetBool();
952 if (bHide
&& !pSect
->IsCondHidden())
954 // This section will be hidden, but it wasn't before
955 if (nShownSections
== 1)
957 // This would be the last section, so set its condition to false, and avoid hiding it.
958 pSect
->SetCondition("0");
963 pSect
->SetCondHidden( bHide
);
967 ::sw::mark::IBookmark
*const pBookmark(
968 const_cast<::sw::mark::IBookmark
*>(it
->GetBookmark()));
971 SwSbxValue
const aValue(aCalc
.Calculate(pBookmark
->GetHideCondition()));
972 if (!aValue
.IsVoidValue())
974 pBookmark
->Hide(aValue
.GetBool());
979 SwTextField
* pTextField
= const_cast<SwTextField
*>(it
->GetTextField());
982 OSL_ENSURE( false, "what's wrong now'" );
986 if (pLayout
&& pLayout
->IsHideRedlines()
987 && IsFieldDeleted(rIDRA
, *pLayout
, *pTextField
))
992 SwFormatField
* pFormatField
= const_cast<SwFormatField
*>(&pTextField
->GetFormatField());
993 const SwField
* pField
= pFormatField
->GetField();
995 nWhich
= pField
->GetTyp()->Which();
998 case SwFieldIds::HiddenText
:
1000 SwHiddenTextField
* pHField
= const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
));
1001 SwSbxValue aValue
= aCalc
.Calculate( pHField
->GetPar1() );
1002 bool bValue
= !aValue
.GetBool();
1003 if(!aValue
.IsVoidValue())
1005 pHField
->SetValue( bValue
);
1007 pHField
->Evaluate(m_rDoc
);
1011 case SwFieldIds::HiddenPara
:
1013 SwHiddenParaField
* pHPField
= const_cast<SwHiddenParaField
*>(static_cast<const SwHiddenParaField
*>(pField
));
1014 SwSbxValue aValue
= aCalc
.Calculate( pHPField
->GetPar1() );
1015 bool bValue
= aValue
.GetBool();
1016 if(!aValue
.IsVoidValue())
1017 pHPField
->SetHidden( bValue
);
1020 case SwFieldIds::DbSetNumber
:
1021 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1023 const_cast<SwDBSetNumberField
*>(static_cast<const SwDBSetNumberField
*>(pField
))->Evaluate(m_rDoc
);
1024 aCalc
.VarChange( sDBNumNm
, static_cast<const SwDBSetNumberField
*>(pField
)->GetSetNumber());
1025 pField
->ExpandField(m_rDoc
.IsClipBoard(), nullptr);
1029 case SwFieldIds::DbNextSet
:
1030 case SwFieldIds::DbNumSet
:
1031 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1033 UpdateDBNumFields( *const_cast<SwDBNameInfField
*>(static_cast<const SwDBNameInfField
*>(pField
)), aCalc
);
1035 bCanFill
= pMgr
->FillCalcWithMergeData( m_rDoc
.GetNumberFormatter(), nLang
, aCalc
);
1039 case SwFieldIds::Database
:
1041 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1043 const_cast<SwDBField
*>(static_cast<const SwDBField
*>(pField
))->Evaluate();
1045 SwDBData
aTmpDBData(static_cast<const SwDBField
*>(pField
)->GetDBData());
1047 if( pMgr
->IsDataSourceOpen(aTmpDBData
.sDataSource
, aTmpDBData
.sCommand
, false))
1048 aCalc
.VarChange( sDBNumNm
, pMgr
->GetSelectedRecordId(aTmpDBData
.sDataSource
, aTmpDBData
.sCommand
, aTmpDBData
.nCommandType
));
1050 const OUString
& rName
= pField
->GetTyp()->GetName();
1052 // Add entry to hash table
1055 HashStr
* pFnd
= aHashStrTable
.Find( rName
, &nPos
);
1056 OUString
const value(pField
->ExpandField(m_rDoc
.IsClipBoard(), nullptr));
1059 // Modify entry in the hash table
1060 pFnd
->aSetStr
= value
;
1065 aHashStrTable
[nPos
].reset( new HashStr( rName
,
1066 value
, aHashStrTable
[nPos
].release()) );
1071 case SwFieldIds::GetExp
:
1072 case SwFieldIds::SetExp
:
1074 if( nsSwGetSetExpType::GSE_STRING
& pField
->GetSubType() ) // replace String
1076 if( SwFieldIds::GetExp
== nWhich
)
1078 SwGetExpField
* pGField
= const_cast<SwGetExpField
*>(static_cast<const SwGetExpField
*>(pField
));
1080 if( (!pUpdateField
|| pUpdateField
== pTextField
)
1081 && pGField
->IsInBodyText() )
1083 OUString aNew
= LookString( aHashStrTable
, pGField
->GetFormula() );
1084 pGField
->ChgExpStr( aNew
, pLayout
);
1089 SwSetExpField
* pSField
= const_cast<SwSetExpField
*>(static_cast<const SwSetExpField
*>(pField
));
1090 // is the "formula" a field?
1091 OUString aNew
= LookString( aHashStrTable
, pSField
->GetFormula() );
1093 if( aNew
.isEmpty() ) // nothing found then the formula is the new value
1094 aNew
= pSField
->GetFormula();
1096 // only update one field
1097 if( !pUpdateField
|| pUpdateField
== pTextField
)
1098 pSField
->ChgExpStr( aNew
, pLayout
);
1100 // lookup the field's name
1101 aNew
= static_cast<SwSetExpFieldType
*>(pSField
->GetTyp())->GetSetRefName();
1104 HashStr
* pFnd
= aHashStrTable
.Find( aNew
, &nPos
);
1106 // Modify entry in the hash table
1107 pFnd
->aSetStr
= pSField
->GetExpStr(pLayout
);
1111 aHashStrTable
[nPos
].reset( new HashStr( aNew
,
1112 pSField
->GetExpStr(pLayout
),
1113 aHashStrTable
[nPos
].release() ) );
1114 pFnd
= aHashStrTable
[nPos
].get();
1117 // Extension for calculation with Strings
1119 aValue
.PutString( pFnd
->aSetStr
);
1120 aCalc
.VarChange( aNew
, aValue
);
1123 else // recalculate formula
1125 if( SwFieldIds::GetExp
== nWhich
)
1127 SwGetExpField
* pGField
= const_cast<SwGetExpField
*>(static_cast<const SwGetExpField
*>(pField
));
1129 if( (!pUpdateField
|| pUpdateField
== pTextField
)
1130 && pGField
->IsInBodyText() )
1132 SwSbxValue aValue
= aCalc
.Calculate(
1133 pGField
->GetFormula());
1134 if(!aValue
.IsVoidValue())
1135 pGField
->SetValue(aValue
.GetDouble(), pLayout
);
1140 SwSetExpField
* pSField
= const_cast<SwSetExpField
*>(static_cast<const SwSetExpField
*>(pField
));
1141 SwSetExpFieldType
* pSFieldTyp
= static_cast<SwSetExpFieldType
*>(pField
->GetTyp());
1142 OUString aNew
= pSFieldTyp
->GetName();
1144 SwNode
* pSeqNd
= nullptr;
1146 if( pSField
->IsSequenceField() )
1148 const sal_uInt8 nLvl
= pSFieldTyp
->GetOutlineLvl();
1149 if( MAXLEVEL
> nLvl
)
1151 // test if the Number needs to be updated
1152 pSeqNd
= m_rDoc
.GetNodes()[ it
->GetNode() ];
1154 const SwTextNode
* pOutlNd
= pSeqNd
->
1155 FindOutlineNodeOfLevel(nLvl
, pLayout
);
1156 auto const iter(SetExpOutlineNodeMap
.find(pSFieldTyp
));
1157 if (iter
== SetExpOutlineNodeMap
.end()
1158 || iter
->second
!= pOutlNd
)
1160 SetExpOutlineNodeMap
[pSFieldTyp
] = pOutlNd
;
1161 aCalc
.VarChange( aNew
, 0 );
1166 aNew
+= "=" + pSField
->GetFormula();
1168 SwSbxValue aValue
= aCalc
.Calculate( aNew
);
1169 if (!aCalc
.IsCalcError())
1171 double nErg
= aValue
.GetDouble();
1172 // only update one field
1173 if( !aValue
.IsVoidValue() && (!pUpdateField
|| pUpdateField
== pTextField
) )
1175 pSField
->SetValue(nErg
, pLayout
);
1178 pSFieldTyp
->SetChapter(*pSField
, *pSeqNd
, pLayout
);
1189 // avoid calling ReplaceText() for input fields, it is pointless
1190 // here and moves the cursor if it's inside the field ...
1191 SwTextInputField
*const pInputField(
1192 pUpdateField
== pTextField
// ... except once, when the dialog
1193 ? nullptr // is used to change content via UpdateOneField()
1194 : dynamic_cast<SwTextInputField
*>(pTextField
));
1197 bool const tmp
= pInputField
->LockNotifyContentChange();
1199 assert(tmp
&& "should not be locked here?");
1201 ::comphelper::ScopeGuard
g([pInputField
]()
1205 pInputField
->UnlockNotifyContentChange();
1208 pFormatField
->ForceUpdateTextNode();
1211 if (pUpdateField
== pTextField
) // if only this one is updated
1213 if( SwFieldIds::GetExp
== nWhich
|| // only GetField or
1214 SwFieldIds::HiddenText
== nWhich
|| // HiddenText?
1215 SwFieldIds::HiddenPara
== nWhich
) // HiddenParaField?
1217 pUpdateField
= nullptr; // update all from here on
1221 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1222 pMgr
->CloseAll(false);
1226 /// Insert field type that was marked as deleted
1227 void DocumentFieldsManager::UpdateUsrFields()
1229 SwCalc
* pCalc
= nullptr;
1230 for( SwFieldTypes::size_type i
= INIT_FLDTYPES
; i
< mpFieldTypes
->size(); ++i
)
1232 const SwFieldType
* pFieldType
= (*mpFieldTypes
)[i
].get();
1233 if( SwFieldIds::User
== pFieldType
->Which() )
1236 pCalc
= new SwCalc( m_rDoc
);
1237 const_cast<SwUserFieldType
*>(static_cast<const SwUserFieldType
*>(pFieldType
))->GetValue( *pCalc
);
1244 m_rDoc
.getIDocumentState().SetModified();
1248 sal_Int32
DocumentFieldsManager::GetRecordsPerDocument() const
1250 sal_Int32 nRecords
= 1;
1252 mpUpdateFields
->MakeFieldList( m_rDoc
, true, GETFLD_ALL
);
1253 if (mpUpdateFields
->GetSortList()->empty())
1256 for (std::unique_ptr
<SetGetExpField
> const& it
: *mpUpdateFields
->GetSortList())
1258 const SwTextField
*pTextField
= it
->GetTextField();
1262 const SwFormatField
&pFormatField
= pTextField
->GetFormatField();
1263 const SwField
* pField
= pFormatField
.GetField();
1265 switch( pField
->GetTyp()->Which() )
1267 case SwFieldIds::DbNextSet
:
1268 case SwFieldIds::DbNumSet
:
1279 void DocumentFieldsManager::UpdatePageFields(const SwTwips nDocPos
)
1281 for(SwFieldTypes::size_type i
= 0; i
< INIT_FLDTYPES
; ++i
)
1283 SwFieldType
* pFieldType
= (*mpFieldTypes
)[i
].get();
1284 switch(pFieldType
->Which())
1286 case SwFieldIds::PageNumber
:
1287 case SwFieldIds::Chapter
:
1288 case SwFieldIds::GetExp
:
1289 case SwFieldIds::RefPageGet
:
1290 pFieldType
->UpdateDocPos(nDocPos
);
1292 case SwFieldIds::DocStat
:
1293 pFieldType
->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1298 SetNewFieldLst(true);
1301 void DocumentFieldsManager::LockExpFields()
1306 void DocumentFieldsManager::UnlockExpFields()
1308 assert(mnLockExpField
!= 0);
1309 if( mnLockExpField
)
1313 bool DocumentFieldsManager::IsExpFieldsLocked() const
1315 return 0 != mnLockExpField
;
1318 SwDocUpdateField
& DocumentFieldsManager::GetUpdateFields() const
1320 return *mpUpdateFields
;
1323 bool DocumentFieldsManager::SetFieldsDirty( bool b
, const SwNode
* pChk
, SwNodeOffset nLen
)
1325 // See if the supplied nodes actually contain fields.
1326 // If they don't, the flag doesn't need to be changed.
1327 bool bFieldsFnd
= false;
1328 if( b
&& pChk
&& !GetUpdateFields().IsFieldsDirty() && !m_rDoc
.IsInDtor()
1329 // ?? what's up with Undo, this is also wanted there!
1330 /*&& &pChk->GetNodes() == &GetNodes()*/ )
1335 SwNodeOffset nStt
= pChk
->GetIndex();
1336 const SwNodes
& rNds
= pChk
->GetNodes();
1339 const SwTextNode
* pTNd
= rNds
[ nStt
++ ]->GetTextNode();
1342 if( pTNd
->GetAttrOutlineLevel() != 0 )
1343 // update chapter fields
1345 else if( pTNd
->GetpSwpHints() && pTNd
->GetSwpHints().Count() )
1347 const size_t nEnd
= pTNd
->GetSwpHints().Count();
1348 for( size_t n
= 0 ; n
< nEnd
; ++n
)
1350 const SwTextAttr
* pAttr
= pTNd
->GetSwpHints().Get(n
);
1351 if ( pAttr
->Which() == RES_TXTATR_FIELD
1352 || pAttr
->Which() == RES_TXTATR_INPUTFIELD
)
1366 GetUpdateFields().SetFieldsDirty( b
);
1370 void DocumentFieldsManager::SetFixFields( const DateTime
* pNewDateTime
)
1372 bool bIsModified
= m_rDoc
.getIDocumentState().IsModified();
1378 nDate
= pNewDateTime
->GetDate();
1379 nTime
= pNewDateTime
->GetTime();
1383 DateTime
aDateTime( DateTime::SYSTEM
);
1384 nDate
= aDateTime
.GetDate();
1385 nTime
= aDateTime
.GetTime();
1388 SwFieldIds
const aTypes
[] {
1389 /*0*/ SwFieldIds::DocInfo
,
1390 /*1*/ SwFieldIds::Author
,
1391 /*2*/ SwFieldIds::ExtUser
,
1392 /*3*/ SwFieldIds::Filename
,
1393 /*4*/ SwFieldIds::DateTime
}; // MUST be at the end!
1395 for(SwFieldIds aType
: aTypes
)
1397 std::vector
<SwFormatField
*> vFields
;
1398 GetSysFieldType(aType
)->GatherFields(vFields
);
1399 for(auto pFormatField
: vFields
)
1401 if (pFormatField
->GetTextField())
1406 case SwFieldIds::DocInfo
:
1407 if( static_cast<SwDocInfoField
*>(pFormatField
->GetField())->IsFixed() )
1410 SwDocInfoField
* pDocInfField
= static_cast<SwDocInfoField
*>(pFormatField
->GetField());
1411 pDocInfField
->SetExpansion( static_cast<SwDocInfoFieldType
*>(
1412 pDocInfField
->GetTyp())->Expand(
1413 pDocInfField
->GetSubType(),
1414 pDocInfField
->GetFormat(),
1415 pDocInfField
->GetLanguage(),
1416 pDocInfField
->GetName() ) );
1420 case SwFieldIds::Author
:
1421 if( static_cast<SwAuthorField
*>(pFormatField
->GetField())->IsFixed() )
1424 SwAuthorField
* pAuthorField
= static_cast<SwAuthorField
*>(pFormatField
->GetField());
1425 pAuthorField
->SetExpansion( SwAuthorFieldType::Expand( pAuthorField
->GetFormat() ) );
1429 case SwFieldIds::ExtUser
:
1430 if( static_cast<SwExtUserField
*>(pFormatField
->GetField())->IsFixed() )
1433 SwExtUserField
* pExtUserField
= static_cast<SwExtUserField
*>(pFormatField
->GetField());
1434 pExtUserField
->SetExpansion( SwExtUserFieldType::Expand(pExtUserField
->GetSubType()) );
1438 case SwFieldIds::DateTime
:
1439 if( static_cast<SwDateTimeField
*>(pFormatField
->GetField())->IsFixed() )
1442 static_cast<SwDateTimeField
*>(pFormatField
->GetField())->SetDateTime(
1443 DateTime(Date(nDate
), tools::Time(nTime
)) );
1447 case SwFieldIds::Filename
:
1448 if( static_cast<SwFileNameField
*>(pFormatField
->GetField())->IsFixed() )
1451 SwFileNameField
* pFileNameField
=
1452 static_cast<SwFileNameField
*>(pFormatField
->GetField());
1453 pFileNameField
->SetExpansion( static_cast<SwFileNameFieldType
*>(
1454 pFileNameField
->GetTyp())->Expand(
1455 pFileNameField
->GetFormat() ) );
1461 // Trigger formatting
1463 pFormatField
->ForceUpdateTextNode();
1469 m_rDoc
.getIDocumentState().ResetModified();
1472 void DocumentFieldsManager::FieldsToCalc(SwCalc
& rCalc
,
1473 const SetGetExpField
& rToThisField
, SwRootFrame
const*const pLayout
)
1475 // create the sorted list of all SetFields
1476 mpUpdateFields
->MakeFieldList( m_rDoc
, mbNewFieldLst
, GETFLD_CALC
);
1477 mbNewFieldLst
= false;
1479 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
1480 SwDBManager
* pMgr
= NULL
;
1482 SwDBManager
* pMgr
= m_rDoc
.GetDBManager();
1483 pMgr
->CloseAll(false);
1486 if (!mpUpdateFields
->GetSortList()->empty())
1488 SetGetExpFields::const_iterator
const itLast
=
1489 mpUpdateFields
->GetSortList()->upper_bound(
1491 for (auto it
= mpUpdateFields
->GetSortList()->begin(); it
!= itLast
; ++it
)
1493 lcl_CalcField(m_rDoc
, rCalc
, **it
, pMgr
, pLayout
);
1496 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1497 pMgr
->CloseAll(false);
1501 void DocumentFieldsManager::FieldsToCalc(SwCalc
& rCalc
,
1502 SwNodeOffset
const nLastNd
, sal_Int32
const nLastCnt
)
1504 // create the sorted list of all SetFields
1505 mpUpdateFields
->MakeFieldList( m_rDoc
, mbNewFieldLst
, GETFLD_CALC
);
1506 mbNewFieldLst
= false;
1508 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
1509 SwDBManager
* pMgr
= NULL
;
1511 SwDBManager
* pMgr
= m_rDoc
.GetDBManager();
1512 pMgr
->CloseAll(false);
1515 SwRootFrame
const* pLayout(nullptr);
1516 SwRootFrame
const* pLayoutRLHidden(nullptr);
1517 for (SwRootFrame
const*const pLay
: m_rDoc
.GetAllLayouts())
1519 if (pLay
->IsHideRedlines())
1521 pLayoutRLHidden
= pLay
;
1529 // note this is not duplicate of the other FieldsToCalc because there is
1530 // (currently) no SetGetExpField that compares only a position
1531 for(auto it
= mpUpdateFields
->GetSortList()->begin();
1532 it
!= mpUpdateFields
->GetSortList()->end() &&
1533 ( (*it
)->GetNode() < nLastNd
||
1534 ( (*it
)->GetNode() == nLastNd
&& (*it
)->GetContent() <= nLastCnt
)
1538 if (pLayout
|| !pLayoutRLHidden
) // always calc *something*...
1540 lcl_CalcField( m_rDoc
, rCalc
, **it
, pMgr
, pLayout
);
1542 if (pLayoutRLHidden
)
1544 lcl_CalcField( m_rDoc
, rCalc
, **it
, pMgr
, pLayoutRLHidden
);
1548 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1549 pMgr
->CloseAll(false);
1553 void DocumentFieldsManager::FieldsToExpand( SwHashTable
<HashStr
> & rHashTable
,
1554 const SetGetExpField
& rToThisField
, SwRootFrame
const& rLayout
)
1556 // create the sorted list of all SetFields
1557 mpUpdateFields
->MakeFieldList( m_rDoc
, mbNewFieldLst
, GETFLD_EXPAND
);
1558 mbNewFieldLst
= false;
1560 IDocumentRedlineAccess
const& rIDRA(m_rDoc
.getIDocumentRedlineAccess());
1562 // Hash table for all string replacements is filled on-the-fly.
1563 // Try to fabricate an uneven number.
1564 sal_uInt16 nTableSize
= ((mpUpdateFields
->GetSortList()->size() / 7) + 1) * 7;
1565 rHashTable
.resize(nTableSize
);
1567 SetGetExpFields::const_iterator
const itLast
=
1568 mpUpdateFields
->GetSortList()->upper_bound(&rToThisField
);
1570 for (auto it
= mpUpdateFields
->GetSortList()->begin(); it
!= itLast
; ++it
)
1572 const SwTextField
* pTextField
= (*it
)->GetTextField();
1576 if (rLayout
.IsHideRedlines()
1577 && IsFieldDeleted(rIDRA
, rLayout
, *pTextField
))
1582 const SwField
* pField
= pTextField
->GetFormatField().GetField();
1583 switch( pField
->GetTyp()->Which() )
1585 case SwFieldIds::SetExp
:
1586 if( nsSwGetSetExpType::GSE_STRING
& pField
->GetSubType() )
1588 // set the new value in the hash table
1589 // is the formula a field?
1590 SwSetExpField
* pSField
= const_cast<SwSetExpField
*>(static_cast<const SwSetExpField
*>(pField
));
1591 OUString aNew
= LookString( rHashTable
, pSField
->GetFormula() );
1593 if( aNew
.isEmpty() ) // nothing found, then the formula is
1594 aNew
= pSField
->GetFormula(); // the new value
1596 // #i3141# - update expression of field as in method
1597 // <SwDoc::UpdateExpFields(..)> for string/text fields
1598 pSField
->ChgExpStr(aNew
, &rLayout
);
1600 // look up the field's name
1601 aNew
= static_cast<SwSetExpFieldType
*>(pSField
->GetTyp())->GetSetRefName();
1604 SwHash
* pFnd
= rHashTable
.Find( aNew
, &nPos
);
1606 // modify entry in the hash table
1607 static_cast<HashStr
*>(pFnd
)->aSetStr
= pSField
->GetExpStr(&rLayout
);
1609 // insert the new entry
1610 rHashTable
[nPos
].reset( new HashStr( aNew
,
1611 pSField
->GetExpStr(&rLayout
), rHashTable
[nPos
].release()));
1614 case SwFieldIds::Database
:
1616 const OUString
& rName
= pField
->GetTyp()->GetName();
1618 // Insert entry in the hash table
1621 HashStr
* pFnd
= rHashTable
.Find( rName
, &nPos
);
1622 OUString
const value(pField
->ExpandField(m_rDoc
.IsClipBoard(), nullptr));
1625 // modify entry in the hash table
1626 pFnd
->aSetStr
= value
;
1630 // insert the new entry
1631 rHashTable
[nPos
].reset( new HashStr( rName
,
1632 value
, rHashTable
[nPos
].release()) );
1642 bool DocumentFieldsManager::IsNewFieldLst() const
1644 return mbNewFieldLst
;
1647 void DocumentFieldsManager::SetNewFieldLst(bool bFlag
)
1649 mbNewFieldLst
= bFlag
;
1652 void DocumentFieldsManager::InsDelFieldInFieldLst( bool bIns
, const SwTextField
& rField
)
1654 if (!mbNewFieldLst
&& !m_rDoc
.IsInDtor())
1655 mpUpdateFields
->InsDelFieldInFieldLst( bIns
, rField
);
1658 SwField
* DocumentFieldsManager::GetFieldAtPos(const SwPosition
& rPos
)
1660 SwTextField
* const pAttr
= GetTextFieldAtPos(rPos
);
1662 return pAttr
? const_cast<SwField
*>( pAttr
->GetFormatField().GetField() ) : nullptr;
1665 SwTextField
* DocumentFieldsManager::GetTextFieldAtPos(const SwPosition
& rPos
)
1667 SwTextNode
* const pNode
= rPos
.GetNode().GetTextNode();
1669 return (pNode
!= nullptr)
1670 ? pNode
->GetFieldTextAttrAt(rPos
.GetContentIndex(), ::sw::GetTextAttrMode::Default
)
1674 /// @note For simplicity assume that all field types have updatable contents so
1675 /// optimization currently only available when no fields exist.
1676 bool DocumentFieldsManager::containsUpdatableFields()
1678 std::vector
<SwFormatField
*> vFields
;
1679 for (auto const& pFieldType
: *mpFieldTypes
)
1681 pFieldType
->GatherFields(vFields
);
1682 if(vFields
.size()>0)
1688 /// Remove all unreferenced field types of a document
1689 void DocumentFieldsManager::GCFieldTypes()
1691 for( auto n
= mpFieldTypes
->size(); n
> INIT_FLDTYPES
; )
1692 if( !(*mpFieldTypes
)[ --n
]->HasWriterListeners() )
1693 RemoveFieldType( n
);
1696 void DocumentFieldsManager::InitFieldTypes() // is being called by the CTOR
1699 mpFieldTypes
->emplace_back( new SwDateTimeFieldType(&m_rDoc
) );
1700 mpFieldTypes
->emplace_back( new SwChapterFieldType
);
1701 mpFieldTypes
->emplace_back( new SwPageNumberFieldType
);
1702 mpFieldTypes
->emplace_back( new SwAuthorFieldType
);
1703 mpFieldTypes
->emplace_back( new SwFileNameFieldType(m_rDoc
) );
1704 mpFieldTypes
->emplace_back( new SwDBNameFieldType(&m_rDoc
) );
1705 mpFieldTypes
->emplace_back( new SwGetExpFieldType(&m_rDoc
) );
1706 mpFieldTypes
->emplace_back( new SwGetRefFieldType(m_rDoc
) );
1707 mpFieldTypes
->emplace_back( new SwHiddenTextFieldType
);
1708 mpFieldTypes
->emplace_back( new SwPostItFieldType(m_rDoc
) );
1709 mpFieldTypes
->emplace_back( new SwDocStatFieldType(m_rDoc
) );
1710 mpFieldTypes
->emplace_back( new SwDocInfoFieldType(&m_rDoc
) );
1711 mpFieldTypes
->emplace_back( new SwInputFieldType( &m_rDoc
) );
1712 mpFieldTypes
->emplace_back( new SwTableFieldType( &m_rDoc
) );
1713 mpFieldTypes
->emplace_back( new SwMacroFieldType(m_rDoc
) );
1714 mpFieldTypes
->emplace_back( new SwHiddenParaFieldType
);
1715 mpFieldTypes
->emplace_back( new SwDBNextSetFieldType
);
1716 mpFieldTypes
->emplace_back( new SwDBNumSetFieldType
);
1717 mpFieldTypes
->emplace_back( new SwDBSetNumberFieldType
);
1718 mpFieldTypes
->emplace_back( new SwTemplNameFieldType(m_rDoc
) );
1719 mpFieldTypes
->emplace_back( new SwTemplNameFieldType(m_rDoc
) );
1720 mpFieldTypes
->emplace_back( new SwExtUserFieldType
);
1721 mpFieldTypes
->emplace_back( new SwRefPageSetFieldType
);
1722 mpFieldTypes
->emplace_back( new SwRefPageGetFieldType(m_rDoc
) );
1723 mpFieldTypes
->emplace_back( new SwJumpEditFieldType(m_rDoc
) );
1724 mpFieldTypes
->emplace_back( new SwScriptFieldType(m_rDoc
) );
1725 mpFieldTypes
->emplace_back( new SwCombinedCharFieldType
);
1726 mpFieldTypes
->emplace_back( new SwDropDownFieldType
);
1728 // Types have to be at the end!
1729 // We expect this in the InsertFieldType!
1730 // MIB 14.04.95: In Sw3StringPool::Setup (sw3imp.cxx) and
1731 // lcl_sw3io_InSetExpField (sw3field.cxx) now also
1732 mpFieldTypes
->emplace_back( new SwSetExpFieldType(&m_rDoc
,
1733 SwResId(STR_POOLCOLL_LABEL_ABB
), nsSwGetSetExpType::GSE_SEQ
) );
1734 mpFieldTypes
->emplace_back( new SwSetExpFieldType(&m_rDoc
,
1735 SwResId(STR_POOLCOLL_LABEL_TABLE
), nsSwGetSetExpType::GSE_SEQ
) );
1736 mpFieldTypes
->emplace_back( new SwSetExpFieldType(&m_rDoc
,
1737 SwResId(STR_POOLCOLL_LABEL_FRAME
), nsSwGetSetExpType::GSE_SEQ
) );
1738 mpFieldTypes
->emplace_back( new SwSetExpFieldType(&m_rDoc
,
1739 SwResId(STR_POOLCOLL_LABEL_DRAWING
), nsSwGetSetExpType::GSE_SEQ
) );
1740 mpFieldTypes
->emplace_back( new SwSetExpFieldType(&m_rDoc
,
1741 SwResId(STR_POOLCOLL_LABEL_FIGURE
), nsSwGetSetExpType::GSE_SEQ
) );
1743 assert( mpFieldTypes
->size() == INIT_FLDTYPES
);
1746 void DocumentFieldsManager::ClearFieldTypes()
1748 mpFieldTypes
->erase( mpFieldTypes
->begin() + INIT_FLDTYPES
, mpFieldTypes
->end() );
1751 void DocumentFieldsManager::UpdateDBNumFields( SwDBNameInfField
& rDBField
, SwCalc
& rCalc
)
1753 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
1757 SwDBManager
* pMgr
= m_rDoc
.GetDBManager();
1759 SwFieldIds nFieldType
= rDBField
.Which();
1761 bool bPar1
= rCalc
.Calculate( rDBField
.GetPar1() ).GetBool();
1763 if( SwFieldIds::DbNextSet
== nFieldType
)
1764 static_cast<SwDBNextSetField
&>(rDBField
).SetCondValid( bPar1
);
1766 static_cast<SwDBNumSetField
&>(rDBField
).SetCondValid( bPar1
);
1768 if( !rDBField
.GetRealDBData().sDataSource
.isEmpty() )
1770 // Edit a certain database
1771 if( SwFieldIds::DbNextSet
== nFieldType
)
1772 static_cast<SwDBNextSetField
&>(rDBField
).Evaluate(m_rDoc
);
1774 static_cast<SwDBNumSetField
&>(rDBField
).Evaluate(m_rDoc
);
1776 SwDBData
aTmpDBData( rDBField
.GetDBData(&m_rDoc
) );
1778 if( pMgr
->OpenDataSource( aTmpDBData
.sDataSource
, aTmpDBData
.sCommand
))
1779 rCalc
.VarChange( lcl_GetDBVarName( m_rDoc
, rDBField
),
1780 pMgr
->GetSelectedRecordId(aTmpDBData
.sDataSource
, aTmpDBData
.sCommand
, aTmpDBData
.nCommandType
) );
1784 OSL_FAIL("TODO: what should happen with unnamed DBFields?");
1789 DocumentFieldsManager::~DocumentFieldsManager()
1791 mpUpdateFields
.reset();
1792 mpFieldTypes
.reset();
1797 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */