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 .
20 #include <config_features.h>
21 #include <config_fuzzers.h>
23 #include <hintids.hxx>
25 #include <comphelper/string.hxx>
26 #include <osl/diagnose.h>
27 #include <unotools/charclass.hxx>
29 #include <unotools/transliterationwrapper.hxx>
31 #include <o3tl/string_view.hxx>
33 #include <IDocumentFieldsAccess.hxx>
34 #include <IDocumentMarkAccess.hxx>
35 #include <IDocumentState.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <node2lay.hxx>
39 #include <pagefrm.hxx>
41 #include <notxtfrm.hxx>
44 #include <swtable.hxx>
48 #include <txttxmrk.hxx>
50 #include <docufld.hxx>
56 #include <section.hxx>
58 #include <authfld.hxx>
59 #include <txtinet.hxx>
60 #include <fmtcntnt.hxx>
63 // the StartIndex can be supplied optionally (e.g. if it was queried before - is a virtual
65 SetGetExpField::SetGetExpField(
67 const SwTextField
* pField
,
68 std::optional
<sal_Int32
> oContentIdx
,
69 sal_uInt16
const nPageNumber
)
70 : m_nPageNumber(nPageNumber
)
72 m_eSetGetExpFieldType
= TEXTFIELD
;
73 m_CNTNT
.pTextField
= pField
;
74 m_nNode
= rNdIdx
.GetIndex();
76 m_nContent
= *oContentIdx
;
78 m_nContent
= pField
->GetStart();
83 SetGetExpField::SetGetExpField( const SwNode
& rNdIdx
,
84 const SwTextINetFormat
& rINet
)
86 m_eSetGetExpFieldType
= TEXTINET
;
87 m_CNTNT
.pTextINet
= &rINet
;
88 m_nNode
= rNdIdx
.GetIndex();
89 m_nContent
= rINet
.GetStart();
92 // Extension for Sections:
93 // these always have content position 0xffffffff!
94 // There is never a field on this, only up to COMPLETE_STRING possible
95 SetGetExpField::SetGetExpField( const SwSectionNode
& rSectNd
,
96 const SwPosition
* pPos
,
97 sal_uInt16
const nPageNumber
)
98 : m_nPageNumber(nPageNumber
)
100 m_eSetGetExpFieldType
= SECTIONNODE
;
101 m_CNTNT
.pSection
= &rSectNd
.GetSection();
105 m_nNode
= pPos
->GetNodeIndex();
106 m_nContent
= pPos
->GetContentIndex();
110 m_nNode
= rSectNd
.GetIndex();
115 SetGetExpField::SetGetExpField(::sw::mark::Bookmark
const& rBookmark
,
116 SwPosition
const*const pPos
,
117 sal_uInt16
const nPageNumber
)
118 : m_nPageNumber(nPageNumber
)
120 m_eSetGetExpFieldType
= BOOKMARK
;
121 m_CNTNT
.pBookmark
= &rBookmark
;
125 m_nNode
= pPos
->GetNodeIndex();
126 m_nContent
= pPos
->GetContentIndex();
130 m_nNode
= rBookmark
.GetMarkStart().GetNodeIndex();
131 m_nContent
= rBookmark
.GetMarkStart().GetContentIndex();;
135 SetGetExpField::SetGetExpField( const SwTableBox
& rTBox
)
137 m_eSetGetExpFieldType
= TABLEBOX
;
138 m_CNTNT
.pTBox
= &rTBox
;
140 m_nNode
= SwNodeOffset(0);
142 if( rTBox
.GetSttNd() )
144 SwNodeIndex
aIdx( *rTBox
.GetSttNd() );
145 const SwContentNode
* pNd
= SwNodes::GoNext(&aIdx
);
147 m_nNode
= pNd
->GetIndex();
151 SetGetExpField::SetGetExpField( const SwNode
& rNdIdx
,
152 const SwTextTOXMark
& rTOX
)
154 m_eSetGetExpFieldType
= TEXTTOXMARK
;
155 m_CNTNT
.pTextTOX
= &rTOX
;
156 m_nNode
= rNdIdx
.GetIndex();
157 m_nContent
= rTOX
.GetStart();
160 SetGetExpField::SetGetExpField( const SwPosition
& rPos
)
162 m_eSetGetExpFieldType
= CRSRPOS
;
163 m_CNTNT
.pPos
= &rPos
;
164 m_nNode
= rPos
.GetNodeIndex();
165 m_nContent
= rPos
.GetContentIndex();
168 SetGetExpField::SetGetExpField( const SwFlyFrameFormat
& rFlyFormat
,
169 const SwPosition
* pPos
)
171 m_eSetGetExpFieldType
= FLYFRAME
;
172 m_CNTNT
.pFlyFormat
= &rFlyFormat
;
175 m_nNode
= pPos
->GetNodeIndex();
176 m_nContent
= pPos
->GetContentIndex();
180 const SwFormatContent
& rContent
= rFlyFormat
.GetContent();
181 m_nNode
= rContent
.GetContentIdx()->GetIndex() + 1;
186 void SetGetExpField::GetPosOfContent( SwPosition
& rPos
) const
188 const SwNode
* pNd
= GetNodeFromContent();
190 pNd
= pNd
->GetContentNode();
194 rPos
.Assign( *static_cast<const SwContentNode
*>(pNd
), GetCntPosFromContent() );
198 rPos
.Assign( m_nNode
, m_nContent
);
202 void SetGetExpField::SetBodyPos( const SwContentFrame
& rFrame
)
204 if( !rFrame
.IsInDocBody() )
206 SwNodeIndex
aIdx( rFrame
.IsTextFrame()
207 ? *static_cast<SwTextFrame
const&>(rFrame
).GetTextNodeFirst()
208 : *static_cast<SwNoTextFrame
const&>(rFrame
).GetNode() );
209 SwDoc
& rDoc
= aIdx
.GetNodes().GetDoc();
210 SwPosition
aPos( aIdx
);
211 bool const bResult
= ::GetBodyTextNode( rDoc
, aPos
, rFrame
);
212 OSL_ENSURE(bResult
, "Where is the field?");
213 m_nNode
= aPos
.GetNodeIndex();
214 // tdf#106663 - use the starting position of the frame
219 bool SetGetExpField::operator==( const SetGetExpField
& rField
) const
221 return m_nNode
== rField
.m_nNode
222 && m_nContent
== rField
.m_nContent
223 && ( !m_CNTNT
.pTextField
224 || !rField
.m_CNTNT
.pTextField
225 || m_CNTNT
.pTextField
== rField
.m_CNTNT
.pTextField
);
228 bool SetGetExpField::operator<( const SetGetExpField
& rField
) const
230 if (m_nPageNumber
!= rField
.m_nPageNumber
)
232 // sort "invalid" page nums of 0 after valid page nums of non 0
233 if (m_nPageNumber
== 0 || rField
.m_nPageNumber
== 0)
234 return m_nPageNumber
!= 0;
235 return m_nPageNumber
< rField
.m_nPageNumber
;
237 if( m_nNode
< rField
.m_nNode
|| ( m_nNode
== rField
.m_nNode
&& m_nContent
< rField
.m_nContent
))
239 else if( m_nNode
!= rField
.m_nNode
|| m_nContent
!= rField
.m_nContent
)
242 const SwNode
*pFirst
= GetNodeFromContent(),
243 *pNext
= rField
.GetNodeFromContent();
245 // Position is the same: continue only if both field pointers are set!
246 if( !pFirst
|| !pNext
)
250 if( pFirst
->StartOfSectionNode() != pNext
->StartOfSectionNode() )
252 // is one in the table?
253 const SwNode
*pFirstStt
, *pNextStt
;
254 const SwTableNode
* pTableNd
= pFirst
->FindTableNode();
256 pFirstStt
= pTableNd
->StartOfSectionNode();
258 pFirstStt
= pFirst
->StartOfSectionNode();
260 pTableNd
= pNext
->FindTableNode();
262 pNextStt
= pTableNd
->StartOfSectionNode();
264 pNextStt
= pNext
->StartOfSectionNode();
266 if( pFirstStt
!= pNextStt
)
268 if( pFirst
->IsTextNode() && pNext
->IsTextNode() &&
269 ( pFirst
->FindFlyStartNode() || pNext
->FindFlyStartNode() ))
271 // FIXME: in NewFieldPortion(), SwGetExpField are expanded via
272 // DocumentFieldsManager::FieldsToExpand() calling
273 // std::upper_bound binary search function - the sort order
274 // depends on the fly positions in the layout, but the fly
275 // positions depend on the expansion of the SwGetExpField!
276 // This circular dep will cause trouble, it would be better to
277 // use only model positions (anchor), but then how to compare
278 // at-page anchored flys which don't have a model anchor?
279 return ::IsFrameBehind( *pNext
->GetTextNode(), m_nContent
, *pFirst
->GetTextNode(), m_nContent
);
281 return pFirstStt
->GetIndex() < pNextStt
->GetIndex();
285 // same Section: is the field in the same Node?
286 if( pFirst
!= pNext
)
287 return pFirst
->GetIndex() < pNext
->GetIndex();
289 // same Node in the Section, check Position in the Node
290 return GetCntPosFromContent() < rField
.GetCntPosFromContent();
293 const SwNode
* SetGetExpField::GetNodeFromContent() const
295 const SwNode
* pRet
= nullptr;
296 if( m_CNTNT
.pTextField
)
297 switch( m_eSetGetExpFieldType
)
300 pRet
= &m_CNTNT
.pTextField
->GetTextNode();
304 pRet
= &m_CNTNT
.pTextINet
->GetTextNode();
308 pRet
= m_CNTNT
.pSection
->GetFormat()->GetSectionNode();
312 pRet
= &m_CNTNT
.pBookmark
->GetMarkStart().GetNode();
316 pRet
= &m_CNTNT
.pPos
->GetNode();
320 pRet
= &m_CNTNT
.pTextTOX
->GetTextNode();
324 if( m_CNTNT
.pTBox
->GetSttNd() )
326 SwNodeIndex
aIdx( *m_CNTNT
.pTBox
->GetSttNd() );
327 pRet
= SwNodes::GoNext(&aIdx
);
333 SwNodeIndex
aIdx( *m_CNTNT
.pFlyFormat
->GetContent().GetContentIdx() );
334 pRet
= SwNodes::GoNext(&aIdx
);
341 sal_Int32
SetGetExpField::GetCntPosFromContent() const
344 if( m_CNTNT
.pTextField
)
345 switch( m_eSetGetExpFieldType
)
348 nRet
= m_CNTNT
.pTextField
->GetStart();
351 nRet
= m_CNTNT
.pTextINet
->GetStart();
354 nRet
= m_CNTNT
.pTextTOX
->GetStart();
357 nRet
= m_CNTNT
.pBookmark
->GetMarkStart().GetContentIndex();
360 nRet
= m_CNTNT
.pPos
->GetContentIndex();
368 /// Look up the Name, if it is present, return its String, otherwise return an empty String
369 OUString
LookString( std::unordered_map
<OUString
, OUString
> const & rTable
, const OUString
& rName
)
371 auto it
= rTable
.find( comphelper::string::strip(rName
, ' ') );
372 if( it
!= rTable
.end() )
378 SwDBData
const & SwDoc::GetDBData()
380 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
381 if(maDBData
.sDataSource
.isEmpty())
383 // Similar to: SwEditShell::IsAnyDatabaseFieldInDoc
384 for (const auto& pFieldType
: *getIDocumentFieldsAccess().GetFieldTypes())
386 if (IsUsed(*pFieldType
))
388 SwFieldIds nWhich
= pFieldType
->Which();
391 case SwFieldIds::Database
:
392 case SwFieldIds::DbNextSet
:
393 case SwFieldIds::DbNumSet
:
394 case SwFieldIds::DbSetNumber
:
396 std::vector
<SwFormatField
*> vFields
;
397 pFieldType
->GatherFields(vFields
);
400 if(SwFieldIds::Database
== nWhich
)
401 maDBData
= static_cast<SwDBFieldType
*>(vFields
.front()->GetField()->GetTyp())->GetDBData();
403 maDBData
= static_cast<SwDBNameInfField
*> (vFields
.front()->GetField())->GetRealDBData();
412 if(maDBData
.sDataSource
.isEmpty())
413 maDBData
= SwDBManager::GetAddressDBName();
418 void SwDoc::SetInitDBFields( bool b
)
420 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
423 GetDBManager()->SetInitDBFields( b
);
427 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
429 /// Get all databases that are used by fields
430 static OUString
lcl_DBDataToString(const SwDBData
& rData
)
432 return rData
.sDataSource
+ OUStringChar(DB_DELIM
)
433 + rData
.sCommand
+ OUStringChar(DB_DELIM
)
434 + OUString::number(rData
.nCommandType
);
439 void SwDoc::GetAllUsedDB( std::vector
<OUString
>& rDBNameList
,
440 const std::vector
<OUString
>* pAllDBNames
)
442 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
446 std::vector
<OUString
> aUsedDBNames
;
447 std::vector
<OUString
> aAllDBNames
;
451 GetAllDBNames( aAllDBNames
);
452 pAllDBNames
= &aAllDBNames
;
455 SwSectionFormats
& rArr
= GetSections();
456 for (auto n
= rArr
.size(); n
; )
458 SwSection
* pSect
= rArr
[ --n
]->GetSection();
462 AddUsedDBToList( rDBNameList
, FindUsedDBs( *pAllDBNames
,
463 pSect
->GetCondition(), aUsedDBNames
) );
464 aUsedDBNames
.clear();
468 for (const TypedWhichId
<SwFormatField
> & nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
470 ForEachFormatField(nWhichHint
,
471 [this, &rDBNameList
, &aUsedDBNames
, &pAllDBNames
] (const SwFormatField
& rFormatField
) -> bool
473 const SwField
* pField
= rFormatField
.GetField();
474 switch (pField
->GetTyp()->Which())
476 case SwFieldIds::Database
:
477 AddUsedDBToList( rDBNameList
,
478 lcl_DBDataToString(static_cast<const SwDBField
*>(pField
)->GetDBData() ));
481 case SwFieldIds::DbSetNumber
:
482 case SwFieldIds::DatabaseName
:
483 AddUsedDBToList( rDBNameList
,
484 lcl_DBDataToString(static_cast<const SwDBNameInfField
*>(pField
)->GetRealDBData() ));
487 case SwFieldIds::DbNumSet
:
488 case SwFieldIds::DbNextSet
:
489 AddUsedDBToList( rDBNameList
,
490 lcl_DBDataToString(static_cast<const SwDBNameInfField
*>(pField
)->GetRealDBData() ));
491 [[fallthrough
]]; // JP: is that right like that?
493 case SwFieldIds::HiddenText
:
494 case SwFieldIds::HiddenPara
:
495 AddUsedDBToList(rDBNameList
, FindUsedDBs( *pAllDBNames
,
496 pField
->GetPar1(), aUsedDBNames
));
497 aUsedDBNames
.clear();
500 case SwFieldIds::SetExp
:
501 case SwFieldIds::GetExp
:
502 case SwFieldIds::Table
:
503 AddUsedDBToList(rDBNameList
, FindUsedDBs( *pAllDBNames
,
504 pField
->GetFormula(), aUsedDBNames
));
505 aUsedDBNames
.clear();
515 void SwDoc::GetAllDBNames( std::vector
<OUString
>& rAllDBNames
)
517 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
520 SwDBManager
* pMgr
= GetDBManager();
522 const SwDSParams_t
& rArr
= pMgr
->GetDSParamArray();
523 for (const auto& pParam
: rArr
)
525 rAllDBNames
.emplace_back(pParam
->sDataSource
+ OUStringChar(DB_DELIM
) + pParam
->sCommand
);
530 std::vector
<OUString
>& SwDoc::FindUsedDBs( const std::vector
<OUString
>& rAllDBNames
,
531 const OUString
& rFormula
,
532 std::vector
<OUString
>& rUsedDBNames
)
534 const CharClass
& rCC
= GetAppCharClass();
536 const OUString
sFormula(rCC
.uppercase( rFormula
));
538 const OUString
sFormula(rFormula
);
541 for (const auto &sItem
: rAllDBNames
)
543 sal_Int32 nPos
= sFormula
.indexOf( sItem
);
545 sFormula
[ nPos
+ sItem
.getLength() ] == '.' &&
546 (!nPos
|| !rCC
.isLetterNumeric( sFormula
, nPos
- 1 )))
548 // Look up table name
549 nPos
+= sItem
.getLength() + 1;
550 const sal_Int32 nEndPos
= sFormula
.indexOf('.', nPos
);
553 rUsedDBNames
.emplace_back(sItem
+ OUStringChar(DB_DELIM
) + sFormula
.subView( nPos
, nEndPos
- nPos
));
560 void SwDoc::AddUsedDBToList( std::vector
<OUString
>& rDBNameList
,
561 const std::vector
<OUString
>& rUsedDBNames
)
563 for ( const auto &sName
: rUsedDBNames
)
564 AddUsedDBToList( rDBNameList
, sName
);
567 void SwDoc::AddUsedDBToList( std::vector
<OUString
>& rDBNameList
, const OUString
& rDBName
)
569 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
573 if( rDBName
.isEmpty() )
577 for( const auto &sName
: rDBNameList
)
578 if( rDBName
== o3tl::getToken(sName
, 0, ';') )
581 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
582 for( const auto &sName
: rDBNameList
)
583 if( rSCmp
.isEqual( rDBName
, sName
.getToken(0, ';') ) )
589 aData
.sDataSource
= rDBName
.getToken(0, DB_DELIM
, nIdx
);
590 aData
.sCommand
= rDBName
.getToken(0, DB_DELIM
, nIdx
);
591 aData
.nCommandType
= -1;
592 GetDBManager()->CreateDSData(aData
);
593 rDBNameList
.push_back(rDBName
);
597 void SwDoc::ChangeDBFields( const std::vector
<OUString
>& rOldNames
,
598 const OUString
& rNewName
)
600 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
606 aNewDBData
.sDataSource
= rNewName
.getToken(0, DB_DELIM
, nIdx
);
607 aNewDBData
.sCommand
= rNewName
.getToken(0, DB_DELIM
, nIdx
);
608 aNewDBData
.nCommandType
= o3tl::toInt32(o3tl::getToken(rNewName
, 0, DB_DELIM
, nIdx
));
610 SwSectionFormats
& rArr
= GetSections();
611 for (auto n
= rArr
.size(); n
; )
613 SwSection
* pSect
= rArr
[ --n
]->GetSection();
617 pSect
->SetCondition(ReplaceUsedDBs(rOldNames
, rNewName
, pSect
->GetCondition()));
621 for (const TypedWhichId
<SwFormatField
> & nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
623 ForEachFormatField(nWhichHint
,
624 [this, &rOldNames
, &aNewDBData
, &rNewName
] (const SwFormatField
& rFormatField
) -> bool
626 const SwTextField
* pTextField
= rFormatField
.GetTextField();
628 SwField
* pField(const_cast<SwFormatField
&>(rFormatField
).GetField());
629 bool bExpand
= false;
631 switch( pField
->GetTyp()->Which() )
633 case SwFieldIds::Database
:
634 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
635 if (IsNameInArray(rOldNames
, lcl_DBDataToString(static_cast<SwDBField
*>(pField
)->GetDBData())))
637 SwDBFieldType
* pOldTyp
= static_cast<SwDBFieldType
*>(pField
->GetTyp());
639 SwDBFieldType
* pTyp
= static_cast<SwDBFieldType
*>(getIDocumentFieldsAccess().InsertFieldType(
640 SwDBFieldType(this, pOldTyp
->GetColumnName(), aNewDBData
)));
642 // SwFormatField is non-shareable, so const_cast is somewhat OK
643 const_cast<SwFormatField
&>(rFormatField
).RegisterToFieldType( *pTyp
);
644 pField
->ChgTyp(pTyp
);
646 static_cast<SwDBField
*>(pField
)->ClearInitialized();
647 static_cast<SwDBField
*>(pField
)->InitContent();
654 case SwFieldIds::DbSetNumber
:
655 case SwFieldIds::DatabaseName
:
656 if (IsNameInArray(rOldNames
,
657 lcl_DBDataToString(static_cast<SwDBNameInfField
*>(pField
)->GetRealDBData())))
659 static_cast<SwDBNameInfField
*>(pField
)->SetDBData(aNewDBData
);
664 case SwFieldIds::DbNumSet
:
665 case SwFieldIds::DbNextSet
:
666 if (IsNameInArray(rOldNames
,
667 lcl_DBDataToString(static_cast<SwDBNameInfField
*>(pField
)->GetRealDBData())))
669 static_cast<SwDBNameInfField
*>(pField
)->SetDBData(aNewDBData
);
672 case SwFieldIds::HiddenText
:
673 case SwFieldIds::HiddenPara
:
674 pField
->SetPar1( ReplaceUsedDBs(rOldNames
, rNewName
, pField
->GetPar1()) );
678 case SwFieldIds::SetExp
:
679 case SwFieldIds::GetExp
:
680 case SwFieldIds::Table
:
681 pField
->SetPar2( ReplaceUsedDBs(rOldNames
, rNewName
, pField
->GetFormula()) );
688 pTextField
->ExpandTextField( true );
692 getIDocumentState().SetModified();
699 OUString
lcl_CutOffDBCommandType(const OUString
& rName
)
701 return rName
.replaceFirst(OUStringChar(DB_DELIM
), ".").getToken(0, DB_DELIM
);
706 OUString
SwDoc::ReplaceUsedDBs( const std::vector
<OUString
>& rUsedDBNames
,
707 const OUString
& rNewName
, const OUString
& rFormula
)
709 const CharClass
& rCC
= GetAppCharClass();
710 const OUString
sNewName( lcl_CutOffDBCommandType(rNewName
) );
711 OUString
sFormula(rFormula
);
713 for(const auto & rUsedDBName
: rUsedDBNames
)
715 const OUString
sDBName( lcl_CutOffDBCommandType(rUsedDBName
) );
717 if (sDBName
!=sNewName
)
722 nPos
= sFormula
.indexOf(sDBName
, nPos
);
728 if( sFormula
[nPos
+ sDBName
.getLength()] == '.' &&
729 (!nPos
|| !rCC
.isLetterNumeric( sFormula
, nPos
- 1 )))
731 sFormula
= sFormula
.replaceAt(nPos
, sDBName
.getLength(), sNewName
);
732 //prevent re-searching - this is useless and provokes
733 //endless loops when names containing each other and numbers are exchanged
734 //e.g.: old ?12345.12345 new: i12345.12345
735 nPos
+= sNewName
.getLength();
743 bool SwDoc::IsNameInArray( const std::vector
<OUString
>& rArr
, const OUString
& rName
)
746 for( const auto &sName
: rArr
)
750 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
751 for( const auto &sName
: rArr
)
752 if( rSCmp
.isEqual( rName
, sName
))
758 void SwDoc::ChangeAuthorityData( const SwAuthEntry
* pNewData
)
760 const SwFieldTypes::size_type nSize
= getIDocumentFieldsAccess().GetFieldTypes()->size();
762 for( SwFieldTypes::size_type i
= INIT_FLDTYPES
; i
< nSize
; ++i
)
764 SwFieldType
* pFieldType
= (*getIDocumentFieldsAccess().GetFieldTypes())[i
].get();
765 if( SwFieldIds::TableOfAuthorities
== pFieldType
->Which() )
767 SwAuthorityFieldType
* pAuthType
= static_cast<SwAuthorityFieldType
*>(pFieldType
);
768 pAuthType
->ChangeEntryContent(pNewData
);
775 void SwDocUpdateField::InsDelFieldInFieldLst( bool bIns
, const SwTextField
& rField
)
777 const SwFieldIds nWhich
= rField
.GetFormatField().GetField()->GetTyp()->Which();
780 case SwFieldIds::Database
:
781 case SwFieldIds::SetExp
:
782 case SwFieldIds::HiddenPara
:
783 case SwFieldIds::HiddenText
:
784 case SwFieldIds::DbNumSet
:
785 case SwFieldIds::DbNextSet
:
786 case SwFieldIds::DbSetNumber
:
787 case SwFieldIds::GetExp
:
788 break; // these have to be added/removed!
794 SetFieldsDirty( true );
795 if (!m_pFieldSortList
)
797 if( !bIns
) // if list is present and deleted
798 return; // don't do a thing
799 m_pFieldSortList
.reset(new SetGetExpFields
);
802 if( bIns
) // insert anew:
803 GetBodyNode( rField
, nWhich
);
806 // look up via the pTextField pointer. It is a sorted list, but it's sorted by node
807 // position. Until this is found, the search for the pointer is already done.
808 SetGetExpFields::size_type n
= 0;
809 while (n
< m_pFieldSortList
->size())
811 if (&rField
== (*m_pFieldSortList
)[n
]->GetPointer())
813 m_pFieldSortList
->erase_at(n
);
814 // one field can occur multiple times
824 void SwDocUpdateField::MakeFieldList( SwDoc
& rDoc
, bool bAll
, int eGetMode
)
826 if (!m_pFieldSortList
|| bAll
827 || ((eGetMode
& m_nFieldListGetMode
) != eGetMode
)
828 || rDoc
.GetNodes().Count() != m_nNodes
)
830 MakeFieldList_( rDoc
, eGetMode
);
834 void SwDocUpdateField::MakeFieldList_( SwDoc
& rDoc
, int eGetMode
)
836 // new version: walk all fields of the attribute pool
837 m_pFieldSortList
.reset(new SetGetExpFields
);
839 // remember sections that were unhidden and need to be hidden again
840 std::vector
<std::reference_wrapper
<SwSection
>> aUnhiddenSections
;
842 // consider and unhide sections
843 // with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>)
845 // eGetMode == GETFLD_CALC in call from methods SwDoc::FieldsToCalc
846 // eGetMode == GETFLD_EXPAND in call from method SwDoc::FieldsToExpand
847 // eGetMode == GETFLD_ALL in call from method SwDoc::UpdateExpFields
848 // I figured out that hidden section only have to be shown,
849 // if fields have updated (call by SwDoc::UpdateExpFields) and thus
850 // the hide conditions of section have to be updated.
851 // For correct updating the hide condition of a section, its position
852 // have to be known in order to insert the hide condition as a new
853 // expression field into the sorted field list (<m_pFieldSortList>).
854 if ( eGetMode
== GETFLD_ALL
)
855 // Collect the sections first. Supply sections that are hidden by condition
856 // with frames so that the contained fields are sorted properly.
858 // In order for the frames to be created the right way, they have to be expanded
859 // from top to bottom
860 std::vector
<SwNodeOffset
> aTmpArr
;
861 std::vector
<SwNodeOffset
>::size_type nArrStt
= 0;
862 SwSectionFormats
& rArr
= rDoc
.GetSections();
863 SwSectionNode
* pSectNd
= nullptr;
864 SwNodeOffset nSttContent
= rDoc
.GetNodes().GetEndOfExtras().GetIndex();
866 for (SwSectionFormats::size_type n
= rArr
.size(); n
; )
868 SwSection
* pSect
= rArr
[ --n
]->GetSection();
869 if( !pSect
|| !pSect
->IsHidden() || pSect
->GetCondition().isEmpty() )
871 pSectNd
= pSect
->GetFormat()->GetSectionNode();
874 SwNodeOffset nIdx
= pSectNd
->GetIndex();
875 aTmpArr
.push_back( nIdx
);
876 if( nIdx
< nSttContent
)
880 std::sort(aTmpArr
.begin(), aTmpArr
.end());
882 // Display all first so that we have frames. The BodyAnchor is defined by that.
883 // First the ContentArea, then the special areas!
884 for (std::vector
<sal_uLong
>::size_type n
= nArrStt
; n
< aTmpArr
.size(); ++n
)
886 pSectNd
= rDoc
.GetNodes()[ aTmpArr
[ n
] ]->GetSectionNode();
887 OSL_ENSURE( pSectNd
, "Where is my SectionNode" );
889 auto& rSection
= pSectNd
->GetSection();
890 // unhide and remember the conditionally hidden sections
891 if (rSection
.IsHidden() && !rSection
.GetCondition().isEmpty() && rSection
.IsCondHidden())
893 aUnhiddenSections
.push_back(std::ref(rSection
)); // remember to later hide again
894 rSection
.SetCondHidden(false);
897 for (std::vector
<sal_uLong
>::size_type n
= 0; n
< nArrStt
; ++n
)
899 pSectNd
= rDoc
.GetNodes()[ aTmpArr
[ n
] ]->GetSectionNode();
900 OSL_ENSURE( pSectNd
, "Where is my SectionNode" );
902 auto& rSection
= pSectNd
->GetSection();
903 // unhide and remember the conditionally hidden sections
904 if (rSection
.IsHidden() && !rSection
.GetCondition().isEmpty() && rSection
.IsCondHidden())
906 aUnhiddenSections
.push_back(std::ref(rSection
)); // remember to later hide again
907 rSection
.SetCondHidden(false);
911 // add all to the list so that they are sorted
912 for (const auto &nId
: aTmpArr
)
914 SwSectionNode
const& rSectionNode(*rDoc
.GetNodes()[ nId
]->GetSectionNode());
915 GetBodyNodeGeneric(rSectionNode
, rSectionNode
);
918 // bookmarks with hide conditions, handle similar to sections
919 auto const& rIDMA(*rDoc
.getIDocumentMarkAccess());
920 for (auto it
= rIDMA
.getBookmarksBegin(); it
!= rIDMA
.getBookmarksEnd(); ++it
)
922 ::sw::mark::Bookmark
const* const pBookmark(*it
);
924 if (!pBookmark
->GetHideCondition().isEmpty())
926 GetBodyNodeGeneric((*it
)->GetMarkStart().GetNode(), *pBookmark
);
931 static constexpr OUString
sTrue(u
"TRUE"_ustr
);
932 static constexpr OUString
sFalse(u
"FALSE"_ustr
);
934 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
935 bool bIsDBManager
= nullptr != rDoc
.GetDBManager();
938 for (const TypedWhichId
<SwFormatField
> & nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
940 rDoc
.ForEachFormatField(nWhichHint
,
941 [this, eGetMode
, &rDoc
942 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
945 ] (const SwFormatField
& rFormatField
) -> bool
947 const SwTextField
* pTextField
= rFormatField
.GetTextField();
950 const SwField
* pField
= rFormatField
.GetField();
951 const SwFieldIds nWhich
= pField
->GetTyp()->Which();
954 case SwFieldIds::DbSetNumber
:
955 case SwFieldIds::GetExp
:
956 if (GETFLD_ALL
== eGetMode
)
960 case SwFieldIds::Database
:
961 if (GETFLD_EXPAND
& eGetMode
)
965 case SwFieldIds::SetExp
:
966 if ((eGetMode
!= GETFLD_EXPAND
) ||
967 (nsSwGetSetExpType::GSE_STRING
& pField
->GetSubType()))
973 case SwFieldIds::HiddenPara
:
974 if (GETFLD_ALL
== eGetMode
)
976 sFormula
= pField
->GetPar1();
977 if (sFormula
.isEmpty() || sFormula
==sFalse
)
978 const_cast<SwHiddenParaField
*>(static_cast<const SwHiddenParaField
*>(pField
))->SetHidden( false );
979 else if (sFormula
==sTrue
)
980 const_cast<SwHiddenParaField
*>(static_cast<const SwHiddenParaField
*>(pField
))->SetHidden( true );
985 // trigger formatting
986 const_cast<SwFormatField
&>(rFormatField
).ForceUpdateTextNode();
990 case SwFieldIds::HiddenText
:
991 if (GETFLD_ALL
== eGetMode
)
993 sFormula
= pField
->GetPar1();
994 if (sFormula
.isEmpty() || sFormula
==sFalse
)
995 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->SetValue( true );
996 else if (sFormula
==sTrue
)
997 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->SetValue( false );
1004 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->Evaluate(rDoc
);
1005 // trigger formatting
1006 const_cast<SwFormatField
&>(rFormatField
).ForceUpdateTextNode();
1010 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1011 case SwFieldIds::DbNumSet
:
1013 SwDBData
aDBData(const_cast<SwDBNumSetField
*>(static_cast<const SwDBNumSetField
*>(pField
))->GetDBData(&rDoc
));
1015 if ( (bIsDBManager
&& rDoc
.GetDBManager()->OpenDataSource(aDBData
.sDataSource
, aDBData
.sCommand
))
1016 && (GETFLD_ALL
== eGetMode
1017 || (GETFLD_CALC
& eGetMode
1018 && static_cast<const SwDBNumSetField
*>(pField
)->IsCondValid()))
1021 sFormula
= pField
->GetPar1();
1025 case SwFieldIds::DbNextSet
:
1027 SwDBData
aDBData(const_cast<SwDBNextSetField
*>(static_cast<const SwDBNextSetField
*>(pField
))->GetDBData(&rDoc
));
1029 if ( (bIsDBManager
&& rDoc
.GetDBManager()->OpenDataSource(aDBData
.sDataSource
, aDBData
.sCommand
))
1030 && (GETFLD_ALL
== eGetMode
1031 || (GETFLD_CALC
& eGetMode
1032 && static_cast<const SwDBNextSetField
*>(pField
)->IsCondValid()))
1035 sFormula
= pField
->GetPar1();
1043 if (!sFormula
.isEmpty())
1045 GetBodyNode( *pTextField
, nWhich
);
1050 m_nFieldListGetMode
= eGetMode
;
1051 m_nNodes
= rDoc
.GetNodes().Count();
1053 // return the conditional hidden value back to the previous value
1054 for (auto& rSectionWrapper
: aUnhiddenSections
)
1056 auto& rSection
= rSectionWrapper
.get();
1057 rSection
.SetCondHidden(true);
1061 void SwDocUpdateField::GetBodyNode( const SwTextField
& rTField
, SwFieldIds nFieldWhich
)
1063 const SwTextNode
& rTextNd
= rTField
.GetTextNode();
1064 const SwDoc
& rDoc
= rTextNd
.GetDoc();
1066 // always the first! (in tab headline, header-/footer)
1068 std::pair
<Point
, bool> const tmp(aPt
, false);
1069 // need pos to get the frame on the correct page
1070 SwPosition
const pos(rTextNd
, rTField
.GetStart());
1071 const SwFrame
* pFrame
= rTextNd
.getLayoutFrame(
1072 rDoc
.getIDocumentLayoutAccess().GetCurrentLayout(), &pos
, &tmp
);
1074 std::unique_ptr
<SetGetExpField
> pNew
;
1075 bool bIsInBody
= false;
1077 if( !pFrame
|| pFrame
->IsInDocBody() )
1079 bIsInBody
= rDoc
.GetNodes().GetEndOfExtras().GetIndex() < rTextNd
.GetIndex();
1081 // We don't want to update fields in redlines, or those
1082 // in frames whose anchor is in redline. However, we do want to update
1083 // fields in hidden sections. So: In order to be updated, a field 1)
1084 // must have a frame, or 2) it must be in the document body.
1085 if (pFrame
== nullptr && bIsInBody
)
1086 { // try harder to get a frame for the page number
1087 pFrame
= ::sw::FindNeighbourFrameForNode(rTextNd
);
1088 // possibly there is no layout at all, happens in mail merge
1090 if( (pFrame
!= nullptr) || bIsInBody
)
1092 pNew
.reset(new SetGetExpField(rTextNd
, &rTField
, std::nullopt
,
1093 pFrame
? pFrame
->GetPhyPageNum() : 0));
1098 // create index to determine the TextNode
1099 SwPosition
aPos( rDoc
.GetNodes().GetEndOfPostIts() );
1100 bool const bResult
= GetBodyTextNode( rDoc
, aPos
, *pFrame
);
1101 OSL_ENSURE(bResult
, "where is the Field");
1102 pNew
.reset(new SetGetExpField(aPos
.GetNode(), &rTField
, aPos
.GetContentIndex(),
1103 pFrame
->GetPhyPageNum()));
1106 // always set the BodyTextFlag in GetExp or DB fields
1107 if( SwFieldIds::GetExp
== nFieldWhich
)
1109 SwGetExpField
* pGetField
= const_cast<SwGetExpField
*>(static_cast<const SwGetExpField
*>(rTField
.GetFormatField().GetField()));
1110 pGetField
->ChgBodyTextFlag( bIsInBody
);
1112 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1113 else if( SwFieldIds::Database
== nFieldWhich
)
1115 SwDBField
* pDBField
= const_cast<SwDBField
*>(static_cast<const SwDBField
*>(rTField
.GetFormatField().GetField()));
1116 pDBField
->ChgBodyTextFlag( bIsInBody
);
1119 if( pNew
!= nullptr )
1120 m_pFieldSortList
->insert( std::move(pNew
) );
1123 template<typename T
>
1124 void SwDocUpdateField::GetBodyNodeGeneric(SwNode
const& rNode
, T
const& rCond
)
1126 const SwDoc
& rDoc
= rNode
.GetDoc();
1127 std::unique_ptr
<SetGetExpField
> pNew
;
1129 if (rNode
.GetIndex() < rDoc
.GetNodes().GetEndOfExtras().GetIndex())
1131 do { // middle check loop
1133 // we need to get the anchor first
1134 // create index to determine the TextNode
1135 SwPosition
aPos(rNode
);
1136 SwContentNode
const*const pCNd
= rNode
.IsSectionNode()
1137 ? SwNodes::GoNext(&aPos
.nNode
) // to the next ContentNode
1138 : rNode
.GetContentNode();
1140 if( !pCNd
|| !pCNd
->IsTextNode() )
1143 // always the first! (in tab headline, header-/footer)
1145 std::pair
<Point
, bool> const tmp(aPt
, false);
1146 const SwContentFrame
* pFrame
= pCNd
->getLayoutFrame(
1147 rDoc
.getIDocumentLayoutAccess().GetCurrentLayout(),
1152 bool const bResult
= GetBodyTextNode( rDoc
, aPos
, *pFrame
);
1153 OSL_ENSURE(bResult
, "where is the Field");
1154 pNew
.reset(new SetGetExpField(rCond
, &aPos
, pFrame
->GetPhyPageNum()));
1161 // try harder to get a frame for the page number
1162 SwFrame
const*const pFrame
= ::sw::FindNeighbourFrameForNode(rNode
);
1163 pNew
.reset(new SetGetExpField(rCond
, nullptr, pFrame
? pFrame
->GetPhyPageNum() : 0));
1166 m_pFieldSortList
->insert( std::move(pNew
) );
1169 void SwDocUpdateField::InsertFieldType( const SwFieldType
& rType
)
1171 OUString sFieldName
;
1172 switch( rType
.Which() )
1174 case SwFieldIds::User
:
1175 sFieldName
= static_cast<const SwUserFieldType
&>(rType
).GetName();
1177 case SwFieldIds::SetExp
:
1178 sFieldName
= static_cast<const SwSetExpFieldType
&>(rType
).GetName();
1181 OSL_ENSURE( false, "No valid field type" );
1184 if( sFieldName
.isEmpty() )
1187 SetFieldsDirty( true );
1188 // look up and remove from the hash table
1189 sFieldName
= GetAppCharClass().lowercase( sFieldName
);
1191 auto it
= m_FieldTypeTable
.find( sFieldName
);
1192 if( it
== m_FieldTypeTable
.end() )
1193 m_FieldTypeTable
.insert( { sFieldName
, &rType
} );
1196 void SwDocUpdateField::RemoveFieldType( const SwFieldType
& rType
)
1198 OUString sFieldName
;
1199 switch( rType
.Which() )
1201 case SwFieldIds::User
:
1202 sFieldName
= static_cast<const SwUserFieldType
&>(rType
).GetName();
1204 case SwFieldIds::SetExp
:
1205 sFieldName
= static_cast<const SwSetExpFieldType
&>(rType
).GetName();
1210 if( sFieldName
.isEmpty() )
1213 SetFieldsDirty( true );
1214 // look up and remove from the hash table
1215 sFieldName
= GetAppCharClass().lowercase( sFieldName
);
1217 GetFieldTypeTable().erase( sFieldName
);
1220 SwDocUpdateField::SwDocUpdateField(SwDoc
& rDoc
)
1222 , m_nFieldListGetMode(0)
1224 , m_bInUpdateFields(false)
1225 , m_bFieldsDirty(false)
1229 SwDocUpdateField::~SwDocUpdateField()
1233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */