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 using namespace ::com::sun::star::uno
;
65 // the StartIndex can be supplied optionally (e.g. if it was queried before - is a virtual
67 SetGetExpField::SetGetExpField(
69 const SwTextField
* pField
,
70 std::optional
<sal_Int32
> oContentIdx
,
71 sal_uInt16
const nPageNumber
)
72 : m_nPageNumber(nPageNumber
)
74 m_eSetGetExpFieldType
= TEXTFIELD
;
75 m_CNTNT
.pTextField
= pField
;
76 m_nNode
= rNdIdx
.GetIndex();
78 m_nContent
= *oContentIdx
;
80 m_nContent
= pField
->GetStart();
85 SetGetExpField::SetGetExpField( const SwNode
& rNdIdx
,
86 const SwTextINetFormat
& rINet
)
88 m_eSetGetExpFieldType
= TEXTINET
;
89 m_CNTNT
.pTextINet
= &rINet
;
90 m_nNode
= rNdIdx
.GetIndex();
91 m_nContent
= rINet
.GetStart();
94 // Extension for Sections:
95 // these always have content position 0xffffffff!
96 // There is never a field on this, only up to COMPLETE_STRING possible
97 SetGetExpField::SetGetExpField( const SwSectionNode
& rSectNd
,
98 const SwPosition
* pPos
,
99 sal_uInt16
const nPageNumber
)
100 : m_nPageNumber(nPageNumber
)
102 m_eSetGetExpFieldType
= SECTIONNODE
;
103 m_CNTNT
.pSection
= &rSectNd
.GetSection();
107 m_nNode
= pPos
->GetNodeIndex();
108 m_nContent
= pPos
->GetContentIndex();
112 m_nNode
= rSectNd
.GetIndex();
117 SetGetExpField::SetGetExpField(::sw::mark::IBookmark
const& rBookmark
,
118 SwPosition
const*const pPos
,
119 sal_uInt16
const nPageNumber
)
120 : m_nPageNumber(nPageNumber
)
122 m_eSetGetExpFieldType
= BOOKMARK
;
123 m_CNTNT
.pBookmark
= &rBookmark
;
127 m_nNode
= pPos
->GetNodeIndex();
128 m_nContent
= pPos
->GetContentIndex();
132 m_nNode
= rBookmark
.GetMarkStart().GetNodeIndex();
133 m_nContent
= rBookmark
.GetMarkStart().GetContentIndex();;
137 SetGetExpField::SetGetExpField( const SwTableBox
& rTBox
)
139 m_eSetGetExpFieldType
= TABLEBOX
;
140 m_CNTNT
.pTBox
= &rTBox
;
142 m_nNode
= SwNodeOffset(0);
144 if( rTBox
.GetSttNd() )
146 SwNodeIndex
aIdx( *rTBox
.GetSttNd() );
147 const SwContentNode
* pNd
= aIdx
.GetNode().GetNodes().GoNext( &aIdx
);
149 m_nNode
= pNd
->GetIndex();
153 SetGetExpField::SetGetExpField( const SwNode
& rNdIdx
,
154 const SwTextTOXMark
& rTOX
)
156 m_eSetGetExpFieldType
= TEXTTOXMARK
;
157 m_CNTNT
.pTextTOX
= &rTOX
;
158 m_nNode
= rNdIdx
.GetIndex();
159 m_nContent
= rTOX
.GetStart();
162 SetGetExpField::SetGetExpField( const SwPosition
& rPos
)
164 m_eSetGetExpFieldType
= CRSRPOS
;
165 m_CNTNT
.pPos
= &rPos
;
166 m_nNode
= rPos
.GetNodeIndex();
167 m_nContent
= rPos
.GetContentIndex();
170 SetGetExpField::SetGetExpField( const SwFlyFrameFormat
& rFlyFormat
,
171 const SwPosition
* pPos
)
173 m_eSetGetExpFieldType
= FLYFRAME
;
174 m_CNTNT
.pFlyFormat
= &rFlyFormat
;
177 m_nNode
= pPos
->GetNodeIndex();
178 m_nContent
= pPos
->GetContentIndex();
182 const SwFormatContent
& rContent
= rFlyFormat
.GetContent();
183 m_nNode
= rContent
.GetContentIdx()->GetIndex() + 1;
188 void SetGetExpField::GetPosOfContent( SwPosition
& rPos
) const
190 const SwNode
* pNd
= GetNodeFromContent();
192 pNd
= pNd
->GetContentNode();
196 rPos
.Assign( *static_cast<const SwContentNode
*>(pNd
), GetCntPosFromContent() );
200 rPos
.Assign( m_nNode
, m_nContent
);
204 void SetGetExpField::SetBodyPos( const SwContentFrame
& rFrame
)
206 if( !rFrame
.IsInDocBody() )
208 SwNodeIndex
aIdx( rFrame
.IsTextFrame()
209 ? *static_cast<SwTextFrame
const&>(rFrame
).GetTextNodeFirst()
210 : *static_cast<SwNoTextFrame
const&>(rFrame
).GetNode() );
211 SwDoc
& rDoc
= aIdx
.GetNodes().GetDoc();
212 SwPosition
aPos( aIdx
);
213 bool const bResult
= ::GetBodyTextNode( rDoc
, aPos
, rFrame
);
214 OSL_ENSURE(bResult
, "Where is the field?");
215 m_nNode
= aPos
.GetNodeIndex();
216 m_nContent
= aPos
.GetContentIndex();
220 bool SetGetExpField::operator==( const SetGetExpField
& rField
) const
222 return m_nNode
== rField
.m_nNode
223 && m_nContent
== rField
.m_nContent
224 && ( !m_CNTNT
.pTextField
225 || !rField
.m_CNTNT
.pTextField
226 || m_CNTNT
.pTextField
== rField
.m_CNTNT
.pTextField
);
229 bool SetGetExpField::operator<( const SetGetExpField
& rField
) const
231 if (m_nPageNumber
!= rField
.m_nPageNumber
)
233 // sort "invalid" page nums of 0 after valid page nums of non 0
234 if (m_nPageNumber
== 0 || rField
.m_nPageNumber
== 0)
235 return m_nPageNumber
!= 0;
236 return m_nPageNumber
< rField
.m_nPageNumber
;
238 if( m_nNode
< rField
.m_nNode
|| ( m_nNode
== rField
.m_nNode
&& m_nContent
< rField
.m_nContent
))
240 else if( m_nNode
!= rField
.m_nNode
|| m_nContent
!= rField
.m_nContent
)
243 const SwNode
*pFirst
= GetNodeFromContent(),
244 *pNext
= rField
.GetNodeFromContent();
246 // Position is the same: continue only if both field pointers are set!
247 if( !pFirst
|| !pNext
)
251 if( pFirst
->StartOfSectionNode() != pNext
->StartOfSectionNode() )
253 // is one in the table?
254 const SwNode
*pFirstStt
, *pNextStt
;
255 const SwTableNode
* pTableNd
= pFirst
->FindTableNode();
257 pFirstStt
= pTableNd
->StartOfSectionNode();
259 pFirstStt
= pFirst
->StartOfSectionNode();
261 pTableNd
= pNext
->FindTableNode();
263 pNextStt
= pTableNd
->StartOfSectionNode();
265 pNextStt
= pNext
->StartOfSectionNode();
267 if( pFirstStt
!= pNextStt
)
269 if( pFirst
->IsTextNode() && pNext
->IsTextNode() &&
270 ( pFirst
->FindFlyStartNode() || pNext
->FindFlyStartNode() ))
272 // FIXME: in NewFieldPortion(), SwGetExpField are expanded via
273 // DocumentFieldsManager::FieldsToExpand() calling
274 // std::upper_bound binary search function - the sort order
275 // depends on the fly positions in the layout, but the fly
276 // positions depend on the expansion of the SwGetExpField!
277 // This circular dep will cause trouble, it would be better to
278 // use only model positions (anchor), but then how to compare
279 // at-page anchored flys which don't have a model anchor?
280 return ::IsFrameBehind( *pNext
->GetTextNode(), m_nContent
, *pFirst
->GetTextNode(), m_nContent
);
282 return pFirstStt
->GetIndex() < pNextStt
->GetIndex();
286 // same Section: is the field in the same Node?
287 if( pFirst
!= pNext
)
288 return pFirst
->GetIndex() < pNext
->GetIndex();
290 // same Node in the Section, check Position in the Node
291 return GetCntPosFromContent() < rField
.GetCntPosFromContent();
294 const SwNode
* SetGetExpField::GetNodeFromContent() const
296 const SwNode
* pRet
= nullptr;
297 if( m_CNTNT
.pTextField
)
298 switch( m_eSetGetExpFieldType
)
301 pRet
= &m_CNTNT
.pTextField
->GetTextNode();
305 pRet
= &m_CNTNT
.pTextINet
->GetTextNode();
309 pRet
= m_CNTNT
.pSection
->GetFormat()->GetSectionNode();
313 pRet
= &m_CNTNT
.pBookmark
->GetMarkStart().GetNode();
317 pRet
= &m_CNTNT
.pPos
->GetNode();
321 pRet
= &m_CNTNT
.pTextTOX
->GetTextNode();
325 if( m_CNTNT
.pTBox
->GetSttNd() )
327 SwNodeIndex
aIdx( *m_CNTNT
.pTBox
->GetSttNd() );
328 pRet
= aIdx
.GetNode().GetNodes().GoNext( &aIdx
);
334 SwNodeIndex
aIdx( *m_CNTNT
.pFlyFormat
->GetContent().GetContentIdx() );
335 pRet
= aIdx
.GetNode().GetNodes().GoNext( &aIdx
);
342 sal_Int32
SetGetExpField::GetCntPosFromContent() const
345 if( m_CNTNT
.pTextField
)
346 switch( m_eSetGetExpFieldType
)
349 nRet
= m_CNTNT
.pTextField
->GetStart();
352 nRet
= m_CNTNT
.pTextINet
->GetStart();
355 nRet
= m_CNTNT
.pTextTOX
->GetStart();
358 nRet
= m_CNTNT
.pBookmark
->GetMarkStart().GetContentIndex();
361 nRet
= m_CNTNT
.pPos
->GetContentIndex();
369 HashStr::HashStr( const OUString
& rName
, OUString aText
,
371 : SwHash( rName
), aSetStr(std::move( aText
))
376 /// Look up the Name, if it is present, return its String, otherwise return an empty String
377 OUString
LookString( SwHashTable
<HashStr
> const & rTable
, const OUString
& rName
)
379 HashStr
* pFnd
= rTable
.Find( comphelper::string::strip(rName
, ' ') );
381 return pFnd
->aSetStr
;
386 SwDBData
const & SwDoc::GetDBData()
388 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
389 if(maDBData
.sDataSource
.isEmpty())
391 // Similar to: SwEditShell::IsAnyDatabaseFieldInDoc
392 for (const auto& pFieldType
: *getIDocumentFieldsAccess().GetFieldTypes())
394 if (IsUsed(*pFieldType
))
396 SwFieldIds nWhich
= pFieldType
->Which();
399 case SwFieldIds::Database
:
400 case SwFieldIds::DbNextSet
:
401 case SwFieldIds::DbNumSet
:
402 case SwFieldIds::DbSetNumber
:
404 std::vector
<SwFormatField
*> vFields
;
405 pFieldType
->GatherFields(vFields
);
408 if(SwFieldIds::Database
== nWhich
)
409 maDBData
= static_cast<SwDBFieldType
*>(vFields
.front()->GetField()->GetTyp())->GetDBData();
411 maDBData
= static_cast<SwDBNameInfField
*> (vFields
.front()->GetField())->GetRealDBData();
420 if(maDBData
.sDataSource
.isEmpty())
421 maDBData
= SwDBManager::GetAddressDBName();
426 void SwDoc::SetInitDBFields( bool b
)
428 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
431 GetDBManager()->SetInitDBFields( b
);
435 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
437 /// Get all databases that are used by fields
438 static OUString
lcl_DBDataToString(const SwDBData
& rData
)
440 return rData
.sDataSource
+ OUStringChar(DB_DELIM
)
441 + rData
.sCommand
+ OUStringChar(DB_DELIM
)
442 + OUString::number(rData
.nCommandType
);
447 void SwDoc::GetAllUsedDB( std::vector
<OUString
>& rDBNameList
,
448 const std::vector
<OUString
>* pAllDBNames
)
450 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
454 std::vector
<OUString
> aUsedDBNames
;
455 std::vector
<OUString
> aAllDBNames
;
459 GetAllDBNames( aAllDBNames
);
460 pAllDBNames
= &aAllDBNames
;
463 SwSectionFormats
& rArr
= GetSections();
464 for (auto n
= rArr
.size(); n
; )
466 SwSection
* pSect
= rArr
[ --n
]->GetSection();
470 AddUsedDBToList( rDBNameList
, FindUsedDBs( *pAllDBNames
,
471 pSect
->GetCondition(), aUsedDBNames
) );
472 aUsedDBNames
.clear();
476 for (sal_uInt16
const nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
478 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(nWhichHint
))
480 const SwFormatField
* pFormatField
= static_cast<const SwFormatField
*>(pItem
);
481 const SwTextField
* pTextField
= pFormatField
->GetTextField();
482 if (!pTextField
|| !pTextField
->GetTextNode().GetNodes().IsDocNodes())
485 const SwField
* pField
= pFormatField
->GetField();
486 switch (pField
->GetTyp()->Which())
488 case SwFieldIds::Database
:
489 AddUsedDBToList( rDBNameList
,
490 lcl_DBDataToString(static_cast<const SwDBField
*>(pField
)->GetDBData() ));
493 case SwFieldIds::DbSetNumber
:
494 case SwFieldIds::DatabaseName
:
495 AddUsedDBToList( rDBNameList
,
496 lcl_DBDataToString(static_cast<const SwDBNameInfField
*>(pField
)->GetRealDBData() ));
499 case SwFieldIds::DbNumSet
:
500 case SwFieldIds::DbNextSet
:
501 AddUsedDBToList( rDBNameList
,
502 lcl_DBDataToString(static_cast<const SwDBNameInfField
*>(pField
)->GetRealDBData() ));
503 [[fallthrough
]]; // JP: is that right like that?
505 case SwFieldIds::HiddenText
:
506 case SwFieldIds::HiddenPara
:
507 AddUsedDBToList(rDBNameList
, FindUsedDBs( *pAllDBNames
,
508 pField
->GetPar1(), aUsedDBNames
));
509 aUsedDBNames
.clear();
512 case SwFieldIds::SetExp
:
513 case SwFieldIds::GetExp
:
514 case SwFieldIds::Table
:
515 AddUsedDBToList(rDBNameList
, FindUsedDBs( *pAllDBNames
,
516 pField
->GetFormula(), aUsedDBNames
));
517 aUsedDBNames
.clear();
526 void SwDoc::GetAllDBNames( std::vector
<OUString
>& rAllDBNames
)
528 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
531 SwDBManager
* pMgr
= GetDBManager();
533 const SwDSParams_t
& rArr
= pMgr
->GetDSParamArray();
534 for (const auto& pParam
: rArr
)
536 rAllDBNames
.emplace_back(pParam
->sDataSource
+ OUStringChar(DB_DELIM
) + pParam
->sCommand
);
541 std::vector
<OUString
>& SwDoc::FindUsedDBs( const std::vector
<OUString
>& rAllDBNames
,
542 const OUString
& rFormula
,
543 std::vector
<OUString
>& rUsedDBNames
)
545 const CharClass
& rCC
= GetAppCharClass();
547 const OUString
sFormula(rCC
.uppercase( rFormula
));
549 const OUString
sFormula(rFormula
);
552 for (const auto &sItem
: rAllDBNames
)
554 sal_Int32 nPos
= sFormula
.indexOf( sItem
);
556 sFormula
[ nPos
+ sItem
.getLength() ] == '.' &&
557 (!nPos
|| !rCC
.isLetterNumeric( sFormula
, nPos
- 1 )))
559 // Look up table name
560 nPos
+= sItem
.getLength() + 1;
561 const sal_Int32 nEndPos
= sFormula
.indexOf('.', nPos
);
564 rUsedDBNames
.emplace_back(sItem
+ OUStringChar(DB_DELIM
) + sFormula
.subView( nPos
, nEndPos
- nPos
));
571 void SwDoc::AddUsedDBToList( std::vector
<OUString
>& rDBNameList
,
572 const std::vector
<OUString
>& rUsedDBNames
)
574 for ( const auto &sName
: rUsedDBNames
)
575 AddUsedDBToList( rDBNameList
, sName
);
578 void SwDoc::AddUsedDBToList( std::vector
<OUString
>& rDBNameList
, const OUString
& rDBName
)
580 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
584 if( rDBName
.isEmpty() )
588 for( const auto &sName
: rDBNameList
)
589 if( rDBName
== o3tl::getToken(sName
, 0, ';') )
592 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
593 for( const auto &sName
: rDBNameList
)
594 if( rSCmp
.isEqual( rDBName
, sName
.getToken(0, ';') ) )
600 aData
.sDataSource
= rDBName
.getToken(0, DB_DELIM
, nIdx
);
601 aData
.sCommand
= rDBName
.getToken(0, DB_DELIM
, nIdx
);
602 aData
.nCommandType
= -1;
603 GetDBManager()->CreateDSData(aData
);
604 rDBNameList
.push_back(rDBName
);
608 void SwDoc::ChangeDBFields( const std::vector
<OUString
>& rOldNames
,
609 const OUString
& rNewName
)
611 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
617 aNewDBData
.sDataSource
= rNewName
.getToken(0, DB_DELIM
, nIdx
);
618 aNewDBData
.sCommand
= rNewName
.getToken(0, DB_DELIM
, nIdx
);
619 aNewDBData
.nCommandType
= o3tl::toInt32(o3tl::getToken(rNewName
, 0, DB_DELIM
, nIdx
));
621 SwSectionFormats
& rArr
= GetSections();
622 for (auto n
= rArr
.size(); n
; )
624 SwSection
* pSect
= rArr
[ --n
]->GetSection();
628 pSect
->SetCondition(ReplaceUsedDBs(rOldNames
, rNewName
, pSect
->GetCondition()));
632 for (sal_uInt16
const nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
634 for (const SfxPoolItem
* pItem
: GetAttrPool().GetItemSurrogates(nWhichHint
))
636 SwFormatField
* pFormatField
= const_cast<SwFormatField
*>(static_cast<const SwFormatField
*>(pItem
));
637 SwTextField
* pTextField
= pFormatField
->GetTextField();
638 if (!pTextField
|| !pTextField
->GetTextNode().GetNodes().IsDocNodes())
641 SwField
* pField
= pFormatField
->GetField();
642 bool bExpand
= false;
644 switch( pField
->GetTyp()->Which() )
646 case SwFieldIds::Database
:
647 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
648 if (IsNameInArray(rOldNames
, lcl_DBDataToString(static_cast<SwDBField
*>(pField
)->GetDBData())))
650 SwDBFieldType
* pOldTyp
= static_cast<SwDBFieldType
*>(pField
->GetTyp());
652 SwDBFieldType
* pTyp
= static_cast<SwDBFieldType
*>(getIDocumentFieldsAccess().InsertFieldType(
653 SwDBFieldType(this, pOldTyp
->GetColumnName(), aNewDBData
)));
655 pFormatField
->RegisterToFieldType( *pTyp
);
656 pField
->ChgTyp(pTyp
);
658 static_cast<SwDBField
*>(pField
)->ClearInitialized();
659 static_cast<SwDBField
*>(pField
)->InitContent();
666 case SwFieldIds::DbSetNumber
:
667 case SwFieldIds::DatabaseName
:
668 if (IsNameInArray(rOldNames
,
669 lcl_DBDataToString(static_cast<SwDBNameInfField
*>(pField
)->GetRealDBData())))
671 static_cast<SwDBNameInfField
*>(pField
)->SetDBData(aNewDBData
);
676 case SwFieldIds::DbNumSet
:
677 case SwFieldIds::DbNextSet
:
678 if (IsNameInArray(rOldNames
,
679 lcl_DBDataToString(static_cast<SwDBNameInfField
*>(pField
)->GetRealDBData())))
681 static_cast<SwDBNameInfField
*>(pField
)->SetDBData(aNewDBData
);
684 case SwFieldIds::HiddenText
:
685 case SwFieldIds::HiddenPara
:
686 pField
->SetPar1( ReplaceUsedDBs(rOldNames
, rNewName
, pField
->GetPar1()) );
690 case SwFieldIds::SetExp
:
691 case SwFieldIds::GetExp
:
692 case SwFieldIds::Table
:
693 pField
->SetPar2( ReplaceUsedDBs(rOldNames
, rNewName
, pField
->GetFormula()) );
700 pTextField
->ExpandTextField( true );
703 getIDocumentState().SetModified();
710 OUString
lcl_CutOffDBCommandType(const OUString
& rName
)
712 return rName
.replaceFirst(OUStringChar(DB_DELIM
), ".").getToken(0, DB_DELIM
);
717 OUString
SwDoc::ReplaceUsedDBs( const std::vector
<OUString
>& rUsedDBNames
,
718 const OUString
& rNewName
, const OUString
& rFormula
)
720 const CharClass
& rCC
= GetAppCharClass();
721 const OUString
sNewName( lcl_CutOffDBCommandType(rNewName
) );
722 OUString
sFormula(rFormula
);
724 for(const auto & rUsedDBName
: rUsedDBNames
)
726 const OUString
sDBName( lcl_CutOffDBCommandType(rUsedDBName
) );
728 if (sDBName
!=sNewName
)
733 nPos
= sFormula
.indexOf(sDBName
, nPos
);
739 if( sFormula
[nPos
+ sDBName
.getLength()] == '.' &&
740 (!nPos
|| !rCC
.isLetterNumeric( sFormula
, nPos
- 1 )))
742 sFormula
= sFormula
.replaceAt(nPos
, sDBName
.getLength(), sNewName
);
743 //prevent re-searching - this is useless and provokes
744 //endless loops when names containing each other and numbers are exchanged
745 //e.g.: old ?12345.12345 new: i12345.12345
746 nPos
+= sNewName
.getLength();
754 bool SwDoc::IsNameInArray( const std::vector
<OUString
>& rArr
, const OUString
& rName
)
757 for( const auto &sName
: rArr
)
761 const ::utl::TransliterationWrapper
& rSCmp
= GetAppCmpStrIgnore();
762 for( const auto &sName
: rArr
)
763 if( rSCmp
.isEqual( rName
, sName
))
769 void SwDoc::ChangeAuthorityData( const SwAuthEntry
* pNewData
)
771 const SwFieldTypes::size_type nSize
= getIDocumentFieldsAccess().GetFieldTypes()->size();
773 for( SwFieldTypes::size_type i
= INIT_FLDTYPES
; i
< nSize
; ++i
)
775 SwFieldType
* pFieldType
= (*getIDocumentFieldsAccess().GetFieldTypes())[i
].get();
776 if( SwFieldIds::TableOfAuthorities
== pFieldType
->Which() )
778 SwAuthorityFieldType
* pAuthType
= static_cast<SwAuthorityFieldType
*>(pFieldType
);
779 pAuthType
->ChangeEntryContent(pNewData
);
786 void SwDocUpdateField::InsDelFieldInFieldLst( bool bIns
, const SwTextField
& rField
)
788 const SwFieldIds nWhich
= rField
.GetFormatField().GetField()->GetTyp()->Which();
791 case SwFieldIds::Database
:
792 case SwFieldIds::SetExp
:
793 case SwFieldIds::HiddenPara
:
794 case SwFieldIds::HiddenText
:
795 case SwFieldIds::DbNumSet
:
796 case SwFieldIds::DbNextSet
:
797 case SwFieldIds::DbSetNumber
:
798 case SwFieldIds::GetExp
:
799 break; // these have to be added/removed!
805 SetFieldsDirty( true );
806 if (!m_pFieldSortList
)
808 if( !bIns
) // if list is present and deleted
809 return; // don't do a thing
810 m_pFieldSortList
.reset(new SetGetExpFields
);
813 if( bIns
) // insert anew:
814 GetBodyNode( rField
, nWhich
);
817 // look up via the pTextField pointer. It is a sorted list, but it's sorted by node
818 // position. Until this is found, the search for the pointer is already done.
819 for (SetGetExpFields::size_type n
= 0; n
< m_pFieldSortList
->size(); ++n
)
821 if (&rField
== (*m_pFieldSortList
)[n
]->GetPointer())
823 m_pFieldSortList
->erase_at(n
);
824 n
--; // one field can occur multiple times
830 void SwDocUpdateField::MakeFieldList( SwDoc
& rDoc
, bool bAll
, int eGetMode
)
832 if (!m_pFieldSortList
|| bAll
833 || ((eGetMode
& m_nFieldListGetMode
) != eGetMode
)
834 || rDoc
.GetNodes().Count() != m_nNodes
)
836 MakeFieldList_( rDoc
, eGetMode
);
840 void SwDocUpdateField::MakeFieldList_( SwDoc
& rDoc
, int eGetMode
)
842 // new version: walk all fields of the attribute pool
843 m_pFieldSortList
.reset(new SetGetExpFields
);
845 // remember sections that were unhidden and need to be hidden again
846 std::vector
<std::reference_wrapper
<SwSection
>> aUnhiddenSections
;
848 // consider and unhide sections
849 // with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>)
851 // eGetMode == GETFLD_CALC in call from methods SwDoc::FieldsToCalc
852 // eGetMode == GETFLD_EXPAND in call from method SwDoc::FieldsToExpand
853 // eGetMode == GETFLD_ALL in call from method SwDoc::UpdateExpFields
854 // I figured out that hidden section only have to be shown,
855 // if fields have updated (call by SwDoc::UpdateExpFields) and thus
856 // the hide conditions of section have to be updated.
857 // For correct updating the hide condition of a section, its position
858 // have to be known in order to insert the hide condition as a new
859 // expression field into the sorted field list (<m_pFieldSortList>).
860 if ( eGetMode
== GETFLD_ALL
)
861 // Collect the sections first. Supply sections that are hidden by condition
862 // with frames so that the contained fields are sorted properly.
864 // In order for the frames to be created the right way, they have to be expanded
865 // from top to bottom
866 std::vector
<SwNodeOffset
> aTmpArr
;
867 std::vector
<SwNodeOffset
>::size_type nArrStt
= 0;
868 SwSectionFormats
& rArr
= rDoc
.GetSections();
869 SwSectionNode
* pSectNd
= nullptr;
870 SwNodeOffset nSttContent
= rDoc
.GetNodes().GetEndOfExtras().GetIndex();
872 for (SwSectionFormats::size_type n
= rArr
.size(); n
; )
874 SwSection
* pSect
= rArr
[ --n
]->GetSection();
875 if( !pSect
|| !pSect
->IsHidden() || pSect
->GetCondition().isEmpty() )
877 pSectNd
= pSect
->GetFormat()->GetSectionNode();
880 SwNodeOffset nIdx
= pSectNd
->GetIndex();
881 aTmpArr
.push_back( nIdx
);
882 if( nIdx
< nSttContent
)
886 std::sort(aTmpArr
.begin(), aTmpArr
.end());
888 // Display all first so that we have frames. The BodyAnchor is defined by that.
889 // First the ContentArea, then the special areas!
890 for (std::vector
<sal_uLong
>::size_type n
= nArrStt
; n
< aTmpArr
.size(); ++n
)
892 pSectNd
= rDoc
.GetNodes()[ aTmpArr
[ n
] ]->GetSectionNode();
893 OSL_ENSURE( pSectNd
, "Where is my SectionNode" );
895 auto& rSection
= pSectNd
->GetSection();
896 // unhide and remember the conditionally hidden sections
897 if (rSection
.IsHidden() && !rSection
.GetCondition().isEmpty() && rSection
.IsCondHidden())
899 aUnhiddenSections
.push_back(std::ref(rSection
)); // remember to later hide again
900 rSection
.SetCondHidden(false);
903 for (std::vector
<sal_uLong
>::size_type n
= 0; n
< nArrStt
; ++n
)
905 pSectNd
= rDoc
.GetNodes()[ aTmpArr
[ n
] ]->GetSectionNode();
906 OSL_ENSURE( pSectNd
, "Where is my SectionNode" );
908 auto& rSection
= pSectNd
->GetSection();
909 // unhide and remember the conditionally hidden sections
910 if (rSection
.IsHidden() && !rSection
.GetCondition().isEmpty() && rSection
.IsCondHidden())
912 aUnhiddenSections
.push_back(std::ref(rSection
)); // remember to later hide again
913 rSection
.SetCondHidden(false);
917 // add all to the list so that they are sorted
918 for (const auto &nId
: aTmpArr
)
920 SwSectionNode
const& rSectionNode(*rDoc
.GetNodes()[ nId
]->GetSectionNode());
921 GetBodyNodeGeneric(rSectionNode
, rSectionNode
);
924 // bookmarks with hide conditions, handle similar to sections
925 auto const& rIDMA(*rDoc
.getIDocumentMarkAccess());
926 for (auto it
= rIDMA
.getBookmarksBegin(); it
!= rIDMA
.getBookmarksEnd(); ++it
)
928 auto const pBookmark(dynamic_cast<::sw::mark::IBookmark
const*>(*it
));
930 if (!pBookmark
->GetHideCondition().isEmpty())
932 GetBodyNodeGeneric((*it
)->GetMarkStart().GetNode(), *pBookmark
);
937 static const OUStringLiteral
sTrue(u
"TRUE");
938 static const OUStringLiteral
sFalse(u
"FALSE");
940 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
941 bool bIsDBManager
= nullptr != rDoc
.GetDBManager();
944 for (sal_uInt16
const nWhichHint
: { RES_TXTATR_FIELD
, RES_TXTATR_INPUTFIELD
})
946 for (const SfxPoolItem
* pItem
: rDoc
.GetAttrPool().GetItemSurrogates(nWhichHint
))
948 const SwFormatField
* pFormatField
= static_cast<const SwFormatField
*>(pItem
);
949 const SwTextField
* pTextField
= pFormatField
->GetTextField();
950 if (!pTextField
|| !pTextField
->GetTextNode().GetNodes().IsDocNodes())
954 const SwField
* pField
= pFormatField
->GetField();
955 const SwFieldIds nWhich
= pField
->GetTyp()->Which();
958 case SwFieldIds::DbSetNumber
:
959 case SwFieldIds::GetExp
:
960 if (GETFLD_ALL
== eGetMode
)
964 case SwFieldIds::Database
:
965 if (GETFLD_EXPAND
& eGetMode
)
969 case SwFieldIds::SetExp
:
970 if ((eGetMode
!= GETFLD_EXPAND
) ||
971 (nsSwGetSetExpType::GSE_STRING
& pField
->GetSubType()))
977 case SwFieldIds::HiddenPara
:
978 if (GETFLD_ALL
== eGetMode
)
980 sFormula
= pField
->GetPar1();
981 if (sFormula
.isEmpty() || sFormula
==sFalse
)
982 const_cast<SwHiddenParaField
*>(static_cast<const SwHiddenParaField
*>(pField
))->SetHidden( false );
983 else if (sFormula
==sTrue
)
984 const_cast<SwHiddenParaField
*>(static_cast<const SwHiddenParaField
*>(pField
))->SetHidden( true );
989 // trigger formatting
990 const_cast<SwFormatField
*>(pFormatField
)->ForceUpdateTextNode();
994 case SwFieldIds::HiddenText
:
995 if (GETFLD_ALL
== eGetMode
)
997 sFormula
= pField
->GetPar1();
998 if (sFormula
.isEmpty() || sFormula
==sFalse
)
999 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->SetValue( true );
1000 else if (sFormula
==sTrue
)
1001 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->SetValue( false );
1008 const_cast<SwHiddenTextField
*>(static_cast<const SwHiddenTextField
*>(pField
))->Evaluate(rDoc
);
1009 // trigger formatting
1010 const_cast<SwFormatField
*>(pFormatField
)->ForceUpdateTextNode();
1014 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1015 case SwFieldIds::DbNumSet
:
1017 SwDBData
aDBData(const_cast<SwDBNumSetField
*>(static_cast<const SwDBNumSetField
*>(pField
))->GetDBData(&rDoc
));
1019 if ( (bIsDBManager
&& rDoc
.GetDBManager()->OpenDataSource(aDBData
.sDataSource
, aDBData
.sCommand
))
1020 && (GETFLD_ALL
== eGetMode
1021 || (GETFLD_CALC
& eGetMode
1022 && static_cast<const SwDBNumSetField
*>(pField
)->IsCondValid()))
1025 sFormula
= pField
->GetPar1();
1029 case SwFieldIds::DbNextSet
:
1031 SwDBData
aDBData(const_cast<SwDBNextSetField
*>(static_cast<const SwDBNextSetField
*>(pField
))->GetDBData(&rDoc
));
1033 if ( (bIsDBManager
&& rDoc
.GetDBManager()->OpenDataSource(aDBData
.sDataSource
, aDBData
.sCommand
))
1034 && (GETFLD_ALL
== eGetMode
1035 || (GETFLD_CALC
& eGetMode
1036 && static_cast<const SwDBNextSetField
*>(pField
)->IsCondValid()))
1039 sFormula
= pField
->GetPar1();
1047 if (!sFormula
.isEmpty())
1049 GetBodyNode( *pTextField
, nWhich
);
1053 m_nFieldListGetMode
= eGetMode
;
1054 m_nNodes
= rDoc
.GetNodes().Count();
1056 // return the conditional hidden value back to the previous value
1057 for (auto& rSectionWrapper
: aUnhiddenSections
)
1059 auto& rSection
= rSectionWrapper
.get();
1060 rSection
.SetCondHidden(true);
1064 void SwDocUpdateField::GetBodyNode( const SwTextField
& rTField
, SwFieldIds nFieldWhich
)
1066 const SwTextNode
& rTextNd
= rTField
.GetTextNode();
1067 const SwDoc
& rDoc
= rTextNd
.GetDoc();
1069 // always the first! (in tab headline, header-/footer)
1071 std::pair
<Point
, bool> const tmp(aPt
, false);
1072 // need pos to get the frame on the correct page
1073 SwPosition
const pos(rTextNd
, rTField
.GetStart());
1074 const SwFrame
* pFrame
= rTextNd
.getLayoutFrame(
1075 rDoc
.getIDocumentLayoutAccess().GetCurrentLayout(), &pos
, &tmp
);
1077 std::unique_ptr
<SetGetExpField
> pNew
;
1078 bool bIsInBody
= false;
1080 if( !pFrame
|| pFrame
->IsInDocBody() )
1082 bIsInBody
= rDoc
.GetNodes().GetEndOfExtras().GetIndex() < rTextNd
.GetIndex();
1084 // We don't want to update fields in redlines, or those
1085 // in frames whose anchor is in redline. However, we do want to update
1086 // fields in hidden sections. So: In order to be updated, a field 1)
1087 // must have a frame, or 2) it must be in the document body.
1088 if (pFrame
== nullptr && bIsInBody
)
1089 { // try harder to get a frame for the page number
1090 pFrame
= ::sw::FindNeighbourFrameForNode(rTextNd
);
1091 // possibly there is no layout at all, happens in mail merge
1093 if( (pFrame
!= nullptr) || bIsInBody
)
1095 pNew
.reset(new SetGetExpField(rTextNd
, &rTField
, std::nullopt
,
1096 pFrame
? pFrame
->GetPhyPageNum() : 0));
1101 // create index to determine the TextNode
1102 SwPosition
aPos( rDoc
.GetNodes().GetEndOfPostIts() );
1103 bool const bResult
= GetBodyTextNode( rDoc
, aPos
, *pFrame
);
1104 OSL_ENSURE(bResult
, "where is the Field");
1105 pNew
.reset(new SetGetExpField(aPos
.GetNode(), &rTField
, aPos
.GetContentIndex(),
1106 pFrame
->GetPhyPageNum()));
1109 // always set the BodyTextFlag in GetExp or DB fields
1110 if( SwFieldIds::GetExp
== nFieldWhich
)
1112 SwGetExpField
* pGetField
= const_cast<SwGetExpField
*>(static_cast<const SwGetExpField
*>(rTField
.GetFormatField().GetField()));
1113 pGetField
->ChgBodyTextFlag( bIsInBody
);
1115 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1116 else if( SwFieldIds::Database
== nFieldWhich
)
1118 SwDBField
* pDBField
= const_cast<SwDBField
*>(static_cast<const SwDBField
*>(rTField
.GetFormatField().GetField()));
1119 pDBField
->ChgBodyTextFlag( bIsInBody
);
1122 if( pNew
!= nullptr )
1123 m_pFieldSortList
->insert( std::move(pNew
) );
1126 template<typename T
>
1127 void SwDocUpdateField::GetBodyNodeGeneric(SwNode
const& rNode
, T
const& rCond
)
1129 const SwDoc
& rDoc
= rNode
.GetDoc();
1130 std::unique_ptr
<SetGetExpField
> pNew
;
1132 if (rNode
.GetIndex() < rDoc
.GetNodes().GetEndOfExtras().GetIndex())
1134 do { // middle check loop
1136 // we need to get the anchor first
1137 // create index to determine the TextNode
1138 SwPosition
aPos(rNode
);
1139 SwContentNode
const*const pCNd
= rNode
.IsSectionNode()
1140 ? rDoc
.GetNodes().GoNext(&aPos
.nNode
) // to the next ContentNode
1141 : rNode
.GetContentNode();
1143 if( !pCNd
|| !pCNd
->IsTextNode() )
1146 // always the first! (in tab headline, header-/footer)
1148 std::pair
<Point
, bool> const tmp(aPt
, false);
1149 const SwContentFrame
* pFrame
= pCNd
->getLayoutFrame(
1150 rDoc
.getIDocumentLayoutAccess().GetCurrentLayout(),
1155 bool const bResult
= GetBodyTextNode( rDoc
, aPos
, *pFrame
);
1156 OSL_ENSURE(bResult
, "where is the Field");
1157 pNew
.reset(new SetGetExpField(rCond
, &aPos
, pFrame
->GetPhyPageNum()));
1164 // try harder to get a frame for the page number
1165 SwFrame
const*const pFrame
= ::sw::FindNeighbourFrameForNode(rNode
);
1166 pNew
.reset(new SetGetExpField(rCond
, nullptr, pFrame
? pFrame
->GetPhyPageNum() : 0));
1169 m_pFieldSortList
->insert( std::move(pNew
) );
1172 void SwDocUpdateField::InsertFieldType( const SwFieldType
& rType
)
1174 OUString sFieldName
;
1175 switch( rType
.Which() )
1177 case SwFieldIds::User
:
1178 sFieldName
= static_cast<const SwUserFieldType
&>(rType
).GetName();
1180 case SwFieldIds::SetExp
:
1181 sFieldName
= static_cast<const SwSetExpFieldType
&>(rType
).GetName();
1184 OSL_ENSURE( false, "No valid field type" );
1187 if( sFieldName
.isEmpty() )
1190 SetFieldsDirty( true );
1191 // look up and remove from the hash table
1192 sFieldName
= GetAppCharClass().lowercase( sFieldName
);
1195 SwCalcFieldType
* pFnd
= GetFieldTypeTable().Find( sFieldName
, &n
);
1199 SwCalcFieldType
* pNew
= new SwCalcFieldType( sFieldName
, &rType
);
1200 pNew
->pNext
.reset( m_FieldTypeTable
[n
].release() );
1201 m_FieldTypeTable
[n
].reset(pNew
);
1205 void SwDocUpdateField::RemoveFieldType( const SwFieldType
& rType
)
1207 OUString sFieldName
;
1208 switch( rType
.Which() )
1210 case SwFieldIds::User
:
1211 sFieldName
= static_cast<const SwUserFieldType
&>(rType
).GetName();
1213 case SwFieldIds::SetExp
:
1214 sFieldName
= static_cast<const SwSetExpFieldType
&>(rType
).GetName();
1219 if( sFieldName
.isEmpty() )
1222 SetFieldsDirty( true );
1223 // look up and remove from the hash table
1224 sFieldName
= GetAppCharClass().lowercase( sFieldName
);
1227 SwCalcFieldType
* pFnd
= GetFieldTypeTable().Find( sFieldName
, &n
);
1231 if (m_FieldTypeTable
[n
].get() == pFnd
)
1233 m_FieldTypeTable
[n
].reset(static_cast<SwCalcFieldType
*>(pFnd
->pNext
.release()));
1237 SwHash
* pPrev
= m_FieldTypeTable
[n
].get();
1238 while( pPrev
->pNext
.get() != pFnd
)
1239 pPrev
= pPrev
->pNext
.get();
1240 pPrev
->pNext
= std::move(pFnd
->pNext
);
1241 // no need to explicitly delete here, the embedded linked list uses unique_ptr
1245 SwDocUpdateField::SwDocUpdateField(SwDoc
& rDoc
)
1246 : m_FieldTypeTable(TBLSZ
)
1248 , m_nFieldListGetMode(0)
1250 , m_bInUpdateFields(false)
1251 , m_bFieldsDirty(false)
1255 SwDocUpdateField::~SwDocUpdateField()
1259 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */