summaryrefslogtreecommitdiffstats
path: root/sw/source/core/fields
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/fields
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/fields')
-rw-r--r--sw/source/core/fields/authfld.cxx858
-rw-r--r--sw/source/core/fields/cellfml.cxx1254
-rw-r--r--sw/source/core/fields/chpfld.cxx309
-rw-r--r--sw/source/core/fields/dbfld.cxx870
-rw-r--r--sw/source/core/fields/ddefld.cxx383
-rw-r--r--sw/source/core/fields/ddetbl.cxx209
-rw-r--r--sw/source/core/fields/docufld.cxx2727
-rw-r--r--sw/source/core/fields/expfld.cxx1437
-rw-r--r--sw/source/core/fields/fldbas.cxx933
-rw-r--r--sw/source/core/fields/flddat.cxx236
-rw-r--r--sw/source/core/fields/flddropdown.cxx217
-rw-r--r--sw/source/core/fields/fldlst.cxx149
-rw-r--r--sw/source/core/fields/macrofld.cxx223
-rw-r--r--sw/source/core/fields/postithelper.cxx278
-rw-r--r--sw/source/core/fields/reffld.cxx1829
-rw-r--r--sw/source/core/fields/scrptfld.cxx120
-rw-r--r--sw/source/core/fields/tblcalc.cxx211
-rw-r--r--sw/source/core/fields/textapi.cxx215
-rw-r--r--sw/source/core/fields/usrfld.cxx397
19 files changed, 12855 insertions, 0 deletions
diff --git a/sw/source/core/fields/authfld.cxx b/sw/source/core/fields/authfld.cxx
new file mode 100644
index 0000000000..35ab9ca9c8
--- /dev/null
+++ b/sw/source/core/fields/authfld.cxx
@@ -0,0 +1,858 @@
+/* -*- 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 <sal/config.h>
+
+#include <memory>
+
+#include <libxml/xmlwriter.h>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/string_view.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <osl/diagnose.h>
+#include <tools/urlobj.hxx>
+#include <swtypes.hxx>
+#include <strings.hrc>
+#include <authfld.hxx>
+#include <expfld.hxx>
+#include <pam.hxx>
+#include <cntfrm.hxx>
+#include <rootfrm.hxx>
+#include <tox.hxx>
+#include <txmsrt.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <ndtxt.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <unofldmid.h>
+#include <unoprnms.hxx>
+#include <docsh.hxx>
+
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+
+SwAuthEntry::SwAuthEntry(const SwAuthEntry& rCopy)
+ : SimpleReferenceObject()
+{
+ for(int i = 0; i < AUTH_FIELD_END; ++i)
+ m_aAuthFields[i] = rCopy.m_aAuthFields[i];
+}
+
+bool SwAuthEntry::operator==(const SwAuthEntry& rComp) const
+{
+ for(int i = 0; i < AUTH_FIELD_END; ++i)
+ if(m_aAuthFields[i] != rComp.m_aAuthFields[i])
+ return false;
+ return true;
+}
+
+SwAuthorityFieldType::SwAuthorityFieldType(SwDoc* pDoc)
+ : SwFieldType( SwFieldIds::TableOfAuthorities ),
+ m_pDoc(pDoc),
+ m_cPrefix('['),
+ m_cSuffix(']'),
+ m_bIsSequence(false),
+ m_bSortByDocument(true),
+ m_eLanguage(::GetAppLanguage())
+{
+}
+
+SwAuthorityFieldType::~SwAuthorityFieldType()
+{
+}
+
+std::unique_ptr<SwFieldType> SwAuthorityFieldType::Copy() const
+{
+ return std::make_unique<SwAuthorityFieldType>(m_pDoc);
+}
+
+void SwAuthorityFieldType::RemoveField(const SwAuthEntry* pEntry)
+{
+ for(SwAuthDataArr::size_type j = 0; j < m_DataArr.size(); ++j)
+ {
+ if(m_DataArr[j].get() == pEntry)
+ {
+ if (m_DataArr[j]->m_nCount <= 1)
+ {
+ m_DataArr.erase(m_DataArr.begin() + j);
+ //re-generate positions of the fields
+ DelSequenceArray();
+ }
+ return;
+ }
+ }
+ assert(false && "SwAuthorityFieldType::RemoveField: pEntry was not added previously");
+}
+
+SwAuthEntry* SwAuthorityFieldType::AddField(std::u16string_view rFieldContents)
+{
+ rtl::Reference<SwAuthEntry> pEntry(new SwAuthEntry);
+ sal_Int32 nIdx{ 0 };
+ for( sal_Int32 i = 0; i < AUTH_FIELD_END; ++i )
+ pEntry->SetAuthorField( static_cast<ToxAuthorityField>(i),
+ OUString(o3tl::getToken(rFieldContents, 0, TOX_STYLE_DELIMITER, nIdx )));
+
+ for (const auto &rpTemp : m_DataArr)
+ {
+ if (*rpTemp == *pEntry)
+ {
+ return rpTemp.get();
+ }
+ }
+
+ //if it is a new Entry - insert
+ m_DataArr.push_back(std::move(pEntry));
+ //re-generate positions of the fields
+ DelSequenceArray();
+ return m_DataArr.back().get();
+}
+
+void SwAuthorityFieldType::GetAllEntryIdentifiers(
+ std::vector<OUString>& rToFill )const
+{
+ for (const auto & rpTemp : m_DataArr)
+ {
+ rToFill.push_back(rpTemp->GetAuthorField(AUTH_FIELD_IDENTIFIER));
+ }
+}
+
+SwAuthEntry* SwAuthorityFieldType::GetEntryByIdentifier(
+ std::u16string_view rIdentifier)const
+{
+ for (const auto &rpTemp : m_DataArr)
+ {
+ if (rIdentifier == rpTemp->GetAuthorField(AUTH_FIELD_IDENTIFIER))
+ {
+ return rpTemp.get();
+ }
+ }
+ return nullptr;
+}
+
+bool SwAuthorityFieldType::ChangeEntryContent(const SwAuthEntry* pNewEntry)
+{
+ for (auto &rpTemp : m_DataArr)
+ {
+ if (rpTemp->GetAuthorField(AUTH_FIELD_IDENTIFIER) ==
+ pNewEntry->GetAuthorField(AUTH_FIELD_IDENTIFIER))
+ {
+ for(int i = 0; i < AUTH_FIELD_END; ++i)
+ {
+ rpTemp->SetAuthorField(static_cast<ToxAuthorityField>(i),
+ pNewEntry->GetAuthorField(static_cast<ToxAuthorityField>(i)));
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/// appends a new entry (if new) and returns the copied entry
+SwAuthEntry* SwAuthorityFieldType::AppendField( const SwAuthEntry& rInsert )
+{
+ for( SwAuthDataArr::size_type nRet = 0; nRet < m_DataArr.size(); ++nRet )
+ {
+ if( *m_DataArr[ nRet ] == rInsert )
+ return m_DataArr[ nRet ].get();
+ }
+
+ //if it is a new Entry - insert
+ m_DataArr.push_back(new SwAuthEntry(rInsert));
+ return m_DataArr.back().get();
+}
+
+std::unique_ptr<SwTOXInternational> SwAuthorityFieldType::CreateTOXInternational() const
+{
+ return std::make_unique<SwTOXInternational>(m_eLanguage, SwTOIOptions::NONE, m_sSortAlgorithm);
+}
+
+sal_uInt16 SwAuthorityFieldType::GetSequencePos(const SwAuthEntry* pAuthEntry,
+ SwRootFrame const*const pLayout)
+{
+ //find the field in a sorted array of handles,
+ if(!m_SequArr.empty() && m_SequArr.size() != m_DataArr.size())
+ DelSequenceArray();
+ if(m_SequArr.empty())
+ {
+ IDocumentRedlineAccess const& rIDRA(m_pDoc->getIDocumentRedlineAccess());
+ std::unique_ptr<SwTOXInternational> pIntl = CreateTOXInternational();
+ // sw_redlinehide: need 2 arrays because the sorting may be different,
+ // if multiple fields refer to the same entry and first one is deleted
+ std::vector<std::unique_ptr<SwTOXSortTabBase>> aSortArr;
+ std::vector<std::unique_ptr<SwTOXSortTabBase>> aSortArrRLHidden;
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(SwFormatField* pFormatField : vFields)
+ {
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if(!pTextField || !pTextField->GetpTextNode())
+ {
+ continue;
+ }
+ const SwTextNode& rFieldTextNode = pTextField->GetTextNode();
+ SwPosition aFieldPos(rFieldTextNode);
+ SwDoc& rDoc = const_cast<SwDoc&>(rFieldTextNode.GetDoc());
+ SwContentFrame *pFrame = rFieldTextNode.getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() );
+ const SwTextNode* pTextNode = nullptr;
+ if(pFrame && !pFrame->IsInDocBody())
+ pTextNode = GetBodyTextNode( rDoc, aFieldPos, *pFrame );
+ //if no text node could be found or the field is in the document
+ //body the directly available text node will be used
+ if(!pTextNode)
+ pTextNode = &rFieldTextNode;
+ if (pTextNode->GetText().isEmpty()
+ || !pTextNode->getLayoutFrame(rDoc.getIDocumentLayoutAccess().GetCurrentLayout())
+ || !pTextNode->GetNodes().IsDocNodes())
+ {
+ continue;
+ }
+ auto const InsertImpl = [&pIntl, pTextNode, pFormatField]
+ (std::vector<std::unique_ptr<SwTOXSortTabBase>> & rSortArr)
+ {
+ std::unique_ptr<SwTOXAuthority> pNew(
+ new SwTOXAuthority(*pTextNode, *pFormatField, *pIntl));
+
+ for (size_t i = 0; i < rSortArr.size(); ++i)
+ {
+ SwTOXSortTabBase* pOld = rSortArr[i].get();
+ if (pOld->equivalent(*pNew))
+ {
+ //only the first occurrence in the document
+ //has to be in the array
+ if (pOld->sort_lt(*pNew))
+ pNew.reset();
+ else // remove the old content
+ rSortArr.erase(rSortArr.begin() + i);
+ break;
+ }
+ }
+ //if it still exists - insert at the correct position
+ if (pNew)
+ {
+ size_t j {0};
+
+ while (j < rSortArr.size())
+ {
+ SwTOXSortTabBase* pOld = rSortArr[j].get();
+ if (pNew->sort_lt(*pOld))
+ break;
+ ++j;
+ }
+ rSortArr.insert(rSortArr.begin() + j, std::move(pNew));
+ }
+ };
+ InsertImpl(aSortArr);
+ if (!sw::IsFieldDeletedInModel(rIDRA, *pTextField))
+ {
+ InsertImpl(aSortArrRLHidden);
+ }
+ }
+
+ for(auto & pBase : aSortArr)
+ {
+ SwFormatField& rFormatField = static_cast<SwTOXAuthority&>(*pBase).GetFieldFormat();
+ SwAuthorityField* pAField = static_cast<SwAuthorityField*>(rFormatField.GetField());
+ m_SequArr.push_back(pAField->GetAuthEntry());
+ }
+ for (auto & pBase : aSortArrRLHidden)
+ {
+ SwFormatField& rFormatField = static_cast<SwTOXAuthority&>(*pBase).GetFieldFormat();
+ SwAuthorityField* pAField = static_cast<SwAuthorityField*>(rFormatField.GetField());
+ m_SequArrRLHidden.push_back(pAField->GetAuthEntry());
+ }
+ }
+ //find nHandle
+ auto const& rSequArr(pLayout && pLayout->IsHideRedlines() ? m_SequArrRLHidden : m_SequArr);
+ for (std::vector<sal_IntPtr>::size_type i = 0; i < rSequArr.size(); ++i)
+ {
+ if (rSequArr[i] == pAuthEntry)
+ {
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+void SwAuthorityFieldType::QueryValue( Any& rVal, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ case FIELD_PROP_PAR2:
+ {
+ OUString sVal;
+ sal_Unicode uRet = FIELD_PROP_PAR1 == nWhichId ? m_cPrefix : m_cSuffix;
+ if(uRet)
+ sVal = OUString(uRet);
+ rVal <<= sVal;
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ rVal <<= GetSortAlgorithm();
+ break;
+
+ case FIELD_PROP_BOOL1:
+ rVal <<= m_bIsSequence;
+ break;
+
+ case FIELD_PROP_BOOL2:
+ rVal <<= m_bSortByDocument;
+ break;
+
+ case FIELD_PROP_LOCALE:
+ rVal <<= LanguageTag(GetLanguage()).getLocale();
+ break;
+
+ case FIELD_PROP_PROP_SEQ:
+ {
+ Sequence<PropertyValues> aRet(m_SortKeyArr.size());
+ PropertyValues* pValues = aRet.getArray();
+ for(SortKeyArr::size_type i = 0; i < m_SortKeyArr.size(); ++i)
+ {
+ const SwTOXSortKey* pKey = &m_SortKeyArr[i];
+ pValues[i].realloc(2);
+ PropertyValue* pValue = pValues[i].getArray();
+ pValue[0].Name = UNO_NAME_SORT_KEY;
+ pValue[0].Value <<= sal_Int16(pKey->eField);
+ pValue[1].Name = UNO_NAME_IS_SORT_ASCENDING;
+ pValue[1].Value <<= pKey->bSortAscending;
+ }
+ rVal <<= aRet;
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwAuthorityFieldType::PutValue( const Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ case FIELD_PROP_PAR2:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ const sal_Unicode uSet = !sTmp.isEmpty() ? sTmp[0] : 0;
+ if( FIELD_PROP_PAR1 == nWhichId )
+ m_cPrefix = uSet;
+ else
+ m_cSuffix = uSet;
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ SetSortAlgorithm(sTmp);
+ break;
+ }
+ case FIELD_PROP_BOOL1:
+ m_bIsSequence = *o3tl::doAccess<bool>(rAny);
+ break;
+ case FIELD_PROP_BOOL2:
+ m_bSortByDocument = *o3tl::doAccess<bool>(rAny);
+ break;
+
+ case FIELD_PROP_LOCALE:
+ {
+ css::lang::Locale aLocale;
+ if( rAny >>= aLocale )
+ SetLanguage( LanguageTag::convertToLanguageType( aLocale ));
+ }
+ break;
+
+ case FIELD_PROP_PROP_SEQ:
+ {
+ Sequence<PropertyValues> aSeq;
+ if( rAny >>= aSeq )
+ {
+ m_SortKeyArr.clear();
+ const PropertyValues* pValues = aSeq.getConstArray();
+ //TODO: Limiting to the first SAL_MAX_UINT16 elements of aSeq so that size of
+ // m_SortKeyArr remains in range of sal_uInt16, as GetSortKeyCount and GetSortKey
+ // still expect m_SortKeyArr to be indexed by sal_uInt16:
+ auto nSize = std::min<sal_Int32>(aSeq.getLength(), SAL_MAX_UINT16);
+ for(sal_Int32 i = 0; i < nSize; i++)
+ {
+ SwTOXSortKey aSortKey;
+ for(const PropertyValue& rValue : pValues[i])
+ {
+ if(rValue.Name == UNO_NAME_SORT_KEY)
+ {
+ sal_Int16 nVal = -1; rValue.Value >>= nVal;
+ if(nVal >= 0 && nVal < AUTH_FIELD_END)
+ aSortKey.eField = static_cast<ToxAuthorityField>(nVal);
+ }
+ else if(rValue.Name == UNO_NAME_IS_SORT_ASCENDING)
+ {
+ aSortKey.bSortAscending = *o3tl::doAccess<bool>(rValue.Value);
+ }
+ }
+ m_SortKeyArr.push_back(aSortKey);
+ }
+ }
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwAuthorityFieldType::SwClientNotify(const SwModify&, const SfxHint& rHint)
+{
+ //re-generate positions of the fields
+ DelSequenceArray();
+ CallSwClientNotify(rHint);
+}
+
+sal_uInt16 SwAuthorityFieldType::GetSortKeyCount() const
+{
+ return m_SortKeyArr.size();
+}
+
+const SwTOXSortKey* SwAuthorityFieldType::GetSortKey(sal_uInt16 nIdx) const
+{
+ if(m_SortKeyArr.size() > nIdx)
+ return &m_SortKeyArr[nIdx];
+ OSL_FAIL("Sort key not found");
+ return nullptr;
+}
+
+void SwAuthorityFieldType::SetSortKeys(sal_uInt16 nKeyCount, SwTOXSortKey const aKeys[])
+{
+ m_SortKeyArr.clear();
+ for(sal_uInt16 i = 0; i < nKeyCount; i++)
+ if(aKeys[i].eField < AUTH_FIELD_END)
+ m_SortKeyArr.push_back(aKeys[i]);
+}
+
+SwAuthorityField::SwAuthorityField( SwAuthorityFieldType* pInitType,
+ std::u16string_view rFieldContents )
+ : SwField(pInitType)
+ , m_nTempSequencePos( -1 )
+ , m_nTempSequencePosRLHidden( -1 )
+{
+ m_xAuthEntry = pInitType->AddField( rFieldContents );
+}
+
+SwAuthorityField::SwAuthorityField( SwAuthorityFieldType* pInitType,
+ SwAuthEntry* pAuthEntry )
+ : SwField( pInitType )
+ , m_xAuthEntry( pAuthEntry )
+ , m_nTempSequencePos( -1 )
+ , m_nTempSequencePosRLHidden( -1 )
+{
+}
+
+SwAuthorityField::~SwAuthorityField()
+{
+ static_cast<SwAuthorityFieldType* >(GetTyp())->RemoveField(m_xAuthEntry.get());
+}
+
+OUString SwAuthorityField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ return ConditionalExpandAuthIdentifier(pLayout);
+}
+
+OUString SwAuthorityField::ConditionalExpandAuthIdentifier(
+ SwRootFrame const*const pLayout) const
+{
+ SwAuthorityFieldType* pAuthType = static_cast<SwAuthorityFieldType*>(GetTyp());
+ OUString sRet;
+ if(pAuthType->GetPrefix())
+ sRet = OUString(pAuthType->GetPrefix());
+
+ if( pAuthType->IsSequence() )
+ {
+ sal_IntPtr & rnTempSequencePos(pLayout && pLayout->IsHideRedlines()
+ ? m_nTempSequencePosRLHidden : m_nTempSequencePos);
+ if(!pAuthType->GetDoc()->getIDocumentFieldsAccess().IsExpFieldsLocked())
+ rnTempSequencePos = pAuthType->GetSequencePos(m_xAuthEntry.get(), pLayout);
+ if (0 <= rnTempSequencePos)
+ sRet += OUString::number(rnTempSequencePos);
+ }
+ else
+ {
+ //TODO: Expand to: identifier, number sequence, ...
+ if(m_xAuthEntry)
+ {
+ OUString sIdentifier(m_xAuthEntry->GetAuthorField(AUTH_FIELD_IDENTIFIER));
+ // tdf#107784 Use title if it's a ooxml citation
+ if (o3tl::starts_with(o3tl::trim(sIdentifier), u"CITATION"))
+ return m_xAuthEntry->GetAuthorField(AUTH_FIELD_TITLE);
+ else
+ sRet += sIdentifier;
+ }
+ }
+ if(pAuthType->GetSuffix())
+ sRet += OUStringChar(pAuthType->GetSuffix());
+ return sRet;
+}
+
+OUString SwAuthorityField::ExpandCitation(ToxAuthorityField eField,
+ SwRootFrame const*const pLayout) const
+{
+ SwAuthorityFieldType* pAuthType = static_cast<SwAuthorityFieldType*>(GetTyp());
+ OUString sRet;
+
+ if( pAuthType->IsSequence() )
+ {
+ sal_IntPtr & rnTempSequencePos(pLayout && pLayout->IsHideRedlines()
+ ? m_nTempSequencePosRLHidden : m_nTempSequencePos);
+ if(!pAuthType->GetDoc()->getIDocumentFieldsAccess().IsExpFieldsLocked())
+ rnTempSequencePos = pAuthType->GetSequencePos(m_xAuthEntry.get(), pLayout);
+ if (0 <= rnTempSequencePos)
+ sRet += OUString::number(rnTempSequencePos);
+ }
+ else
+ {
+ //TODO: Expand to: identifier, number sequence, ...
+ if(m_xAuthEntry)
+ sRet += m_xAuthEntry->GetAuthorField(eField);
+ }
+ return sRet;
+}
+
+std::unique_ptr<SwField> SwAuthorityField::Copy() const
+{
+ SwAuthorityFieldType* pAuthType = static_cast<SwAuthorityFieldType*>(GetTyp());
+ return std::make_unique<SwAuthorityField>(pAuthType, m_xAuthEntry.get());
+}
+
+const OUString & SwAuthorityField::GetFieldText(ToxAuthorityField eField) const
+{
+ return m_xAuthEntry->GetAuthorField( eField );
+}
+
+void SwAuthorityField::SetPar1(const OUString& rStr)
+{
+ SwAuthorityFieldType* pInitType = static_cast<SwAuthorityFieldType* >(GetTyp());
+ pInitType->RemoveField(m_xAuthEntry.get());
+ m_xAuthEntry = pInitType->AddField(rStr);
+}
+
+OUString SwAuthorityField::GetDescription() const
+{
+ return SwResId(STR_AUTHORITY_ENTRY);
+}
+
+OUString SwAuthorityField::GetAuthority(const SwRootFrame* pLayout, const SwForm* pTOX) const
+{
+ OUString aText;
+
+ std::unique_ptr<SwForm> pDefaultTOX;
+ if (!pTOX)
+ {
+ pDefaultTOX = std::make_unique<SwForm>(TOX_AUTHORITIES);
+ pTOX = pDefaultTOX.get();
+ }
+
+ SwAuthorityFieldType* pFieldType = static_cast<SwAuthorityFieldType*>(GetTyp());
+ std::unique_ptr<SwTOXInternational> pIntl(pFieldType->CreateTOXInternational());
+
+ // This is based on SwTOXAuthority::GetLevel()
+ OUString sText = GetFieldText(AUTH_FIELD_AUTHORITY_TYPE);
+ ToxAuthorityType nAuthorityKind = AUTH_TYPE_ARTICLE;
+ if (pIntl->IsNumeric(sText))
+ nAuthorityKind = static_cast<ToxAuthorityType>(sText.toUInt32());
+ if (nAuthorityKind > AUTH_TYPE_END)
+ nAuthorityKind = AUTH_TYPE_ARTICLE;
+
+ // Must be incremented by 1, since the pattern 0 is for the heading
+ const SwFormTokens& aPattern = pTOX->GetPattern(static_cast<int>(nAuthorityKind) + 1);
+
+ for (const auto& rToken : aPattern)
+ {
+ switch (rToken.eTokenType)
+ {
+ case TOKEN_TAB_STOP:
+ {
+ aText += "\t";
+ break;
+ }
+ case TOKEN_TEXT:
+ {
+ aText += rToken.sText;
+ break;
+ }
+ case TOKEN_AUTHORITY:
+ {
+ ToxAuthorityField eField = static_cast<ToxAuthorityField>(rToken.nAuthorityField);
+
+ if (AUTH_FIELD_IDENTIFIER == eField)
+ {
+ // Why isn't there a way to get the identifier without parentheses???
+ OUString sTmp = ExpandField(true, pLayout);
+ if (sal_Unicode cPref = pFieldType->GetPrefix(); cPref && cPref != ' ')
+ sTmp = sTmp.copy(1);
+ if (sal_Unicode cSuff = pFieldType->GetSuffix(); cSuff && cSuff != ' ')
+ sTmp = sTmp.copy(0, sTmp.getLength() - 1);
+ aText += sTmp;
+ }
+ else if (AUTH_FIELD_AUTHORITY_TYPE == eField)
+ {
+ aText += SwAuthorityFieldType::GetAuthTypeName(nAuthorityKind);
+ }
+ else if (AUTH_FIELD_URL == eField)
+ {
+ aText += GetRelativeURI();
+ }
+ else
+ {
+ aText += GetFieldText(eField);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return aText;
+}
+
+SwAuthorityField::TargetType SwAuthorityField::GetTargetType() const
+{
+ return SwAuthorityField::TargetType(GetAuthEntry()->GetAuthorField(AUTH_FIELD_TARGET_TYPE).toInt32());
+}
+
+OUString SwAuthorityField::GetAbsoluteURL() const
+{
+ const OUString& rURL = GetAuthEntry()->GetAuthorField(
+ GetTargetType() == SwAuthorityField::TargetType::UseDisplayURL
+ ? AUTH_FIELD_URL : AUTH_FIELD_TARGET_URL);
+ SwDoc* pDoc = static_cast<SwAuthorityFieldType*>(GetTyp())->GetDoc();
+ SwDocShell* pDocShell = pDoc->GetDocShell();
+ OUString aBasePath = pDocShell->getDocumentBaseURL();
+ return INetURLObject::GetAbsURL(aBasePath, rURL, INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::WithCharset);
+}
+
+OUString SwAuthorityField::GetRelativeURI() const
+{
+ OUString sTmp = GetFieldText(AUTH_FIELD_URL);
+
+ SwDoc* pDoc = static_cast<SwAuthorityFieldType*>(GetTyp())->GetDoc();
+ SwDocShell* pDocShell = pDoc->GetDocShell();
+ const OUString aBaseURL = pDocShell->getDocumentBaseURL();
+ std::u16string_view aBaseURIScheme;
+ sal_Int32 nSep = aBaseURL.indexOf(':');
+ if (nSep != -1)
+ {
+ aBaseURIScheme = aBaseURL.subView(0, nSep);
+ }
+
+ uno::Reference<uri::XUriReferenceFactory> xUriReferenceFactory
+ = uri::UriReferenceFactory::create(comphelper::getProcessComponentContext());
+ uno::Reference<uri::XUriReference> xUriRef;
+ try
+ {
+ xUriRef = xUriReferenceFactory->parse(sTmp);
+ }
+ catch (const uno::Exception& rException)
+ {
+ SAL_WARN("sw.core",
+ "SwTOXAuthority::GetSourceURL: failed to parse url: " << rException.Message);
+ }
+ if (xUriRef.is() && xUriRef->getFragment().startsWith("page="))
+ {
+ xUriRef->clearFragment();
+ sTmp = xUriRef->getUriReference();
+ }
+
+ // convert to relative
+ bool bSaveRelFSys = officecfg::Office::Common::Save::URL::FileSystem::get();
+ if (xUriRef.is() && bSaveRelFSys && xUriRef->getScheme() == aBaseURIScheme)
+ {
+ sTmp = INetURLObject::GetRelURL(aBaseURL, sTmp);
+ }
+ return sTmp;
+}
+
+void SwAuthorityField::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwAuthorityField"));
+ SwField::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_xAuthEntry"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", m_xAuthEntry.get());
+ if (m_xAuthEntry.is())
+ {
+ m_xAuthEntry->dumpAsXml(pWriter);
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_nTempSequencePos"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
+ BAD_CAST(OString::number(m_nTempSequencePos).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_nTempSequencePosRLHidden"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
+ BAD_CAST(OString::number(m_nTempSequencePosRLHidden).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+const char* const aFieldNames[] =
+{
+ "Identifier",
+ "BibiliographicType",
+ "Address",
+ "Annote",
+ "Author",
+ "Booktitle",
+ "Chapter",
+ "Edition",
+ "Editor",
+ "Howpublished",
+ "Institution",
+ "Journal",
+ "Month",
+ "Note",
+ "Number",
+ "Organizations",
+ "Pages",
+ "Publisher",
+ "School",
+ "Series",
+ "Title",
+ "Report_Type",
+ "Volume",
+ "Year",
+ "URL",
+ "Custom1",
+ "Custom2",
+ "Custom3",
+ "Custom4",
+ "Custom5",
+ "ISBN",
+ "LocalURL",
+ "TargetType",
+ "TargetURL",
+};
+
+void SwAuthEntry::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwAuthEntry"));
+
+ for (int i = 0; i < AUTH_FIELD_END; ++i)
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_aAuthField"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("key"), BAD_CAST(aFieldNames[i]));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(m_aAuthFields[i].toUtf8().getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+bool SwAuthorityField::QueryValue( Any& rAny, sal_uInt16 /*nWhichId*/ ) const
+{
+ if(!GetTyp())
+ return false;
+ if(!m_xAuthEntry)
+ return false;
+ Sequence <PropertyValue> aRet(AUTH_FIELD_END);
+ PropertyValue* pValues = aRet.getArray();
+ for(int i = 0; i < AUTH_FIELD_END; ++i)
+ {
+ pValues[i].Name = OUString::createFromAscii(aFieldNames[i]);
+ const OUString& sField = m_xAuthEntry->GetAuthorField(static_cast<ToxAuthorityField>(i));
+ if(i == AUTH_FIELD_AUTHORITY_TYPE)
+ pValues[i].Value <<= sal_Int16(sField.toInt32());
+ else
+ pValues[i].Value <<= sField;
+ }
+ rAny <<= aRet;
+ /* FIXME: it is weird that we always return false here */
+ return false;
+}
+
+static sal_Int32 lcl_Find(std::u16string_view rFieldName)
+{
+ for(sal_Int32 i = 0; i < AUTH_FIELD_END; ++i)
+ if(o3tl::equalsAscii(rFieldName, aFieldNames[i]))
+ return i;
+ return -1;
+}
+
+bool SwAuthorityField::PutValue( const Any& rAny, sal_uInt16 /*nWhichId*/ )
+{
+ if(!GetTyp() || !m_xAuthEntry)
+ return false;
+
+ Sequence <PropertyValue> aParam;
+ if(!(rAny >>= aParam))
+ return false;
+
+ OUStringBuffer sBuf(+(AUTH_FIELD_END - 1));
+ comphelper::string::padToLength(sBuf, (AUTH_FIELD_END - 1), TOX_STYLE_DELIMITER);
+ OUString sToSet(sBuf.makeStringAndClear());
+ for(const PropertyValue& rParam : std::as_const(aParam))
+ {
+ const sal_Int32 nFound = lcl_Find(rParam.Name);
+ if(nFound >= 0)
+ {
+ OUString sContent;
+ if(AUTH_FIELD_AUTHORITY_TYPE == nFound)
+ {
+ sal_Int16 nVal = 0;
+ rParam.Value >>= nVal;
+ sContent = OUString::number(nVal);
+ }
+ else
+ rParam.Value >>= sContent;
+ sToSet = comphelper::string::setToken(sToSet, nFound, TOX_STYLE_DELIMITER, sContent);
+ }
+ }
+
+ static_cast<SwAuthorityFieldType*>(GetTyp())->RemoveField(m_xAuthEntry.get());
+ m_xAuthEntry = static_cast<SwAuthorityFieldType*>(GetTyp())->AddField(sToSet);
+
+ /* FIXME: it is weird that we always return false here */
+ return false;
+}
+
+SwFieldType* SwAuthorityField::ChgTyp( SwFieldType* pFieldTyp )
+{
+ SwAuthorityFieldType* pSrcTyp = static_cast<SwAuthorityFieldType*>(GetTyp()),
+ * pDstTyp = static_cast<SwAuthorityFieldType*>(pFieldTyp);
+ if( pSrcTyp != pDstTyp )
+ {
+ const SwAuthEntry* pSrcEntry = m_xAuthEntry.get();
+ m_xAuthEntry = pDstTyp->AppendField( *pSrcEntry );
+ pSrcTyp->RemoveField( pSrcEntry );
+ SwField::ChgTyp( pFieldTyp );
+ }
+ return pSrcTyp;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/cellfml.cxx b/sw/source/core/fields/cellfml.cxx
new file mode 100644
index 0000000000..7c8179f672
--- /dev/null
+++ b/sw/source/core/fields/cellfml.cxx
@@ -0,0 +1,1254 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include <float.h>
+#include <hintids.hxx>
+#include <hints.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <frmfmt.hxx>
+#include <layfrm.hxx>
+#include <cntfrm.hxx>
+#include <tabfrm.hxx>
+#include <doc.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <ndtxt.hxx>
+#include <swtable.hxx>
+#include <tblsel.hxx>
+#include <cellfml.hxx>
+#include <calc.hxx>
+#include <expfld.hxx>
+#include <usrfld.hxx>
+#include <flddat.hxx>
+#include <cellatr.hxx>
+#include <ndindex.hxx>
+#include <frameformats.hxx>
+#include <comphelper/string.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
+#include <utility>
+
+namespace
+{
+
+const sal_Unicode cRelSeparator = ',';
+const sal_Unicode cRelIdentifier = '\x12'; // CTRL-R
+
+enum
+{
+ cMAXSTACKSIZE = 50
+};
+
+}
+
+static const SwFrame* lcl_GetBoxFrame( const SwTableBox& rBox );
+static sal_Int32 lcl_GetLongBoxNum( OUString& rStr );
+static const SwTableBox* lcl_RelToBox( const SwTable& rTable,
+ const SwTableBox* pRefBox,
+ const OUString& sGetName);
+static OUString lcl_BoxNmToRel( const SwTable& rTable,
+ const SwTableNode& rTableNd,
+ const OUString& sRefBoxNm,
+ const OUString& sGetStr,
+ bool bExtrnlNm);
+
+/** Get value of this box.
+ *
+ * The value is comes from the first TextNode. If it starts with a number/
+ * formula then calculate it, if it starts with a field then get the value.
+ * All other conditions return 0 (and an error?).
+ */
+double SwTableBox::GetValue( SwTableCalcPara& rCalcPara ) const
+{
+ double nRet = 0;
+
+ if( rCalcPara.m_rCalc.IsCalcError() )
+ return nRet; // stop if there is already an error set
+
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // default: error
+
+ // no content box?
+ if( !m_pStartNode )
+ return nRet;
+
+ if( rCalcPara.IncStackCnt() )
+ return nRet;
+
+ rCalcPara.SetLastTableBox( this );
+
+ // Does it create a recursion?
+ SwTableBox* pBox = const_cast<SwTableBox*>(this);
+ if( rCalcPara.m_pBoxStack->find( pBox ) != rCalcPara.m_pBoxStack->end() )
+ return nRet; // already on the stack: error
+
+ // re-start with this box
+ rCalcPara.SetLastTableBox( this );
+
+ rCalcPara.m_pBoxStack->insert( pBox ); // add
+ do { // Middle-Check-Loop, so that we can jump from here. Used so that the box pointer
+ // will be removed from stack at the end.
+ SwDoc* pDoc = GetFrameFormat()->GetDoc();
+
+ if( const SwTableBoxFormula* pFormulaItem = GetFrameFormat()->GetItemIfSet(
+ RES_BOXATR_FORMULA, false ) )
+ {
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status
+ if( !pFormulaItem->IsValid() )
+ {
+ // calculate
+ const SwTable* pTmp = rCalcPara.m_pTable;
+ rCalcPara.m_pTable = &pBox->GetSttNd()->FindTableNode()->GetTable();
+ const_cast<SwTableBoxFormula*>(pFormulaItem)->Calc( rCalcPara, nRet );
+
+ if( !rCalcPara.IsStackOverflow() )
+ {
+ SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
+ SfxItemSetFixed<RES_BOXATR_BEGIN,RES_BOXATR_END-1> aTmp( pDoc->GetAttrPool() );
+ aTmp.Put( SwTableBoxValue( nRet ) );
+ if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT ))
+ aTmp.Put( SwTableBoxNumFormat( 0 ));
+ pFormat->SetFormatAttr( aTmp );
+ }
+ rCalcPara.m_pTable = pTmp;
+ }
+ else
+ nRet = GetFrameFormat()->GetTableBoxValue().GetValue();
+ break;
+ }
+ else if( const SwTableBoxValue* pBoxValueItem = pBox->GetFrameFormat()->GetItemIfSet(
+ RES_BOXATR_VALUE, false ) )
+ {
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status
+ nRet = pBoxValueItem->GetValue();
+ break;
+ }
+
+ SwTextNode* pTextNd = pDoc->GetNodes()[ m_pStartNode->GetIndex() + 1 ]->GetTextNode();
+ if( !pTextNd )
+ break;
+
+ sal_Int32 nSttPos = 0;
+ OUString sText = pTextNd->GetText();
+
+ // use text of the tracked changes
+ if ( sText.getLength() > 0 &&
+ sText[0] != CH_TXTATR_BREAKWORD && sText[0] != CH_TXTATR_INWORD )
+ {
+ sText = pTextNd->GetRedlineText();
+ }
+
+ while ( nSttPos < sText.getLength() && ( sText[nSttPos]==' ' || sText[nSttPos]=='\t' ) )
+ ++nSttPos;
+
+ // if there is a calculation field at position 1, get the value of it
+ const bool bOK = nSttPos<sText.getLength();
+ const sal_Unicode Char = bOK ? sText[nSttPos] : 0;
+ SwTextField * pTextField = nullptr;
+ if ( bOK && (Char==CH_TXTATR_BREAKWORD || Char==CH_TXTATR_INWORD) )
+ {
+ pTextField = static_txtattr_cast<SwTextField*>(pTextNd->GetTextAttrForCharAt(nSttPos, RES_TXTATR_FIELD));
+ }
+ if ( pTextField != nullptr )
+ {
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status
+
+ const SwField* pField = pTextField->GetFormatField().GetField();
+ switch ( pField->GetTyp()->Which() )
+ {
+ case SwFieldIds::SetExp:
+ nRet = static_cast<const SwSetExpField*>(pField)->GetValue(rCalcPara.m_pLayout);
+ break;
+ case SwFieldIds::User:
+ nRet = static_cast<const SwUserField*>(pField)->GetValue();
+ break;
+ case SwFieldIds::Table:
+ {
+ SwTableField* pTableField = const_cast<SwTableField*>(static_cast<const SwTableField*>(pField));
+ if( !pTableField->IsValid() )
+ {
+ // use the right table!
+ const SwTable* pTmp = rCalcPara.m_pTable;
+ rCalcPara.m_pTable = &pTextNd->FindTableNode()->GetTable();
+ pTableField->CalcField( rCalcPara );
+ rCalcPara.m_pTable = pTmp;
+ }
+ nRet = pTableField->GetValue();
+ }
+ break;
+
+ case SwFieldIds::DateTime:
+ nRet = static_cast<const SwDateTimeField*>( pField )->GetValue();
+ break;
+
+ case SwFieldIds::JumpEdit:
+ //JP 14.09.98: Bug 56112 - placeholder never have the right content!
+ nRet = 0;
+ break;
+
+ default:
+ nRet = rCalcPara.m_rCalc.Calculate( pField->ExpandField(true, nullptr) ).GetDouble();
+ }
+ }
+ else if ( nSttPos < sText.getLength()
+ && Char == CH_TXT_ATR_INPUTFIELDSTART )
+ {
+ const SwTextInputField * pTextInputField =
+ dynamic_cast< const SwTextInputField* >(
+ pTextNd->GetTextAttrAt( nSttPos, RES_TXTATR_INPUTFIELD ) );
+ if ( pTextInputField == nullptr )
+ break;
+ nRet = rCalcPara.m_rCalc.Calculate( pTextInputField->GetFieldContent() ).GetDouble();
+ }
+ else if ( Char != CH_TXTATR_BREAKWORD )
+ {
+ // result is 0 but no error!
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status
+
+ double aNum = 0.0;
+ sText = bOK ? sText.copy( nSttPos ) : OUString();
+ sal_uInt32 nFormatIndex = GetFrameFormat()->GetTableBoxNumFormat().GetValue();
+
+ SvNumberFormatter* pNumFormatr = pDoc->GetNumberFormatter();
+
+ const SvNumFormatType nFormatType = pNumFormatr->GetType( nFormatIndex );
+ if( nFormatType == SvNumFormatType::TEXT )
+ nFormatIndex = 0;
+ // JP 22.04.98: Bug 49659 - special treatment for percentages
+ else if( !sText.isEmpty() &&
+ SvNumFormatType::PERCENT == nFormatType)
+ {
+ sal_uInt32 nTmpFormat = 0;
+ if( pDoc->IsNumberFormat( sText, nTmpFormat, aNum ) &&
+ SvNumFormatType::NUMBER == pNumFormatr->GetType( nTmpFormat ))
+ sText += "%";
+ }
+
+ if( pDoc->IsNumberFormat( sText, nFormatIndex, aNum ))
+ nRet = aNum;
+ else
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::NaN ); // set for interoperability functions
+ }
+ // ?? otherwise it is an error
+ } while( false );
+
+ if( !rCalcPara.IsStackOverflow() )
+ {
+ rCalcPara.m_pBoxStack->erase( pBox ); // remove from stack
+ rCalcPara.DecStackCnt();
+ }
+
+ //JP 12.01.99: error detection, Bug 60794
+ if( DBL_MAX == nRet )
+ rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error
+
+ return nRet;
+}
+
+// structure needed for calculation of tables
+
+SwTableCalcPara::SwTableCalcPara(SwCalc& rCalculator, const SwTable& rTable,
+ SwRootFrame const*const pLayout)
+ : m_pLastTableBox(nullptr)
+ , m_nStackCount( 0 )
+ , m_nMaxSize( cMAXSTACKSIZE )
+ , m_pLayout(pLayout)
+ , m_pBoxStack( new SwTableSortBoxes )
+ , m_rCalc( rCalculator )
+ , m_pTable( &rTable )
+{
+}
+
+SwTableCalcPara::~SwTableCalcPara()
+{
+}
+
+bool SwTableCalcPara::CalcWithStackOverflow()
+{
+ // If a stack overflow was detected, redo with last box.
+ sal_uInt16 nSaveMaxSize = m_nMaxSize;
+
+ m_nMaxSize = cMAXSTACKSIZE - 5;
+ sal_uInt16 nCnt = 0;
+ SwTableBoxes aStackOverflows;
+ do {
+ SwTableBox* pBox = const_cast<SwTableBox*>(m_pLastTableBox);
+ m_nStackCount = 0;
+ m_rCalc.SetCalcError( SwCalcError::NONE );
+ aStackOverflows.insert( aStackOverflows.begin() + nCnt++, pBox );
+
+ m_pBoxStack->erase( pBox );
+ pBox->GetValue( *this );
+ } while( IsStackOverflow() );
+
+ m_nMaxSize = cMAXSTACKSIZE - 3; // decrease at least one level
+
+ // if recursion was detected
+ m_nStackCount = 0;
+ m_rCalc.SetCalcError( SwCalcError::NONE );
+ m_pBoxStack->clear();
+
+ while( !m_rCalc.IsCalcError() && nCnt )
+ {
+ aStackOverflows[ --nCnt ]->GetValue( *this );
+ if( IsStackOverflow() && !CalcWithStackOverflow() )
+ break;
+ }
+
+ m_nMaxSize = nSaveMaxSize;
+ aStackOverflows.clear();
+ return !m_rCalc.IsCalcError();
+}
+
+SwTableFormula::SwTableFormula( OUString aFormula )
+: m_sFormula( std::move(aFormula) )
+, m_eNmType( EXTRNL_NAME )
+, m_bValidValue( false )
+{
+}
+
+SwTableFormula::~SwTableFormula()
+{
+}
+
+void SwTableFormula::MakeFormula_( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ SwTableCalcPara* pCalcPara = static_cast<SwTableCalcPara*>(pPara);
+ if( pCalcPara->m_rCalc.IsCalcError() ) // stop if there is already an error set
+ return;
+
+ SwTableBox *pEndBox = nullptr;
+
+ rFirstBox = rFirstBox.copy(1); // erase label of this box
+ // a region in this area?
+ if( pLastBox )
+ {
+ pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64()));
+
+ // Is it actually a valid pointer?
+ if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() )
+ pEndBox = nullptr;
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+ SwTableBox* pSttBox = reinterpret_cast<SwTableBox*>(
+ sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64()));
+ // Is it actually a valid pointer?
+ if( rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() )
+ pSttBox = nullptr;
+
+ rNewStr.append(" ");
+ if( pEndBox && pSttBox ) // area?
+ {
+ // get all selected boxes via layout and calculate their values
+ SwSelBoxes aBoxes;
+ GetBoxes( *pSttBox, *pEndBox, aBoxes );
+
+ // don't use empty cells or cells with text content as zeroes in interoperability functions
+ sal_Int16 nUseOnlyNumber = -1;
+
+ rNewStr.append("(");
+ bool bDelim = false;
+ for (size_t n = 0; n < aBoxes.size() &&
+ !pCalcPara->m_rCalc.IsCalcError(); ++n)
+ {
+ const SwTableBox* pTableBox = aBoxes[n];
+ if ( pTableBox->getRowSpan() >= 1 )
+ {
+ double fVal = pTableBox->GetValue( *pCalcPara );
+
+ if ( pCalcPara->m_rCalc.IsCalcNotANumber() )
+ {
+ if ( nUseOnlyNumber == -1 )
+ {
+ OUString sFormula = rNewStr.toString().toAsciiUpperCase();
+ nUseOnlyNumber = sal_Int16(
+ sFormula.lastIndexOf("AVERAGE") > -1 ||
+ sFormula.lastIndexOf("COUNT") > -1 ||
+ sFormula.lastIndexOf("PRODUCT") > -1 );
+ }
+ if ( nUseOnlyNumber > 0 )
+ continue;
+ }
+
+ if( bDelim )
+ rNewStr.append(cListDelim);
+ bDelim = true;
+ rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal ));
+ }
+ }
+ rNewStr.append(")");
+ }
+ else if( pSttBox && !pLastBox ) // only the StartBox?
+ {
+ // JP 12.01.99: and no EndBox in the formula!
+ // calculate the value of the box
+ if ( pSttBox->getRowSpan() >= 1 )
+ {
+ rNewStr.append("(");
+ double fVal = pSttBox->GetValue( *pCalcPara );
+ // don't use empty cell or a cell with text content as zero in interoperability functions
+ // (except PRODUCT, where the result is correct anyway)
+ if ( !pCalcPara->m_rCalc.IsCalcNotANumber() ||
+ ( rNewStr.toString().toAsciiUpperCase().lastIndexOf("AVERAGE") == -1 &&
+ rNewStr.toString().toAsciiUpperCase().lastIndexOf("COUNT") == -1 ) )
+ {
+ rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal ));
+ }
+ rNewStr.append(")");
+ }
+ }
+ else
+ pCalcPara->m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error
+ rNewStr.append(" ");
+}
+
+void SwTableFormula::RelNmsToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ // relative name w.r.t. box name (external presentation)
+ SwNode* pNd = static_cast<SwNode*>(pPara);
+ OSL_ENSURE( pNd, "Field isn't in any TextNode" );
+ const SwTableBox *pBox = rTable.GetTableBox(
+ pNd->FindTableBoxStartNode()->GetIndex() );
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+ if( pLastBox )
+ {
+ const SwTableBox *pRelLastBox = lcl_RelToBox( rTable, pBox, *pLastBox );
+ if ( pRelLastBox )
+ rNewStr.append(pRelLastBox->GetName());
+ else
+ rNewStr.append("A1");
+ rNewStr.append(":");
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ const SwTableBox *pRelFirstBox = lcl_RelToBox( rTable, pBox, rFirstBox );
+
+ if (pRelFirstBox)
+ rNewStr.append(pRelFirstBox->GetName());
+ else
+ rNewStr.append("A1");
+
+ // get label for the box
+ rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]);
+}
+
+void SwTableFormula::RelBoxNmsToPtr( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ // relative name w.r.t. box name (internal presentation)
+ SwNode* pNd = static_cast<SwNode*>(pPara);
+ OSL_ENSURE( pNd, "Field not placed in any Node" );
+ const SwTableBox *pBox = rTable.GetTableBox(
+ pNd->FindTableBoxStartNode()->GetIndex() );
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+ if( pLastBox )
+ {
+ const SwTableBox *pRelLastBox = lcl_RelToBox( rTable, pBox, *pLastBox );
+ if ( pRelLastBox )
+ rNewStr.append(reinterpret_cast<sal_IntPtr>(pRelLastBox));
+ else
+ rNewStr.append("0");
+ rNewStr.append(":");
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ const SwTableBox *pRelFirstBox = lcl_RelToBox( rTable, pBox, rFirstBox );
+ if ( pRelFirstBox )
+ rNewStr.append(reinterpret_cast<sal_IntPtr>(pRelFirstBox));
+ else
+ rNewStr.append("0");
+
+ // get label for the box
+ rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]);
+}
+
+void SwTableFormula::BoxNmsToRelNm( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ // box name (external presentation) w.r.t. relative name
+ SwNode* pNd = static_cast<SwNode*>(pPara);
+ OSL_ENSURE( pNd, "Field not placed in any Node" );
+ const SwTableNode* pTableNd = pNd->FindTableNode();
+
+ OUString sRefBoxNm;
+ if( &pTableNd->GetTable() == &rTable )
+ {
+ const SwTableBox *pBox = rTable.GetTableBox(
+ pNd->FindTableBoxStartNode()->GetIndex() );
+ OSL_ENSURE( pBox, "Field not placed in any Table" );
+ sRefBoxNm = pBox->GetName();
+ }
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+ if( pLastBox )
+ {
+ rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, *pLastBox,
+ m_eNmType == EXTRNL_NAME ));
+ rNewStr.append(":");
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, rFirstBox,
+ m_eNmType == EXTRNL_NAME ));
+
+ // get label for the box
+ rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]);
+}
+
+void SwTableFormula::PtrToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* ) const
+{
+ // area in these parentheses?
+ SwTableBox* pBox;
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+ if( pLastBox )
+ {
+ pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64()));
+
+ // Is it actually a valid pointer?
+ if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() )
+ rNewStr.append(pBox->GetName());
+ else
+ rNewStr.append("?");
+ rNewStr.append(":");
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64()));
+ // Is it actually a valid pointer?
+ if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() )
+ rNewStr.append(pBox->GetName());
+ else
+ rNewStr.append("?");
+
+ // get label for the box
+ rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]);
+}
+
+void SwTableFormula::BoxNmsToPtr( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* ) const
+{
+ // area in these parentheses?
+ const SwTableBox* pBox;
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+ if( pLastBox )
+ {
+ pBox = rTable.GetTableBox( *pLastBox );
+ rNewStr.append(OUString::number(reinterpret_cast<sal_IntPtr>(pBox)) +
+ ":");
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ pBox = rTable.GetTableBox( rFirstBox );
+ rNewStr.append(OUString::number(reinterpret_cast<sal_IntPtr>(pBox))
+ + OUStringChar(rFirstBox[ rFirstBox.getLength()-1 ])); // get label for the box
+}
+
+/// create external formula (for UI)
+void SwTableFormula::PtrToBoxNm( const SwTable* pTable )
+{
+ const SwNode* pNd = nullptr;
+ FnScanFormula fnFormula = nullptr;
+ switch (m_eNmType)
+ {
+ case INTRNL_NAME:
+ if( pTable )
+ fnFormula = &SwTableFormula::PtrToBoxNms;
+ break;
+ case REL_NAME:
+ if( pTable )
+ {
+ fnFormula = &SwTableFormula::RelNmsToBoxNms;
+ pNd = GetNodeOfFormula();
+ }
+ break;
+ case EXTRNL_NAME:
+ return;
+ }
+ m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) );
+ m_eNmType = EXTRNL_NAME;
+}
+
+/// create internal formula (in CORE)
+void SwTableFormula::BoxNmToPtr( const SwTable* pTable )
+{
+ const SwNode* pNd = nullptr;
+ FnScanFormula fnFormula = nullptr;
+ switch (m_eNmType)
+ {
+ case EXTRNL_NAME:
+ if( pTable )
+ fnFormula = &SwTableFormula::BoxNmsToPtr;
+ break;
+ case REL_NAME:
+ if( pTable )
+ {
+ fnFormula = &SwTableFormula::RelBoxNmsToPtr;
+ pNd = GetNodeOfFormula();
+ }
+ break;
+ case INTRNL_NAME:
+ return;
+ }
+ m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) );
+ m_eNmType = INTRNL_NAME;
+}
+
+/// create relative formula (for copy)
+void SwTableFormula::ToRelBoxNm( const SwTable* pTable )
+{
+ const SwNode* pNd = nullptr;
+ FnScanFormula fnFormula = nullptr;
+ switch (m_eNmType)
+ {
+ case INTRNL_NAME:
+ case EXTRNL_NAME:
+ if( pTable )
+ {
+ fnFormula = &SwTableFormula::BoxNmsToRelNm;
+ pNd = GetNodeOfFormula();
+ }
+ break;
+ case REL_NAME:
+ return;
+ }
+ m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) );
+ m_eNmType = REL_NAME;
+}
+
+OUString SwTableFormula::ScanString( FnScanFormula fnFormula, const SwTable& rTable,
+ void* pPara ) const
+{
+ OUStringBuffer aStr;
+ sal_Int32 nFormula = 0;
+ sal_Int32 nEnd = 0;
+
+ do {
+ // If the formula is preceded by a name, use this table!
+ const SwTable* pTable = &rTable;
+
+ sal_Int32 nStt = m_sFormula.indexOf( '<', nFormula );
+ if ( nStt>=0 )
+ {
+ while ( nStt>=0 )
+ {
+ const sal_Int32 nNxt = nStt+1;
+ if (nNxt>=m_sFormula.getLength())
+ {
+ nStt = -1;
+ break;
+ }
+ if ( m_sFormula[nNxt]!=' ' && m_sFormula[nNxt]!='=' )
+ break;
+ nStt = m_sFormula.indexOf( '<', nNxt );
+ }
+
+ if ( nStt>=0 )
+ // Start searching from current position, which is valid for sure
+ nEnd = m_sFormula.indexOf( '>', nStt );
+ }
+ if (nStt<0 || nEnd<0 )
+ {
+ // set the rest and finish
+ aStr.append(m_sFormula.subView(nFormula));
+ break;
+ }
+
+ // write beginning
+ aStr.append(m_sFormula.subView(nFormula, nStt - nFormula));
+
+ if (fnFormula)
+ {
+ sal_Int32 nSeparator = 0;
+ // Is a table name preceded?
+ // JP 16.02.99: SplitMergeBoxNm take care of the name themself
+ // JP 22.02.99: Linux compiler needs cast
+ // JP 28.06.99: rel. BoxName has no preceding tablename!
+ if( fnFormula != &SwTableFormula::SplitMergeBoxNm_ &&
+ m_sFormula.getLength()>(nStt+1) && cRelIdentifier != m_sFormula[nStt+1] &&
+ (nSeparator = m_sFormula.indexOf( '.', nStt ))>=0
+ && nSeparator < nEnd )
+ {
+ OUString sTableNm( m_sFormula.copy( nStt, nEnd - nStt ));
+
+ // If there are dots in the name, then they appear in pairs (e.g. A1.1.1)!
+ if( (comphelper::string::getTokenCount(sTableNm, '.') - 1) & 1 )
+ {
+ sTableNm = sTableNm.copy( 0, nSeparator - nStt );
+
+ // when creating a formula the table name is unwanted
+ if( fnFormula != &SwTableFormula::MakeFormula_ )
+ aStr.append(sTableNm);
+ nStt = nSeparator;
+
+ sTableNm = sTableNm.copy( 1 ); // delete separator
+ if( sTableNm != rTable.GetFrameFormat()->GetName() )
+ {
+ // then search for table
+ const SwTable* pFnd = FindTable(
+ *rTable.GetFrameFormat()->GetDoc(),
+ sTableNm );
+ if( pFnd )
+ pTable = pFnd;
+ // ??
+ OSL_ENSURE( pFnd, "No table found. What now?" );
+ }
+ }
+ }
+
+ OUString sBox( m_sFormula.copy( nStt, nEnd - nStt + 1 ));
+ // area in these parentheses?
+ nSeparator = m_sFormula.indexOf( ':', nStt );
+ if ( nSeparator>=0 && nSeparator<nEnd )
+ {
+ // without opening parenthesis
+ OUString aFirstBox( m_sFormula.copy( nStt+1, nSeparator - nStt - 1 ));
+ (this->*fnFormula)( *pTable, aStr, sBox, &aFirstBox, pPara );
+ }
+ else
+ (this->*fnFormula)( *pTable, aStr, sBox, nullptr, pPara );
+ }
+
+ nFormula = nEnd+1;
+ } while( true );
+ return aStr.makeStringAndClear();
+}
+
+const SwTable* SwTableFormula::FindTable( SwDoc& rDoc, std::u16string_view rNm )
+{
+ const sw::TableFrameFormats& rTableFormats = *rDoc.GetTableFrameFormats();
+ const SwTable* pTmpTable = nullptr, *pRet = nullptr;
+ for( auto nFormatCnt = rTableFormats.size(); nFormatCnt; )
+ {
+ SwTableFormat* pFormat = rTableFormats[ --nFormatCnt ];
+ // if we are called from Sw3Writer, a number is dependent on the format name
+ SwTableBox* pFBox;
+ if ( rNm == o3tl::getToken(pFormat->GetName(), 0, 0x0a) &&
+ nullptr != ( pTmpTable = SwTable::FindTable( pFormat ) ) &&
+ nullptr != (pFBox = pTmpTable->GetTabSortBoxes()[0] ) &&
+ pFBox->GetSttNd() &&
+ pFBox->GetSttNd()->GetNodes().IsDocNodes() )
+ {
+ // a table in the normal NodesArr
+ pRet = pTmpTable;
+ break;
+ }
+ }
+ return pRet;
+}
+
+static const SwFrame* lcl_GetBoxFrame( const SwTableBox& rBox )
+{
+ SwNodeIndex aIdx( *rBox.GetSttNd() );
+ SwContentNode* pCNd = aIdx.GetNodes().GoNext( &aIdx );
+ OSL_ENSURE( pCNd, "Box has no TextNode" );
+ Point aPt; // get the first frame of the layout - table headline
+ std::pair<Point, bool> const tmp(aPt, false);
+ return pCNd->getLayoutFrame(pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp);
+}
+
+static sal_Int32 lcl_GetLongBoxNum( OUString& rStr )
+{
+ sal_Int32 nRet;
+ const sal_Int32 nPos = rStr.indexOf( cRelSeparator );
+ if ( nPos<0 )
+ {
+ nRet = rStr.toInt32();
+ rStr.clear();
+ }
+ else
+ {
+ nRet = o3tl::toInt32(rStr.subView( 0, nPos ));
+ rStr = rStr.copy( nPos+1 );
+ }
+ return nRet;
+}
+
+static const SwTableBox* lcl_RelToBox( const SwTable& rTable,
+ const SwTableBox* pRefBox,
+ const OUString& _sGetName )
+{
+ // get line
+ const SwTableBox* pBox = nullptr;
+ OUString sGetName = _sGetName;
+
+ // Is it really a relative value?
+ if ( cRelIdentifier == sGetName[0] ) // yes
+ {
+ if( !pRefBox )
+ return nullptr;
+
+ sGetName = sGetName.copy( 1 );
+
+ const SwTableLines* pLines = &rTable.GetTabLines();
+ const SwTableBoxes* pBoxes;
+ const SwTableLine* pLine;
+
+ // determine starting values of the box,...
+ pBox = pRefBox;
+ pLine = pBox->GetUpper();
+ while( pLine->GetUpper() )
+ {
+ pBox = pLine->GetUpper();
+ pLine = pBox->GetUpper();
+ }
+ sal_uInt16 nSttBox = pLine->GetBoxPos( pBox );
+ sal_uInt16 nSttLine = rTable.GetTabLines().GetPos( pLine );
+
+ const sal_Int32 nBoxOffset = lcl_GetLongBoxNum( sGetName ) + nSttBox;
+ const sal_Int32 nLineOffset = lcl_GetLongBoxNum( sGetName ) + nSttLine;
+
+ if( nBoxOffset < 0 ||
+ nLineOffset < 0 )
+ return nullptr;
+
+ if( o3tl::make_unsigned(nLineOffset) >= pLines->size() )
+ return nullptr;
+
+ pLine = (*pLines)[ nLineOffset ];
+
+ // ... then search the box
+ pBoxes = &pLine->GetTabBoxes();
+ if( o3tl::make_unsigned(nBoxOffset) >= pBoxes->size() )
+ return nullptr;
+ pBox = (*pBoxes)[ nBoxOffset ];
+
+ while (!sGetName.isEmpty())
+ {
+ nSttBox = SwTable::GetBoxNum( sGetName );
+ pLines = &pBox->GetTabLines();
+ if( nSttBox )
+ --nSttBox;
+
+ nSttLine = SwTable::GetBoxNum( sGetName );
+
+ // determine line
+ if( !nSttLine || nSttLine > pLines->size() )
+ break;
+ pLine = (*pLines)[ nSttLine-1 ];
+
+ // determine box
+ pBoxes = &pLine->GetTabBoxes();
+ if( nSttBox >= pBoxes->size() )
+ break;
+ pBox = (*pBoxes)[ nSttBox ];
+ }
+
+ if( pBox )
+ {
+ if( !pBox->GetSttNd() )
+ // "bubble up" to first box
+ while( !pBox->GetTabLines().empty() )
+ pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
+ }
+ }
+ else
+ {
+ // otherwise it is an absolute external presentation
+ pBox = rTable.GetTableBox( sGetName );
+ }
+ return pBox;
+}
+
+static OUString lcl_BoxNmToRel( const SwTable& rTable, const SwTableNode& rTableNd,
+ const OUString& _sRefBoxNm, const OUString& _sTmp, bool bExtrnlNm )
+{
+ OUString sTmp = _sTmp;
+ OUString sRefBoxNm = _sRefBoxNm;
+ if( !bExtrnlNm )
+ {
+ // convert into external presentation
+ SwTableBox* pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(sTmp.toInt64()));
+ if( rTable.GetTabSortBoxes().find( pBox ) == rTable.GetTabSortBoxes().end() )
+ return OUString('?');
+ sTmp = pBox->GetName();
+ }
+
+ // If the formula is spanning over a table then keep external presentation
+ if( &rTable == &rTableNd.GetTable() )
+ {
+ tools::Long nBox = SwTable::GetBoxNum( sTmp, true );
+ nBox -= SwTable::GetBoxNum( sRefBoxNm, true );
+ tools::Long nLine = SwTable::GetBoxNum( sTmp );
+ nLine -= SwTable::GetBoxNum( sRefBoxNm );
+
+ const OUString sCpy = sTmp; //JP 01.11.95: add rest from box name
+
+ sTmp = OUStringChar(cRelIdentifier) + OUString::number( nBox )
+ + OUStringChar(cRelSeparator) + OUString::number( nLine );
+
+ if (!sCpy.isEmpty())
+ {
+ sTmp += OUStringChar(cRelSeparator) + sCpy;
+ }
+ }
+
+ if (sTmp.endsWith(">"))
+ return sTmp.copy(0, sTmp.getLength()-1 );
+
+ return sTmp;
+}
+
+void SwTableFormula::GetBoxesOfFormula( const SwTable& rTable,
+ SwSelBoxes& rBoxes )
+{
+ rBoxes.clear();
+
+ BoxNmToPtr( &rTable );
+ ScanString( &SwTableFormula::GetFormulaBoxes, rTable, &rBoxes );
+}
+
+void SwTableFormula::GetFormulaBoxes( const SwTable& rTable, OUStringBuffer& ,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ SwSelBoxes* pBoxes = static_cast<SwSelBoxes*>(pPara);
+ SwTableBox* pEndBox = nullptr;
+
+ rFirstBox = rFirstBox.copy(1); // delete box label
+ // area in these parentheses?
+ if( pLastBox )
+ {
+ pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64()));
+
+ // Is it actually a valid pointer?
+ if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() )
+ pEndBox = nullptr;
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+ }
+
+ SwTableBox *pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64()));
+ // Is it actually a valid pointer?
+ if( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() )
+ return;
+
+ if ( pEndBox ) // area?
+ {
+ // get all selected boxes via layout and calculate their values
+ SwSelBoxes aBoxes;
+ GetBoxes( *pSttBox, *pEndBox, aBoxes );
+ pBoxes->insert( aBoxes );
+ }
+ else // only the StartBox?
+ pBoxes->insert( pSttBox );
+}
+
+void SwTableFormula::GetBoxes( const SwTableBox& rSttBox,
+ const SwTableBox& rEndBox,
+ SwSelBoxes& rBoxes )
+{
+ // get all selected boxes via layout
+ const SwLayoutFrame *pStt, *pEnd;
+ const SwFrame* pFrame = lcl_GetBoxFrame( rSttBox );
+ pStt = pFrame ? pFrame->GetUpper() : nullptr;
+ pFrame = lcl_GetBoxFrame( rEndBox );
+ pEnd = pFrame ? pFrame->GetUpper() : nullptr;
+ if( !pStt || !pEnd )
+ return ; // no valid selection
+
+ GetTableSel( pStt, pEnd, rBoxes, nullptr );
+
+ const SwTable* pTable = pStt->FindTabFrame()->GetTable();
+
+ // filter headline boxes
+ if( pTable->GetRowsToRepeat() <= 0 )
+ return;
+
+ do { // middle-check loop
+ const SwTableLine* pLine = rSttBox.GetUpper();
+ while( pLine->GetUpper() )
+ pLine = pLine->GetUpper()->GetUpper();
+
+ if( pTable->IsHeadline( *pLine ) )
+ break; // headline in this area!
+
+ // maybe start and end are swapped
+ pLine = rEndBox.GetUpper();
+ while ( pLine->GetUpper() )
+ pLine = pLine->GetUpper()->GetUpper();
+
+ if( pTable->IsHeadline( *pLine ) )
+ break; // headline in this area!
+
+ const SwTabFrame *pStartTable = pStt->FindTabFrame();
+ const SwTabFrame *pEndTable = pEnd->FindTabFrame();
+
+ if (pStartTable == pEndTable) // no split table
+ break;
+
+ // then remove table headers
+ for (size_t n = 0; n < rBoxes.size(); ++n)
+ {
+ pLine = rBoxes[n]->GetUpper();
+ while( pLine->GetUpper() )
+ pLine = pLine->GetUpper()->GetUpper();
+
+ if( pTable->IsHeadline( *pLine ) )
+ rBoxes.erase( rBoxes.begin() + n-- );
+ }
+ } while( false );
+}
+
+/// Are all boxes valid that are referenced by the formula?
+void SwTableFormula::HasValidBoxes_( const SwTable& rTable, OUStringBuffer& ,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ bool* pBValid = static_cast<bool*>(pPara);
+ if( !(*pBValid) ) // wrong is wrong
+ return;
+
+ SwTableBox* pSttBox = nullptr, *pEndBox = nullptr;
+ rFirstBox = rFirstBox.copy(1); // delete identifier of box
+
+ // area in this parenthesis?
+ if( pLastBox )
+ rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 );
+
+ switch (m_eNmType)
+ {
+ case INTRNL_NAME:
+ if( pLastBox )
+ pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64()));
+ pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64()));
+ break;
+
+ case REL_NAME:
+ {
+ const SwNode* pNd = GetNodeOfFormula();
+ const SwTableBox* pBox = !pNd ? nullptr
+ : const_cast<SwTableBox *>(rTable.GetTableBox(
+ pNd->FindTableBoxStartNode()->GetIndex() ));
+ if( pLastBox )
+ pEndBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, *pLastBox ));
+ pSttBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, rFirstBox ));
+ }
+ break;
+
+ case EXTRNL_NAME:
+ if( pLastBox )
+ pEndBox = const_cast<SwTableBox*>(rTable.GetTableBox( *pLastBox ));
+ pSttBox = const_cast<SwTableBox*>(rTable.GetTableBox( rFirstBox ));
+ break;
+ }
+
+ // Are these valid pointers?
+ if( ( pLastBox &&
+ ( !pEndBox || rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) ) ||
+ ( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) )
+ *pBValid = false;
+}
+
+bool SwTableFormula::HasValidBoxes() const
+{
+ bool bRet = true;
+ const SwNode* pNd = GetNodeOfFormula();
+ if( pNd && nullptr != ( pNd = pNd->FindTableNode() ) )
+ ScanString( &SwTableFormula::HasValidBoxes_,
+ static_cast<const SwTableNode*>(pNd)->GetTable(), &bRet );
+ return bRet;
+}
+
+sal_uInt16 SwTableFormula::GetLnPosInTable( const SwTable& rTable, const SwTableBox* pBox )
+{
+ sal_uInt16 nRet = USHRT_MAX;
+ if( pBox )
+ {
+ const SwTableLine* pLn = pBox->GetUpper();
+ while( pLn->GetUpper() )
+ pLn = pLn->GetUpper()->GetUpper();
+ nRet = rTable.GetTabLines().GetPos( pLn );
+ }
+ return nRet;
+}
+
+void SwTableFormula::SplitMergeBoxNm_( const SwTable& rTable, OUStringBuffer& rNewStr,
+ OUString& rFirstBox, OUString* pLastBox, void* pPara ) const
+{
+ SwTableFormulaUpdate& rTableUpd = *static_cast<SwTableFormulaUpdate*>(pPara);
+
+ rNewStr.append(rFirstBox[0]); // get label for the box
+ rFirstBox = rFirstBox.copy(1);
+
+ OUString sTableNm;
+ const SwTable* pTable = &rTable;
+
+ OUString* pTableNmBox = pLastBox ? pLastBox : &rFirstBox;
+
+ const sal_Int32 nLastBoxLen = pTableNmBox->getLength();
+ const sal_Int32 nSeparator = pTableNmBox->indexOf('.');
+ if ( nSeparator>=0 &&
+ // If there are dots in the name, then these appear in pairs (e.g. A1.1.1)!
+ (comphelper::string::getTokenCount(*pTableNmBox, '.') - 1) & 1 )
+ {
+ sTableNm = pTableNmBox->copy( 0, nSeparator );
+ *pTableNmBox = pTableNmBox->copy( nSeparator + 1); // remove dot
+ const SwTable* pFnd = FindTable( *rTable.GetFrameFormat()->GetDoc(), sTableNm );
+ if( pFnd )
+ pTable = pFnd;
+
+ if( TBL_MERGETBL == rTableUpd.m_eFlags )
+ {
+ if( pFnd )
+ {
+ if( pFnd == rTableUpd.m_aData.pDelTable )
+ {
+ if( rTableUpd.m_pTable != &rTable ) // not the current one
+ rNewStr.append(rTableUpd.m_pTable->GetFrameFormat()->GetName() + "."); // set new table name
+ rTableUpd.m_bModified = true;
+ }
+ else if( pFnd != rTableUpd.m_pTable ||
+ ( rTableUpd.m_pTable != &rTable && &rTable != rTableUpd.m_aData.pDelTable))
+ rNewStr.append(sTableNm + "."); // keep table name
+ else
+ rTableUpd.m_bModified = true;
+ }
+ else
+ rNewStr.append(sTableNm + "."); // keep table name
+ }
+ }
+ if( pTableNmBox == pLastBox )
+ rFirstBox = rFirstBox.copy( nLastBoxLen + 1 );
+
+ SwTableBox* pSttBox = nullptr, *pEndBox = nullptr;
+ switch (m_eNmType)
+ {
+ case INTRNL_NAME:
+ if( pLastBox )
+ pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64()));
+ pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64()));
+ break;
+
+ case REL_NAME:
+ {
+ const SwNode* pNd = GetNodeOfFormula();
+ const SwTableBox* pBox = pNd ? pTable->GetTableBox(
+ pNd->FindTableBoxStartNode()->GetIndex() ) : nullptr;
+ if( pLastBox )
+ pEndBox = const_cast<SwTableBox*>(lcl_RelToBox( *pTable, pBox, *pLastBox ));
+ pSttBox = const_cast<SwTableBox*>(lcl_RelToBox( *pTable, pBox, rFirstBox ));
+ }
+ break;
+
+ case EXTRNL_NAME:
+ if( pLastBox )
+ pEndBox = const_cast<SwTableBox*>(pTable->GetTableBox( *pLastBox ));
+ pSttBox = const_cast<SwTableBox*>(pTable->GetTableBox( rFirstBox ));
+ break;
+ }
+
+ if( pLastBox && pTable->GetTabSortBoxes().find( pEndBox ) == pTable->GetTabSortBoxes().end() )
+ pEndBox = nullptr;
+ if( pTable->GetTabSortBoxes().find( pSttBox ) == pTable->GetTabSortBoxes().end() )
+ pSttBox = nullptr;
+
+ if( TBL_SPLITTBL == rTableUpd.m_eFlags )
+ {
+ // Where are the boxes - in the old or in the new table?
+ bool bInNewTable = false;
+ if( pLastBox )
+ {
+ // It is the "first" box in this selection. It determines if the formula is placed in
+ // the new or the old table.
+ sal_uInt16 nEndLnPos = SwTableFormula::GetLnPosInTable( *pTable, pEndBox ),
+ nSttLnPos = SwTableFormula::GetLnPosInTable( *pTable, pSttBox );
+
+ if( USHRT_MAX != nSttLnPos && USHRT_MAX != nEndLnPos &&
+ ((rTableUpd.m_nSplitLine <= nSttLnPos) ==
+ (rTableUpd.m_nSplitLine <= nEndLnPos)) )
+ {
+ // stay in same table
+ bInNewTable = rTableUpd.m_nSplitLine <= nEndLnPos &&
+ pTable == rTableUpd.m_pTable;
+ }
+ else
+ {
+ // this is definitely an invalid formula, also mark as modified for Undo
+ rTableUpd.m_bModified = true;
+ if( pEndBox )
+ bInNewTable = USHRT_MAX != nEndLnPos &&
+ rTableUpd.m_nSplitLine <= nEndLnPos &&
+ pTable == rTableUpd.m_pTable;
+ }
+ }
+ else
+ {
+ sal_uInt16 nSttLnPos = SwTableFormula::GetLnPosInTable( *pTable, pSttBox );
+ // Put it in the new table?
+ bInNewTable = USHRT_MAX != nSttLnPos &&
+ rTableUpd.m_nSplitLine <= nSttLnPos &&
+ pTable == rTableUpd.m_pTable;
+ }
+
+ // formula goes into new table
+ if( rTableUpd.m_bBehindSplitLine )
+ {
+ if( !bInNewTable )
+ {
+ rTableUpd.m_bModified = true;
+ rNewStr.append(rTableUpd.m_pTable->GetFrameFormat()->GetName() + ".");
+ }
+ else if( !sTableNm.isEmpty() )
+ rNewStr.append(sTableNm + ".");
+ }
+ else if( bInNewTable )
+ {
+ rTableUpd.m_bModified = true;
+ rNewStr.append(*rTableUpd.m_aData.pNewTableNm + ".");
+ }
+ else if( !sTableNm.isEmpty() )
+ rNewStr.append(sTableNm + ".");
+ }
+
+ if( pLastBox )
+ rNewStr.append(OUString::number(reinterpret_cast<sal_IntPtr>(pEndBox)) + ":");
+
+ rNewStr.append(OUString::number(reinterpret_cast<sal_IntPtr>(pSttBox))
+ + OUStringChar(rFirstBox[ rFirstBox.getLength()-1] ));
+}
+
+/// Create external formula but remember that the formula is placed in a split/merged table
+void SwTableFormula::ToSplitMergeBoxNm( SwTableFormulaUpdate& rTableUpd )
+{
+ const SwTable* pTable;
+ const SwNode* pNd = GetNodeOfFormula();
+ if( pNd && nullptr != ( pNd = pNd->FindTableNode() ))
+ pTable = &static_cast<const SwTableNode*>(pNd)->GetTable();
+ else
+ pTable = rTableUpd.m_pTable;
+
+ m_sFormula = ScanString( &SwTableFormula::SplitMergeBoxNm_, *pTable, static_cast<void*>(&rTableUpd) );
+ m_eNmType = INTRNL_NAME;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/chpfld.cxx b/sw/source/core/fields/chpfld.cxx
new file mode 100644
index 0000000000..a56a779e89
--- /dev/null
+++ b/sw/source/core/fields/chpfld.cxx
@@ -0,0 +1,309 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include <com/sun/star/text/ChapterFormat.hpp>
+#include <osl/diagnose.h>
+#include <doc.hxx>
+#include <frame.hxx>
+#include <rootfrm.hxx>
+#include <txtfrm.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <chpfld.hxx>
+#include <expfld.hxx>
+#include <unofldmid.h>
+#include <numrule.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+
+OUString removeControlChars(std::u16string_view sIn)
+{
+ OUStringBuffer aBuf(sIn);
+ aBuf = aBuf.replace('\n', ' ').replace('\t', ' ');
+ sal_Int32 nLen = aBuf.getLength();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if (aBuf[i] < ' ')
+ {
+ sal_Int32 j = i+1;
+ while (j<nLen && aBuf[j]<' ') ++j;
+ aBuf.remove(i, j-i);
+ nLen = aBuf.getLength();
+ }
+ }
+ return aBuf.makeStringAndClear();
+}
+
+}
+
+SwChapterFieldType::SwChapterFieldType()
+ : SwFieldType( SwFieldIds::Chapter )
+{
+}
+
+std::unique_ptr<SwFieldType> SwChapterFieldType::Copy() const
+{
+ return std::make_unique<SwChapterFieldType>();
+}
+
+// chapter field
+
+SwChapterField::SwChapterField(SwChapterFieldType* pTyp, sal_uInt32 nFormat)
+ : SwField(pTyp, nFormat)
+{
+}
+
+sal_uInt8 SwChapterField::GetLevel(SwRootFrame const*const pLayout) const
+{
+ State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
+ return rState.nLevel;
+}
+
+// this is called from UI or from import filters, so override both states
+void SwChapterField::SetLevel(sal_uInt8 nLev)
+{
+ m_State.nLevel = nLev;
+ m_StateRLHidden.nLevel = nLev;
+}
+
+const OUString& SwChapterField::GetNumber(SwRootFrame const*const pLayout) const
+{
+ State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
+ return rState.sNumber;
+}
+
+const OUString& SwChapterField::GetTitle(SwRootFrame const*const pLayout) const
+{
+ State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
+ return rState.sTitle;
+}
+
+OUString SwChapterField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ State const& rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
+ switch( GetFormat() )
+ {
+ case CF_TITLE:
+ return rState.sTitle;
+ case CF_NUMBER:
+ return rState.sPre + rState.sNumber + rState.sPost;
+ case CF_NUM_TITLE:
+ return rState.sPre + rState.sNumber + rState.sPost + rState.sLabelFollowedBy + rState.sTitle;
+ case CF_NUM_NOPREPST_TITLE:
+ return rState.sNumber + rState.sLabelFollowedBy + rState.sTitle;
+ }
+ // CF_NUMBER_NOPREPST
+ return rState.sNumber;
+}
+
+std::unique_ptr<SwField> SwChapterField::Copy() const
+{
+ std::unique_ptr<SwChapterField> pTmp(
+ new SwChapterField(static_cast<SwChapterFieldType*>(GetTyp()), GetFormat()));
+ pTmp->m_State = m_State;
+ pTmp->m_StateRLHidden = m_StateRLHidden;
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+// #i53420#
+void SwChapterField::ChangeExpansion(const SwFrame & rFrame,
+ const SwContentNode* pContentNode,
+ bool bSrchNum )
+{
+ SwDoc& rDoc = const_cast<SwDoc&>(pContentNode->GetDoc());
+
+ const SwTextNode* pTextNode = pContentNode->GetTextNode();
+ if (!pTextNode || !rFrame.IsInDocBody())
+ {
+ SwPosition aDummyPos( rDoc.GetNodes().GetEndOfContent() );
+ pTextNode = GetBodyTextNode( rDoc, aDummyPos, rFrame );
+ }
+
+ if ( pTextNode )
+ {
+ ChangeExpansion( *pTextNode, bSrchNum, rFrame.getRootFrame() );
+ }
+}
+
+void SwChapterField::ChangeExpansion(const SwTextNode &rTextNd, bool bSrchNum,
+ SwRootFrame const*const pLayout)
+{
+ State & rState(pLayout && pLayout->IsHideRedlines() ? m_StateRLHidden : m_State);
+ rState.sNumber.clear();
+ rState.sLabelFollowedBy.clear();
+ rState.sTitle.clear();
+ rState.sPost.clear();
+ rState.sPre.clear();
+
+ SwDoc& rDoc = const_cast<SwDoc&>(rTextNd.GetDoc());
+ const SwTextNode *pTextNd = rTextNd.FindOutlineNodeOfLevel(rState.nLevel, pLayout);
+ if( !pTextNd )
+ return;
+
+ if( bSrchNum )
+ {
+ const SwTextNode* pONd = pTextNd;
+ do {
+ if( pONd && pONd->GetTextColl() )
+ {
+ sal_uInt8 nPrevLvl = rState.nLevel;
+
+ OSL_ENSURE( pONd->GetAttrOutlineLevel() >= 0 && pONd->GetAttrOutlineLevel() <= MAXLEVEL,
+ "<SwChapterField::ChangeExpansion(..)> - outline node with inconsistent outline level. Serious defect." );
+ rState.nLevel = static_cast<sal_uInt8>(pONd->GetAttrOutlineLevel());
+
+ if (nPrevLvl < rState.nLevel)
+ rState.nLevel = nPrevLvl;
+ else if( SVX_NUM_NUMBER_NONE != rDoc.GetOutlineNumRule()
+ ->Get( rState.nLevel ).GetNumberingType() )
+ {
+ pTextNd = pONd;
+ break;
+ }
+
+ if (!rState.nLevel--)
+ break;
+ pONd = pTextNd->FindOutlineNodeOfLevel(rState.nLevel, pLayout);
+ }
+ else
+ break;
+ } while( true );
+ }
+
+ // get the number without Pre-/Post-fixstrings
+
+ if ( pTextNd->IsOutline() )
+ {
+ // correction of refactoring done by cws swnumtree:
+ // retrieve numbering string without prefix and suffix strings
+ // as stated in the above german comment.
+ rState.sNumber = pTextNd->GetNumString(false, MAXLEVEL, pLayout);
+
+ SwNumRule* pRule( pTextNd->GetNumRule() );
+ if ( pTextNd->IsCountedInList() && pRule )
+ {
+ int nListLevel = pTextNd->GetActualListLevel();
+ if (nListLevel < 0)
+ nListLevel = 0;
+ if (nListLevel >= MAXLEVEL)
+ nListLevel = MAXLEVEL - 1;
+
+ const SwNumFormat& rNFormat = pRule->Get(nListLevel);
+ rState.sPost = rNFormat.GetSuffix();
+ rState.sPre = rNFormat.GetPrefix();
+ rState.sLabelFollowedBy = removeControlChars(rNFormat.GetLabelFollowedByAsString());
+ }
+ }
+ else
+ {
+ rState.sNumber = "??";
+ }
+
+ rState.sTitle = removeControlChars(sw::GetExpandTextMerged(pLayout,
+ *pTextNd, false, false, ExpandMode(0)));
+}
+
+bool SwChapterField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BYTE1:
+ rAny <<= static_cast<sal_Int8>(m_State.nLevel);
+ break;
+
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nRet;
+ switch( GetFormat() )
+ {
+ case CF_NUMBER: nRet = text::ChapterFormat::NUMBER; break;
+ case CF_TITLE: nRet = text::ChapterFormat::NAME; break;
+ case CF_NUMBER_NOPREPST:
+ nRet = text::ChapterFormat::DIGIT;
+ break;
+ case CF_NUM_NOPREPST_TITLE:
+ nRet = text::ChapterFormat::NO_PREFIX_SUFFIX;
+ break;
+ case CF_NUM_TITLE:
+ default: nRet = text::ChapterFormat::NAME_NUMBER;
+ }
+ rAny <<= nRet;
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwChapterField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BYTE1:
+ {
+ sal_Int8 nTmp = 0;
+ rAny >>= nTmp;
+ if(nTmp >= 0 && nTmp < MAXLEVEL)
+ {
+ m_State.nLevel = nTmp;
+ m_StateRLHidden.nLevel = nTmp;
+ }
+ else
+ bRet = false;
+ break;
+ }
+
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nVal = 0;
+ rAny >>= nVal;
+ switch( nVal )
+ {
+ case text::ChapterFormat::NAME: SetFormat(CF_TITLE); break;
+ case text::ChapterFormat::NUMBER: SetFormat(CF_NUMBER); break;
+ case text::ChapterFormat::NO_PREFIX_SUFFIX:
+ SetFormat(CF_NUM_NOPREPST_TITLE);
+ break;
+ case text::ChapterFormat::DIGIT:
+ SetFormat(CF_NUMBER_NOPREPST);
+ break;
+
+ default: SetFormat(CF_NUM_TITLE);
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/dbfld.cxx b/sw/source/core/fields/dbfld.cxx
new file mode 100644
index 0000000000..867aac13c2
--- /dev/null
+++ b/sw/source/core/fields/dbfld.cxx
@@ -0,0 +1,870 @@
+/* -*- 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 <float.h>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <calc.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <docary.hxx>
+#include <fldbas.hxx>
+#include <dbfld.hxx>
+#include <dbmgr.hxx>
+#include <unofldmid.h>
+#include <o3tl/string_view.hxx>
+#include <utility>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star;
+
+/// replace database separator by dots for display
+static OUString lcl_DBSeparatorConvert(const OUString& aContent)
+{
+ return aContent.replaceAll(OUStringChar(DB_DELIM), ".");
+}
+
+// database field type
+
+SwDBFieldType::SwDBFieldType(SwDoc* pDocPtr, const OUString& rNam, SwDBData aDBData ) :
+ SwValueFieldType( pDocPtr, SwFieldIds::Database ),
+ m_aDBData(std::move(aDBData)),
+ m_sName(rNam),
+ m_sColumn(rNam),
+ m_nRefCnt(0)
+{
+ if(!m_aDBData.sDataSource.isEmpty() || !m_aDBData.sCommand.isEmpty())
+ {
+ m_sName = m_aDBData.sDataSource
+ + OUStringChar(DB_DELIM)
+ + m_aDBData.sCommand
+ + OUStringChar(DB_DELIM)
+ + m_sName;
+ }
+}
+
+SwDBFieldType::~SwDBFieldType()
+{
+}
+
+std::unique_ptr<SwFieldType> SwDBFieldType::Copy() const
+{
+ return std::make_unique<SwDBFieldType>(GetDoc(), m_sColumn, m_aDBData);
+}
+
+OUString SwDBFieldType::GetName() const
+{
+ return m_sName;
+}
+
+void SwDBFieldType::ReleaseRef()
+{
+ OSL_ENSURE(m_nRefCnt > 0, "RefCount < 0!");
+
+ if (--m_nRefCnt > 0)
+ return;
+
+ size_t nPos = 0;
+ for (auto const & pFieldType : *GetDoc()->getIDocumentFieldsAccess().GetFieldTypes())
+ {
+ if (pFieldType.get() == this)
+ break;
+ ++nPos;
+ }
+ if (nPos < GetDoc()->getIDocumentFieldsAccess().GetFieldTypes()->size())
+ {
+ GetDoc()->getIDocumentFieldsAccess().RemoveFieldType(nPos);
+ delete this;
+ }
+}
+
+void SwDBFieldType::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aDBData.sDataSource;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_aDBData.sCommand;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= m_sColumn;
+ break;
+ case FIELD_PROP_SHORT1:
+ rAny <<= m_aDBData.nCommandType;
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwDBFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aDBData.sDataSource;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_aDBData.sCommand;
+ break;
+ case FIELD_PROP_PAR3:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ if( sTmp != m_sColumn )
+ {
+ m_sColumn = sTmp;
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(auto pFormatField: vFields)
+ {
+ SwDBField* pDBField = static_cast<SwDBField*>(pFormatField->GetField());
+ pDBField->ClearInitialized();
+ pDBField->InitContent();
+ }
+ }
+ }
+ break;
+ case FIELD_PROP_SHORT1:
+ rAny >>= m_aDBData.nCommandType;
+ break;
+ default:
+ assert(false);
+ }
+}
+
+// database field
+
+SwDBField::SwDBField(SwDBFieldType* pTyp, sal_uInt32 nFormat)
+ : SwValueField(pTyp, nFormat),
+ m_nSubType(0),
+ m_bIsInBodyText(true),
+ m_bValidValue(false),
+ m_bInitialized(false)
+{
+ if (GetTyp())
+ static_cast<SwDBFieldType*>(GetTyp())->AddRef();
+ InitContent();
+}
+
+SwDBField::~SwDBField()
+{
+ if (GetTyp())
+ static_cast<SwDBFieldType*>(GetTyp())->ReleaseRef();
+}
+
+void SwDBField::InitContent()
+{
+ if (!IsInitialized())
+ {
+ m_aContent = "<" + static_cast<const SwDBFieldType*>(GetTyp())->GetColumnName() + ">";
+ }
+}
+
+void SwDBField::InitContent(const OUString& rExpansion)
+{
+ if (rExpansion.startsWith("<") && rExpansion.endsWith(">"))
+ {
+ const OUString sColumn( rExpansion.copy( 1, rExpansion.getLength() - 2 ) );
+ if( ::GetAppCmpStrIgnore().isEqual( sColumn,
+ static_cast<SwDBFieldType *>(GetTyp())->GetColumnName() ))
+ {
+ InitContent();
+ return;
+ }
+ }
+ SetExpansion( rExpansion );
+}
+
+OUString SwDBField::ExpandImpl(SwRootFrame const*const) const
+{
+ if(0 ==(GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE))
+ return lcl_DBSeparatorConvert(m_aContent);
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwDBField::Copy() const
+{
+ std::unique_ptr<SwDBField> pTmp(new SwDBField(static_cast<SwDBFieldType*>(GetTyp()), GetFormat()));
+ pTmp->m_aContent = m_aContent;
+ pTmp->m_bIsInBodyText = m_bIsInBodyText;
+ pTmp->m_bValidValue = m_bValidValue;
+ pTmp->m_bInitialized = m_bInitialized;
+ pTmp->m_nSubType = m_nSubType;
+ pTmp->SetValue(GetValue());
+ pTmp->m_sFieldCode = m_sFieldCode;
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+OUString SwDBField::GetFieldName() const
+{
+ const OUString rDBName = static_cast<SwDBFieldType*>(GetTyp())->GetName();
+
+ OUString sContent( rDBName.getToken(0, DB_DELIM) );
+
+ if (sContent.getLength() > 1)
+ {
+ sContent += OUStringChar(DB_DELIM)
+ + o3tl::getToken(rDBName, 1, DB_DELIM)
+ + OUStringChar(DB_DELIM)
+ + o3tl::getToken(rDBName, 2, DB_DELIM);
+ }
+ return lcl_DBSeparatorConvert(sContent);
+}
+
+void SwDBField::ChgValue( double d, bool bVal )
+{
+ m_bValidValue = bVal;
+ SetValue(d);
+
+ if( m_bValidValue )
+ m_aContent = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(d, GetFormat(), GetLanguage());
+}
+
+SwFieldType* SwDBField::ChgTyp( SwFieldType* pNewType )
+{
+ SwFieldType* pOld = SwValueField::ChgTyp( pNewType );
+
+ static_cast<SwDBFieldType*>(pNewType)->AddRef();
+ static_cast<SwDBFieldType*>(pOld)->ReleaseRef();
+
+ return pOld;
+}
+
+bool SwDBField::FormatValue( SvNumberFormatter const * pDocFormatter, OUString const &aString, sal_uInt32 nFormat,
+ double &aNumber, sal_Int32 nColumnType, SwDBField *pField )
+{
+ bool bValidValue = false;
+
+ if( DBL_MAX != aNumber )
+ {
+ if( DataType::DATE == nColumnType || DataType::TIME == nColumnType ||
+ DataType::TIMESTAMP == nColumnType )
+ {
+ Date aStandard( 1, 1, 1900 );
+ if( pDocFormatter->GetNullDate() != aStandard )
+ aNumber += (aStandard - pDocFormatter->GetNullDate());
+ }
+ bValidValue = true;
+ if( pField )
+ pField->SetValue( aNumber );
+ }
+ else
+ {
+ SwSbxValue aVal;
+ aVal.PutString( aString );
+
+ if (aVal.IsNumeric())
+ {
+ if( pField )
+ pField->SetValue(aVal.GetDouble());
+ else
+ aNumber = aVal.GetDouble();
+
+ if (nFormat && nFormat != SAL_MAX_UINT32 && !pDocFormatter->IsTextFormat(nFormat))
+ bValidValue = true; // because of bug #60339 not for all strings
+ }
+ else
+ {
+ // if string length > 0 then true, else false
+ if( pField )
+ pField->SetValue(aString.isEmpty() ? 0 : 1);
+ else
+ aNumber = aString.isEmpty() ? 0 : 1;
+ }
+ }
+
+ return bValidValue;
+}
+
+/// get current field value and cache it
+void SwDBField::Evaluate()
+{
+ SwDBManager* pMgr = GetDoc()->GetDBManager();
+
+ // first delete
+ m_bValidValue = false;
+ double nValue = DBL_MAX;
+ const SwDBData& aTmpData = GetDBData();
+
+ if(!pMgr || !pMgr->IsDataSourceOpen(aTmpData.sDataSource, aTmpData.sCommand, true))
+ return ;
+
+ sal_uInt32 nFormat = 0;
+
+ // search corresponding column name
+ OUString aColNm( static_cast<SwDBFieldType*>(GetTyp())->GetColumnName() );
+
+ SvNumberFormatter* pDocFormatter = GetDoc()->GetNumberFormatter();
+ pMgr->GetMergeColumnCnt(aColNm, GetLanguage(), m_aContent, &nValue);
+ if( !( m_nSubType & nsSwExtendedSubType::SUB_OWN_FMT ) )
+ {
+ nFormat = pMgr->GetColumnFormat( aTmpData.sDataSource, aTmpData.sCommand,
+ aColNm, pDocFormatter, GetLanguage() );
+ SetFormat( nFormat );
+ }
+
+ sal_Int32 nColumnType = nValue == DBL_MAX
+ ? 0
+ : pMgr->GetColumnType(aTmpData.sDataSource, aTmpData.sCommand, aColNm);
+
+ m_bValidValue = FormatValue( pDocFormatter, m_aContent, nFormat, nValue, nColumnType, this );
+
+ if( DBL_MAX != nValue )
+ m_aContent = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(nValue, GetFormat(), GetLanguage());
+
+ m_bInitialized = true;
+}
+
+/// get name
+OUString SwDBField::GetPar1() const
+{
+ return static_cast<const SwDBFieldType*>(GetTyp())->GetName();
+}
+
+sal_uInt16 SwDBField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwDBField::SetSubType(sal_uInt16 nType)
+{
+ m_nSubType = nType;
+}
+
+bool SwDBField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ rAny <<= 0 == (GetSubType()&nsSwExtendedSubType::SUB_OWN_FMT);
+ break;
+ case FIELD_PROP_BOOL2:
+ rAny <<= 0 == (GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE);
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aContent;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_sFieldCode;
+ break;
+ default:
+ OSL_FAIL("illegal property");
+ }
+ return true;
+}
+
+bool SwDBField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ if( *o3tl::doAccess<bool>(rAny) )
+ SetSubType(GetSubType()&~nsSwExtendedSubType::SUB_OWN_FMT);
+ else
+ SetSubType(GetSubType()|nsSwExtendedSubType::SUB_OWN_FMT);
+ break;
+ case FIELD_PROP_BOOL2:
+ {
+ sal_uInt16 nSubTyp = GetSubType();
+ bool bVisible = false;
+ if(!(rAny >>= bVisible))
+ return false;
+ if(bVisible)
+ nSubTyp &= ~nsSwExtendedSubType::SUB_INVISIBLE;
+ else
+ nSubTyp |= nsSwExtendedSubType::SUB_INVISIBLE;
+ SetSubType(nSubTyp);
+ //invalidate text node
+ auto pType = GetTyp();
+ if(!pType)
+ break;
+ std::vector<SwFormatField*> vFields;
+ pType->GatherFields(vFields, false);
+ for(auto pFormatField: vFields)
+ {
+ SwTextField* pTextField = pFormatField->GetTextField();
+ if(pTextField && static_cast<SwDBField*>(pFormatField->GetField()) == this)
+ {
+ //notify the change
+ pTextField->NotifyContentChange(*pFormatField);
+ break;
+ }
+ }
+ }
+ break;
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int32 nTemp = 0;
+ rAny >>= nTemp;
+ SetFormat(nTemp);
+ }
+ break;
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aContent;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_sFieldCode;
+ break;
+ default:
+ OSL_FAIL("illegal property");
+ }
+ return true;
+}
+
+// base class for all further database fields
+
+SwDBNameInfField::SwDBNameInfField(SwFieldType* pTyp, SwDBData aDBData, sal_uInt32 nFormat) :
+ SwField(pTyp, nFormat),
+ m_aDBData(std::move(aDBData)),
+ m_nSubType(0)
+{
+}
+
+SwDBData SwDBNameInfField::GetDBData(SwDoc* pDoc)
+{
+ SwDBData aRet;
+ if(!m_aDBData.sDataSource.isEmpty())
+ aRet = m_aDBData;
+ else
+ aRet = pDoc->GetDBData();
+ return aRet;
+}
+
+void SwDBNameInfField::SetDBData(const SwDBData & rDBData)
+{
+ m_aDBData = rDBData;
+}
+
+OUString SwDBNameInfField::GetFieldName() const
+{
+ OUString sStr( SwField::GetFieldName() );
+ if (!m_aDBData.sDataSource.isEmpty())
+ {
+ sStr += ":"
+ + m_aDBData.sDataSource
+ + OUStringChar(DB_DELIM)
+ + m_aDBData.sCommand;
+ }
+ return lcl_DBSeparatorConvert(sStr);
+}
+
+bool SwDBNameInfField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aDBData.sDataSource;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_aDBData.sCommand;
+ break;
+ case FIELD_PROP_SHORT1:
+ rAny <<= m_aDBData.nCommandType;
+ break;
+ case FIELD_PROP_BOOL2:
+ rAny <<= 0 == (GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE);
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwDBNameInfField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aDBData.sDataSource;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_aDBData.sCommand;
+ break;
+ case FIELD_PROP_SHORT1:
+ rAny >>= m_aDBData.nCommandType;
+ break;
+ case FIELD_PROP_BOOL2:
+ {
+ sal_uInt16 nSubTyp = GetSubType();
+ bool bVisible = false;
+ if(!(rAny >>= bVisible))
+ return false;
+ if(bVisible)
+ nSubTyp &= ~nsSwExtendedSubType::SUB_INVISIBLE;
+ else
+ nSubTyp |= nsSwExtendedSubType::SUB_INVISIBLE;
+ SetSubType(nSubTyp);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+sal_uInt16 SwDBNameInfField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwDBNameInfField::SetSubType(sal_uInt16 nType)
+{
+ m_nSubType = nType;
+}
+
+// next dataset
+
+SwDBNextSetFieldType::SwDBNextSetFieldType()
+ : SwFieldType( SwFieldIds::DbNextSet )
+{
+}
+
+std::unique_ptr<SwFieldType> SwDBNextSetFieldType::Copy() const
+{
+ return std::make_unique<SwDBNextSetFieldType>();
+}
+
+// SwDBSetField
+
+SwDBNextSetField::SwDBNextSetField(SwDBNextSetFieldType* pTyp,
+ OUString aCond,
+ const SwDBData& rDBData) :
+ SwDBNameInfField(pTyp, rDBData), m_aCond(std::move(aCond)), m_bCondValid(true)
+{}
+
+OUString SwDBNextSetField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwDBNextSetField::Copy() const
+{
+ std::unique_ptr<SwDBNextSetField> pTmp(new SwDBNextSetField(static_cast<SwDBNextSetFieldType*>(GetTyp()),
+ m_aCond, GetDBData()));
+ pTmp->SetSubType(GetSubType());
+ pTmp->m_bCondValid = m_bCondValid;
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+void SwDBNextSetField::Evaluate(const SwDoc& rDoc)
+{
+ SwDBManager* pMgr = rDoc.GetDBManager();
+ const SwDBData& rData = GetDBData();
+ if( !m_bCondValid ||
+ !pMgr || !pMgr->IsDataSourceOpen(rData.sDataSource, rData.sCommand, false))
+ return ;
+ pMgr->ToNextRecord(rData.sDataSource, rData.sCommand);
+}
+
+/// get condition
+OUString SwDBNextSetField::GetPar1() const
+{
+ return m_aCond;
+}
+
+/// set condition
+void SwDBNextSetField::SetPar1(const OUString& rStr)
+{
+ m_aCond = rStr;
+}
+
+bool SwDBNextSetField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR3:
+ rAny <<= m_aCond;
+ break;
+ default:
+ bRet = SwDBNameInfField::QueryValue( rAny, nWhichId );
+ }
+ return bRet;
+}
+
+bool SwDBNextSetField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR3:
+ rAny >>= m_aCond;
+ break;
+ default:
+ bRet = SwDBNameInfField::PutValue( rAny, nWhichId );
+ }
+ return bRet;
+}
+
+// dataset with certain ID
+
+SwDBNumSetFieldType::SwDBNumSetFieldType() :
+ SwFieldType( SwFieldIds::DbNumSet )
+{
+}
+
+std::unique_ptr<SwFieldType> SwDBNumSetFieldType::Copy() const
+{
+ return std::make_unique<SwDBNumSetFieldType>();
+}
+
+SwDBNumSetField::SwDBNumSetField(SwDBNumSetFieldType* pTyp,
+ OUString aCond,
+ OUString aDBNum,
+ const SwDBData& rDBData) :
+ SwDBNameInfField(pTyp, rDBData),
+ m_aCond(std::move(aCond)),
+ m_aPar2(std::move(aDBNum)),
+ m_bCondValid(true)
+{}
+
+OUString SwDBNumSetField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwDBNumSetField::Copy() const
+{
+ std::unique_ptr<SwDBNumSetField> pTmp(new SwDBNumSetField(static_cast<SwDBNumSetFieldType*>(GetTyp()),
+ m_aCond, m_aPar2, GetDBData()));
+ pTmp->m_bCondValid = m_bCondValid;
+ pTmp->SetSubType(GetSubType());
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+void SwDBNumSetField::Evaluate(const SwDoc& rDoc)
+{
+ SwDBManager* pMgr = rDoc.GetDBManager();
+ const SwDBData& aTmpData = GetDBData();
+
+ if( m_bCondValid && pMgr && pMgr->IsInMerge() &&
+ pMgr->IsDataSourceOpen(aTmpData.sDataSource, aTmpData.sCommand, true))
+ { // condition OK -> adjust current Set
+ pMgr->ToRecordId(std::max(o3tl::narrowing<sal_uInt16>(m_aPar2.toInt32()), sal_uInt16(1))-1);
+ }
+}
+
+/// get LogDBName
+OUString SwDBNumSetField::GetPar1() const
+{
+ return m_aCond;
+}
+
+/// set LogDBName
+void SwDBNumSetField::SetPar1(const OUString& rStr)
+{
+ m_aCond = rStr;
+}
+
+/// get condition
+OUString SwDBNumSetField::GetPar2() const
+{
+ return m_aPar2;
+}
+
+/// set condition
+void SwDBNumSetField::SetPar2(const OUString& rStr)
+{
+ m_aPar2 = rStr;
+}
+
+bool SwDBNumSetField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR3:
+ rAny <<= m_aCond;
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= m_aPar2.toInt32();
+ break;
+ default:
+ bRet = SwDBNameInfField::QueryValue(rAny, nWhichId );
+ }
+ return bRet;
+}
+
+bool SwDBNumSetField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR3:
+ rAny >>= m_aCond;
+ break;
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int32 nVal = 0;
+ rAny >>= nVal;
+ m_aPar2 = OUString::number(nVal);
+ }
+ break;
+ default:
+ bRet = SwDBNameInfField::PutValue(rAny, nWhichId );
+ }
+ return bRet;
+}
+
+SwDBNameFieldType::SwDBNameFieldType(SwDoc* pDocument)
+ : SwFieldType( SwFieldIds::DatabaseName )
+{
+ m_pDoc = pDocument;
+}
+
+OUString SwDBNameFieldType::Expand() const
+{
+ const SwDBData aData = m_pDoc->GetDBData();
+ return aData.sDataSource + "." + aData.sCommand;
+}
+
+std::unique_ptr<SwFieldType> SwDBNameFieldType::Copy() const
+{
+ return std::make_unique<SwDBNameFieldType>(m_pDoc);
+}
+
+// name of the connected database
+
+SwDBNameField::SwDBNameField(SwDBNameFieldType* pTyp, const SwDBData& rDBData)
+ : SwDBNameInfField(pTyp, rDBData, 0)
+{}
+
+OUString SwDBNameField::ExpandImpl(SwRootFrame const*const) const
+{
+ if(0 ==(GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE))
+ return static_cast<SwDBNameFieldType*>(GetTyp())->Expand();
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwDBNameField::Copy() const
+{
+ std::unique_ptr<SwDBNameField> pTmp(new SwDBNameField(static_cast<SwDBNameFieldType*>(GetTyp()), GetDBData()));
+ pTmp->ChangeFormat(GetFormat());
+ pTmp->SetLanguage(GetLanguage());
+ pTmp->SetSubType(GetSubType());
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+bool SwDBNameField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ return SwDBNameInfField::QueryValue(rAny, nWhichId );
+}
+
+bool SwDBNameField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ return SwDBNameInfField::PutValue(rAny, nWhichId );
+}
+
+SwDBSetNumberFieldType::SwDBSetNumberFieldType()
+ : SwFieldType( SwFieldIds::DbSetNumber )
+{
+}
+
+std::unique_ptr<SwFieldType> SwDBSetNumberFieldType::Copy() const
+{
+ return std::make_unique<SwDBSetNumberFieldType>();
+}
+
+// set-number of the connected database
+
+SwDBSetNumberField::SwDBSetNumberField(SwDBSetNumberFieldType* pTyp,
+ const SwDBData& rDBData,
+ sal_uInt32 nFormat)
+ : SwDBNameInfField(pTyp, rDBData, nFormat), m_nNumber(0)
+{}
+
+OUString SwDBSetNumberField::ExpandImpl(SwRootFrame const*const) const
+{
+ if(0 !=(GetSubType() & nsSwExtendedSubType::SUB_INVISIBLE) || m_nNumber == 0)
+ return OUString();
+ return FormatNumber(m_nNumber, static_cast<SvxNumType>(GetFormat()));
+}
+
+void SwDBSetNumberField::Evaluate(const SwDoc& rDoc)
+{
+ SwDBManager* pMgr = rDoc.GetDBManager();
+
+ const SwDBData& aTmpData = GetDBData();
+ if (!pMgr || !pMgr->IsInMerge() ||
+ !pMgr->IsDataSourceOpen(aTmpData.sDataSource, aTmpData.sCommand, false))
+ return;
+ m_nNumber = pMgr->GetSelectedRecordId();
+}
+
+std::unique_ptr<SwField> SwDBSetNumberField::Copy() const
+{
+ std::unique_ptr<SwDBSetNumberField> pTmp(
+ new SwDBSetNumberField(static_cast<SwDBSetNumberFieldType*>(GetTyp()), GetDBData(), GetFormat()));
+ pTmp->SetLanguage(GetLanguage());
+ pTmp->SetSetNumber(m_nNumber);
+ pTmp->SetSubType(GetSubType());
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+bool SwDBSetNumberField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(GetFormat());
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= m_nNumber;
+ break;
+ default:
+ bRet = SwDBNameInfField::QueryValue( rAny, nWhichId );
+ }
+ return bRet;
+}
+
+bool SwDBSetNumberField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nSet = 0;
+ rAny >>= nSet;
+ if(nSet < css::style::NumberingType::NUMBER_NONE )
+ SetFormat(nSet);
+ }
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny >>= m_nNumber;
+ break;
+ default:
+ bRet = SwDBNameInfField::PutValue( rAny, nWhichId );
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/ddefld.cxx b/sw/source/core/fields/ddefld.cxx
new file mode 100644
index 0000000000..46ac3d5049
--- /dev/null
+++ b/sw/source/core/fields/ddefld.cxx
@@ -0,0 +1,383 @@
+/* -*- 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 <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <rtl/ustrbuf.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sot/exchange.hxx>
+#include <doc.hxx>
+#include <IDocumentLinksAdministration.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <editsh.hxx>
+#include <fmtfld.hxx>
+#include <ddefld.hxx>
+#include <swddetbl.hxx>
+#include <swbaslnk.hxx>
+#include <unofldmid.h>
+#include <hints.hxx>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+class SwIntrnlRefLink : public SwBaseLink
+{
+ SwDDEFieldType& m_rFieldType;
+
+public:
+ SwIntrnlRefLink(SwDDEFieldType& rType, SfxLinkUpdateMode nUpdateType)
+ : SwBaseLink(nUpdateType, SotClipboardFormatId::STRING)
+ , m_rFieldType(rType)
+ {}
+
+ virtual void Closed() override;
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const css::uno::Any & rValue ) override;
+
+ virtual const SwNode* GetAnchor() const override;
+ virtual bool IsInRange( SwNodeOffset nSttNd, SwNodeOffset nEndNd ) const override;
+};
+
+}
+
+::sfx2::SvBaseLink::UpdateResult SwIntrnlRefLink::DataChanged( const OUString& rMimeType,
+ const uno::Any & rValue )
+{
+ switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
+ {
+ case SotClipboardFormatId::STRING:
+ if( !IsNoDataFlag() )
+ {
+ OUString sStr;
+ if (!(rValue >>= sStr))
+ {
+ uno::Sequence< sal_Int8 > aSeq;
+ rValue >>= aSeq;
+ sStr = OUString(reinterpret_cast<char const*>(aSeq.getConstArray()), aSeq.getLength(), osl_getThreadTextEncoding());
+ }
+
+ // remove not needed CR-LF at the end
+ sal_Int32 n = sStr.getLength();
+ while( n && 0 == sStr[ n-1 ] )
+ --n;
+ if( n && 0x0a == sStr[ n-1 ] )
+ --n;
+ if( n && 0x0d == sStr[ n-1 ] )
+ --n;
+
+ bool bDel = n != sStr.getLength();
+ if( bDel )
+ sStr = sStr.copy( 0, n );
+
+ m_rFieldType.SetExpansion(sStr);
+ // set Expansion first! (otherwise this flag will be deleted)
+ m_rFieldType.SetCRLFDelFlag(bDel);
+ }
+ break;
+
+ // other formats
+ default:
+ return SUCCESS;
+ }
+
+ if(!ChkNoDataFlag())
+ m_rFieldType.UpdateDDE();
+
+ return SUCCESS;
+}
+
+void SwIntrnlRefLink::Closed()
+{
+ if (m_rFieldType.GetDoc() && !m_rFieldType.GetDoc()->IsInDtor())
+ {
+ // advise goes, convert all fields into text?
+ SwViewShell* pSh = m_rFieldType.GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
+ if (SwEditShell* pESh = m_rFieldType.GetDoc()->GetEditShell())
+ {
+ pESh->StartAllAction();
+ pESh->FieldToText(&m_rFieldType);
+ pESh->EndAllAction();
+ }
+ else
+ {
+ pSh->StartAction();
+ // to call at the doc ??
+ pSh->EndAction();
+ }
+ }
+ SvBaseLink::Closed();
+}
+
+sw::LinkAnchorSearchHint::~LinkAnchorSearchHint() {};
+
+const SwNode* SwIntrnlRefLink::GetAnchor() const
+{
+ // here, any anchor of the normal NodesArray should be sufficient
+ const SwNode* pNd = nullptr;
+ m_rFieldType.CallSwClientNotify(
+ sw::LinkAnchorSearchHint(m_rFieldType.GetDoc()->GetNodes(), pNd));
+ return pNd;
+}
+
+bool SwIntrnlRefLink::IsInRange( SwNodeOffset nSttNd, SwNodeOffset nEndNd ) const
+{
+ bool bInRange = false;
+ m_rFieldType.CallSwClientNotify(sw::InRangeSearchHint(nSttNd, nEndNd, bInRange));
+ return bInRange;
+}
+
+SwDDEFieldType::SwDDEFieldType( OUString aName,
+ const OUString& rCmd, SfxLinkUpdateMode nUpdateType )
+ : SwFieldType( SwFieldIds::Dde ),
+ m_aName( std::move(aName) ), m_pDoc( nullptr ), m_nRefCount( 0 )
+{
+ m_bCRLFFlag = m_bDeleted = false;
+ m_RefLink = new SwIntrnlRefLink( *this, nUpdateType );
+ SetCmd( rCmd );
+}
+
+SwDDEFieldType::~SwDDEFieldType()
+{
+ if( m_pDoc && !m_pDoc->IsInDtor() )
+ m_pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ m_RefLink->Disconnect();
+}
+
+std::unique_ptr<SwFieldType> SwDDEFieldType::Copy() const
+{
+ std::unique_ptr<SwDDEFieldType> pType(new SwDDEFieldType( m_aName, GetCmd(), GetType() ));
+ pType->m_aExpansion = m_aExpansion;
+ pType->m_bCRLFFlag = m_bCRLFFlag;
+ pType->m_bDeleted = m_bDeleted;
+ pType->SetDoc( m_pDoc );
+ return pType;
+}
+
+OUString SwDDEFieldType::GetName() const
+{
+ return m_aName;
+}
+
+void SwDDEFieldType::SetCmd( const OUString& _aStr )
+{
+ OUString aStr = _aStr;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aStr = aStr.replaceFirst(" ", " ", &nIndex);
+ } while (nIndex>=0);
+ m_RefLink->SetLinkSourceName( aStr );
+}
+
+OUString const & SwDDEFieldType::GetCmd() const
+{
+ return m_RefLink->GetLinkSourceName();
+}
+
+void SwDDEFieldType::SetDoc( SwDoc* pNewDoc )
+{
+ if( pNewDoc == m_pDoc )
+ return;
+
+ if( m_pDoc && m_RefLink.is() )
+ {
+ OSL_ENSURE( !m_nRefCount, "How do we get the references?" );
+ m_pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ }
+
+ m_pDoc = pNewDoc;
+ if( m_pDoc && m_nRefCount )
+ {
+ m_RefLink->SetVisible( m_pDoc->getIDocumentLinksAdministration().IsVisibleLinks() );
+ m_pDoc->getIDocumentLinksAdministration().GetLinkManager().InsertDDELink( m_RefLink.get() );
+ }
+}
+
+void SwDDEFieldType::RefCntChgd()
+{
+ if( m_nRefCount )
+ {
+ m_RefLink->SetVisible( m_pDoc->getIDocumentLinksAdministration().IsVisibleLinks() );
+ m_pDoc->getIDocumentLinksAdministration().GetLinkManager().InsertDDELink( m_RefLink.get() );
+ if( m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() )
+ m_RefLink->Update();
+ }
+ else
+ {
+ Disconnect();
+ m_pDoc->getIDocumentLinksAdministration().GetLinkManager().Remove( m_RefLink.get() );
+ }
+}
+
+void SwDDEFieldType::QueryValue( uno::Any& rVal, sal_uInt16 nWhichId ) const
+{
+ sal_Int32 nPart = -1;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR2: nPart = 2; break;
+ case FIELD_PROP_PAR4: nPart = 1; break;
+ case FIELD_PROP_SUBTYPE: nPart = 0; break;
+ case FIELD_PROP_BOOL1:
+ rVal <<= GetType() == SfxLinkUpdateMode::ALWAYS;
+ break;
+ case FIELD_PROP_PAR5:
+ rVal <<= m_aExpansion;
+ break;
+ default:
+ assert(false);
+ }
+ if ( nPart>=0 )
+ rVal <<= GetCmd().getToken(nPart, sfx2::cTokenSeparator);
+}
+
+void SwDDEFieldType::PutValue( const uno::Any& rVal, sal_uInt16 nWhichId )
+{
+ sal_Int32 nPart = -1;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR2: nPart = 2; break;
+ case FIELD_PROP_PAR4: nPart = 1; break;
+ case FIELD_PROP_SUBTYPE: nPart = 0; break;
+ case FIELD_PROP_BOOL1:
+ SetType( *o3tl::doAccess<bool>(rVal) ?
+ SfxLinkUpdateMode::ALWAYS :
+ SfxLinkUpdateMode::ONCALL );
+ break;
+ case FIELD_PROP_PAR5:
+ rVal >>= m_aExpansion;
+ break;
+ default:
+ assert(false);
+ }
+ if( nPart<0 )
+ return;
+
+ const OUString sOldCmd( GetCmd() );
+ OUStringBuffer sNewCmd;
+ sal_Int32 nIndex = 0;
+ for (sal_Int32 i=0; i<3; ++i)
+ {
+ OUString sToken = sOldCmd.getToken(0, sfx2::cTokenSeparator, nIndex);
+ if (i==nPart)
+ {
+ rVal >>= sToken;
+ }
+ sNewCmd.append((i < 2)
+ ? sToken + OUStringChar(sfx2::cTokenSeparator) : sToken);
+ }
+ SetCmd( sNewCmd.makeStringAndClear() );
+}
+
+void SwDDEFieldType::UpdateDDE(const bool bNotifyShells)
+{
+ auto pDoc = GetDoc();
+ assert(pDoc);
+ if(IsModifyLocked())
+ return;
+ SwViewShell* pSh = bNotifyShells ? pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() : nullptr;
+ SwEditShell* pESh = bNotifyShells ? pDoc->GetEditShell() : nullptr;
+
+ // Search for fields. If no valid found, disconnect.
+ LockModify();
+
+ std::vector<SwFormatField*> vFields;
+ std::vector<SwDDETable*> vTables;
+ GatherFields(vFields, false);
+ GatherDdeTables(vTables);
+ const bool bDoAction = vFields.size() || vTables.size();
+ if(bDoAction)
+ {
+ if(pESh)
+ pESh->StartAllAction();
+ else if(pSh)
+ pSh->StartAction();
+ }
+
+ // a DDE tables in the text
+ for(auto pTable: vTables)
+ pTable->ChangeContent();
+
+ UnlockModify();
+
+ if(bDoAction)
+ {
+ if(pESh)
+ pESh->EndAllAction();
+ else if(pSh)
+ pSh->EndAction();
+
+ if(pSh)
+ pSh->GetDoc()->getIDocumentState().SetModified();
+ }
+}
+
+SwDDEField::SwDDEField( SwDDEFieldType* pInitType )
+ : SwField(pInitType)
+{
+}
+
+SwDDEField::~SwDDEField()
+{
+ if( GetTyp()->HasOnlyOneListener() )
+ static_cast<SwDDEFieldType*>(GetTyp())->Disconnect();
+}
+
+OUString SwDDEField::ExpandImpl(SwRootFrame const*const) const
+{
+ OUString aStr = static_cast<SwDDEFieldType*>(GetTyp())->GetExpansion();
+ aStr = aStr.replaceAll("\r", "");
+ aStr = aStr.replaceAll("\t", " ");
+ aStr = aStr.replaceAll("\n", "|");
+ if (aStr.endsWith("|"))
+ {
+ return aStr.copy(0, aStr.getLength()-1);
+ }
+ return aStr;
+}
+
+std::unique_ptr<SwField> SwDDEField::Copy() const
+{
+ return std::make_unique<SwDDEField>(static_cast<SwDDEFieldType*>(GetTyp()));
+}
+
+/// get field type name
+OUString SwDDEField::GetPar1() const
+{
+ return static_cast<const SwDDEFieldType*>(GetTyp())->GetName();
+}
+
+/// get field type command
+OUString SwDDEField::GetPar2() const
+{
+ return static_cast<const SwDDEFieldType*>(GetTyp())->GetCmd();
+}
+
+/// set field type command
+void SwDDEField::SetPar2(const OUString& rStr)
+{
+ static_cast<SwDDEFieldType*>(GetTyp())->SetCmd(rStr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/ddetbl.cxx b/sw/source/core/fields/ddetbl.cxx
new file mode 100644
index 0000000000..816abd07ca
--- /dev/null
+++ b/sw/source/core/fields/ddetbl.cxx
@@ -0,0 +1,209 @@
+/* -*- 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 <doc.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <contentindex.hxx>
+#include <ndtxt.hxx>
+#include <swtable.hxx>
+#include <swddetbl.hxx>
+#include <fmtfld.hxx>
+#include <ddefld.hxx>
+#include <ndindex.hxx>
+#include <fldupde.hxx>
+#include <swtblfmt.hxx>
+#include <fieldhint.hxx>
+#include <osl/diagnose.h>
+#include <pam.hxx>
+
+/// Ctor moves all lines/boxes from a SwTable into itself.
+/// Afterwards the SwTable is empty and must be deleted.
+SwDDETable::SwDDETable( SwTable& rTable, SwDDEFieldType* pDDEType, bool bUpdate )
+ : SwTable(rTable), m_aDepends(*this), m_pDDEType(pDDEType)
+{
+ m_aDepends.StartListening(m_pDDEType);
+ // copy the table data
+ m_TabSortContentBoxes.insert(rTable.GetTabSortBoxes());
+ rTable.GetTabSortBoxes().clear();
+
+ m_aLines.insert( m_aLines.begin(),
+ rTable.GetTabLines().begin(), rTable.GetTabLines().end() ); // move lines
+ rTable.GetTabLines().clear();
+
+ if( !m_aLines.empty() )
+ {
+ const SwNode& rNd = *GetTabSortBoxes()[0]->GetSttNd();
+ if( rNd.GetNodes().IsDocNodes() )
+ {
+ pDDEType->IncRefCnt();
+
+ // update box content only if update flag is set (false in import)
+ if (bUpdate)
+ ChangeContent();
+ }
+ }
+}
+
+SwDDETable::~SwDDETable()
+{
+ SwDoc* pDoc = GetFrameFormat()->GetDoc();
+ if (!pDoc->IsInDtor() && !m_aLines.empty())
+ {
+ assert(m_pTableNode);
+ if (m_pTableNode->GetNodes().IsDocNodes())
+ {
+ m_pDDEType->DecRefCnt();
+ }
+ }
+
+ // If it is the last dependent of the "deleted field" than delete it finally
+ if( m_pDDEType->IsDeleted() && m_pDDEType->HasOnlyOneListener() )
+ {
+ m_aDepends.EndListeningAll();
+ delete m_pDDEType;
+ m_pDDEType = nullptr;
+ }
+}
+
+void SwDDETable::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::SwLegacyModify || rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
+ {
+ SwTable::SwClientNotify(rModify, rHint);
+ }
+ else if (rHint.GetId() == SfxHintId::SwField)
+ {
+ auto pFieldHint = static_cast<const SwFieldHint*>(&rHint);
+ pFieldHint->m_pPaM->DeleteMark(); // TODO: this is really hackish
+ // replace DDETable by real table
+ NoDDETable();
+ }
+ else if(const auto pLinkAnchorHint = dynamic_cast<const sw::LinkAnchorSearchHint*>(&rHint))
+ {
+ if(pLinkAnchorHint->m_rpFoundNode)
+ return;
+ const auto pNd = GetTabSortBoxes()[0]->GetSttNd();
+ if( pNd && &pLinkAnchorHint->m_rNodes == &pNd->GetNodes() )
+ pLinkAnchorHint->m_rpFoundNode = pNd;
+ }
+ else if(const sw::InRangeSearchHint* pInRangeHint = dynamic_cast<const sw::InRangeSearchHint*>(&rHint))
+ {
+ if(pInRangeHint->m_rIsInRange)
+ return;
+ const SwTableNode* pTableNd = GetTabSortBoxes()[0]->GetSttNd()->FindTableNode();
+ if( pTableNd->GetNodes().IsDocNodes() &&
+ pInRangeHint->m_nSttNd < pTableNd->EndOfSectionIndex() &&
+ pInRangeHint->m_nEndNd > pTableNd->GetIndex() )
+ pInRangeHint->m_rIsInRange = true;
+ } else if (const auto pGatherDdeTablesHint = dynamic_cast<const sw::GatherDdeTablesHint*>(&rHint))
+ {
+ pGatherDdeTablesHint->m_rvTables.push_back(this);
+ }
+ else if (auto pModifyChangedHint = dynamic_cast<const sw::ModifyChangedHint*>(&rHint))
+ {
+ if(m_pDDEType == &rModify)
+ m_pDDEType = const_cast<SwDDEFieldType*>(static_cast<const SwDDEFieldType*>(pModifyChangedHint->m_pNew));
+ }
+}
+
+void SwDDETable::ChangeContent()
+{
+ OSL_ENSURE( GetFrameFormat(), "No FrameFormat" );
+
+ // Is this the correct NodesArray? (because of UNDO)
+ if( m_aLines.empty() )
+ return;
+ OSL_ENSURE( !GetTabSortBoxes().empty(), "Table without content?" );
+ if( !GetTabSortBoxes()[0]->GetSttNd()->GetNodes().IsDocNodes() )
+ return;
+
+
+ OUString aExpand = m_pDDEType->GetExpansion().replaceAll("\r", "");
+ sal_Int32 nExpandTokenPos = 0;
+
+ for( size_t n = 0; n < m_aLines.size(); ++n )
+ {
+ OUString aLine = aExpand.getToken( 0, '\n', nExpandTokenPos );
+ sal_Int32 nLineTokenPos = 0;
+ SwTableLine* pLine = m_aLines[ n ];
+ for( size_t i = 0; i < pLine->GetTabBoxes().size(); ++i )
+ {
+ SwTableBox* pBox = pLine->GetTabBoxes()[ i ];
+ OSL_ENSURE( pBox->GetSttIdx(), "no content box" );
+ SwNodeIndex aNdIdx( *pBox->GetSttNd(), 1 );
+ SwTextNode* pTextNode = aNdIdx.GetNode().GetTextNode();
+ OSL_ENSURE( pTextNode, "No Node" );
+ SwContentIndex aCntIdx( pTextNode, 0 );
+ pTextNode->EraseText( aCntIdx );
+ pTextNode->InsertText( aLine.getToken( 0, '\t', nLineTokenPos ), aCntIdx );
+
+ SwTableBoxFormat* pBoxFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
+ pBoxFormat->LockModify();
+ pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
+ pBoxFormat->UnlockModify();
+ }
+ }
+
+ const IDocumentSettingAccess& rIDSA = GetFrameFormat()->getIDocumentSettingAccess();
+ SwDoc* pDoc = GetFrameFormat()->GetDoc();
+ if( AUTOUPD_FIELD_AND_CHARTS == rIDSA.getFieldUpdateFlags(true) )
+ pDoc->getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, SwNodeOffset(0) );
+}
+
+SwDDEFieldType* SwDDETable::GetDDEFieldType()
+{
+ return m_pDDEType;
+}
+
+void SwDDETable::NoDDETable()
+{
+ // search table node
+ OSL_ENSURE( GetFrameFormat(), "No FrameFormat" );
+ SwDoc* pDoc = GetFrameFormat()->GetDoc();
+
+ // Is this the correct NodesArray? (because of UNDO)
+ if( m_aLines.empty() )
+ return;
+ OSL_ENSURE( !GetTabSortBoxes().empty(), "Table without content?" );
+ SwNode* pNd = const_cast<SwNode*>(static_cast<SwNode const *>(GetTabSortBoxes()[0]->GetSttNd()));
+ if( !pNd->GetNodes().IsDocNodes() )
+ return;
+
+ SwTableNode* pTableNd = pNd->FindTableNode();
+ OSL_ENSURE( pTableNd, "Where is the table?");
+
+ std::unique_ptr<SwTable> pNewTable(new SwTable( *this ));
+
+ // copy the table data
+ pNewTable->GetTabSortBoxes().insert( GetTabSortBoxes() ); // move content boxes
+ GetTabSortBoxes().clear();
+
+ pNewTable->GetTabLines().insert( pNewTable->GetTabLines().begin(),
+ GetTabLines().begin(), GetTabLines().end() ); // move lines
+ GetTabLines().clear();
+
+ if( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() )
+ m_pDDEType->DecRefCnt();
+
+ pTableNd->SetNewTable( std::move(pNewTable) ); // replace table
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx
new file mode 100644
index 0000000000..ba5f45bece
--- /dev/null
+++ b/sw/source/core/fields/docufld.cxx
@@ -0,0 +1,2727 @@
+/* -*- 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 <textapi.hxx>
+
+#include <hintids.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/text/PlaceholderType.hpp>
+#include <com/sun/star/text/TemplateDisplayFormat.hpp>
+#include <com/sun/star/text/PageNumberType.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Duration.hpp>
+#include <o3tl/any.hxx>
+#include <o3tl/string_view.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/numformat.hxx>
+#include <svl/urihelper.hxx>
+#include <unotools/useroptions.hxx>
+#include <unotools/syslocale.hxx>
+#include <libxml/xmlstring.h>
+#include <libxml/xmlwriter.h>
+
+#include <tools/time.hxx>
+#include <tools/datetime.hxx>
+
+#include <com/sun/star/util/DateTime.hpp>
+
+#include <swmodule.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/doctempl.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <charfmt.hxx>
+#include <docstat.hxx>
+#include <pagedesc.hxx>
+#include <fmtpdsc.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentStatistics.hxx>
+#include <IDocumentStylePoolAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <cntfrm.hxx>
+#include <pam.hxx>
+#include <utility>
+#include <viewsh.hxx>
+#include <dbmgr.hxx>
+#include <shellres.hxx>
+#include <docufld.hxx>
+#include <flddat.hxx>
+#include <docfld.hxx>
+#include <ndtxt.hxx>
+#include <expfld.hxx>
+#include <poolfmt.hxx>
+#include <docsh.hxx>
+#include <unofldmid.h>
+#include <swunohelper.hxx>
+#include <strings.hrc>
+
+#include <editeng/outlobj.hxx>
+#include <calbck.hxx>
+#include <hints.hxx>
+
+#define URL_DECODE INetURLObject::DecodeMechanism::Unambiguous
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace nsSwDocInfoSubType;
+
+SwPageNumberFieldType::SwPageNumberFieldType()
+ : SwFieldType( SwFieldIds::PageNumber ),
+ m_nNumberingType( SVX_NUM_ARABIC ),
+ m_bVirtual( false )
+{
+}
+
+OUString SwPageNumberFieldType::Expand( SvxNumType nFormat, short nOff,
+ sal_uInt16 const nPageNumber, sal_uInt16 const nMaxPage,
+ const OUString& rUserStr, LanguageType nLang ) const
+{
+ SvxNumType nTmpFormat = (SVX_NUM_PAGEDESC == nFormat) ? m_nNumberingType : nFormat;
+ int const nTmp = nPageNumber + nOff;
+
+ if (0 > nTmp || SVX_NUM_NUMBER_NONE == nTmpFormat || (!m_bVirtual && nTmp > nMaxPage))
+ return OUString();
+
+ if( SVX_NUM_CHAR_SPECIAL == nTmpFormat )
+ return rUserStr;
+
+ return FormatNumber( nTmp, nTmpFormat, nLang );
+}
+
+std::unique_ptr<SwFieldType> SwPageNumberFieldType::Copy() const
+{
+ std::unique_ptr<SwPageNumberFieldType> pTmp(new SwPageNumberFieldType());
+
+ pTmp->m_nNumberingType = m_nNumberingType;
+ pTmp->m_bVirtual = m_bVirtual;
+
+ return pTmp;
+}
+
+void SwPageNumberFieldType::ChangeExpansion( SwDoc* pDoc,
+ bool bVirt,
+ const SvxNumType* pNumFormat )
+{
+ if( pNumFormat )
+ m_nNumberingType = *pNumFormat;
+
+ m_bVirtual = false;
+ if (!(bVirt && pDoc))
+ return;
+
+ // check the flag since the layout NEVER sets it back
+ const SfxItemPool &rPool = pDoc->GetAttrPool();
+ for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_PAGEDESC))
+ {
+ auto pDesc = dynamic_cast<const SwFormatPageDesc*>(pItem);
+ if( pDesc && pDesc->GetNumOffset() && pDesc->GetDefinedIn() )
+ {
+ const SwContentNode* pNd = dynamic_cast<const SwContentNode*>( pDesc->GetDefinedIn() );
+ if( pNd )
+ {
+ if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pNd).First())
+ // sw_redlinehide: not sure if this should happen only if
+ // it's the first node, because that's where RES_PAGEDESC
+ // is effective?
+ m_bVirtual = true;
+ }
+ else if( dynamic_cast< const SwFormat* >(pDesc->GetDefinedIn()) != nullptr)
+ {
+ m_bVirtual = false;
+ sw::AutoFormatUsedHint aHint(m_bVirtual, pDoc->GetNodes());
+ pDesc->GetDefinedIn()->CallSwClientNotify(aHint);
+ break;
+ }
+ }
+ }
+}
+
+SwPageNumberField::SwPageNumberField(SwPageNumberFieldType* pTyp,
+ sal_uInt16 nSub, sal_uInt32 nFormat, short nOff,
+ sal_uInt16 const nPageNumber, sal_uInt16 const nMaxPage)
+ : SwField(pTyp, nFormat), m_nSubType(nSub), m_nOffset(nOff)
+ , m_nPageNumber(nPageNumber)
+ , m_nMaxPage(nMaxPage)
+{
+}
+
+void SwPageNumberField::ChangeExpansion(sal_uInt16 const nPageNumber,
+ sal_uInt16 const nMaxPage)
+{
+ m_nPageNumber = nPageNumber;
+ m_nMaxPage = nMaxPage;
+}
+
+OUString SwPageNumberField::ExpandImpl(SwRootFrame const*const) const
+{
+ OUString sRet;
+ SwPageNumberFieldType* pFieldType = static_cast<SwPageNumberFieldType*>(GetTyp());
+
+ if( PG_NEXT == m_nSubType && 1 != m_nOffset )
+ {
+ sRet = pFieldType->Expand(static_cast<SvxNumType>(GetFormat()), 1, m_nPageNumber, m_nMaxPage, m_sUserStr, GetLanguage());
+ if (!sRet.isEmpty())
+ {
+ sRet = pFieldType->Expand(static_cast<SvxNumType>(GetFormat()), m_nOffset, m_nPageNumber, m_nMaxPage, m_sUserStr, GetLanguage());
+ }
+ }
+ else if( PG_PREV == m_nSubType && -1 != m_nOffset )
+ {
+ sRet = pFieldType->Expand(static_cast<SvxNumType>(GetFormat()), -1, m_nPageNumber, m_nMaxPage, m_sUserStr, GetLanguage());
+ if (!sRet.isEmpty())
+ {
+ sRet = pFieldType->Expand(static_cast<SvxNumType>(GetFormat()), m_nOffset, m_nPageNumber, m_nMaxPage, m_sUserStr, GetLanguage());
+ }
+ }
+ else
+ sRet = pFieldType->Expand(static_cast<SvxNumType>(GetFormat()), m_nOffset, m_nPageNumber, m_nMaxPage, m_sUserStr, GetLanguage());
+ return sRet;
+}
+
+std::unique_ptr<SwField> SwPageNumberField::Copy() const
+{
+ std::unique_ptr<SwPageNumberField> pTmp(new SwPageNumberField(
+ static_cast<SwPageNumberFieldType*>(GetTyp()), m_nSubType,
+ GetFormat(), m_nOffset, m_nPageNumber, m_nMaxPage));
+ pTmp->SetLanguage( GetLanguage() );
+ pTmp->SetUserString( m_sUserStr );
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+OUString SwPageNumberField::GetPar2() const
+{
+ return OUString::number(m_nOffset);
+}
+
+void SwPageNumberField::SetPar2(const OUString& rStr)
+{
+ m_nOffset = static_cast<short>(rStr.toInt32());
+}
+
+sal_uInt16 SwPageNumberField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+bool SwPageNumberField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int16>(GetFormat());
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny <<= m_nOffset;
+ break;
+ case FIELD_PROP_SUBTYPE:
+ {
+ text::PageNumberType eType;
+ eType = text::PageNumberType_CURRENT;
+ if(m_nSubType == PG_PREV)
+ eType = text::PageNumberType_PREV;
+ else if(m_nSubType == PG_NEXT)
+ eType = text::PageNumberType_NEXT;
+ rAny <<= eType;
+ }
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sUserStr;
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwPageNumberField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ sal_Int16 nSet = 0;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ rAny >>= nSet;
+
+ // TODO: where do the defines come from?
+ if(nSet <= SVX_NUM_PAGEDESC )
+ SetFormat(nSet);
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny >>= nSet;
+ m_nOffset = nSet;
+ break;
+ case FIELD_PROP_SUBTYPE:
+ switch( static_cast<text::PageNumberType>(SWUnoHelper::GetEnumAsInt32( rAny )) )
+ {
+ case text::PageNumberType_CURRENT:
+ m_nSubType = PG_RANDOM;
+ break;
+ case text::PageNumberType_PREV:
+ m_nSubType = PG_PREV;
+ break;
+ case text::PageNumberType_NEXT:
+ m_nSubType = PG_NEXT;
+ break;
+ default:
+ bRet = false;
+ }
+ break;
+ case FIELD_PROP_PAR1:
+ rAny >>= m_sUserStr;
+ break;
+
+ default:
+ assert(false);
+ }
+ return bRet;
+}
+
+SwAuthorFieldType::SwAuthorFieldType()
+ : SwFieldType( SwFieldIds::Author )
+{
+}
+
+OUString SwAuthorFieldType::Expand(sal_uLong nFormat)
+{
+ SvtUserOptions& rOpt = SW_MOD()->GetUserOptions();
+ if((nFormat & 0xff) == AF_NAME)
+ {
+ // Prefer the view's redline author name.
+ // (set in SwXTextDocument::initializeForTiledRendering)
+ std::size_t nAuthor = SW_MOD()->GetRedlineAuthor();
+ OUString sAuthor = SW_MOD()->GetRedlineAuthor(nAuthor);
+ if (sAuthor.isEmpty())
+ return rOpt.GetFullName();
+
+ return sAuthor;
+ }
+
+ return rOpt.GetID();
+}
+
+std::unique_ptr<SwFieldType> SwAuthorFieldType::Copy() const
+{
+ return std::make_unique<SwAuthorFieldType>();
+}
+
+SwAuthorField::SwAuthorField(SwAuthorFieldType* pTyp, sal_uInt32 nFormat)
+ : SwField(pTyp, nFormat)
+{
+ m_aContent = SwAuthorFieldType::Expand(GetFormat());
+}
+
+OUString SwAuthorField::ExpandImpl(SwRootFrame const*const) const
+{
+ if (!IsFixed())
+ const_cast<SwAuthorField*>(this)->m_aContent =
+ SwAuthorFieldType::Expand(GetFormat());
+
+ return m_aContent;
+}
+
+std::unique_ptr<SwField> SwAuthorField::Copy() const
+{
+ std::unique_ptr<SwAuthorField> pTmp(new SwAuthorField( static_cast<SwAuthorFieldType*>(GetTyp()),
+ GetFormat()));
+ pTmp->SetExpansion(m_aContent);
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+bool SwAuthorField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ rAny <<= (GetFormat() & 0xff) == AF_NAME;
+ break;
+
+ case FIELD_PROP_BOOL2:
+ rAny <<= IsFixed();
+ break;
+
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aContent;
+ break;
+
+ case FIELD_PROP_TITLE:
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwAuthorField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ SetFormat( *o3tl::doAccess<bool>(rAny) ? AF_NAME : AF_SHORTCUT );
+ break;
+
+ case FIELD_PROP_BOOL2:
+ if( *o3tl::doAccess<bool>(rAny) )
+ SetFormat( GetFormat() | AF_FIXED);
+ else
+ SetFormat( GetFormat() & ~AF_FIXED);
+ break;
+
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aContent;
+ break;
+
+ case FIELD_PROP_TITLE:
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+SwFileNameFieldType::SwFileNameFieldType(SwDoc& rDocument)
+ : SwFieldType( SwFieldIds::Filename )
+ , m_rDoc(rDocument)
+{
+}
+
+OUString SwFileNameFieldType::Expand(sal_uLong nFormat) const
+{
+ OUString aRet;
+ const SwDocShell* pDShell = m_rDoc.GetDocShell();
+ if( pDShell && pDShell->HasName() )
+ {
+ const INetURLObject& rURLObj = pDShell->GetMedium()->GetURLObject();
+ switch( nFormat & ~FF_FIXED )
+ {
+ case FF_PATH:
+ {
+ if( INetProtocol::File == rURLObj.GetProtocol() )
+ {
+ INetURLObject aTemp(rURLObj);
+ aTemp.removeSegment();
+ // last slash should belong to the pathname
+ aRet = aTemp.PathToFileName();
+ }
+ else
+ {
+ aRet = URIHelper::removePassword(
+ rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ INetURLObject::EncodeMechanism::WasEncoded, URL_DECODE );
+ const sal_Int32 nPos = aRet.indexOf(rURLObj.GetLastName( URL_DECODE ));
+ if (nPos>=0)
+ {
+ aRet = aRet.copy(0, nPos);
+ }
+ }
+ }
+ break;
+
+ case FF_NAME:
+ aRet = rURLObj.GetLastName( INetURLObject::DecodeMechanism::WithCharset );
+ break;
+
+ case FF_NAME_NOEXT:
+ aRet = rURLObj.GetBase();
+ break;
+
+ default:
+ if( INetProtocol::File == rURLObj.GetProtocol() )
+ aRet = rURLObj.GetFull();
+ else
+ aRet = URIHelper::removePassword(
+ rURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ INetURLObject::EncodeMechanism::WasEncoded, URL_DECODE );
+ }
+ }
+ return aRet;
+}
+
+std::unique_ptr<SwFieldType> SwFileNameFieldType::Copy() const
+{
+ return std::make_unique<SwFileNameFieldType>(m_rDoc);
+}
+
+SwFileNameField::SwFileNameField(SwFileNameFieldType* pTyp, sal_uInt32 nFormat)
+ : SwField(pTyp, nFormat)
+{
+ m_aContent = static_cast<SwFileNameFieldType*>(GetTyp())->Expand(GetFormat());
+}
+
+OUString SwFileNameField::ExpandImpl(SwRootFrame const*const) const
+{
+ if (!IsFixed())
+ const_cast<SwFileNameField*>(this)->m_aContent = static_cast<SwFileNameFieldType*>(GetTyp())->Expand(GetFormat());
+
+ return m_aContent;
+}
+
+std::unique_ptr<SwField> SwFileNameField::Copy() const
+{
+ std::unique_ptr<SwFileNameField> pTmp(
+ new SwFileNameField(static_cast<SwFileNameFieldType*>(GetTyp()), GetFormat()));
+ pTmp->SetExpansion(m_aContent);
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+bool SwFileNameField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int16 nRet;
+ switch( GetFormat() &(~FF_FIXED) )
+ {
+ case FF_PATH:
+ nRet = text::FilenameDisplayFormat::PATH;
+ break;
+ case FF_NAME_NOEXT:
+ nRet = text::FilenameDisplayFormat::NAME;
+ break;
+ case FF_NAME:
+ nRet = text::FilenameDisplayFormat::NAME_AND_EXT;
+ break;
+ default: nRet = text::FilenameDisplayFormat::FULL;
+ }
+ rAny <<= nRet;
+ }
+ break;
+
+ case FIELD_PROP_BOOL2:
+ rAny <<= IsFixed();
+ break;
+
+ case FIELD_PROP_PAR3:
+ rAny <<= m_aContent;
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwFileNameField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ {
+ //JP 24.10.2001: int32 because in UnoField.cxx a putvalue is
+ // called with a int32 value! But normally we need
+ // here only a int16
+ sal_Int32 nType = 0;
+ rAny >>= nType;
+ bool bFixed = IsFixed();
+ switch( nType )
+ {
+ case text::FilenameDisplayFormat::PATH:
+ nType = FF_PATH;
+ break;
+ case text::FilenameDisplayFormat::NAME:
+ nType = FF_NAME_NOEXT;
+ break;
+ case text::FilenameDisplayFormat::NAME_AND_EXT:
+ nType = FF_NAME;
+ break;
+ default: nType = FF_PATHNAME;
+ }
+ if(bFixed)
+ nType |= FF_FIXED;
+ SetFormat(nType);
+ }
+ break;
+
+ case FIELD_PROP_BOOL2:
+ if( *o3tl::doAccess<bool>(rAny) )
+ SetFormat( GetFormat() | FF_FIXED);
+ else
+ SetFormat( GetFormat() & ~FF_FIXED);
+ break;
+
+ case FIELD_PROP_PAR3:
+ rAny >>= m_aContent;
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+SwTemplNameFieldType::SwTemplNameFieldType(SwDoc& rDocument)
+ : SwFieldType( SwFieldIds::TemplateName )
+ , m_rDoc(rDocument)
+{
+}
+
+OUString SwTemplNameFieldType::Expand(sal_uLong nFormat) const
+{
+ OSL_ENSURE( nFormat < FF_END, "Expand: no valid Format!" );
+
+ OUString aRet;
+ SwDocShell *pDocShell(m_rDoc.GetDocShell());
+ OSL_ENSURE(pDocShell, "no SwDocShell");
+ if (pDocShell) {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ pDocShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ xDPS->getDocumentProperties());
+ OSL_ENSURE(xDocProps.is(), "Doc has no DocumentProperties");
+
+ if( FF_UI_NAME == nFormat )
+ aRet = xDocProps->getTemplateName();
+ else if( !xDocProps->getTemplateURL().isEmpty() )
+ {
+ if( FF_UI_RANGE == nFormat )
+ {
+ // for getting region names!
+ SfxDocumentTemplates aFac;
+ OUString sTmp;
+ OUString sRegion;
+ aFac.GetLogicNames( xDocProps->getTemplateURL(), sRegion, sTmp );
+ aRet = sRegion;
+ }
+ else
+ {
+ INetURLObject aPathName( xDocProps->getTemplateURL() );
+ if( FF_NAME == nFormat )
+ aRet = aPathName.GetLastName(URL_DECODE);
+ else if( FF_NAME_NOEXT == nFormat )
+ aRet = aPathName.GetBase();
+ else
+ {
+ if( FF_PATH == nFormat )
+ {
+ aPathName.removeSegment();
+ aRet = aPathName.GetFull();
+ }
+ else
+ aRet = aPathName.GetFull();
+ }
+ }
+ }
+ }
+ return aRet;
+}
+
+std::unique_ptr<SwFieldType> SwTemplNameFieldType::Copy() const
+{
+ return std::make_unique<SwTemplNameFieldType>(m_rDoc);
+}
+
+SwTemplNameField::SwTemplNameField(SwTemplNameFieldType* pTyp, sal_uInt32 nFormat)
+ : SwField(pTyp, nFormat)
+{}
+
+OUString SwTemplNameField::ExpandImpl(SwRootFrame const*const) const
+{
+ return static_cast<SwTemplNameFieldType*>(GetTyp())->Expand(GetFormat());
+}
+
+std::unique_ptr<SwField> SwTemplNameField::Copy() const
+{
+ return std::make_unique<SwTemplNameField>(static_cast<SwTemplNameFieldType*>(GetTyp()), GetFormat());
+}
+
+bool SwTemplNameField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int16 nRet;
+ switch( GetFormat() )
+ {
+ case FF_PATH: nRet = text::FilenameDisplayFormat::PATH; break;
+ case FF_NAME_NOEXT: nRet = text::FilenameDisplayFormat::NAME; break;
+ case FF_NAME: nRet = text::FilenameDisplayFormat::NAME_AND_EXT; break;
+ case FF_UI_RANGE: nRet = text::TemplateDisplayFormat::AREA; break;
+ case FF_UI_NAME: nRet = text::TemplateDisplayFormat::TITLE; break;
+ default: nRet = text::FilenameDisplayFormat::FULL;
+
+ }
+ rAny <<= nRet;
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwTemplNameField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_FORMAT:
+ {
+ //JP 24.10.2001: int32 because in UnoField.cxx a putvalue is
+ // called with a int32 value! But normally we need
+ // here only a int16
+ sal_Int32 nType = 0;
+ rAny >>= nType;
+ switch( nType )
+ {
+ case text::FilenameDisplayFormat::PATH:
+ SetFormat(FF_PATH);
+ break;
+ case text::FilenameDisplayFormat::NAME:
+ SetFormat(FF_NAME_NOEXT);
+ break;
+ case text::FilenameDisplayFormat::NAME_AND_EXT:
+ SetFormat(FF_NAME);
+ break;
+ case text::TemplateDisplayFormat::AREA :
+ SetFormat(FF_UI_RANGE);
+ break;
+ case text::TemplateDisplayFormat::TITLE :
+ SetFormat(FF_UI_NAME);
+ break;
+ default: SetFormat(FF_PATHNAME);
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+SwDocStatFieldType::SwDocStatFieldType(SwDoc& rDocument)
+ : SwFieldType(SwFieldIds::DocStat)
+ , m_rDoc(rDocument)
+ , m_nNumberingType(SVX_NUM_ARABIC)
+{
+}
+
+OUString SwDocStatFieldType::Expand(sal_uInt16 nSubType, SvxNumType nFormat) const
+{
+ sal_uInt32 nVal = 0;
+ const SwDocStat& rDStat = m_rDoc.getIDocumentStatistics().GetDocStat();
+ switch( nSubType )
+ {
+ case DS_TBL: nVal = rDStat.nTable; break;
+ case DS_GRF: nVal = rDStat.nGrf; break;
+ case DS_OLE: nVal = rDStat.nOLE; break;
+ case DS_PARA: nVal = rDStat.nPara; break;
+ case DS_WORD: nVal = rDStat.nWord; break;
+ case DS_CHAR: nVal = rDStat.nChar; break;
+ case DS_PAGE:
+ if( m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout() )
+ const_cast<SwDocStat &>(rDStat).nPage = m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetPageNum();
+ nVal = rDStat.nPage;
+ if( SVX_NUM_PAGEDESC == nFormat )
+ nFormat = m_nNumberingType;
+ break;
+ default:
+ OSL_FAIL( "SwDocStatFieldType::Expand: unknown SubType" );
+ }
+
+ if( nVal <= SHRT_MAX )
+ return FormatNumber( nVal, nFormat );
+
+ return OUString::number( nVal );
+}
+
+std::unique_ptr<SwFieldType> SwDocStatFieldType::Copy() const
+{
+ return std::make_unique<SwDocStatFieldType>(m_rDoc);
+}
+
+/**
+ * @param pTyp
+ * @param nSub SubType
+ * @param nFormat
+ */
+SwDocStatField::SwDocStatField(SwDocStatFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 nFormat)
+ : SwField(pTyp, nFormat),
+ m_nSubType(nSub)
+{}
+
+OUString SwDocStatField::ExpandImpl(SwRootFrame const*const) const
+{
+ return static_cast<SwDocStatFieldType*>(GetTyp())->Expand(m_nSubType, static_cast<SvxNumType>(GetFormat()));
+}
+
+std::unique_ptr<SwField> SwDocStatField::Copy() const
+{
+ return std::make_unique<SwDocStatField>(
+ static_cast<SwDocStatFieldType*>(GetTyp()), m_nSubType, GetFormat() );
+}
+
+sal_uInt16 SwDocStatField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwDocStatField::SetSubType(sal_uInt16 nSub)
+{
+ m_nSubType = nSub;
+}
+
+void SwDocStatField::ChangeExpansion( const SwFrame* pFrame )
+{
+ if( DS_PAGE == m_nSubType && SVX_NUM_PAGEDESC == GetFormat() )
+ static_cast<SwDocStatFieldType*>(GetTyp())->SetNumFormat(
+ pFrame->FindPageFrame()->GetPageDesc()->GetNumType().GetNumberingType() );
+}
+
+bool SwDocStatField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_USHORT2:
+ rAny <<= static_cast<sal_Int16>(GetFormat());
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwDocStatField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = false;
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_USHORT2:
+ {
+ sal_Int16 nSet = 0;
+ rAny >>= nSet;
+ if(nSet <= SVX_NUM_CHARS_LOWER_LETTER_N &&
+ nSet != SVX_NUM_CHAR_SPECIAL &&
+ nSet != SVX_NUM_BITMAP)
+ {
+ SetFormat(nSet);
+ bRet = true;
+ }
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return bRet;
+}
+
+// Document info field type
+
+SwDocInfoFieldType::SwDocInfoFieldType(SwDoc* pDc)
+ : SwValueFieldType( pDc, SwFieldIds::DocInfo )
+{
+}
+
+std::unique_ptr<SwFieldType> SwDocInfoFieldType::Copy() const
+{
+ return std::make_unique<SwDocInfoFieldType>(GetDoc());
+}
+
+static void lcl_GetLocalDataWrapper( LanguageType nLang,
+ const LocaleDataWrapper **ppAppLocalData,
+ const LocaleDataWrapper **ppLocalData )
+{
+ SvtSysLocale aLocale;
+ *ppAppLocalData = &aLocale.GetLocaleData();
+ *ppLocalData = *ppAppLocalData;
+ if( nLang != (*ppLocalData)->getLanguageTag().getLanguageType() )
+ *ppLocalData = new LocaleDataWrapper(LanguageTag( nLang ));
+}
+
+OUString SwDocInfoFieldType::Expand( sal_uInt16 nSub, sal_uInt32 nFormat,
+ LanguageType nLang, const OUString& rName ) const
+{
+ const LocaleDataWrapper *pAppLocalData = nullptr, *pLocalData = nullptr;
+ SwDocShell *pDocShell(GetDoc()->GetDocShell());
+ OSL_ENSURE(pDocShell, "no SwDocShell");
+ if (!pDocShell) { return OUString(); }
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ pDocShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ xDPS->getDocumentProperties());
+ OSL_ENSURE(xDocProps.is(), "Doc has no DocumentProperties");
+
+ sal_uInt16 nExtSub = nSub & 0xff00;
+ nSub &= 0xff; // do not consider extended SubTypes
+
+ OUString aStr;
+ switch(nSub)
+ {
+ case DI_TITLE: aStr = xDocProps->getTitle(); break;
+ case DI_SUBJECT:aStr = xDocProps->getSubject(); break;
+ case DI_KEYS: aStr = ::comphelper::string::convertCommaSeparated(
+ xDocProps->getKeywords());
+ break;
+ case DI_COMMENT:aStr = xDocProps->getDescription(); break;
+ case DI_DOCNO: aStr = OUString::number(
+ xDocProps->getEditingCycles() );
+ break;
+ case DI_EDIT:
+ if ( !nFormat )
+ {
+ lcl_GetLocalDataWrapper( nLang, &pAppLocalData, &pLocalData );
+ sal_Int32 dur = xDocProps->getEditingDuration();
+ // If Seconds > 0 then bSec should be TRUE otherwise Seconds
+ // information will be lost if file has EditTime in Seconds format.
+ aStr = pLocalData->getTime( tools::Time(dur/3600, (dur%3600)/60, dur%60),
+ dur%60 > 0);
+ }
+ else
+ {
+ sal_Int32 dur = xDocProps->getEditingDuration();
+ double fVal = tools::Time(dur/3600, (dur%3600)/60, dur%60).GetTimeInDays();
+ aStr = ExpandValue(fVal, nFormat, nLang);
+ }
+ break;
+ case DI_CUSTOM:
+ {
+ OUString sVal;
+ try
+ {
+ uno::Any aAny;
+ uno::Reference < beans::XPropertySet > xSet(
+ xDocProps->getUserDefinedProperties(),
+ uno::UNO_QUERY_THROW);
+ aAny = xSet->getPropertyValue( rName );
+
+ uno::Reference < script::XTypeConverter > xConverter( script::Converter::create(comphelper::getProcessComponentContext()) );
+ uno::Any aNew = xConverter->convertToSimpleType( aAny, uno::TypeClass_STRING );
+ aNew >>= sVal;
+ }
+ catch (uno::Exception&) {}
+ return sVal;
+ }
+
+ default:
+ {
+ OUString aName( xDocProps->getAuthor() );
+ util::DateTime uDT( xDocProps->getCreationDate() );
+ DateTime aDate(uDT);
+ if( nSub == DI_CREATE )
+ ; // that's it !!
+ else if( nSub == DI_CHANGE )
+ {
+ aName = xDocProps->getModifiedBy();
+ uDT = xDocProps->getModificationDate();
+ aDate = DateTime(uDT);
+ }
+ else if( nSub == DI_PRINT )
+ {
+ aName = xDocProps->getPrintedBy();
+ if ( !std::getenv("STABLE_FIELDS_HACK") )
+ {
+ uDT = xDocProps->getPrintDate();
+ aDate = DateTime(uDT);
+ }
+ }
+ else
+ break;
+
+ if (aDate.IsValidAndGregorian())
+ {
+ switch (nExtSub & ~DI_SUB_FIXED)
+ {
+ case DI_SUB_AUTHOR:
+ aStr = aName;
+ break;
+
+ case DI_SUB_TIME:
+ if (!nFormat)
+ {
+ lcl_GetLocalDataWrapper( nLang, &pAppLocalData,
+ &pLocalData );
+ aStr = pLocalData->getTime( aDate,
+ false);
+ }
+ else
+ {
+ // start the number formatter
+ double fVal = SwDateTimeField::GetDateTime( *GetDoc(),
+ aDate);
+ aStr = ExpandValue(fVal, nFormat, nLang);
+ }
+ break;
+
+ case DI_SUB_DATE:
+ if (!nFormat)
+ {
+ lcl_GetLocalDataWrapper( nLang, &pAppLocalData,
+ &pLocalData );
+ aStr = pLocalData->getDate( aDate );
+ }
+ else
+ {
+ // start the number formatter
+ double fVal = SwDateTimeField::GetDateTime( *GetDoc(),
+ aDate);
+ aStr = ExpandValue(fVal, nFormat, nLang);
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ if( pAppLocalData != pLocalData )
+ delete pLocalData;
+
+ return aStr;
+}
+
+// document info field
+
+SwDocInfoField::SwDocInfoField(SwDocInfoFieldType* pTyp, sal_uInt16 nSub, const OUString& rName, sal_uInt32 nFormat) :
+ SwValueField(pTyp, nFormat), m_nSubType(nSub)
+{
+ m_aName = rName;
+ m_aContent = static_cast<SwDocInfoFieldType*>(GetTyp())->Expand(m_nSubType, nFormat, GetLanguage(), m_aName);
+}
+
+SwDocInfoField::SwDocInfoField(SwDocInfoFieldType* pTyp, sal_uInt16 nSub, const OUString& rName, const OUString& rValue, sal_uInt32 nFormat) :
+ SwValueField(pTyp, nFormat), m_nSubType(nSub)
+{
+ m_aName = rName;
+ m_aContent = rValue;
+}
+
+template<class T>
+static double lcl_TimeToDouble( const T& rTime )
+{
+ const double fNanoSecondsPerDay = 86400000000000.0;
+ return ( (rTime.Hours * SAL_CONST_INT64(3600000000000))
+ + (rTime.Minutes * SAL_CONST_INT64( 60000000000))
+ + (rTime.Seconds * SAL_CONST_INT64( 1000000000))
+ + (rTime.NanoSeconds))
+ / fNanoSecondsPerDay;
+}
+
+template<class D>
+static double lcl_DateToDouble( const D& rDate, const Date& rNullDate )
+{
+ tools::Long nDate = Date::DateToDays( rDate.Day, rDate.Month, rDate.Year );
+ tools::Long nNullDate = Date::DateToDays( rNullDate.GetDay(), rNullDate.GetMonth(), rNullDate.GetYear() );
+ return double( nDate - nNullDate );
+}
+
+OUString SwDocInfoField::ExpandImpl(SwRootFrame const*const) const
+{
+ if ( ( m_nSubType & 0xFF ) == DI_CUSTOM )
+ {
+ // custom properties currently need special treatment
+ // We don't have a secure way to detect "real" custom properties in Word import of text
+ // fields, so we treat *every* unknown property as a custom property, even the "built-in"
+ // section in Word's document summary information stream as these properties have not been
+ // inserted when the document summary information was imported, we do it here.
+ // This approach is still a lot better than the old one to import such fields as
+ // "user fields" and simple text
+ SwDocShell* pDocShell = GetDoc()->GetDocShell();
+ if( !pDocShell )
+ return m_aContent;
+ try
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS( pDocShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps( xDPS->getDocumentProperties());
+ uno::Reference < beans::XPropertySet > xSet( xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
+ uno::Reference < beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
+
+ uno::Any aAny;
+ if( xSetInfo->hasPropertyByName( m_aName ) )
+ aAny = xSet->getPropertyValue( m_aName );
+ if ( aAny.getValueType() != cppu::UnoType<void>::get() )
+ {
+ // "void" type means that the property has not been inserted until now
+ if ( !IsFixed() )
+ {
+ // if the field is "fixed" we don't update it from the property
+ OUString sVal;
+ uno::Reference < script::XTypeConverter > xConverter( script::Converter::create(comphelper::getProcessComponentContext()) );
+ util::Date aDate;
+ util::DateTime aDateTime;
+ util::Duration aDuration;
+ if( aAny >>= aDate)
+ {
+ SvNumberFormatter* pFormatter = pDocShell->GetDoc()->GetNumberFormatter();
+ const Date& rNullDate = pFormatter->GetNullDate();
+ sVal = ExpandValue( lcl_DateToDouble<util::Date>( aDate, rNullDate ), GetFormat(), GetLanguage());
+ }
+ else if( aAny >>= aDateTime )
+ {
+ double fDateTime = lcl_TimeToDouble<util::DateTime>( aDateTime );
+ SvNumberFormatter* pFormatter = pDocShell->GetDoc()->GetNumberFormatter();
+ const Date& rNullDate = pFormatter->GetNullDate();
+ fDateTime += lcl_DateToDouble<util::DateTime>( aDateTime, rNullDate );
+ sVal = ExpandValue( fDateTime, GetFormat(), GetLanguage());
+ }
+ else if( aAny >>= aDuration )
+ {
+ sVal = OUStringChar(aDuration.Negative ? '-' : '+')
+ + SwViewShell::GetShellRes()->sDurationFormat;
+ sVal = sVal.replaceFirst("%1", OUString::number( aDuration.Years ) );
+ sVal = sVal.replaceFirst("%2", OUString::number( aDuration.Months ) );
+ sVal = sVal.replaceFirst("%3", OUString::number( aDuration.Days ) );
+ sVal = sVal.replaceFirst("%4", OUString::number( aDuration.Hours ) );
+ sVal = sVal.replaceFirst("%5", OUString::number( aDuration.Minutes) );
+ sVal = sVal.replaceFirst("%6", OUString::number( aDuration.Seconds) );
+ }
+ else
+ {
+ uno::Any aNew = xConverter->convertToSimpleType( aAny, uno::TypeClass_STRING );
+ aNew >>= sVal;
+ }
+ const_cast<SwDocInfoField*>(this)->m_aContent = sVal;
+ }
+ }
+ }
+ catch (uno::Exception&) {}
+ }
+ else if ( !IsFixed() )
+ const_cast<SwDocInfoField*>(this)->m_aContent = static_cast<SwDocInfoFieldType*>(GetTyp())->Expand(m_nSubType, GetFormat(), GetLanguage(), m_aName);
+
+ return m_aContent;
+}
+
+OUString SwDocInfoField::GetFieldName() const
+{
+ OUString aStr(SwFieldType::GetTypeStr(GetTypeId()) + ":");
+
+ sal_uInt16 const nSub = m_nSubType & 0xff;
+
+ switch (nSub)
+ {
+ case DI_CUSTOM:
+ aStr += m_aName;
+ break;
+
+ default:
+ aStr += SwViewShell::GetShellRes()
+ ->aDocInfoLst[ nSub - DI_SUBTYPE_BEGIN ];
+ break;
+ }
+ if (IsFixed())
+ {
+ aStr += " " + SwViewShell::GetShellRes()->aFixedStr;
+ }
+ return aStr;
+}
+
+std::unique_ptr<SwField> SwDocInfoField::Copy() const
+{
+ std::unique_ptr<SwDocInfoField> pField(new SwDocInfoField(static_cast<SwDocInfoFieldType*>(GetTyp()), m_nSubType, m_aName, GetFormat()));
+ pField->SetAutomaticLanguage(IsAutomaticLanguage());
+ pField->m_aContent = m_aContent;
+
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+sal_uInt16 SwDocInfoField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwDocInfoField::SetSubType(sal_uInt16 nSub)
+{
+ m_nSubType = nSub;
+}
+
+void SwDocInfoField::SetLanguage(LanguageType nLng)
+{
+ if (!GetFormat())
+ SwField::SetLanguage(nLng);
+ else
+ SwValueField::SetLanguage(nLng);
+}
+
+bool SwDocInfoField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aContent;
+ break;
+
+ case FIELD_PROP_PAR4:
+ rAny <<= m_aName;
+ break;
+
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(m_aContent.toInt32());
+ break;
+
+ case FIELD_PROP_BOOL1:
+ rAny <<= 0 != (m_nSubType & DI_SUB_FIXED);
+ break;
+
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+
+ case FIELD_PROP_DOUBLE:
+ {
+ double fVal = GetValue();
+ rAny <<= fVal;
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= ExpandImpl(nullptr);
+ break;
+ case FIELD_PROP_BOOL2:
+ {
+ sal_uInt16 nExtSub = (m_nSubType & 0xff00) & ~DI_SUB_FIXED;
+ rAny <<= nExtSub == DI_SUB_DATE;
+ }
+ break;
+ default:
+ return SwField::QueryValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+bool SwDocInfoField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ sal_Int32 nValue = 0;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ if( m_nSubType & DI_SUB_FIXED )
+ rAny >>= m_aContent;
+ break;
+
+ case FIELD_PROP_USHORT1:
+ if( m_nSubType & DI_SUB_FIXED )
+ {
+ rAny >>= nValue;
+ m_aContent = OUString::number(nValue);
+ }
+ break;
+
+ case FIELD_PROP_BOOL1:
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType |= DI_SUB_FIXED;
+ else
+ m_nSubType &= ~DI_SUB_FIXED;
+ break;
+ case FIELD_PROP_FORMAT:
+ {
+ rAny >>= nValue;
+ if( nValue >= 0)
+ SetFormat(nValue);
+ }
+ break;
+
+ case FIELD_PROP_PAR3:
+ rAny >>= m_aContent;
+ break;
+ case FIELD_PROP_BOOL2:
+ m_nSubType &= 0xf0ff;
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType |= DI_SUB_DATE;
+ else
+ m_nSubType |= DI_SUB_TIME;
+ break;
+ default:
+ return SwField::PutValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+SwHiddenTextFieldType::SwHiddenTextFieldType( bool bSetHidden )
+ : SwFieldType( SwFieldIds::HiddenText ), m_bHidden( bSetHidden )
+{
+}
+
+std::unique_ptr<SwFieldType> SwHiddenTextFieldType::Copy() const
+{
+ return std::make_unique<SwHiddenTextFieldType>( m_bHidden );
+}
+
+void SwHiddenTextFieldType::SetHiddenFlag( bool bSetHidden )
+{
+ if( m_bHidden != bSetHidden )
+ {
+ m_bHidden = bSetHidden;
+ UpdateFields(); // notify all HiddenTexts
+ }
+}
+
+SwHiddenTextField::SwHiddenTextField( SwHiddenTextFieldType* pFieldType,
+ bool bConditional,
+ OUString aCond,
+ const OUString& rStr,
+ bool bHidden,
+ SwFieldTypesEnum nSub) :
+ SwField( pFieldType ), m_aCond(std::move(aCond)), m_nSubType(nSub),
+ m_bCanToggle(bConditional), m_bIsHidden(bHidden), m_bValid(false)
+{
+ if(m_nSubType == SwFieldTypesEnum::ConditionalText)
+ {
+ sal_Int32 nPos = 0;
+ m_aTRUEText = rStr.getToken(0, '|', nPos);
+
+ if(nPos != -1)
+ {
+ m_aFALSEText = rStr.getToken(0, '|', nPos);
+ if(nPos != -1)
+ {
+ m_aContent = rStr.getToken(0, '|', nPos);
+ m_bValid = true;
+ }
+ }
+ }
+ else
+ m_aTRUEText = rStr;
+}
+
+SwHiddenTextField::SwHiddenTextField( SwHiddenTextFieldType* pFieldType,
+ OUString aCond,
+ OUString aTrue,
+ OUString aFalse,
+ SwFieldTypesEnum nSub)
+ : SwField( pFieldType ), m_aTRUEText(std::move(aTrue)), m_aFALSEText(std::move(aFalse)), m_aCond(std::move(aCond)), m_nSubType(nSub),
+ m_bIsHidden(true), m_bValid(false)
+{
+ m_bCanToggle = !m_aCond.isEmpty();
+}
+
+OUString SwHiddenTextField::ExpandImpl(SwRootFrame const*const) const
+{
+ // Type: !Hidden -> show always
+ // Hide -> evaluate condition
+
+ if( SwFieldTypesEnum::ConditionalText == m_nSubType )
+ {
+ if( m_bValid )
+ return m_aContent;
+
+ if( m_bCanToggle && !m_bIsHidden )
+ return m_aTRUEText;
+ }
+ else if( !static_cast<SwHiddenTextFieldType*>(GetTyp())->GetHiddenFlag() ||
+ ( m_bCanToggle && m_bIsHidden ))
+ return m_aTRUEText;
+
+ return m_aFALSEText;
+}
+
+/// get current field value and cache it
+void SwHiddenTextField::Evaluate(SwDoc& rDoc)
+{
+ if( SwFieldTypesEnum::ConditionalText != m_nSubType )
+ return;
+
+#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
+ (void) rDoc;
+#else
+ SwDBManager* pMgr = rDoc.GetDBManager();
+#endif
+ m_bValid = false;
+ OUString sTmpName = (m_bCanToggle && !m_bIsHidden) ? m_aTRUEText : m_aFALSEText;
+
+ // Database expressions need to be different from normal text. Therefore, normal text is set
+ // in quotes. If the latter exist they will be removed. If not, check if potential DB name.
+ // Only if there are two or more dots and no quotes, we assume a database.
+ if (sTmpName.getLength()>1 &&
+ sTmpName.startsWith("\"") &&
+ sTmpName.endsWith("\""))
+ {
+ m_aContent = sTmpName.copy(1, sTmpName.getLength() - 2);
+ m_bValid = true;
+ }
+ else if(sTmpName.indexOf('\"')<0 &&
+ comphelper::string::getTokenCount(sTmpName, '.') > 2)
+ {
+ sTmpName = ::ReplacePoint(sTmpName);
+ if(sTmpName.startsWith("[") && sTmpName.endsWith("]"))
+ { // remove brackets
+ sTmpName = sTmpName.copy(1, sTmpName.getLength() - 2);
+ }
+#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
+ if( pMgr)
+ {
+ sal_Int32 nIdx{ 0 };
+ OUString sDBName( GetDBName( sTmpName, rDoc ));
+ OUString sDataSource(sDBName.getToken(0, DB_DELIM, nIdx));
+ OUString sDataTableOrQuery(sDBName.getToken(0, DB_DELIM, nIdx));
+ if( pMgr->IsInMerge() && !sDBName.isEmpty() &&
+ pMgr->IsDataSourceOpen( sDataSource,
+ sDataTableOrQuery, false))
+ {
+ double fNumber;
+ pMgr->GetMergeColumnCnt(GetColumnName( sTmpName ),
+ GetLanguage(), m_aContent, &fNumber );
+ m_bValid = true;
+ }
+ }
+#endif
+ }
+}
+
+OUString SwHiddenTextField::GetFieldName() const
+{
+ OUString aStr = SwFieldType::GetTypeStr(m_nSubType) +
+ " " + m_aCond + " " + m_aTRUEText;
+
+ if (m_nSubType == SwFieldTypesEnum::ConditionalText)
+ {
+ aStr += " : " + m_aFALSEText;
+ }
+ return aStr;
+}
+
+std::unique_ptr<SwField> SwHiddenTextField::Copy() const
+{
+ std::unique_ptr<SwHiddenTextField> pField(
+ new SwHiddenTextField(static_cast<SwHiddenTextFieldType*>(GetTyp()), m_aCond,
+ m_aTRUEText, m_aFALSEText));
+ pField->m_bIsHidden = m_bIsHidden;
+ pField->m_bValid = m_bValid;
+ pField->m_aContent = m_aContent;
+ pField->SetFormat(GetFormat());
+ pField->m_nSubType = m_nSubType;
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+/// set condition
+void SwHiddenTextField::SetPar1(const OUString& rStr)
+{
+ m_aCond = rStr;
+ m_bCanToggle = !m_aCond.isEmpty();
+}
+
+OUString SwHiddenTextField::GetPar1() const
+{
+ return m_aCond;
+}
+
+/// set True/False text
+void SwHiddenTextField::SetPar2(const OUString& rStr)
+{
+ if (m_nSubType == SwFieldTypesEnum::ConditionalText)
+ {
+ sal_Int32 nPos = rStr.indexOf('|');
+ if (nPos == -1)
+ m_aTRUEText = rStr;
+ else
+ {
+ m_aTRUEText = rStr.copy(0, nPos);
+ m_aFALSEText = rStr.copy(nPos + 1);
+ }
+ }
+ else
+ m_aTRUEText = rStr;
+}
+
+/// get True/False text
+OUString SwHiddenTextField::GetPar2() const
+{
+ if(m_nSubType != SwFieldTypesEnum::ConditionalText)
+ {
+ return m_aTRUEText;
+ }
+ return m_aTRUEText + "|" + m_aFALSEText;
+}
+
+sal_uInt16 SwHiddenTextField::GetSubType() const
+{
+ return static_cast<sal_uInt16>(m_nSubType);
+}
+
+bool SwHiddenTextField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aCond;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_aTRUEText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= m_aFALSEText;
+ break;
+ case FIELD_PROP_PAR4 :
+ rAny <<= m_aContent;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= m_bIsHidden;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwHiddenTextField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ {
+ OUString sVal;
+ rAny >>= sVal;
+ SetPar1(sVal);
+ }
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_aTRUEText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny >>= m_aFALSEText;
+ break;
+ case FIELD_PROP_BOOL1:
+ m_bIsHidden = *o3tl::doAccess<bool>(rAny);
+ break;
+ case FIELD_PROP_PAR4:
+ rAny >>= m_aContent;
+ m_bValid = true;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+OUString SwHiddenTextField::GetColumnName(const OUString& rName)
+{
+ sal_Int32 nPos = rName.indexOf(DB_DELIM);
+ if( nPos>=0 )
+ {
+ nPos = rName.indexOf(DB_DELIM, nPos + 1);
+
+ if( nPos>=0 )
+ return rName.copy(nPos + 1);
+ }
+ return rName;
+}
+
+OUString SwHiddenTextField::GetDBName(std::u16string_view rName, SwDoc& rDoc)
+{
+ size_t nPos = rName.find(DB_DELIM);
+ if( nPos != std::u16string_view::npos )
+ {
+ nPos = rName.find(DB_DELIM, nPos + 1);
+
+ if( nPos != std::u16string_view::npos )
+ return OUString(rName.substr(0, nPos));
+ }
+
+ SwDBData aData = rDoc.GetDBData();
+ return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand;
+}
+
+// [aFieldDefinition] value sample : " IF A == B \"TrueText\" \"FalseText\""
+void SwHiddenTextField::ParseIfFieldDefinition(std::u16string_view aFieldDefinition,
+ OUString& rCondition,
+ OUString& rTrue,
+ OUString& rFalse)
+{
+ // get all positions inside the input string where words are started
+ //
+ // In: " IF A == B \"TrueText\" \"FalseText\""
+ // 0 1 2 3
+ // 01234567890 123456789 01 2345678901 2
+ //
+ // result:
+ // [1, 4, 6, 9, 11, 22]
+ std::vector<sal_Int32> wordPosition;
+ {
+ bool quoted = false;
+ bool insideWord = false;
+ for (size_t i = 0; i < aFieldDefinition.size(); i++)
+ {
+ if (quoted)
+ {
+ if (aFieldDefinition[i] == '\"')
+ {
+ quoted = false;
+ insideWord = false;
+ }
+ }
+ else
+ {
+ if (aFieldDefinition[i] == ' ')
+ {
+ // word delimiter
+ insideWord = false;
+ }
+ else
+ {
+ if (insideWord)
+ {
+ quoted = (aFieldDefinition[i] == '\"');
+ }
+ else
+ {
+ insideWord = true;
+ wordPosition.push_back(i);
+ quoted = (aFieldDefinition[i] == '\"');
+ }
+ }
+ }
+ }
+ }
+
+ // first word is always "IF"
+ // last two words are: true-case and false-case,
+ // everything before is treated as condition expression
+ // => we need at least 4 words to be inside the input string
+ if (wordPosition.size() < 4)
+ {
+ return;
+ }
+
+
+ const sal_Int32 conditionBegin = wordPosition[1];
+ const sal_Int32 trueBegin = wordPosition[wordPosition.size() - 2];
+ const sal_Int32 falseBegin = wordPosition[wordPosition.size() - 1];
+
+ const sal_Int32 conditionLength = trueBegin - conditionBegin;
+ const sal_Int32 trueLength = falseBegin - trueBegin;
+
+ // Syntax
+ // OUString::copy( sal_Int32 beginIndex, sal_Int32 count )
+ rCondition = o3tl::trim(aFieldDefinition.substr(conditionBegin, conditionLength));
+ rTrue = o3tl::trim(aFieldDefinition.substr(trueBegin, trueLength));
+ rFalse = o3tl::trim(aFieldDefinition.substr(falseBegin));
+
+ // remove quotes
+ if (rCondition.getLength() >= 2)
+ {
+ if (rCondition[0] == '\"' && rCondition[rCondition.getLength() - 1] == '\"')
+ rCondition = rCondition.copy(1, rCondition.getLength() - 2);
+ }
+ if (rTrue.getLength() >= 2)
+ {
+ if (rTrue[0] == '\"' && rTrue[rTrue.getLength() - 1] == '\"')
+ rTrue = rTrue.copy(1, rTrue.getLength() - 2);
+ }
+ if (rFalse.getLength() >= 2)
+ {
+ if (rFalse[0] == '\"' && rFalse[rFalse.getLength() - 1] == '\"')
+ rFalse = rFalse.copy(1, rFalse.getLength() - 2);
+ }
+
+ // Note: do not make trim once again, while this is a user defined data
+}
+
+// field type for line height 0
+
+SwHiddenParaFieldType::SwHiddenParaFieldType()
+ : SwFieldType( SwFieldIds::HiddenPara )
+{
+}
+
+std::unique_ptr<SwFieldType> SwHiddenParaFieldType::Copy() const
+{
+ return std::make_unique<SwHiddenParaFieldType>();
+}
+
+// field for line height 0
+
+SwHiddenParaField::SwHiddenParaField(SwHiddenParaFieldType* pTyp, OUString aStr)
+ : SwField(pTyp), m_aCond(std::move(aStr))
+{
+ m_bIsHidden = false;
+}
+
+OUString SwHiddenParaField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwHiddenParaField::Copy() const
+{
+ std::unique_ptr<SwHiddenParaField> pField(new SwHiddenParaField(static_cast<SwHiddenParaFieldType*>(GetTyp()), m_aCond));
+ pField->m_bIsHidden = m_bIsHidden;
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+bool SwHiddenParaField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aCond;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= m_bIsHidden;
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwHiddenParaField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aCond;
+ break;
+ case FIELD_PROP_BOOL1:
+ m_bIsHidden = *o3tl::doAccess<bool>(rAny);
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/// set condition
+void SwHiddenParaField::SetPar1(const OUString& rStr)
+{
+ m_aCond = rStr;
+}
+
+OUString SwHiddenParaField::GetPar1() const
+{
+ return m_aCond;
+}
+
+// PostIt field type
+
+SwPostItFieldType::SwPostItFieldType(SwDoc& rDoc)
+ : SwFieldType( SwFieldIds::Postit )
+ , mrDoc(rDoc)
+{}
+
+std::unique_ptr<SwFieldType> SwPostItFieldType::Copy() const
+{
+ return std::make_unique<SwPostItFieldType>(mrDoc);
+}
+
+// PostIt field
+
+sal_uInt32 SwPostItField::s_nLastPostItId = 1;
+
+SwPostItField::SwPostItField( SwPostItFieldType* pT,
+ OUString aAuthor,
+ OUString aText,
+ OUString aInitials,
+ OUString aName,
+ const DateTime& rDateTime,
+ const bool bResolved,
+ const sal_uInt32 nPostItId,
+ const sal_uInt32 nParentId,
+ const sal_uInt32 nParaId,
+ const sal_uInt32 nParentPostItId,
+ const OUString aParentName
+)
+ : SwField( pT )
+ , m_sText( std::move(aText) )
+ , m_sAuthor( std::move(aAuthor) )
+ , m_sInitials( std::move(aInitials) )
+ , m_sName( std::move(aName) )
+ , m_aDateTime( rDateTime )
+ , m_bResolved( bResolved )
+ , m_nParentId( nParentId )
+ , m_nParaId( nParaId )
+ , m_nParentPostItId ( nParentPostItId )
+ , m_sParentName( aParentName )
+{
+ m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId;
+}
+
+SwPostItField::~SwPostItField()
+{
+ if ( m_xTextObject.is() )
+ {
+ m_xTextObject->DisposeEditSource();
+ }
+
+ mpText.reset();
+}
+
+OUString SwPostItField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+OUString SwPostItField::GetDescription() const
+{
+ return SwResId(STR_NOTE);
+}
+
+void SwPostItField::SetResolved(bool bNewState)
+{
+ m_bResolved = bNewState;
+}
+
+void SwPostItField::ToggleResolved()
+{
+ m_bResolved = !m_bResolved;
+}
+
+bool SwPostItField::GetResolved() const
+{
+ return m_bResolved;
+}
+
+std::unique_ptr<SwField> SwPostItField::Copy() const
+{
+ std::unique_ptr<SwPostItField> pRet(new SwPostItField( static_cast<SwPostItFieldType*>(GetTyp()), m_sAuthor, m_sText, m_sInitials, m_sName,
+ m_aDateTime, m_bResolved, m_nPostItId, m_nParentId, m_nParaId, m_nParentPostItId, m_sParentName));
+ if (mpText)
+ pRet->SetTextObject( *mpText );
+
+ // Note: member <m_xTextObject> not copied.
+
+ return std::unique_ptr<SwField>(pRet.release());
+}
+
+/// set author
+void SwPostItField::SetPar1(const OUString& rStr)
+{
+ m_sAuthor = rStr;
+}
+
+/// get author
+OUString SwPostItField::GetPar1() const
+{
+ return m_sAuthor;
+}
+
+/// set the PostIt's text
+void SwPostItField::SetPar2(const OUString& rStr)
+{
+ m_sText = rStr;
+}
+
+/// get the PostIt's text
+OUString SwPostItField::GetPar2() const
+{
+ return m_sText;
+}
+
+
+void SwPostItField::SetName(const OUString& rName)
+{
+ m_sName = rName;
+}
+
+void SwPostItField::SetParentName(const OUString& rName)
+{
+ m_sParentName = rName;
+}
+
+void SwPostItField::SetTextObject( std::optional<OutlinerParaObject> pText )
+{
+ mpText = std::move(pText);
+}
+
+sal_Int32 SwPostItField::GetNumberOfParagraphs() const
+{
+ return mpText ? mpText->Count() : 1;
+}
+
+void SwPostItField::ChangeStyleSheetName(std::u16string_view rOldName, const SfxStyleSheetBase* pStyleSheet)
+{
+ if (mpText && pStyleSheet)
+ mpText->ChangeStyleSheetName(pStyleSheet->GetFamily(), rOldName, pStyleSheet->GetName());
+}
+
+void SwPostItField::SetPostItId(const sal_uInt32 nPostItId)
+{
+ m_nPostItId = nPostItId == 0 ? s_nLastPostItId++ : nPostItId;
+}
+
+void SwPostItField::SetParentPostItId(const sal_uInt32 nParentPostItId)
+{
+ m_nParentPostItId = nParentPostItId;
+}
+
+void SwPostItField::SetParentId(const sal_uInt32 nParentId)
+{
+ m_nParentId = nParentId;
+}
+
+void SwPostItField::SetParaId(const sal_uInt32 nParaId)
+{
+ m_nParaId = nParaId;
+}
+
+bool SwPostItField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sAuthor;
+ break;
+ case FIELD_PROP_PAR2:
+ {
+ rAny <<= m_sText;
+ break;
+ }
+ case FIELD_PROP_PAR3:
+ rAny <<= m_sInitials;
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= m_sName;
+ break;
+ case FIELD_PROP_PAR7: // PAR5 (Parent Para Id) and PAR6 (Para Id) are skipped - they are not written into xml. Used for file conversion.
+ rAny <<= m_sParentName;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= m_bResolved;
+ break;
+ case FIELD_PROP_TEXT:
+ {
+ if ( !m_xTextObject.is() )
+ {
+ SwPostItFieldType* pGetType = static_cast<SwPostItFieldType*>(GetTyp());
+ SwDoc& rDoc = pGetType->GetDoc();
+ auto pObj = std::make_unique<SwTextAPIEditSource>( &rDoc );
+ const_cast <SwPostItField*> (this)->m_xTextObject = new SwTextAPIObject( std::move(pObj) );
+ }
+
+ if ( mpText )
+ m_xTextObject->SetText( *mpText );
+ else
+ m_xTextObject->SetString( m_sText );
+
+ uno::Reference < text::XText > xText( m_xTextObject );
+ rAny <<= xText;
+ break;
+ }
+ case FIELD_PROP_DATE:
+ {
+ rAny <<= m_aDateTime.GetUNODate();
+ }
+ break;
+ case FIELD_PROP_DATE_TIME:
+ {
+ rAny <<= m_aDateTime.GetUNODateTime();
+ }
+ break;
+ case FIELD_PROP_PAR5:
+ {
+ rAny <<= OUString(OUString::number(m_nParentId, 16).toAsciiUpperCase());
+ }
+ break;
+ case FIELD_PROP_PAR6:
+ {
+ rAny <<= OUString(OUString::number(m_nPostItId, 16).toAsciiUpperCase());
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwPostItField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_sAuthor;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_sText;
+ //#i100374# new string via api, delete complex text object so SwPostItNote picks up the new string
+ mpText.reset();
+ break;
+ case FIELD_PROP_PAR3:
+ rAny >>= m_sInitials;
+ break;
+ case FIELD_PROP_PAR4:
+ rAny >>= m_sName;
+ break;
+ case FIELD_PROP_PAR7: // PAR5 (Parent Para Id) and PAR6 (Para Id) are skipped - they are not written into xml. Used for file conversion.
+ rAny >>= m_sParentName;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny >>= m_bResolved;
+ break;
+ case FIELD_PROP_TEXT:
+ OSL_FAIL("Not implemented!");
+ break;
+ case FIELD_PROP_DATE:
+ if( auto aSetDate = o3tl::tryAccess<util::Date>(rAny) )
+ {
+ m_aDateTime = Date(aSetDate->Day, aSetDate->Month, aSetDate->Year);
+ }
+ break;
+ case FIELD_PROP_DATE_TIME:
+ {
+ util::DateTime aDateTimeValue;
+ if(!(rAny >>= aDateTimeValue))
+ return false;
+ m_aDateTime = DateTime(aDateTimeValue);
+ }
+ break;
+ case FIELD_PROP_PAR5:
+ {
+ OUString sTemp;
+ rAny >>= sTemp;
+ m_nParentId = sTemp.toInt32(16);
+ }
+ break;
+ case FIELD_PROP_PAR6:
+ {
+ OUString sTemp;
+ rAny >>= sTemp;
+ m_nPostItId = sTemp.toInt32(16);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+void SwPostItField::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwPostItField"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("name"), BAD_CAST(GetName().toUtf8().getStr()));
+
+ SwField::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("mpText"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", mpText ? &*mpText : nullptr);
+ if (mpText)
+ mpText->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+// extended user information field type
+
+SwExtUserFieldType::SwExtUserFieldType()
+ : SwFieldType( SwFieldIds::ExtUser )
+{
+}
+
+std::unique_ptr<SwFieldType> SwExtUserFieldType::Copy() const
+{
+ return std::make_unique<SwExtUserFieldType>();
+}
+
+OUString SwExtUserFieldType::Expand(sal_uInt16 nSub )
+{
+ UserOptToken nRet = static_cast<UserOptToken>(USHRT_MAX);
+ switch(nSub)
+ {
+ case EU_FIRSTNAME: nRet = UserOptToken::FirstName; break;
+ case EU_NAME: nRet = UserOptToken::LastName; break;
+ case EU_SHORTCUT: nRet = UserOptToken::ID; break;
+
+ case EU_COMPANY: nRet = UserOptToken::Company; break;
+ case EU_STREET: nRet = UserOptToken::Street; break;
+ case EU_TITLE: nRet = UserOptToken::Title; break;
+ case EU_POSITION: nRet = UserOptToken::Position; break;
+ case EU_PHONE_PRIVATE: nRet = UserOptToken::TelephoneHome; break;
+ case EU_PHONE_COMPANY: nRet = UserOptToken::TelephoneWork; break;
+ case EU_FAX: nRet = UserOptToken::Fax; break;
+ case EU_EMAIL: nRet = UserOptToken::Email; break;
+ case EU_COUNTRY: nRet = UserOptToken::Country; break;
+ case EU_ZIP: nRet = UserOptToken::Zip; break;
+ case EU_CITY: nRet = UserOptToken::City; break;
+ case EU_STATE: nRet = UserOptToken::State; break;
+ case EU_FATHERSNAME: nRet = UserOptToken::FathersName; break;
+ case EU_APARTMENT: nRet = UserOptToken::Apartment; break;
+ default: OSL_ENSURE( false, "Field unknown");
+ }
+ if( static_cast<UserOptToken>(USHRT_MAX) != nRet )
+ {
+ SvtUserOptions& rUserOpt = SW_MOD()->GetUserOptions();
+ return rUserOpt.GetToken( nRet );
+ }
+ return OUString();
+}
+
+// extended user information field
+
+SwExtUserField::SwExtUserField(SwExtUserFieldType* pTyp, sal_uInt16 nSubTyp, sal_uInt32 nFormat) :
+ SwField(pTyp, nFormat), m_nType(nSubTyp)
+{
+ m_aContent = SwExtUserFieldType::Expand(m_nType);
+}
+
+OUString SwExtUserField::ExpandImpl(SwRootFrame const*const) const
+{
+ if (!IsFixed())
+ const_cast<SwExtUserField*>(this)->m_aContent = SwExtUserFieldType::Expand(m_nType);
+
+ return m_aContent;
+}
+
+std::unique_ptr<SwField> SwExtUserField::Copy() const
+{
+ std::unique_ptr<SwExtUserField> pField(new SwExtUserField(static_cast<SwExtUserFieldType*>(GetTyp()), m_nType, GetFormat()));
+ pField->SetExpansion(m_aContent);
+
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+sal_uInt16 SwExtUserField::GetSubType() const
+{
+ return m_nType;
+}
+
+void SwExtUserField::SetSubType(sal_uInt16 nSub)
+{
+ m_nType = nSub;
+}
+
+bool SwExtUserField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_aContent;
+ break;
+
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nTmp = m_nType;
+ rAny <<= nTmp;
+ }
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= IsFixed();
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwExtUserField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_aContent;
+ break;
+
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nTmp = 0;
+ rAny >>= nTmp;
+ m_nType = nTmp;
+ }
+ break;
+ case FIELD_PROP_BOOL1:
+ if( *o3tl::doAccess<bool>(rAny) )
+ SetFormat(GetFormat() | AF_FIXED);
+ else
+ SetFormat(GetFormat() & ~AF_FIXED);
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+// field type for relative page numbers
+
+SwRefPageSetFieldType::SwRefPageSetFieldType()
+ : SwFieldType( SwFieldIds::RefPageSet )
+{
+}
+
+std::unique_ptr<SwFieldType> SwRefPageSetFieldType::Copy() const
+{
+ return std::make_unique<SwRefPageSetFieldType>();
+}
+
+// overridden since there is nothing to update
+void SwRefPageSetFieldType::SwClientNotify(const SwModify&, const SfxHint&)
+{
+}
+
+// field for relative page numbers
+
+SwRefPageSetField::SwRefPageSetField( SwRefPageSetFieldType* pTyp,
+ short nOff, bool bFlag )
+ : SwField( pTyp ), m_nOffset( nOff ), m_bOn( bFlag )
+{
+}
+
+OUString SwRefPageSetField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwRefPageSetField::Copy() const
+{
+ return std::make_unique<SwRefPageSetField>( static_cast<SwRefPageSetFieldType*>(GetTyp()), m_nOffset, m_bOn );
+}
+
+OUString SwRefPageSetField::GetPar2() const
+{
+ return OUString::number(GetOffset());
+}
+
+void SwRefPageSetField::SetPar2(const OUString& rStr)
+{
+ SetOffset( static_cast<short>(rStr.toInt32()) );
+}
+
+bool SwRefPageSetField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ rAny <<= m_bOn;
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(m_nOffset);
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwRefPageSetField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ m_bOn = *o3tl::doAccess<bool>(rAny);
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny >>=m_nOffset;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+// relative page numbers - query field
+
+SwRefPageGetFieldType::SwRefPageGetFieldType( SwDoc& rDc )
+ : SwFieldType( SwFieldIds::RefPageGet ), m_rDoc( rDc ), m_nNumberingType( SVX_NUM_ARABIC )
+{
+}
+
+std::unique_ptr<SwFieldType> SwRefPageGetFieldType::Copy() const
+{
+ std::unique_ptr<SwRefPageGetFieldType> pNew(new SwRefPageGetFieldType( m_rDoc ));
+ pNew->m_nNumberingType = m_nNumberingType;
+ return pNew;
+}
+
+void SwRefPageGetFieldType::SwClientNotify(const SwModify&, const SfxHint& rHint)
+{
+ if (rHint.GetId() != SfxHintId::SwLegacyModify)
+ return;
+ auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
+ auto const ModifyImpl = [this](SwRootFrame const*const pLayout)
+ {
+ // first collect all SetPageRefFields
+ SetGetExpFields aTmpLst;
+ if (MakeSetList(aTmpLst, pLayout))
+ {
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(auto pFormatField: vFields)
+ UpdateField(pFormatField->GetTextField(), aTmpLst, pLayout);
+ }
+ };
+
+ // update all GetReference fields
+ if( !pLegacy->m_pNew && !pLegacy->m_pOld && HasWriterListeners() )
+ {
+ SwRootFrame const* pLayout(nullptr);
+ SwRootFrame const* pLayoutRLHidden(nullptr);
+ for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
+ {
+ if (pLay->IsHideRedlines())
+ {
+ pLayoutRLHidden = pLay;
+ }
+ else
+ {
+ pLayout = pLay;
+ }
+ }
+ ModifyImpl(pLayout);
+ if (pLayoutRLHidden)
+ {
+ ModifyImpl(pLayoutRLHidden);
+ }
+ }
+
+ // forward to text fields, they "expand" the text
+ CallSwClientNotify(rHint);
+}
+
+bool SwRefPageGetFieldType::MakeSetList(SetGetExpFields& rTmpLst,
+ SwRootFrame const*const pLayout)
+{
+ IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
+ std::vector<SwFormatField*> vFields;
+ m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::RefPageSet)->GatherFields(vFields);
+ for(auto pFormatField: vFields)
+ {
+ // update only the GetRef fields
+ const SwTextField* pTField = pFormatField->GetTextField();
+ if (!pLayout || !pLayout->IsHideRedlines() || !sw::IsFieldDeletedInModel(rIDRA, *pTField))
+ {
+ const SwTextNode& rTextNd = pTField->GetTextNode();
+
+ // Always the first! (in Tab-Headline, header/footer )
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+ const SwContentFrame *const pFrame = rTextNd.getLayoutFrame(
+ pLayout, nullptr, &tmp);
+
+ std::unique_ptr<SetGetExpField> pNew;
+
+ if( !pFrame ||
+ pFrame->IsInDocBody() ||
+ // #i31868#
+ // Check if pFrame is not yet connected to the layout.
+ !pFrame->FindPageFrame() )
+ {
+ pNew.reset( new SetGetExpField( rTextNd, pTField ) );
+ }
+ else
+ {
+ // create index for determination of the TextNode
+ SwPosition aPos( m_rDoc.GetNodes().GetEndOfPostIts() );
+ bool const bResult = GetBodyTextNode( m_rDoc, aPos, *pFrame );
+ OSL_ENSURE(bResult, "where is the Field?");
+ pNew.reset( new SetGetExpField( aPos.GetNode(), pTField,
+ aPos.GetContentIndex() ) );
+ }
+
+ rTmpLst.insert( std::move(pNew) );
+ }
+ }
+ return !rTmpLst.empty();
+}
+
+void SwRefPageGetFieldType::UpdateField( SwTextField const * pTextField,
+ SetGetExpFields const & rSetList,
+ SwRootFrame const*const pLayout)
+{
+ SwRefPageGetField* pGetField = const_cast<SwRefPageGetField*>(static_cast<const SwRefPageGetField*>(pTextField->GetFormatField().GetField()));
+ pGetField->SetText( OUString(), pLayout );
+
+ // then search the correct RefPageSet field
+ SwTextNode* pTextNode = &pTextField->GetTextNode();
+ if( pTextNode->StartOfSectionIndex() >
+ m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
+ {
+ SetGetExpField aEndField( *pTextNode, pTextField );
+
+ SetGetExpFields::const_iterator itLast = rSetList.lower_bound( &aEndField );
+
+ if( itLast != rSetList.begin() )
+ {
+ --itLast;
+ const SwTextField* pRefTextField = (*itLast)->GetTextField();
+ const SwRefPageSetField* pSetField =
+ static_cast<const SwRefPageSetField*>(pRefTextField->GetFormatField().GetField());
+ if( pSetField->IsOn() )
+ {
+ // determine the correct offset
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+ const SwContentFrame *const pFrame = pTextNode->getLayoutFrame(
+ pLayout, nullptr, &tmp);
+ const SwContentFrame *const pRefFrame = pRefTextField->GetTextNode().getLayoutFrame(
+ pLayout, nullptr, &tmp);
+ const SwPageFrame* pPgFrame = nullptr;
+ short nDiff = 1;
+ if ( pFrame && pRefFrame )
+ {
+ pPgFrame = pFrame->FindPageFrame();
+ nDiff = pPgFrame->GetPhyPageNum() -
+ pRefFrame->FindPageFrame()->GetPhyPageNum() + 1;
+ }
+
+ SvxNumType nTmpFormat = SVX_NUM_PAGEDESC == static_cast<SvxNumType>(pGetField->GetFormat())
+ ? ( !pPgFrame
+ ? SVX_NUM_ARABIC
+ : pPgFrame->GetPageDesc()->GetNumType().GetNumberingType() )
+ : static_cast<SvxNumType>(pGetField->GetFormat());
+ const short nPageNum = std::max<short>(0, pSetField->GetOffset() + nDiff);
+ pGetField->SetText(FormatNumber(nPageNum, nTmpFormat), pLayout);
+ }
+ }
+ }
+ // start formatting
+ const_cast<SwFormatField&>(pTextField->GetFormatField()).ForceUpdateTextNode();
+}
+
+// queries for relative page numbering
+
+SwRefPageGetField::SwRefPageGetField( SwRefPageGetFieldType* pTyp,
+ sal_uInt32 nFormat )
+ : SwField( pTyp, nFormat )
+{
+}
+
+void SwRefPageGetField::SetText(const OUString& rText,
+ SwRootFrame const*const pLayout)
+{
+ if (!pLayout || !pLayout->IsHideRedlines())
+ {
+ m_sText = rText;
+ }
+ if (!pLayout || pLayout->IsHideRedlines())
+ {
+ m_sTextRLHidden = rText;
+ }
+}
+
+OUString SwRefPageGetField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ return pLayout && pLayout->IsHideRedlines() ? m_sTextRLHidden : m_sText;
+}
+
+std::unique_ptr<SwField> SwRefPageGetField::Copy() const
+{
+ std::unique_ptr<SwRefPageGetField> pCpy(new SwRefPageGetField(
+ static_cast<SwRefPageGetFieldType*>(GetTyp()), GetFormat() ));
+ pCpy->m_sText = m_sText;
+ pCpy->m_sTextRLHidden = m_sTextRLHidden;
+ return std::unique_ptr<SwField>(pCpy.release());
+}
+
+void SwRefPageGetField::ChangeExpansion(const SwFrame& rFrame,
+ const SwTextField* pField )
+{
+ // only fields in Footer, Header, FootNote, Flys
+ SwRefPageGetFieldType* pGetType = static_cast<SwRefPageGetFieldType*>(GetTyp());
+ SwDoc& rDoc = pGetType->GetDoc();
+ if( pField->GetTextNode().StartOfSectionIndex() >
+ rDoc.GetNodes().GetEndOfExtras().GetIndex() )
+ return;
+
+ SwRootFrame const& rLayout(*rFrame.getRootFrame());
+ OUString & rText(rLayout.IsHideRedlines() ? m_sTextRLHidden : m_sText);
+ rText.clear();
+
+ OSL_ENSURE(!rFrame.IsInDocBody(), "Flag incorrect, frame is in DocBody");
+
+ // collect all SetPageRefFields
+ SetGetExpFields aTmpLst;
+ if (!pGetType->MakeSetList(aTmpLst, &rLayout))
+ return ;
+
+ // create index for determination of the TextNode
+ SwPosition aPos( rDoc.GetNodes() );
+ SwTextNode* pTextNode = const_cast<SwTextNode*>(GetBodyTextNode(rDoc, aPos, rFrame));
+
+ // If no layout exists, ChangeExpansion is called for header and
+ // footer lines via layout formatting without existing TextNode.
+ if(!pTextNode)
+ return;
+
+ SetGetExpField aEndField( aPos.GetNode(), pField, aPos.GetContentIndex() );
+
+ SetGetExpFields::const_iterator itLast = aTmpLst.lower_bound( &aEndField );
+
+ if( itLast == aTmpLst.begin() )
+ return; // there is no corresponding set-field in front
+ --itLast;
+
+ const SwTextField* pRefTextField = (*itLast)->GetTextField();
+ const SwRefPageSetField* pSetField =
+ static_cast<const SwRefPageSetField*>(pRefTextField->GetFormatField().GetField());
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+ const SwContentFrame *const pRefFrame = pRefTextField->GetTextNode().getLayoutFrame(
+ &rLayout, nullptr, &tmp);
+ if( !(pSetField->IsOn() && pRefFrame) )
+ return;
+
+ // determine the correct offset
+ const SwPageFrame* pPgFrame = rFrame.FindPageFrame();
+ const short nDiff = pPgFrame->GetPhyPageNum() -
+ pRefFrame->FindPageFrame()->GetPhyPageNum() + 1;
+
+ SwRefPageGetField* pGetField = const_cast<SwRefPageGetField*>(static_cast<const SwRefPageGetField*>(pField->GetFormatField().GetField()));
+ SvxNumType nTmpFormat = SVX_NUM_PAGEDESC == pGetField->GetFormat()
+ ? pPgFrame->GetPageDesc()->GetNumType().GetNumberingType()
+ : static_cast<SvxNumType>(pGetField->GetFormat());
+ const short nPageNum = std::max<short>(0, pSetField->GetOffset() + nDiff);
+ pGetField->SetText(FormatNumber(nPageNum, nTmpFormat), &rLayout);
+}
+
+bool SwRefPageGetField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(GetFormat());
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sText;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwRefPageGetField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nSet = 0;
+ rAny >>= nSet;
+ if(nSet <= SVX_NUM_PAGEDESC )
+ SetFormat(nSet);
+ }
+ break;
+ case FIELD_PROP_PAR1:
+ rAny >>= m_sText;
+ m_sTextRLHidden = m_sText;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+// field type to jump to and edit
+
+SwJumpEditFieldType::SwJumpEditFieldType( SwDoc& rD )
+ : SwFieldType( SwFieldIds::JumpEdit ), m_rDoc( rD ), m_aDep( *this )
+{
+}
+
+std::unique_ptr<SwFieldType> SwJumpEditFieldType::Copy() const
+{
+ return std::make_unique<SwJumpEditFieldType>( m_rDoc );
+}
+
+SwCharFormat* SwJumpEditFieldType::GetCharFormat()
+{
+ SwCharFormat* pFormat = m_rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( RES_POOLCHR_JUMPEDIT );
+ m_aDep.StartListening(pFormat);
+ return pFormat;
+}
+
+SwJumpEditField::SwJumpEditField( SwJumpEditFieldType* pTyp, sal_uInt32 nForm,
+ OUString aText, OUString aHelp )
+ : SwField( pTyp, nForm ), m_sText( std::move(aText) ), m_sHelp( std::move(aHelp) )
+{
+}
+
+OUString SwJumpEditField::ExpandImpl(SwRootFrame const*const) const
+{
+ return "<" + m_sText + ">";
+}
+
+std::unique_ptr<SwField> SwJumpEditField::Copy() const
+{
+ return std::make_unique<SwJumpEditField>( static_cast<SwJumpEditFieldType*>(GetTyp()), GetFormat(),
+ m_sText, m_sHelp );
+}
+
+/// get place holder text
+OUString SwJumpEditField::GetPar1() const
+{
+ return m_sText;
+}
+
+/// set place holder text
+void SwJumpEditField::SetPar1(const OUString& rStr)
+{
+ m_sText = rStr;
+}
+
+/// get hint text
+OUString SwJumpEditField::GetPar2() const
+{
+ return m_sHelp;
+}
+
+/// set hint text
+void SwJumpEditField::SetPar2(const OUString& rStr)
+{
+ m_sHelp = rStr;
+}
+
+bool SwJumpEditField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nRet;
+ switch( GetFormat() )
+ {
+ case JE_FMT_TABLE: nRet = text::PlaceholderType::TABLE; break;
+ case JE_FMT_FRAME: nRet = text::PlaceholderType::TEXTFRAME; break;
+ case JE_FMT_GRAPHIC:nRet = text::PlaceholderType::GRAPHIC; break;
+ case JE_FMT_OLE: nRet = text::PlaceholderType::OBJECT; break;
+ default:
+ nRet = text::PlaceholderType::TEXT; break;
+ }
+ rAny <<= nRet;
+ }
+ break;
+ case FIELD_PROP_PAR1 :
+ rAny <<= m_sHelp;
+ break;
+ case FIELD_PROP_PAR2 :
+ rAny <<= m_sText;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwJumpEditField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ //JP 24.10.2001: int32 because in UnoField.cxx a putvalue is
+ // called with a int32 value! But normally we need
+ // here only a int16
+ sal_Int32 nSet = 0;
+ rAny >>= nSet;
+ switch( nSet )
+ {
+ case text::PlaceholderType::TEXT : SetFormat(JE_FMT_TEXT); break;
+ case text::PlaceholderType::TABLE : SetFormat(JE_FMT_TABLE); break;
+ case text::PlaceholderType::TEXTFRAME: SetFormat(JE_FMT_FRAME); break;
+ case text::PlaceholderType::GRAPHIC : SetFormat(JE_FMT_GRAPHIC); break;
+ case text::PlaceholderType::OBJECT : SetFormat(JE_FMT_OLE); break;
+ }
+ }
+ break;
+ case FIELD_PROP_PAR1 :
+ rAny >>= m_sHelp;
+ break;
+ case FIELD_PROP_PAR2 :
+ rAny >>= m_sText;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+// combined character field type
+
+SwCombinedCharFieldType::SwCombinedCharFieldType()
+ : SwFieldType( SwFieldIds::CombinedChars )
+{
+}
+
+std::unique_ptr<SwFieldType> SwCombinedCharFieldType::Copy() const
+{
+ return std::make_unique<SwCombinedCharFieldType>();
+}
+
+// combined character field
+
+SwCombinedCharField::SwCombinedCharField( SwCombinedCharFieldType* pFTyp,
+ const OUString& rChars )
+ : SwField( pFTyp, 0 ),
+ m_sCharacters( rChars.copy( 0, std::min<sal_Int32>(rChars.getLength(), MAX_COMBINED_CHARACTERS) ))
+{
+}
+
+OUString SwCombinedCharField::ExpandImpl(SwRootFrame const*const) const
+{
+ return m_sCharacters;
+}
+
+std::unique_ptr<SwField> SwCombinedCharField::Copy() const
+{
+ return std::make_unique<SwCombinedCharField>( static_cast<SwCombinedCharFieldType*>(GetTyp()),
+ m_sCharacters );
+}
+
+OUString SwCombinedCharField::GetPar1() const
+{
+ return m_sCharacters;
+}
+
+void SwCombinedCharField::SetPar1(const OUString& rStr)
+{
+ m_sCharacters = rStr.copy(0, std::min<sal_Int32>(rStr.getLength(), MAX_COMBINED_CHARACTERS));
+}
+
+bool SwCombinedCharField::QueryValue( uno::Any& rAny,
+ sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sCharacters;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwCombinedCharField::PutValue( const uno::Any& rAny,
+ sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ SetPar1(sTmp);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
new file mode 100644
index 0000000000..434f676729
--- /dev/null
+++ b/sw/source/core/fields/expfld.cxx
@@ -0,0 +1,1437 @@
+/* -*- 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 <sal/config.h>
+
+#include <limits>
+
+#include <UndoTable.hxx>
+#include <hintids.hxx>
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <com/sun/star/text/SetVariableType.hpp>
+#include <unofield.hxx>
+#include <frmfmt.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <fmtanchr.hxx>
+#include <txtftn.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <layfrm.hxx>
+#include <pagefrm.hxx>
+#include <cntfrm.hxx>
+#include <txtfrm.hxx>
+#include <rootfrm.hxx>
+#include <tabfrm.hxx>
+#include <flyfrm.hxx>
+#include <ftnfrm.hxx>
+#include <rowfrm.hxx>
+#include <expfld.hxx>
+#include <usrfld.hxx>
+#include <ndtxt.hxx>
+#include <calc.hxx>
+#include <pam.hxx>
+#include <docfld.hxx>
+#include <swtable.hxx>
+#include <breakit.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <unofldmid.h>
+#include <numrule.hxx>
+#include <utility>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::text;
+
+static sal_Int16 lcl_SubTypeToAPI(sal_uInt16 nSubType)
+{
+ sal_Int16 nRet = 0;
+ switch(nSubType)
+ {
+ case nsSwGetSetExpType::GSE_EXPR:
+ nRet = SetVariableType::VAR; // 0
+ break;
+ case nsSwGetSetExpType::GSE_SEQ:
+ nRet = SetVariableType::SEQUENCE; // 1
+ break;
+ case nsSwGetSetExpType::GSE_FORMULA:
+ nRet = SetVariableType::FORMULA; // 2
+ break;
+ case nsSwGetSetExpType::GSE_STRING:
+ nRet = SetVariableType::STRING; // 3
+ break;
+ }
+ return nRet;
+}
+
+static sal_Int32 lcl_APIToSubType(const uno::Any& rAny)
+{
+ sal_Int16 nVal = 0;
+ rAny >>= nVal;
+ sal_Int32 nSet = 0;
+ switch(nVal)
+ {
+ case SetVariableType::VAR: nSet = nsSwGetSetExpType::GSE_EXPR; break;
+ case SetVariableType::SEQUENCE: nSet = nsSwGetSetExpType::GSE_SEQ; break;
+ case SetVariableType::FORMULA: nSet = nsSwGetSetExpType::GSE_FORMULA; break;
+ case SetVariableType::STRING: nSet = nsSwGetSetExpType::GSE_STRING; break;
+ default:
+ OSL_FAIL("wrong value");
+ nSet = -1;
+ }
+ return nSet;
+}
+
+OUString ReplacePoint( const OUString& rTmpName, bool bWithCommandType )
+{
+ // replace first and last (if bWithCommandType: last two) dot
+ // since table names may contain dots
+
+ sal_Int32 nIndex = rTmpName.lastIndexOf('.');
+ if (nIndex<0)
+ {
+ return rTmpName;
+ }
+
+ OUString sRes = rTmpName.replaceAt(nIndex, 1, rtl::OUStringChar(DB_DELIM));
+
+ if (bWithCommandType)
+ {
+ nIndex = sRes.lastIndexOf('.', nIndex);
+ if (nIndex<0)
+ {
+ return sRes;
+ }
+ sRes = sRes.replaceAt(nIndex, 1, rtl::OUStringChar(DB_DELIM));
+ }
+
+ nIndex = sRes.indexOf('.');
+ if (nIndex>=0)
+ {
+ sRes = sRes.replaceAt(nIndex, 1, rtl::OUStringChar(DB_DELIM));
+ }
+ return sRes;
+}
+
+static SwTextNode* GetFirstTextNode( const SwDoc& rDoc, SwPosition& rPos,
+ const SwContentFrame *pCFrame, Point &rPt )
+{
+ SwTextNode* pTextNode = nullptr;
+ if ( !pCFrame )
+ {
+ const SwNodes& rNodes = rDoc.GetNodes();
+ rPos.Assign( *rNodes.GetEndOfContent().StartOfSectionNode() );
+ SwContentNode* pCNd;
+ while( nullptr != (pCNd = rNodes.GoNext( &rPos ) ) &&
+ nullptr == ( pTextNode = pCNd->GetTextNode() ) )
+ ;
+ OSL_ENSURE( pTextNode, "Where is the 1. TextNode?" );
+ }
+ else if ( !pCFrame->isFrameAreaDefinitionValid() )
+ {
+ assert(pCFrame->IsTextFrame());
+ rPos = static_cast<SwTextFrame const*>(pCFrame)->MapViewToModelPos(TextFrameIndex(0));
+ }
+ else
+ {
+ pCFrame->GetModelPositionForViewPoint( &rPos, rPt );
+ pTextNode = rPos.GetNode().GetTextNode();
+ }
+ return pTextNode;
+}
+
+const SwTextNode* GetBodyTextNode( const SwDoc& rDoc, SwPosition& rPos,
+ const SwFrame& rFrame )
+{
+ const SwLayoutFrame* pLayout = rFrame.GetUpper();
+ const SwTextNode* pTextNode = nullptr;
+
+ while( pLayout )
+ {
+ if( pLayout->IsFlyFrame() )
+ {
+ // get the FlyFormat
+ const SwFrameFormat* pFlyFormat = static_cast<const SwFlyFrame*>(pLayout)->GetFormat();
+ OSL_ENSURE( pFlyFormat, "Could not find FlyFormat, where is the field?" );
+
+ const SwFormatAnchor &rAnchor = pFlyFormat->GetAnchor();
+
+ if( RndStdIds::FLY_AT_FLY == rAnchor.GetAnchorId() )
+ {
+ // the fly needs to be attached somewhere, so ask it
+ pLayout = static_cast<const SwLayoutFrame*>(static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame());
+ continue;
+ }
+ else if ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
+ (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) ||
+ (RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId()))
+ {
+ OSL_ENSURE( rAnchor.GetContentAnchor(), "no valid position" );
+ rPos = *rAnchor.GetContentAnchor();
+ pTextNode = rPos.GetNode().GetTextNode();
+ if ( RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() )
+ {
+ rPos.AssignStartIndex(*pTextNode);
+ }
+
+ // do not break yet, might be as well in Header/Footer/Footnote/Fly
+ pLayout = static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame()
+ ? static_cast<const SwFlyFrame*>(pLayout)->GetAnchorFrame()->GetUpper() : nullptr;
+ continue;
+ }
+ else
+ {
+ pLayout->FindPageFrame()->GetContentPosition(
+ pLayout->getFrameArea().Pos(), rPos );
+ pTextNode = rPos.GetNode().GetTextNode();
+ }
+ }
+ else if( pLayout->IsFootnoteFrame() )
+ {
+ // get the anchor's node
+ const SwTextFootnote* pFootnote = static_cast<const SwFootnoteFrame*>(pLayout)->GetAttr();
+ pTextNode = &pFootnote->GetTextNode();
+ rPos.Assign( *pTextNode, pFootnote->GetStart() );
+ }
+ else if( pLayout->IsHeaderFrame() || pLayout->IsFooterFrame() )
+ {
+ const SwContentFrame* pContentFrame;
+ const SwPageFrame* pPgFrame = pLayout->FindPageFrame();
+ if( pLayout->IsHeaderFrame() )
+ {
+ const SwTabFrame *pTab;
+ if( nullptr != ( pContentFrame = pPgFrame->FindFirstBodyContent()) &&
+ nullptr != (pTab = pContentFrame->FindTabFrame()) && pTab->IsFollow() &&
+ pTab->GetTable()->GetRowsToRepeat() > 0 &&
+ pTab->IsInHeadline( *pContentFrame ) )
+ {
+ // take the next line
+ const SwLayoutFrame* pRow = pTab->GetFirstNonHeadlineRow();
+ pContentFrame = pRow->ContainsContent();
+ }
+ }
+ else
+ pContentFrame = pPgFrame->FindLastBodyContent();
+
+ if( pContentFrame )
+ {
+ assert(pContentFrame->IsTextFrame());
+ SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pContentFrame));
+ rPos = pFrame->MapViewToModelPos(TextFrameIndex(pFrame->GetText().getLength()));
+ pTextNode = rPos.GetNode().GetTextNode();
+ assert(pTextNode);
+ }
+ else
+ {
+ Point aPt( pLayout->getFrameArea().Pos() );
+ aPt.AdjustY( 1 ); // get out of the header
+ pContentFrame = pPgFrame->GetContentPos( aPt, false, true );
+ pTextNode = GetFirstTextNode( rDoc, rPos, pContentFrame, aPt );
+ }
+ }
+ else
+ {
+ pLayout = pLayout->GetUpper();
+ continue;
+ }
+ break; // found, so finish loop
+ }
+ return pTextNode;
+}
+
+SwGetExpFieldType::SwGetExpFieldType(SwDoc* pDc)
+ : SwValueFieldType( pDc, SwFieldIds::GetExp )
+{
+}
+
+std::unique_ptr<SwFieldType> SwGetExpFieldType::Copy() const
+{
+ return std::make_unique<SwGetExpFieldType>(GetDoc());
+}
+
+void SwGetExpFieldType::SwClientNotify(const SwModify&, const SfxHint&)
+{
+ // do not expand anything (else)
+}
+
+SwGetExpField::SwGetExpField(SwGetExpFieldType* pTyp, const OUString& rFormel,
+ sal_uInt16 nSub, sal_uLong nFormat)
+ : SwFormulaField( pTyp, nFormat, 0.0 )
+ , m_fValueRLHidden(0.0)
+ ,
+ m_bIsInBodyText( true ),
+ m_nSubType(nSub),
+ m_bLateInitialization( false )
+{
+ SetFormula( rFormel );
+}
+
+void SwGetExpField::ChgExpStr(const OUString& rExpand, SwRootFrame const*const pLayout)
+{
+ if (!pLayout || pLayout->IsHideRedlines())
+ {
+ m_sExpandRLHidden = rExpand;
+ }
+ if (!pLayout || !pLayout->IsHideRedlines())
+ {
+ m_sExpand = rExpand;
+ }
+}
+
+OUString SwGetExpField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ if(m_nSubType & nsSwExtendedSubType::SUB_CMD)
+ return GetFormula();
+
+ return (pLayout && pLayout->IsHideRedlines()) ? m_sExpandRLHidden : m_sExpand;
+}
+
+OUString SwGetExpField::GetFieldName() const
+{
+ const SwFieldTypesEnum nType =
+ (nsSwGetSetExpType::GSE_FORMULA & m_nSubType)
+ ? SwFieldTypesEnum::Formel
+ : SwFieldTypesEnum::Get;
+
+ return SwFieldType::GetTypeStr(nType) + " " + GetFormula();
+}
+
+std::unique_ptr<SwField> SwGetExpField::Copy() const
+{
+ std::unique_ptr<SwGetExpField> pTmp(new SwGetExpField(static_cast<SwGetExpFieldType*>(GetTyp()),
+ GetFormula(), m_nSubType, GetFormat()));
+ pTmp->SetLanguage(GetLanguage());
+ pTmp->m_fValueRLHidden = m_fValueRLHidden;
+ pTmp->SwValueField::SetValue(GetValue());
+ pTmp->m_sExpand = m_sExpand;
+ pTmp->m_sExpandRLHidden = m_sExpandRLHidden;
+ pTmp->m_bIsInBodyText = m_bIsInBodyText;
+ pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
+ if( m_bLateInitialization )
+ pTmp->SetLateInitialization();
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+void SwGetExpField::ChangeExpansion( const SwFrame& rFrame, const SwTextField& rField )
+{
+ if( m_bIsInBodyText ) // only fields in Footer, Header, FootNote, Flys
+ return;
+
+ OSL_ENSURE( !rFrame.IsInDocBody(), "Flag incorrect, frame is in DocBody" );
+
+ // determine document (or is there an easier way?)
+ const SwTextNode* pTextNode = &rField.GetTextNode();
+ SwDoc& rDoc = const_cast<SwDoc&>(pTextNode->GetDoc());
+
+ // create index for determination of the TextNode
+ SwPosition aPos( rDoc.GetNodes() );
+ pTextNode = GetBodyTextNode( rDoc, aPos, rFrame );
+
+ // If no layout exists, ChangeExpansion is called for header and
+ // footer lines via layout formatting without existing TextNode.
+ if(!pTextNode)
+ return;
+ // #i82544#
+ if( m_bLateInitialization )
+ {
+ SwFieldType* pSetExpField = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, GetFormula(), false);
+ if( pSetExpField )
+ {
+ m_bLateInitialization = false;
+ if( !(GetSubType() & nsSwGetSetExpType::GSE_STRING) &&
+ static_cast< SwSetExpFieldType* >(pSetExpField)->GetType() == nsSwGetSetExpType::GSE_STRING )
+ SetSubType( nsSwGetSetExpType::GSE_STRING );
+ }
+ }
+
+ SwRootFrame const& rLayout(*rFrame.getRootFrame());
+ OUString & rExpand(rLayout.IsHideRedlines() ? m_sExpandRLHidden : m_sExpand);
+ // here a page number is needed to sort correctly
+ SetGetExpField aEndField(aPos.GetNode(), &rField, aPos.GetContentIndex(), rFrame.GetPhyPageNum());
+ if(GetSubType() & nsSwGetSetExpType::GSE_STRING)
+ {
+ std::unordered_map<OUString, OUString> aHashTable;
+ rDoc.getIDocumentFieldsAccess().FieldsToExpand(aHashTable, aEndField, rLayout);
+ rExpand = LookString( aHashTable, GetFormula() );
+ }
+ else
+ {
+ // fill calculator with values
+ SwCalc aCalc( rDoc );
+ rDoc.getIDocumentFieldsAccess().FieldsToCalc(aCalc, aEndField, &rLayout);
+
+ // calculate value
+ SetValue(aCalc.Calculate(GetFormula()).GetDouble(), &rLayout);
+
+ // analyse based on format
+ rExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
+ GetValue(&rLayout), GetFormat(), GetLanguage());
+ }
+}
+
+OUString SwGetExpField::GetPar2() const
+{
+ return GetFormula();
+}
+
+void SwGetExpField::SetPar2(const OUString& rStr)
+{
+ SetFormula(rStr);
+}
+
+sal_uInt16 SwGetExpField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwGetExpField::SetSubType(sal_uInt16 nType)
+{
+ m_nSubType = nType;
+}
+
+void SwGetExpField::SetLanguage(LanguageType nLng)
+{
+ if (m_nSubType & nsSwExtendedSubType::SUB_CMD)
+ SwField::SetLanguage(nLng);
+ else
+ SwValueField::SetLanguage(nLng);
+}
+
+bool SwGetExpField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_DOUBLE:
+ rAny <<= GetValue();
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(m_nSubType);
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= GetFormula();
+ break;
+ case FIELD_PROP_SUBTYPE:
+ {
+ sal_Int16 nRet = lcl_SubTypeToAPI(GetSubType() & 0xff);
+ rAny <<= nRet;
+ }
+ break;
+ case FIELD_PROP_BOOL2:
+ rAny <<= 0 != (m_nSubType & nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= m_sExpand;
+ break;
+ default:
+ return SwField::QueryValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+bool SwGetExpField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ sal_Int32 nTmp = 0;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_DOUBLE:
+ SwValueField::SetValue(*o3tl::doAccess<double>(rAny));
+ m_fValueRLHidden = *o3tl::doAccess<double>(rAny);
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny >>= nTmp;
+ SetFormat(nTmp);
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny >>= nTmp;
+ m_nSubType = o3tl::narrowing<sal_uInt16>(nTmp);
+ break;
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ SetFormula(sTmp);
+ break;
+ }
+ case FIELD_PROP_SUBTYPE:
+ nTmp = lcl_APIToSubType(rAny);
+ if( nTmp >=0 )
+ SetSubType( o3tl::narrowing<sal_uInt16>((GetSubType() & 0xff00) | nTmp));
+ break;
+ case FIELD_PROP_BOOL2:
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType |= nsSwExtendedSubType::SUB_CMD;
+ else
+ m_nSubType &= (~nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_PAR4:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ ChgExpStr(sTmp, nullptr);
+ break;
+ }
+ default:
+ return SwField::PutValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+SwSetExpFieldType::SwSetExpFieldType( SwDoc* pDc, OUString aName, sal_uInt16 nTyp )
+ : SwValueFieldType( pDc, SwFieldIds::SetExp ),
+ m_sName( std::move(aName) ),
+ m_sDelim( "." ),
+ m_nType(nTyp), m_nLevel( UCHAR_MAX ),
+ m_bDeleted( false )
+{
+ if( ( nsSwGetSetExpType::GSE_SEQ | nsSwGetSetExpType::GSE_STRING ) & m_nType )
+ EnableFormat(false); // do not use Numberformatter
+}
+
+std::unique_ptr<SwFieldType> SwSetExpFieldType::Copy() const
+{
+ std::unique_ptr<SwSetExpFieldType> pNew(new SwSetExpFieldType(GetDoc(), m_sName, m_nType));
+ pNew->m_bDeleted = m_bDeleted;
+ pNew->m_sDelim = m_sDelim;
+ pNew->m_nLevel = m_nLevel;
+
+ return pNew;
+}
+
+OUString SwSetExpFieldType::GetName() const
+{
+ return m_sName;
+}
+
+const OUString& SwSetExpField::GetExpStr(SwRootFrame const*const pLayout) const
+{
+ return (pLayout && pLayout->IsHideRedlines()) ? msExpandRLHidden : msExpand;
+}
+
+void SwSetExpField::ChgExpStr(const OUString& rExpand, SwRootFrame const*const pLayout)
+{
+ if (!pLayout || pLayout->IsHideRedlines())
+ {
+ msExpandRLHidden = rExpand;
+ }
+ if (!pLayout || !pLayout->IsHideRedlines())
+ {
+ msExpand = rExpand;
+ }
+}
+
+void SwSetExpFieldType::SwClientNotify(const SwModify&, const SfxHint&)
+{
+ // do not expand further
+}
+
+void SwSetExpFieldType::SetSeqFormat(sal_uLong nFormat)
+{
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields, false);
+ for(auto pFormatField: vFields)
+ pFormatField->GetField()->ChangeFormat(nFormat);
+}
+
+sal_uLong SwSetExpFieldType::GetSeqFormat() const
+{
+ if( !HasWriterListeners() )
+ return SVX_NUM_ARABIC;
+
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields, false);
+ return vFields.front()->GetField()->GetFormat();
+}
+
+void SwSetExpFieldType::SetSeqRefNo( SwSetExpField& rField )
+{
+ if( !HasWriterListeners() || !(nsSwGetSetExpType::GSE_SEQ & m_nType) )
+ return;
+
+ std::vector<sal_uInt16> aArr;
+
+ // check if number is already used and if a new one needs to be created
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(SwFormatField* pF: vFields)
+ if(pF->GetField() != &rField)
+ InsertSort(aArr, static_cast<SwSetExpField*>(pF->GetField())->GetSeqNumber());
+
+ // check first if number already exists
+ sal_uInt16 nNum = rField.GetSeqNumber();
+ if( USHRT_MAX != nNum )
+ {
+ std::vector<sal_uInt16>::size_type n {0};
+
+ for( n = 0; n < aArr.size(); ++n )
+ if( aArr[ n ] >= nNum )
+ break;
+
+ if( n == aArr.size() || aArr[ n ] > nNum )
+ return; // no -> use it
+ }
+
+ // flagged all numbers, so determine the right number
+ std::vector<sal_uInt16>::size_type n = aArr.size();
+ OSL_ENSURE( n <= std::numeric_limits<sal_uInt16>::max(), "Array is too big for using a sal_uInt16 index" );
+
+ if ( n > 0 && aArr[ n-1 ] != n-1 )
+ {
+ for( n = 0; n < aArr.size(); ++n )
+ if( n != aArr[ n ] )
+ break;
+ }
+
+ rField.SetSeqNumber( n );
+}
+
+size_t SwSetExpFieldType::GetSeqFieldList(SwSeqFieldList& rList,
+ SwRootFrame const*const pLayout)
+{
+ rList.Clear();
+
+ IDocumentRedlineAccess const& rIDRA(GetDoc()->getIDocumentRedlineAccess());
+
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(SwFormatField* pF: vFields)
+ {
+ const SwTextNode* pNd;
+ if( nullptr != ( pNd = pF->GetTextField()->GetpTextNode() )
+ && (!pLayout || !pLayout->IsHideRedlines()
+ || !sw::IsFieldDeletedInModel(rIDRA, *pF->GetTextField())))
+ {
+ SeqFieldLstElem aNew(
+ pNd->GetExpandText(pLayout),
+ static_cast<SwSetExpField*>(pF->GetField())->GetSeqNumber() );
+ rList.InsertSort( std::move(aNew) );
+ }
+ }
+ return rList.Count();
+}
+
+void SwSetExpFieldType::SetChapter(SwSetExpField& rField, const SwNode& rNd,
+ SwRootFrame const*const pLayout)
+{
+ const SwTextNode* pTextNd = rNd.FindOutlineNodeOfLevel(m_nLevel, pLayout);
+ if( !pTextNd )
+ return;
+
+ SwNumRule * pRule = pTextNd->GetNumRule();
+
+ if (!pRule)
+ return;
+
+ // --> OD 2005-11-02 #i51089 - TUNING#
+ if (SwNodeNum const*const pNum = pTextNd->GetNum(pLayout))
+ {
+ // only get the number, without pre-/post-fixstrings
+ OUString const sNumber(pRule->MakeNumString(*pNum, false));
+
+ if( !sNumber.isEmpty() )
+ rField.ChgExpStr(sNumber + m_sDelim + rField.GetExpStr(pLayout), pLayout);
+ }
+ else
+ {
+ OSL_ENSURE(pTextNd->GetNum(nullptr), "<SwSetExpFieldType::SetChapter(..)> - text node with numbering rule, but without number. This is a serious defect");
+ }
+}
+
+void SwSetExpFieldType::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_SUBTYPE:
+ {
+ sal_Int16 nRet = lcl_SubTypeToAPI(GetType());
+ rAny <<= nRet;
+ }
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= GetDelimiter();
+ break;
+ case FIELD_PROP_SHORT1:
+ {
+ sal_Int8 nRet = m_nLevel < MAXLEVEL? m_nLevel : -1;
+ rAny <<= nRet;
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwSetExpFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_SUBTYPE:
+ {
+ sal_Int32 nSet = lcl_APIToSubType(rAny);
+ if(nSet >=0)
+ SetType(o3tl::narrowing<sal_uInt16>(nSet));
+ }
+ break;
+ case FIELD_PROP_PAR2:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ if( !sTmp.isEmpty() )
+ SetDelimiter( sTmp );
+ else
+ SetDelimiter( " " );
+ }
+ break;
+ case FIELD_PROP_SHORT1:
+ {
+ sal_Int8 nLvl = 0;
+ rAny >>= nLvl;
+ if(nLvl < 0 || nLvl >= MAXLEVEL)
+ SetOutlineLvl(UCHAR_MAX);
+ else
+ SetOutlineLvl(nLvl);
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+bool SwSeqFieldList::InsertSort( SeqFieldLstElem aNew )
+{
+ OUStringBuffer aBuf(aNew.sDlgEntry);
+ const sal_Int32 nLen = aBuf.getLength();
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if (aBuf[i]<' ')
+ {
+ aBuf[i]=' ';
+ }
+ }
+ aNew.sDlgEntry = aBuf.makeStringAndClear();
+
+ size_t nPos = 0;
+ bool bRet = SeekEntry( aNew, &nPos );
+ if( !bRet )
+ maData.insert( maData.begin() + nPos, aNew );
+ return bRet;
+}
+
+bool SwSeqFieldList::SeekEntry( const SeqFieldLstElem& rNew, size_t* pP ) const
+{
+ size_t nO = maData.size();
+ size_t nU = 0;
+ if( nO > 0 )
+ {
+ CollatorWrapper & rCaseColl = ::GetAppCaseCollator(),
+ & rColl = ::GetAppCollator();
+ const CharClass& rCC = GetAppCharClass();
+
+ //#59900# Sorting should sort number correctly (e.g. "10" after "9" not after "1")
+ const OUString rTmp2 = rNew.sDlgEntry;
+ sal_Int32 nFndPos2 = 0;
+ const OUString sNum2( rTmp2.getToken( 0, ' ', nFndPos2 ));
+ bool bIsNum2IsNumeric = CharClass::isAsciiNumeric( sNum2 );
+ sal_Int32 nNum2 = bIsNum2IsNumeric ? sNum2.toInt32() : 0;
+
+ nO--;
+ while( nU <= nO )
+ {
+ const size_t nM = nU + ( nO - nU ) / 2;
+
+ //#59900# Sorting should sort number correctly (e.g. "10" after "9" not after "1")
+ const OUString rTmp1 = maData[nM].sDlgEntry;
+ sal_Int32 nFndPos1 = 0;
+ const OUString sNum1( rTmp1.getToken( 0, ' ', nFndPos1 ));
+ sal_Int32 nCmp;
+
+ if( bIsNum2IsNumeric && rCC.isNumeric( sNum1 ) )
+ {
+ sal_Int32 nNum1 = sNum1.toInt32();
+ nCmp = nNum2 - nNum1;
+ if( 0 == nCmp )
+ {
+ OUString aTmp1 = nFndPos1 != -1 ? rTmp1.copy(nFndPos1) : OUString();
+ OUString aTmp2 = nFndPos2 != -1 ? rTmp2.copy(nFndPos2) : OUString();
+ nCmp = rCaseColl.compareString(aTmp2, aTmp1);
+ }
+ }
+ else
+ nCmp = rColl.compareString( rTmp2, rTmp1 );
+
+ if( 0 == nCmp )
+ {
+ if( pP ) *pP = nM;
+ return true;
+ }
+ else if( 0 < nCmp )
+ nU = nM + 1;
+ else if( nM == 0 )
+ break;
+ else
+ nO = nM - 1;
+ }
+ }
+ if( pP ) *pP = nU;
+ return false;
+}
+
+SwSetExpField::SwSetExpField(SwSetExpFieldType* pTyp, const OUString& rFormel,
+ sal_uLong nFormat)
+ : SwFormulaField( pTyp, nFormat, 0.0 )
+ , m_fValueRLHidden(0.0)
+ , mnSeqNo( USHRT_MAX )
+ , mnSubType(0)
+ , mpFormatField(nullptr)
+{
+ SetFormula(rFormel);
+ // ignore SubType
+ mbInput = false;
+ if( IsSequenceField() )
+ {
+ SwValueField::SetValue(1.0);
+ m_fValueRLHidden = 1.0;
+ if( rFormel.isEmpty() )
+ {
+ SetFormula(pTyp->GetName() + "+1");
+ }
+ }
+}
+
+void SwSetExpField::SetFormatField(SwFormatField & rFormatField)
+{
+ mpFormatField = &rFormatField;
+}
+
+OUString SwSetExpField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ if (mnSubType & nsSwExtendedSubType::SUB_CMD)
+ { // we need the CommandString
+ return GetTyp()->GetName() + " = " + GetFormula();
+ }
+ if(!(mnSubType & nsSwExtendedSubType::SUB_INVISIBLE))
+ { // value is visible
+ return (pLayout && pLayout->IsHideRedlines()) ? msExpandRLHidden : msExpand;
+ }
+ return OUString();
+}
+
+/// @return the field name
+OUString SwSetExpField::GetFieldName() const
+{
+ SwFieldTypesEnum const nStrType( (IsSequenceField())
+ ? SwFieldTypesEnum::Sequence
+ : mbInput
+ ? SwFieldTypesEnum::SetInput
+ : SwFieldTypesEnum::Set );
+
+ OUString aStr(
+ SwFieldType::GetTypeStr( nStrType )
+ + " "
+ + GetTyp()->GetName() );
+
+ // Sequence: without formula
+ if (SwFieldTypesEnum::Sequence != nStrType)
+ {
+ aStr += " = " + GetFormula();
+ }
+ return aStr;
+}
+
+std::unique_ptr<SwField> SwSetExpField::Copy() const
+{
+ std::unique_ptr<SwSetExpField> pTmp(new SwSetExpField(static_cast<SwSetExpFieldType*>(GetTyp()),
+ GetFormula(), GetFormat()));
+ pTmp->SwValueField::SetValue(GetValue());
+ pTmp->m_fValueRLHidden = m_fValueRLHidden;
+ pTmp->msExpand = msExpand;
+ pTmp->msExpandRLHidden = msExpandRLHidden;
+ pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
+ pTmp->SetLanguage(GetLanguage());
+ pTmp->maPText = maPText;
+ pTmp->mbInput = mbInput;
+ pTmp->mnSeqNo = mnSeqNo;
+ pTmp->SetSubType(GetSubType());
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+void SwSetExpField::SetSubType(sal_uInt16 nSub)
+{
+ static_cast<SwSetExpFieldType*>(GetTyp())->SetType(nSub & 0xff);
+ mnSubType = nSub & 0xff00;
+
+ OSL_ENSURE( (nSub & 0xff) != 3, "SubType is illegal!" );
+}
+
+sal_uInt16 SwSetExpField::GetSubType() const
+{
+ return static_cast<SwSetExpFieldType*>(GetTyp())->GetType() | mnSubType;
+}
+
+void SwSetExpField::SetValue( const double& rAny )
+{
+ SwValueField::SetValue(rAny);
+
+ if( IsSequenceField() )
+ msExpand = FormatNumber( GetValue(), static_cast<SvxNumType>(GetFormat()), GetLanguage() );
+ else
+ msExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue( rAny,
+ GetFormat(), GetLanguage());
+}
+
+void SwSetExpField::SetValue(const double& rValue, SwRootFrame const*const pLayout)
+{
+ if (!pLayout || !pLayout->IsHideRedlines())
+ {
+ SetValue(rValue);
+ }
+ if (pLayout && !pLayout->IsHideRedlines())
+ return;
+
+ m_fValueRLHidden = rValue;
+ if (IsSequenceField())
+ {
+ msExpandRLHidden = FormatNumber(rValue, static_cast<SvxNumType>(GetFormat()), GetLanguage());
+ }
+ else
+ {
+ msExpandRLHidden = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
+ rValue, GetFormat(), GetLanguage());
+ }
+}
+
+double SwSetExpField::GetValue(SwRootFrame const* pLayout) const
+{
+ return (pLayout && pLayout->IsHideRedlines()) ? m_fValueRLHidden : GetValue();
+}
+
+void SwGetExpField::SetValue( const double& rAny )
+{
+ SwValueField::SetValue(rAny);
+ m_sExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue( rAny, GetFormat(),
+ GetLanguage());
+}
+
+void SwGetExpField::SetValue(const double& rValue, SwRootFrame const*const pLayout)
+{
+ if (!pLayout || !pLayout->IsHideRedlines())
+ {
+ SetValue(rValue);
+ }
+ if (!pLayout || pLayout->IsHideRedlines())
+ {
+ m_fValueRLHidden = rValue;
+ m_sExpandRLHidden = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(
+ rValue, GetFormat(), GetLanguage());
+ }
+}
+
+double SwGetExpField::GetValue(SwRootFrame const* pLayout) const
+{
+ return (pLayout && pLayout->IsHideRedlines()) ? m_fValueRLHidden : GetValue();
+}
+
+/** Find the index of the reference text following the current field
+ *
+ * @param rFormat
+ * @param rDoc
+ * @param nHint search starting position after the current field (or 0 if default)
+ * @return
+ */
+sal_Int32 SwGetExpField::GetReferenceTextPos( const SwFormatField& rFormat, SwDoc& rDoc, sal_Int32 nHint)
+{
+
+ const SwTextField* pTextField = rFormat.GetTextField();
+ const SwTextNode& rTextNode = pTextField->GetTextNode();
+
+ sal_Int32 nRet = nHint ? nHint : pTextField->GetStart() + 1;
+ OUString sNodeText = rTextNode.GetText();
+
+ if(nRet<sNodeText.getLength())
+ {
+ sNodeText = sNodeText.copy(nRet);
+
+ // now check if sNodeText starts with a non-alphanumeric character plus blanks
+ sal_uInt16 nSrcpt = g_pBreakIt->GetRealScriptOfText( sNodeText, 0 );
+
+ static const WhichRangesContainer nIds(svl::Items<
+ RES_CHRATR_FONT, RES_CHRATR_FONT,
+ RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
+ RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONT,
+ RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
+ RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONT,
+ RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE
+ >);
+ SwAttrSet aSet(rDoc.GetAttrPool(), nIds);
+ rTextNode.GetParaAttr(aSet, nRet, nRet+1);
+
+ TypedWhichId<SvxFontItem> nFontWhich = GetWhichOfScript( RES_CHRATR_FONT, nSrcpt );
+ if( RTL_TEXTENCODING_SYMBOL != aSet.Get( nFontWhich ).GetCharSet() )
+ {
+ TypedWhichId<SvxLanguageItem> nLangWhich = GetWhichOfScript( RES_CHRATR_LANGUAGE, nSrcpt ) ;
+ LanguageType eLang = aSet.Get(nLangWhich).GetLanguage();
+ CharClass aCC(( LanguageTag(eLang) ));
+ sal_Unicode c0 = sNodeText[0];
+ bool bIsAlphaNum = aCC.isAlphaNumeric( sNodeText, 0 );
+ if( !bIsAlphaNum ||
+ (c0 == ' ' || c0 == '\t'))
+ {
+ // ignoring blanks
+ nRet++;
+ const sal_Int32 nLen = sNodeText.getLength();
+ for (sal_Int32 i = 1;
+ i<nLen && (sNodeText[i]==' ' || sNodeText[i]=='\t');
+ ++i
+ )
+ ++nRet;
+ }
+ }
+ }
+ return nRet;
+}
+
+OUString SwSetExpField::GetPar1() const
+{
+ return static_cast<const SwSetExpFieldType*>(GetTyp())->GetName();
+}
+
+OUString SwSetExpField::GetPar2() const
+{
+ sal_uInt16 nType = static_cast<SwSetExpFieldType*>(GetTyp())->GetType();
+
+ if (nType & nsSwGetSetExpType::GSE_STRING)
+ return GetFormula();
+ return GetExpandedFormula();
+}
+
+void SwSetExpField::SetPar2(const OUString& rStr)
+{
+ sal_uInt16 nType = static_cast<SwSetExpFieldType*>(GetTyp())->GetType();
+
+ if( !(nType & nsSwGetSetExpType::GSE_SEQ) || !rStr.isEmpty() )
+ {
+ if (nType & nsSwGetSetExpType::GSE_STRING)
+ SetFormula(rStr);
+ else
+ SetExpandedFormula(rStr);
+ }
+}
+
+bool SwSetExpField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ sal_Int32 nTmp32 = 0;
+ sal_Int16 nTmp16 = 0;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL2:
+ if(*o3tl::doAccess<bool>(rAny))
+ mnSubType &= ~nsSwExtendedSubType::SUB_INVISIBLE;
+ else
+ mnSubType |= nsSwExtendedSubType::SUB_INVISIBLE;
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny >>= nTmp32;
+ SetFormat(nTmp32);
+ break;
+ case FIELD_PROP_USHORT2:
+ {
+ rAny >>= nTmp16;
+ if(nTmp16 <= css::style::NumberingType::NUMBER_NONE )
+ SetFormat(nTmp16);
+ else {
+ //exception(wrong_value)
+ ;
+ }
+ }
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny >>= nTmp16;
+ mnSeqNo = nTmp16;
+ break;
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ SetPar1( SwStyleNameMapper::GetUIName( sTmp, SwGetPoolIdFromName::TxtColl ) );
+ }
+ break;
+ case FIELD_PROP_PAR2:
+ {
+ OUString uTmp;
+ rAny >>= uTmp;
+ //I18N - if the formula contains only "TypeName+1"
+ //and it's one of the initially created sequence fields
+ //then the localized names has to be replaced by a programmatic name
+ OUString sMyFormula = SwXFieldMaster::LocalizeFormula(*this, uTmp, false);
+ SetFormula( sMyFormula );
+ }
+ break;
+ case FIELD_PROP_DOUBLE:
+ {
+ double fVal = 0.0;
+ rAny >>= fVal;
+ SetValue(fVal);
+ m_fValueRLHidden = fVal;
+ }
+ break;
+ case FIELD_PROP_SUBTYPE:
+ nTmp32 = lcl_APIToSubType(rAny);
+ if(nTmp32 >= 0)
+ SetSubType(o3tl::narrowing<sal_uInt16>((GetSubType() & 0xff00) | nTmp32));
+ break;
+ case FIELD_PROP_PAR3:
+ rAny >>= maPText;
+ break;
+ case FIELD_PROP_BOOL3:
+ if(*o3tl::doAccess<bool>(rAny))
+ mnSubType |= nsSwExtendedSubType::SUB_CMD;
+ else
+ mnSubType &= (~nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_BOOL1:
+ {
+ bool newInput(*o3tl::doAccess<bool>(rAny));
+ if (newInput != GetInputFlag())
+ {
+ if (static_cast<SwSetExpFieldType*>(GetTyp())->GetType()
+ & nsSwGetSetExpType::GSE_STRING)
+ {
+ SwXTextField::TransmuteLeadToInputField(*this);
+ }
+ else
+ {
+ SetInputFlag(newInput);
+ }
+ }
+ }
+ break;
+ case FIELD_PROP_PAR4:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ ChgExpStr(sTmp, nullptr);
+ }
+ break;
+ default:
+ return SwField::PutValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+bool SwSetExpField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL2:
+ rAny <<= 0 == (mnSubType & nsSwExtendedSubType::SUB_INVISIBLE);
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ case FIELD_PROP_USHORT2:
+ rAny <<= static_cast<sal_Int16>(GetFormat());
+ break;
+ case FIELD_PROP_USHORT1:
+ rAny <<= static_cast<sal_Int16>(mnSeqNo);
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= SwStyleNameMapper::GetProgName(GetPar1(), SwGetPoolIdFromName::TxtColl );
+ break;
+ case FIELD_PROP_PAR2:
+ {
+ //I18N - if the formula contains only "TypeName+1"
+ //and it's one of the initially created sequence fields
+ //then the localized names has to be replaced by a programmatic name
+ OUString sMyFormula = SwXFieldMaster::LocalizeFormula(*this, GetFormula(), true);
+ rAny <<= sMyFormula;
+ }
+ break;
+ case FIELD_PROP_DOUBLE:
+ rAny <<= GetValue();
+ break;
+ case FIELD_PROP_SUBTYPE:
+ {
+ sal_Int16 nRet = lcl_SubTypeToAPI(GetSubType() & 0xff);
+ rAny <<= nRet;
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= maPText;
+ break;
+ case FIELD_PROP_BOOL3:
+ rAny <<= 0 != (mnSubType & nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= GetInputFlag();
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= GetExpStr(nullptr);
+ break;
+ default:
+ return SwField::QueryValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+SwInputFieldType::SwInputFieldType( SwDoc* pD )
+ : SwFieldType( SwFieldIds::Input )
+ , mpDoc( pD )
+{
+}
+
+std::unique_ptr<SwFieldType> SwInputFieldType::Copy() const
+{
+ return std::make_unique<SwInputFieldType>( mpDoc );
+}
+
+SwInputField::SwInputField( SwInputFieldType* pFieldType,
+ OUString aContent,
+ OUString aPrompt,
+ sal_uInt16 nSub,
+ sal_uLong nFormat,
+ bool bIsFormField )
+ : SwField( pFieldType, nFormat, LANGUAGE_SYSTEM, false )
+ , maContent(std::move(aContent))
+ , maPText(std::move(aPrompt))
+ , mnSubType(nSub)
+ , mbIsFormField( bIsFormField )
+ , mpFormatField( nullptr )
+{
+}
+
+SwInputField::~SwInputField()
+{
+}
+
+void SwInputField::SetFormatField( SwFormatField& rFormatField )
+{
+ mpFormatField = &rFormatField;
+}
+
+
+void SwInputField::applyFieldContent( const OUString& rNewFieldContent )
+{
+ if ( (mnSubType & 0x00ff) == INP_TXT )
+ {
+ maContent = rNewFieldContent;
+ }
+ else if( (mnSubType & 0x00ff) == INP_USR )
+ {
+ SwUserFieldType* pUserTyp = static_cast<SwUserFieldType*>(
+ static_cast<SwInputFieldType*>(GetTyp())->GetDoc()->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::User, getContent(), false ) );
+ if( pUserTyp )
+ {
+ pUserTyp->SetContent( rNewFieldContent );
+ if (!pUserTyp->IsModifyLocked())
+ {
+ // trigger update of the corresponding User Fields and other
+ // related Input Fields
+ bool bUnlock(false);
+ if (GetFormatField() != nullptr)
+ {
+ SwTextInputField *const pTextInputField =
+ dynamic_cast<SwTextInputField*>(GetFormatField()->GetTextField());
+ if (pTextInputField != nullptr)
+ {
+ bUnlock = pTextInputField->LockNotifyContentChange();
+ }
+ }
+ pUserTyp->UpdateFields();
+ if (bUnlock)
+ {
+ SwTextInputField *const pTextInputField =
+ dynamic_cast<SwTextInputField*>(GetFormatField()->GetTextField());
+ if (pTextInputField != nullptr)
+ {
+ pTextInputField->UnlockNotifyContentChange();
+ }
+ }
+ }
+ }
+ }
+}
+
+OUString SwInputField::GetFieldName() const
+{
+ OUString aStr(SwField::GetFieldName());
+ if ((mnSubType & 0x00ff) == INP_USR)
+ {
+ aStr += GetTyp()->GetName() + " " + getContent();
+ }
+ return aStr;
+}
+
+std::unique_ptr<SwField> SwInputField::Copy() const
+{
+ std::unique_ptr<SwInputField> pField(
+ new SwInputField(
+ static_cast<SwInputFieldType*>(GetTyp()),
+ getContent(),
+ maPText,
+ GetSubType(),
+ GetFormat(),
+ mbIsFormField ));
+
+ pField->SetHelp( maHelp );
+ pField->SetToolTip( maToolTip );
+ pField->maGrabBag = maGrabBag;
+
+ pField->SetAutomaticLanguage(IsAutomaticLanguage());
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+OUString SwInputField::ExpandImpl(SwRootFrame const*const) const
+{
+ if((mnSubType & 0x00ff) == INP_TXT)
+ {
+ return getContent();
+ }
+
+ if( (mnSubType & 0x00ff) == INP_USR )
+ {
+ SwUserFieldType* pUserTyp = static_cast<SwUserFieldType*>(
+ static_cast<SwInputFieldType*>(GetTyp())->GetDoc()->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::User, getContent(), false ) );
+ if( pUserTyp )
+ return pUserTyp->GetContent();
+ }
+
+ return OUString();
+}
+
+bool SwInputField::isFormField() const
+{
+ return mbIsFormField
+ || !maHelp.isEmpty()
+ || !maToolTip.isEmpty();
+}
+
+bool SwInputField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= getContent();
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= maPText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= maHelp;
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= maToolTip;
+ break;
+ case FIELD_PROP_GRABBAG:
+ rAny <<= maGrabBag;
+ break;
+ case FIELD_PROP_TITLE:
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwInputField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= maContent;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= maPText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny >>= maHelp;
+ break;
+ case FIELD_PROP_PAR4:
+ rAny >>= maToolTip;
+ break;
+ case FIELD_PROP_GRABBAG:
+ rAny >>= maGrabBag;
+ break;
+ case FIELD_PROP_TITLE:
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/// set condition
+void SwInputField::SetPar1(const OUString& rStr)
+{
+ maContent = rStr;
+}
+
+OUString SwInputField::GetPar1() const
+{
+ return getContent();
+}
+
+void SwInputField::SetPar2(const OUString& rStr)
+{
+ maPText = rStr;
+}
+
+OUString SwInputField::GetPar2() const
+{
+ return maPText;
+}
+
+void SwInputField::SetHelp(const OUString & rStr)
+{
+ maHelp = rStr;
+}
+
+const OUString& SwInputField::GetHelp() const
+{
+ return maHelp;
+}
+
+void SwInputField::SetToolTip(const OUString & rStr)
+{
+ maToolTip = rStr;
+}
+
+const OUString& SwInputField::GetToolTip() const
+{
+ return maToolTip;
+}
+
+sal_uInt16 SwInputField::GetSubType() const
+{
+ return mnSubType;
+}
+
+void SwInputField::SetSubType(sal_uInt16 nSub)
+{
+ mnSubType = nSub;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/fldbas.cxx b/sw/source/core/fields/fldbas.cxx
new file mode 100644
index 0000000000..b3fab811f1
--- /dev/null
+++ b/sw/source/core/fields/fldbas.cxx
@@ -0,0 +1,933 @@
+/* -*- 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 <fldbas.hxx>
+
+#include <float.h>
+
+#include <libxml/xmlwriter.h>
+
+#include <rtl/math.hxx>
+#include <comphelper/string.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <o3tl/enumarray.hxx>
+#include <osl/diagnose.h>
+#include <unofldmid.h>
+#include <doc.hxx>
+#include <fmtfld.hxx>
+#include <docufld.hxx>
+#include <expfld.hxx>
+#include <shellres.hxx>
+#include <calc.hxx>
+#include <strings.hrc>
+#include <docary.hxx>
+#include <authfld.hxx>
+#include <calbck.hxx>
+#include <viewsh.hxx>
+#include <hints.hxx>
+#include <unofield.hxx>
+
+using namespace ::com::sun::star;
+using namespace nsSwDocInfoSubType;
+
+static LanguageType lcl_GetLanguageOfFormat( LanguageType nLng, sal_uLong nFormat,
+ const SvNumberFormatter& rFormatter )
+{
+ if( nLng == LANGUAGE_NONE ) // Bug #60010
+ nLng = LANGUAGE_SYSTEM;
+ else if( nLng == ::GetAppLanguage() )
+ switch( rFormatter.GetIndexTableOffset( nFormat ))
+ {
+ case NF_NUMBER_SYSTEM:
+ case NF_DATE_SYSTEM_SHORT:
+ case NF_DATE_SYSTEM_LONG:
+ case NF_DATETIME_SYSTEM_SHORT_HHMM:
+ nLng = LANGUAGE_SYSTEM;
+ break;
+ default: break;
+ }
+ return nLng;
+}
+
+// Globals
+
+/// field names
+std::vector<OUString>* SwFieldType::s_pFieldNames = nullptr;
+
+namespace
+{
+
+ const o3tl::enumarray<SwFieldIds,SwFieldTypesEnum> aTypeTab {
+ /* SwFieldIds::Database */ SwFieldTypesEnum::Database,
+ /* SwFieldIds::User */ SwFieldTypesEnum::User,
+ /* SwFieldIds::Filename */ SwFieldTypesEnum::Filename,
+ /* SwFieldIds::DatabaseName */ SwFieldTypesEnum::DatabaseName,
+ /* SwFieldIds::Date */ SwFieldTypesEnum::Date,
+ /* SwFieldIds::Time */ SwFieldTypesEnum::Time,
+ /* SwFieldIds::PageNumber */ SwFieldTypesEnum::PageNumber, // dynamic
+ /* SwFieldIds::Author */ SwFieldTypesEnum::Author,
+ /* SwFieldIds::Chapter */ SwFieldTypesEnum::Chapter,
+ /* SwFieldIds::DocStat */ SwFieldTypesEnum::DocumentStatistics,
+ /* SwFieldIds::GetExp */ SwFieldTypesEnum::Get, // dynamic
+ /* SwFieldIds::SetExp */ SwFieldTypesEnum::Set, // dynamic
+ /* SwFieldIds::GetRef */ SwFieldTypesEnum::GetRef,
+ /* SwFieldIds::HiddenText */ SwFieldTypesEnum::HiddenText,
+ /* SwFieldIds::Postit */ SwFieldTypesEnum::Postit,
+ /* SwFieldIds::FixDate */ SwFieldTypesEnum::FixedDate,
+ /* SwFieldIds::FixTime */ SwFieldTypesEnum::FixedTime,
+ /* SwFieldIds::Reg */ SwFieldTypesEnum::Begin, // old (no change since 2000)
+ /* SwFieldIds::VarReg */ SwFieldTypesEnum::Begin, // old (no change since 2000)
+ /* SwFieldIds::SetRef */ SwFieldTypesEnum::SetRef,
+ /* SwFieldIds::Input */ SwFieldTypesEnum::Input,
+ /* SwFieldIds::Macro */ SwFieldTypesEnum::Macro,
+ /* SwFieldIds::Dde */ SwFieldTypesEnum::DDE,
+ /* SwFieldIds::Table */ SwFieldTypesEnum::Formel,
+ /* SwFieldIds::HiddenPara */ SwFieldTypesEnum::HiddenParagraph,
+ /* SwFieldIds::DocInfo */ SwFieldTypesEnum::DocumentInfo,
+ /* SwFieldIds::TemplateName */ SwFieldTypesEnum::TemplateName,
+ /* SwFieldIds::DbNextSet */ SwFieldTypesEnum::DatabaseNextSet,
+ /* SwFieldIds::DbNumSet */ SwFieldTypesEnum::DatabaseNumberSet,
+ /* SwFieldIds::DbSetNumber */ SwFieldTypesEnum::DatabaseSetNumber,
+ /* SwFieldIds::ExtUser */ SwFieldTypesEnum::ExtendedUser,
+ /* SwFieldIds::RefPageSet */ SwFieldTypesEnum::SetRefPage,
+ /* SwFieldIds::RefPageGet */ SwFieldTypesEnum::GetRefPage,
+ /* SwFieldIds::Internet */ SwFieldTypesEnum::Internet,
+ /* SwFieldIds::JumpEdit */ SwFieldTypesEnum::JumpEdit,
+ /* SwFieldIds::Script */ SwFieldTypesEnum::Script,
+ /* SwFieldIds::DateTime */ SwFieldTypesEnum::Begin, // dynamic
+ /* SwFieldIds::TableOfAuthorities*/ SwFieldTypesEnum::Authority,
+ /* SwFieldIds::CombinedChars */ SwFieldTypesEnum::CombinedChars,
+ /* SwFieldIds::Dropdown */ SwFieldTypesEnum::Dropdown,
+ /* SwFieldIds::ParagraphSignature */ SwFieldTypesEnum::ParagraphSignature
+ };
+
+}
+
+const OUString & SwFieldType::GetTypeStr(SwFieldTypesEnum nTypeId)
+{
+ if (!s_pFieldNames)
+ GetFieldName_();
+
+ return (*SwFieldType::s_pFieldNames)[static_cast<int>(nTypeId)];
+}
+
+// each field references a field type that is unique for each document
+SwFieldType::SwFieldType( SwFieldIds nWhichId )
+ : sw::BroadcastingModify()
+ , m_nWhich(nWhichId)
+{
+}
+
+OUString SwFieldType::GetName() const
+{
+ return OUString();
+}
+
+void SwFieldType::QueryValue( uno::Any&, sal_uInt16 ) const
+{
+}
+void SwFieldType::PutValue( const uno::Any& , sal_uInt16 )
+{
+}
+
+void SwFieldType::PrintHiddenPara()
+{
+ const SwMsgPoolItem aHint(RES_HIDDENPARA_PRINT);
+ SwClientNotify(*this, sw::LegacyModifyHint(&aHint, nullptr));
+}
+
+void SwFieldType::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ if(!vFields.size())
+ return;
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFieldType"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
+ for(const auto pFormatField: vFields)
+ pFormatField->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SwFormatField* SwFieldType::FindFormatForField(const SwField* pField) const {
+ SwFormatField* pFormat = nullptr;
+ CallSwClientNotify(sw::FindFormatForFieldHint(pField, pFormat));
+ return pFormat;
+}
+
+SwFormatField* SwFieldType::FindFormatForPostItId(sal_uInt32 nPostItId) const {
+ SwFormatField* pFormat = nullptr;
+ CallSwClientNotify(sw::FindFormatForPostItIdHint(nPostItId, pFormat));
+ return pFormat;
+}
+
+void SwFieldType::CollectPostIts(std::vector<SwFormatField*>& rvFormatFields, IDocumentRedlineAccess const& rIDRA, const bool bHideRedlines)
+{
+ CallSwClientNotify(sw::CollectPostItsHint(rvFormatFields, rIDRA, bHideRedlines));
+}
+
+bool SwFieldType::HasHiddenInformationNotes() const
+{
+ bool bHasHiddenInformationNotes = false;
+ CallSwClientNotify(sw::HasHiddenInformationNotesHint(bHasHiddenInformationNotes));
+ return bHasHiddenInformationNotes;
+}
+
+void SwFieldType::GatherNodeIndex(std::vector<SwNodeOffset>& rvNodeIndex)
+{
+ CallSwClientNotify(sw::GatherNodeIndexHint(rvNodeIndex));
+}
+
+void SwFieldType::GatherRefFields(std::vector<SwGetRefField*>& rvRFields, const sal_uInt16 nTyp)
+{
+ CallSwClientNotify(sw::GatherRefFieldsHint(rvRFields, nTyp));
+}
+
+void SwFieldType::GatherFields(std::vector<SwFormatField*>& rvFields, bool bCollectOnlyInDocNodes) const
+{
+ CallSwClientNotify(sw::GatherFieldsHint(rvFields, bCollectOnlyInDocNodes));
+}
+
+void SwFieldType::GatherDdeTables(std::vector<SwDDETable*>& rvTables) const
+{
+ CallSwClientNotify(sw::GatherDdeTablesHint(rvTables));
+}
+
+void SwFieldType::UpdateDocPos(const SwTwips nDocPos)
+{
+ CallSwClientNotify(sw::DocPosUpdate(nDocPos));
+}
+void SwFieldType::UpdateFields()
+{
+ CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
+};
+
+void SwFieldType::SetXObject(rtl::Reference<SwXFieldMaster> const& xFieldMaster)
+{
+ m_wXFieldMaster = xFieldMaster.get();
+}
+
+void SwFieldTypes::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFieldTypes"));
+ sal_uInt16 nCount = size();
+ for (sal_uInt16 nType = 0; nType < nCount; ++nType)
+ (*this)[nType]->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+
+// Base class for all fields.
+// A field (multiple can exist) references a field type (can exists only once)
+SwField::SwField(
+ SwFieldType* pType,
+ sal_uInt32 nFormat,
+ LanguageType nLang,
+ bool bUseFieldValueCache)
+ : m_pType( pType )
+ , m_nFormat( nFormat )
+ , m_nLang( nLang )
+ , m_bUseFieldValueCache( bUseFieldValueCache )
+ , m_bIsAutomaticLanguage( true )
+{
+ assert(m_pType);
+}
+
+SwField::~SwField()
+{
+}
+
+SwFieldTypesEnum SwField::GetTypeId() const
+{
+
+ SwFieldTypesEnum nRet;
+ switch (m_pType->Which())
+ {
+ case SwFieldIds::DateTime:
+ if (GetSubType() & FIXEDFLD)
+ nRet = GetSubType() & DATEFLD ? SwFieldTypesEnum::FixedDate : SwFieldTypesEnum::FixedTime;
+ else
+ nRet = GetSubType() & DATEFLD ? SwFieldTypesEnum::Date : SwFieldTypesEnum::Time;
+ break;
+ case SwFieldIds::GetExp:
+ nRet = nsSwGetSetExpType::GSE_FORMULA & GetSubType() ? SwFieldTypesEnum::Formel : SwFieldTypesEnum::Get;
+ break;
+
+ case SwFieldIds::HiddenText:
+ nRet = static_cast<SwFieldTypesEnum>(GetSubType());
+ break;
+
+ case SwFieldIds::SetExp:
+ if( nsSwGetSetExpType::GSE_SEQ & GetSubType() )
+ nRet = SwFieldTypesEnum::Sequence;
+ else if( static_cast<const SwSetExpField*>(this)->GetInputFlag() )
+ nRet = SwFieldTypesEnum::SetInput;
+ else
+ nRet = SwFieldTypesEnum::Set;
+ break;
+
+ case SwFieldIds::PageNumber:
+ {
+ auto nSubType = GetSubType();
+ if( PG_NEXT == nSubType )
+ nRet = SwFieldTypesEnum::NextPage;
+ else if( PG_PREV == nSubType )
+ nRet = SwFieldTypesEnum::PreviousPage;
+ else
+ nRet = SwFieldTypesEnum::PageNumber;
+ }
+ break;
+
+ default:
+ nRet = aTypeTab[ m_pType->Which() ];
+ }
+ return nRet;
+}
+
+/// get name or content
+OUString SwField::GetFieldName() const
+{
+ SwFieldTypesEnum nTypeId = GetTypeId();
+ if (SwFieldIds::DateTime == GetTyp()->Which())
+ {
+ nTypeId =
+ ((GetSubType() & DATEFLD) != 0) ? SwFieldTypesEnum::Date : SwFieldTypesEnum::Time;
+ }
+ OUString sRet = SwFieldType::GetTypeStr( nTypeId );
+ if (IsFixed())
+ {
+ sRet += " " + SwViewShell::GetShellRes()->aFixedStr;
+ }
+ return sRet;
+}
+
+OUString SwField::GetPar1() const
+{
+ return OUString();
+}
+
+OUString SwField::GetPar2() const
+{
+ return OUString();
+}
+
+OUString SwField::GetFormula() const
+{
+ return GetPar2();
+}
+
+void SwField::SetPar1(const OUString& )
+{}
+
+void SwField::SetPar2(const OUString& )
+{}
+
+sal_uInt16 SwField::GetSubType() const
+{
+ return 0;
+}
+
+void SwField::SetSubType(sal_uInt16 )
+{
+}
+
+bool SwField::QueryValue( uno::Any& rVal, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL4:
+ rVal <<= !m_bIsAutomaticLanguage;
+ break;
+ case FIELD_PROP_TITLE:
+ {
+ rVal <<= m_aTitle;
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwField::PutValue( const uno::Any& rVal, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL4:
+ {
+ bool bFixed = false;
+ if(rVal >>= bFixed)
+ m_bIsAutomaticLanguage = !bFixed;
+ }
+ break;
+ case FIELD_PROP_TITLE:
+ {
+ OUString aTitle;
+ if (rVal >>= aTitle)
+ {
+ m_aTitle = aTitle;
+ }
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/** Set a new type
+ *
+ * This is needed/used for copying between documents.
+ * Needs to be always of the same type.
+ * @param pNewType The new type.
+ * @return The old type.
+ */
+SwFieldType* SwField::ChgTyp( SwFieldType* pNewType )
+{
+ assert(pNewType && pNewType->Which() == m_pType->Which());
+
+ SwFieldType* pOld = m_pType;
+ m_pType = pNewType;
+ return pOld;
+}
+
+/// Does the field have an action on a ClickHandler? (E.g. INetFields,...)
+bool SwField::HasClickHdl() const
+{
+ bool bRet = false;
+ switch (m_pType->Which())
+ {
+ case SwFieldIds::Internet:
+ case SwFieldIds::JumpEdit:
+ case SwFieldIds::GetRef:
+ case SwFieldIds::Macro:
+ case SwFieldIds::Input:
+ case SwFieldIds::Dropdown:
+ case SwFieldIds::TableOfAuthorities:
+ bRet = true;
+ break;
+
+ case SwFieldIds::SetExp:
+ bRet = static_cast<const SwSetExpField*>(this)->GetInputFlag();
+ break;
+
+ default: break;
+ }
+ return bRet;
+}
+
+void SwField::SetLanguage(LanguageType const nLang)
+{
+ m_nLang = nLang;
+}
+
+void SwField::ChangeFormat(sal_uInt32 const nFormat)
+{
+ m_nFormat = nFormat;
+}
+
+bool SwField::IsFixed() const
+{
+ bool bRet = false;
+ switch (m_pType->Which())
+ {
+ case SwFieldIds::FixDate:
+ case SwFieldIds::FixTime:
+ bRet = true;
+ break;
+
+ case SwFieldIds::DateTime:
+ bRet = 0 != (GetSubType() & FIXEDFLD);
+ break;
+
+ case SwFieldIds::ExtUser:
+ case SwFieldIds::Author:
+ bRet = 0 != (GetFormat() & AF_FIXED);
+ break;
+
+ case SwFieldIds::Filename:
+ bRet = 0 != (GetFormat() & FF_FIXED);
+ break;
+
+ case SwFieldIds::DocInfo:
+ bRet = 0 != (GetSubType() & DI_SUB_FIXED);
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+OUString
+SwField::ExpandField(bool const bCached, SwRootFrame const*const pLayout) const
+{
+ if ( m_bUseFieldValueCache )
+ {
+ if (!bCached) // #i85766# do not expand fields in clipboard documents
+ {
+ if (GetTypeId() == SwFieldTypesEnum::Authority)
+ {
+ const SwAuthorityField* pAuthorityField = static_cast<const SwAuthorityField*>(this);
+ m_Cache = pAuthorityField->ConditionalExpandAuthIdentifier(pLayout);
+ }
+ else
+ m_Cache = ExpandImpl(pLayout);
+ }
+ return m_Cache;
+ }
+
+ return ExpandImpl(pLayout);
+}
+
+std::unique_ptr<SwField> SwField::CopyField() const
+{
+ std::unique_ptr<SwField> pNew = Copy();
+ // #i85766# cache expansion of source (for clipboard)
+ // use this->cache, not this->Expand(): only text formatting calls Expand()
+ pNew->m_Cache = m_Cache;
+ pNew->m_bUseFieldValueCache = m_bUseFieldValueCache;
+
+ return pNew;
+}
+
+/// expand numbering
+OUString FormatNumber(sal_uInt32 nNum, SvxNumType nFormat, LanguageType nLang)
+{
+ if(SVX_NUM_PAGEDESC == nFormat)
+ return OUString::number( nNum );
+ SvxNumberType aNumber;
+
+ OSL_ENSURE(nFormat != SVX_NUM_NUMBER_NONE, "wrong number format" );
+
+ aNumber.SetNumberingType(nFormat);
+
+ if (nLang == LANGUAGE_NONE)
+ return aNumber.GetNumStr(nNum);
+ else
+ return aNumber.GetNumStr(nNum, LanguageTag::convertToLocale(nLang));
+}
+
+SwFieldTypesEnum SwFieldTypeFromString(std::u16string_view rString)
+{
+ if (rString == u"Date")
+ return SwFieldTypesEnum::Date;
+ if (rString == u"Time")
+ return SwFieldTypesEnum::Time;
+ if (rString == u"Filename")
+ return SwFieldTypesEnum::Filename;
+ if (rString == u"DatabaseName")
+ return SwFieldTypesEnum::DatabaseName;
+ if (rString == u"Chapter")
+ return SwFieldTypesEnum::Chapter;
+ if (rString == u"PageNumber")
+ return SwFieldTypesEnum::PageNumber;
+ if (rString == u"DocumentStatistics")
+ return SwFieldTypesEnum::DocumentStatistics;
+ if (rString == u"Author")
+ return SwFieldTypesEnum::Author;
+ if (rString == u"Set")
+ return SwFieldTypesEnum::Set;
+ if (rString == u"Get")
+ return SwFieldTypesEnum::Get;
+ if (rString == u"Formel")
+ return SwFieldTypesEnum::Formel;
+ if (rString == u"HiddenText")
+ return SwFieldTypesEnum::HiddenText;
+ if (rString == u"SetRef")
+ return SwFieldTypesEnum::SetRef;
+ return SwFieldTypesEnum::Unknown;
+}
+
+SwValueFieldType::SwValueFieldType(SwDoc *const pDoc, SwFieldIds const nWhichId)
+ : SwFieldType(nWhichId)
+ , m_pDoc(pDoc)
+ , m_bUseFormat(true)
+{
+}
+
+SwValueFieldType::SwValueFieldType( const SwValueFieldType& rTyp )
+ : SwFieldType(rTyp.Which())
+ , m_pDoc(rTyp.GetDoc())
+ , m_bUseFormat(rTyp.UseFormat())
+{
+}
+
+/// return value formatted as string
+OUString SwValueFieldType::ExpandValue( const double& rVal,
+ sal_uInt32 nFormat, LanguageType nLng) const
+{
+ if (rVal >= DBL_MAX) // error string for calculator
+ return SwViewShell::GetShellRes()->aCalc_Error;
+
+ OUString sExpand;
+ SvNumberFormatter* pFormatter = m_pDoc->GetNumberFormatter();
+ const Color* pCol = nullptr;
+
+ // Bug #60010
+ LanguageType nFormatLng = ::lcl_GetLanguageOfFormat( nLng, nFormat, *pFormatter );
+
+ if( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && LANGUAGE_SYSTEM != nFormatLng )
+ {
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nFormat);
+
+ if (pEntry && nLng != pEntry->GetLanguage())
+ {
+ sal_uInt32 nNewFormat = pFormatter->GetFormatForLanguageIfBuiltIn(nFormat,
+ nFormatLng);
+ if (nNewFormat == nFormat)
+ {
+ // probably user-defined format
+ OUString sFormat(pEntry->GetFormatstring());
+ sal_Int32 nDummy;
+ SvNumFormatType nType = SvNumFormatType::DEFINED;
+
+ pFormatter->PutandConvertEntry(sFormat, nDummy, nType, nFormat,
+ pEntry->GetLanguage(), nFormatLng, false);
+ }
+ else
+ nFormat = nNewFormat;
+ }
+ OSL_ENSURE(pEntry, "unknown number format!");
+ }
+
+ if( pFormatter->IsTextFormat( nFormat ) )
+ {
+ pFormatter->GetOutputString(DoubleToString(rVal, nFormatLng), nFormat,
+ sExpand, &pCol);
+ }
+ else
+ {
+ pFormatter->GetOutputString(rVal, nFormat, sExpand, &pCol);
+ }
+ return sExpand;
+}
+
+OUString SwValueFieldType::DoubleToString(const double &rVal,
+ sal_uInt32 nFormat) const
+{
+ SvNumberFormatter* pFormatter = m_pDoc->GetNumberFormatter();
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nFormat);
+
+ if (!pEntry)
+ return OUString();
+
+ return DoubleToString(rVal, pEntry->GetLanguage());
+}
+
+OUString SwValueFieldType::DoubleToString( const double &rVal,
+ LanguageType nLng ) const
+{
+ SvNumberFormatter* pFormatter = m_pDoc->GetNumberFormatter();
+
+ // Bug #60010
+ if( nLng == LANGUAGE_NONE )
+ nLng = LANGUAGE_SYSTEM;
+
+ pFormatter->ChangeIntl( nLng ); // get separator in the correct language
+ return ::rtl::math::doubleToUString( rVal, rtl_math_StringFormat_F, 12,
+ pFormatter->GetNumDecimalSep()[0], true );
+}
+
+OUString SwValueFieldType::GetInputOrDateTime( const OUString& rInput, const double& rVal, sal_uInt32 nFormat ) const
+{
+ if (nFormat && nFormat != SAL_MAX_UINT32 && UseFormat())
+ {
+ SvNumberFormatter* pFormatter = m_pDoc->GetNumberFormatter();
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nFormat);
+ if (pEntry && (pEntry->GetType() & SvNumFormatType::DATETIME))
+ {
+ OUString aEdit;
+ pFormatter->GetInputLineString( rVal, nFormat, aEdit);
+ return aEdit;
+ }
+ }
+ return rInput;
+}
+
+SwValueField::SwValueField( SwValueFieldType* pFieldType, sal_uInt32 nFormat,
+ LanguageType nLng, const double fVal )
+ : SwField(pFieldType, nFormat, nLng)
+ , m_fValue(fVal)
+{
+}
+
+SwValueField::SwValueField( const SwValueField& rField )
+ : SwField(rField)
+ , m_fValue(rField.GetValue())
+{
+}
+
+SwValueField::~SwValueField()
+{
+}
+
+/** Set a new type
+ *
+ * This is needed/used for copying between documents.
+ * Needs to be always of the same type.
+ * @param pNewType The new type.
+ * @return The old type.
+ */
+SwFieldType* SwValueField::ChgTyp( SwFieldType* pNewType )
+{
+ SwDoc* pNewDoc = static_cast<SwValueFieldType *>(pNewType)->GetDoc();
+ SwDoc* pDoc = GetDoc();
+
+ if( pNewDoc && pDoc && pDoc != pNewDoc)
+ {
+ SvNumberFormatter* pFormatter = pNewDoc->GetNumberFormatter();
+
+ if( pFormatter && pFormatter->HasMergeFormatTable() &&
+ static_cast<SwValueFieldType *>(GetTyp())->UseFormat() )
+ SetFormat(pFormatter->GetMergeFormatIndex( GetFormat() ));
+ }
+
+ return SwField::ChgTyp(pNewType);
+}
+
+/// get format in office language
+sal_uInt32 SwValueField::GetSystemFormat(SvNumberFormatter* pFormatter, sal_uInt32 nFormat)
+{
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nFormat);
+ LanguageType nLng = SvtSysLocale().GetLanguageTag().getLanguageType();
+
+ if (pEntry && nLng != pEntry->GetLanguage())
+ {
+ sal_uInt32 nNewFormat = pFormatter->GetFormatForLanguageIfBuiltIn(nFormat,
+ nLng);
+
+ if (nNewFormat == nFormat)
+ {
+ // probably user-defined format
+ SvNumFormatType nType = SvNumFormatType::DEFINED;
+ sal_Int32 nDummy;
+
+ OUString sFormat(pEntry->GetFormatstring());
+
+ sal_uInt32 nTempFormat = nFormat;
+ pFormatter->PutandConvertEntry(sFormat, nDummy, nType,
+ nTempFormat, pEntry->GetLanguage(), nLng, true);
+ nFormat = nTempFormat;
+ }
+ else
+ nFormat = nNewFormat;
+ }
+
+ return nFormat;
+}
+
+void SwValueField::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwValueField"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_fValue"), BAD_CAST(OString::number(m_fValue).getStr()));
+ SwField::dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/// set language of the format
+void SwValueField::SetLanguage( LanguageType nLng )
+{
+ if( IsAutomaticLanguage() &&
+ static_cast<SwValueFieldType *>(GetTyp())->UseFormat() &&
+ GetFormat() != SAL_MAX_UINT32 )
+ {
+ // Bug #60010
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+ LanguageType nFormatLng = ::lcl_GetLanguageOfFormat( nLng, GetFormat(),
+ *pFormatter );
+
+ if( (GetFormat() >= SV_COUNTRY_LANGUAGE_OFFSET ||
+ LANGUAGE_SYSTEM != nFormatLng ) &&
+ !(Which() == SwFieldIds::User && (GetSubType()&nsSwExtendedSubType::SUB_CMD) ) )
+ {
+ const SvNumberformat* pEntry = pFormatter->GetEntry(GetFormat());
+
+ if( pEntry && nFormatLng != pEntry->GetLanguage() )
+ {
+ sal_uInt32 nNewFormat = pFormatter->GetFormatForLanguageIfBuiltIn(
+ GetFormat(), nFormatLng );
+
+ if( nNewFormat == GetFormat() )
+ {
+ // probably user-defined format
+ SvNumFormatType nType = SvNumFormatType::DEFINED;
+ sal_Int32 nDummy;
+ OUString sFormat( pEntry->GetFormatstring() );
+ pFormatter->PutandConvertEntry( sFormat, nDummy, nType,
+ nNewFormat,
+ pEntry->GetLanguage(),
+ nFormatLng, false);
+ }
+ SetFormat( nNewFormat );
+ }
+ OSL_ENSURE(pEntry, "unknown number format!");
+ }
+ }
+
+ SwField::SetLanguage(nLng);
+}
+
+double SwValueField::GetValue() const
+{
+ return m_fValue;
+}
+
+void SwValueField::SetValue( const double& rVal )
+{
+ m_fValue = rVal;
+}
+
+SwFormulaField::SwFormulaField( SwValueFieldType* pFieldType, sal_uInt32 nFormat, const double fVal)
+ : SwValueField(pFieldType, nFormat, LANGUAGE_SYSTEM, fVal)
+{
+}
+
+SwFormulaField::SwFormulaField( const SwFormulaField& rField )
+ : SwValueField(static_cast<SwValueFieldType *>(rField.GetTyp()), rField.GetFormat(),
+ rField.GetLanguage(), rField.GetValue())
+{
+}
+
+OUString SwFormulaField::GetFormula() const
+{
+ return m_sFormula;
+}
+
+void SwFormulaField::SetFormula(const OUString& rStr)
+{
+ m_sFormula = rStr;
+
+ sal_uLong nFormat(GetFormat());
+
+ if( nFormat && SAL_MAX_UINT32 != nFormat )
+ {
+ sal_Int32 nPos = 0;
+ double fTmpValue;
+ // Uses the SwCalc document locale.
+ if( SwCalc::Str2Double( rStr, nPos, fTmpValue, GetDoc() ) )
+ SwValueField::SetValue( fTmpValue );
+ }
+}
+
+void SwFormulaField::SetExpandedFormula( const OUString& rStr )
+{
+ sal_uInt32 nFormat(GetFormat());
+
+ if (nFormat && nFormat != SAL_MAX_UINT32 && static_cast<SwValueFieldType *>(GetTyp())->UseFormat())
+ {
+ double fTmpValue;
+
+ if (GetDoc()->IsNumberFormat(rStr, nFormat, fTmpValue))
+ {
+ SwValueField::SetValue(fTmpValue);
+
+ // Will get reinterpreted by SwCalc when updating fields, so use
+ // the proper locale.
+ m_sFormula = static_cast<SwValueFieldType *>(GetTyp())->DoubleToString( fTmpValue,
+ SwCalc::GetDocAppScriptLang( *GetDoc()));
+ return;
+ }
+ }
+ m_sFormula = rStr;
+}
+
+OUString SwFormulaField::GetExpandedFormula() const
+{
+ sal_uInt32 nFormat(GetFormat());
+
+ if (nFormat && nFormat != SAL_MAX_UINT32 && static_cast<SwValueFieldType *>(GetTyp())->UseFormat())
+ {
+ OUString sFormattedValue;
+ const Color* pCol = nullptr;
+
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+
+ if (pFormatter->IsTextFormat(nFormat))
+ {
+ OUString sTempIn(static_cast<SwValueFieldType *>(GetTyp())->DoubleToString(GetValue(), nFormat));
+ pFormatter->GetOutputString(sTempIn, nFormat, sFormattedValue, &pCol);
+ }
+ else
+ {
+ pFormatter->GetOutputString(GetValue(), nFormat, sFormattedValue, &pCol);
+ }
+ return sFormattedValue;
+ }
+ else
+ return GetFormula();
+}
+
+OUString SwFormulaField::GetInputOrDateTime() const
+{
+ // GetFormula() leads to problems with date formats because only the
+ // number string without formatting is returned (additionally that may or
+ // may not use a localized decimal separator due to the convoluted handling
+ // of "formula"). It must be used for expressions though because otherwise
+ // with GetPar2() only the value calculated by SwCalc would be displayed
+ // (instead of test2 = test + 1).
+ // Force a formatted edit value for date+time formats, assuming they are
+ // not editable calculated expressions if the formula doesn't contain
+ // arithmetic operators or assignment.
+
+ const OUString aFormula( GetFormula());
+
+ if (comphelper::string::indexOfAny( aFormula, u"=+-*/", 0) == -1)
+ return static_cast<SwValueFieldType*>(GetTyp())->GetInputOrDateTime( aFormula, GetValue(), GetFormat());
+
+ return aFormula;
+}
+
+OUString SwField::GetDescription() const
+{
+ return SwResId(STR_FIELD);
+}
+
+bool SwField::IsClickable() const
+{
+ switch (Which())
+ {
+ case SwFieldIds::JumpEdit:
+ case SwFieldIds::Macro:
+ case SwFieldIds::GetRef:
+ case SwFieldIds::Input:
+ case SwFieldIds::SetExp:
+ case SwFieldIds::Dropdown:
+ case SwFieldIds::TableOfAuthorities:
+ return true;
+ default: break;
+ }
+ return false;
+}
+
+void SwField::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwField"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*this).name()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nFormat"), BAD_CAST(OString::number(m_nFormat).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nLang"), BAD_CAST(OString::number(m_nLang.get()).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_aTitle"), BAD_CAST(m_aTitle.toUtf8().getStr()));
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/flddat.cxx b/sw/source/core/fields/flddat.cxx
new file mode 100644
index 0000000000..264b7538f9
--- /dev/null
+++ b/sw/source/core/fields/flddat.cxx
@@ -0,0 +1,236 @@
+/* -*- 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 <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/temporary.hxx>
+#include <tools/datetime.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <com/sun/star/util/DateTime.hpp>
+#include <doc.hxx>
+#include <fldbas.hxx>
+#include <flddat.hxx>
+#include <unofldmid.h>
+
+using namespace ::com::sun::star;
+
+SwDateTimeFieldType::SwDateTimeFieldType(SwDoc* pInitDoc)
+ : SwValueFieldType( pInitDoc, SwFieldIds::DateTime )
+{}
+
+std::unique_ptr<SwFieldType> SwDateTimeFieldType::Copy() const
+{
+ return std::make_unique<SwDateTimeFieldType>(GetDoc());
+}
+
+SwDateTimeField::SwDateTimeField(SwDateTimeFieldType* pInitType, sal_uInt16 nSub, sal_uLong nFormat, LanguageType nLng)
+ : SwValueField(pInitType, nFormat, nLng, 0.0),
+ m_nSubType(nSub),
+ m_nOffset(0)
+{
+ if (!nFormat)
+ {
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+ if (m_nSubType & DATEFLD)
+ ChangeFormat(pFormatter->GetFormatIndex(NF_DATE_SYSTEM_SHORT, GetLanguage()));
+ else
+ ChangeFormat(pFormatter->GetFormatIndex(NF_TIME_HHMMSS, GetLanguage()));
+ }
+ if (IsFixed())
+ {
+ DateTime aDateTime( DateTime::SYSTEM );
+ SetDateTime(aDateTime);
+ }
+}
+
+OUString SwDateTimeField::ExpandImpl(SwRootFrame const*const) const
+{
+ if (getenv("STABLE_FIELDS_HACK"))
+ {
+ const_cast<SwDateTimeField*>(this)->m_nSubType |= FIXEDFLD; //HACK
+ }
+
+ double fVal;
+
+ if (!(IsFixed()))
+ {
+ DateTime aDateTime( DateTime::SYSTEM );
+ fVal = GetDateTime(*GetDoc(), aDateTime);
+ }
+ else
+ fVal = GetValue();
+
+ if (m_nOffset)
+ fVal += m_nOffset * ( 60 / 86400.0 );
+
+ return ExpandValue(fVal, GetFormat(), GetLanguage());
+}
+
+std::unique_ptr<SwField> SwDateTimeField::Copy() const
+{
+ std::unique_ptr<SwDateTimeField> pTmp(
+ new SwDateTimeField(static_cast<SwDateTimeFieldType*>(GetTyp()), m_nSubType,
+ GetFormat(), GetLanguage()) );
+
+ pTmp->SetValue(GetValue());
+ pTmp->SetOffset(m_nOffset);
+ pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
+
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+sal_uInt16 SwDateTimeField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwDateTimeField::SetSubType(sal_uInt16 nType)
+{
+ m_nSubType = nType;
+}
+
+void SwDateTimeField::SetPar2(const OUString& rStr)
+{
+ m_nOffset = rStr.toInt32();
+}
+
+OUString SwDateTimeField::GetPar2() const
+{
+ if (m_nOffset)
+ return OUString::number(m_nOffset);
+ return OUString();
+}
+
+void SwDateTimeField::SetDateTime(const DateTime& rDT)
+{
+ SetValue(GetDateTime(*GetDoc(), rDT));
+}
+
+double SwDateTimeField::GetDateTime(SwDoc& rDoc, const DateTime& rDT)
+{
+ SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
+ const Date& rNullDate = pFormatter->GetNullDate();
+
+ double fResult = DateTime::Sub(rDT, DateTime(rNullDate));
+
+ return fResult;
+}
+
+double SwDateTimeField::GetValue() const
+{
+ if (getenv("STABLE_FIELDS_HACK"))
+ {
+ const_cast<SwDateTimeField*>(this)->m_nSubType |= FIXEDFLD; //HACK
+ }
+
+ if (IsFixed())
+ return SwValueField::GetValue();
+ else
+ return GetDateTime(*GetDoc(), DateTime( DateTime::SYSTEM ));
+}
+
+Date SwDateTimeField::GetDate() const
+{
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+ const Date& rNullDate = pFormatter->GetNullDate();
+
+ tools::Long nVal = static_cast<tools::Long>( GetValue() );
+
+ Date aDate = rNullDate + nVal;
+
+ return aDate;
+}
+
+tools::Time SwDateTimeField::GetTime() const
+{
+ double fFract = modf(GetValue(), &o3tl::temporary(double()));
+ DateTime aDT( DateTime::EMPTY );
+ aDT.AddTime(fFract);
+ return static_cast<tools::Time>(aDT);
+}
+
+bool SwDateTimeField::QueryValue( uno::Any& rVal, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ rVal <<= IsFixed();
+ break;
+ case FIELD_PROP_BOOL2:
+ rVal <<= (m_nSubType & DATEFLD) != 0;
+ break;
+ case FIELD_PROP_FORMAT:
+ rVal <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ case FIELD_PROP_SUBTYPE:
+ rVal <<= static_cast<sal_Int32>(m_nOffset);
+ break;
+ case FIELD_PROP_DATE_TIME:
+ {
+ DateTime aDateTime(GetDate(), GetTime());
+ rVal <<= aDateTime.GetUNODateTime();
+ }
+ break;
+ default:
+ return SwField::QueryValue(rVal, nWhichId);
+ }
+ return true;
+}
+
+bool SwDateTimeField::PutValue( const uno::Any& rVal, sal_uInt16 nWhichId )
+{
+ sal_Int32 nTmp = 0;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ if(*o3tl::doAccess<bool>(rVal))
+ m_nSubType |= FIXEDFLD;
+ else
+ m_nSubType &= ~FIXEDFLD;
+ break;
+ case FIELD_PROP_BOOL2:
+ m_nSubType &= ~(DATEFLD|TIMEFLD);
+ m_nSubType |= *o3tl::doAccess<bool>(rVal) ? DATEFLD : TIMEFLD;
+ break;
+ case FIELD_PROP_FORMAT:
+ rVal >>= nTmp;
+ ChangeFormat(nTmp);
+ break;
+ case FIELD_PROP_SUBTYPE:
+ rVal >>= nTmp;
+ m_nOffset = nTmp;
+ break;
+ case FIELD_PROP_DATE_TIME:
+ {
+ util::DateTime aDateTimeValue;
+ if(!(rVal >>= aDateTimeValue))
+ return false;
+ DateTime aDateTime(aDateTimeValue);
+ SetDateTime(aDateTime);
+ }
+ break;
+ default:
+ return SwField::PutValue(rVal, nWhichId);
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/flddropdown.cxx b/sw/source/core/fields/flddropdown.cxx
new file mode 100644
index 0000000000..57106978e1
--- /dev/null
+++ b/sw/source/core/fields/flddropdown.cxx
@@ -0,0 +1,217 @@
+/* -*- 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 <flddropdown.hxx>
+
+#include <algorithm>
+
+#include <svl/poolitem.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <unofldmid.h>
+
+using namespace com::sun::star;
+
+using std::vector;
+
+SwDropDownFieldType::SwDropDownFieldType()
+ : SwFieldType(SwFieldIds::Dropdown)
+{
+}
+
+SwDropDownFieldType::~SwDropDownFieldType()
+{
+}
+
+std::unique_ptr<SwFieldType> SwDropDownFieldType::Copy() const
+{
+ return std::make_unique<SwDropDownFieldType>();
+}
+
+SwDropDownField::SwDropDownField(SwFieldType * pTyp)
+ : SwField(pTyp, 0, LANGUAGE_SYSTEM)
+{
+}
+
+SwDropDownField::SwDropDownField(const SwDropDownField & rSrc)
+ : SwField(rSrc.GetTyp(), rSrc.GetFormat(), rSrc.GetLanguage()),
+ m_aValues(rSrc.m_aValues), m_aSelectedItem(rSrc.m_aSelectedItem),
+ m_aName(rSrc.m_aName), m_aHelp(rSrc.m_aHelp), m_aToolTip(rSrc.m_aToolTip)
+{
+}
+
+SwDropDownField::~SwDropDownField()
+{
+}
+
+OUString SwDropDownField::ExpandImpl(SwRootFrame const*const) const
+{
+ OUString sSelect = GetSelectedItem();
+ if (sSelect.isEmpty())
+ {
+ vector<OUString>::const_iterator aIt = m_aValues.begin();
+ if ( aIt != m_aValues.end())
+ sSelect = *aIt;
+ }
+ // if still no list value is available a default text of 10 spaces is to be set
+ if (sSelect.isEmpty())
+ sSelect = " ";
+ return sSelect;
+}
+
+std::unique_ptr<SwField> SwDropDownField::Copy() const
+{
+ return std::make_unique<SwDropDownField>(*this);
+}
+
+OUString SwDropDownField::GetPar1() const
+{
+ return GetSelectedItem();
+}
+
+OUString SwDropDownField::GetPar2() const
+{
+ return GetName();
+}
+
+void SwDropDownField::SetPar1(const OUString & rStr)
+{
+ SetSelectedItem(rStr);
+}
+
+void SwDropDownField::SetPar2(const OUString & rName)
+{
+ SetName(rName);
+}
+
+void SwDropDownField::SetItems(vector<OUString> && rItems)
+{
+ m_aValues = std::move(rItems);
+ m_aSelectedItem.clear();
+}
+
+void SwDropDownField::SetItems(const uno::Sequence<OUString> & rItems)
+{
+ m_aValues.clear();
+
+ comphelper::sequenceToContainer(m_aValues, rItems);
+
+ m_aSelectedItem.clear();
+}
+
+uno::Sequence<OUString> SwDropDownField::GetItemSequence() const
+{
+ return comphelper::containerToSequence(m_aValues);
+}
+
+
+void SwDropDownField::SetSelectedItem(const OUString & rItem)
+{
+ vector<OUString>::const_iterator aIt =
+ std::find(m_aValues.begin(), m_aValues.end(), rItem);
+
+ if (aIt != m_aValues.end())
+ m_aSelectedItem = *aIt;
+ else
+ m_aSelectedItem.clear();
+}
+
+void SwDropDownField::SetName(const OUString & rName)
+{
+ m_aName = rName;
+}
+
+void SwDropDownField::SetHelp(const OUString & rHelp)
+{
+ m_aHelp = rHelp;
+}
+
+void SwDropDownField::SetToolTip(const OUString & rToolTip)
+{
+ m_aToolTip = rToolTip;
+}
+
+bool SwDropDownField::QueryValue(::uno::Any &rVal, sal_uInt16 nWhich) const
+{
+ nWhich &= ~CONVERT_TWIPS;
+ switch( nWhich )
+ {
+ case FIELD_PROP_PAR1:
+ rVal <<= m_aSelectedItem;
+ break;
+ case FIELD_PROP_PAR2:
+ rVal <<= m_aName;
+ break;
+ case FIELD_PROP_PAR3:
+ rVal <<= m_aHelp;
+ break;
+ case FIELD_PROP_PAR4:
+ rVal <<= m_aToolTip;
+ break;
+ case FIELD_PROP_STRINGS:
+ rVal <<= GetItemSequence();
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwDropDownField::PutValue(const uno::Any &rVal,
+ sal_uInt16 nWhich)
+{
+ switch( nWhich )
+ {
+ case FIELD_PROP_PAR1:
+ {
+ OUString aTmpStr;
+ rVal >>= aTmpStr;
+
+ SetSelectedItem(aTmpStr);
+ }
+ break;
+
+ case FIELD_PROP_PAR2:
+ rVal >>= m_aName;
+ break;
+
+ case FIELD_PROP_PAR3:
+ rVal >>= m_aHelp;
+ break;
+
+ case FIELD_PROP_PAR4:
+ rVal >>= m_aToolTip;
+ break;
+
+ case FIELD_PROP_STRINGS:
+ {
+ uno::Sequence<OUString> aSeq;
+ rVal >>= aSeq;
+ SetItems(aSeq);
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/fldlst.cxx b/sw/source/core/fields/fldlst.cxx
new file mode 100644
index 0000000000..635d09d0ea
--- /dev/null
+++ b/sw/source/core/fields/fldlst.cxx
@@ -0,0 +1,149 @@
+/* -*- 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 <editsh.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <docary.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <expfld.hxx>
+#include <docfld.hxx>
+#include <ndtxt.hxx>
+
+#include <osl/diagnose.h>
+
+// sort input values
+
+SwInputFieldList::SwInputFieldList( SwEditShell* pShell, bool bBuildTmpLst )
+ : mpSh(pShell)
+{
+ // create sorted list of all input fields
+ mpSrtLst.reset( new SetGetExpFields );
+
+ const SwFieldTypes& rFieldTypes = *mpSh->GetDoc()->getIDocumentFieldsAccess().GetFieldTypes();
+ const size_t nSize = rFieldTypes.size();
+
+ // iterate over all types
+ std::vector<SwFormatField*> vFields;
+ for(size_t i = 0; i < nSize; ++i)
+ {
+ SwFieldType* pFieldType = rFieldTypes[ i ].get();
+ const SwFieldIds nType = pFieldType->Which();
+ if(SwFieldIds::SetExp == nType || SwFieldIds::Input == nType || SwFieldIds::Dropdown == nType)
+ pFieldType->GatherFields(vFields);
+ }
+ for(auto pFormatField: vFields)
+ {
+ auto pSetExpField = dynamic_cast<SwSetExpField*>(pFormatField->GetField());
+ if(pSetExpField && !pSetExpField->GetInputFlag())
+ continue;
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ if(bBuildTmpLst)
+ maTmpLst.insert(pTextField);
+ else
+ {
+ std::unique_ptr<SetGetExpField> pNew(new SetGetExpField(pTextField->GetTextNode(), pTextField));
+ mpSrtLst->insert(std::move(pNew));
+ }
+ }
+}
+
+SwInputFieldList::~SwInputFieldList()
+{
+}
+
+size_t SwInputFieldList::Count() const
+{
+ return mpSrtLst->size();
+}
+
+// get field from list in sorted order
+SwField* SwInputFieldList::GetField(size_t nId)
+{
+ const SwTextField* pTextField = (*mpSrtLst)[ nId ]->GetTextField();
+ OSL_ENSURE( pTextField, "no TextField" );
+ return const_cast<SwField*>(pTextField->GetFormatField().GetField());
+}
+
+/// save cursor
+void SwInputFieldList::PushCursor()
+{
+ mpSh->Push();
+ mpSh->ClearMark();
+}
+
+/// get cursor
+void SwInputFieldList::PopCursor()
+{
+ mpSh->Pop(SwCursorShell::PopMode::DeleteCurrent);
+}
+
+/// go to position of a field
+void SwInputFieldList::GotoFieldPos(size_t nId)
+{
+ mpSh->StartAllAction();
+ (*mpSrtLst)[ nId ]->GetPosOfContent( *mpSh->GetCursor()->GetPoint() );
+ mpSh->EndAllAction();
+}
+
+/** Compare TmpLst with current fields.
+ *
+ * All new ones are added to SortList so that they can be updated.
+ * For text blocks: update only input fields.
+ *
+ * @return true if not empty
+ */
+bool SwInputFieldList::BuildSortLst()
+{
+ const SwFieldTypes& rFieldTypes = *mpSh->GetDoc()->getIDocumentFieldsAccess().GetFieldTypes();
+ const size_t nSize = rFieldTypes.size();
+
+ // iterate over all types
+ std::vector<SwFormatField*> vFields;
+ for(size_t i = 0; i < nSize; ++i)
+ {
+ SwFieldType* pFieldType = rFieldTypes[ i ].get();
+ const SwFieldIds nType = pFieldType->Which();
+ if(SwFieldIds::SetExp == nType || SwFieldIds::Input == nType)
+ pFieldType->GatherFields(vFields);
+ }
+ for(auto pFormatField: vFields)
+ {
+ auto pSetExpField = dynamic_cast<SwSetExpField*>(pFormatField->GetField());
+ if(pSetExpField && !pSetExpField->GetInputFlag())
+ continue;
+ const SwTextField* pTextField = pFormatField->GetTextField();
+ // not in TempList, thus add to SortList
+ auto it = maTmpLst.find(pTextField);
+ if(maTmpLst.end() == it)
+ {
+ std::unique_ptr<SetGetExpField> pNew(new SetGetExpField(pTextField->GetTextNode(), pTextField ));
+ mpSrtLst->insert(std::move(pNew));
+ }
+ else
+ maTmpLst.erase(it);
+ }
+
+ // the pointers are not needed anymore
+ maTmpLst.clear();
+ return !mpSrtLst->empty();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/macrofld.cxx b/sw/source/core/fields/macrofld.cxx
new file mode 100644
index 0000000000..244edae398
--- /dev/null
+++ b/sw/source/core/fields/macrofld.cxx
@@ -0,0 +1,223 @@
+/* -*- 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 <doc.hxx>
+#include <docufld.hxx>
+#include <unofldmid.h>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrl.hpp>
+#include <comphelper/processfactory.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+SwMacroFieldType::SwMacroFieldType(SwDoc& rDocument)
+ : SwFieldType( SwFieldIds::Macro )
+ , m_rDoc(rDocument)
+{
+}
+
+std::unique_ptr<SwFieldType> SwMacroFieldType::Copy() const
+{
+ return std::make_unique<SwMacroFieldType>(m_rDoc);
+}
+
+SwMacroField::SwMacroField(SwMacroFieldType* pInitType,
+ OUString aLibAndName, OUString aText) :
+ SwField(pInitType), m_aMacro(std::move(aLibAndName)), m_aText(std::move(aText)), m_bIsScriptURL(false)
+{
+ m_bIsScriptURL = isScriptURL(m_aMacro);
+}
+
+OUString SwMacroField::ExpandImpl(SwRootFrame const*const) const
+{
+ return m_aText ;
+}
+
+std::unique_ptr<SwField> SwMacroField::Copy() const
+{
+ return std::make_unique<SwMacroField>(static_cast<SwMacroFieldType*>(GetTyp()), m_aMacro, m_aText);
+}
+
+OUString SwMacroField::GetFieldName() const
+{
+ return GetTyp()->GetName() + " " + m_aMacro;
+}
+
+OUString SwMacroField::GetLibName() const
+{
+ // if it is a Scripting Framework macro return an empty string
+ if (m_bIsScriptURL)
+ {
+ return OUString();
+ }
+
+ if (!m_aMacro.isEmpty())
+ {
+ sal_Int32 nPos = m_aMacro.getLength();
+
+ for (sal_Int32 i = 0; i < 3 && nPos > 0; i++)
+ while (m_aMacro[--nPos] != '.' && nPos > 0) ;
+
+ return m_aMacro.copy(0, nPos);
+ }
+
+ OSL_FAIL("No LibName");
+ return OUString();
+}
+
+OUString SwMacroField::GetMacroName() const
+{
+ if (!m_aMacro.isEmpty())
+ {
+ if (m_bIsScriptURL)
+ {
+ return m_aMacro;
+ }
+ else
+ {
+ sal_Int32 nPos = m_aMacro.getLength();
+
+ for (sal_Int32 i = 0; i < 3 && nPos > 0; i++)
+ while (m_aMacro[--nPos] != '.' && nPos > 0) ;
+
+ return m_aMacro.copy( ++nPos );
+ }
+ }
+
+ OSL_FAIL("No MacroName");
+ return OUString();
+}
+
+SvxMacro SwMacroField::GetSvxMacro() const
+{
+ if (m_bIsScriptURL)
+ {
+ return SvxMacro(m_aMacro, OUString(), EXTENDED_STYPE);
+ }
+ else
+ {
+ return SvxMacro(GetMacroName(), GetLibName(), STARBASIC);
+ }
+}
+
+/// LibName and MacroName
+void SwMacroField::SetPar1(const OUString& rStr)
+{
+ m_aMacro = rStr;
+ m_bIsScriptURL = isScriptURL(m_aMacro);
+}
+
+/// Get macro
+OUString SwMacroField::GetPar1() const
+{
+ return m_aMacro;
+}
+
+/// set macro text
+void SwMacroField::SetPar2(const OUString& rStr)
+{
+ m_aText = rStr;
+}
+
+/// get macro text
+OUString SwMacroField::GetPar2() const
+{
+ return m_aText;
+}
+
+bool SwMacroField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= GetMacroName();
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_aText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= GetLibName();
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= m_bIsScriptURL ? GetMacroName() : OUString();
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwMacroField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ OUString sTmp;
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= sTmp;
+ CreateMacroString( m_aMacro, sTmp, GetLibName());
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_aText;
+ break;
+ case FIELD_PROP_PAR3:
+ rAny >>= sTmp;
+ CreateMacroString(m_aMacro, GetMacroName(), sTmp );
+ break;
+ case FIELD_PROP_PAR4:
+ rAny >>= m_aMacro;
+ m_bIsScriptURL = isScriptURL(m_aMacro);
+ break;
+ default:
+ assert(false);
+ }
+
+ return true;
+}
+
+/// create an internally used macro name from the library and macro name parts
+void SwMacroField::CreateMacroString(
+ OUString& rMacro,
+ std::u16string_view rMacroName,
+ const OUString& rLibraryName )
+{
+ // concatenate library and name; use dot only if both strings have content
+ rMacro = rLibraryName;
+ if ( !rLibraryName.isEmpty() && !rMacroName.empty() )
+ rMacro += ".";
+ rMacro += rMacroName;
+}
+
+bool SwMacroField::isScriptURL( const OUString& str )
+{
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference<uri::XUriReferenceFactory> xFactory = uri::UriReferenceFactory::create(xContext);
+ uno::Reference<uri::XVndSunStarScriptUrl> xUrl(xFactory->parse(str), uno::UNO_QUERY);
+ return xUrl.is();
+ }
+ catch (...)
+ {
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/postithelper.cxx b/sw/source/core/fields/postithelper.cxx
new file mode 100644
index 0000000000..a3f27be6f5
--- /dev/null
+++ b/sw/source/core/fields/postithelper.cxx
@@ -0,0 +1,278 @@
+/* -*- 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 <postithelper.hxx>
+#include <PostItMgr.hxx>
+#include <AnnotationWin.hxx>
+
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <ndtxt.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <txtfrm.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <redline.hxx>
+#include <scriptinfo.hxx>
+#include <calbck.hxx>
+#include <IMark.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <fmtanchr.hxx>
+
+class Point;
+
+namespace
+{
+/// Checks if pAnnotationMark covers exactly rAnchorPos (the comment anchor).
+bool AnnotationMarkCoversCommentAnchor(const sw::mark::IMark* pAnnotationMark,
+ const SwPosition& rAnchorPos)
+{
+ if (!pAnnotationMark)
+ {
+ return false;
+ }
+
+ const SwPosition& rMarkStart = pAnnotationMark->GetMarkStart();
+ const SwPosition& rMarkEnd = pAnnotationMark->GetMarkEnd();
+
+ if (rMarkStart != rAnchorPos)
+ {
+ // This can be the as-char case: the comment placeholder character is exactly between the
+ // annotation mark start and end.
+ SwPosition aPosition(rMarkStart);
+ aPosition.AdjustContent(+1);
+ if (aPosition != rAnchorPos)
+ {
+ return false;
+ }
+
+ aPosition.AdjustContent(+1);
+ if (aPosition != rMarkEnd)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (rMarkStart.GetNode() != rMarkEnd.GetNode())
+ {
+ return false;
+ }
+
+ return rMarkEnd.GetContentIndex() == rMarkStart.GetContentIndex() + 1;
+}
+
+/**
+ * Finds the first draw object of rTextFrame which has the same anchor position as the start of
+ * rAnnotationMark.
+ */
+SwAnchoredObject* GetAnchoredObjectOfAnnotationMark(const sw::mark::IMark& rAnnotationMark,
+ const SwTextFrame& rTextFrame)
+{
+ const SwSortedObjs* pAnchored = rTextFrame.GetDrawObjs();
+ if (!pAnchored)
+ {
+ return nullptr;
+ }
+
+ for (SwAnchoredObject* pObject : *pAnchored)
+ {
+ SwFrameFormat& rFrameFormat = pObject->GetFrameFormat();
+ const SwPosition* pFrameAnchor = rFrameFormat.GetAnchor().GetContentAnchor();
+ if (!pFrameAnchor)
+ {
+ continue;
+ }
+
+ if (rAnnotationMark.GetMarkStart() == *pFrameAnchor)
+ {
+ return pObject;
+ }
+ }
+
+ return nullptr;
+}
+}
+
+SwSidebarItem::SwSidebarItem(const bool aFocus)
+ : mpPostIt(nullptr)
+ , mbShow(true)
+ , mbFocus(aFocus)
+ , mbPendingLayout(false)
+ , mLayoutStatus(SwPostItHelper::INVISIBLE)
+{
+}
+
+SwSidebarItem::~SwSidebarItem() {}
+
+SwPostItHelper::SwLayoutStatus SwPostItHelper::getLayoutInfos(
+ SwLayoutInfo& o_rInfo,
+ const SwPosition& rAnchorPos,
+ const sw::mark::IMark* pAnnotationMark )
+{
+ SwLayoutStatus aRet = INVISIBLE;
+ SwTextNode* pTextNode = rAnchorPos.GetNode().GetTextNode();
+ if ( pTextNode == nullptr )
+ return aRet;
+
+ SwIterator<SwTextFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
+ for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame != nullptr; pTextFrame = aIter.Next() )
+ {
+ if( !pTextFrame->IsFollow() )
+ {
+ pTextFrame = pTextFrame->GetFrameAtPos( rAnchorPos );
+ SwPageFrame *pPage = pTextFrame ? pTextFrame->FindPageFrame() : nullptr;
+ if ( pPage != nullptr && !pPage->IsInvalid() && !pPage->IsInvalidFly() )
+ {
+ aRet = VISIBLE;
+
+ o_rInfo.mpAnchorFrame = pTextFrame;
+ {
+ DisableCallbackAction a(*pTextFrame->getRootFrame());
+ bool bPositionFromCommentAnchor = true;
+ if (AnnotationMarkCoversCommentAnchor(pAnnotationMark, rAnchorPos))
+ {
+ SwAnchoredObject* pFrame
+ = GetAnchoredObjectOfAnnotationMark(*pAnnotationMark, *pTextFrame);
+ if (pFrame)
+ {
+ o_rInfo.mPosition = pFrame->GetObjRect();
+ bPositionFromCommentAnchor = false;
+ }
+ }
+ if (bPositionFromCommentAnchor)
+ {
+ pTextFrame->GetCharRect(o_rInfo.mPosition, rAnchorPos, nullptr, false);
+ }
+ o_rInfo.mPositionFromCommentAnchor = bPositionFromCommentAnchor;
+ }
+ if (pAnnotationMark != nullptr)
+ {
+ const SwPosition& rAnnotationStartPos = pAnnotationMark->GetMarkStart();
+ o_rInfo.mnStartNodeIdx = rAnnotationStartPos.GetNodeIndex();
+ o_rInfo.mnStartContent = rAnnotationStartPos.GetContentIndex();
+ }
+ else
+ {
+ o_rInfo.mnStartNodeIdx = SwNodeOffset(0);
+ o_rInfo.mnStartContent = -1;
+ }
+ o_rInfo.mPageFrame = pPage->getFrameArea();
+ o_rInfo.mPagePrtArea = pPage->getFramePrintArea();
+ o_rInfo.mPagePrtArea.Pos() += o_rInfo.mPageFrame.Pos();
+ o_rInfo.mnPageNumber = pPage->GetPhyPageNum();
+ o_rInfo.meSidebarPosition = pPage->SidebarPosition();
+ o_rInfo.mRedlineAuthor = 0;
+
+ const IDocumentRedlineAccess& rIDRA = pTextNode->getIDocumentRedlineAccess();
+ if( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
+ {
+ const SwRangeRedline* pRedline = rIDRA.GetRedline( rAnchorPos, nullptr );
+ if( pRedline )
+ {
+ if( RedlineType::Insert == pRedline->GetType() )
+ aRet = INSERTED;
+ else if( RedlineType::Delete == pRedline->GetType() )
+ {
+ bool bDeleted = pAnnotationMark == nullptr;
+ if( !bDeleted )
+ {
+ IDocumentMarkAccess& rDMA(*pTextNode->GetDoc().getIDocumentMarkAccess());
+ IDocumentMarkAccess::const_iterator_t pAnnotationBookmark =
+ rDMA.findAnnotationBookmark(pAnnotationMark->GetName());
+ // tdf#140980 only really deleted, if there is no helper bookmark
+ // in ChangesInMargin mode
+ if ( pAnnotationBookmark == rDMA.getBookmarksEnd() )
+ bDeleted = true;
+ }
+ if ( bDeleted )
+ aRet = DELETED;
+ }
+ o_rInfo.mRedlineAuthor = pRedline->GetAuthor();
+ }
+ }
+ }
+ }
+ }
+
+ return ( (aRet==VISIBLE) && SwScriptInfo::IsInHiddenRange( *pTextNode , rAnchorPos.GetContentIndex()) )
+ ? HIDDEN
+ : aRet;
+}
+
+tools::Long SwPostItHelper::getLayoutHeight( const SwRootFrame* pRoot )
+{
+ tools::Long nRet = pRoot ? pRoot->getFrameArea().Height() : 0;
+ return nRet;
+}
+
+void SwPostItHelper::setSidebarChanged( SwRootFrame* pRoot, bool bBrowseMode )
+{
+ if( pRoot )
+ {
+ pRoot->SetSidebarChanged();
+ if( bBrowseMode )
+ pRoot->InvalidateBrowseWidth();
+ }
+}
+
+tools::ULong SwPostItHelper::getPageInfo( SwRect& rPageFrame, const SwRootFrame* pRoot, const Point& rPoint )
+{
+ tools::ULong nRet = 0;
+ const SwFrame* pPage = pRoot->GetPageAtPos( rPoint, nullptr, true );
+ if( pPage )
+ {
+ nRet = pPage->GetPhyPageNum();
+ rPageFrame = pPage->getFrameArea();
+ }
+ return nRet;
+}
+
+SwPosition SwAnnotationItem::GetAnchorPosition() const
+{
+ SwTextField* pTextField = mrFormatField.GetTextField();
+ SwTextNode* pTextNode = pTextField->GetpTextNode();
+
+ SwPosition aPos( *pTextNode, pTextField->GetStart() );
+ return aPos;
+}
+
+bool SwAnnotationItem::UseElement(SwRootFrame const& rLayout,
+ IDocumentRedlineAccess const& rIDRA)
+{
+ return mrFormatField.IsFieldInDoc()
+ && (!rLayout.IsHideRedlines()
+ || !sw::IsFieldDeletedInModel(rIDRA, *mrFormatField.GetTextField()));
+}
+
+VclPtr<sw::annotation::SwAnnotationWin> SwAnnotationItem::GetSidebarWindow(
+ SwEditWin& rEditWin,
+ SwPostItMgr& aMgr)
+{
+ return VclPtr<sw::annotation::SwAnnotationWin>::Create( rEditWin,
+ aMgr,
+ *this,
+ &mrFormatField );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx
new file mode 100644
index 0000000000..0ee26771bb
--- /dev/null
+++ b/sw/source/core/fields/reffld.cxx
@@ -0,0 +1,1829 @@
+/* -*- 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 <com/sun/star/text/ReferenceFieldPart.hpp>
+#include <com/sun/star/text/ReferenceFieldSource.hpp>
+#include <o3tl/unreachable.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <pam.hxx>
+#include <cntfrm.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <modeltoviewhelper.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <txtftn.hxx>
+#include <fmtrfmrk.hxx>
+#include <txtrfmrk.hxx>
+#include <fmtftn.hxx>
+#include <ndtxt.hxx>
+#include <chpfld.hxx>
+#include <reffld.hxx>
+#include <expfld.hxx>
+#include <txtfrm.hxx>
+#include <notxtfrm.hxx>
+#include <flyfrm.hxx>
+#include <pagedesc.hxx>
+#include <IMark.hxx>
+#include <crossrefbookmark.hxx>
+#include <ftnidx.hxx>
+#include <utility>
+#include <viewsh.hxx>
+#include <unofldmid.h>
+#include <SwStyleNameMapper.hxx>
+#include <shellres.hxx>
+#include <poolfmt.hxx>
+#include <strings.hrc>
+#include <numrule.hxx>
+#include <SwNodeNum.hxx>
+#include <calbck.hxx>
+
+#include <cstddef>
+#include <memory>
+#include <vector>
+#include <set>
+#include <string_view>
+#include <map>
+#include <algorithm>
+#include <deque>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::lang;
+
+static std::pair<OUString, bool> MakeRefNumStr(SwRootFrame const* pLayout,
+ const SwTextNode& rTextNodeOfField,
+ const SwTextNode& rTextNodeOfReferencedItem,
+ sal_uInt16 nSubType,
+ sal_uInt32 nRefNumFormat,
+ sal_uInt16 nFlags);
+
+static void lcl_GetLayTree( const SwFrame* pFrame, std::vector<const SwFrame*>& rArr )
+{
+ while( pFrame )
+ {
+ if( pFrame->IsBodyFrame() ) // unspectacular
+ pFrame = pFrame->GetUpper();
+ else
+ {
+ rArr.push_back( pFrame );
+
+ // this is the last page
+ if( pFrame->IsPageFrame() )
+ break;
+
+ if( pFrame->IsFlyFrame() )
+ pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
+ else
+ pFrame = pFrame->GetUpper();
+ }
+ }
+}
+
+bool IsFrameBehind( const SwTextNode& rMyNd, sal_Int32 nMySttPos,
+ const SwTextNode& rBehindNd, sal_Int32 nSttPos )
+{
+ const SwTextFrame * pMyFrame = static_cast<SwTextFrame*>(rMyNd.getLayoutFrame(
+ rMyNd.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
+ const SwTextFrame * pFrame = static_cast<SwTextFrame*>(rBehindNd.getLayoutFrame(
+ rBehindNd.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr));
+
+ if( !pFrame || !pMyFrame)
+ return false;
+
+ TextFrameIndex const nMySttPosIndex(pMyFrame->MapModelToView(&rMyNd, nMySttPos));
+ TextFrameIndex const nSttPosIndex(pFrame->MapModelToView(&rBehindNd, nSttPos));
+ while (pFrame && !pFrame->IsInside(nSttPosIndex))
+ pFrame = pFrame->GetFollow();
+ while (pMyFrame && !pMyFrame->IsInside(nMySttPosIndex))
+ pMyFrame = pMyFrame->GetFollow();
+
+ if( !pFrame || !pMyFrame || pFrame == pMyFrame )
+ return false;
+
+ std::vector<const SwFrame*> aRefArr, aArr;
+ ::lcl_GetLayTree( pFrame, aRefArr );
+ ::lcl_GetLayTree( pMyFrame, aArr );
+
+ size_t nRefCnt = aRefArr.size() - 1, nCnt = aArr.size() - 1;
+ bool bVert = false;
+ bool bR2L = false;
+
+ // Loop as long as a frame does not equal?
+ while( nRefCnt && nCnt && aRefArr[ nRefCnt ] == aArr[ nCnt ] )
+ {
+ const SwFrame* pTmpFrame = aArr[ nCnt ];
+ bVert = pTmpFrame->IsVertical();
+ bR2L = pTmpFrame->IsRightToLeft();
+ --nCnt;
+ --nRefCnt;
+ }
+
+ // If a counter overflows?
+ if( aRefArr[ nRefCnt ] == aArr[ nCnt ] )
+ {
+ if( nCnt )
+ --nCnt;
+ else
+ --nRefCnt;
+ }
+
+ const SwFrame* pRefFrame = aRefArr[ nRefCnt ];
+ const SwFrame* pFieldFrame = aArr[ nCnt ];
+
+ // different frames, check their Y-/X-position
+ bool bRefIsLower = false;
+ if( ( SwFrameType::Column | SwFrameType::Cell ) & pFieldFrame->GetType() ||
+ ( SwFrameType::Column | SwFrameType::Cell ) & pRefFrame->GetType() )
+ {
+ if( pFieldFrame->GetType() == pRefFrame->GetType() )
+ {
+ // here, the X-pos is more important
+ if( bVert )
+ {
+ if( bR2L )
+ bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
+ ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
+ pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() );
+ else
+ bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
+ ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
+ pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() );
+ }
+ else if( bR2L )
+ bRefIsLower = pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() ||
+ ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
+ pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
+ else
+ bRefIsLower = pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() ||
+ ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
+ pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
+ pRefFrame = nullptr;
+ }
+ else if( ( SwFrameType::Column | SwFrameType::Cell ) & pFieldFrame->GetType() )
+ pFieldFrame = aArr[ nCnt - 1 ];
+ else
+ pRefFrame = aRefArr[ nRefCnt - 1 ];
+ }
+
+ if( pRefFrame ) // misuse as flag
+ {
+ if( bVert )
+ {
+ if( bR2L )
+ bRefIsLower = pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() ||
+ ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
+ pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
+ else
+ bRefIsLower = pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() ||
+ ( pRefFrame->getFrameArea().Left() == pFieldFrame->getFrameArea().Left() &&
+ pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() );
+ }
+ else if( bR2L )
+ bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
+ ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
+ pRefFrame->getFrameArea().Left() > pFieldFrame->getFrameArea().Left() );
+ else
+ bRefIsLower = pRefFrame->getFrameArea().Top() < pFieldFrame->getFrameArea().Top() ||
+ ( pRefFrame->getFrameArea().Top() == pFieldFrame->getFrameArea().Top() &&
+ pRefFrame->getFrameArea().Left() < pFieldFrame->getFrameArea().Left() );
+ }
+ return bRefIsLower;
+}
+
+// tdf#115319 create alternative reference formats, if the user asked for it
+// (ReferenceFieldLanguage attribute of the reference field is not empty), and
+// language of the text and ReferenceFieldLanguage are the same.
+// Right now only HUNGARIAN seems to need this (as in the related issue,
+// the reversed caption order in autocaption, solved by #i61007#)
+static void lcl_formatReferenceLanguage( OUString& rRefText,
+ bool bClosingParenthesis, LanguageType eLang,
+ std::u16string_view rReferenceLanguage)
+{
+ if (eLang != LANGUAGE_HUNGARIAN || (rReferenceLanguage != u"hu" && rReferenceLanguage != u"Hu"))
+ return;
+
+ // Add Hungarian definitive article (a/az) before references,
+ // similar to \aref, \apageref etc. of LaTeX Babel package.
+ //
+ // for example:
+ //
+ // "az 1. oldalon" ("on page 1"), but
+ // "a 2. oldalon" ("on page 2")
+ // "a fentebbi", "az alábbi" (above/below)
+ // "a Lorem", "az Ipsum"
+ //
+ // Support following numberings of EU publications:
+ //
+ // 1., 1a., a), (1), (1a), iii., III., IA.
+ //
+ // (http://publications.europa.eu/code/hu/hu-120700.htm,
+ // http://publications.europa.eu/code/hu/hu-4100600.htm)
+
+ CharClass aCharClass(( LanguageTag(eLang) ));
+ sal_Int32 nLen = rRefText.getLength();
+ sal_Int32 i;
+ // substring of rRefText starting with letter or number
+ OUString sNumbering;
+ // is article "az"?
+ bool bArticleAz = false;
+ // is numbering a number?
+ bool bNum = false;
+
+ // search first member of the numbering (numbers or letters)
+ for (i=0; i<nLen && (sNumbering.isEmpty() ||
+ ((bNum && aCharClass.isDigit(rRefText, i)) ||
+ (!bNum && aCharClass.isLetter(rRefText, i)))); ++i)
+ {
+ // start of numbering within the field text
+ if (sNumbering.isEmpty() && aCharClass.isLetterNumeric(rRefText, i)) {
+ sNumbering = rRefText.copy(i);
+ bNum = aCharClass.isDigit(rRefText, i);
+ }
+ }
+
+ // length of numbering
+ nLen = i - (rRefText.getLength() - sNumbering.getLength());
+
+ if (bNum)
+ {
+ // az 1, 1000, 1000000, 1000000000...
+ // az 5, 50, 500...
+ if ((sNumbering.startsWith("1") && (nLen == 1 || nLen == 4 || nLen == 7 || nLen == 10)) ||
+ sNumbering.startsWith("5"))
+ bArticleAz = true;
+ }
+ else if (nLen == 1 && sNumbering[0] < 128)
+ {
+ // ASCII 1-letter numbering
+ // az a), e), f) ... x)
+ // az i., v. (but, a x.)
+ static const std::u16string_view sLettersStartingWithVowels = u"aefilmnorsuxyAEFILMNORSUXY";
+ if (sLettersStartingWithVowels.find(sNumbering[0]) != std::u16string_view::npos)
+ {
+ // x), X) are letters, but x. and X. etc. are Roman numbers
+ if (bClosingParenthesis ||
+ (sNumbering[0] != 'x' && sNumbering[0] != 'X'))
+ bArticleAz = true;
+ } else if ((sNumbering[0] == 'v' || sNumbering[0] == 'V') && !bClosingParenthesis)
+ // v), V) are letters, but v. and V. are Roman numbers
+ bArticleAz = true;
+ }
+ else
+ {
+ static const sal_Unicode sVowelsWithDiacritic[] = {
+ 0x00E1, 0x00C1, 0x00E9, 0x00C9, 0x00ED, 0x00CD,
+ 0x00F3, 0x00D3, 0x00F6, 0x00D6, 0x0151, 0x0150,
+ 0x00FA, 0x00DA, 0x00FC, 0x00DC, 0x0171, 0x0170, 0 };
+ static const OUString sVowels = OUString::Concat(u"aAeEiIoOuU") + sVowelsWithDiacritic;
+
+ // handle more than 1-letter long Roman numbers and
+ // their possible combinations with letters:
+ // az IA, a IIB, a IIIC., az Ia, a IIb., a iiic), az LVIII. szonett
+ bool bRomanNumber = false;
+ if (nLen > 1 && (nLen + 1 >= sNumbering.getLength() || sNumbering[nLen] == '.'))
+ {
+ sal_Unicode last = sNumbering[nLen - 1];
+ OUString sNumberingTrim;
+ if ((last >= 'A' && last < 'I') || (last >= 'a' && last < 'i'))
+ sNumberingTrim = sNumbering.copy(0, nLen - 1);
+ else
+ sNumberingTrim = sNumbering.copy(0, nLen);
+ bRomanNumber =
+ sNumberingTrim.replaceAll("i", "").replaceAll("v", "").replaceAll("x", "").replaceAll("l", "").replaceAll("c", "").isEmpty() ||
+ sNumberingTrim.replaceAll("I", "").replaceAll("V", "").replaceAll("X", "").replaceAll("L", "").replaceAll("C", "").isEmpty();
+ }
+
+ if (
+ // Roman number and a letter optionally
+ ( bRomanNumber && (
+ (sNumbering[0] == 'i' && sNumbering[1] != 'i' && sNumbering[1] != 'v' && sNumbering[1] != 'x') ||
+ (sNumbering[0] == 'I' && sNumbering[1] != 'I' && sNumbering[1] != 'V' && sNumbering[1] != 'X') ||
+ (sNumbering[0] == 'v' && sNumbering[1] != 'i') ||
+ (sNumbering[0] == 'V' && sNumbering[1] != 'I') ||
+ (sNumbering[0] == 'l' && sNumbering[1] != 'x') ||
+ (sNumbering[0] == 'L' && sNumbering[1] != 'X')) ) ||
+ // a word starting with vowel (not Roman number)
+ ( !bRomanNumber && sVowels.indexOf(sNumbering[0]) != -1))
+ {
+ bArticleAz = true;
+ }
+ }
+ // not a title text starting already with a definitive article
+ if ( sNumbering.startsWith("A ") || sNumbering.startsWith("Az ") ||
+ sNumbering.startsWith("a ") || sNumbering.startsWith("az ") )
+ return;
+
+ // lowercase, if rReferenceLanguage == "hu", not "Hu"
+ OUString sArticle;
+
+ if ( rReferenceLanguage == u"hu" )
+ sArticle = "a";
+ else
+ sArticle = "A";
+
+ if (bArticleAz)
+ sArticle += "z";
+
+ rRefText = sArticle + " " + rRefText;
+}
+
+/// get references
+SwGetRefField::SwGetRefField( SwGetRefFieldType* pFieldType,
+ OUString aSetRef, OUString aSetReferenceLanguage, sal_uInt16 nSubTyp,
+ sal_uInt16 nSequenceNo, sal_uInt16 nFlags, sal_uLong nFormat )
+ : SwField(pFieldType, nFormat),
+ m_sSetRefName(std::move(aSetRef)),
+ m_sSetReferenceLanguage(std::move(aSetReferenceLanguage)),
+ m_nSubType(nSubTyp),
+ m_nSeqNo(nSequenceNo),
+ m_nFlags(nFlags)
+{
+}
+
+SwGetRefField::~SwGetRefField()
+{
+}
+
+OUString SwGetRefField::GetDescription() const
+{
+ return SwResId(STR_REFERENCE);
+}
+
+sal_uInt16 SwGetRefField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwGetRefField::SetSubType( sal_uInt16 n )
+{
+ m_nSubType = n;
+}
+
+// #i81002#
+bool SwGetRefField::IsRefToHeadingCrossRefBookmark() const
+{
+ return GetSubType() == REF_BOOKMARK &&
+ ::sw::mark::CrossRefHeadingBookmark::IsLegalName(m_sSetRefName);
+}
+
+bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
+{
+ return GetSubType() == REF_BOOKMARK &&
+ ::sw::mark::CrossRefNumItemBookmark::IsLegalName(m_sSetRefName);
+}
+
+const SwTextNode* SwGetRefField::GetReferencedTextNode(SwTextNode* pTextNode, SwFrame* pFrame) const
+{
+ SwGetRefFieldType *pTyp = dynamic_cast<SwGetRefFieldType*>(GetTyp());
+ if (!pTyp)
+ return nullptr;
+ sal_Int32 nDummy = -1;
+ return SwGetRefFieldType::FindAnchor( &pTyp->GetDoc(), m_sSetRefName, m_nSubType, m_nSeqNo, m_nFlags, &nDummy,
+ nullptr, nullptr, pTextNode, pFrame );
+}
+
+// strikethrough for tooltips using Unicode combining character
+static OUString lcl_formatStringByCombiningCharacter(std::u16string_view sText, const sal_Unicode cChar)
+{
+ OUStringBuffer sRet(sText.size() * 2);
+ for (size_t i = 0; i < sText.size(); ++i)
+ {
+ sRet.append(OUStringChar(sText[i]) + OUStringChar(cChar));
+ }
+ return sRet.makeStringAndClear();
+}
+
+// #i85090#
+OUString SwGetRefField::GetExpandedTextOfReferencedTextNode(
+ SwRootFrame const& rLayout, SwTextNode* pTextNode, SwFrame* pFrame) const
+{
+ const SwTextNode* pReferencedTextNode( GetReferencedTextNode(pTextNode, pFrame) );
+ if ( !pReferencedTextNode )
+ return OUString();
+
+ // show the referenced text without the deletions, but if the whole text was
+ // deleted, show the original text for the sake of the comfortable reviewing,
+ // but with Unicode strikethrough in the tooltip
+ OUString sRet = sw::GetExpandTextMerged(&rLayout, *pReferencedTextNode, true, false, ExpandMode::HideDeletions);
+ if ( sRet.isEmpty() )
+ {
+ static const sal_Unicode cStrikethrough = u'\x0336';
+ sRet = sw::GetExpandTextMerged(&rLayout, *pReferencedTextNode, true, false, ExpandMode(0));
+ sRet = lcl_formatStringByCombiningCharacter( sRet, cStrikethrough );
+ }
+
+ return sRet;
+}
+
+void SwGetRefField::SetExpand( const OUString& rStr )
+{
+ m_sText = rStr;
+ m_sTextRLHidden = rStr;
+}
+
+OUString SwGetRefField::ExpandImpl(SwRootFrame const*const pLayout) const
+{
+ return pLayout && pLayout->IsHideRedlines() ? m_sTextRLHidden : m_sText;
+}
+
+OUString SwGetRefField::GetFieldName() const
+{
+ const OUString aName = GetTyp()->GetName();
+ if ( !aName.isEmpty() || !m_sSetRefName.isEmpty() )
+ {
+ return aName + " " + m_sSetRefName;
+ }
+ return ExpandImpl(nullptr);
+}
+
+
+static void FilterText(OUString & rText, LanguageType const eLang,
+ std::u16string_view rSetReferenceLanguage)
+{
+ // remove all special characters (replace them with blanks)
+ if (rText.isEmpty())
+ return;
+
+ rText = rText.replaceAll(u"\u00ad", "");
+ OUStringBuffer aBuf(rText);
+ const sal_Int32 l = aBuf.getLength();
+ for (sal_Int32 i = 0; i < l; ++i)
+ {
+ if (aBuf[i] < ' ')
+ {
+ aBuf[i] = ' ';
+ }
+ else if (aBuf[i] == 0x2011)
+ {
+ aBuf[i] = '-';
+ }
+ }
+ rText = aBuf.makeStringAndClear();
+ if (!rSetReferenceLanguage.empty())
+ {
+ lcl_formatReferenceLanguage(rText, false, eLang, rSetReferenceLanguage);
+ }
+}
+
+// #i81002# - parameter <pFieldTextAttr> added
+void SwGetRefField::UpdateField( const SwTextField* pFieldTextAttr, SwFrame* pFrame )
+{
+ SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
+
+ for (SwRootFrame const* const pLay : rDoc.GetAllLayouts())
+ {
+ if (pLay->IsHideRedlines())
+ {
+ UpdateField(pFieldTextAttr, pFrame, pLay, m_sTextRLHidden);
+ }
+ else
+ {
+ UpdateField(pFieldTextAttr, pFrame, pLay, m_sText);
+ }
+ }
+}
+
+void SwGetRefField::UpdateField(const SwTextField* pFieldTextAttr, SwFrame* pFrameContainingField,
+ const SwRootFrame* const pLayout, OUString& rText)
+{
+ SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
+
+ rText.clear();
+
+ // finding the reference target (the number)
+ sal_Int32 nNumStart = -1;
+ sal_Int32 nNumEnd = -1;
+ SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(
+ &rDoc, m_sSetRefName, m_nSubType, m_nSeqNo, m_nFlags, &nNumStart, &nNumEnd,
+ pLayout, pFieldTextAttr ? pFieldTextAttr->GetpTextNode() : nullptr, pFrameContainingField
+ );
+ // not found?
+ if ( !pTextNd )
+ {
+ rText = SwViewShell::GetShellRes()->aGetRefField_RefItemNotFound;
+
+ return;
+ }
+
+ // where is the category name (e.g. "Illustration")?
+ const OUString aText = pTextNd->GetText();
+ const sal_Int32 nCatStart = aText.indexOf(m_sSetRefName);
+ const bool bHasCat = nCatStart>=0;
+ const sal_Int32 nCatEnd = bHasCat ? nCatStart + m_sSetRefName.getLength() : -1;
+
+ // length of the referenced text
+ const sal_Int32 nLen = aText.getLength();
+
+ // which format?
+ switch( GetFormat() )
+ {
+ case REF_CONTENT:
+ case REF_ONLYNUMBER:
+ case REF_ONLYCAPTION:
+ case REF_ONLYSEQNO:
+ {
+ // needed part of Text
+ sal_Int32 nStart;
+ sal_Int32 nEnd;
+
+ switch( m_nSubType )
+ {
+ case REF_SEQUENCEFLD:
+
+ switch( GetFormat() )
+ {
+ // "Category and Number"
+ case REF_ONLYNUMBER:
+ if (bHasCat) {
+ nStart = std::min(nNumStart, nCatStart);
+ nEnd = std::max(nNumEnd, nCatEnd);
+ } else {
+ nStart = nNumStart;
+ nEnd = nNumEnd;
+ }
+ break;
+
+ // "Caption Text"
+ case REF_ONLYCAPTION: {
+ // next alphanumeric character after category+number
+ if (const SwTextAttr* const pTextAttr =
+ pTextNd->GetTextAttrForCharAt(nNumStart, RES_TXTATR_FIELD)
+ ) {
+ // start searching from nFrom
+ const sal_Int32 nFrom = bHasCat
+ ? std::max(nNumStart + 1, nCatEnd)
+ : nNumStart + 1;
+ nStart = SwGetExpField::GetReferenceTextPos( pTextAttr->GetFormatField(), rDoc, nFrom );
+ } else {
+ nStart = bHasCat ? std::max(nNumEnd, nCatEnd) : nNumEnd;
+ }
+ nEnd = nLen;
+ break;
+ }
+
+ // "Numbering"
+ case REF_ONLYSEQNO:
+ nStart = nNumStart;
+ nEnd = std::min(nStart + 1, nLen);
+ break;
+
+ // "Reference" (whole Text)
+ case REF_CONTENT:
+ nStart = 0;
+ nEnd = nLen;
+ break;
+
+ default:
+ O3TL_UNREACHABLE;
+ }
+ break;
+
+ case REF_BOOKMARK:
+ nStart = nNumStart;
+ // text is spread across multiple nodes - get whole text or only until end of node?
+ nEnd = nNumEnd<0 ? nLen : nNumEnd;
+ break;
+
+ case REF_OUTLINE:
+ nStart = nNumStart;
+ nEnd = nNumEnd;
+ break;
+
+ case REF_FOOTNOTE:
+ case REF_ENDNOTE:
+ // get number or numString
+ for( size_t i = 0; i < rDoc.GetFootnoteIdxs().size(); ++i )
+ {
+ SwTextFootnote* const pFootnoteIdx = rDoc.GetFootnoteIdxs()[i];
+ if( m_nSeqNo == pFootnoteIdx->GetSeqRefNo() )
+ {
+ rText = pFootnoteIdx->GetFootnote().GetViewNumStr(rDoc, pLayout);
+ if (!m_sSetReferenceLanguage.isEmpty())
+ {
+ lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ break;
+ }
+ }
+ return;
+
+ case REF_STYLE:
+ nStart = 0;
+ nEnd = nLen;
+ break;
+
+ case REF_SETREFATTR:
+ nStart = nNumStart;
+ nEnd = nNumEnd;
+ break;
+
+ default:
+ O3TL_UNREACHABLE;
+ }
+
+ if( nStart != nEnd ) // a section?
+ {
+ if (pLayout->IsHideRedlines())
+ {
+ if (m_nSubType == REF_OUTLINE
+ || (m_nSubType == REF_SEQUENCEFLD && REF_CONTENT == GetFormat()))
+ {
+ rText = sw::GetExpandTextMerged(pLayout, *pTextNd, false, false,
+ ExpandMode(0));
+ }
+ else
+ {
+ rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
+ false, ExpandMode::HideDeletions);
+ }
+ }
+ else
+ {
+ rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
+ false, ExpandMode::HideDeletions);
+ // show the referenced text without the deletions, but if the whole text was
+ // deleted, show the original text for the sake of the comfortable reviewing
+ // (with strikethrough in tooltip, see GetExpandedTextOfReferencedTextNode())
+ if (rText.isEmpty())
+ rText = pTextNd->GetExpandText(pLayout, nStart, nEnd - nStart, false, false,
+ false, ExpandMode(0));
+ }
+ FilterText(rText, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ }
+ break;
+
+ case REF_PAGE:
+ case REF_PAGE_PGDESC:
+ {
+ SwTextFrame const* pFrame = static_cast<SwTextFrame*>(pTextNd->getLayoutFrame(pLayout, nullptr, nullptr));
+ SwTextFrame const*const pSave = pFrame;
+ if (pFrame)
+ {
+ TextFrameIndex const nNumStartIndex(pFrame->MapModelToView(pTextNd, nNumStart));
+ while (pFrame && !pFrame->IsInside(nNumStartIndex))
+ pFrame = pFrame->GetFollow();
+ }
+
+ if( pFrame || nullptr != ( pFrame = pSave ))
+ {
+ sal_uInt16 nPageNo = pFrame->GetVirtPageNum();
+ const SwPageFrame *pPage;
+ if( REF_PAGE_PGDESC == GetFormat() &&
+ nullptr != ( pPage = pFrame->FindPageFrame() ) &&
+ pPage->GetPageDesc() )
+ {
+ rText = pPage->GetPageDesc()->GetNumType().GetNumStr(nPageNo);
+ }
+ else
+ {
+ rText = OUString::number(nPageNo);
+ }
+
+ if (!m_sSetReferenceLanguage.isEmpty())
+ lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ }
+ break;
+
+ case REF_CHAPTER:
+ {
+ // a bit tricky: search any frame
+ SwFrame const* const pFrame = pTextNd->getLayoutFrame(pLayout);
+ if (pFrame)
+ {
+ SwChapterFieldType aFieldTyp;
+ SwChapterField aField(&aFieldTyp, 0);
+ aField.SetLevel(MAXLEVEL - 1);
+ aField.ChangeExpansion(*pFrame, pTextNd, true);
+
+ rText = aField.GetNumber(pLayout);
+
+ if (!m_sSetReferenceLanguage.isEmpty())
+ lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ }
+ break;
+
+ case REF_UPDOWN:
+ {
+ // #i81002#
+ // simplified: use parameter <pFieldTextAttr>
+ if( !pFieldTextAttr || !pFieldTextAttr->GetpTextNode() )
+ break;
+
+ LocaleDataWrapper aLocaleData(( LanguageTag( GetLanguage() ) ));
+
+ // first a "short" test - in case both are in the same node
+ if( pFieldTextAttr->GetpTextNode() == pTextNd )
+ {
+ rText = nNumStart < pFieldTextAttr->GetStart()
+ ? aLocaleData.getAboveWord()
+ : aLocaleData.getBelowWord();
+ break;
+ }
+
+ rText = ::IsFrameBehind( *pFieldTextAttr->GetpTextNode(), pFieldTextAttr->GetStart(),
+ *pTextNd, nNumStart )
+ ? aLocaleData.getAboveWord()
+ : aLocaleData.getBelowWord();
+
+ if (!m_sSetReferenceLanguage.isEmpty())
+ lcl_formatReferenceLanguage(rText, false, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ break;
+ // #i81002#
+ case REF_NUMBER:
+ case REF_NUMBER_NO_CONTEXT:
+ case REF_NUMBER_FULL_CONTEXT:
+ {
+ if ( pFieldTextAttr && pFieldTextAttr->GetpTextNode() )
+ {
+ auto result =
+ MakeRefNumStr(pLayout, pFieldTextAttr->GetTextNode(), *pTextNd, m_nSubType, GetFormat(), GetFlags());
+ rText = result.first;
+ // for differentiation of Roman numbers and letters in Hungarian article handling
+ bool bClosingParenthesis = result.second;
+ if (!m_sSetReferenceLanguage.isEmpty())
+ {
+ lcl_formatReferenceLanguage(rText, bClosingParenthesis, GetLanguage(), m_sSetReferenceLanguage);
+ }
+ }
+ }
+
+ break;
+
+ default:
+ OSL_FAIL("<SwGetRefField::UpdateField(..)> - unknown format type");
+ }
+}
+
+
+// #i81002#
+static std::pair<OUString, bool> MakeRefNumStr(
+ SwRootFrame const*const pLayout,
+ const SwTextNode& i_rTextNodeOfField,
+ const SwTextNode& i_rTextNodeOfReferencedItem,
+ const sal_uInt16 nSubType,
+ const sal_uInt32 nRefNumFormat,
+ const sal_uInt16 nFlags)
+{
+ bool bHideNonNumerical = (nSubType == REF_STYLE) && ((nFlags & REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL) == REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL);
+ SwTextNode const& rTextNodeOfField(pLayout
+ ? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfField)
+ : i_rTextNodeOfField);
+ SwTextNode const& rTextNodeOfReferencedItem(pLayout
+ ? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfReferencedItem)
+ : i_rTextNodeOfReferencedItem);
+ if ( rTextNodeOfReferencedItem.HasNumber(pLayout) &&
+ rTextNodeOfReferencedItem.IsCountedInList() )
+ {
+ OSL_ENSURE( rTextNodeOfReferencedItem.GetNum(pLayout),
+ "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance!" );
+
+ // Determine, up to which level the superior list labels have to be
+ // included - default is to include all superior list labels.
+ int nRestrictInclToThisLevel( 0 );
+ // Determine for format REF_NUMBER the level, up to which the superior
+ // list labels have to be restricted, if the text node of the reference
+ // field and the text node of the referenced item are in the same
+ // document context.
+ if ( nRefNumFormat == REF_NUMBER &&
+ rTextNodeOfField.FindFlyStartNode()
+ == rTextNodeOfReferencedItem.FindFlyStartNode() &&
+ rTextNodeOfField.FindFootnoteStartNode()
+ == rTextNodeOfReferencedItem.FindFootnoteStartNode() &&
+ rTextNodeOfField.FindHeaderStartNode()
+ == rTextNodeOfReferencedItem.FindHeaderStartNode() &&
+ rTextNodeOfField.FindFooterStartNode()
+ == rTextNodeOfReferencedItem.FindFooterStartNode() )
+ {
+ const SwNodeNum* pNodeNumForTextNodeOfField( nullptr );
+ if ( rTextNodeOfField.HasNumber(pLayout) &&
+ rTextNodeOfField.GetNumRule() == rTextNodeOfReferencedItem.GetNumRule() )
+ {
+ pNodeNumForTextNodeOfField = rTextNodeOfField.GetNum(pLayout);
+ }
+ else
+ {
+ pNodeNumForTextNodeOfField =
+ rTextNodeOfReferencedItem.GetNum(pLayout)->GetPrecedingNodeNumOf(rTextNodeOfField);
+ }
+ if ( pNodeNumForTextNodeOfField )
+ {
+ const SwNumberTree::tNumberVector rFieldNumVec =
+ pNodeNumForTextNodeOfField->GetNumberVector();
+ const SwNumberTree::tNumberVector rRefItemNumVec =
+ rTextNodeOfReferencedItem.GetNum()->GetNumberVector();
+ std::size_t nLevel( 0 );
+ while ( nLevel < rFieldNumVec.size() && nLevel < rRefItemNumVec.size() )
+ {
+ if ( rRefItemNumVec[nLevel] == rFieldNumVec[nLevel] )
+ {
+ nRestrictInclToThisLevel = nLevel + 1;
+ }
+ else
+ {
+ break;
+ }
+ ++nLevel;
+ }
+ }
+ }
+
+ // Determine, if superior list labels have to be included
+ const bool bInclSuperiorNumLabels(
+ ( nRestrictInclToThisLevel < rTextNodeOfReferencedItem.GetActualListLevel() &&
+ ( nRefNumFormat == REF_NUMBER || nRefNumFormat == REF_NUMBER_FULL_CONTEXT ) ) );
+
+ OSL_ENSURE( rTextNodeOfReferencedItem.GetNumRule(),
+ "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set!" );
+ return std::make_pair(
+ rTextNodeOfReferencedItem.GetNumRule()->MakeRefNumString(
+ *(rTextNodeOfReferencedItem.GetNum(pLayout)),
+ bInclSuperiorNumLabels,
+ nRestrictInclToThisLevel,
+ bHideNonNumerical ),
+ rTextNodeOfReferencedItem.GetNumRule()->MakeNumString(
+ *(rTextNodeOfReferencedItem.GetNum(pLayout)),
+ true).endsWith(")") );
+ }
+
+ return std::make_pair(OUString(), false);
+}
+
+std::unique_ptr<SwField> SwGetRefField::Copy() const
+{
+ std::unique_ptr<SwGetRefField> pField( new SwGetRefField( static_cast<SwGetRefFieldType*>(GetTyp()),
+ m_sSetRefName, m_sSetReferenceLanguage, m_nSubType,
+ m_nSeqNo, m_nFlags, GetFormat() ) );
+ pField->m_sText = m_sText;
+ pField->m_sTextRLHidden = m_sTextRLHidden;
+ return std::unique_ptr<SwField>(pField.release());
+}
+
+/// get reference name
+OUString SwGetRefField::GetPar1() const
+{
+ return m_sSetRefName;
+}
+
+/// set reference name
+void SwGetRefField::SetPar1( const OUString& rName )
+{
+ m_sSetRefName = rName;
+}
+
+OUString SwGetRefField::GetPar2() const
+{
+ return ExpandImpl(nullptr);
+}
+
+bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nPart = 0;
+ switch(GetFormat())
+ {
+ case REF_PAGE : nPart = ReferenceFieldPart::PAGE ; break;
+ case REF_CHAPTER : nPart = ReferenceFieldPart::CHAPTER ; break;
+ case REF_CONTENT : nPart = ReferenceFieldPart::TEXT ; break;
+ case REF_UPDOWN : nPart = ReferenceFieldPart::UP_DOWN ; break;
+ case REF_PAGE_PGDESC: nPart = ReferenceFieldPart::PAGE_DESC ; break;
+ case REF_ONLYNUMBER : nPart = ReferenceFieldPart::CATEGORY_AND_NUMBER ; break;
+ case REF_ONLYCAPTION: nPart = ReferenceFieldPart::ONLY_CAPTION ; break;
+ case REF_ONLYSEQNO : nPart = ReferenceFieldPart::ONLY_SEQUENCE_NUMBER; break;
+ // #i81002#
+ case REF_NUMBER: nPart = ReferenceFieldPart::NUMBER; break;
+ case REF_NUMBER_NO_CONTEXT: nPart = ReferenceFieldPart::NUMBER_NO_CONTEXT; break;
+ case REF_NUMBER_FULL_CONTEXT: nPart = ReferenceFieldPart::NUMBER_FULL_CONTEXT; break;
+ }
+ rAny <<= nPart;
+ }
+ break;
+ case FIELD_PROP_USHORT2:
+ {
+ sal_Int16 nSource = 0;
+ switch(m_nSubType)
+ {
+ case REF_SETREFATTR : nSource = ReferenceFieldSource::REFERENCE_MARK; break;
+ case REF_SEQUENCEFLD: nSource = ReferenceFieldSource::SEQUENCE_FIELD; break;
+ case REF_BOOKMARK : nSource = ReferenceFieldSource::BOOKMARK; break;
+ case REF_OUTLINE : OSL_FAIL("not implemented"); break;
+ case REF_FOOTNOTE : nSource = ReferenceFieldSource::FOOTNOTE; break;
+ case REF_ENDNOTE : nSource = ReferenceFieldSource::ENDNOTE; break;
+ case REF_STYLE : nSource = ReferenceFieldSource::STYLE; break;
+ }
+ rAny <<= nSource;
+ }
+ break;
+ case FIELD_PROP_USHORT3:
+ rAny <<= m_nFlags;
+ break;
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmp(GetPar1());
+ if(REF_SEQUENCEFLD == m_nSubType)
+ {
+ sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( sTmp, SwGetPoolIdFromName::TxtColl );
+ switch( nPoolId )
+ {
+ case RES_POOLCOLL_LABEL_ABB:
+ case RES_POOLCOLL_LABEL_TABLE:
+ case RES_POOLCOLL_LABEL_FRAME:
+ case RES_POOLCOLL_LABEL_DRAWING:
+ case RES_POOLCOLL_LABEL_FIGURE:
+ SwStyleNameMapper::FillProgName(nPoolId, sTmp) ;
+ break;
+ }
+ }
+ rAny <<= sTmp;
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ rAny <<= ExpandImpl(nullptr);
+ break;
+ case FIELD_PROP_PAR4:
+ rAny <<= m_sSetReferenceLanguage;
+ break;
+ case FIELD_PROP_SHORT1:
+ rAny <<= static_cast<sal_Int16>(m_nSeqNo);
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_USHORT1:
+ {
+ sal_Int16 nPart = 0;
+ rAny >>= nPart;
+ switch(nPart)
+ {
+ case ReferenceFieldPart::PAGE: nPart = REF_PAGE; break;
+ case ReferenceFieldPart::CHAPTER: nPart = REF_CHAPTER; break;
+ case ReferenceFieldPart::TEXT: nPart = REF_CONTENT; break;
+ case ReferenceFieldPart::UP_DOWN: nPart = REF_UPDOWN; break;
+ case ReferenceFieldPart::PAGE_DESC: nPart = REF_PAGE_PGDESC; break;
+ case ReferenceFieldPart::CATEGORY_AND_NUMBER: nPart = REF_ONLYNUMBER; break;
+ case ReferenceFieldPart::ONLY_CAPTION: nPart = REF_ONLYCAPTION; break;
+ case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER : nPart = REF_ONLYSEQNO; break;
+ // #i81002#
+ case ReferenceFieldPart::NUMBER: nPart = REF_NUMBER; break;
+ case ReferenceFieldPart::NUMBER_NO_CONTEXT: nPart = REF_NUMBER_NO_CONTEXT; break;
+ case ReferenceFieldPart::NUMBER_FULL_CONTEXT: nPart = REF_NUMBER_FULL_CONTEXT; break;
+ default: return false;
+ }
+ SetFormat(nPart);
+ }
+ break;
+ case FIELD_PROP_USHORT2:
+ {
+ sal_Int16 nSource = 0;
+ rAny >>= nSource;
+ switch(nSource)
+ {
+ case ReferenceFieldSource::REFERENCE_MARK : m_nSubType = REF_SETREFATTR ; break;
+ case ReferenceFieldSource::SEQUENCE_FIELD :
+ {
+ if(REF_SEQUENCEFLD == m_nSubType)
+ break;
+ m_nSubType = REF_SEQUENCEFLD;
+ ConvertProgrammaticToUIName();
+ }
+ break;
+ case ReferenceFieldSource::BOOKMARK : m_nSubType = REF_BOOKMARK ; break;
+ case ReferenceFieldSource::FOOTNOTE : m_nSubType = REF_FOOTNOTE ; break;
+ case ReferenceFieldSource::ENDNOTE : m_nSubType = REF_ENDNOTE ; break;
+ case ReferenceFieldSource::STYLE : m_nSubType = REF_STYLE ; break;
+ }
+ }
+ break;
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmpStr;
+ rAny >>= sTmpStr;
+ SetPar1(sTmpStr);
+ ConvertProgrammaticToUIName();
+ }
+ break;
+ case FIELD_PROP_PAR3:
+ {
+ OUString sTmpStr;
+ rAny >>= sTmpStr;
+ SetExpand( sTmpStr );
+ }
+ break;
+ case FIELD_PROP_PAR4:
+ rAny >>= m_sSetReferenceLanguage;
+ break;
+ case FIELD_PROP_USHORT3:
+ {
+ sal_uInt16 nSetFlags = 0;
+ rAny >>= nSetFlags;
+ m_nFlags = nSetFlags;
+ }
+ break;
+ case FIELD_PROP_SHORT1:
+ {
+ sal_Int16 nSetSeq = 0;
+ rAny >>= nSetSeq;
+ if(nSetSeq >= 0)
+ m_nSeqNo = nSetSeq;
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+void SwGetRefField::ConvertProgrammaticToUIName()
+{
+ if(!(GetTyp() && REF_SEQUENCEFLD == m_nSubType))
+ return;
+
+ SwDoc& rDoc = static_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
+ const OUString rPar1 = GetPar1();
+ // don't convert when the name points to an existing field type
+ if (rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, rPar1, false))
+ return;
+
+ sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromProgName( rPar1, SwGetPoolIdFromName::TxtColl );
+ TranslateId pResId;
+ switch( nPoolId )
+ {
+ case RES_POOLCOLL_LABEL_ABB:
+ pResId = STR_POOLCOLL_LABEL_ABB;
+ break;
+ case RES_POOLCOLL_LABEL_TABLE:
+ pResId = STR_POOLCOLL_LABEL_TABLE;
+ break;
+ case RES_POOLCOLL_LABEL_FRAME:
+ pResId = STR_POOLCOLL_LABEL_FRAME;
+ break;
+ case RES_POOLCOLL_LABEL_DRAWING:
+ pResId = STR_POOLCOLL_LABEL_DRAWING;
+ break;
+ case RES_POOLCOLL_LABEL_FIGURE:
+ pResId = STR_POOLCOLL_LABEL_FIGURE;
+ break;
+ }
+ if (pResId)
+ SetPar1(SwResId(pResId));
+}
+
+SwGetRefFieldType::SwGetRefFieldType( SwDoc& rDc )
+ : SwFieldType( SwFieldIds::GetRef ), m_rDoc( rDc )
+{}
+
+std::unique_ptr<SwFieldType> SwGetRefFieldType::Copy() const
+{
+ return std::make_unique<SwGetRefFieldType>( m_rDoc );
+}
+
+void SwGetRefFieldType::UpdateGetReferences()
+{
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields, false);
+ for(auto pFormatField: vFields)
+ {
+ // update only the GetRef fields
+ //JP 3.4.2001: Task 71231 - we need the correct language
+ SwGetRefField* pGRef = static_cast<SwGetRefField*>(pFormatField->GetField());
+ const SwTextField* pTField;
+ if(!pGRef->GetLanguage() &&
+ nullptr != (pTField = pFormatField->GetTextField()) &&
+ pTField->GetpTextNode())
+ {
+ pGRef->SetLanguage(pTField->GetpTextNode()->GetLang(pTField->GetStart()));
+ }
+
+ // #i81002#
+ pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
+ }
+ CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
+}
+
+void SwGetRefFieldType::UpdateStyleReferences()
+{
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields, false);
+ bool bModified = false;
+ for(auto pFormatField: vFields)
+ {
+ // update only the GetRef fields which are also STYLEREF fields
+ SwGetRefField* pGRef = static_cast<SwGetRefField*>(pFormatField->GetField());
+
+ if (pGRef->GetSubType() != REF_STYLE) continue;
+
+ const SwTextField* pTField;
+ if(!pGRef->GetLanguage() &&
+ nullptr != (pTField = pFormatField->GetTextField()) &&
+ pTField->GetpTextNode())
+ {
+ pGRef->SetLanguage(pTField->GetpTextNode()->GetLang(pTField->GetStart()));
+ }
+
+ pGRef->UpdateField(pFormatField->GetTextField(), nullptr);
+ bModified = true;
+ }
+ if (bModified)
+ CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
+}
+
+void SwGetRefFieldType::SwClientNotify(const SwModify&, const SfxHint& rHint)
+{
+ if (rHint.GetId() != SfxHintId::SwLegacyModify)
+ return;
+ auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
+ if(!pLegacy->m_pNew && !pLegacy->m_pOld)
+ // update to all GetReference fields
+ // hopefully, this codepath is soon dead code, and
+ // UpdateGetReferences gets only called directly
+ UpdateGetReferences();
+ else
+ // forward to text fields, they "expand" the text
+ CallSwClientNotify(rHint);
+}
+
+namespace sw {
+
+bool IsMarkHintHidden(SwRootFrame const& rLayout,
+ SwTextNode const& rNode, SwTextAttrEnd const& rHint)
+{
+ if (!rLayout.HasMergedParas())
+ {
+ return false;
+ }
+ SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
+ rNode.getLayoutFrame(&rLayout)));
+ if (!pFrame)
+ {
+ return true;
+ }
+ sal_Int32 const*const pEnd(rHint.GetEnd());
+ if (pEnd)
+ {
+ return pFrame->MapModelToView(&rNode, rHint.GetStart())
+ == pFrame->MapModelToView(&rNode, *pEnd);
+ }
+ else
+ {
+ assert(rHint.HasDummyChar());
+ return pFrame->MapModelToView(&rNode, rHint.GetStart())
+ == pFrame->MapModelToView(&rNode, rHint.GetStart() + 1);
+ }
+}
+
+} // namespace sw
+
+namespace
+{
+ enum StyleRefElementType
+ {
+ Default,
+ Reference, /* e.g. footnotes, endnotes */
+ Marginal, /* headers, footers */
+ };
+
+ /// Picks the first text node with a matching style from a double ended queue, starting at the front
+ /// This allows us to use the deque either as a stack or as a queue depending on whether we want to search up or down
+ SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, const std::deque<SwNode*>& pToSearch,
+ std::u16string_view rStyleName, bool bCaseSensitive = true)
+ {
+ std::deque<SwNode*> pSearching(pToSearch);
+ while (!pSearching.empty())
+ {
+ SwNode* pCurrent = pSearching.front();
+ pSearching.pop_front();
+
+ if (*pCurrent == *pSelf)
+ continue;
+
+ SwTextNode* pTextNode = pCurrent->GetTextNode();
+ if (!pTextNode)
+ continue;
+
+ if (bCaseSensitive)
+ {
+ if (pTextNode->GetFormatColl()->GetName() == rStyleName)
+ return pTextNode;
+ }
+ else
+ {
+ if (pTextNode->GetFormatColl()->GetName().equalsIgnoreAsciiCase(rStyleName))
+ return pTextNode;
+ }
+ }
+
+ return nullptr;
+ }
+}
+
+SwTextNode* SwGetRefFieldType::FindAnchor(SwDoc* pDoc, const OUString& rRefMark,
+ sal_uInt16 nSubType, sal_uInt16 nSeqNo, sal_uInt16 nFlags,
+ sal_Int32* pStt, sal_Int32* pEnd, SwRootFrame const* const pLayout,
+ SwTextNode* pSelf, SwFrame* pContentFrame)
+{
+ OSL_ENSURE( pStt, "Why did no one check the StartPos?" );
+
+ IDocumentRedlineAccess & rIDRA(pDoc->getIDocumentRedlineAccess());
+ SwTextNode* pTextNd = nullptr;
+ switch( nSubType )
+ {
+ case REF_SETREFATTR:
+ {
+ const SwFormatRefMark *pRef = pDoc->GetRefMark( rRefMark );
+ SwTextRefMark const*const pRefMark(pRef ? pRef->GetTextRefMark() : nullptr);
+ if (pRefMark && (!pLayout || !sw::IsMarkHintHidden(*pLayout,
+ pRefMark->GetTextNode(), *pRefMark)))
+ {
+ pTextNd = const_cast<SwTextNode*>(&pRef->GetTextRefMark()->GetTextNode());
+ *pStt = pRef->GetTextRefMark()->GetStart();
+ if( pEnd )
+ *pEnd = pRef->GetTextRefMark()->GetAnyEnd();
+ }
+ }
+ break;
+
+ case REF_SEQUENCEFLD:
+ {
+ SwFieldType* pFieldType = pDoc->getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp, rRefMark, false );
+ if( pFieldType && pFieldType->HasWriterListeners() &&
+ nsSwGetSetExpType::GSE_SEQ & static_cast<SwSetExpFieldType*>(pFieldType)->GetType() )
+ {
+ std::vector<SwFormatField*> vFields;
+ pFieldType->GatherFields(vFields, false);
+ for(auto pFormatField: vFields)
+ {
+ SwTextField *const pTextField(pFormatField->GetTextField());
+ if (pTextField && nSeqNo ==
+ static_cast<SwSetExpField*>(pFormatField->GetField())->GetSeqNumber()
+ && (!pLayout || !pLayout->IsHideRedlines()
+ || !sw::IsFieldDeletedInModel(rIDRA, *pTextField)))
+ {
+ pTextNd = pTextField->GetpTextNode();
+ *pStt = pTextField->GetStart();
+ if( pEnd )
+ *pEnd = (*pStt) + 1;
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case REF_BOOKMARK:
+ {
+ IDocumentMarkAccess::const_iterator_t ppMark = pDoc->getIDocumentMarkAccess()->findMark(rRefMark);
+ if (ppMark != pDoc->getIDocumentMarkAccess()->getAllMarksEnd()
+ && (!pLayout || !pLayout->IsHideRedlines()
+ || !sw::IsMarkHidden(*pLayout, **ppMark)))
+ {
+ const ::sw::mark::IMark* pBkmk = *ppMark;
+ const SwPosition* pPos = &pBkmk->GetMarkStart();
+
+ pTextNd = pPos->GetNode().GetTextNode();
+ *pStt = pPos->GetContentIndex();
+ if(pEnd)
+ {
+ if(!pBkmk->IsExpanded())
+ {
+ *pEnd = *pStt;
+ // #i81002#
+ if(dynamic_cast< ::sw::mark::CrossRefBookmark const *>(pBkmk))
+ {
+ OSL_ENSURE( pTextNd,
+ "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash" );
+ *pEnd = pTextNd->Len();
+ }
+ }
+ else if(pBkmk->GetOtherMarkPos().GetNode() == pBkmk->GetMarkPos().GetNode())
+ *pEnd = pBkmk->GetMarkEnd().GetContentIndex();
+ else
+ *pEnd = -1;
+ }
+ }
+ }
+ break;
+
+ case REF_OUTLINE:
+ break;
+
+ case REF_FOOTNOTE:
+ case REF_ENDNOTE:
+ {
+ for( auto pFootnoteIdx : pDoc->GetFootnoteIdxs() )
+ if( nSeqNo == pFootnoteIdx->GetSeqRefNo() )
+ {
+ if (pLayout && pLayout->IsHideRedlines()
+ && sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
+ {
+ return nullptr;
+ }
+ // otherwise: the position at the start of the footnote
+ // will be mapped to something visible at least...
+ const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
+ if( pIdx )
+ {
+ SwNodeIndex aIdx( *pIdx, 1 );
+ pTextNd = aIdx.GetNode().GetTextNode();
+ if( nullptr == pTextNd )
+ pTextNd = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext( &aIdx ));
+ }
+ *pStt = 0;
+ if( pEnd )
+ *pEnd = 0;
+ break;
+ }
+ }
+ break;
+ case REF_STYLE:
+ if (!pSelf) break;
+
+ const SwNodes& nodes = pDoc->GetNodes();
+
+ StyleRefElementType elementType = StyleRefElementType::Default;
+ const SwTextNode* pReference = nullptr;
+
+ { /* Check if we're a footnote/endnote */
+ for (SwTextFootnote* pFootnoteIdx : pDoc->GetFootnoteIdxs())
+ {
+ if (pLayout && pLayout->IsHideRedlines()
+ && sw::IsFootnoteDeleted(rIDRA, *pFootnoteIdx))
+ {
+ continue;
+ }
+ const SwNodeIndex* pIdx = pFootnoteIdx->GetStartNode();
+ if (pIdx)
+ {
+ SwNodeIndex aIdx(*pIdx, 1);
+ SwTextNode* pFootnoteNode = aIdx.GetNode().GetTextNode();
+ if (nullptr == pFootnoteNode)
+ pFootnoteNode
+ = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
+
+ if (*pSelf == *pFootnoteNode)
+ {
+ elementType = StyleRefElementType::Reference;
+ pReference = &pFootnoteIdx->GetTextNode();
+ }
+ }
+ }
+ }
+
+ if (pDoc->IsInHeaderFooter(*pSelf))
+ {
+ elementType = StyleRefElementType::Marginal;
+ }
+
+ if (pReference == nullptr)
+ {
+ pReference = pSelf;
+ }
+
+ switch (elementType)
+ {
+ case Marginal:
+ {
+ // For marginals, styleref tries to act on the current page first
+ // 1. Get the page we're on, search it from top to bottom
+
+ bool bFlagFromBottom = (nFlags & REFFLDFLAG_STYLE_FROM_BOTTOM) == REFFLDFLAG_STYLE_FROM_BOTTOM;
+
+ Point aPt;
+ std::pair<Point, bool> const tmp(aPt, false);
+
+ if (!pContentFrame) SAL_WARN("xmloff.text", "<SwGetRefFieldType::FindAnchor(..)>: Missing content frame for marginal styleref");
+ const SwPageFrame* pPageFrame = nullptr;
+
+ if (pContentFrame)
+ pPageFrame = pContentFrame->FindPageFrame();
+
+ const SwNode* pPageStart(nullptr);
+ const SwNode* pPageEnd(nullptr);
+
+ if (pPageFrame)
+ {
+ const SwContentFrame* pPageStartFrame = pPageFrame->FindFirstBodyContent();
+ const SwContentFrame* pPageEndFrame = pPageFrame->FindLastBodyContent();
+
+ if (pPageStartFrame) {
+ if (pPageStartFrame->IsTextFrame())
+ {
+ pPageStart = static_cast<const SwTextFrame*>(pPageStartFrame)
+ ->GetTextNodeFirst();
+ }
+ else
+ {
+ pPageStart
+ = static_cast<const SwNoTextFrame*>(pPageStartFrame)->GetNode();
+ }
+ }
+
+ if (pPageEndFrame) {
+ if (pPageEndFrame->IsTextFrame())
+ {
+ pPageEnd = static_cast<const SwTextFrame*>(pPageEndFrame)
+ ->GetTextNodeFirst();
+ }
+ else
+ {
+ pPageEnd = static_cast<const SwNoTextFrame*>(pPageEndFrame)->GetNode();
+ }
+ }
+ }
+
+ if (!pPageStart || !pPageEnd)
+ {
+ pPageStart = pReference;
+ pPageEnd = pReference;
+ }
+
+ std::deque<SwNode*> pSearchSecond;
+ std::deque<SwNode*> pInPage; /* or pSearchFirst */
+ std::deque<SwNode*> pSearchThird;
+
+ bool beforeStart = true;
+ bool beforeEnd = true;
+
+ for (SwNodeOffset n(0); n < nodes.Count(); n++)
+ {
+ if (beforeStart && *pPageStart == *nodes[n])
+ {
+ beforeStart = false;
+ }
+
+ if (beforeStart)
+ {
+ pSearchSecond.push_front(nodes[n]);
+ }
+ else if (beforeEnd)
+ {
+ if (bFlagFromBottom)
+ pInPage.push_front(nodes[n]);
+ else
+ pInPage.push_back(nodes[n]);
+
+ if (*pPageEnd == *nodes[n])
+ {
+ beforeEnd = false;
+ }
+ }
+ else
+ pSearchThird.push_back(nodes[n]);
+ }
+
+ pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ // 2. Search up from the top of the page
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchSecond, rRefMark);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ // 3. Search down from the bottom of the page
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchThird, rRefMark);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ // Word has case insensitive styles. LO has case sensitive styles. If we didn't find
+ // it yet, maybe we could with a case insensitive search. Let's do that
+
+ pTextNd = SearchForStyleAnchor(pSelf, pInPage, rRefMark,
+ false /* bCaseSensitive */);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchSecond, rRefMark,
+ false /* bCaseSensitive */);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchThird, rRefMark,
+ false /* bCaseSensitive */);
+ break;
+ }
+ case Reference:
+ case Default:
+ {
+ // Normally, styleref does searches around the field position
+ // For references, styleref acts from the position of the reference not the field
+ // Happily, the previous code saves either one into pReference, so the following is generic for both
+
+ std::deque<SwNode*> pSearchFirst;
+ std::deque<SwNode*> pSearchSecond;
+
+ bool beforeElement = true;
+
+ for (SwNodeOffset n(0); n < nodes.Count(); n++)
+ {
+ if (beforeElement)
+ {
+ pSearchFirst.push_front(nodes[n]);
+
+ if (*pReference == *nodes[n])
+ {
+ beforeElement = false;
+ }
+ }
+ pSearchSecond.push_back(nodes[n]);
+ }
+
+ // 1. Search up until we hit the top of the document
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchFirst, rRefMark);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ // 2. Search down until we hit the bottom of the document
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchSecond, rRefMark);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ // Again, we need to remember that Word styles are not case sensitive
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchFirst, rRefMark,
+ false /* bCaseSensitive */);
+ if (pTextNd)
+ {
+ break;
+ }
+
+ pTextNd = SearchForStyleAnchor(pSelf, pSearchSecond, rRefMark,
+ false /* bCaseSensitive */);
+ break;
+ }
+ default:
+ OSL_FAIL("<SwGetRefFieldType::FindAnchor(..)> - unknown getref element type");
+ }
+
+ if (pTextNd)
+ {
+ *pStt = 0;
+ if (pEnd)
+ *pEnd = pTextNd->GetText().getLength();
+ }
+
+ break;
+ }
+
+ return pTextNd;
+}
+
+namespace {
+
+struct RefIdsMap
+{
+private:
+ OUString aName;
+ std::set<sal_uInt16> aIds;
+ std::set<sal_uInt16> aDstIds;
+ std::map<sal_uInt16, sal_uInt16> sequencedIds; /// ID numbers sorted by sequence number.
+ bool bInit;
+
+ void Init(SwDoc& rDoc, SwDoc& rDestDoc, bool bField );
+ static void GetNoteIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds );
+ void GetFieldIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds );
+ void AddId( sal_uInt16 id, sal_uInt16 seqNum );
+ static sal_uInt16 GetFirstUnusedId( std::set<sal_uInt16> &rIds );
+
+public:
+ explicit RefIdsMap( OUString _aName ) : aName(std::move( _aName )), bInit( false ) {}
+
+ void Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rField, bool bField );
+
+ const OUString& GetName() const { return aName; }
+};
+
+}
+
+/// Get a sorted list of the field IDs from a document.
+/// @param[in] rDoc The document to search.
+/// @param[in,out] rIds The list of IDs found in the document.
+void RefIdsMap::GetFieldIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds)
+{
+ SwFieldType *const pType = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp, aName, false);
+ if (!pType)
+ return;
+ std::vector<SwFormatField*> vFields;
+ pType->GatherFields(vFields);
+ for(const auto pF: vFields)
+ rIds.insert(static_cast<SwSetExpField const*>(pF->GetField())->GetSeqNumber());
+}
+
+/// Get a sorted list of the footnote/endnote IDs from a document.
+/// @param[in] rDoc The document to search.
+/// @param[in,out] rIds The list of IDs found in the document.
+void RefIdsMap::GetNoteIdsFromDoc( SwDoc& rDoc, std::set<sal_uInt16> &rIds)
+{
+ for( auto n = rDoc.GetFootnoteIdxs().size(); n; )
+ rIds.insert( rDoc.GetFootnoteIdxs()[ --n ]->GetSeqRefNo() );
+}
+
+/// Initialise the aIds and aDestIds collections from the source documents.
+/// @param[in] rDoc The source document.
+/// @param[in] rDestDoc The destination document.
+/// @param[in] bField True if we're interested in all fields, false for footnotes.
+void RefIdsMap::Init( SwDoc& rDoc, SwDoc& rDestDoc, bool bField )
+{
+ if( bInit )
+ return;
+
+ if( bField )
+ {
+ GetFieldIdsFromDoc( rDestDoc, aIds );
+ GetFieldIdsFromDoc( rDoc, aDstIds );
+
+ // Map all the new src fields to the next available unused id
+ for (const auto& rId : aDstIds)
+ AddId( GetFirstUnusedId(aIds), rId );
+
+ // Change the Sequence number of all SetExp fields in the source document
+ SwFieldType* pType = rDoc.getIDocumentFieldsAccess().GetFieldType( SwFieldIds::SetExp, aName, false );
+ if(pType)
+ {
+ std::vector<SwFormatField*> vFields;
+ pType->GatherFields(vFields, false);
+ for(auto pF: vFields)
+ {
+ if(!pF->GetTextField())
+ continue;
+ SwSetExpField *const pSetExp(static_cast<SwSetExpField *>(pF->GetField()));
+ sal_uInt16 const n = pSetExp->GetSeqNumber();
+ pSetExp->SetSeqNumber(sequencedIds[n]);
+ }
+ }
+ }
+ else
+ {
+ GetNoteIdsFromDoc( rDestDoc, aIds );
+ GetNoteIdsFromDoc( rDoc, aDstIds );
+
+ for (const auto& rId : aDstIds)
+ AddId( GetFirstUnusedId(aIds), rId );
+
+ // Change the footnotes/endnotes in the source doc to the new ID
+ for ( const auto pFootnoteIdx : rDoc.GetFootnoteIdxs() )
+ {
+ sal_uInt16 const n = pFootnoteIdx->GetSeqRefNo();
+ pFootnoteIdx->SetSeqNo(sequencedIds[n]);
+ }
+ }
+ bInit = true;
+}
+
+/// Get the lowest number unused in the passed set.
+/// @param[in] rIds The set of used ID numbers.
+/// @returns The lowest number unused by the passed set
+sal_uInt16 RefIdsMap::GetFirstUnusedId( std::set<sal_uInt16> &rIds )
+{
+ sal_uInt16 num(0);
+
+ for( const auto& rId : rIds )
+ {
+ if( num != rId )
+ {
+ return num;
+ }
+ ++num;
+ }
+ return num;
+}
+
+/// Add a new ID and sequence number to the "occupied" collection.
+/// @param[in] id The ID number.
+/// @param[in] seqNum The sequence number.
+void RefIdsMap::AddId( sal_uInt16 id, sal_uInt16 seqNum )
+{
+ aIds.insert( id );
+ sequencedIds[ seqNum ] = id;
+}
+
+void RefIdsMap::Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rField,
+ bool bField )
+{
+ Init( rDoc, rDestDoc, bField);
+
+ sal_uInt16 const nSeqNo = rField.GetSeqNo();
+
+ // check if it needs to be remapped
+ // if sequencedIds doesn't contain the number, it means there is no
+ // SetExp field / footnote in the source document: do not modify
+ // the number, which works well for copy from/paste to same document
+ // (and if it is not the same document, there's no "correct" result anyway)
+ if (sequencedIds.count(nSeqNo))
+ {
+ rField.SetSeqNo( sequencedIds[nSeqNo] );
+ }
+}
+
+/// 1. if _both_ SetExp + GetExp / Footnote + GetExp field are copied,
+/// ensure that both get a new unused matching number
+/// 2. if only SetExp / Footnote is copied, it gets a new unused number
+/// 3. if only GetExp field is copied, for the case of copy from / paste to
+/// same document it's desirable to keep the same number;
+/// for other cases of copy/paste or master documents it's not obvious
+/// what is most desirable since it's going to be wrong anyway
+void SwGetRefFieldType::MergeWithOtherDoc( SwDoc& rDestDoc )
+{
+ if (&rDestDoc == &m_rDoc)
+ return;
+
+ if (rDestDoc.IsClipBoard())
+ {
+ // when copying _to_ clipboard, expectation is that no fields exist
+ // so no re-mapping is required to avoid collisions
+ assert(!rDestDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::GetRef)->HasWriterListeners());
+ return; // don't modify the fields in the source doc
+ }
+
+ // then there are RefFields in the DescDox - so all RefFields in the SourceDoc
+ // need to be converted to have unique IDs for both documents
+ RefIdsMap aFntMap { OUString() };
+ std::vector<std::unique_ptr<RefIdsMap>> aFieldMap;
+
+ std::vector<SwFormatField*> vFields;
+ GatherFields(vFields);
+ for(auto pField: vFields)
+ {
+ SwGetRefField& rRefField = *static_cast<SwGetRefField*>(pField->GetField());
+ switch( rRefField.GetSubType() )
+ {
+ case REF_SEQUENCEFLD:
+ {
+ RefIdsMap* pMap = nullptr;
+ for( auto n = aFieldMap.size(); n; )
+ {
+ if (aFieldMap[ --n ]->GetName() == rRefField.GetSetRefName())
+ {
+ pMap = aFieldMap[ n ].get();
+ break;
+ }
+ }
+ if( !pMap )
+ {
+ pMap = new RefIdsMap( rRefField.GetSetRefName() );
+ aFieldMap.push_back(std::unique_ptr<RefIdsMap>(pMap));
+ }
+
+ pMap->Check(m_rDoc, rDestDoc, rRefField, true);
+ }
+ break;
+
+ case REF_FOOTNOTE:
+ case REF_ENDNOTE:
+ aFntMap.Check(m_rDoc, rDestDoc, rRefField, false);
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/scrptfld.cxx b/sw/source/core/fields/scrptfld.cxx
new file mode 100644
index 0000000000..302845281d
--- /dev/null
+++ b/sw/source/core/fields/scrptfld.cxx
@@ -0,0 +1,120 @@
+/* -*- 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 <docufld.hxx>
+#include <unofldmid.h>
+#include <strings.hrc>
+#include <o3tl/any.hxx>
+#include <swtypes.hxx>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+SwScriptFieldType::SwScriptFieldType( SwDoc& rD )
+ : SwFieldType( SwFieldIds::Script ), m_rDoc( rD )
+{}
+
+std::unique_ptr<SwFieldType> SwScriptFieldType::Copy() const
+{
+ return std::make_unique<SwScriptFieldType>( m_rDoc );
+}
+
+SwScriptField::SwScriptField( SwScriptFieldType* pInitType,
+ OUString aType, OUString aCode,
+ bool bURL )
+ : SwField( pInitType ), m_sType( std::move(aType) ), m_sCode( std::move(aCode) ), m_bCodeURL( bURL )
+{
+}
+
+OUString SwScriptField::GetDescription() const
+{
+ return SwResId(STR_SCRIPT);
+}
+
+OUString SwScriptField::ExpandImpl(SwRootFrame const*const) const
+{
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwScriptField::Copy() const
+{
+ return std::make_unique<SwScriptField>( static_cast<SwScriptFieldType*>(GetTyp()), m_sType, m_sCode, m_bCodeURL );
+}
+
+/// set type
+void SwScriptField::SetPar1( const OUString& rStr )
+{
+ m_sType = rStr;
+}
+
+OUString SwScriptField::GetPar1() const
+{
+ return m_sType;
+}
+
+/// set code
+void SwScriptField::SetPar2( const OUString& rStr )
+{
+ m_sCode = rStr;
+}
+
+OUString SwScriptField::GetPar2() const
+{
+ return m_sCode;
+}
+
+bool SwScriptField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sType;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_sCode;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= m_bCodeURL;
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+bool SwScriptField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_PAR1:
+ rAny >>= m_sType;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_sCode;
+ break;
+ case FIELD_PROP_BOOL1:
+ m_bCodeURL = *o3tl::doAccess<bool>(rAny);
+ break;
+ default:
+ assert(false);
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/tblcalc.cxx b/sw/source/core/fields/tblcalc.cxx
new file mode 100644
index 0000000000..d9c78be88e
--- /dev/null
+++ b/sw/source/core/fields/tblcalc.cxx
@@ -0,0 +1,211 @@
+/* -*- 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 <sal/config.h>
+
+#include <o3tl/any.hxx>
+
+#include <calc.hxx>
+#include <doc.hxx>
+#include <ndtxt.hxx>
+#include <fmtfld.hxx>
+#include <txtfld.hxx>
+#include <expfld.hxx>
+#include <unofldmid.h>
+
+using namespace ::com::sun::star;
+
+SwTableFieldType::SwTableFieldType(SwDoc* pDocPtr)
+ : SwValueFieldType( pDocPtr, SwFieldIds::Table )
+{}
+
+std::unique_ptr<SwFieldType> SwTableFieldType::Copy() const
+{
+ return std::make_unique<SwTableFieldType>(GetDoc());
+}
+
+void SwTableField::CalcField( SwTableCalcPara& rCalcPara )
+{
+ if( rCalcPara.m_rCalc.IsCalcError() ) // stop if there is already an error set
+ return;
+
+ // create pointers from box name
+ BoxNmToPtr( rCalcPara.m_pTable );
+ OUString sFormula( MakeFormula( rCalcPara ));
+ SetValue( rCalcPara.m_rCalc.Calculate( sFormula ).GetDouble() );
+ ChgValid( !rCalcPara.IsStackOverflow() ); // is the value again valid?
+}
+
+SwTableField::SwTableField( SwTableFieldType* pInitType, const OUString& rFormel,
+ sal_uInt16 nType, sal_uLong nFormat )
+ : SwValueField( pInitType, nFormat ), SwTableFormula( rFormel ),
+ m_nSubType(nType)
+{
+ m_sExpand = "0";
+}
+
+std::unique_ptr<SwField> SwTableField::Copy() const
+{
+ std::unique_ptr<SwTableField> pTmp(new SwTableField( static_cast<SwTableFieldType*>(GetTyp()),
+ SwTableFormula::GetFormula(), m_nSubType, GetFormat() ));
+ pTmp->m_sExpand = m_sExpand;
+ pTmp->SwValueField::SetValue(GetValue());
+ pTmp->SwTableFormula::operator=( *this );
+ pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
+ return std::unique_ptr<SwField>(pTmp.release());
+}
+
+OUString SwTableField::GetFieldName() const
+{
+ return GetTyp()->GetName() + " " + const_cast<SwTableField *>(this)->GetCommand();
+}
+
+/// search TextNode containing this field
+const SwNode* SwTableField::GetNodeOfFormula() const
+{
+ auto pFormat = GetTyp()->FindFormatForField(this);
+ return pFormat ? &pFormat->GetTextField()->GetTextNode() : nullptr;
+}
+
+OUString SwTableField::GetCommand()
+{
+ if (EXTRNL_NAME != GetNameType())
+ {
+ SwNode const*const pNd = GetNodeOfFormula();
+ SwTableNode const*const pTableNd = pNd ? pNd->FindTableNode() : nullptr;
+ if (pTableNd)
+ {
+ PtrToBoxNm( &pTableNd->GetTable() );
+ }
+ }
+ return (EXTRNL_NAME == GetNameType())
+ ? SwTableFormula::GetFormula()
+ : OUString();
+}
+
+OUString SwTableField::ExpandImpl(SwRootFrame const*const) const
+{
+ if (m_nSubType & nsSwExtendedSubType::SUB_CMD)
+ {
+ return const_cast<SwTableField *>(this)->GetCommand();
+ }
+
+ if(m_nSubType & nsSwGetSetExpType::GSE_STRING)
+ {
+ // it is a string
+ return m_sExpand.copy(1, m_sExpand.getLength()-2);
+ }
+
+ return m_sExpand;
+}
+
+sal_uInt16 SwTableField::GetSubType() const
+{
+ return m_nSubType;
+}
+
+void SwTableField::SetSubType(sal_uInt16 nType)
+{
+ m_nSubType = nType;
+}
+
+void SwTableField::SetValue( const double& rVal )
+{
+ SwValueField::SetValue(rVal);
+ m_sExpand = static_cast<SwValueFieldType*>(GetTyp())->ExpandValue(rVal, GetFormat(), GetLanguage());
+}
+
+OUString SwTableField::GetPar2() const
+{
+ return SwTableFormula::GetFormula();
+}
+
+void SwTableField::SetPar2(const OUString& rStr)
+{
+ SetFormula( rStr );
+}
+
+bool SwTableField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ bool bRet = true;
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_PAR2:
+ {
+ sal_uInt16 nOldSubType = m_nSubType;
+ SwTableField* pThis = const_cast<SwTableField*>(this);
+ pThis->m_nSubType |= nsSwExtendedSubType::SUB_CMD;
+ rAny <<= ExpandImpl(nullptr);
+ pThis->m_nSubType = nOldSubType;
+ }
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= 0 != (nsSwExtendedSubType::SUB_CMD & m_nSubType);
+ break;
+ case FIELD_PROP_PAR1:
+ rAny <<= m_sExpand;
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+bool SwTableField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ bool bRet = true;
+ switch ( nWhichId )
+ {
+ case FIELD_PROP_PAR2:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ SetFormula( sTmp );
+ }
+ break;
+ case FIELD_PROP_BOOL1:
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType = nsSwGetSetExpType::GSE_FORMULA|nsSwExtendedSubType::SUB_CMD;
+ else
+ m_nSubType = nsSwGetSetExpType::GSE_FORMULA;
+ break;
+ case FIELD_PROP_PAR1:
+ {
+ OUString sTmp;
+ rAny >>= sTmp;
+ ChgExpStr( sTmp );
+ }
+ break;
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int32 nTmp = 0;
+ rAny >>= nTmp;
+ SetFormat(nTmp);
+ }
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/textapi.cxx b/sw/source/core/fields/textapi.cxx
new file mode 100644
index 0000000000..ccbf299b1e
--- /dev/null
+++ b/sw/source/core/fields/textapi.cxx
@@ -0,0 +1,215 @@
+/* -*- 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 <textapi.hxx>
+#include <doc.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <docsh.hxx>
+#include <docstyle.hxx>
+#include <strings.hrc>
+#include <SwStyleNameMapper.hxx>
+#include <unoprnms.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unoforou.hxx>
+#include <editeng/unoipset.hxx>
+
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+
+using namespace com::sun::star;
+
+static const SvxItemPropertySet* ImplGetSvxTextPortionPropertySet()
+{
+ static const SfxItemPropertyMapEntry aSvxTextPortionPropertyMap[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_OUTLINER_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ {UNO_NAME_PARA_STYLE_NAME, WID_PARASTYLENAME,
+ cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ {u"TextField"_ustr, EE_FEATURE_FIELD,
+ cppu::UnoType<text::XTextField>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {u"TextPortionType"_ustr, WID_PORTIONTYPE,
+ ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {u"TextUserDefinedAttributes"_ustr, EE_CHAR_XMLATTRIBS,
+ cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ {u"ParaUserDefinedAttributes"_ustr, EE_PARA_XMLATTRIBS,
+ cppu::UnoType<css::container::XNameContainer>::get(), 0, 0},
+ };
+ static SvxItemPropertySet aSvxTextPortionPropertySet( aSvxTextPortionPropertyMap, EditEngine::GetGlobalItemPool() );
+ return &aSvxTextPortionPropertySet;
+}
+
+SwTextAPIObject::SwTextAPIObject( std::unique_ptr<SwTextAPIEditSource> p )
+: SvxUnoText( p.get(), ImplGetSvxTextPortionPropertySet(), uno::Reference < text::XText >() )
+, m_pSource(std::move(p))
+{
+}
+
+SwTextAPIObject::~SwTextAPIObject() noexcept
+{
+ m_pSource->Dispose();
+ m_pSource.reset();
+}
+
+struct SwTextAPIEditSource_Impl
+{
+ // needed for "internal" refcounting
+ SfxItemPool* mpPool;
+ SwDoc* mpDoc;
+ std::unique_ptr<Outliner> mpOutliner;
+ std::unique_ptr<SvxOutlinerForwarder> mpTextForwarder;
+ sal_Int32 mnRef;
+};
+
+namespace {
+
+class SwTextAPIForwarder : public SvxOutlinerForwarder
+{
+public:
+ using SvxOutlinerForwarder::SvxOutlinerForwarder;
+ OUString GetStyleSheet(sal_Int32 nPara) const override
+ {
+ return SwStyleNameMapper::GetProgName(SvxOutlinerForwarder::GetStyleSheet(nPara), SwGetPoolIdFromName::TxtColl);
+ }
+
+ void SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) override
+ {
+ SvxOutlinerForwarder::SetStyleSheet(nPara, SwStyleNameMapper::GetUIName(rStyleName, SwGetPoolIdFromName::TxtColl));
+ }
+};
+
+}
+
+SwTextAPIEditSource::SwTextAPIEditSource( const SwTextAPIEditSource& rSource )
+: SvxEditSource( *this )
+{
+ // shallow copy; uses internal refcounting
+ m_pImpl = rSource.m_pImpl;
+ m_pImpl->mnRef++;
+}
+
+std::unique_ptr<SvxEditSource> SwTextAPIEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new SwTextAPIEditSource( *this ));
+}
+
+void SwTextAPIEditSource::UpdateData()
+{
+ // data is kept in outliner all the time
+}
+
+SwTextAPIEditSource::SwTextAPIEditSource(SwDoc* pDoc)
+: m_pImpl(new SwTextAPIEditSource_Impl)
+{
+ m_pImpl->mpPool = &pDoc->GetDocShell()->GetPool();
+ m_pImpl->mpDoc = pDoc;
+ m_pImpl->mnRef = 1;
+}
+
+SwTextAPIEditSource::~SwTextAPIEditSource()
+{
+ if (!--m_pImpl->mnRef)
+ delete m_pImpl;
+}
+
+void SwTextAPIEditSource::Dispose()
+{
+ m_pImpl->mpPool=nullptr;
+ m_pImpl->mpDoc=nullptr;
+ m_pImpl->mpTextForwarder.reset();
+ m_pImpl->mpOutliner.reset();
+}
+
+void SwTextAPIEditSource::EnsureOutliner()
+{
+ if( !m_pImpl->mpOutliner )
+ {
+ //init draw model first
+ m_pImpl->mpDoc->getIDocumentDrawModelAccess().GetOrCreateDrawModel();
+ m_pImpl->mpOutliner.reset(new Outliner(m_pImpl->mpPool, OutlinerMode::TextObject));
+ m_pImpl->mpOutliner->SetStyleSheetPool(
+ static_cast<SwDocStyleSheetPool*>(m_pImpl->mpDoc->GetDocShell()->GetStyleSheetPool())->GetEEStyleSheetPool());
+ m_pImpl->mpDoc->SetCalcFieldValueHdl(m_pImpl->mpOutliner.get());
+ }
+}
+
+SvxTextForwarder* SwTextAPIEditSource::GetTextForwarder()
+{
+ if( !m_pImpl->mpPool )
+ return nullptr; // mpPool == 0 can be used to flag this as disposed
+
+ EnsureOutliner();
+
+ if( !m_pImpl->mpTextForwarder )
+ {
+ m_pImpl->mpTextForwarder.reset(new SwTextAPIForwarder(*m_pImpl->mpOutliner, false));
+ }
+
+ return m_pImpl->mpTextForwarder.get();
+}
+
+void SwTextAPIEditSource::SetText( OutlinerParaObject const & rText )
+{
+ if ( m_pImpl->mpPool )
+ {
+ EnsureOutliner();
+ m_pImpl->mpOutliner->SetText( rText );
+ }
+}
+
+void SwTextAPIEditSource::SetString( const OUString& rText )
+{
+ if ( !m_pImpl->mpPool )
+ return;
+
+ if ( m_pImpl->mpOutliner )
+ m_pImpl->mpOutliner->Clear();
+
+ EnsureOutliner();
+
+ if (auto pStyle = m_pImpl->mpOutliner->GetStyleSheetPool()->Find(SwResId(STR_POOLCOLL_COMMENT), SfxStyleFamily::Para))
+ m_pImpl->mpOutliner->SetStyleSheet(0, static_cast<SfxStyleSheet*>(pStyle));
+ m_pImpl->mpOutliner->Insert( rText );
+}
+
+std::optional<OutlinerParaObject> SwTextAPIEditSource::CreateText()
+{
+ if ( m_pImpl->mpPool && m_pImpl->mpOutliner )
+ return m_pImpl->mpOutliner->CreateParaObject();
+ else
+ return std::nullopt;
+}
+
+OUString SwTextAPIEditSource::GetText() const
+{
+ if ( m_pImpl->mpPool && m_pImpl->mpOutliner )
+ return m_pImpl->mpOutliner->GetEditEngine().GetText();
+ else
+ return OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/usrfld.cxx b/sw/source/core/fields/usrfld.cxx
new file mode 100644
index 0000000000..ebfe46fdb9
--- /dev/null
+++ b/sw/source/core/fields/usrfld.cxx
@@ -0,0 +1,397 @@
+/* -*- 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 <sal/config.h>
+
+#include <libxml/xmlwriter.h>
+
+#include <o3tl/any.hxx>
+
+#include <svl/numformat.hxx>
+#include <unotools/charclass.hxx>
+
+#include <calc.hxx>
+#include <usrfld.hxx>
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentState.hxx>
+#include <unofldmid.h>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/**
+ * Returns the language used for float <-> string conversions in
+ * SwUserFieldType.
+ */
+LanguageType GetFieldTypeLanguage()
+{
+ return LANGUAGE_SYSTEM;
+}
+}
+
+// Userfields
+
+SwUserField::SwUserField(SwUserFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 nFormat)
+ : SwValueField(pTyp, nFormat),
+ m_nSubType(nSub)
+{
+}
+
+OUString SwUserField::ExpandImpl(SwRootFrame const*const) const
+{
+ if(!(m_nSubType & nsSwExtendedSubType::SUB_INVISIBLE))
+ return static_cast<SwUserFieldType*>(GetTyp())->Expand(GetFormat(), m_nSubType, GetLanguage());
+
+ return OUString();
+}
+
+std::unique_ptr<SwField> SwUserField::Copy() const
+{
+ std::unique_ptr<SwField> pTmp(new SwUserField(static_cast<SwUserFieldType*>(GetTyp()), m_nSubType, GetFormat()));
+ pTmp->SetAutomaticLanguage(IsAutomaticLanguage());
+ pTmp->SetTitle(GetTitle());
+ return pTmp;
+}
+
+OUString SwUserField::GetFieldName() const
+{
+ return SwFieldType::GetTypeStr(SwFieldTypesEnum::User) +
+ " " + GetTyp()->GetName() + " = " +
+ static_cast<SwUserFieldType*>(GetTyp())->GetContent();
+}
+
+double SwUserField::GetValue() const
+{
+ return static_cast<SwUserFieldType*>(GetTyp())->GetValue();
+}
+
+void SwUserField::SetValue( const double& rVal )
+{
+ static_cast<SwUserFieldType*>(GetTyp())->SetValue(rVal);
+}
+
+/// Get name
+OUString SwUserField::GetPar1() const
+{
+ return static_cast<const SwUserFieldType*>(GetTyp())->GetName();
+}
+
+/// Get content
+OUString SwUserField::GetPar2() const
+{
+ return static_cast<SwUserFieldType*>(GetTyp())->GetContent(GetFormat());
+}
+
+void SwUserField::SetPar2(const OUString& rStr)
+{
+ static_cast<SwUserFieldType*>(GetTyp())->SetContent(rStr, GetFormat());
+}
+
+sal_uInt16 SwUserField::GetSubType() const
+{
+ return static_cast<SwUserFieldType*>(GetTyp())->GetType() | m_nSubType;
+}
+
+void SwUserField::SetSubType(sal_uInt16 nSub)
+{
+ static_cast<SwUserFieldType*>(GetTyp())->SetType(nSub & 0x00ff);
+ m_nSubType = nSub & 0xff00;
+}
+
+bool SwUserField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL2:
+ rAny <<= 0 != (m_nSubType & nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= 0 == (m_nSubType & nsSwExtendedSubType::SUB_INVISIBLE);
+ break;
+ case FIELD_PROP_FORMAT:
+ rAny <<= static_cast<sal_Int32>(GetFormat());
+ break;
+ default:
+ return SwField::QueryValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+bool SwUserField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_BOOL1:
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType &= (~nsSwExtendedSubType::SUB_INVISIBLE);
+ else
+ m_nSubType |= nsSwExtendedSubType::SUB_INVISIBLE;
+ break;
+ case FIELD_PROP_BOOL2:
+ if(*o3tl::doAccess<bool>(rAny))
+ m_nSubType |= nsSwExtendedSubType::SUB_CMD;
+ else
+ m_nSubType &= (~nsSwExtendedSubType::SUB_CMD);
+ break;
+ case FIELD_PROP_FORMAT:
+ {
+ sal_Int32 nTmp = 0;
+ rAny >>= nTmp;
+ SetFormat(nTmp);
+ }
+ break;
+ default:
+ return SwField::PutValue(rAny, nWhichId);
+ }
+ return true;
+}
+
+void SwUserField::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUserField"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nSubType"), BAD_CAST(OString::number(m_nSubType).getStr()));
+ SwValueField::dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SwUserFieldType::SwUserFieldType( SwDoc* pDocPtr, const OUString& aNam )
+ : SwValueFieldType( pDocPtr, SwFieldIds::User ),
+ m_nValue( 0 ),
+ m_nType(nsSwGetSetExpType::GSE_STRING)
+{
+ m_bValidValue = m_bDeleted = false;
+ m_aName = aNam;
+
+ EnableFormat(false); // Do not use a Numberformatter for nsSwGetSetExpType::GSE_STRING
+}
+
+OUString SwUserFieldType::Expand(sal_uInt32 nFormat, sal_uInt16 nSubType, LanguageType nLng)
+{
+ if((m_nType & nsSwGetSetExpType::GSE_EXPR) && !(nSubType & nsSwExtendedSubType::SUB_CMD))
+ {
+ EnableFormat();
+ return ExpandValue(m_nValue, nFormat, nLng);
+ }
+
+ EnableFormat(false); // Do not use a Numberformatter
+ return m_aContent;
+}
+
+std::unique_ptr<SwFieldType> SwUserFieldType::Copy() const
+{
+ std::unique_ptr<SwUserFieldType> pTmp(new SwUserFieldType( GetDoc(), m_aName ));
+ pTmp->m_aContent = m_aContent;
+ pTmp->m_aContentLang = m_aContentLang;
+ pTmp->m_nType = m_nType;
+ pTmp->m_bValidValue = m_bValidValue;
+ pTmp->m_nValue = m_nValue;
+ pTmp->m_bDeleted = m_bDeleted;
+
+ return pTmp;
+}
+
+OUString SwUserFieldType::GetName() const
+{
+ return m_aName;
+}
+
+void SwUserFieldType::SwClientNotify(const SwModify&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::SwLegacyModify)
+ {
+ auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
+ if (!pLegacy->m_pOld && !pLegacy->m_pNew)
+ m_bValidValue = false;
+ }
+
+ CallSwClientNotify(rHint);
+ // update input fields that might be connected to the user field
+ if (!IsModifyLocked())
+ {
+ LockModify();
+ GetDoc()->getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Input)->UpdateFields();
+ UnlockModify();
+ }
+}
+
+double SwUserFieldType::GetValue( SwCalc& rCalc )
+{
+ if(m_bValidValue)
+ return m_nValue;
+
+ if(!rCalc.Push( this ))
+ {
+ rCalc.SetCalcError( SwCalcError::Syntax );
+ return 0;
+ }
+
+ // See if we need to temporarily switch rCalc's language: in case it
+ // differs from the field type locale.
+ const CharClass* pCharClass = rCalc.GetCharClass();
+ LanguageTag aCharClassLanguage = pCharClass->getLanguageTag();
+ LanguageTag aContentLang(m_aContentLang);
+
+ // for the call of calculate we need the language that was used for putting/setting
+ // the m_aContent string, otherwise the aContent could be interpreted wrongly,
+
+ bool bSwitchLanguage = m_aContentLang != aCharClassLanguage.getBcp47();
+
+ if (bSwitchLanguage)
+ rCalc.SetCharClass(aContentLang);
+
+ m_nValue = rCalc.Calculate( m_aContent ).GetDouble();
+
+ // we than have to set the proper char class languageTag again
+
+ if (bSwitchLanguage)
+ rCalc.SetCharClass(aCharClassLanguage);
+
+ rCalc.Pop();
+
+ if( !rCalc.IsCalcError() )
+ m_bValidValue = true;
+ else
+ m_nValue = 0;
+
+ return m_nValue;
+}
+
+OUString SwUserFieldType::GetInputOrDateTime( sal_uInt32 nFormat ) const
+{
+ return static_cast<const SwValueFieldType*>(this)->GetInputOrDateTime( m_aContent, GetValue(), nFormat);
+}
+
+OUString SwUserFieldType::GetContent( sal_uInt32 nFormat ) const
+{
+ if (nFormat && nFormat != SAL_MAX_UINT32)
+ {
+ OUString sFormattedValue;
+ const Color* pCol = nullptr;
+
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+
+ pFormatter->GetOutputString(GetValue(), nFormat, sFormattedValue, &pCol);
+ return sFormattedValue;
+ }
+
+ return m_aContent;
+}
+
+void SwUserFieldType::SetContent( const OUString& rStr, sal_uInt32 nFormat )
+{
+ if( m_aContent == rStr )
+ return;
+
+ m_aContent = rStr;
+
+ if (nFormat && nFormat != SAL_MAX_UINT32)
+ {
+ double fValue;
+
+ if (GetDoc()->IsNumberFormat(rStr, nFormat, fValue))
+ {
+ SetValue(fValue);
+ LanguageTag aContentLanguage(GetFieldTypeLanguage());
+ m_aContentLang = aContentLanguage.getBcp47();
+ m_aContent = DoubleToString(fValue, aContentLanguage.getLanguageType());
+ }
+ }
+
+ bool bModified = GetDoc()->getIDocumentState().IsModified();
+ GetDoc()->getIDocumentState().SetModified();
+ if( !bModified ) // Bug 57028
+ {
+ GetDoc()->GetIDocumentUndoRedo().SetUndoNoResetModified();
+ }
+}
+
+void SwUserFieldType::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_DOUBLE:
+ rAny <<= m_nValue;
+ break;
+ case FIELD_PROP_PAR2:
+ rAny <<= m_aContent;
+ break;
+ case FIELD_PROP_BOOL1:
+ rAny <<= 0 != (nsSwGetSetExpType::GSE_EXPR&m_nType);
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwUserFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
+{
+ switch( nWhichId )
+ {
+ case FIELD_PROP_DOUBLE:
+ {
+ double fVal = 0;
+ rAny >>= fVal;
+ m_nValue = fVal;
+ LanguageTag aContentLanguage(GetFieldTypeLanguage());
+ m_aContentLang = aContentLanguage.getBcp47();
+ m_aContent = DoubleToString(m_nValue, aContentLanguage.getLanguageType());
+ }
+ break;
+ case FIELD_PROP_PAR2:
+ rAny >>= m_aContent;
+ break;
+ case FIELD_PROP_BOOL1:
+ if(*o3tl::doAccess<bool>(rAny))
+ {
+ m_nType |= nsSwGetSetExpType::GSE_EXPR;
+ m_nType &= ~nsSwGetSetExpType::GSE_STRING;
+ }
+ else
+ {
+ m_nType &= ~nsSwGetSetExpType::GSE_EXPR;
+ m_nType |= nsSwGetSetExpType::GSE_STRING;
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+void SwUserFieldType::EnsureValid()
+{
+ if(IsValid())
+ return;
+ SwCalc aCalc(*GetDoc());
+ GetValue(aCalc);
+}
+
+void SwUserFieldType::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUserFieldType"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nValue"), BAD_CAST(OString::number(m_nValue).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aContent"), BAD_CAST(m_aContent.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("aContentLang"), BAD_CAST(m_aContentLang.toUtf8().getStr()));
+ SwFieldType::dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */