summaryrefslogtreecommitdiffstats
path: root/editeng/source/items/numitem.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /editeng/source/items/numitem.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'editeng/source/items/numitem.cxx')
-rw-r--r--editeng/source/items/numitem.cxx1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/editeng/source/items/numitem.cxx b/editeng/source/items/numitem.cxx
new file mode 100644
index 000000000..cbbd7efb9
--- /dev/null
+++ b/editeng/source/items/numitem.cxx
@@ -0,0 +1,1129 @@
+/* -*- 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 <algorithm>
+
+#include <editeng/numitem.hxx>
+
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <comphelper/propertyvalue.hxx>
+#include <editeng/brushitem.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <vcl/font.hxx>
+#include <vcl/settings.hxx>
+#include <editeng/editids.hrc>
+#include <editeng/numdef.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/text/XNumberingFormatter.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <comphelper/fileformat.h>
+#include <comphelper/processfactory.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+#include <tools/GenericTypeSerializer.hxx>
+#include <unotools/configmgr.hxx>
+#include <libxml/xmlwriter.h>
+#include <editeng/unonrule.hxx>
+#include <sal/log.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <editeng/legacyitem.hxx>
+
+constexpr sal_Int32 DEF_WRITER_LSPACE = 500; //Standard Indentation
+constexpr sal_Int32 DEF_DRAW_LSPACE = 800; //Standard Indentation
+
+constexpr sal_uInt16 NUMITEM_VERSION_03 = 0x03;
+constexpr sal_uInt16 NUMITEM_VERSION_04 = 0x04;
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::style;
+
+sal_Int32 SvxNumberType::nRefCount = 0;
+css::uno::Reference<css::text::XNumberingFormatter> SvxNumberType::xFormatter;
+static void lcl_getFormatter(css::uno::Reference<css::text::XNumberingFormatter>& _xFormatter)
+{
+ if(_xFormatter.is())
+ return;
+
+ try
+ {
+ Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
+ Reference<XDefaultNumberingProvider> xRet = text::DefaultNumberingProvider::create(xContext);
+ _xFormatter.set(xRet, UNO_QUERY);
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("editeng", "service missing: \"com.sun.star.text.DefaultNumberingProvider\"");
+ }
+}
+
+SvxNumberType::SvxNumberType(SvxNumType nType) :
+ nNumType(nType),
+ bShowSymbol(true)
+{
+ nRefCount++;
+}
+
+SvxNumberType::SvxNumberType(const SvxNumberType& rType) :
+ nNumType(rType.nNumType),
+ bShowSymbol(rType.bShowSymbol)
+{
+ nRefCount++;
+}
+
+SvxNumberType::~SvxNumberType()
+{
+ if(!--nRefCount)
+ xFormatter = nullptr;
+}
+
+OUString SvxNumberType::GetNumStr( sal_Int32 nNo ) const
+{
+ LanguageTag aLang = utl::ConfigManager::IsFuzzing() ?
+ LanguageTag("en-US") :
+ Application::GetSettings().GetLanguageTag();
+ return GetNumStr( nNo, aLang.getLocale() );
+}
+
+OUString SvxNumberType::GetNumStr( sal_Int32 nNo, const css::lang::Locale& rLocale ) const
+{
+ lcl_getFormatter(xFormatter);
+ if(!xFormatter.is())
+ return OUString();
+
+ if(bShowSymbol)
+ {
+ switch(nNumType)
+ {
+ case NumberingType::CHAR_SPECIAL:
+ case NumberingType::BITMAP:
+ break;
+ default:
+ {
+ // '0' allowed for ARABIC numberings
+ if(NumberingType::ARABIC == nNumType && 0 == nNo )
+ return OUString('0');
+ else
+ {
+ static constexpr OUStringLiteral sNumberingType = u"NumberingType";
+ static constexpr OUStringLiteral sValue = u"Value";
+ Sequence< PropertyValue > aProperties
+ {
+ comphelper::makePropertyValue(sNumberingType, static_cast<sal_uInt16>(nNumType)),
+ comphelper::makePropertyValue(sValue, nNo)
+ };
+
+ try
+ {
+ return xFormatter->makeNumberingString( aProperties, rLocale );
+ }
+ catch(const Exception&)
+ {
+ }
+ }
+ }
+ }
+ }
+ return OUString();
+}
+
+void SvxNumberType::dumpAsXml( xmlTextWriterPtr pWriter ) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumberType"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("NumType"), BAD_CAST(OString::number(nNumType).getStr()));
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SvxNumberFormat::SvxNumberFormat( SvxNumType eType )
+ : SvxNumberType(eType),
+ eNumAdjust(SvxAdjust::Left),
+ nInclUpperLevels(1),
+ nStart(1),
+ cBullet(SVX_DEF_BULLET),
+ nBulletRelSize(100),
+ nBulletColor(COL_BLACK),
+ mePositionAndSpaceMode( LABEL_WIDTH_AND_POSITION ),
+ nFirstLineOffset(0),
+ nAbsLSpace(0),
+ nCharTextDistance(0),
+ meLabelFollowedBy( LISTTAB ),
+ mnListtabPos( 0 ),
+ mnFirstLineIndent( 0 ),
+ mnIndentAt( 0 ),
+ eVertOrient(text::VertOrientation::NONE)
+{
+}
+
+SvxNumberFormat::SvxNumberFormat(const SvxNumberFormat& rFormat) :
+ SvxNumberType(rFormat),
+ mePositionAndSpaceMode( rFormat.mePositionAndSpaceMode )
+{
+ *this = rFormat;
+}
+
+SvxNumberFormat::SvxNumberFormat( SvStream &rStream )
+ : nStart(0)
+ , nBulletRelSize(100)
+ , nFirstLineOffset(0)
+ , nAbsLSpace(0)
+ , nCharTextDistance(0)
+{
+ sal_uInt16 nTmp16(0);
+ sal_Int32 nTmp32(0);
+ rStream.ReadUInt16( nTmp16 ); // Version number
+
+ rStream.ReadUInt16( nTmp16 ); SetNumberingType( static_cast<SvxNumType>(nTmp16) );
+ rStream.ReadUInt16( nTmp16 ); eNumAdjust = static_cast<SvxAdjust>(nTmp16);
+ rStream.ReadUInt16( nTmp16 ); nInclUpperLevels = nTmp16;
+ rStream.ReadUInt16( nStart );
+ rStream.ReadUInt16( nTmp16 ); cBullet = static_cast<sal_Unicode>(nTmp16);
+
+ sal_Int16 temp = 0;
+ rStream.ReadInt16( temp );
+ nFirstLineOffset = temp;
+ temp = 0;
+ rStream.ReadInt16( temp );
+ nAbsLSpace = temp;
+ rStream.SeekRel(2); //skip old now unused nLSpace;
+
+ rStream.ReadInt16( nCharTextDistance );
+
+ sPrefix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
+ sSuffix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
+ sCharStyleName = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
+
+ sal_uInt16 hasGraphicBrush = 0;
+ rStream.ReadUInt16( hasGraphicBrush );
+ if ( hasGraphicBrush )
+ {
+ pGraphicBrush.reset(new SvxBrushItem(SID_ATTR_BRUSH));
+ legacy::SvxBrush::Create(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
+ }
+ else pGraphicBrush = nullptr;
+ rStream.ReadUInt16( nTmp16 ); eVertOrient = nTmp16;
+
+ sal_uInt16 hasBulletFont = 0;
+ rStream.ReadUInt16( hasBulletFont );
+ if ( hasBulletFont )
+ {
+ pBulletFont.emplace();
+ ReadFont( rStream, *pBulletFont );
+ }
+ else pBulletFont.reset();
+
+ tools::GenericTypeSerializer aSerializer(rStream);
+ aSerializer.readSize(aGraphicSize);
+ aSerializer.readColor(nBulletColor);
+
+ rStream.ReadUInt16( nBulletRelSize );
+ rStream.ReadUInt16( nTmp16 ); SetShowSymbol( nTmp16 != 0 );
+
+ rStream.ReadUInt16( nTmp16 ); mePositionAndSpaceMode = static_cast<SvxNumPositionAndSpaceMode>(nTmp16);
+ rStream.ReadUInt16( nTmp16 ); meLabelFollowedBy = static_cast<LabelFollowedBy>(nTmp16);
+ rStream.ReadInt32( nTmp32 ); mnListtabPos = nTmp32;
+ rStream.ReadInt32( nTmp32 ); mnFirstLineIndent = nTmp32;
+ rStream.ReadInt32( nTmp32 ); mnIndentAt = nTmp32;
+}
+
+SvxNumberFormat::~SvxNumberFormat()
+{
+}
+
+void SvxNumberFormat::Store(SvStream &rStream, FontToSubsFontConverter pConverter)
+{
+ if(pConverter && pBulletFont)
+ {
+ cBullet = ConvertFontToSubsFontChar(pConverter, cBullet);
+ OUString sFontName = GetFontToSubsFontName(pConverter);
+ pBulletFont->SetFamilyName(sFontName);
+ }
+
+ tools::GenericTypeSerializer aSerializer(rStream);
+
+ rStream.WriteUInt16( NUMITEM_VERSION_04 );
+
+ rStream.WriteUInt16( GetNumberingType() );
+ rStream.WriteUInt16( static_cast<sal_uInt16>(eNumAdjust) );
+ rStream.WriteUInt16( nInclUpperLevels );
+ rStream.WriteUInt16( nStart );
+ rStream.WriteUInt16( cBullet );
+
+ rStream.WriteInt16(
+ sal_Int16(std::clamp<sal_Int32>(nFirstLineOffset, SAL_MIN_INT16, SAL_MAX_INT16)) );
+ //TODO: better way to handle out-of-bounds value?
+ rStream.WriteInt16(
+ sal_Int16(std::clamp<sal_Int32>(nAbsLSpace, SAL_MIN_INT16, SAL_MAX_INT16)) );
+ //TODO: better way to handle out-of-bounds value?
+ rStream.WriteInt16( 0 ); // write a dummy for old now unused nLSpace
+
+ rStream.WriteInt16( nCharTextDistance );
+ rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
+ rStream.WriteUniOrByteString(sPrefix, eEnc);
+ rStream.WriteUniOrByteString(sSuffix, eEnc);
+ rStream.WriteUniOrByteString(sCharStyleName, eEnc);
+ if(pGraphicBrush)
+ {
+ rStream.WriteUInt16( 1 );
+
+ // in SD or SI force bullet itself to be stored,
+ // for that purpose throw away link when link and graphic
+ // are present, so Brush save is forced
+ if(!pGraphicBrush->GetGraphicLink().isEmpty() && pGraphicBrush->GetGraphic())
+ {
+ pGraphicBrush->SetGraphicLink("");
+ }
+
+ legacy::SvxBrush::Store(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
+ }
+ else
+ rStream.WriteUInt16( 0 );
+
+ rStream.WriteUInt16( eVertOrient );
+ if(pBulletFont)
+ {
+ rStream.WriteUInt16( 1 );
+ WriteFont( rStream, *pBulletFont );
+ }
+ else
+ rStream.WriteUInt16( 0 );
+
+ aSerializer.writeSize(aGraphicSize);
+
+ Color nTempColor = nBulletColor;
+ if(COL_AUTO == nBulletColor)
+ nTempColor = COL_BLACK;
+
+ aSerializer.writeColor(nTempColor);
+ rStream.WriteUInt16( nBulletRelSize );
+ rStream.WriteUInt16( sal_uInt16(IsShowSymbol()) );
+
+ rStream.WriteUInt16( mePositionAndSpaceMode );
+ rStream.WriteUInt16( meLabelFollowedBy );
+ rStream.WriteInt32( mnListtabPos );
+ rStream.WriteInt32( mnFirstLineIndent );
+ rStream.WriteInt32( mnIndentAt );
+}
+
+SvxNumberFormat& SvxNumberFormat::operator=( const SvxNumberFormat& rFormat )
+{
+ if (& rFormat == this) { return *this; }
+
+ SvxNumberType::SetNumberingType(rFormat.GetNumberingType());
+ eNumAdjust = rFormat.eNumAdjust ;
+ nInclUpperLevels = rFormat.nInclUpperLevels ;
+ nStart = rFormat.nStart ;
+ cBullet = rFormat.cBullet ;
+ mePositionAndSpaceMode = rFormat.mePositionAndSpaceMode;
+ nFirstLineOffset = rFormat.nFirstLineOffset;
+ nAbsLSpace = rFormat.nAbsLSpace ;
+ nCharTextDistance = rFormat.nCharTextDistance ;
+ meLabelFollowedBy = rFormat.meLabelFollowedBy;
+ mnListtabPos = rFormat.mnListtabPos;
+ mnFirstLineIndent = rFormat.mnFirstLineIndent;
+ mnIndentAt = rFormat.mnIndentAt;
+ eVertOrient = rFormat.eVertOrient;
+ sPrefix = rFormat.sPrefix;
+ sSuffix = rFormat.sSuffix;
+ sListFormat = rFormat.sListFormat;
+ aGraphicSize = rFormat.aGraphicSize ;
+ nBulletColor = rFormat.nBulletColor ;
+ nBulletRelSize = rFormat.nBulletRelSize;
+ SetShowSymbol(rFormat.IsShowSymbol());
+ sCharStyleName = rFormat.sCharStyleName;
+ pGraphicBrush.reset();
+ if(rFormat.pGraphicBrush)
+ {
+ pGraphicBrush.reset( new SvxBrushItem(*rFormat.pGraphicBrush) );
+ }
+ pBulletFont.reset();
+ if(rFormat.pBulletFont)
+ pBulletFont = *rFormat.pBulletFont;
+ return *this;
+}
+
+bool SvxNumberFormat::operator==( const SvxNumberFormat& rFormat) const
+{
+ if( GetNumberingType() != rFormat.GetNumberingType() ||
+ eNumAdjust != rFormat.eNumAdjust ||
+ nInclUpperLevels != rFormat.nInclUpperLevels ||
+ nStart != rFormat.nStart ||
+ cBullet != rFormat.cBullet ||
+ mePositionAndSpaceMode != rFormat.mePositionAndSpaceMode ||
+ nFirstLineOffset != rFormat.nFirstLineOffset ||
+ nAbsLSpace != rFormat.nAbsLSpace ||
+ nCharTextDistance != rFormat.nCharTextDistance ||
+ meLabelFollowedBy != rFormat.meLabelFollowedBy ||
+ mnListtabPos != rFormat.mnListtabPos ||
+ mnFirstLineIndent != rFormat.mnFirstLineIndent ||
+ mnIndentAt != rFormat.mnIndentAt ||
+ eVertOrient != rFormat.eVertOrient ||
+ sPrefix != rFormat.sPrefix ||
+ sSuffix != rFormat.sSuffix ||
+ sListFormat != rFormat.sListFormat ||
+ aGraphicSize != rFormat.aGraphicSize ||
+ nBulletColor != rFormat.nBulletColor ||
+ nBulletRelSize != rFormat.nBulletRelSize ||
+ IsShowSymbol() != rFormat.IsShowSymbol() ||
+ sCharStyleName != rFormat.sCharStyleName
+ )
+ return false;
+ if (
+ (pGraphicBrush && !rFormat.pGraphicBrush) ||
+ (!pGraphicBrush && rFormat.pGraphicBrush) ||
+ (pGraphicBrush && *pGraphicBrush != *rFormat.pGraphicBrush)
+ )
+ {
+ return false;
+ }
+ if (
+ (pBulletFont && !rFormat.pBulletFont) ||
+ (!pBulletFont && rFormat.pBulletFont) ||
+ (pBulletFont && *pBulletFont != *rFormat.pBulletFont)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+void SvxNumberFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem,
+ const Size* pSize, const sal_Int16* pOrient)
+{
+ if (!pBrushItem)
+ pGraphicBrush.reset();
+ else if ( !pGraphicBrush || (*pBrushItem != *pGraphicBrush) )
+ pGraphicBrush.reset(pBrushItem->Clone());
+
+ if(pOrient)
+ eVertOrient = *pOrient;
+ else
+ eVertOrient = text::VertOrientation::NONE;
+ if(pSize)
+ aGraphicSize = *pSize;
+ else
+ {
+ aGraphicSize.setWidth(0);
+ aGraphicSize.setHeight(0);
+ }
+}
+
+void SvxNumberFormat::SetGraphic( const OUString& rName )
+{
+ if( pGraphicBrush && pGraphicBrush->GetGraphicLink() == rName )
+ return ;
+
+ pGraphicBrush.reset( new SvxBrushItem( rName, "", GPOS_AREA, 0 ) );
+ if( eVertOrient == text::VertOrientation::NONE )
+ eVertOrient = text::VertOrientation::TOP;
+
+ aGraphicSize.setWidth(0);
+ aGraphicSize.setHeight(0);
+}
+
+sal_Int16 SvxNumberFormat::GetVertOrient() const
+{
+ return eVertOrient;
+}
+
+void SvxNumberFormat::SetBulletFont(const vcl::Font* pFont)
+{
+ if (pFont)
+ pBulletFont = *pFont;
+ else
+ pBulletFont.reset();
+}
+
+void SvxNumberFormat::SetPositionAndSpaceMode( SvxNumPositionAndSpaceMode ePositionAndSpaceMode )
+{
+ mePositionAndSpaceMode = ePositionAndSpaceMode;
+}
+
+sal_Int32 SvxNumberFormat::GetAbsLSpace() const
+{
+ return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
+ ? nAbsLSpace
+ : static_cast<sal_Int32>( GetFirstLineIndent() + GetIndentAt() );
+}
+sal_Int32 SvxNumberFormat::GetFirstLineOffset() const
+{
+ return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
+ ? nFirstLineOffset
+ : static_cast<sal_Int32>( GetFirstLineIndent() );
+}
+short SvxNumberFormat::GetCharTextDistance() const
+{
+ return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION ? nCharTextDistance : 0;
+}
+
+void SvxNumberFormat::SetLabelFollowedBy( const LabelFollowedBy eLabelFollowedBy )
+{
+ meLabelFollowedBy = eLabelFollowedBy;
+}
+
+OUString SvxNumberFormat::GetLabelFollowedByAsString() const
+{
+ switch (meLabelFollowedBy)
+ {
+ case LISTTAB:
+ return "\t";
+ case SPACE:
+ return " ";
+ case NEWLINE:
+ return "\n";
+ case NOTHING:
+ // intentionally left blank.
+ return OUString();
+ default:
+ SAL_WARN("editeng", "Unknown SvxNumberFormat::GetLabelFollowedBy() return value");
+ assert(false);
+ }
+ return OUString();
+}
+
+void SvxNumberFormat::SetListtabPos( const tools::Long nListtabPos )
+{
+ mnListtabPos = nListtabPos;
+}
+void SvxNumberFormat::SetFirstLineIndent( const tools::Long nFirstLineIndent )
+{
+ mnFirstLineIndent = nFirstLineIndent;
+}
+void SvxNumberFormat::SetIndentAt( const tools::Long nIndentAt )
+{
+ mnIndentAt = nIndentAt;
+}
+
+Size SvxNumberFormat::GetGraphicSizeMM100(const Graphic* pGraphic)
+{
+ const MapMode aMapMM100( MapUnit::Map100thMM );
+ const Size& rSize = pGraphic->GetPrefSize();
+ Size aRetSize;
+ if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ {
+ OutputDevice* pOutDev = Application::GetDefaultDevice();
+ MapMode aOldMap( pOutDev->GetMapMode() );
+ pOutDev->SetMapMode( aMapMM100 );
+ aRetSize = pOutDev->PixelToLogic( rSize );
+ pOutDev->SetMapMode( aOldMap );
+ }
+ else
+ aRetSize = OutputDevice::LogicToLogic( rSize, pGraphic->GetPrefMapMode(), aMapMM100 );
+ return aRetSize;
+}
+
+OUString SvxNumberFormat::CreateRomanString( sal_Int32 nNo, bool bUpper )
+{
+ OUStringBuffer sRet;
+
+ constexpr char romans[][13] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
+ constexpr sal_Int32 values[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
+
+ for (size_t i = 0; i < std::size(romans); ++i)
+ {
+ while(nNo - values[i] >= 0)
+ {
+ sRet.appendAscii(romans[i]);
+ nNo -= values[i];
+ }
+ }
+
+ return bUpper ? sRet.makeStringAndClear()
+ : sRet.makeStringAndClear().toAsciiLowerCase();
+}
+
+void SvxNumberFormat::SetListFormat(const OUString& rPrefix, const OUString& rSuffix, int nLevel)
+{
+ sPrefix = rPrefix;
+ sSuffix = rSuffix;
+
+ // Generate list format
+ sListFormat = std::make_optional(sPrefix);
+
+ for (int i = 1; i <= nInclUpperLevels; i++)
+ {
+ int nLevelId = nLevel - nInclUpperLevels + i;
+ if (nLevelId < 0)
+ // There can be cases with current level 1, but request to show 10 upper levels. Trim it
+ continue;
+
+ *sListFormat += "%";
+ *sListFormat += OUString::number(nLevelId + 1);
+ *sListFormat += "%";
+ if (i != nInclUpperLevels)
+ *sListFormat += "."; // Default separator for older ODT
+ }
+
+ *sListFormat += sSuffix;
+}
+
+void SvxNumberFormat::SetListFormat(std::optional<OUString> oSet)
+{
+ sPrefix.clear();
+ sSuffix.clear();
+
+ if (!oSet.has_value())
+ {
+ return;
+ }
+
+ sListFormat = oSet;
+
+ // For backward compatibility and UI we should create something looking like
+ // a prefix, suffix and included levels also. This is not possible in general case
+ // since level format string is much more flexible. But for most cases is okay
+ sal_Int32 nFirstReplacement = sListFormat->indexOf('%');
+ sal_Int32 nLastReplacement = sListFormat->lastIndexOf('%') + 1;
+ if (nFirstReplacement > 0)
+ // Everything before first '%' will be prefix
+ sPrefix = sListFormat->copy(0, nFirstReplacement);
+ if (nLastReplacement >= 0 && nLastReplacement < sListFormat->getLength())
+ // Everything beyond last '%' is a suffix
+ sSuffix = sListFormat->copy(nLastReplacement);
+
+ sal_uInt8 nPercents = 0;
+ for (sal_Int32 i = 0; i < sListFormat->getLength(); i++)
+ {
+ if ((*sListFormat)[i] == '%')
+ nPercents++;
+ }
+ nInclUpperLevels = nPercents/2;
+ if (nInclUpperLevels < 1)
+ {
+ // There should be always at least one level. This will be not required
+ // in future (when we get rid of prefix/suffix), but nowadays there
+ // are too many conversions "list format" <-> "prefix/suffix/inclUpperLevel"
+ nInclUpperLevels = 1;
+ }
+}
+
+OUString SvxNumberFormat::GetListFormat(bool bIncludePrefixSuffix /*= true*/) const
+{
+ assert(sListFormat.has_value());
+
+ if (bIncludePrefixSuffix)
+ return *sListFormat;
+
+ // Strip prefix & suffix from string
+ return sListFormat->copy(sPrefix.getLength(), sListFormat->getLength() - sPrefix.getLength() - sSuffix.getLength());
+}
+
+OUString SvxNumberFormat::GetCharFormatName()const
+{
+ return sCharStyleName;
+}
+
+sal_Int32 SvxNumRule::nRefCount = 0;
+static SvxNumberFormat* pStdNumFmt = nullptr;
+static SvxNumberFormat* pStdOutlineNumFmt = nullptr;
+SvxNumRule::SvxNumRule( SvxNumRuleFlags nFeatures,
+ sal_uInt16 nLevels,
+ bool bCont,
+ SvxNumRuleType eType,
+ SvxNumberFormat::SvxNumPositionAndSpaceMode
+ eDefaultNumberFormatPositionAndSpaceMode )
+ : nLevelCount(nLevels),
+ nFeatureFlags(nFeatures),
+ eNumberingType(eType),
+ bContinuousNumbering(bCont)
+{
+ ++nRefCount;
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(i < nLevels)
+ {
+ aFmts[i].reset( new SvxNumberFormat(SVX_NUM_CHARS_UPPER_LETTER) );
+ // It is a distinction between writer and draw
+ if(nFeatures & SvxNumRuleFlags::CONTINUOUS)
+ {
+ if ( eDefaultNumberFormatPositionAndSpaceMode ==
+ SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+ {
+ aFmts[i]->SetAbsLSpace(o3tl::toTwips(DEF_WRITER_LSPACE * (i+1), o3tl::Length::mm100));
+ aFmts[i]->SetFirstLineOffset(o3tl::toTwips(-DEF_WRITER_LSPACE, o3tl::Length::mm100));
+ }
+ else if ( eDefaultNumberFormatPositionAndSpaceMode ==
+ SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ // first line indent of general numbering in inch: -0,25 inch
+ constexpr tools::Long cFirstLineIndent = o3tl::toTwips(-0.25, o3tl::Length::in);
+ // indent values of general numbering in inch:
+ // 0,5 0,75 1,0 1,25 1,5
+ // 1,75 2,0 2,25 2,5 2,75
+ constexpr tools::Long cIndentAt = o3tl::toTwips(0.25, o3tl::Length::in);
+ aFmts[i]->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT );
+ aFmts[i]->SetLabelFollowedBy( SvxNumberFormat::LISTTAB );
+ aFmts[i]->SetListtabPos( cIndentAt * (i+2) );
+ aFmts[i]->SetFirstLineIndent( cFirstLineIndent );
+ aFmts[i]->SetIndentAt( cIndentAt * (i+2) );
+ }
+ }
+ else
+ {
+ aFmts[i]->SetAbsLSpace( DEF_DRAW_LSPACE * i );
+ }
+ }
+ else
+ aFmts[i] = nullptr;
+ aFmtsSet[i] = false;
+ }
+}
+
+SvxNumRule::SvxNumRule(const SvxNumRule& rCopy)
+{
+ ++nRefCount;
+ nLevelCount = rCopy.nLevelCount ;
+ nFeatureFlags = rCopy.nFeatureFlags ;
+ bContinuousNumbering = rCopy.bContinuousNumbering;
+ eNumberingType = rCopy.eNumberingType;
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(rCopy.aFmts[i])
+ aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
+ else
+ aFmts[i].reset();
+ aFmtsSet[i] = rCopy.aFmtsSet[i];
+ }
+}
+
+SvxNumRule::SvxNumRule(SvxNumRule&& rCopy) noexcept
+{
+ ++nRefCount;
+ nLevelCount = rCopy.nLevelCount ;
+ nFeatureFlags = rCopy.nFeatureFlags ;
+ bContinuousNumbering = rCopy.bContinuousNumbering;
+ eNumberingType = rCopy.eNumberingType;
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(rCopy.aFmts[i])
+ aFmts[i] = std::move(rCopy.aFmts[i]);
+ aFmtsSet[i] = rCopy.aFmtsSet[i];
+ }
+}
+
+SvxNumRule::SvxNumRule( SvStream &rStream )
+ : nLevelCount(0)
+{
+ sal_uInt16 nTmp16(0);
+ rStream.ReadUInt16( nTmp16 ); // NUM_ITEM_VERSION
+ rStream.ReadUInt16( nLevelCount );
+
+ if (nLevelCount > SVX_MAX_NUM)
+ {
+ SAL_WARN("editeng", "nLevelCount: " << nLevelCount << " greater than max of: " << SVX_MAX_NUM);
+ nLevelCount = SVX_MAX_NUM;
+ }
+
+ // first nFeatureFlags of old Versions
+ rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
+ rStream.ReadUInt16( nTmp16 ); bContinuousNumbering = nTmp16;
+ rStream.ReadUInt16( nTmp16 ); eNumberingType = static_cast<SvxNumRuleType>(nTmp16);
+
+ for (sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ rStream.ReadUInt16( nTmp16 );
+ bool hasNumberingFormat = nTmp16 & 1;
+ aFmtsSet[i] = nTmp16 & 2; // fdo#68648 reset flag
+ if ( hasNumberingFormat ){
+ aFmts[i].reset( new SvxNumberFormat( rStream ) );
+ }
+ else
+ {
+ aFmts[i].reset();
+ aFmtsSet[i] = false; // actually only false is valid
+ }
+ }
+ //second nFeatureFlags for new versions
+ rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
+}
+
+void SvxNumRule::Store( SvStream &rStream )
+{
+ rStream.WriteUInt16( NUMITEM_VERSION_03 );
+ rStream.WriteUInt16( nLevelCount );
+ //first save of nFeatureFlags for old versions
+ rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
+ rStream.WriteUInt16( sal_uInt16(bContinuousNumbering) );
+ rStream.WriteUInt16( static_cast<sal_uInt16>(eNumberingType) );
+
+ FontToSubsFontConverter pConverter = nullptr;
+ bool bConvertBulletFont = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_50 ) && ( rStream.GetVersion() );
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ sal_uInt16 nSetFlag(aFmtsSet[i] ? 2 : 0); // fdo#68648 store that too
+ if(aFmts[i])
+ {
+ rStream.WriteUInt16( 1 | nSetFlag );
+ if(bConvertBulletFont && aFmts[i]->GetBulletFont())
+ {
+ if(!pConverter)
+ pConverter =
+ CreateFontToSubsFontConverter(aFmts[i]->GetBulletFont()->GetFamilyName(),
+ FontToSubsFontFlags::EXPORT);
+ }
+ aFmts[i]->Store(rStream, pConverter);
+ }
+ else
+ rStream.WriteUInt16( 0 | nSetFlag );
+ }
+ //second save of nFeatureFlags for new versions
+ rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
+}
+
+void SvxNumRule::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumRule"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("levelCount"), BAD_CAST(OString::number(nLevelCount).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("continuousNumbering"), BAD_CAST(OString::boolean(bContinuousNumbering).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("numberingType"), BAD_CAST(OString::number(static_cast<int>(eNumberingType)).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("featureFlags"), BAD_CAST(OString::number(static_cast<int>(nFeatureFlags)).getStr()));
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(aFmts[i])
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("aFmts"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("i"), BAD_CAST(OString::number(i).getStr()));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", aFmts[i].get());
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+ }
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+
+SvxNumRule::~SvxNumRule()
+{
+ if(!--nRefCount)
+ {
+ delete pStdNumFmt;
+ pStdNumFmt = nullptr;
+ delete pStdOutlineNumFmt;
+ pStdOutlineNumFmt = nullptr;
+ }
+}
+
+SvxNumRule& SvxNumRule::operator=( const SvxNumRule& rCopy )
+{
+ if (this != &rCopy)
+ {
+ nLevelCount = rCopy.nLevelCount;
+ nFeatureFlags = rCopy.nFeatureFlags;
+ bContinuousNumbering = rCopy.bContinuousNumbering;
+ eNumberingType = rCopy.eNumberingType;
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(rCopy.aFmts[i])
+ aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
+ else
+ aFmts[i].reset();
+ aFmtsSet[i] = rCopy.aFmtsSet[i];
+ }
+ }
+ return *this;
+}
+
+SvxNumRule& SvxNumRule::operator=( SvxNumRule&& rCopy ) noexcept
+{
+ if (this != &rCopy)
+ {
+ nLevelCount = rCopy.nLevelCount;
+ nFeatureFlags = rCopy.nFeatureFlags;
+ bContinuousNumbering = rCopy.bContinuousNumbering;
+ eNumberingType = rCopy.eNumberingType;
+ for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
+ {
+ if(rCopy.aFmts[i])
+ aFmts[i] = std::move(rCopy.aFmts[i]);
+ aFmtsSet[i] = rCopy.aFmtsSet[i];
+ }
+ }
+ return *this;
+}
+
+bool SvxNumRule::operator==( const SvxNumRule& rCopy) const
+{
+ if(nLevelCount != rCopy.nLevelCount ||
+ nFeatureFlags != rCopy.nFeatureFlags ||
+ bContinuousNumbering != rCopy.bContinuousNumbering ||
+ eNumberingType != rCopy.eNumberingType)
+ return false;
+ for(sal_uInt16 i = 0; i < nLevelCount; i++)
+ {
+ if (
+ (aFmtsSet[i] != rCopy.aFmtsSet[i]) ||
+ (!aFmts[i] && rCopy.aFmts[i]) ||
+ (aFmts[i] && !rCopy.aFmts[i]) ||
+ (aFmts[i] && *aFmts[i] != *rCopy.aFmts[i])
+ )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+const SvxNumberFormat* SvxNumRule::Get(sal_uInt16 nLevel)const
+{
+ DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
+ if( nLevel < SVX_MAX_NUM )
+ return aFmtsSet[nLevel] ? aFmts[nLevel].get() : nullptr;
+ else
+ return nullptr;
+}
+
+const SvxNumberFormat& SvxNumRule::GetLevel(sal_uInt16 nLevel)const
+{
+ if(!pStdNumFmt)
+ {
+ pStdNumFmt = new SvxNumberFormat(SVX_NUM_ARABIC);
+ pStdOutlineNumFmt = new SvxNumberFormat(SVX_NUM_NUMBER_NONE);
+ }
+
+ DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
+
+ return ( ( nLevel < SVX_MAX_NUM ) && aFmts[nLevel] ) ?
+ *aFmts[nLevel] : eNumberingType == SvxNumRuleType::NUMBERING ?
+ *pStdNumFmt : *pStdOutlineNumFmt;
+}
+
+void SvxNumRule::SetLevel( sal_uInt16 i, const SvxNumberFormat& rNumFmt, bool bIsValid )
+{
+ DBG_ASSERT(i < SVX_MAX_NUM, "Wrong Level" );
+
+ if( i >= SVX_MAX_NUM )
+ return;
+
+ bool bReplace = !aFmtsSet[i];
+ if (!bReplace)
+ {
+ const SvxNumberFormat *pFmt = Get(i);
+ bReplace = pFmt == nullptr || rNumFmt != *pFmt;
+ }
+
+ if (bReplace)
+ {
+ aFmts[i].reset( new SvxNumberFormat(rNumFmt) );
+ aFmtsSet[i] = bIsValid;
+ }
+}
+
+void SvxNumRule::SetLevel(sal_uInt16 nLevel, const SvxNumberFormat* pFmt)
+{
+ DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
+
+ if( nLevel < SVX_MAX_NUM )
+ {
+ aFmtsSet[nLevel] = nullptr != pFmt;
+ if(pFmt)
+ SetLevel(nLevel, *pFmt);
+ else
+ {
+ aFmts[nLevel].reset();
+ }
+ }
+}
+
+OUString SvxNumRule::MakeNumString( const SvxNodeNum& rNum ) const
+{
+ OUStringBuffer aStr;
+ if( SVX_NO_NUM > rNum.GetLevel() && !( SVX_NO_NUMLEVEL & rNum.GetLevel() ) )
+ {
+ const SvxNumberFormat& rMyNFmt = GetLevel( rNum.GetLevel() );
+ aStr.append(rMyNFmt.GetPrefix());
+ if( SVX_NUM_NUMBER_NONE != rMyNFmt.GetNumberingType() )
+ {
+ sal_uInt8 i = rNum.GetLevel();
+
+ if( !IsContinuousNumbering() &&
+ 1 < rMyNFmt.GetIncludeUpperLevels() ) // only on own level?
+ {
+ sal_uInt8 n = rMyNFmt.GetIncludeUpperLevels();
+ if( 1 < n )
+ {
+ if( i+1 >= n )
+ i -= n - 1;
+ else
+ i = 0;
+ }
+ }
+
+ for( ; i <= rNum.GetLevel(); ++i )
+ {
+ const SvxNumberFormat& rNFmt = GetLevel( i );
+ if( SVX_NUM_NUMBER_NONE == rNFmt.GetNumberingType() )
+ {
+ continue;
+ }
+
+ bool bDot = true;
+ if( rNum.GetLevelVal()[ i ] )
+ {
+ if(SVX_NUM_BITMAP != rNFmt.GetNumberingType())
+ {
+ const LanguageTag& rLang = Application::GetSettings().GetLanguageTag();
+ aStr.append(rNFmt.GetNumStr( rNum.GetLevelVal()[ i ], rLang.getLocale() ));
+ }
+ else
+ bDot = false;
+ }
+ else
+ aStr.append("0"); // all 0-levels are a 0
+ if( i != rNum.GetLevel() && bDot)
+ aStr.append(".");
+ }
+ }
+
+ aStr.append(rMyNFmt.GetSuffix());
+ }
+ return aStr.makeStringAndClear();
+}
+
+// changes linked to embedded bitmaps
+void SvxNumRule::UnLinkGraphics()
+{
+ for(sal_uInt16 i = 0; i < GetLevelCount(); i++)
+ {
+ SvxNumberFormat aFmt(GetLevel(i));
+ const SvxBrushItem* pBrush = aFmt.GetBrush();
+ if(SVX_NUM_BITMAP == aFmt.GetNumberingType())
+ {
+ if(pBrush && !pBrush->GetGraphicLink().isEmpty())
+ {
+ const Graphic* pGraphic = pBrush->GetGraphic();
+ if (pGraphic)
+ {
+ SvxBrushItem aTempItem(*pBrush);
+ aTempItem.SetGraphicLink("");
+ aTempItem.SetGraphic(*pGraphic);
+ sal_Int16 eOrient = aFmt.GetVertOrient();
+ aFmt.SetGraphicBrush( &aTempItem, &aFmt.GetGraphicSize(), &eOrient );
+ }
+ }
+ }
+ else if((SVX_NUM_BITMAP|LINK_TOKEN) == static_cast<int>(aFmt.GetNumberingType()))
+ aFmt.SetNumberingType(SVX_NUM_BITMAP);
+ SetLevel(i, aFmt);
+ }
+}
+
+SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule) :
+ SfxPoolItem(SID_ATTR_NUMBERING_RULE),
+ maNumRule(rRule)
+{
+}
+
+SvxNumBulletItem::SvxNumBulletItem(SvxNumRule && rRule) :
+ SfxPoolItem(SID_ATTR_NUMBERING_RULE),
+ maNumRule(std::move(rRule))
+{
+}
+
+SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule, sal_uInt16 _nWhich ) :
+ SfxPoolItem(_nWhich),
+ maNumRule(rRule)
+{
+}
+
+SvxNumBulletItem::SvxNumBulletItem(SvxNumRule && rRule, sal_uInt16 _nWhich ) :
+ SfxPoolItem(_nWhich),
+ maNumRule(std::move(rRule))
+{
+}
+
+SvxNumBulletItem::SvxNumBulletItem(const SvxNumBulletItem& rCopy) :
+ SfxPoolItem(rCopy),
+ maNumRule(rCopy.maNumRule)
+{
+}
+
+SvxNumBulletItem::~SvxNumBulletItem()
+{
+}
+
+bool SvxNumBulletItem::operator==( const SfxPoolItem& rCopy) const
+{
+ return SfxPoolItem::operator==(rCopy) &&
+ maNumRule == static_cast<const SvxNumBulletItem&>(rCopy).maNumRule;
+}
+
+SvxNumBulletItem* SvxNumBulletItem::Clone( SfxItemPool * ) const
+{
+ return new SvxNumBulletItem(*this);
+}
+
+bool SvxNumBulletItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
+{
+ rVal <<= SvxCreateNumRule( maNumRule );
+ return true;
+}
+
+bool SvxNumBulletItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
+{
+ uno::Reference< container::XIndexReplace > xRule;
+ if( rVal >>= xRule )
+ {
+ try
+ {
+ SvxNumRule aNewRule( SvxGetNumRule( xRule ) );
+ if( aNewRule.GetLevelCount() != maNumRule.GetLevelCount() ||
+ aNewRule.GetNumRuleType() != maNumRule.GetNumRuleType() )
+ {
+ aNewRule = SvxConvertNumRule( aNewRule, maNumRule.GetLevelCount(), maNumRule.GetNumRuleType() );
+ }
+ maNumRule = std::move( aNewRule );
+ return true;
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ }
+ }
+ return false;
+}
+
+void SvxNumBulletItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumBulletItem"));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+ maNumRule.dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
+SvxNumRule SvxConvertNumRule( const SvxNumRule& rRule, sal_uInt16 nLevels, SvxNumRuleType eType )
+{
+ const sal_uInt16 nSrcLevels = rRule.GetLevelCount();
+ SvxNumRule aNewRule(rRule.GetFeatureFlags(), nLevels, rRule.IsContinuousNumbering(), eType );
+
+ for( sal_uInt16 nLevel = 0; (nLevel < nLevels) && (nLevel < nSrcLevels); nLevel++ )
+ aNewRule.SetLevel( nLevel, rRule.GetLevel( nLevel ) );
+
+ return aNewRule;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */