diff options
Diffstat (limited to 'sw/source/core/doc/number.cxx')
-rw-r--r-- | sw/source/core/doc/number.cxx | 1589 |
1 files changed, 1589 insertions, 0 deletions
diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx new file mode 100644 index 000000000..4e353a2b2 --- /dev/null +++ b/sw/source/core/doc/number.cxx @@ -0,0 +1,1589 @@ +/* -*- 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 <memory> +#include <hintids.hxx> + +#include <vcl/font.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/numitem.hxx> +#include <svl/grabbagitem.hxx> +#include <fmtornt.hxx> +#include <doc.hxx> +#include <charfmt.hxx> +#include <ndtxt.hxx> +#include <docary.hxx> +#include <SwStyleNameMapper.hxx> + +// Needed to load default bullet list configuration +#include <unotools/configmgr.hxx> +#include <unotools/configitem.hxx> + +#include <numrule.hxx> +#include <SwNodeNum.hxx> + +#include <list.hxx> + +#include <algorithm> +#include <unordered_map> +#include <libxml/xmlwriter.h> + +#include <rtl/ustrbuf.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <unotools/saveopt.hxx> +#include <osl/diagnose.h> + +#include <IDocumentListsAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <IDocumentState.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <wrtsh.hxx> + +using namespace ::com::sun::star; + +sal_uInt16 SwNumRule::snRefCount = 0; +SwNumFormat* SwNumRule::saBaseFormats[ RULE_END ][ MAXLEVEL ] = { + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } }; + +SwNumFormat* SwNumRule::saLabelAlignmentBaseFormats[ RULE_END ][ MAXLEVEL ] = { + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } }; + +const sal_uInt16 SwNumRule::saDefNumIndents[ MAXLEVEL ] = { + o3tl::toTwips(25, o3tl::Length::in100), + o3tl::toTwips(50, o3tl::Length::in100), + o3tl::toTwips(75, o3tl::Length::in100), + o3tl::toTwips(100, o3tl::Length::in100), + o3tl::toTwips(125, o3tl::Length::in100), + o3tl::toTwips(150, o3tl::Length::in100), + o3tl::toTwips(175, o3tl::Length::in100), + o3tl::toTwips(200, o3tl::Length::in100), + o3tl::toTwips(225, o3tl::Length::in100), + o3tl::toTwips(250, o3tl::Length::in100), +}; + +OUString SwNumRule::GetOutlineRuleName() +{ + return "Outline"; +} + +const SwNumFormat& SwNumRule::Get( sal_uInt16 i ) const +{ + assert( i < MAXLEVEL && meRuleType < RULE_END ); + return maFormats[ i ] + ? *maFormats[ i ] + : ( meDefaultNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION + ? *saBaseFormats[ meRuleType ][ i ] + : *saLabelAlignmentBaseFormats[ meRuleType ][ i ] ); +} + +const SwNumFormat* SwNumRule::GetNumFormat( sal_uInt16 i ) const +{ + const SwNumFormat * pResult = nullptr; + + assert( i < MAXLEVEL && meRuleType < RULE_END ); + if ( i < MAXLEVEL && meRuleType < RULE_END) + { + pResult = maFormats[ i ].get(); + } + + return pResult; +} + +// #i91400# +void SwNumRule::SetName( const OUString & rName, + IDocumentListsAccess& rDocListAccess) +{ + if ( msName == rName ) + return; + + if (mpNumRuleMap) + { + mpNumRuleMap->erase(msName); + (*mpNumRuleMap)[rName] = this; + + if ( !GetDefaultListId().isEmpty() ) + { + rDocListAccess.trackChangeOfListStyleName( msName, rName ); + } + } + + msName = rName; +} + +void SwNumRule::GetTextNodeList( SwNumRule::tTextNodeList& rTextNodeList ) const +{ + rTextNodeList = maTextNodeList; +} + +SwNumRule::tTextNodeList::size_type SwNumRule::GetTextNodeListSize() const +{ + return maTextNodeList.size(); +} + +void SwNumRule::AddTextNode( SwTextNode& rTextNode ) +{ + tTextNodeList::iterator aIter = + std::find( maTextNodeList.begin(), maTextNodeList.end(), &rTextNode ); + + if ( aIter == maTextNodeList.end() ) + { + maTextNodeList.push_back( &rTextNode ); + } +} + +void SwNumRule::RemoveTextNode( SwTextNode& rTextNode ) +{ + tTextNodeList::iterator aIter = + std::find( maTextNodeList.begin(), maTextNodeList.end(), &rTextNode ); + + if ( aIter != maTextNodeList.end() ) + { + maTextNodeList.erase( aIter ); + } +} + +void SwNumRule::SetNumRuleMap(std::unordered_map<OUString, SwNumRule *> * + pNumRuleMap) +{ + mpNumRuleMap = pNumRuleMap; +} + +sal_uInt16 SwNumRule::GetNumIndent( sal_uInt8 nLvl ) +{ + OSL_ENSURE( MAXLEVEL > nLvl, "NumLevel is out of range" ); + return saDefNumIndents[ nLvl ]; +} + +sal_uInt16 SwNumRule::GetBullIndent( sal_uInt8 nLvl ) +{ + OSL_ENSURE( MAXLEVEL > nLvl, "NumLevel is out of range" ); + return saDefNumIndents[ nLvl ]; +} + +static void lcl_SetRuleChgd( SwTextNode& rNd, sal_uInt8 nLevel ) +{ + if( rNd.GetActualListLevel() == nLevel ) + rNd.NumRuleChgd(); +} + +SwNumFormat::SwNumFormat() : + SvxNumberFormat(SVX_NUM_ARABIC), + SwClient( nullptr ), + m_pVertOrient(new SwFormatVertOrient( 0, text::VertOrientation::NONE)) + ,m_cGrfBulletCP(USHRT_MAX)//For i120928,record the cp info of graphic within bullet +{ +} + +SwNumFormat::SwNumFormat( const SwNumFormat& rFormat) : + SvxNumberFormat(rFormat), + SwClient( rFormat.GetRegisteredInNonConst() ), + m_pVertOrient(new SwFormatVertOrient( 0, rFormat.GetVertOrient())) + ,m_cGrfBulletCP(rFormat.m_cGrfBulletCP)//For i120928,record the cp info of graphic within bullet +{ + sal_Int16 eMyVertOrient = rFormat.GetVertOrient(); + SetGraphicBrush( rFormat.GetBrush(), &rFormat.GetGraphicSize(), + &eMyVertOrient); +} + +SwNumFormat::SwNumFormat(const SvxNumberFormat& rNumFormat, SwDoc* pDoc) + : SvxNumberFormat(rNumFormat) + , m_pVertOrient(new SwFormatVertOrient( 0, rNumFormat.GetVertOrient())) + , m_cGrfBulletCP(USHRT_MAX) +{ + sal_Int16 eMyVertOrient = rNumFormat.GetVertOrient(); + SetGraphicBrush( rNumFormat.GetBrush(), &rNumFormat.GetGraphicSize(), + &eMyVertOrient); + const OUString rCharStyleName = rNumFormat.SvxNumberFormat::GetCharFormatName(); + if( !rCharStyleName.isEmpty() ) + { + SwCharFormat* pCFormat = pDoc->FindCharFormatByName( rCharStyleName ); + if( !pCFormat ) + { + sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCharStyleName, + SwGetPoolIdFromName::ChrFmt ); + pCFormat = nId != USHRT_MAX + ? pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( nId ) + : pDoc->MakeCharFormat( rCharStyleName, nullptr ); + } + pCFormat->Add( this ); + } + else + EndListeningAll(); +} + +SwNumFormat::~SwNumFormat() +{ +} + +// #i22362# +bool SwNumFormat::IsEnumeration() const +{ + // #i30655# native numbering did not work any longer + // using this code. Therefore HBRINKM and I agreed upon defining + // IsEnumeration() as !IsItemize() + return !IsItemize(); +} + +bool SwNumFormat::IsItemize() const +{ + bool bResult; + + switch(GetNumberingType()) + { + case SVX_NUM_CHAR_SPECIAL: + case SVX_NUM_BITMAP: + bResult = true; + + break; + + default: + bResult = false; + } + + return bResult; + +} + +SwNumFormat& SwNumFormat::operator=( const SwNumFormat& rNumFormat) +{ + SvxNumberFormat::operator=(rNumFormat); + StartListeningToSameModifyAs(rNumFormat); + //For i120928,record the cp info of graphic within bullet + m_cGrfBulletCP = rNumFormat.m_cGrfBulletCP; + return *this; +} + +bool SwNumFormat::operator==( const SwNumFormat& rNumFormat) const +{ + bool bRet = SvxNumberFormat::operator==(rNumFormat) && + GetRegisteredIn() == rNumFormat.GetRegisteredIn(); + return bRet; +} + +void SwNumFormat::SetCharFormat( SwCharFormat* pChFormat) +{ + if( pChFormat ) + pChFormat->Add( this ); + else + EndListeningAll(); +} + +void SwNumFormat::SwClientNotify(const SwModify&, const SfxHint& rHint) +{ + if (rHint.GetId() != SfxHintId::SwLegacyModify) + return; + auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint); + // Look for the NumRules object in the Doc where this NumFormat is set. + // The format does not need to exist! + const SwCharFormat* pFormat = nullptr; + switch(pLegacy->GetWhich()) + { + case RES_ATTRSET_CHG: + case RES_FMT_CHG: + pFormat = GetCharFormat(); + break; + } + + if(pFormat && !pFormat->GetDoc()->IsInDtor()) + UpdateNumNodes(*const_cast<SwDoc*>(pFormat->GetDoc())); + else + CheckRegistration(pLegacy->m_pOld); +} + +OUString SwNumFormat::GetCharFormatName() const +{ + if(static_cast<const SwCharFormat*>(GetRegisteredIn())) + return static_cast<const SwCharFormat*>(GetRegisteredIn())->GetName(); + + return OUString(); +} + +void SwNumFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem, const Size* pSize, + const sal_Int16* pOrient) +{ + if(pOrient) + m_pVertOrient->SetVertOrient( *pOrient ); + SvxNumberFormat::SetGraphicBrush( pBrushItem, pSize, pOrient); +} + +void SwNumFormat::UpdateNumNodes( SwDoc& rDoc ) +{ + bool bDocIsModified = rDoc.getIDocumentState().IsModified(); + bool bFnd = false; + for( SwNumRuleTable::size_type n = rDoc.GetNumRuleTable().size(); !bFnd && n; ) + { + const SwNumRule* pRule = rDoc.GetNumRuleTable()[ --n ]; + for( sal_uInt8 i = 0; i < MAXLEVEL; ++i ) + if( pRule->GetNumFormat( i ) == this ) + { + SwNumRule::tTextNodeList aTextNodeList; + pRule->GetTextNodeList( aTextNodeList ); + for ( auto& rpTextNode : aTextNodeList ) + { + lcl_SetRuleChgd( *rpTextNode, i ); + } + bFnd = true; + break; + } + } + + if( bFnd && !bDocIsModified ) + rDoc.getIDocumentState().ResetModified(); +} + +const SwFormatVertOrient* SwNumFormat::GetGraphicOrientation() const +{ + sal_Int16 eOrient = SvxNumberFormat::GetVertOrient(); + if(text::VertOrientation::NONE == eOrient) + return nullptr; + else + { + m_pVertOrient->SetVertOrient(eOrient); + return m_pVertOrient.get(); + } +} + +SwNumRule::SwNumRule( const OUString& rNm, + const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode, + SwNumRuleType eType ) + : mpNumRuleMap(nullptr), + msName( rNm ), + meRuleType( eType ), + mnPoolFormatId( USHRT_MAX ), + mnPoolHelpId( USHRT_MAX ), + mnPoolHlpFileId( UCHAR_MAX ), + mbAutoRuleFlag( true ), + mbInvalidRuleFlag( true ), + mbContinusNum( false ), + mbAbsSpaces( false ), + mbHidden( false ), + mbCountPhantoms( true ), + mbUsedByRedline( false ), + meDefaultNumberFormatPositionAndSpaceMode( eDefaultNumberFormatPositionAndSpaceMode ) +{ + if( !snRefCount++ ) // for the first time, initialize + { + SwNumFormat* pFormat; + sal_uInt8 n; + + // numbering: + // position-and-space mode LABEL_WIDTH_AND_POSITION: + for( n = 0; n < MAXLEVEL; ++n ) + { + pFormat = new SwNumFormat; + pFormat->SetIncludeUpperLevels( 1 ); + pFormat->SetStart( 1 ); + pFormat->SetAbsLSpace( lNumberIndent + SwNumRule::GetNumIndent( n ) ); + pFormat->SetFirstLineOffset( lNumberFirstLineOffset ); + pFormat->SetListFormat("%" + OUString::number(n + 1) + "%."); + pFormat->SetBulletChar(numfunc::GetBulletChar(n)); + SwNumRule::saBaseFormats[ NUM_RULE ][ n ] = pFormat; + } + // position-and-space mode LABEL_ALIGNMENT + // first line indent of general numbering in inch: -0,25 inch + const tools::Long cFirstLineIndent = o3tl::toTwips(-0.25, o3tl::Length::in); + // indent values of general numbering in inch: + const tools::Long cIndentAt[ MAXLEVEL ] = { + o3tl::toTwips(50, o3tl::Length::in100), + o3tl::toTwips(75, o3tl::Length::in100), + o3tl::toTwips(100, o3tl::Length::in100), + o3tl::toTwips(125, o3tl::Length::in100), + o3tl::toTwips(150, o3tl::Length::in100), + o3tl::toTwips(175, o3tl::Length::in100), + o3tl::toTwips(200, o3tl::Length::in100), + o3tl::toTwips(225, o3tl::Length::in100), + o3tl::toTwips(250, o3tl::Length::in100), + o3tl::toTwips(275, o3tl::Length::in100), + }; + for( n = 0; n < MAXLEVEL; ++n ) + { + pFormat = new SwNumFormat; + pFormat->SetIncludeUpperLevels( 1 ); + pFormat->SetStart( 1 ); + pFormat->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + pFormat->SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + pFormat->SetListtabPos( cIndentAt[ n ] ); + pFormat->SetFirstLineIndent( cFirstLineIndent ); + pFormat->SetIndentAt( cIndentAt[ n ] ); + pFormat->SetListFormat( "%" + OUString::number(n + 1) + "%."); + pFormat->SetBulletChar( numfunc::GetBulletChar(n)); + SwNumRule::saLabelAlignmentBaseFormats[ NUM_RULE ][ n ] = pFormat; + } + + // outline: + // position-and-space mode LABEL_WIDTH_AND_POSITION: + for( n = 0; n < MAXLEVEL; ++n ) + { + pFormat = new SwNumFormat; + pFormat->SetNumberingType(SVX_NUM_NUMBER_NONE); + pFormat->SetIncludeUpperLevels( MAXLEVEL ); + pFormat->SetStart( 1 ); + pFormat->SetCharTextDistance( lOutlineMinTextDistance ); + pFormat->SetBulletChar( numfunc::GetBulletChar(n)); + SwNumRule::saBaseFormats[ OUTLINE_RULE ][ n ] = pFormat; + } + // position-and-space mode LABEL_ALIGNMENT: + for( n = 0; n < MAXLEVEL; ++n ) + { + pFormat = new SwNumFormat; + pFormat->SetNumberingType(SVX_NUM_NUMBER_NONE); + pFormat->SetIncludeUpperLevels( MAXLEVEL ); + pFormat->SetStart( 1 ); + pFormat->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + pFormat->SetBulletChar( numfunc::GetBulletChar(n)); + SwNumRule::saLabelAlignmentBaseFormats[ OUTLINE_RULE ][ n ] = pFormat; + } + } + OSL_ENSURE( !msName.isEmpty(), "NumRule without a name!" ); +} + +SwNumRule::SwNumRule( const SwNumRule& rNumRule ) + : mpNumRuleMap(nullptr), + msName( rNumRule.msName ), + meRuleType( rNumRule.meRuleType ), + mnPoolFormatId( rNumRule.GetPoolFormatId() ), + mnPoolHelpId( rNumRule.GetPoolHelpId() ), + mnPoolHlpFileId( rNumRule.GetPoolHlpFileId() ), + mbAutoRuleFlag( rNumRule.mbAutoRuleFlag ), + mbInvalidRuleFlag( true ), + mbContinusNum( rNumRule.mbContinusNum ), + mbAbsSpaces( rNumRule.mbAbsSpaces ), + mbHidden( rNumRule.mbHidden ), + mbCountPhantoms( true ), + mbUsedByRedline( false ), + meDefaultNumberFormatPositionAndSpaceMode( rNumRule.meDefaultNumberFormatPositionAndSpaceMode ), + msDefaultListId( rNumRule.msDefaultListId ) +{ + ++snRefCount; + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + if( rNumRule.maFormats[ n ] ) + Set( n, *rNumRule.maFormats[ n ] ); +} + +SwNumRule::~SwNumRule() +{ + for (auto & i : maFormats) + i.reset(); + + if (mpNumRuleMap) + { + mpNumRuleMap->erase(GetName()); + } + + if( !--snRefCount ) // the last one closes the door (?) + { + // Numbering: + SwNumFormat** ppFormats = &SwNumRule::saBaseFormats[0][0]; + int n; + + for( n = 0; n < MAXLEVEL; ++n, ++ppFormats ) + { + delete *ppFormats; + *ppFormats = nullptr; + } + + // Outline: + for( n = 0; n < MAXLEVEL; ++n, ++ppFormats ) + { + delete *ppFormats; + *ppFormats = nullptr; + } + + ppFormats = &SwNumRule::saLabelAlignmentBaseFormats[0][0]; + for( n = 0; n < MAXLEVEL; ++n, ++ppFormats ) + { + delete *ppFormats; + *ppFormats = nullptr; + } + for( n = 0; n < MAXLEVEL; ++n, ++ppFormats ) + { + delete *ppFormats; + *ppFormats = nullptr; + } + } + + maTextNodeList.clear(); + maParagraphStyleList.clear(); +} + +void SwNumRule::CheckCharFormats( SwDoc& rDoc ) +{ + for(auto& rpNumFormat : maFormats) + { + if( rpNumFormat ) + { + SwCharFormat* pFormat = rpNumFormat->GetCharFormat(); + if( pFormat && pFormat->GetDoc() != &rDoc ) + { + // copy + SwNumFormat* pNew = new SwNumFormat( *rpNumFormat ); + pNew->SetCharFormat( rDoc.CopyCharFormat( *pFormat ) ); + rpNumFormat.reset(pNew); + } + } + } +} + +SwNumRule& SwNumRule::operator=( const SwNumRule& rNumRule ) +{ + if( this != &rNumRule ) + { + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + Set( n, rNumRule.maFormats[ n ].get() ); + + meRuleType = rNumRule.meRuleType; + msName = rNumRule.msName; + mbAutoRuleFlag = rNumRule.mbAutoRuleFlag; + mbInvalidRuleFlag = true; + mbContinusNum = rNumRule.mbContinusNum; + mbAbsSpaces = rNumRule.mbAbsSpaces; + mbHidden = rNumRule.mbHidden; + mnPoolFormatId = rNumRule.GetPoolFormatId(); + mnPoolHelpId = rNumRule.GetPoolHelpId(); + mnPoolHlpFileId = rNumRule.GetPoolHlpFileId(); + } + return *this; +} + +void SwNumRule::Reset( const OUString& rName ) +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + Set( n, nullptr); + + meRuleType = NUM_RULE; + msName = rName; + mbAutoRuleFlag = true; + mbInvalidRuleFlag = true; + mbContinusNum = false; + mbAbsSpaces = false; + mbHidden = false; + mnPoolFormatId = USHRT_MAX; + mnPoolHelpId = USHRT_MAX; + mnPoolHlpFileId = UCHAR_MAX; +} + +bool SwNumRule::operator==( const SwNumRule& rRule ) const +{ + bool bRet = meRuleType == rRule.meRuleType && + msName == rRule.msName && + mbAutoRuleFlag == rRule.mbAutoRuleFlag && + mbContinusNum == rRule.mbContinusNum && + mbAbsSpaces == rRule.mbAbsSpaces && + mnPoolFormatId == rRule.GetPoolFormatId() && + mnPoolHelpId == rRule.GetPoolHelpId() && + mnPoolHlpFileId == rRule.GetPoolHlpFileId(); + if( bRet ) + { + for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) + if( rRule.Get( n ) != Get( n ) ) + { + bRet = false; + break; + } + } + return bRet; +} + +void SwNumRule::Set( sal_uInt16 i, const SwNumFormat& rNumFormat ) +{ + OSL_ENSURE( i < MAXLEVEL, "Serious defect" ); + if( i < MAXLEVEL ) + { + if( !maFormats[ i ] || (rNumFormat != Get( i )) ) + { + maFormats[ i ].reset(new SwNumFormat( rNumFormat )); + mbInvalidRuleFlag = true; + } + } +} + +void SwNumRule::Set( sal_uInt16 i, const SwNumFormat* pNumFormat ) +{ + OSL_ENSURE( i < MAXLEVEL, "Serious defect" ); + if( i >= MAXLEVEL ) + return; + if( !maFormats[ i ] ) + { + if( pNumFormat ) + { + maFormats[ i ].reset(new SwNumFormat( *pNumFormat )); + mbInvalidRuleFlag = true; + } + } + else if( !pNumFormat ) + { + maFormats[ i ].reset(); + mbInvalidRuleFlag = true; + } + else if( *maFormats[i] != *pNumFormat ) + { + *maFormats[ i ] = *pNumFormat; + mbInvalidRuleFlag = true; + } +} + +OUString SwNumRule::MakeNumString( const SwNodeNum& rNum, bool bInclStrings ) const +{ + if (rNum.IsCounted()) + return MakeNumString(rNum.GetNumberVector(), bInclStrings); + + return OUString(); +} + +OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVector, + const bool bInclStrings, + const unsigned int _nRestrictToThisLevel, + SwNumRule::Extremities* pExtremities, + LanguageType nLang ) const +{ + OUStringBuffer aStr; + + SwNumberTree::tNumberVector::size_type nLevel = rNumVector.size() - 1; + + if ( pExtremities ) + pExtremities->nPrefixChars = pExtremities->nSuffixChars = 0; + + if ( nLevel > _nRestrictToThisLevel ) + { + nLevel = _nRestrictToThisLevel; + } + + assert(nLevel < MAXLEVEL); + + const SwNumFormat& rMyNFormat = Get( o3tl::narrowing<sal_uInt16>(nLevel) ); + + if (rMyNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE) + { + if (!rMyNFormat.HasListFormat()) + return OUString(); + + // If numbering is disabled for this level we should emit just prefix/suffix + // Remove everything between first %1% and last %n% (including markers) + OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings); + sal_Int32 nFirstPosition = sLevelFormat.indexOf("%"); + sal_Int32 nLastPosition = sLevelFormat.lastIndexOf("%"); + if (nFirstPosition >= 0 && nLastPosition >= nFirstPosition) + sLevelFormat = sLevelFormat.replaceAt(nFirstPosition, nLastPosition - nFirstPosition + 1, u""); + return sLevelFormat; + } + + css::lang::Locale aLocale( LanguageTag::convertToLocale(nLang)); + + if (rMyNFormat.HasListFormat()) + { + OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings); + + // In this case we are ignoring GetIncludeUpperLevels: we put all + // level numbers requested by level format + for (SwNumberTree::tNumberVector::size_type i=0; i <= nLevel; ++i) + { + OUString sReplacement; + const SwNumFormat& rNFormat = Get(i); + if (rNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE) + { + // Numbering disabled - replacement is empty + // And we should skip all level string content until next level marker: + // so %1%.%2%.%3% with second level as NONE will result 1.1, not 1..1 + OUString sFind("%" + OUString::number(i + 1) + "%"); + sal_Int32 nPositionToken = sLevelFormat.indexOf(sFind); + sal_Int32 nPositionNextToken = sLevelFormat.indexOf('%', nPositionToken + sFind.getLength()); + if (nPositionToken >= 0 && nPositionNextToken >= nPositionToken) + { + sLevelFormat = sLevelFormat.replaceAt(nPositionToken, nPositionNextToken - nPositionToken, u""); + } + } + else if (rNumVector[i]) + sReplacement = Get(i).GetNumStr(rNumVector[i], aLocale); + else + sReplacement = "0"; // all 0 level are a 0 + + OUString sFind("%" + OUString::number(i + 1) + "%"); + sal_Int32 nPosition = sLevelFormat.indexOf(sFind); + if (nPosition >= 0) + sLevelFormat = sLevelFormat.replaceAt(nPosition, sFind.getLength(), sReplacement); + } + + aStr = sLevelFormat; + } + else + { + // Fallback case: level format is not defined + // So use old way with levels joining by dot "." + SwNumberTree::tNumberVector::size_type i = nLevel; + + if (!IsContinusNum() && + // - do not include upper levels, if level isn't numbered. + rMyNFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE && + rMyNFormat.GetIncludeUpperLevels()) // Just the own level? + { + sal_uInt8 n = rMyNFormat.GetIncludeUpperLevels(); + if (1 < n) + { + if (i + 1 >= n) + i -= n - 1; + else + i = 0; + } + } + + for (; i <= nLevel; ++i) + { + const SwNumFormat& rNFormat = Get(i); + if (SVX_NUM_NUMBER_NONE == rNFormat.GetNumberingType()) + { + // Should 1.1.1 --> 2. NoNum --> 1..1 or 1.1 ?? + // if( i != rNum.nMyLevel ) + // aStr += "."; + continue; + } + + if (rNumVector[i]) + aStr.append(rNFormat.GetNumStr(rNumVector[i], aLocale)); + else + aStr.append("0"); // all 0 level are a 0 + if (i != nLevel && !aStr.isEmpty()) + aStr.append("."); + } + + // The type doesn't have any number, so don't append + // the post-/prefix string + if (bInclStrings && + SVX_NUM_CHAR_SPECIAL != rMyNFormat.GetNumberingType() && + SVX_NUM_BITMAP != rMyNFormat.GetNumberingType()) + { + const OUString& sPrefix = rMyNFormat.GetPrefix(); + const OUString& sSuffix = rMyNFormat.GetSuffix(); + + aStr.insert(0, sPrefix); + aStr.append(sSuffix); + if (pExtremities) + { + pExtremities->nPrefixChars = sPrefix.getLength(); + pExtremities->nSuffixChars = sSuffix.getLength(); + } + } + } + + return aStr.makeStringAndClear(); +} + +OUString SwNumRule::MakeRefNumString( const SwNodeNum& rNodeNum, + const bool bInclSuperiorNumLabels, + const int nRestrictInclToThisLevel ) const +{ + OUString aRefNumStr; + + if ( rNodeNum.GetLevelInListTree() >= 0 ) + { + bool bOldHadPrefix = true; + + const SwNodeNum* pWorkingNodeNum( &rNodeNum ); + do + { + bool bMakeNumStringForPhantom( false ); + if ( pWorkingNodeNum->IsPhantom() ) + { + int nListLevel = pWorkingNodeNum->GetLevelInListTree(); + + if (nListLevel < 0) + nListLevel = 0; + + if (nListLevel >= MAXLEVEL) + nListLevel = MAXLEVEL - 1; + + SwNumFormat aFormat( Get( o3tl::narrowing<sal_uInt16>(nListLevel) ) ); + bMakeNumStringForPhantom = aFormat.IsEnumeration() && + SVX_NUM_NUMBER_NONE != aFormat.GetNumberingType(); + + } + if ( bMakeNumStringForPhantom || + ( !pWorkingNodeNum->IsPhantom() && + pWorkingNodeNum->GetTextNode() && + pWorkingNodeNum->GetTextNode()->HasNumber() ) ) + { + Extremities aExtremities; + OUString aPrevStr = MakeNumString( pWorkingNodeNum->GetNumberVector(), + true, MAXLEVEL, + &aExtremities); + sal_Int32 nStrip = 0; + while ( nStrip < aExtremities.nPrefixChars ) + { + const sal_Unicode c = aPrevStr[nStrip]; + if ( c!='\t' && c!=' ') + break; + ++nStrip; + } + + if (nStrip) + { + aPrevStr = aPrevStr.copy( nStrip ); + aExtremities.nPrefixChars -= nStrip; + } + + if (bOldHadPrefix && + aExtremities.nSuffixChars && + !aExtremities.nPrefixChars + ) + { + aPrevStr = aPrevStr.copy(0, + aPrevStr.getLength() - aExtremities.nSuffixChars); + } + + bOldHadPrefix = ( aExtremities.nPrefixChars > 0); + + aRefNumStr = aPrevStr + aRefNumStr; + } + + if ( bInclSuperiorNumLabels && pWorkingNodeNum->GetLevelInListTree() > 0 ) + { + sal_uInt8 n = Get( o3tl::narrowing<sal_uInt16>(pWorkingNodeNum->GetLevelInListTree()) ).GetIncludeUpperLevels(); + pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent()); + // skip parents, whose list label is already contained in the actual list label. + while ( pWorkingNodeNum && n > 1 ) + { + pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent()); + --n; + } + } + else + { + break; + } + } while ( pWorkingNodeNum && + pWorkingNodeNum->GetLevelInListTree() >= 0 && + pWorkingNodeNum->GetLevelInListTree() >= nRestrictInclToThisLevel ); + } + + if (aRefNumStr.endsWith(".")) + { + // tdf#144563: looks like a special case for refs by MS Word: if numbering is ending with dot, this dot is removed + aRefNumStr = aRefNumStr.copy(0, aRefNumStr.getLength() - 1); + } + + return aRefNumStr; +} + +OUString SwNumRule::MakeParagraphStyleListString() const +{ + OUString aParagraphStyleListString; + for (const auto& rParagraphStyle : maParagraphStyleList) + { + if (!aParagraphStyleListString.isEmpty()) + aParagraphStyleListString += ", "; + aParagraphStyleListString += rParagraphStyle->GetName(); + } + return aParagraphStyleListString; +} + +/** Copy method of SwNumRule + + A kind of copy constructor, so that the num formats are attached to the + right CharFormats of a Document. + Copies the NumFormats and returns itself. */ +SwNumRule& SwNumRule::CopyNumRule( SwDoc& rDoc, const SwNumRule& rNumRule ) +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + Set( n, rNumRule.maFormats[ n ].get() ); + if( maFormats[ n ] && maFormats[ n ]->GetCharFormat() && + !rDoc.GetCharFormats()->ContainsFormat(maFormats[n]->GetCharFormat())) + { + // If we copy across different Documents, then copy the + // corresponding CharFormat into the new Document. + maFormats[n]->SetCharFormat( rDoc.CopyCharFormat( *maFormats[n]-> + GetCharFormat() ) ); + } + } + meRuleType = rNumRule.meRuleType; + msName = rNumRule.msName; + mbAutoRuleFlag = rNumRule.mbAutoRuleFlag; + mnPoolFormatId = rNumRule.GetPoolFormatId(); + mnPoolHelpId = rNumRule.GetPoolHelpId(); + mnPoolHlpFileId = rNumRule.GetPoolHlpFileId(); + mbInvalidRuleFlag = true; + return *this; +} + +void SwNumRule::SetSvxRule(const SvxNumRule& rNumRule, SwDoc* pDoc) +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + const SvxNumberFormat* pSvxFormat = rNumRule.Get(n); + maFormats[n].reset( pSvxFormat ? new SwNumFormat(*pSvxFormat, pDoc) : nullptr ); + } + + mbInvalidRuleFlag = true; + mbContinusNum = rNumRule.IsContinuousNumbering(); +} + +SvxNumRule SwNumRule::MakeSvxNumRule() const +{ + SvxNumRule aRule(SvxNumRuleFlags::CONTINUOUS | SvxNumRuleFlags::CHAR_STYLE | + SvxNumRuleFlags::ENABLE_LINKED_BMP | SvxNumRuleFlags::ENABLE_EMBEDDED_BMP, + MAXLEVEL, mbContinusNum, + meRuleType == NUM_RULE ? SvxNumRuleType::NUMBERING : SvxNumRuleType::OUTLINE_NUMBERING ); + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + const SwNumFormat & rNumFormat = Get(n); + if(rNumFormat.GetCharFormat()) + { + SwNumFormat aNewFormat = rNumFormat; + aNewFormat.SetCharFormatName(rNumFormat.GetCharFormat()->GetName()); + aRule.SetLevel(n, aNewFormat, maFormats[n] != nullptr); + } + else + aRule.SetLevel(n, rNumFormat, maFormats[n] != nullptr); + } + return aRule; +} + +void SwNumRule::SetInvalidRule(bool bFlag) +{ + if (bFlag) + { + o3tl::sorted_vector< SwList* > aLists; + for ( const SwTextNode* pTextNode : maTextNodeList ) + { + // #i111681# - applying patch from cmc + SwList* pList = pTextNode->GetDoc().getIDocumentListsAccess().getListByName( pTextNode->GetListId() ); + OSL_ENSURE( pList, "<SwNumRule::SetInvalidRule(..)> - list at which the text node is registered at does not exist. This is a serious issue."); + if ( pList ) + { + aLists.insert( pList ); + } + } + for ( auto aList : aLists ) + aList->InvalidateListTree(); + } + + mbInvalidRuleFlag = bFlag; +} + +/// change indent of all list levels by given difference +void SwNumRule::ChangeIndent( const sal_Int32 nDiff ) +{ + for ( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + SwNumFormat aTmpNumFormat( Get(i) ); + + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFormat.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + auto nNewIndent = nDiff + + aTmpNumFormat.GetAbsLSpace(); + if ( nNewIndent < 0 ) + { + nNewIndent = 0; + } + aTmpNumFormat.SetAbsLSpace( nNewIndent ); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + // adjust also the list tab position, if a list tab stop is applied + if ( aTmpNumFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB ) + { + const tools::Long nNewListTab = aTmpNumFormat.GetListtabPos() + nDiff; + aTmpNumFormat.SetListtabPos( nNewListTab ); + } + + const tools::Long nNewIndent = nDiff + + aTmpNumFormat.GetIndentAt(); + aTmpNumFormat.SetIndentAt( nNewIndent ); + } + + Set( i, aTmpNumFormat ); + } + + SetInvalidRule( true ); +} + +/// set indent of certain list level to given value +void SwNumRule::SetIndent( const short nNewIndent, + const sal_uInt16 nListLevel ) +{ + SwNumFormat aTmpNumFormat( Get(nListLevel) ); + + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFormat.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aTmpNumFormat.SetAbsLSpace( nNewIndent ); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + // adjust also the list tab position, if a list tab stop is applied + if ( aTmpNumFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB ) + { + const tools::Long nNewListTab = aTmpNumFormat.GetListtabPos() + + ( nNewIndent - aTmpNumFormat.GetIndentAt() ); + aTmpNumFormat.SetListtabPos( nNewListTab ); + } + + aTmpNumFormat.SetIndentAt( nNewIndent ); + } + + SetInvalidRule( true ); +} + +/// set indent of first list level to given value and change other list level's +/// indents accordingly +void SwNumRule::SetIndentOfFirstListLevelAndChangeOthers( const short nNewIndent ) +{ + SwNumFormat aTmpNumFormat( Get(0) ); + + sal_Int32 nDiff( 0 ); + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFormat.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + nDiff = nNewIndent + - aTmpNumFormat.GetFirstLineOffset() + - aTmpNumFormat.GetAbsLSpace(); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + nDiff = nNewIndent - aTmpNumFormat.GetIndentAt(); + } + if ( nDiff != 0 ) + { + ChangeIndent( nDiff ); + } +} + +void SwNumRule::Validate(const SwDoc& rDoc) +{ + o3tl::sorted_vector< SwList* > aLists; + for ( const SwTextNode* pTextNode : maTextNodeList ) + { + aLists.insert( pTextNode->GetDoc().getIDocumentListsAccess().getListByName( pTextNode->GetListId() ) ); + } + for ( auto aList : aLists ) + aList->ValidateListTree(rDoc); + + SetInvalidRule(false); +} + +void SwNumRule::SetCountPhantoms(bool bCountPhantoms) +{ + mbCountPhantoms = bCountPhantoms; +} + +SwNumRule::tParagraphStyleList::size_type SwNumRule::GetParagraphStyleListSize() const +{ + return maParagraphStyleList.size(); +} + +void SwNumRule::AddParagraphStyle( SwTextFormatColl& rTextFormatColl ) +{ + tParagraphStyleList::iterator aIter = + std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTextFormatColl ); + + if ( aIter == maParagraphStyleList.end() ) + { + maParagraphStyleList.push_back( &rTextFormatColl ); + } +} + +void SwNumRule::RemoveParagraphStyle( SwTextFormatColl& rTextFormatColl ) +{ + tParagraphStyleList::iterator aIter = + std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTextFormatColl ); + + if ( aIter != maParagraphStyleList.end() ) + { + maParagraphStyleList.erase( aIter ); + } +} + +void SwNumRule::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwNumRule")); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("msName"), BAD_CAST(msName.toUtf8().getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mnPoolFormatId"), BAD_CAST(OString::number(mnPoolFormatId).getStr())); + (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mbAutoRuleFlag"), BAD_CAST(OString::boolean(mbAutoRuleFlag).getStr())); + + for (const auto& pFormat : maFormats) + { + if (!pFormat) + { + continue; + } + + pFormat->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +void SwNumRule::GetGrabBagItem(uno::Any& rVal) const +{ + if (mpGrabBagItem) + mpGrabBagItem->QueryValue(rVal); + else + rVal <<= uno::Sequence<beans::PropertyValue>(); +} + +void SwNumRule::SetGrabBagItem(const uno::Any& rVal) +{ + if (!mpGrabBagItem) + mpGrabBagItem = std::make_shared<SfxGrabBagItem>(); + + mpGrabBagItem->PutValue(rVal, 0); +} + +bool SwNumRule::HasContinueList() const +{ + // In case all text nodes are after each other, then we won't have a later list that wants to + // continue us. + SwNodeOffset nIndex(0); + for (size_t i = 0; i < maTextNodeList.size(); ++i) + { + SwTextNode* pNode = maTextNodeList[i]; + if (i > 0) + { + if (pNode->GetIndex() != nIndex + 1) + { + // May have a continue list. + return true; + } + } + nIndex = pNode->GetIndex(); + } + + // Definitely won't have a continue list. + return false; +} + +namespace numfunc +{ + namespace { + + /** class containing default bullet list configuration data */ + class SwDefBulletConfig : private utl::ConfigItem + { + public: + static SwDefBulletConfig& getInstance(); + + const OUString& GetFontname() const + { + return msFontname; + } + + bool IsFontnameUserDefined() const + { + return mbUserDefinedFontname; + } + + const vcl::Font& GetFont() const + { + return *mpFont; + } + + sal_Unicode GetChar( sal_uInt8 p_nListLevel ) const + { + if (p_nListLevel >= MAXLEVEL) + { + p_nListLevel = MAXLEVEL - 1; + } + + return mnLevelChars[p_nListLevel]; + } + + SwDefBulletConfig(); + + private: + /** sets internal default bullet configuration data to default values */ + void SetToDefault(); + + /** returns sequence of default bullet configuration property names */ + static uno::Sequence<OUString> GetPropNames(); + + /** loads default bullet configuration properties and applies + values to internal data */ + void LoadConfig(); + + /** initialize font instance for default bullet list */ + void InitFont(); + + /** catches notification about changed default bullet configuration data */ + virtual void Notify( const uno::Sequence<OUString>& aPropertyNames ) override; + virtual void ImplCommit() override; + + // default bullet list configuration data + OUString msFontname; + bool mbUserDefinedFontname; + FontWeight meFontWeight; + FontItalic meFontItalic; + sal_Unicode mnLevelChars[MAXLEVEL]; + + // default bullet list font instance + std::optional<vcl::Font> mpFont; + }; + + } + + SwDefBulletConfig& SwDefBulletConfig::getInstance() + { + static SwDefBulletConfig theSwDefBulletConfig; + return theSwDefBulletConfig; + } + + SwDefBulletConfig::SwDefBulletConfig() + : ConfigItem( "Office.Writer/Numbering/DefaultBulletList" ), + // default bullet font is now OpenSymbol + msFontname( OUString("OpenSymbol") ), + mbUserDefinedFontname( false ), + meFontWeight( WEIGHT_DONTKNOW ), + meFontItalic( ITALIC_NONE ) + { + SetToDefault(); + LoadConfig(); + InitFont(); + + // enable notification for changes on default bullet configuration change + EnableNotification( GetPropNames() ); + } + + void SwDefBulletConfig::SetToDefault() + { + msFontname = "OpenSymbol"; + mbUserDefinedFontname = false; + meFontWeight = WEIGHT_DONTKNOW; + meFontItalic = ITALIC_NONE; + + mnLevelChars[0] = 0x2022; + mnLevelChars[1] = 0x25e6; + mnLevelChars[2] = 0x25aa; + mnLevelChars[3] = 0x2022; + mnLevelChars[4] = 0x25e6; + mnLevelChars[5] = 0x25aa; + mnLevelChars[6] = 0x2022; + mnLevelChars[7] = 0x25e6; + mnLevelChars[8] = 0x25aa; + mnLevelChars[9] = 0x2022; + } + + uno::Sequence<OUString> SwDefBulletConfig::GetPropNames() + { + uno::Sequence<OUString> aPropNames(13); + OUString* pNames = aPropNames.getArray(); + pNames[0] = "BulletFont/FontFamilyname"; + pNames[1] = "BulletFont/FontWeight"; + pNames[2] = "BulletFont/FontItalic"; + pNames[3] = "BulletCharLvl1"; + pNames[4] = "BulletCharLvl2"; + pNames[5] = "BulletCharLvl3"; + pNames[6] = "BulletCharLvl4"; + pNames[7] = "BulletCharLvl5"; + pNames[8] = "BulletCharLvl6"; + pNames[9] = "BulletCharLvl7"; + pNames[10] = "BulletCharLvl8"; + pNames[11] = "BulletCharLvl9"; + pNames[12] = "BulletCharLvl10"; + + return aPropNames; + } + + void SwDefBulletConfig::LoadConfig() + { + uno::Sequence<OUString> aPropNames = GetPropNames(); + uno::Sequence<uno::Any> aValues = GetProperties( aPropNames ); + const uno::Any* pValues = aValues.getConstArray(); + OSL_ENSURE( aValues.getLength() == aPropNames.getLength(), + "<SwDefBulletConfig::SwDefBulletConfig()> - GetProperties failed"); + if ( aValues.getLength() != aPropNames.getLength() ) + return; + + for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( nProp ) + { + case 0: + { + OUString aStr; + pValues[nProp] >>= aStr; + msFontname = aStr; + mbUserDefinedFontname = true; + } + break; + case 1: + case 2: + { + sal_Int16 nTmp = 0; + pValues[nProp] >>= nTmp; + if ( nProp == 1 ) + meFontWeight = static_cast<FontWeight>(nTmp); + else if ( nProp == 2 ) + meFontItalic = static_cast<FontItalic>(nTmp); + } + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + { + sal_Unicode cChar = sal_Unicode(); + pValues[nProp] >>= cChar; + mnLevelChars[nProp-3] = cChar; + } + break; + } + } + } + + } + + void SwDefBulletConfig::InitFont() + { + mpFont.emplace( msFontname, OUString(), Size( 0, 14 ) ); + mpFont->SetWeight( meFontWeight ); + mpFont->SetItalic( meFontItalic ); + mpFont->SetCharSet( RTL_TEXTENCODING_SYMBOL ); + } + + void SwDefBulletConfig::Notify( const uno::Sequence<OUString>& ) + { + SetToDefault(); + LoadConfig(); + InitFont(); + } + + void SwDefBulletConfig::ImplCommit() + { + } + + OUString const & GetDefBulletFontname() + { + return SwDefBulletConfig::getInstance().GetFontname(); + } + + bool IsDefBulletFontUserDefined() + { + return SwDefBulletConfig::getInstance().IsFontnameUserDefined(); + } + + const vcl::Font& GetDefBulletFont() + { + return SwDefBulletConfig::getInstance().GetFont(); + } + + sal_Unicode GetBulletChar( sal_uInt8 nLevel ) + { + return SwDefBulletConfig::getInstance().GetChar( nLevel ); + } + + namespace { + + /** class containing configuration data about user interface behavior + regarding lists and list items. + configuration item about behavior of <TAB>/<SHIFT-TAB>-key at first + position of first list item + */ + class SwNumberingUIBehaviorConfig : private utl::ConfigItem + { + public: + static SwNumberingUIBehaviorConfig& getInstance(); + + bool ChangeIndentOnTabAtFirstPosOfFirstListItem() const + { + return mbChangeIndentOnTabAtFirstPosOfFirstListItem; + } + + SwNumberingUIBehaviorConfig(); + + private: + + /** sets internal configuration data to default values */ + void SetToDefault(); + + /** returns sequence of configuration property names */ + static css::uno::Sequence<OUString> GetPropNames(); + + /** loads configuration properties and applies values to internal data */ + void LoadConfig(); + + /** catches notification about changed configuration data */ + virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames ) override; + virtual void ImplCommit() override; + + // configuration data + bool mbChangeIndentOnTabAtFirstPosOfFirstListItem; + }; + + } + + SwNumberingUIBehaviorConfig& SwNumberingUIBehaviorConfig::getInstance() + { + static SwNumberingUIBehaviorConfig theSwNumberingUIBehaviorConfig; + return theSwNumberingUIBehaviorConfig; + } + + SwNumberingUIBehaviorConfig::SwNumberingUIBehaviorConfig() + : ConfigItem( "Office.Writer/Numbering/UserInterfaceBehavior" ), + mbChangeIndentOnTabAtFirstPosOfFirstListItem( true ) + { + SetToDefault(); + LoadConfig(); + + // enable notification for changes on configuration change + EnableNotification( GetPropNames() ); + } + + void SwNumberingUIBehaviorConfig::SetToDefault() + { + mbChangeIndentOnTabAtFirstPosOfFirstListItem = true; + } + + css::uno::Sequence<OUString> SwNumberingUIBehaviorConfig::GetPropNames() + { + css::uno::Sequence<OUString> aPropNames { "ChangeIndentOnTabAtFirstPosOfFirstListItem" }; + + return aPropNames; + } + + void SwNumberingUIBehaviorConfig::ImplCommit() {} + + void SwNumberingUIBehaviorConfig::LoadConfig() + { + css::uno::Sequence<OUString> aPropNames = GetPropNames(); + css::uno::Sequence<css::uno::Any> aValues = GetProperties( aPropNames ); + const css::uno::Any* pValues = aValues.getConstArray(); + OSL_ENSURE( aValues.getLength() == aPropNames.getLength(), + "<SwNumberingUIBehaviorConfig::LoadConfig()> - GetProperties failed"); + if ( aValues.getLength() != aPropNames.getLength() ) + return; + + for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( nProp ) + { + case 0: + { + pValues[nProp] >>= mbChangeIndentOnTabAtFirstPosOfFirstListItem; + } + break; + default: + { + OSL_FAIL( "<SwNumberingUIBehaviorConfig::LoadConfig()> - unknown configuration property"); + } + } + } + } + } + + void SwNumberingUIBehaviorConfig::Notify( const css::uno::Sequence<OUString>& ) + { + SetToDefault(); + LoadConfig(); + } + + bool ChangeIndentOnTabAtFirstPosOfFirstListItem() + { + return SwNumberingUIBehaviorConfig::getInstance().ChangeIndentOnTabAtFirstPosOfFirstListItem(); + } + + bool NumDownChangesIndent(const SwWrtShell& rShell) + { + SwPaM* pCursor = rShell.GetCursor(); + if (!pCursor) + { + return true; + } + + SwTextNode* pTextNode = pCursor->GetNode().GetTextNode(); + if (!pTextNode) + { + return true; + } + + const SwNumRule* pNumRule = pTextNode->GetNumRule(); + if (!pNumRule) + { + return true; + } + + int nOldLevel = pTextNode->GetActualListLevel(); + int nNewLevel = nOldLevel + 1; + if (nNewLevel >= MAXLEVEL) + { + return true; + } + + const SwNumFormat& rOldFormat = pNumRule->Get(nOldLevel); + if (rOldFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE) + { + return true; + } + + const SwNumFormat& rNewFormat = pNumRule->Get(nNewLevel); + if (rNewFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE) + { + return true; + } + + // This is the case when the numbering levels don't differ, so changing between them is not + // a better alternative to inserting a tab character. + return rOldFormat.GetIndentAt() != rNewFormat.GetIndentAt(); + } + + SvxNumberFormat::SvxNumPositionAndSpaceMode GetDefaultPositionAndSpaceMode() + { + if (utl::ConfigManager::IsFuzzing()) + return SvxNumberFormat::LABEL_ALIGNMENT; + + SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode; + switch (GetODFSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_010: + case SvtSaveOptions::ODFSVER_011: + { + ePosAndSpaceMode = SvxNumberFormat::LABEL_WIDTH_AND_POSITION; + } + break; + default: // >= ODFSVER_012 + { + ePosAndSpaceMode = SvxNumberFormat::LABEL_ALIGNMENT; + } + } + + return ePosAndSpaceMode; + } +} + +void SwNumRuleTable::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwNumRuleTable")); + for (SwNumRule* pNumRule : *this) + pNumRule->dumpAsXml(pWriter); + (void)xmlTextWriterEndElement(pWriter); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |