android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / docfld.cxx
blobb6e8f7267d3399148e61d67bb350e89f27de0591
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
28 #ifndef UNX
29 #include <unotools/transliterationwrapper.hxx>
30 #endif
31 #include <o3tl/string_view.hxx>
32 #include <doc.hxx>
33 #include <IDocumentFieldsAccess.hxx>
34 #include <IDocumentMarkAccess.hxx>
35 #include <IDocumentState.hxx>
36 #include <IDocumentLayoutAccess.hxx>
37 #include <node2lay.hxx>
38 #include <cntfrm.hxx>
39 #include <pagefrm.hxx>
40 #include <txtfrm.hxx>
41 #include <notxtfrm.hxx>
42 #include <pam.hxx>
43 #include <ndtxt.hxx>
44 #include <swtable.hxx>
45 #include <calc.hxx>
46 #include <txtfld.hxx>
47 #include <fmtfld.hxx>
48 #include <txttxmrk.hxx>
49 #include <docfld.hxx>
50 #include <docufld.hxx>
51 #include <usrfld.hxx>
52 #include <expfld.hxx>
53 #include <dbfld.hxx>
54 #include <reffld.hxx>
55 #include <dbmgr.hxx>
56 #include <section.hxx>
57 #include <docary.hxx>
58 #include <authfld.hxx>
59 #include <txtinet.hxx>
60 #include <fmtcntnt.hxx>
61 #include <utility>
63 using namespace ::com::sun::star::uno;
65 // the StartIndex can be supplied optionally (e.g. if it was queried before - is a virtual
66 // method otherwise!)
67 SetGetExpField::SetGetExpField(
68 const SwNode& rNdIdx,
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();
77 if( oContentIdx )
78 m_nContent = *oContentIdx;
79 else if( pField )
80 m_nContent = pField->GetStart();
81 else
82 m_nContent = 0;
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();
105 if( pPos )
107 m_nNode = pPos->GetNodeIndex();
108 m_nContent = pPos->GetContentIndex();
110 else
112 m_nNode = rSectNd.GetIndex();
113 m_nContent = 0;
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;
125 if (pPos)
127 m_nNode = pPos->GetNodeIndex();
128 m_nContent = pPos->GetContentIndex();
130 else
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);
143 m_nContent = 0;
144 if( rTBox.GetSttNd() )
146 SwNodeIndex aIdx( *rTBox.GetSttNd() );
147 const SwContentNode* pNd = aIdx.GetNode().GetNodes().GoNext( &aIdx );
148 if( pNd )
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;
175 if( pPos )
177 m_nNode = pPos->GetNodeIndex();
178 m_nContent = pPos->GetContentIndex();
180 else
182 const SwFormatContent& rContent = rFlyFormat.GetContent();
183 m_nNode = rContent.GetContentIdx()->GetIndex() + 1;
184 m_nContent = 0;
188 void SetGetExpField::GetPosOfContent( SwPosition& rPos ) const
190 const SwNode* pNd = GetNodeFromContent();
191 if( pNd )
192 pNd = pNd->GetContentNode();
194 if( pNd )
196 rPos.Assign( *static_cast<const SwContentNode*>(pNd), GetCntPosFromContent() );
198 else
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 ))
239 return true;
240 else if( m_nNode != rField.m_nNode || m_nContent != rField.m_nContent )
241 return false;
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 )
248 return false;
250 // same Section?
251 if( pFirst->StartOfSectionNode() != pNext->StartOfSectionNode() )
253 // is one in the table?
254 const SwNode *pFirstStt, *pNextStt;
255 const SwTableNode* pTableNd = pFirst->FindTableNode();
256 if( pTableNd )
257 pFirstStt = pTableNd->StartOfSectionNode();
258 else
259 pFirstStt = pFirst->StartOfSectionNode();
261 pTableNd = pNext->FindTableNode();
262 if( pTableNd )
263 pNextStt = pTableNd->StartOfSectionNode();
264 else
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 )
300 case TEXTFIELD:
301 pRet = &m_CNTNT.pTextField->GetTextNode();
302 break;
304 case TEXTINET:
305 pRet = &m_CNTNT.pTextINet->GetTextNode();
306 break;
308 case SECTIONNODE:
309 pRet = m_CNTNT.pSection->GetFormat()->GetSectionNode();
310 break;
312 case BOOKMARK:
313 pRet = &m_CNTNT.pBookmark->GetMarkStart().GetNode();
314 break;
316 case CRSRPOS:
317 pRet = &m_CNTNT.pPos->GetNode();
318 break;
320 case TEXTTOXMARK:
321 pRet = &m_CNTNT.pTextTOX->GetTextNode();
322 break;
324 case TABLEBOX:
325 if( m_CNTNT.pTBox->GetSttNd() )
327 SwNodeIndex aIdx( *m_CNTNT.pTBox->GetSttNd() );
328 pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
330 break;
332 case FLYFRAME:
334 SwNodeIndex aIdx( *m_CNTNT.pFlyFormat->GetContent().GetContentIdx() );
335 pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx );
337 break;
339 return pRet;
342 sal_Int32 SetGetExpField::GetCntPosFromContent() const
344 sal_Int32 nRet = 0;
345 if( m_CNTNT.pTextField )
346 switch( m_eSetGetExpFieldType )
348 case TEXTFIELD:
349 nRet = m_CNTNT.pTextField->GetStart();
350 break;
351 case TEXTINET:
352 nRet = m_CNTNT.pTextINet->GetStart();
353 break;
354 case TEXTTOXMARK:
355 nRet = m_CNTNT.pTextTOX->GetStart();
356 break;
357 case BOOKMARK:
358 nRet = m_CNTNT.pBookmark->GetMarkStart().GetContentIndex();
359 break;
360 case CRSRPOS:
361 nRet = m_CNTNT.pPos->GetContentIndex();
362 break;
363 default:
364 break;
366 return nRet;
369 HashStr::HashStr( const OUString& rName, OUString aText,
370 HashStr* pNxt )
371 : SwHash( rName ), aSetStr(std::move( aText ))
373 pNext.reset( pNxt );
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, ' ') );
380 if( pFnd )
381 return pFnd->aSetStr;
383 return OUString();
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();
397 switch(nWhich)
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);
406 if(vFields.size())
408 if(SwFieldIds::Database == nWhich)
409 maDBData = static_cast<SwDBFieldType*>(vFields.front()->GetField()->GetTyp())->GetDBData();
410 else
411 maDBData = static_cast<SwDBNameInfField*> (vFields.front()->GetField())->GetRealDBData();
414 break;
415 default: break;
420 if(maDBData.sDataSource.isEmpty())
421 maDBData = SwDBManager::GetAddressDBName();
422 #endif
423 return maDBData;
426 void SwDoc::SetInitDBFields( bool b )
428 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
429 (void) b;
430 #else
431 GetDBManager()->SetInitDBFields( b );
432 #endif
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);
445 #endif
447 void SwDoc::GetAllUsedDB( std::vector<OUString>& rDBNameList,
448 const std::vector<OUString>* pAllDBNames )
450 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
451 (void) rDBNameList;
452 (void) pAllDBNames;
453 #else
454 std::vector<OUString> aUsedDBNames;
455 std::vector<OUString> aAllDBNames;
457 if( !pAllDBNames )
459 GetAllDBNames( aAllDBNames );
460 pAllDBNames = &aAllDBNames;
463 SwSectionFormats& rArr = GetSections();
464 for (auto n = rArr.size(); n; )
466 SwSection* pSect = rArr[ --n ]->GetSection();
468 if( pSect )
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())
483 continue;
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() ));
491 break;
493 case SwFieldIds::DbSetNumber:
494 case SwFieldIds::DatabaseName:
495 AddUsedDBToList( rDBNameList,
496 lcl_DBDataToString(static_cast<const SwDBNameInfField*>(pField)->GetRealDBData() ));
497 break;
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();
510 break;
512 case SwFieldIds::SetExp:
513 case SwFieldIds::GetExp:
514 case SwFieldIds::Table:
515 AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames,
516 pField->GetFormula(), aUsedDBNames ));
517 aUsedDBNames.clear();
518 break;
519 default: break;
523 #endif
526 void SwDoc::GetAllDBNames( std::vector<OUString>& rAllDBNames )
528 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
529 (void) rAllDBNames;
530 #else
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);
538 #endif
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();
546 #ifndef UNX
547 const OUString sFormula(rCC.uppercase( rFormula ));
548 #else
549 const OUString sFormula(rFormula);
550 #endif
552 for (const auto &sItem : rAllDBNames)
554 sal_Int32 nPos = sFormula.indexOf( sItem );
555 if( nPos>=0 &&
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);
562 if( nEndPos>=0 )
564 rUsedDBNames.emplace_back(sItem + OUStringChar(DB_DELIM) + sFormula.subView( nPos, nEndPos - nPos ));
568 return rUsedDBNames;
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
581 (void) rDBNameList;
582 (void) rDBName;
583 #else
584 if( rDBName.isEmpty() )
585 return;
587 #ifdef UNX
588 for( const auto &sName : rDBNameList )
589 if( rDBName == o3tl::getToken(sName, 0, ';') )
590 return;
591 #else
592 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
593 for( const auto &sName : rDBNameList )
594 if( rSCmp.isEqual( rDBName, sName.getToken(0, ';') ) )
595 return;
596 #endif
598 SwDBData aData;
599 sal_Int32 nIdx{ 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);
605 #endif
608 void SwDoc::ChangeDBFields( const std::vector<OUString>& rOldNames,
609 const OUString& rNewName )
611 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
612 (void) rOldNames;
613 (void) rNewName;
614 #else
615 SwDBData aNewDBData;
616 sal_Int32 nIdx{ 0 };
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();
626 if( pSect )
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())
639 continue;
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();
661 bExpand = true;
663 #endif
664 break;
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);
672 bExpand = true;
674 break;
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);
683 [[fallthrough]];
684 case SwFieldIds::HiddenText:
685 case SwFieldIds::HiddenPara:
686 pField->SetPar1( ReplaceUsedDBs(rOldNames, rNewName, pField->GetPar1()) );
687 bExpand = true;
688 break;
690 case SwFieldIds::SetExp:
691 case SwFieldIds::GetExp:
692 case SwFieldIds::Table:
693 pField->SetPar2( ReplaceUsedDBs(rOldNames, rNewName, pField->GetFormula()) );
694 bExpand = true;
695 break;
696 default: break;
699 if (bExpand)
700 pTextField->ExpandTextField( true );
703 getIDocumentState().SetModified();
704 #endif
707 namespace
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)
730 sal_Int32 nPos = 0;
731 for (;;)
733 nPos = sFormula.indexOf(sDBName, nPos);
734 if (nPos<0)
736 break;
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();
751 return sFormula;
754 bool SwDoc::IsNameInArray( const std::vector<OUString>& rArr, const OUString& rName )
756 #ifdef UNX
757 for( const auto &sName : rArr )
758 if( rName == sName )
759 return true;
760 #else
761 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
762 for( const auto &sName : rArr )
763 if( rSCmp.isEqual( rName, sName ))
764 return true;
765 #endif
766 return false;
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);
780 break;
786 void SwDocUpdateField::InsDelFieldInFieldLst( bool bIns, const SwTextField& rField )
788 const SwFieldIds nWhich = rField.GetFormatField().GetField()->GetTyp()->Which();
789 switch( nWhich )
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!
801 default:
802 return;
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 );
815 else
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>)
850 // notes by OD:
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() )
876 continue;
877 pSectNd = pSect->GetFormat()->GetSectionNode();
878 if( pSectNd )
880 SwNodeOffset nIdx = pSectNd->GetIndex();
881 aTmpArr.push_back( nIdx );
882 if( nIdx < nSttContent )
883 ++nArrStt;
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));
929 assert(pBookmark);
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();
942 #endif
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())
951 continue;
953 OUString sFormula;
954 const SwField* pField = pFormatField->GetField();
955 const SwFieldIds nWhich = pField->GetTyp()->Which();
956 switch (nWhich)
958 case SwFieldIds::DbSetNumber:
959 case SwFieldIds::GetExp:
960 if (GETFLD_ALL == eGetMode)
961 sFormula = sTrue;
962 break;
964 case SwFieldIds::Database:
965 if (GETFLD_EXPAND & eGetMode)
966 sFormula = sTrue;
967 break;
969 case SwFieldIds::SetExp:
970 if ((eGetMode != GETFLD_EXPAND) ||
971 (nsSwGetSetExpType::GSE_STRING & pField->GetSubType()))
973 sFormula = sTrue;
975 break;
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 );
985 else
986 break;
988 sFormula.clear();
989 // trigger formatting
990 const_cast<SwFormatField*>(pFormatField)->ForceUpdateTextNode();
992 break;
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 );
1002 else
1003 break;
1005 sFormula.clear();
1007 // evaluate field
1008 const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField))->Evaluate(rDoc);
1009 // trigger formatting
1010 const_cast<SwFormatField*>(pFormatField)->ForceUpdateTextNode();
1012 break;
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();
1028 break;
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();
1042 break;
1043 #endif
1044 default: break;
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)
1070 Point aPt;
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));
1099 else
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 );
1121 #endif
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() )
1144 break;
1146 // always the first! (in tab headline, header-/footer)
1147 Point aPt;
1148 std::pair<Point, bool> const tmp(aPt, false);
1149 const SwContentFrame* pFrame = pCNd->getLayoutFrame(
1150 rDoc.getIDocumentLayoutAccess().GetCurrentLayout(),
1151 nullptr, &tmp);
1152 if( !pFrame )
1153 break;
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()));
1159 } while( false );
1162 if( !pNew )
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();
1179 break;
1180 case SwFieldIds::SetExp:
1181 sFieldName = static_cast<const SwSetExpFieldType&>(rType).GetName();
1182 break;
1183 default:
1184 OSL_ENSURE( false, "No valid field type" );
1187 if( sFieldName.isEmpty() )
1188 return;
1190 SetFieldsDirty( true );
1191 // look up and remove from the hash table
1192 sFieldName = GetAppCharClass().lowercase( sFieldName );
1193 sal_uInt32 n;
1195 SwCalcFieldType* pFnd = GetFieldTypeTable().Find( sFieldName, &n );
1197 if( !pFnd )
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();
1212 break;
1213 case SwFieldIds::SetExp:
1214 sFieldName = static_cast<const SwSetExpFieldType&>(rType).GetName();
1215 break;
1216 default: break;
1219 if( sFieldName.isEmpty() )
1220 return;
1222 SetFieldsDirty( true );
1223 // look up and remove from the hash table
1224 sFieldName = GetAppCharClass().lowercase( sFieldName );
1225 sal_uInt32 n;
1227 SwCalcFieldType* pFnd = GetFieldTypeTable().Find( sFieldName, &n );
1228 if( !pFnd )
1229 return;
1231 if (m_FieldTypeTable[n].get() == pFnd)
1233 m_FieldTypeTable[n].reset(static_cast<SwCalcFieldType*>(pFnd->pNext.release()));
1235 else
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)
1247 , m_nNodes(0)
1248 , m_nFieldListGetMode(0)
1249 , m_rDoc(rDoc)
1250 , m_bInUpdateFields(false)
1251 , m_bFieldsDirty(false)
1255 SwDocUpdateField::~SwDocUpdateField()
1259 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */