summaryrefslogtreecommitdiffstats
path: root/sw/source/core/doc/docfld.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/doc/docfld.cxx')
-rw-r--r--sw/source/core/doc/docfld.cxx1259
1 files changed, 1259 insertions, 0 deletions
diff --git a/sw/source/core/doc/docfld.cxx b/sw/source/core/doc/docfld.cxx
new file mode 100644
index 000000000..d0e489b7b
--- /dev/null
+++ b/sw/source/core/doc/docfld.cxx
@@ -0,0 +1,1259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+#include <config_fuzzers.h>
+
+#include <hintids.hxx>
+
+#include <comphelper/string.hxx>
+#include <osl/diagnose.h>
+#include <unotools/charclass.hxx>
+#ifndef UNX
+#include <unotools/transliterationwrapper.hxx>
+#endif
+#include <o3tl/string_view.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <node2lay.hxx>
+#include <cntfrm.hxx>
+#include <pagefrm.hxx>
+#include <txtfrm.hxx>
+#include <notxtfrm.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <swtable.hxx>
+#include <calc.hxx>
+#include <txtfld.hxx>
+#include <fmtfld.hxx>
+#include <txttxmrk.hxx>
+#include <docfld.hxx>
+#include <docufld.hxx>
+#include <usrfld.hxx>
+#include <expfld.hxx>
+#include <dbfld.hxx>
+#include <reffld.hxx>
+#include <dbmgr.hxx>
+#include <section.hxx>
+#include <docary.hxx>
+#include <authfld.hxx>
+#include <txtinet.hxx>
+#include <fmtcntnt.hxx>
+
+using namespace ::com::sun::star::uno;
+
+// the StartIndex can be supplied optionally (e.g. if it was queried before - is a virtual
+// method otherwise!)
+SetGetExpField::SetGetExpField(
+ const SwNodeIndex& rNdIdx,
+ const SwTextField* pField,
+ const SwIndex* pIdx,
+ sal_uInt16 const nPageNumber)
+ : m_nPageNumber(nPageNumber)
+{
+ m_eSetGetExpFieldType = TEXTFIELD;
+ m_CNTNT.pTextField = pField;
+ m_nNode = rNdIdx.GetIndex();
+ if( pIdx )
+ m_nContent = pIdx->GetIndex();
+ else if( pField )
+ m_nContent = pField->GetStart();
+ else
+ m_nContent = 0;
+}
+
+SetGetExpField::SetGetExpField( const SwNodeIndex& rNdIdx,
+ const SwTextINetFormat& rINet )
+{
+ m_eSetGetExpFieldType = TEXTINET;
+ m_CNTNT.pTextINet = &rINet;
+ m_nNode = rNdIdx.GetIndex();
+ m_nContent = rINet.GetStart();
+}
+
+// Extension for Sections:
+// these always have content position 0xffffffff!
+// There is never a field on this, only up to COMPLETE_STRING possible
+SetGetExpField::SetGetExpField( const SwSectionNode& rSectNd,
+ const SwPosition* pPos,
+ sal_uInt16 const nPageNumber)
+ : m_nPageNumber(nPageNumber)
+{
+ m_eSetGetExpFieldType = SECTIONNODE;
+ m_CNTNT.pSection = &rSectNd.GetSection();
+
+ if( pPos )
+ {
+ m_nNode = pPos->nNode.GetIndex();
+ m_nContent = pPos->nContent.GetIndex();
+ }
+ else
+ {
+ m_nNode = rSectNd.GetIndex();
+ m_nContent = 0;
+ }
+}
+
+SetGetExpField::SetGetExpField(::sw::mark::IBookmark const& rBookmark,
+ SwPosition const*const pPos,
+ sal_uInt16 const nPageNumber)
+ : m_nPageNumber(nPageNumber)
+{
+ m_eSetGetExpFieldType = BOOKMARK;
+ m_CNTNT.pBookmark = &rBookmark;
+
+ if (pPos)
+ {
+ m_nNode = pPos->nNode.GetIndex();
+ m_nContent = pPos->nContent.GetIndex();
+ }
+ else
+ {
+ m_nNode = rBookmark.GetMarkStart().nNode.GetIndex();
+ m_nContent = rBookmark.GetMarkStart().nContent.GetIndex();;
+ }
+}
+
+SetGetExpField::SetGetExpField( const SwTableBox& rTBox )
+{
+ m_eSetGetExpFieldType = TABLEBOX;
+ m_CNTNT.pTBox = &rTBox;
+
+ m_nNode = SwNodeOffset(0);
+ m_nContent = 0;
+ if( rTBox.GetSttNd() )
+ {
+ SwNodeIndex aIdx( *rTBox.GetSttNd() );
+ const SwContentNode* pNd = aIdx.GetNode().GetNodes().GoNext( &aIdx );
+ if( pNd )
+ m_nNode = pNd->GetIndex();
+ }
+}
+
+SetGetExpField::SetGetExpField( const SwNodeIndex& rNdIdx,
+ const SwTextTOXMark& rTOX )
+{
+ m_eSetGetExpFieldType = TEXTTOXMARK;
+ m_CNTNT.pTextTOX = &rTOX;
+ m_nNode = rNdIdx.GetIndex();
+ m_nContent = rTOX.GetStart();
+}
+
+SetGetExpField::SetGetExpField( const SwPosition& rPos )
+{
+ m_eSetGetExpFieldType = CRSRPOS;
+ m_CNTNT.pPos = &rPos;
+ m_nNode = rPos.nNode.GetIndex();
+ m_nContent = rPos.nContent.GetIndex();
+}
+
+SetGetExpField::SetGetExpField( const SwFlyFrameFormat& rFlyFormat,
+ const SwPosition* pPos )
+{
+ m_eSetGetExpFieldType = FLYFRAME;
+ m_CNTNT.pFlyFormat = &rFlyFormat;
+ if( pPos )
+ {
+ m_nNode = pPos->nNode.GetIndex();
+ m_nContent = pPos->nContent.GetIndex();
+ }
+ else
+ {
+ const SwFormatContent& rContent = rFlyFormat.GetContent();
+ m_nNode = rContent.GetContentIdx()->GetIndex() + 1;
+ m_nContent = 0;
+ }
+}
+
+void SetGetExpField::GetPosOfContent( SwPosition& rPos ) const
+{
+ const SwNode* pNd = GetNodeFromContent();
+ if( pNd )
+ pNd = pNd->GetContentNode();
+
+ if( pNd )
+ {
+ rPos.nNode = *pNd;
+ rPos.nContent.Assign( const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pNd)), GetCntPosFromContent() );
+ }
+ else
+ {
+ rPos.nNode = m_nNode;
+ rPos.nContent.Assign( rPos.nNode.GetNode().GetContentNode(), m_nContent );
+ }
+}
+
+void SetGetExpField::SetBodyPos( const SwContentFrame& rFrame )
+{
+ if( !rFrame.IsInDocBody() )
+ {
+ SwNodeIndex aIdx( rFrame.IsTextFrame()
+ ? *static_cast<SwTextFrame const&>(rFrame).GetTextNodeFirst()
+ : *static_cast<SwNoTextFrame const&>(rFrame).GetNode() );
+ SwDoc& rDoc = aIdx.GetNodes().GetDoc();
+ SwPosition aPos( aIdx );
+ bool const bResult = ::GetBodyTextNode( rDoc, aPos, rFrame );
+ OSL_ENSURE(bResult, "Where is the field?");
+ m_nNode = aPos.nNode.GetIndex();
+ m_nContent = aPos.nContent.GetIndex();
+ }
+}
+
+bool SetGetExpField::operator==( const SetGetExpField& rField ) const
+{
+ return m_nNode == rField.m_nNode
+ && m_nContent == rField.m_nContent
+ && ( !m_CNTNT.pTextField
+ || !rField.m_CNTNT.pTextField
+ || m_CNTNT.pTextField == rField.m_CNTNT.pTextField );
+}
+
+bool SetGetExpField::operator<( const SetGetExpField& rField ) const
+{
+ if (m_nPageNumber != 0 && rField.m_nPageNumber != 0 && m_nPageNumber != rField.m_nPageNumber)
+ {
+ return m_nPageNumber < rField.m_nPageNumber;
+ }
+ if( m_nNode < rField.m_nNode || ( m_nNode == rField.m_nNode && m_nContent < rField.m_nContent ))
+ return true;
+ else if( m_nNode != rField.m_nNode || m_nContent != rField.m_nContent )
+ return false;
+
+ const SwNode *pFirst = GetNodeFromContent(),
+ *pNext = rField.GetNodeFromContent();
+
+ // Position is the same: continue only if both field pointers are set!
+ if( !pFirst || !pNext )
+ return false;
+
+ // same Section?
+ if( pFirst->StartOfSectionNode() != pNext->StartOfSectionNode() )
+ {
+ // is one in the table?
+ const SwNode *pFirstStt, *pNextStt;
+ const SwTableNode* pTableNd = pFirst->FindTableNode();
+ if( pTableNd )
+ pFirstStt = pTableNd->StartOfSectionNode();
+ else
+ pFirstStt = pFirst->StartOfSectionNode();
+
+ pTableNd = pNext->FindTableNode();
+ if( pTableNd )
+ pNextStt = pTableNd->StartOfSectionNode();
+ else
+ pNextStt = pNext->StartOfSectionNode();
+
+ if( pFirstStt != pNextStt )
+ {
+ if( pFirst->IsTextNode() && pNext->IsTextNode() &&
+ ( pFirst->FindFlyStartNode() || pNext->FindFlyStartNode() ))
+ {
+ // FIXME: in NewFieldPortion(), SwGetExpField are expanded via
+ // DocumentFieldsManager::FieldsToExpand() calling
+ // std::upper_bound binary search function - the sort order
+ // depends on the fly positions in the layout, but the fly
+ // positions depend on the expansion of the SwGetExpField!
+ // This circular dep will cause trouble, it would be better to
+ // use only model positions (anchor), but then how to compare
+ // at-page anchored flys which don't have a model anchor?
+ return ::IsFrameBehind( *pNext->GetTextNode(), m_nContent, *pFirst->GetTextNode(), m_nContent );
+ }
+ return pFirstStt->GetIndex() < pNextStt->GetIndex();
+ }
+ }
+
+ // same Section: is the field in the same Node?
+ if( pFirst != pNext )
+ return pFirst->GetIndex() < pNext->GetIndex();
+
+ // same Node in the Section, check Position in the Node
+ return GetCntPosFromContent() < rField.GetCntPosFromContent();
+}
+
+const SwNode* SetGetExpField::GetNodeFromContent() const
+{
+ const SwNode* pRet = nullptr;
+ if( m_CNTNT.pTextField )
+ switch( m_eSetGetExpFieldType )
+ {
+ case TEXTFIELD:
+ pRet = &m_CNTNT.pTextField->GetTextNode();
+ break;
+
+ case TEXTINET:
+ pRet = &m_CNTNT.pTextINet->GetTextNode();
+ break;
+
+ case SECTIONNODE:
+ pRet = m_CNTNT.pSection->GetFormat()->GetSectionNode();
+ break;
+
+ case BOOKMARK:
+ pRet = &m_CNTNT.pBookmark->GetMarkStart().nNode.GetNode();
+ break;
+
+ case CRSRPOS:
+ pRet = &m_CNTNT.pPos->nNode.GetNode();
+ break;
+
+ case TEXTTOXMARK:
+ pRet = &m_CNTNT.pTextTOX->GetTextNode();
+ break;
+
+ case TABLEBOX:
+ if( m_CNTNT.pTBox->GetSttNd() )
+ {
+ SwNodeIndex aIdx( *m_CNTNT.pTBox->GetSttNd() );
+ pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
+ }
+ break;
+
+ case FLYFRAME:
+ {
+ SwNodeIndex aIdx( *m_CNTNT.pFlyFormat->GetContent().GetContentIdx() );
+ pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
+ }
+ break;
+ }
+ return pRet;
+}
+
+sal_Int32 SetGetExpField::GetCntPosFromContent() const
+{
+ sal_Int32 nRet = 0;
+ if( m_CNTNT.pTextField )
+ switch( m_eSetGetExpFieldType )
+ {
+ case TEXTFIELD:
+ nRet = m_CNTNT.pTextField->GetStart();
+ break;
+ case TEXTINET:
+ nRet = m_CNTNT.pTextINet->GetStart();
+ break;
+ case TEXTTOXMARK:
+ nRet = m_CNTNT.pTextTOX->GetStart();
+ break;
+ case BOOKMARK:
+ nRet = m_CNTNT.pBookmark->GetMarkStart().nContent.GetIndex();
+ break;
+ case CRSRPOS:
+ nRet = m_CNTNT.pPos->nContent.GetIndex();
+ break;
+ default:
+ break;
+ }
+ return nRet;
+}
+
+HashStr::HashStr( const OUString& rName, const OUString& rText,
+ HashStr* pNxt )
+ : SwHash( rName ), aSetStr( rText )
+{
+ pNext.reset( pNxt );
+}
+
+/// Look up the Name, if it is present, return its String, otherwise return an empty String
+OUString LookString( SwHashTable<HashStr> const & rTable, const OUString& rName )
+{
+ HashStr* pFnd = rTable.Find( comphelper::string::strip(rName, ' ') );
+ if( pFnd )
+ return pFnd->aSetStr;
+
+ return OUString();
+}
+
+SwDBData const & SwDoc::GetDBData()
+{
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ if(maDBData.sDataSource.isEmpty())
+ {
+ // Similar to: SwEditShell::IsAnyDatabaseFieldInDoc
+ for (const auto& pFieldType : *getIDocumentFieldsAccess().GetFieldTypes())
+ {
+ if (IsUsed(*pFieldType))
+ {
+ SwFieldIds nWhich = pFieldType->Which();
+ switch(nWhich)
+ {
+ case SwFieldIds::Database:
+ case SwFieldIds::DbNextSet:
+ case SwFieldIds::DbNumSet:
+ case SwFieldIds::DbSetNumber:
+ {
+ std::vector<SwFormatField*> vFields;
+ pFieldType->GatherFields(vFields);
+ if(vFields.size())
+ {
+ if(SwFieldIds::Database == nWhich)
+ maDBData = static_cast<SwDBFieldType*>(vFields.front()->GetField()->GetTyp())->GetDBData();
+ else
+ maDBData = static_cast<SwDBNameInfField*> (vFields.front()->GetField())->GetRealDBData();
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ }
+ }
+ if(maDBData.sDataSource.isEmpty())
+ maDBData = SwDBManager::GetAddressDBName();
+#endif
+ return maDBData;
+}
+
+void SwDoc::SetInitDBFields( bool b )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) b;
+#else
+ GetDBManager()->SetInitDBFields( b );
+#endif
+}
+
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+
+/// Get all databases that are used by fields
+static OUString lcl_DBDataToString(const SwDBData& rData)
+{
+ return rData.sDataSource + OUStringChar(DB_DELIM)
+ + rData.sCommand + OUStringChar(DB_DELIM)
+ + OUString::number(rData.nCommandType);
+}
+
+#endif
+
+void SwDoc::GetAllUsedDB( std::vector<OUString>& rDBNameList,
+ const std::vector<OUString>* pAllDBNames )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) rDBNameList;
+ (void) pAllDBNames;
+#else
+ std::vector<OUString> aUsedDBNames;
+ std::vector<OUString> aAllDBNames;
+
+ if( !pAllDBNames )
+ {
+ GetAllDBNames( aAllDBNames );
+ pAllDBNames = &aAllDBNames;
+ }
+
+ SwSectionFormats& rArr = GetSections();
+ for (auto n = rArr.size(); n; )
+ {
+ SwSection* pSect = rArr[ --n ]->GetSection();
+
+ if( pSect )
+ {
+ AddUsedDBToList( rDBNameList, FindUsedDBs( *pAllDBNames,
+ pSect->GetCondition(), aUsedDBNames ) );
+ aUsedDBNames.clear();
+ }
+ }
+
+ for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD })
+ {
+ for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(nWhichHint))
+ {
+ const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem);
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes())
+ continue;
+
+ const SwField* pField = pFormatField->GetField();
+ switch (pField->GetTyp()->Which())
+ {
+ case SwFieldIds::Database:
+ AddUsedDBToList( rDBNameList,
+ lcl_DBDataToString(static_cast<const SwDBField*>(pField)->GetDBData() ));
+ break;
+
+ case SwFieldIds::DbSetNumber:
+ case SwFieldIds::DatabaseName:
+ AddUsedDBToList( rDBNameList,
+ lcl_DBDataToString(static_cast<const SwDBNameInfField*>(pField)->GetRealDBData() ));
+ break;
+
+ case SwFieldIds::DbNumSet:
+ case SwFieldIds::DbNextSet:
+ AddUsedDBToList( rDBNameList,
+ lcl_DBDataToString(static_cast<const SwDBNameInfField*>(pField)->GetRealDBData() ));
+ [[fallthrough]]; // JP: is that right like that?
+
+ case SwFieldIds::HiddenText:
+ case SwFieldIds::HiddenPara:
+ AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames,
+ pField->GetPar1(), aUsedDBNames ));
+ aUsedDBNames.clear();
+ break;
+
+ case SwFieldIds::SetExp:
+ case SwFieldIds::GetExp:
+ case SwFieldIds::Table:
+ AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames,
+ pField->GetFormula(), aUsedDBNames ));
+ aUsedDBNames.clear();
+ break;
+ default: break;
+ }
+ }
+ }
+#endif
+}
+
+void SwDoc::GetAllDBNames( std::vector<OUString>& rAllDBNames )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) rAllDBNames;
+#else
+ SwDBManager* pMgr = GetDBManager();
+
+ const SwDSParams_t& rArr = pMgr->GetDSParamArray();
+ for (const auto& pParam : rArr)
+ {
+ rAllDBNames.emplace_back(pParam->sDataSource + OUStringChar(DB_DELIM) + pParam->sCommand);
+ }
+#endif
+}
+
+std::vector<OUString>& SwDoc::FindUsedDBs( const std::vector<OUString>& rAllDBNames,
+ const OUString& rFormula,
+ std::vector<OUString>& rUsedDBNames )
+{
+ const CharClass& rCC = GetAppCharClass();
+#ifndef UNX
+ const OUString sFormula(rCC.uppercase( rFormula ));
+#else
+ const OUString sFormula(rFormula);
+#endif
+
+ for (const auto &sItem : rAllDBNames)
+ {
+ sal_Int32 nPos = sFormula.indexOf( sItem );
+ if( nPos>=0 &&
+ sFormula[ nPos + sItem.getLength() ] == '.' &&
+ (!nPos || !rCC.isLetterNumeric( sFormula, nPos - 1 )))
+ {
+ // Look up table name
+ nPos += sItem.getLength() + 1;
+ const sal_Int32 nEndPos = sFormula.indexOf('.', nPos);
+ if( nEndPos>=0 )
+ {
+ rUsedDBNames.emplace_back(sItem + OUStringChar(DB_DELIM) + sFormula.subView( nPos, nEndPos - nPos ));
+ }
+ }
+ }
+ return rUsedDBNames;
+}
+
+void SwDoc::AddUsedDBToList( std::vector<OUString>& rDBNameList,
+ const std::vector<OUString>& rUsedDBNames )
+{
+ for ( const auto &sName : rUsedDBNames )
+ AddUsedDBToList( rDBNameList, sName );
+}
+
+void SwDoc::AddUsedDBToList( std::vector<OUString>& rDBNameList, const OUString& rDBName)
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) rDBNameList;
+ (void) rDBName;
+#else
+ if( rDBName.isEmpty() )
+ return;
+
+#ifdef UNX
+ for( const auto &sName : rDBNameList )
+ if( rDBName == o3tl::getToken(sName, 0, ';') )
+ return;
+#else
+ const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
+ for( const auto &sName : rDBNameList )
+ if( rSCmp.isEqual( rDBName, sName.getToken(0, ';') ) )
+ return;
+#endif
+
+ SwDBData aData;
+ sal_Int32 nIdx{ 0 };
+ aData.sDataSource = rDBName.getToken(0, DB_DELIM, nIdx);
+ aData.sCommand = rDBName.getToken(0, DB_DELIM, nIdx);
+ aData.nCommandType = -1;
+ GetDBManager()->CreateDSData(aData);
+ rDBNameList.push_back(rDBName);
+#endif
+}
+
+void SwDoc::ChangeDBFields( const std::vector<OUString>& rOldNames,
+ const OUString& rNewName )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) rOldNames;
+ (void) rNewName;
+#else
+ SwDBData aNewDBData;
+ sal_Int32 nIdx{ 0 };
+ aNewDBData.sDataSource = rNewName.getToken(0, DB_DELIM, nIdx);
+ aNewDBData.sCommand = rNewName.getToken(0, DB_DELIM, nIdx);
+ aNewDBData.nCommandType = o3tl::toInt32(o3tl::getToken(rNewName, 0, DB_DELIM, nIdx));
+
+ SwSectionFormats& rArr = GetSections();
+ for (auto n = rArr.size(); n; )
+ {
+ SwSection* pSect = rArr[ --n ]->GetSection();
+
+ if( pSect )
+ {
+ pSect->SetCondition(ReplaceUsedDBs(rOldNames, rNewName, pSect->GetCondition()));
+ }
+ }
+
+ for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD })
+ {
+ for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(nWhichHint))
+ {
+ SwFormatField* pFormatField = const_cast<SwFormatField*>(static_cast<const SwFormatField*>(pItem));
+ SwTextField* pTextField = pFormatField->GetTextField();
+ if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes())
+ continue;
+
+ SwField* pField = pFormatField->GetField();
+ bool bExpand = false;
+
+ switch( pField->GetTyp()->Which() )
+ {
+ case SwFieldIds::Database:
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ if (IsNameInArray(rOldNames, lcl_DBDataToString(static_cast<SwDBField*>(pField)->GetDBData())))
+ {
+ SwDBFieldType* pOldTyp = static_cast<SwDBFieldType*>(pField->GetTyp());
+
+ SwDBFieldType* pTyp = static_cast<SwDBFieldType*>(getIDocumentFieldsAccess().InsertFieldType(
+ SwDBFieldType(this, pOldTyp->GetColumnName(), aNewDBData)));
+
+ pFormatField->RegisterToFieldType( *pTyp );
+ pField->ChgTyp(pTyp);
+
+ static_cast<SwDBField*>(pField)->ClearInitialized();
+ static_cast<SwDBField*>(pField)->InitContent();
+
+ bExpand = true;
+ }
+#endif
+ break;
+
+ case SwFieldIds::DbSetNumber:
+ case SwFieldIds::DatabaseName:
+ if (IsNameInArray(rOldNames,
+ lcl_DBDataToString(static_cast<SwDBNameInfField*>(pField)->GetRealDBData())))
+ {
+ static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData);
+ bExpand = true;
+ }
+ break;
+
+ case SwFieldIds::DbNumSet:
+ case SwFieldIds::DbNextSet:
+ if (IsNameInArray(rOldNames,
+ lcl_DBDataToString(static_cast<SwDBNameInfField*>(pField)->GetRealDBData())))
+ {
+ static_cast<SwDBNameInfField*>(pField)->SetDBData(aNewDBData);
+ }
+ [[fallthrough]];
+ case SwFieldIds::HiddenText:
+ case SwFieldIds::HiddenPara:
+ pField->SetPar1( ReplaceUsedDBs(rOldNames, rNewName, pField->GetPar1()) );
+ bExpand = true;
+ break;
+
+ case SwFieldIds::SetExp:
+ case SwFieldIds::GetExp:
+ case SwFieldIds::Table:
+ pField->SetPar2( ReplaceUsedDBs(rOldNames, rNewName, pField->GetFormula()) );
+ bExpand = true;
+ break;
+ default: break;
+ }
+
+ if (bExpand)
+ pTextField->ExpandTextField( true );
+ }
+ }
+ getIDocumentState().SetModified();
+#endif
+}
+
+namespace
+{
+
+OUString lcl_CutOffDBCommandType(const OUString& rName)
+{
+ return rName.replaceFirst(OUStringChar(DB_DELIM), ".").getToken(0, DB_DELIM);
+}
+
+}
+
+OUString SwDoc::ReplaceUsedDBs( const std::vector<OUString>& rUsedDBNames,
+ const OUString& rNewName, const OUString& rFormula )
+{
+ const CharClass& rCC = GetAppCharClass();
+ const OUString sNewName( lcl_CutOffDBCommandType(rNewName) );
+ OUString sFormula(rFormula);
+
+ for(const auto & rUsedDBName : rUsedDBNames)
+ {
+ const OUString sDBName( lcl_CutOffDBCommandType(rUsedDBName) );
+
+ if (sDBName!=sNewName)
+ {
+ sal_Int32 nPos = 0;
+ for (;;)
+ {
+ nPos = sFormula.indexOf(sDBName, nPos);
+ if (nPos<0)
+ {
+ break;
+ }
+
+ if( sFormula[nPos + sDBName.getLength()] == '.' &&
+ (!nPos || !rCC.isLetterNumeric( sFormula, nPos - 1 )))
+ {
+ sFormula = sFormula.replaceAt(nPos, sDBName.getLength(), sNewName);
+ //prevent re-searching - this is useless and provokes
+ //endless loops when names containing each other and numbers are exchanged
+ //e.g.: old ?12345.12345 new: i12345.12345
+ nPos += sNewName.getLength();
+ }
+ }
+ }
+ }
+ return sFormula;
+}
+
+bool SwDoc::IsNameInArray( const std::vector<OUString>& rArr, const OUString& rName )
+{
+#ifdef UNX
+ for( const auto &sName : rArr )
+ if( rName == sName )
+ return true;
+#else
+ const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
+ for( const auto &sName : rArr )
+ if( rSCmp.isEqual( rName, sName ))
+ return true;
+#endif
+ return false;
+}
+
+void SwDoc::ChangeAuthorityData( const SwAuthEntry* pNewData )
+{
+ const SwFieldTypes::size_type nSize = getIDocumentFieldsAccess().GetFieldTypes()->size();
+
+ for( SwFieldTypes::size_type i = INIT_FLDTYPES; i < nSize; ++i )
+ {
+ SwFieldType* pFieldType = (*getIDocumentFieldsAccess().GetFieldTypes())[i].get();
+ if( SwFieldIds::TableOfAuthorities == pFieldType->Which() )
+ {
+ SwAuthorityFieldType* pAuthType = static_cast<SwAuthorityFieldType*>(pFieldType);
+ pAuthType->ChangeEntryContent(pNewData);
+ break;
+ }
+ }
+
+}
+
+void SwDocUpdateField::InsDelFieldInFieldLst( bool bIns, const SwTextField& rField )
+{
+ const SwFieldIds nWhich = rField.GetFormatField().GetField()->GetTyp()->Which();
+ switch( nWhich )
+ {
+ case SwFieldIds::Database:
+ case SwFieldIds::SetExp:
+ case SwFieldIds::HiddenPara:
+ case SwFieldIds::HiddenText:
+ case SwFieldIds::DbNumSet:
+ case SwFieldIds::DbNextSet:
+ case SwFieldIds::DbSetNumber:
+ case SwFieldIds::GetExp:
+ break; // these have to be added/removed!
+
+ default:
+ return;
+ }
+
+ SetFieldsDirty( true );
+ if (!m_pFieldSortList)
+ {
+ if( !bIns ) // if list is present and deleted
+ return; // don't do a thing
+ m_pFieldSortList.reset(new SetGetExpFields);
+ }
+
+ if( bIns ) // insert anew:
+ GetBodyNode( rField, nWhich );
+ else
+ {
+ // look up via the pTextField pointer. It is a sorted list, but it's sorted by node
+ // position. Until this is found, the search for the pointer is already done.
+ for (SetGetExpFields::size_type n = 0; n < m_pFieldSortList->size(); ++n)
+ {
+ if (&rField == (*m_pFieldSortList)[n]->GetPointer())
+ {
+ m_pFieldSortList->erase_at(n);
+ n--; // one field can occur multiple times
+ }
+ }
+ }
+}
+
+void SwDocUpdateField::MakeFieldList( SwDoc& rDoc, bool bAll, int eGetMode )
+{
+ if (!m_pFieldSortList || bAll
+ || ((eGetMode & m_nFieldListGetMode) != eGetMode)
+ || rDoc.GetNodes().Count() != m_nNodes)
+ {
+ MakeFieldList_( rDoc, eGetMode );
+ }
+}
+
+void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode )
+{
+ // new version: walk all fields of the attribute pool
+ m_pFieldSortList.reset(new SetGetExpFields);
+
+ // remembeer sections that were unhidden and need to be hidden again
+ std::vector<std::reference_wrapper<SwSection>> aUnhiddenSections;
+
+ // consider and unhide sections
+ // with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>)
+ // notes by OD:
+ // eGetMode == GETFLD_CALC in call from methods SwDoc::FieldsToCalc
+ // eGetMode == GETFLD_EXPAND in call from method SwDoc::FieldsToExpand
+ // eGetMode == GETFLD_ALL in call from method SwDoc::UpdateExpFields
+ // I figured out that hidden section only have to be shown,
+ // if fields have updated (call by SwDoc::UpdateExpFields) and thus
+ // the hide conditions of section have to be updated.
+ // For correct updating the hide condition of a section, its position
+ // have to be known in order to insert the hide condition as a new
+ // expression field into the sorted field list (<m_pFieldSortList>).
+ if ( eGetMode == GETFLD_ALL )
+ // Collect the sections first. Supply sections that are hidden by condition
+ // with frames so that the contained fields are sorted properly.
+ {
+ // In order for the frames to be created the right way, they have to be expanded
+ // from top to bottom
+ std::vector<SwNodeOffset> aTmpArr;
+ std::vector<SwNodeOffset>::size_type nArrStt = 0;
+ SwSectionFormats& rArr = rDoc.GetSections();
+ SwSectionNode* pSectNd = nullptr;
+ SwNodeOffset nSttContent = rDoc.GetNodes().GetEndOfExtras().GetIndex();
+
+ for (SwSectionFormats::size_type n = rArr.size(); n; )
+ {
+ SwSection* pSect = rArr[ --n ]->GetSection();
+ if( !pSect || !pSect->IsHidden() || pSect->GetCondition().isEmpty() )
+ continue;
+ pSectNd = pSect->GetFormat()->GetSectionNode();
+ if( pSectNd )
+ {
+ SwNodeOffset nIdx = pSectNd->GetIndex();
+ aTmpArr.push_back( nIdx );
+ if( nIdx < nSttContent )
+ ++nArrStt;
+ }
+ }
+ std::sort(aTmpArr.begin(), aTmpArr.end());
+
+ // Display all first so that we have frames. The BodyAnchor is defined by that.
+ // First the ContentArea, then the special areas!
+ for (std::vector<sal_uLong>::size_type n = nArrStt; n < aTmpArr.size(); ++n)
+ {
+ pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
+ OSL_ENSURE( pSectNd, "Where is my SectionNode" );
+
+ auto& rSection = pSectNd->GetSection();
+ // unhide and remember the conditionally hidden sections
+ if (rSection.IsHidden() && !rSection.GetCondition().isEmpty() && rSection.IsCondHidden())
+ {
+ aUnhiddenSections.push_back(std::ref(rSection)); // remember to later hide again
+ rSection.SetCondHidden(false);
+ }
+ }
+ for (std::vector<sal_uLong>::size_type n = 0; n < nArrStt; ++n)
+ {
+ pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
+ OSL_ENSURE( pSectNd, "Where is my SectionNode" );
+
+ auto& rSection = pSectNd->GetSection();
+ // unhide and remember the conditionally hidden sections
+ if (rSection.IsHidden() && !rSection.GetCondition().isEmpty() && rSection.IsCondHidden())
+ {
+ aUnhiddenSections.push_back(std::ref(rSection)); // remember to later hide again
+ rSection.SetCondHidden(false);
+ }
+ }
+
+ // add all to the list so that they are sorted
+ for (const auto &nId : aTmpArr)
+ {
+ SwSectionNode const& rSectionNode(*rDoc.GetNodes()[ nId ]->GetSectionNode());
+ GetBodyNodeGeneric(rSectionNode, rSectionNode);
+ }
+
+ // bookmarks with hide conditions, handle similar to sections
+ auto const& rIDMA(*rDoc.getIDocumentMarkAccess());
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ auto const pBookmark(dynamic_cast<::sw::mark::IBookmark const*>(*it));
+ assert(pBookmark);
+ if (!pBookmark->GetHideCondition().isEmpty())
+ {
+ GetBodyNodeGeneric((*it)->GetMarkStart().nNode.GetNode(), *pBookmark);
+ }
+ }
+ }
+
+ static const OUStringLiteral sTrue(u"TRUE");
+ static const OUStringLiteral sFalse(u"FALSE");
+
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ bool bIsDBManager = nullptr != rDoc.GetDBManager();
+#endif
+
+ for (sal_uInt16 const nWhichHint : { RES_TXTATR_FIELD, RES_TXTATR_INPUTFIELD })
+ {
+ for (const SfxPoolItem* pItem : rDoc.GetAttrPool().GetItemSurrogates(nWhichHint))
+ {
+ const SwFormatField* pFormatField = static_cast<const SwFormatField*>(pItem);
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if (!pTextField || !pTextField->GetTextNode().GetNodes().IsDocNodes())
+ continue;
+
+ OUString sFormula;
+ const SwField* pField = pFormatField->GetField();
+ const SwFieldIds nWhich = pField->GetTyp()->Which();
+ switch (nWhich)
+ {
+ case SwFieldIds::DbSetNumber:
+ case SwFieldIds::GetExp:
+ if (GETFLD_ALL == eGetMode)
+ sFormula = sTrue;
+ break;
+
+ case SwFieldIds::Database:
+ if (GETFLD_EXPAND & eGetMode)
+ sFormula = sTrue;
+ break;
+
+ case SwFieldIds::SetExp:
+ if ((eGetMode != GETFLD_EXPAND) ||
+ (nsSwGetSetExpType::GSE_STRING & pField->GetSubType()))
+ {
+ sFormula = sTrue;
+ }
+ break;
+
+ case SwFieldIds::HiddenPara:
+ if (GETFLD_ALL == eGetMode)
+ {
+ sFormula = pField->GetPar1();
+ if (sFormula.isEmpty() || sFormula==sFalse)
+ const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( false );
+ else if (sFormula==sTrue)
+ const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField))->SetHidden( true );
+ else
+ break;
+
+ sFormula.clear();
+ // trigger formatting
+ const_cast<SwFormatField*>(pFormatField)->UpdateTextNode( nullptr, nullptr );
+ }
+ break;
+
+ case SwFieldIds::HiddenText:
+ if (GETFLD_ALL == eGetMode)
+ {
+ sFormula = pField->GetPar1();
+ if (sFormula.isEmpty() || sFormula==sFalse)
+ const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( true );
+ else if (sFormula==sTrue)
+ const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->SetValue( false );
+ else
+ break;
+
+ sFormula.clear();
+
+ // evaluate field
+ const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->Evaluate(rDoc);
+ // trigger formatting
+ const_cast<SwFormatField*>(pFormatField)->UpdateTextNode(nullptr, nullptr);
+ }
+ break;
+
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ case SwFieldIds::DbNumSet:
+ {
+ SwDBData aDBData(const_cast<SwDBNumSetField*>(static_cast<const SwDBNumSetField*>(pField))->GetDBData(&rDoc));
+
+ if ( (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand))
+ && (GETFLD_ALL == eGetMode
+ || (GETFLD_CALC & eGetMode
+ && static_cast<const SwDBNumSetField*>(pField)->IsCondValid()))
+ )
+ {
+ sFormula = pField->GetPar1();
+ }
+ }
+ break;
+ case SwFieldIds::DbNextSet:
+ {
+ SwDBData aDBData(const_cast<SwDBNextSetField*>(static_cast<const SwDBNextSetField*>(pField))->GetDBData(&rDoc));
+
+ if ( (bIsDBManager && rDoc.GetDBManager()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand))
+ && (GETFLD_ALL == eGetMode
+ || (GETFLD_CALC & eGetMode
+ && static_cast<const SwDBNextSetField*>(pField)->IsCondValid()))
+ )
+ {
+ sFormula = pField->GetPar1();
+ }
+ }
+ break;
+#endif
+ default: break;
+ }
+
+ if (!sFormula.isEmpty())
+ {
+ GetBodyNode( *pTextField, nWhich );
+ }
+ }
+ }
+ m_nFieldListGetMode = eGetMode;
+ m_nNodes = rDoc.GetNodes().Count();
+
+ // return the conditional hidden value back to the previous value
+ for (auto& rSectionWrapper : aUnhiddenSections)
+ {
+ auto& rSection = rSectionWrapper.get();
+ rSection.SetCondHidden(true);
+ }
+}
+
+void SwDocUpdateField::GetBodyNode( const SwTextField& rTField, SwFieldIds nFieldWhich )
+{
+ const SwTextNode& rTextNd = rTField.GetTextNode();
+ const SwDoc& rDoc = rTextNd.GetDoc();
+
+ // always the first! (in tab headline, header-/footer)
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+ // need pos to get the frame on the correct page
+ SwPosition const pos(const_cast<SwTextNode&>(rTextNd), rTField.GetStart());
+ const SwFrame* pFrame = rTextNd.getLayoutFrame(
+ rDoc.getIDocumentLayoutAccess().GetCurrentLayout(), &pos, &tmp);
+
+ std::unique_ptr<SetGetExpField> pNew;
+ bool bIsInBody = false;
+
+ if( !pFrame || pFrame->IsInDocBody() )
+ {
+ // create index to determine the TextNode
+ SwNodeIndex aIdx( rTextNd );
+ bIsInBody = rDoc.GetNodes().GetEndOfExtras().GetIndex() < aIdx.GetIndex();
+
+ // We don't want to update fields in redlines, or those
+ // in frames whose anchor is in redline. However, we do want to update
+ // fields in hidden sections. So: In order to be updated, a field 1)
+ // must have a frame, or 2) it must be in the document body.
+ if (pFrame == nullptr && bIsInBody)
+ { // try harder to get a frame for the page number
+ pFrame = ::sw::FindNeighbourFrameForNode(rTextNd);
+ // possibly there is no layout at all, happens in mail merge
+ }
+ if( (pFrame != nullptr) || bIsInBody )
+ {
+ pNew.reset(new SetGetExpField(aIdx, &rTField, nullptr,
+ pFrame ? pFrame->GetPhyPageNum() : 0));
+ }
+ }
+ else
+ {
+ // create index to determine the TextNode
+ SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() );
+ bool const bResult = GetBodyTextNode( rDoc, aPos, *pFrame );
+ OSL_ENSURE(bResult, "where is the Field");
+ pNew.reset(new SetGetExpField(aPos.nNode, &rTField, &aPos.nContent,
+ pFrame->GetPhyPageNum()));
+ }
+
+ // always set the BodyTextFlag in GetExp or DB fields
+ if( SwFieldIds::GetExp == nFieldWhich )
+ {
+ SwGetExpField* pGetField = const_cast<SwGetExpField*>(static_cast<const SwGetExpField*>(rTField.GetFormatField().GetField()));
+ pGetField->ChgBodyTextFlag( bIsInBody );
+ }
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ else if( SwFieldIds::Database == nFieldWhich )
+ {
+ SwDBField* pDBField = const_cast<SwDBField*>(static_cast<const SwDBField*>(rTField.GetFormatField().GetField()));
+ pDBField->ChgBodyTextFlag( bIsInBody );
+ }
+#endif
+ if( pNew != nullptr )
+ m_pFieldSortList->insert( std::move(pNew) );
+}
+
+template<typename T>
+void SwDocUpdateField::GetBodyNodeGeneric(SwNode const& rNode, T const& rCond)
+{
+ const SwDoc& rDoc = rNode.GetDoc();
+ std::unique_ptr<SetGetExpField> pNew;
+
+ if (rNode.GetIndex() < rDoc.GetNodes().GetEndOfExtras().GetIndex())
+ {
+ do { // middle check loop
+
+ // we need to get the anchor first
+ // create index to determine the TextNode
+ SwPosition aPos(rNode);
+ SwContentNode const*const pCNd = rNode.IsSectionNode()
+ ? rDoc.GetNodes().GoNext(&aPos.nNode) // to the next ContentNode
+ : rNode.GetContentNode();
+
+ if( !pCNd || !pCNd->IsTextNode() )
+ break;
+
+ // always the first! (in tab headline, header-/footer)
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+ const SwContentFrame* pFrame = pCNd->getLayoutFrame(
+ rDoc.getIDocumentLayoutAccess().GetCurrentLayout(),
+ nullptr, &tmp);
+ if( !pFrame )
+ break;
+
+ bool const bResult = GetBodyTextNode( rDoc, aPos, *pFrame );
+ OSL_ENSURE(bResult, "where is the Field");
+ pNew.reset(new SetGetExpField(rCond, &aPos, pFrame->GetPhyPageNum()));
+
+ } while( false );
+ }
+
+ if( !pNew )
+ {
+ // try harder to get a frame for the page number
+ SwFrame const*const pFrame = ::sw::FindNeighbourFrameForNode(rNode);
+ pNew.reset(new SetGetExpField(rCond, nullptr, pFrame ? pFrame->GetPhyPageNum() : 0));
+ }
+
+ m_pFieldSortList->insert( std::move(pNew) );
+}
+
+void SwDocUpdateField::InsertFieldType( const SwFieldType& rType )
+{
+ OUString sFieldName;
+ switch( rType.Which() )
+ {
+ case SwFieldIds::User :
+ sFieldName = static_cast<const SwUserFieldType&>(rType).GetName();
+ break;
+ case SwFieldIds::SetExp:
+ sFieldName = static_cast<const SwSetExpFieldType&>(rType).GetName();
+ break;
+ default:
+ OSL_ENSURE( false, "No valid field type" );
+ }
+
+ if( sFieldName.isEmpty() )
+ return;
+
+ SetFieldsDirty( true );
+ // look up and remove from the hash table
+ sFieldName = GetAppCharClass().lowercase( sFieldName );
+ sal_uInt16 n;
+
+ SwCalcFieldType* pFnd = GetFieldTypeTable().Find( sFieldName, &n );
+
+ if( !pFnd )
+ {
+ SwCalcFieldType* pNew = new SwCalcFieldType( sFieldName, &rType );
+ pNew->pNext.reset( m_FieldTypeTable[n].release() );
+ m_FieldTypeTable[n].reset(pNew);
+ }
+}
+
+void SwDocUpdateField::RemoveFieldType( const SwFieldType& rType )
+{
+ OUString sFieldName;
+ switch( rType.Which() )
+ {
+ case SwFieldIds::User :
+ sFieldName = static_cast<const SwUserFieldType&>(rType).GetName();
+ break;
+ case SwFieldIds::SetExp:
+ sFieldName = static_cast<const SwSetExpFieldType&>(rType).GetName();
+ break;
+ default: break;
+ }
+
+ if( sFieldName.isEmpty() )
+ return;
+
+ SetFieldsDirty( true );
+ // look up and remove from the hash table
+ sFieldName = GetAppCharClass().lowercase( sFieldName );
+ sal_uInt16 n;
+
+ SwCalcFieldType* pFnd = GetFieldTypeTable().Find( sFieldName, &n );
+ if( !pFnd )
+ return;
+
+ if (m_FieldTypeTable[n].get() == pFnd)
+ {
+ m_FieldTypeTable[n].reset(static_cast<SwCalcFieldType*>(pFnd->pNext.release()));
+ }
+ else
+ {
+ SwHash* pPrev = m_FieldTypeTable[n].get();
+ while( pPrev->pNext.get() != pFnd )
+ pPrev = pPrev->pNext.get();
+ pPrev->pNext = std::move(pFnd->pNext);
+ // no need to explicitly delete here, the embedded linked list uses unique_ptr
+ }
+}
+
+SwDocUpdateField::SwDocUpdateField(SwDoc& rDoc)
+ : m_FieldTypeTable(TBLSZ)
+ , m_nNodes(0)
+ , m_nFieldListGetMode(0)
+ , m_rDoc(rDoc)
+ , m_bInUpdateFields(false)
+ , m_bFieldsDirty(false)
+{
+}
+
+SwDocUpdateField::~SwDocUpdateField()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */