1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
)
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
) :
95 SvxNumberType::SvxNumberType(const SvxNumberType
& rType
) :
96 nNumType(rType
.nNumType
),
97 bShowSymbol(rType
.bShowSymbol
)
102 SvxNumberType::~SvxNumberType()
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
);
126 case NumberingType::CHAR_SPECIAL
:
127 case NumberingType::BITMAP
:
131 // '0' allowed for ARABIC numberings
132 if(NumberingType::ARABIC
== nNumType
&& 0 == nNo
)
133 return OUString('0');
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
&)
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
),
170 cBullet(SVX_DEF_BULLET
),
172 nBulletColor(COL_BLACK
),
173 mePositionAndSpaceMode( LABEL_WIDTH_AND_POSITION
),
176 nCharTextDistance(0),
177 meLabelFollowedBy( LISTTAB
),
179 mnFirstLineIndent( 0 ),
181 eVertOrient(text::VertOrientation::NONE
)
185 SvxNumberFormat::SvxNumberFormat(const SvxNumberFormat
& rFormat
) :
186 SvxNumberType(rFormat
),
187 mePositionAndSpaceMode( rFormat
.mePositionAndSpaceMode
)
192 SvxNumberFormat::SvxNumberFormat( SvStream
&rStream
)
194 , nBulletRelSize(100)
195 , nFirstLineOffset(0)
197 , nCharTextDistance(0)
199 sal_uInt16
nTmp16(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
);
210 rStream
.ReadInt16( temp
);
211 nFirstLineOffset
= temp
;
213 rStream
.ReadInt16( 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
);
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
);
280 sal_Int16(std::clamp
<sal_Int32
>(nFirstLineOffset
, SAL_MIN_INT16
, SAL_MAX_INT16
)) );
281 //TODO: better way to handle out-of-bounds value?
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
);
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
);
307 rStream
.WriteUInt16( 0 );
309 rStream
.WriteUInt16( eVertOrient
);
312 rStream
.WriteUInt16( 1 );
313 WriteFont( rStream
, *pBulletFont
);
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
) );
367 if(rFormat
.pBulletFont
)
368 pBulletFont
= *rFormat
.pBulletFont
;
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
399 (pGraphicBrush
&& !rFormat
.pGraphicBrush
) ||
400 (!pGraphicBrush
&& rFormat
.pGraphicBrush
) ||
401 (pGraphicBrush
&& *pGraphicBrush
!= *rFormat
.pGraphicBrush
)
407 (pBulletFont
&& !rFormat
.pBulletFont
) ||
408 (!pBulletFont
&& rFormat
.pBulletFont
) ||
409 (pBulletFont
&& *pBulletFont
!= *rFormat
.pBulletFont
)
417 void SvxNumberFormat::SetGraphicBrush( const SvxBrushItem
* pBrushItem
,
418 const Size
* pSize
, const sal_Int16
* pOrient
)
421 pGraphicBrush
.reset();
422 else if ( !pGraphicBrush
|| (*pBrushItem
!= *pGraphicBrush
) )
423 pGraphicBrush
.reset(pBrushItem
->Clone());
426 eVertOrient
= *pOrient
;
428 eVertOrient
= text::VertOrientation::NONE
;
430 aGraphicSize
= *pSize
;
433 aGraphicSize
.setWidth(0);
434 aGraphicSize
.setHeight(0);
438 void SvxNumberFormat::SetGraphic( const OUString
& rName
)
440 if( pGraphicBrush
&& pGraphicBrush
->GetGraphicLink() == rName
)
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
456 void SvxNumberFormat::SetBulletFont(const vcl::Font
* pFont
)
459 pBulletFont
= *pFont
;
464 void SvxNumberFormat::SetPositionAndSpaceMode( SvxNumPositionAndSpaceMode ePositionAndSpaceMode
)
466 mePositionAndSpaceMode
= ePositionAndSpaceMode
;
469 sal_Int32
SvxNumberFormat::GetAbsLSpace() const
471 return mePositionAndSpaceMode
== LABEL_WIDTH_AND_POSITION
473 : static_cast<sal_Int32
>( GetFirstLineIndent() + GetIndentAt() );
475 sal_Int32
SvxNumberFormat::GetFirstLineOffset() const
477 return mePositionAndSpaceMode
== LABEL_WIDTH_AND_POSITION
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
)
502 // intentionally left blank.
505 SAL_WARN("editeng", "Unknown SvxNumberFormat::GetLabelFollowedBy() return value");
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();
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
);
538 aRetSize
= OutputDevice::LogicToLogic( rSize
, pGraphic
->GetPrefMapMode(), aMapMM100
);
542 OUString
SvxNumberFormat::CreateRomanString( sal_Int32 nNo
, bool bUpper
)
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
]);
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())
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())
580 void SvxNumberFormat::SetListFormat(const OUString
& rPrefix
, const OUString
& rSuffix
, int nLevel
)
585 // Generate list format
586 sListFormat
= std::make_optional(sPrefix
);
588 for (int i
= 1; i
<= nInclUpperLevels
; i
++)
590 int nLevelId
= nLevel
- nInclUpperLevels
+ i
;
592 // There can be cases with current level 1, but request to show 10 upper levels. Trim it
596 *sListFormat
+= OUString::number(nLevelId
+ 1);
598 if (i
!= nInclUpperLevels
)
599 *sListFormat
+= "."; // Default separator for older ODT
602 *sListFormat
+= sSuffix
;
605 void SvxNumberFormat::SetListFormat(std::optional
<OUString
> oSet
)
612 if (!oSet
.has_value())
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
] == '%')
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
)
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
,
667 SvxNumRuleType eType
,
668 SvxNumberFormat::SvxNumPositionAndSpaceMode
669 eDefaultNumberFormatPositionAndSpaceMode
)
670 : nLevelCount(nLevels
),
671 nFeatureFlags(nFeatures
),
672 eNumberingType(eType
),
673 bContinuousNumbering(bCont
)
676 for(sal_uInt16 i
= 0; i
< SVX_MAX_NUM
; i
++)
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) );
708 aFmts
[i
]->SetAbsLSpace( DEF_DRAW_LSPACE
* i
);
717 SvxNumRule::SvxNumRule(const SvxNumRule
& rCopy
)
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
++)
727 aFmts
[i
].reset( new SvxNumberFormat(*rCopy
.aFmts
[i
]) );
730 aFmtsSet
[i
] = rCopy
.aFmtsSet
[i
];
734 SvxNumRule::SvxNumRule(SvxNumRule
&& rCopy
) noexcept
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
++)
744 aFmts
[i
] = std::move(rCopy
.aFmts
[i
]);
745 aFmtsSet
[i
] = rCopy
.aFmtsSet
[i
];
749 SvxNumRule::SvxNumRule( SvStream
&rStream
)
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
) );
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
801 rStream
.WriteUInt16( 1 | nSetFlag
);
802 if(bConvertBulletFont
&& aFmts
[i
]->GetBulletFont())
806 CreateFontToSubsFontConverter(aFmts
[i
]->GetBulletFont()->GetFamilyName(),
807 FontToSubsFontFlags::EXPORT
);
809 aFmts
[i
]->Store(rStream
, pConverter
);
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
++)
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()
844 pStdNumFmt
= nullptr;
845 delete pStdOutlineNumFmt
;
846 pStdOutlineNumFmt
= nullptr;
850 SvxNumRule
& SvxNumRule::operator=( const SvxNumRule
& 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
++)
861 aFmts
[i
].reset( new SvxNumberFormat(*rCopy
.aFmts
[i
]) );
864 aFmtsSet
[i
] = rCopy
.aFmtsSet
[i
];
870 SvxNumRule
& SvxNumRule::operator=( SvxNumRule
&& rCopy
) noexcept
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
++)
881 aFmts
[i
] = std::move(rCopy
.aFmts
[i
]);
882 aFmtsSet
[i
] = rCopy
.aFmtsSet
[i
];
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
)
895 for(sal_uInt16 i
= 0; i
< nLevelCount
; i
++)
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
])
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;
919 const SvxNumberFormat
& SvxNumRule::GetLevel(sal_uInt16 nLevel
)const
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
)
941 bool bReplace
= !aFmtsSet
[i
];
944 const SvxNumberFormat
*pFmt
= Get(i
);
945 bReplace
= pFmt
== nullptr || rNumFmt
!= *pFmt
;
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
;
963 SetLevel(nLevel
, *pFmt
);
966 aFmts
[nLevel
].reset();
971 OUString
SvxNumRule::MakeNumString( const SvxNodeNum
& rNum
) const
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();
995 for( ; i
<= rNum
.GetLevel(); ++i
)
997 const SvxNumberFormat
& rNFmt
= GetLevel( i
);
998 if( SVX_NUM_NUMBER_NONE
== rNFmt
.GetNumberingType() )
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() ));
1015 aStr
.append("0"); // all 0-levels are a 0
1016 if( i
!= rNum
.GetLevel() && bDot
)
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();
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
);
1054 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule
const & rRule
) :
1055 SfxPoolItem(SID_ATTR_NUMBERING_RULE
),
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
),
1072 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule
&& rRule
, sal_uInt16 _nWhich
) :
1073 SfxPoolItem(_nWhich
),
1074 maNumRule(std::move(rRule
))
1078 SvxNumBulletItem::SvxNumBulletItem(const SvxNumBulletItem
& 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
);
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
);
1121 catch(const lang::IllegalArgumentException
&)
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
) );
1147 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */