1
0
Fork 0
libreoffice/sw/source/core/fields/expfld.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

1447 lines
42 KiB
C++

/* -*- 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 = SwNodes::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();
assert(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 && !pContentFrame->IsInFootnote() )
{
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( u"."_ustr ),
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( u" "_ustr );
}
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)
{
assert((nSub & 0xff) != (nsSwGetSetExpType::GSE_STRING|nsSwGetSetExpType::GSE_EXPR) && "SubType is illegal!");
static_cast<SwSetExpFieldType*>(GetTyp())->SetType(nSub & 0xff);
mnSubType = nSub & 0xff00;
}
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 (0 <= nTmp32 && nTmp32 != (GetSubType() & 0xff))
{
auto const subType(o3tl::narrowing<sal_uInt16>((GetSubType() & 0xff00) | nTmp32));
if (((nTmp32 & nsSwGetSetExpType::GSE_STRING) != (GetSubType() & nsSwGetSetExpType::GSE_STRING))
&& GetInputFlag())
{
SwXTextField::TransmuteLeadToInputField(*this, &subType);
}
else
{
SetSubType(subType);
}
}
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, nullptr);
}
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: */