bump product version to 7.6.3.2-android
[LibreOffice.git] / editeng / source / items / numitem.cxx
blobe8c1c4d9a77c0ae5ef35e5294ef682dca227ae0a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <algorithm>
24 #include <editeng/numitem.hxx>
26 #include <com/sun/star/text/VertOrientation.hpp>
27 #include <comphelper/propertyvalue.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <rtl/ustrbuf.hxx>
30 #include <vcl/font.hxx>
31 #include <vcl/settings.hxx>
32 #include <editeng/editids.hrc>
33 #include <editeng/numdef.hxx>
34 #include <vcl/graph.hxx>
35 #include <vcl/outdev.hxx>
36 #include <vcl/svapp.hxx>
37 #include <com/sun/star/text/XNumberingFormatter.hpp>
38 #include <com/sun/star/text/DefaultNumberingProvider.hpp>
39 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
40 #include <com/sun/star/style/NumberingType.hpp>
41 #include <com/sun/star/lang/IllegalArgumentException.hpp>
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <comphelper/fileformat.h>
44 #include <comphelper/processfactory.hxx>
45 #include <tools/mapunit.hxx>
46 #include <tools/stream.hxx>
47 #include <tools/debug.hxx>
48 #include <tools/GenericTypeSerializer.hxx>
49 #include <unotools/configmgr.hxx>
50 #include <libxml/xmlwriter.h>
51 #include <editeng/unonrule.hxx>
52 #include <sal/log.hxx>
53 #include <i18nlangtag/languagetag.hxx>
54 #include <editeng/legacyitem.hxx>
56 constexpr sal_Int32 DEF_WRITER_LSPACE = 500; //Standard Indentation
57 constexpr sal_Int32 DEF_DRAW_LSPACE = 800; //Standard Indentation
59 constexpr sal_uInt16 NUMITEM_VERSION_03 = 0x03;
60 constexpr sal_uInt16 NUMITEM_VERSION_04 = 0x04;
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::lang;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::text;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::style;
69 sal_Int32 SvxNumberType::nRefCount = 0;
70 css::uno::Reference<css::text::XNumberingFormatter> SvxNumberType::xFormatter;
71 static void lcl_getFormatter(css::uno::Reference<css::text::XNumberingFormatter>& _xFormatter)
73 if(_xFormatter.is())
74 return;
76 try
78 Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
79 Reference<XDefaultNumberingProvider> xRet = text::DefaultNumberingProvider::create(xContext);
80 _xFormatter.set(xRet, UNO_QUERY);
82 catch(const Exception&)
84 SAL_WARN("editeng", "service missing: \"com.sun.star.text.DefaultNumberingProvider\"");
88 SvxNumberType::SvxNumberType(SvxNumType nType) :
89 nNumType(nType),
90 bShowSymbol(true)
92 nRefCount++;
95 SvxNumberType::SvxNumberType(const SvxNumberType& rType) :
96 nNumType(rType.nNumType),
97 bShowSymbol(rType.bShowSymbol)
99 nRefCount++;
102 SvxNumberType::~SvxNumberType()
104 if(!--nRefCount)
105 xFormatter = nullptr;
108 OUString SvxNumberType::GetNumStr( sal_Int32 nNo ) const
110 LanguageTag aLang = utl::ConfigManager::IsFuzzing() ?
111 LanguageTag("en-US") :
112 Application::GetSettings().GetLanguageTag();
113 return GetNumStr( nNo, aLang.getLocale() );
116 OUString SvxNumberType::GetNumStr( sal_Int32 nNo, const css::lang::Locale& rLocale ) const
118 lcl_getFormatter(xFormatter);
119 if(!xFormatter.is())
120 return OUString();
122 if(bShowSymbol)
124 switch(nNumType)
126 case NumberingType::CHAR_SPECIAL:
127 case NumberingType::BITMAP:
128 break;
129 default:
131 // '0' allowed for ARABIC numberings
132 if(NumberingType::ARABIC == nNumType && 0 == nNo )
133 return OUString('0');
134 else
136 static constexpr OUStringLiteral sNumberingType = u"NumberingType";
137 static constexpr OUStringLiteral sValue = u"Value";
138 Sequence< PropertyValue > aProperties
140 comphelper::makePropertyValue(sNumberingType, static_cast<sal_uInt16>(nNumType)),
141 comphelper::makePropertyValue(sValue, nNo)
146 return xFormatter->makeNumberingString( aProperties, rLocale );
148 catch(const Exception&)
155 return OUString();
158 void SvxNumberType::dumpAsXml( xmlTextWriterPtr pWriter ) const
160 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumberType"));
161 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("NumType"), BAD_CAST(OString::number(nNumType).getStr()));
162 (void)xmlTextWriterEndElement(pWriter);
165 SvxNumberFormat::SvxNumberFormat( SvxNumType eType )
166 : SvxNumberType(eType),
167 eNumAdjust(SvxAdjust::Left),
168 nInclUpperLevels(1),
169 nStart(1),
170 cBullet(SVX_DEF_BULLET),
171 nBulletRelSize(100),
172 nBulletColor(COL_BLACK),
173 mePositionAndSpaceMode( LABEL_WIDTH_AND_POSITION ),
174 nFirstLineOffset(0),
175 nAbsLSpace(0),
176 nCharTextDistance(0),
177 meLabelFollowedBy( LISTTAB ),
178 mnListtabPos( 0 ),
179 mnFirstLineIndent( 0 ),
180 mnIndentAt( 0 ),
181 eVertOrient(text::VertOrientation::NONE)
185 SvxNumberFormat::SvxNumberFormat(const SvxNumberFormat& rFormat) :
186 SvxNumberType(rFormat),
187 mePositionAndSpaceMode( rFormat.mePositionAndSpaceMode )
189 *this = rFormat;
192 SvxNumberFormat::SvxNumberFormat( SvStream &rStream )
193 : nStart(0)
194 , nBulletRelSize(100)
195 , nFirstLineOffset(0)
196 , nAbsLSpace(0)
197 , nCharTextDistance(0)
199 sal_uInt16 nTmp16(0);
200 sal_Int32 nTmp32(0);
201 rStream.ReadUInt16( nTmp16 ); // Version number
203 rStream.ReadUInt16( nTmp16 ); SetNumberingType( static_cast<SvxNumType>(nTmp16) );
204 rStream.ReadUInt16( nTmp16 ); eNumAdjust = static_cast<SvxAdjust>(nTmp16);
205 rStream.ReadUInt16( nTmp16 ); nInclUpperLevels = nTmp16;
206 rStream.ReadUInt16( nStart );
207 rStream.ReadUInt16( nTmp16 ); cBullet = static_cast<sal_Unicode>(nTmp16);
209 sal_Int16 temp = 0;
210 rStream.ReadInt16( temp );
211 nFirstLineOffset = temp;
212 temp = 0;
213 rStream.ReadInt16( temp );
214 nAbsLSpace = temp;
215 rStream.SeekRel(2); //skip old now unused nLSpace;
217 rStream.ReadInt16( nCharTextDistance );
219 sPrefix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
220 sSuffix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
221 sCharStyleName = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
223 sal_uInt16 hasGraphicBrush = 0;
224 rStream.ReadUInt16( hasGraphicBrush );
225 if ( hasGraphicBrush )
227 pGraphicBrush.reset(new SvxBrushItem(SID_ATTR_BRUSH));
228 legacy::SvxBrush::Create(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
230 else pGraphicBrush = nullptr;
231 rStream.ReadUInt16( nTmp16 ); eVertOrient = nTmp16;
233 sal_uInt16 hasBulletFont = 0;
234 rStream.ReadUInt16( hasBulletFont );
235 if ( hasBulletFont )
237 pBulletFont.emplace();
238 ReadFont( rStream, *pBulletFont );
240 else pBulletFont.reset();
242 tools::GenericTypeSerializer aSerializer(rStream);
243 aSerializer.readSize(aGraphicSize);
244 aSerializer.readColor(nBulletColor);
246 rStream.ReadUInt16( nBulletRelSize );
247 rStream.ReadUInt16( nTmp16 ); SetShowSymbol( nTmp16 != 0 );
249 rStream.ReadUInt16( nTmp16 ); mePositionAndSpaceMode = static_cast<SvxNumPositionAndSpaceMode>(nTmp16);
250 rStream.ReadUInt16( nTmp16 ); meLabelFollowedBy = static_cast<LabelFollowedBy>(nTmp16);
251 rStream.ReadInt32( nTmp32 ); mnListtabPos = nTmp32;
252 rStream.ReadInt32( nTmp32 ); mnFirstLineIndent = nTmp32;
253 rStream.ReadInt32( nTmp32 ); mnIndentAt = nTmp32;
256 SvxNumberFormat::~SvxNumberFormat()
260 void SvxNumberFormat::Store(SvStream &rStream, FontToSubsFontConverter pConverter)
262 if(pConverter && pBulletFont)
264 cBullet = ConvertFontToSubsFontChar(pConverter, cBullet);
265 OUString sFontName = GetFontToSubsFontName(pConverter);
266 pBulletFont->SetFamilyName(sFontName);
269 tools::GenericTypeSerializer aSerializer(rStream);
271 rStream.WriteUInt16( NUMITEM_VERSION_04 );
273 rStream.WriteUInt16( GetNumberingType() );
274 rStream.WriteUInt16( static_cast<sal_uInt16>(eNumAdjust) );
275 rStream.WriteUInt16( nInclUpperLevels );
276 rStream.WriteUInt16( nStart );
277 rStream.WriteUInt16( cBullet );
279 rStream.WriteInt16(
280 sal_Int16(std::clamp<sal_Int32>(nFirstLineOffset, SAL_MIN_INT16, SAL_MAX_INT16)) );
281 //TODO: better way to handle out-of-bounds value?
282 rStream.WriteInt16(
283 sal_Int16(std::clamp<sal_Int32>(nAbsLSpace, SAL_MIN_INT16, SAL_MAX_INT16)) );
284 //TODO: better way to handle out-of-bounds value?
285 rStream.WriteInt16( 0 ); // write a dummy for old now unused nLSpace
287 rStream.WriteInt16( nCharTextDistance );
288 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
289 rStream.WriteUniOrByteString(sPrefix, eEnc);
290 rStream.WriteUniOrByteString(sSuffix, eEnc);
291 rStream.WriteUniOrByteString(sCharStyleName, eEnc);
292 if(pGraphicBrush)
294 rStream.WriteUInt16( 1 );
296 // in SD or SI force bullet itself to be stored,
297 // for that purpose throw away link when link and graphic
298 // are present, so Brush save is forced
299 if(!pGraphicBrush->GetGraphicLink().isEmpty() && pGraphicBrush->GetGraphic())
301 pGraphicBrush->SetGraphicLink("");
304 legacy::SvxBrush::Store(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
306 else
307 rStream.WriteUInt16( 0 );
309 rStream.WriteUInt16( eVertOrient );
310 if(pBulletFont)
312 rStream.WriteUInt16( 1 );
313 WriteFont( rStream, *pBulletFont );
315 else
316 rStream.WriteUInt16( 0 );
318 aSerializer.writeSize(aGraphicSize);
320 Color nTempColor = nBulletColor;
321 if(COL_AUTO == nBulletColor)
322 nTempColor = COL_BLACK;
324 aSerializer.writeColor(nTempColor);
325 rStream.WriteUInt16( nBulletRelSize );
326 rStream.WriteUInt16( sal_uInt16(IsShowSymbol()) );
328 rStream.WriteUInt16( mePositionAndSpaceMode );
329 rStream.WriteUInt16( meLabelFollowedBy );
330 rStream.WriteInt32( mnListtabPos );
331 rStream.WriteInt32( mnFirstLineIndent );
332 rStream.WriteInt32( mnIndentAt );
335 SvxNumberFormat& SvxNumberFormat::operator=( const SvxNumberFormat& rFormat )
337 if (& rFormat == this) { return *this; }
339 SvxNumberType::SetNumberingType(rFormat.GetNumberingType());
340 eNumAdjust = rFormat.eNumAdjust ;
341 nInclUpperLevels = rFormat.nInclUpperLevels ;
342 nStart = rFormat.nStart ;
343 cBullet = rFormat.cBullet ;
344 mePositionAndSpaceMode = rFormat.mePositionAndSpaceMode;
345 nFirstLineOffset = rFormat.nFirstLineOffset;
346 nAbsLSpace = rFormat.nAbsLSpace ;
347 nCharTextDistance = rFormat.nCharTextDistance ;
348 meLabelFollowedBy = rFormat.meLabelFollowedBy;
349 mnListtabPos = rFormat.mnListtabPos;
350 mnFirstLineIndent = rFormat.mnFirstLineIndent;
351 mnIndentAt = rFormat.mnIndentAt;
352 eVertOrient = rFormat.eVertOrient;
353 sPrefix = rFormat.sPrefix;
354 sSuffix = rFormat.sSuffix;
355 sListFormat = rFormat.sListFormat;
356 aGraphicSize = rFormat.aGraphicSize ;
357 nBulletColor = rFormat.nBulletColor ;
358 nBulletRelSize = rFormat.nBulletRelSize;
359 SetShowSymbol(rFormat.IsShowSymbol());
360 sCharStyleName = rFormat.sCharStyleName;
361 pGraphicBrush.reset();
362 if(rFormat.pGraphicBrush)
364 pGraphicBrush.reset( new SvxBrushItem(*rFormat.pGraphicBrush) );
366 pBulletFont.reset();
367 if(rFormat.pBulletFont)
368 pBulletFont = *rFormat.pBulletFont;
369 return *this;
372 bool SvxNumberFormat::operator==( const SvxNumberFormat& rFormat) const
374 if( GetNumberingType() != rFormat.GetNumberingType() ||
375 eNumAdjust != rFormat.eNumAdjust ||
376 nInclUpperLevels != rFormat.nInclUpperLevels ||
377 nStart != rFormat.nStart ||
378 cBullet != rFormat.cBullet ||
379 mePositionAndSpaceMode != rFormat.mePositionAndSpaceMode ||
380 nFirstLineOffset != rFormat.nFirstLineOffset ||
381 nAbsLSpace != rFormat.nAbsLSpace ||
382 nCharTextDistance != rFormat.nCharTextDistance ||
383 meLabelFollowedBy != rFormat.meLabelFollowedBy ||
384 mnListtabPos != rFormat.mnListtabPos ||
385 mnFirstLineIndent != rFormat.mnFirstLineIndent ||
386 mnIndentAt != rFormat.mnIndentAt ||
387 eVertOrient != rFormat.eVertOrient ||
388 sPrefix != rFormat.sPrefix ||
389 sSuffix != rFormat.sSuffix ||
390 sListFormat != rFormat.sListFormat ||
391 aGraphicSize != rFormat.aGraphicSize ||
392 nBulletColor != rFormat.nBulletColor ||
393 nBulletRelSize != rFormat.nBulletRelSize ||
394 IsShowSymbol() != rFormat.IsShowSymbol() ||
395 sCharStyleName != rFormat.sCharStyleName
397 return false;
398 if (
399 (pGraphicBrush && !rFormat.pGraphicBrush) ||
400 (!pGraphicBrush && rFormat.pGraphicBrush) ||
401 (pGraphicBrush && *pGraphicBrush != *rFormat.pGraphicBrush)
404 return false;
406 if (
407 (pBulletFont && !rFormat.pBulletFont) ||
408 (!pBulletFont && rFormat.pBulletFont) ||
409 (pBulletFont && *pBulletFont != *rFormat.pBulletFont)
412 return false;
414 return true;
417 void SvxNumberFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem,
418 const Size* pSize, const sal_Int16* pOrient)
420 if (!pBrushItem)
421 pGraphicBrush.reset();
422 else if ( !pGraphicBrush || (*pBrushItem != *pGraphicBrush) )
423 pGraphicBrush.reset(pBrushItem->Clone());
425 if(pOrient)
426 eVertOrient = *pOrient;
427 else
428 eVertOrient = text::VertOrientation::NONE;
429 if(pSize)
430 aGraphicSize = *pSize;
431 else
433 aGraphicSize.setWidth(0);
434 aGraphicSize.setHeight(0);
438 void SvxNumberFormat::SetGraphic( const OUString& rName )
440 if( pGraphicBrush && pGraphicBrush->GetGraphicLink() == rName )
441 return ;
443 pGraphicBrush.reset( new SvxBrushItem( rName, "", GPOS_AREA, 0 ) );
444 if( eVertOrient == text::VertOrientation::NONE )
445 eVertOrient = text::VertOrientation::TOP;
447 aGraphicSize.setWidth(0);
448 aGraphicSize.setHeight(0);
451 sal_Int16 SvxNumberFormat::GetVertOrient() const
453 return eVertOrient;
456 void SvxNumberFormat::SetBulletFont(const vcl::Font* pFont)
458 if (pFont)
459 pBulletFont = *pFont;
460 else
461 pBulletFont.reset();
464 void SvxNumberFormat::SetPositionAndSpaceMode( SvxNumPositionAndSpaceMode ePositionAndSpaceMode )
466 mePositionAndSpaceMode = ePositionAndSpaceMode;
469 sal_Int32 SvxNumberFormat::GetAbsLSpace() const
471 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
472 ? nAbsLSpace
473 : static_cast<sal_Int32>( GetFirstLineIndent() + GetIndentAt() );
475 sal_Int32 SvxNumberFormat::GetFirstLineOffset() const
477 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
478 ? nFirstLineOffset
479 : static_cast<sal_Int32>( GetFirstLineIndent() );
481 short SvxNumberFormat::GetCharTextDistance() const
483 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION ? nCharTextDistance : 0;
486 void SvxNumberFormat::SetLabelFollowedBy( const LabelFollowedBy eLabelFollowedBy )
488 meLabelFollowedBy = eLabelFollowedBy;
491 OUString SvxNumberFormat::GetLabelFollowedByAsString() const
493 switch (meLabelFollowedBy)
495 case LISTTAB:
496 return "\t";
497 case SPACE:
498 return " ";
499 case NEWLINE:
500 return "\n";
501 case NOTHING:
502 // intentionally left blank.
503 return OUString();
504 default:
505 SAL_WARN("editeng", "Unknown SvxNumberFormat::GetLabelFollowedBy() return value");
506 assert(false);
508 return OUString();
511 void SvxNumberFormat::SetListtabPos( const tools::Long nListtabPos )
513 mnListtabPos = nListtabPos;
515 void SvxNumberFormat::SetFirstLineIndent( const tools::Long nFirstLineIndent )
517 mnFirstLineIndent = nFirstLineIndent;
519 void SvxNumberFormat::SetIndentAt( const tools::Long nIndentAt )
521 mnIndentAt = nIndentAt;
524 Size SvxNumberFormat::GetGraphicSizeMM100(const Graphic* pGraphic)
526 const MapMode aMapMM100( MapUnit::Map100thMM );
527 const Size& rSize = pGraphic->GetPrefSize();
528 Size aRetSize;
529 if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
531 OutputDevice* pOutDev = Application::GetDefaultDevice();
532 MapMode aOldMap( pOutDev->GetMapMode() );
533 pOutDev->SetMapMode( aMapMM100 );
534 aRetSize = pOutDev->PixelToLogic( rSize );
535 pOutDev->SetMapMode( aOldMap );
537 else
538 aRetSize = OutputDevice::LogicToLogic( rSize, pGraphic->GetPrefMapMode(), aMapMM100 );
539 return aRetSize;
542 OUString SvxNumberFormat::CreateRomanString( sal_Int32 nNo, bool bUpper )
544 OUStringBuffer sRet;
546 constexpr char romans[][13] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
547 constexpr sal_Int32 values[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
549 for (size_t i = 0; i < std::size(romans); ++i)
551 while(nNo - values[i] >= 0)
553 sRet.appendAscii(romans[i]);
554 nNo -= values[i];
558 return bUpper ? sRet.makeStringAndClear()
559 : sRet.makeStringAndClear().toAsciiLowerCase();
562 void SvxNumberFormat::SetPrefix(const OUString& rSet)
564 // ListFormat manages the prefix. If badly changed via this function, sListFormat is invalidated
565 if (sListFormat && rSet.getLength() != sPrefix.getLength())
566 sListFormat.reset();
568 sPrefix = rSet;
571 void SvxNumberFormat::SetSuffix(const OUString& rSet)
573 // ListFormat manages the suffix. If badly changed via this function, sListFormat is invalidated
574 if (sListFormat && rSet.getLength() != sSuffix.getLength())
575 sListFormat.reset();
577 sSuffix = rSet;
580 void SvxNumberFormat::SetListFormat(const OUString& rPrefix, const OUString& rSuffix, int nLevel)
582 sPrefix = rPrefix;
583 sSuffix = rSuffix;
585 // Generate list format
586 sListFormat = std::make_optional(sPrefix);
588 for (int i = 1; i <= nInclUpperLevels; i++)
590 int nLevelId = nLevel - nInclUpperLevels + i;
591 if (nLevelId < 0)
592 // There can be cases with current level 1, but request to show 10 upper levels. Trim it
593 continue;
595 *sListFormat += "%";
596 *sListFormat += OUString::number(nLevelId + 1);
597 *sListFormat += "%";
598 if (i != nInclUpperLevels)
599 *sListFormat += "."; // Default separator for older ODT
602 *sListFormat += sSuffix;
605 void SvxNumberFormat::SetListFormat(std::optional<OUString> oSet)
607 sPrefix.clear();
608 sSuffix.clear();
610 sListFormat = oSet;
612 if (!oSet.has_value())
614 return;
617 // For backward compatibility and UI we should create something looking like
618 // a prefix, suffix and included levels also. This is not possible in general case
619 // since level format string is much more flexible. But for most cases is okay
620 sal_Int32 nFirstReplacement = sListFormat->indexOf('%');
621 sal_Int32 nLastReplacement = sListFormat->lastIndexOf('%') + 1;
622 if (nFirstReplacement > 0)
623 // Everything before first '%' will be prefix
624 sPrefix = sListFormat->copy(0, nFirstReplacement);
625 if (nLastReplacement >= 0 && nLastReplacement < sListFormat->getLength())
626 // Everything beyond last '%' is a suffix
627 sSuffix = sListFormat->copy(nLastReplacement);
629 sal_uInt8 nPercents = 0;
630 for (sal_Int32 i = 0; i < sListFormat->getLength(); i++)
632 if ((*sListFormat)[i] == '%')
633 nPercents++;
635 nInclUpperLevels = nPercents/2;
636 if (nInclUpperLevels < 1)
638 // There should be always at least one level. This will be not required
639 // in future (when we get rid of prefix/suffix), but nowadays there
640 // are too many conversions "list format" <-> "prefix/suffix/inclUpperLevel"
641 nInclUpperLevels = 1;
645 OUString SvxNumberFormat::GetListFormat(bool bIncludePrefixSuffix /*= true*/) const
647 assert(sListFormat.has_value());
649 if (bIncludePrefixSuffix)
650 return *sListFormat;
652 // Strip prefix & suffix from string
653 return sListFormat->copy(sPrefix.getLength(), sListFormat->getLength() - sPrefix.getLength() - sSuffix.getLength());
656 OUString SvxNumberFormat::GetCharFormatName()const
658 return sCharStyleName;
661 sal_Int32 SvxNumRule::nRefCount = 0;
662 static SvxNumberFormat* pStdNumFmt = nullptr;
663 static SvxNumberFormat* pStdOutlineNumFmt = nullptr;
664 SvxNumRule::SvxNumRule( SvxNumRuleFlags nFeatures,
665 sal_uInt16 nLevels,
666 bool bCont,
667 SvxNumRuleType eType,
668 SvxNumberFormat::SvxNumPositionAndSpaceMode
669 eDefaultNumberFormatPositionAndSpaceMode )
670 : nLevelCount(nLevels),
671 nFeatureFlags(nFeatures),
672 eNumberingType(eType),
673 bContinuousNumbering(bCont)
675 ++nRefCount;
676 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
678 if(i < nLevels)
680 aFmts[i].reset( new SvxNumberFormat(SVX_NUM_CHARS_UPPER_LETTER) );
681 // It is a distinction between writer and draw
682 if(nFeatures & SvxNumRuleFlags::CONTINUOUS)
684 if ( eDefaultNumberFormatPositionAndSpaceMode ==
685 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
687 aFmts[i]->SetAbsLSpace(o3tl::toTwips(DEF_WRITER_LSPACE * (i+1), o3tl::Length::mm100));
688 aFmts[i]->SetFirstLineOffset(o3tl::toTwips(-DEF_WRITER_LSPACE, o3tl::Length::mm100));
690 else if ( eDefaultNumberFormatPositionAndSpaceMode ==
691 SvxNumberFormat::LABEL_ALIGNMENT )
693 // first line indent of general numbering in inch: -0,25 inch
694 constexpr tools::Long cFirstLineIndent = o3tl::toTwips(-0.25, o3tl::Length::in);
695 // indent values of general numbering in inch:
696 // 0,5 0,75 1,0 1,25 1,5
697 // 1,75 2,0 2,25 2,5 2,75
698 constexpr tools::Long cIndentAt = o3tl::toTwips(0.25, o3tl::Length::in);
699 aFmts[i]->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT );
700 aFmts[i]->SetLabelFollowedBy( SvxNumberFormat::LISTTAB );
701 aFmts[i]->SetListtabPos( cIndentAt * (i+2) );
702 aFmts[i]->SetFirstLineIndent( cFirstLineIndent );
703 aFmts[i]->SetIndentAt( cIndentAt * (i+2) );
706 else
708 aFmts[i]->SetAbsLSpace( DEF_DRAW_LSPACE * i );
711 else
712 aFmts[i] = nullptr;
713 aFmtsSet[i] = false;
717 SvxNumRule::SvxNumRule(const SvxNumRule& rCopy)
719 ++nRefCount;
720 nLevelCount = rCopy.nLevelCount ;
721 nFeatureFlags = rCopy.nFeatureFlags ;
722 bContinuousNumbering = rCopy.bContinuousNumbering;
723 eNumberingType = rCopy.eNumberingType;
724 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
726 if(rCopy.aFmts[i])
727 aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
728 else
729 aFmts[i].reset();
730 aFmtsSet[i] = rCopy.aFmtsSet[i];
734 SvxNumRule::SvxNumRule(SvxNumRule&& rCopy) noexcept
736 ++nRefCount;
737 nLevelCount = rCopy.nLevelCount ;
738 nFeatureFlags = rCopy.nFeatureFlags ;
739 bContinuousNumbering = rCopy.bContinuousNumbering;
740 eNumberingType = rCopy.eNumberingType;
741 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
743 if(rCopy.aFmts[i])
744 aFmts[i] = std::move(rCopy.aFmts[i]);
745 aFmtsSet[i] = rCopy.aFmtsSet[i];
749 SvxNumRule::SvxNumRule( SvStream &rStream )
750 : nLevelCount(0)
752 sal_uInt16 nTmp16(0);
753 rStream.ReadUInt16( nTmp16 ); // NUM_ITEM_VERSION
754 rStream.ReadUInt16( nLevelCount );
756 if (nLevelCount > SVX_MAX_NUM)
758 SAL_WARN("editeng", "nLevelCount: " << nLevelCount << " greater than max of: " << SVX_MAX_NUM);
759 nLevelCount = SVX_MAX_NUM;
762 // first nFeatureFlags of old Versions
763 rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
764 rStream.ReadUInt16( nTmp16 ); bContinuousNumbering = nTmp16;
765 rStream.ReadUInt16( nTmp16 ); eNumberingType = static_cast<SvxNumRuleType>(nTmp16);
767 for (sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
769 rStream.ReadUInt16( nTmp16 );
770 bool hasNumberingFormat = nTmp16 & 1;
771 aFmtsSet[i] = nTmp16 & 2; // fdo#68648 reset flag
772 if ( hasNumberingFormat ){
773 aFmts[i].reset( new SvxNumberFormat( rStream ) );
775 else
777 aFmts[i].reset();
778 aFmtsSet[i] = false; // actually only false is valid
781 //second nFeatureFlags for new versions
782 rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
785 void SvxNumRule::Store( SvStream &rStream )
787 rStream.WriteUInt16( NUMITEM_VERSION_03 );
788 rStream.WriteUInt16( nLevelCount );
789 //first save of nFeatureFlags for old versions
790 rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
791 rStream.WriteUInt16( sal_uInt16(bContinuousNumbering) );
792 rStream.WriteUInt16( static_cast<sal_uInt16>(eNumberingType) );
794 FontToSubsFontConverter pConverter = nullptr;
795 bool bConvertBulletFont = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_50 ) && ( rStream.GetVersion() );
796 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
798 sal_uInt16 nSetFlag(aFmtsSet[i] ? 2 : 0); // fdo#68648 store that too
799 if(aFmts[i])
801 rStream.WriteUInt16( 1 | nSetFlag );
802 if(bConvertBulletFont && aFmts[i]->GetBulletFont())
804 if(!pConverter)
805 pConverter =
806 CreateFontToSubsFontConverter(aFmts[i]->GetBulletFont()->GetFamilyName(),
807 FontToSubsFontFlags::EXPORT);
809 aFmts[i]->Store(rStream, pConverter);
811 else
812 rStream.WriteUInt16( 0 | nSetFlag );
814 //second save of nFeatureFlags for new versions
815 rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
818 void SvxNumRule::dumpAsXml(xmlTextWriterPtr pWriter) const
820 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumRule"));
821 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("levelCount"), BAD_CAST(OString::number(nLevelCount).getStr()));
822 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("continuousNumbering"), BAD_CAST(OString::boolean(bContinuousNumbering).getStr()));
823 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("numberingType"), BAD_CAST(OString::number(static_cast<int>(eNumberingType)).getStr()));
824 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("featureFlags"), BAD_CAST(OString::number(static_cast<int>(nFeatureFlags)).getStr()));
825 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
827 if(aFmts[i])
829 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("aFmts"));
830 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("i"), BAD_CAST(OString::number(i).getStr()));
831 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", aFmts[i].get());
832 (void)xmlTextWriterEndElement(pWriter);
835 (void)xmlTextWriterEndElement(pWriter);
839 SvxNumRule::~SvxNumRule()
841 if(!--nRefCount)
843 delete pStdNumFmt;
844 pStdNumFmt = nullptr;
845 delete pStdOutlineNumFmt;
846 pStdOutlineNumFmt = nullptr;
850 SvxNumRule& SvxNumRule::operator=( const SvxNumRule& rCopy )
852 if (this != &rCopy)
854 nLevelCount = rCopy.nLevelCount;
855 nFeatureFlags = rCopy.nFeatureFlags;
856 bContinuousNumbering = rCopy.bContinuousNumbering;
857 eNumberingType = rCopy.eNumberingType;
858 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
860 if(rCopy.aFmts[i])
861 aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
862 else
863 aFmts[i].reset();
864 aFmtsSet[i] = rCopy.aFmtsSet[i];
867 return *this;
870 SvxNumRule& SvxNumRule::operator=( SvxNumRule&& rCopy ) noexcept
872 if (this != &rCopy)
874 nLevelCount = rCopy.nLevelCount;
875 nFeatureFlags = rCopy.nFeatureFlags;
876 bContinuousNumbering = rCopy.bContinuousNumbering;
877 eNumberingType = rCopy.eNumberingType;
878 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
880 if(rCopy.aFmts[i])
881 aFmts[i] = std::move(rCopy.aFmts[i]);
882 aFmtsSet[i] = rCopy.aFmtsSet[i];
885 return *this;
888 bool SvxNumRule::operator==( const SvxNumRule& rCopy) const
890 if(nLevelCount != rCopy.nLevelCount ||
891 nFeatureFlags != rCopy.nFeatureFlags ||
892 bContinuousNumbering != rCopy.bContinuousNumbering ||
893 eNumberingType != rCopy.eNumberingType)
894 return false;
895 for(sal_uInt16 i = 0; i < nLevelCount; i++)
897 if (
898 (aFmtsSet[i] != rCopy.aFmtsSet[i]) ||
899 (!aFmts[i] && rCopy.aFmts[i]) ||
900 (aFmts[i] && !rCopy.aFmts[i]) ||
901 (aFmts[i] && *aFmts[i] != *rCopy.aFmts[i])
904 return false;
907 return true;
910 const SvxNumberFormat* SvxNumRule::Get(sal_uInt16 nLevel)const
912 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
913 if( nLevel < SVX_MAX_NUM )
914 return aFmtsSet[nLevel] ? aFmts[nLevel].get() : nullptr;
915 else
916 return nullptr;
919 const SvxNumberFormat& SvxNumRule::GetLevel(sal_uInt16 nLevel)const
921 if(!pStdNumFmt)
923 pStdNumFmt = new SvxNumberFormat(SVX_NUM_ARABIC);
924 pStdOutlineNumFmt = new SvxNumberFormat(SVX_NUM_NUMBER_NONE);
927 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
929 return ( ( nLevel < SVX_MAX_NUM ) && aFmts[nLevel] ) ?
930 *aFmts[nLevel] : eNumberingType == SvxNumRuleType::NUMBERING ?
931 *pStdNumFmt : *pStdOutlineNumFmt;
934 void SvxNumRule::SetLevel( sal_uInt16 i, const SvxNumberFormat& rNumFmt, bool bIsValid )
936 DBG_ASSERT(i < SVX_MAX_NUM, "Wrong Level" );
938 if( i >= SVX_MAX_NUM )
939 return;
941 bool bReplace = !aFmtsSet[i];
942 if (!bReplace)
944 const SvxNumberFormat *pFmt = Get(i);
945 bReplace = pFmt == nullptr || rNumFmt != *pFmt;
948 if (bReplace)
950 aFmts[i].reset( new SvxNumberFormat(rNumFmt) );
951 aFmtsSet[i] = bIsValid;
955 void SvxNumRule::SetLevel(sal_uInt16 nLevel, const SvxNumberFormat* pFmt)
957 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
959 if( nLevel < SVX_MAX_NUM )
961 aFmtsSet[nLevel] = nullptr != pFmt;
962 if(pFmt)
963 SetLevel(nLevel, *pFmt);
964 else
966 aFmts[nLevel].reset();
971 OUString SvxNumRule::MakeNumString( const SvxNodeNum& rNum ) const
973 OUStringBuffer aStr;
974 if( SVX_NO_NUM > rNum.GetLevel() && !( SVX_NO_NUMLEVEL & rNum.GetLevel() ) )
976 const SvxNumberFormat& rMyNFmt = GetLevel( rNum.GetLevel() );
977 aStr.append(rMyNFmt.GetPrefix());
978 if( SVX_NUM_NUMBER_NONE != rMyNFmt.GetNumberingType() )
980 sal_uInt8 i = rNum.GetLevel();
982 if( !IsContinuousNumbering() &&
983 1 < rMyNFmt.GetIncludeUpperLevels() ) // only on own level?
985 sal_uInt8 n = rMyNFmt.GetIncludeUpperLevels();
986 if( 1 < n )
988 if( i+1 >= n )
989 i -= n - 1;
990 else
991 i = 0;
995 for( ; i <= rNum.GetLevel(); ++i )
997 const SvxNumberFormat& rNFmt = GetLevel( i );
998 if( SVX_NUM_NUMBER_NONE == rNFmt.GetNumberingType() )
1000 continue;
1003 bool bDot = true;
1004 if( rNum.GetLevelVal()[ i ] )
1006 if(SVX_NUM_BITMAP != rNFmt.GetNumberingType())
1008 const LanguageTag& rLang = Application::GetSettings().GetLanguageTag();
1009 aStr.append(rNFmt.GetNumStr( rNum.GetLevelVal()[ i ], rLang.getLocale() ));
1011 else
1012 bDot = false;
1014 else
1015 aStr.append("0"); // all 0-levels are a 0
1016 if( i != rNum.GetLevel() && bDot)
1017 aStr.append(".");
1021 aStr.append(rMyNFmt.GetSuffix());
1023 return aStr.makeStringAndClear();
1026 // changes linked to embedded bitmaps
1027 void SvxNumRule::UnLinkGraphics()
1029 for(sal_uInt16 i = 0; i < GetLevelCount(); i++)
1031 SvxNumberFormat aFmt(GetLevel(i));
1032 const SvxBrushItem* pBrush = aFmt.GetBrush();
1033 if(SVX_NUM_BITMAP == aFmt.GetNumberingType())
1035 if(pBrush && !pBrush->GetGraphicLink().isEmpty())
1037 const Graphic* pGraphic = pBrush->GetGraphic();
1038 if (pGraphic)
1040 SvxBrushItem aTempItem(*pBrush);
1041 aTempItem.SetGraphicLink("");
1042 aTempItem.SetGraphic(*pGraphic);
1043 sal_Int16 eOrient = aFmt.GetVertOrient();
1044 aFmt.SetGraphicBrush( &aTempItem, &aFmt.GetGraphicSize(), &eOrient );
1048 else if((SVX_NUM_BITMAP|LINK_TOKEN) == static_cast<int>(aFmt.GetNumberingType()))
1049 aFmt.SetNumberingType(SVX_NUM_BITMAP);
1050 SetLevel(i, aFmt);
1054 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule) :
1055 SfxPoolItem(SID_ATTR_NUMBERING_RULE),
1056 maNumRule(rRule)
1060 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule && rRule) :
1061 SfxPoolItem(SID_ATTR_NUMBERING_RULE),
1062 maNumRule(std::move(rRule))
1066 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule, sal_uInt16 _nWhich ) :
1067 SfxPoolItem(_nWhich),
1068 maNumRule(rRule)
1072 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule && rRule, sal_uInt16 _nWhich ) :
1073 SfxPoolItem(_nWhich),
1074 maNumRule(std::move(rRule))
1078 SvxNumBulletItem::SvxNumBulletItem(const SvxNumBulletItem& rCopy) :
1079 SfxPoolItem(rCopy),
1080 maNumRule(rCopy.maNumRule)
1084 SvxNumBulletItem::~SvxNumBulletItem()
1088 bool SvxNumBulletItem::operator==( const SfxPoolItem& rCopy) const
1090 return SfxPoolItem::operator==(rCopy) &&
1091 maNumRule == static_cast<const SvxNumBulletItem&>(rCopy).maNumRule;
1094 SvxNumBulletItem* SvxNumBulletItem::Clone( SfxItemPool * ) const
1096 return new SvxNumBulletItem(*this);
1099 bool SvxNumBulletItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
1101 rVal <<= SvxCreateNumRule( maNumRule );
1102 return true;
1105 bool SvxNumBulletItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
1107 uno::Reference< container::XIndexReplace > xRule;
1108 if( rVal >>= xRule )
1112 SvxNumRule aNewRule( SvxGetNumRule( xRule ) );
1113 if( aNewRule.GetLevelCount() != maNumRule.GetLevelCount() ||
1114 aNewRule.GetNumRuleType() != maNumRule.GetNumRuleType() )
1116 aNewRule = SvxConvertNumRule( aNewRule, maNumRule.GetLevelCount(), maNumRule.GetNumRuleType() );
1118 maNumRule = std::move( aNewRule );
1119 return true;
1121 catch(const lang::IllegalArgumentException&)
1125 return false;
1128 void SvxNumBulletItem::dumpAsXml(xmlTextWriterPtr pWriter) const
1130 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumBulletItem"));
1131 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
1132 maNumRule.dumpAsXml(pWriter);
1133 (void)xmlTextWriterEndElement(pWriter);
1136 SvxNumRule SvxConvertNumRule( const SvxNumRule& rRule, sal_uInt16 nLevels, SvxNumRuleType eType )
1138 const sal_uInt16 nSrcLevels = rRule.GetLevelCount();
1139 SvxNumRule aNewRule(rRule.GetFeatureFlags(), nLevels, rRule.IsContinuousNumbering(), eType );
1141 for( sal_uInt16 nLevel = 0; (nLevel < nLevels) && (nLevel < nSrcLevels); nLevel++ )
1142 aNewRule.SetLevel( nLevel, rRule.GetLevel( nLevel ) );
1144 return aNewRule;
1147 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */