bump product version to 6.4.0.3
[LibreOffice.git] / editeng / source / items / numitem.cxx
blob67cf0373cc373757dae5b03f08e734dbfd377860
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/HoriOrientation.hpp>
27 #include <com/sun/star/text/VertOrientation.hpp>
28 #include <com/sun/star/text/RelOrientation.hpp>
29 #include <editeng/brushitem.hxx>
30 #include <vcl/font.hxx>
31 #include <vcl/settings.hxx>
32 #include <editeng/editids.hrc>
33 #include <editeng/numdef.hxx>
34 #include <editeng/eeitem.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/window.hxx>
37 #include <vcl/svapp.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <com/sun/star/text/XNumberingFormatter.hpp>
40 #include <com/sun/star/text/DefaultNumberingProvider.hpp>
41 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
42 #include <com/sun/star/style/NumberingType.hpp>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <com/sun/star/lang/IllegalArgumentException.hpp>
45 #include <com/sun/star/beans/PropertyValue.hpp>
46 #include <comphelper/fileformat.h>
47 #include <comphelper/processfactory.hxx>
48 #include <tools/mapunit.hxx>
49 #include <tools/stream.hxx>
50 #include <tools/debug.hxx>
51 #include <tools/GenericTypeSerializer.hxx>
52 #include <unotools/configmgr.hxx>
53 #include <libxml/xmlwriter.h>
54 #include <editeng/unonrule.hxx>
55 #include <sal/log.hxx>
56 #include <i18nlangtag/languagetag.hxx>
57 #include <editeng/legacyitem.hxx>
59 #define DEF_WRITER_LSPACE 500 //Standard Indentation
60 #define DEF_DRAW_LSPACE 800 //Standard Indentation
62 #define NUMITEM_VERSION_03 0x03
63 #define NUMITEM_VERSION_04 0x04
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::lang;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::text;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::style;
72 sal_Int32 SvxNumberType::nRefCount = 0;
73 css::uno::Reference<css::text::XNumberingFormatter> SvxNumberType::xFormatter;
74 static void lcl_getFormatter(css::uno::Reference<css::text::XNumberingFormatter>& _xFormatter)
76 if(!_xFormatter.is())
78 try
80 Reference<XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
81 Reference<XDefaultNumberingProvider> xRet = text::DefaultNumberingProvider::create(xContext);
82 _xFormatter.set(xRet, UNO_QUERY);
84 catch(const Exception&)
86 SAL_WARN("editeng", "service missing: \"com.sun.star.text.DefaultNumberingProvider\"");
91 SvxNumberType::SvxNumberType(SvxNumType nType) :
92 nNumType(nType),
93 bShowSymbol(true)
95 nRefCount++;
98 SvxNumberType::SvxNumberType(const SvxNumberType& rType) :
99 nNumType(rType.nNumType),
100 bShowSymbol(rType.bShowSymbol)
102 nRefCount++;
105 SvxNumberType::~SvxNumberType()
107 if(!--nRefCount)
108 xFormatter = nullptr;
111 OUString SvxNumberType::GetNumStr( sal_Int32 nNo ) const
113 LanguageTag aLang = utl::ConfigManager::IsFuzzing() ?
114 LanguageTag("en-US") :
115 Application::GetSettings().GetLanguageTag();
116 return GetNumStr( nNo, aLang.getLocale() );
119 OUString SvxNumberType::GetNumStr( sal_Int32 nNo, const css::lang::Locale& rLocale ) const
121 lcl_getFormatter(xFormatter);
122 if(!xFormatter.is())
123 return OUString();
125 if(bShowSymbol)
127 switch(nNumType)
129 case NumberingType::CHAR_SPECIAL:
130 case NumberingType::BITMAP:
131 break;
132 default:
134 // '0' allowed for ARABIC numberings
135 if(NumberingType::ARABIC == nNumType && 0 == nNo )
136 return OUString('0');
137 else
139 Sequence< PropertyValue > aProperties(2);
140 PropertyValue* pValues = aProperties.getArray();
141 pValues[0].Name = "NumberingType";
142 pValues[0].Value <<= static_cast<sal_uInt16>(nNumType);
143 pValues[1].Name = "Value";
144 pValues[1].Value <<= nNo;
148 return xFormatter->makeNumberingString( aProperties, rLocale );
150 catch(const Exception&)
157 return OUString();
160 SvxNumberFormat::SvxNumberFormat( SvxNumType eType )
161 : SvxNumberType(eType),
162 eNumAdjust(SvxAdjust::Left),
163 nInclUpperLevels(0),
164 nStart(1),
165 cBullet(SVX_DEF_BULLET),
166 nBulletRelSize(100),
167 nBulletColor(COL_BLACK),
168 mePositionAndSpaceMode( LABEL_WIDTH_AND_POSITION ),
169 nFirstLineOffset(0),
170 nAbsLSpace(0),
171 nCharTextDistance(0),
172 meLabelFollowedBy( LISTTAB ),
173 mnListtabPos( 0 ),
174 mnFirstLineIndent( 0 ),
175 mnIndentAt( 0 ),
176 eVertOrient(text::VertOrientation::NONE)
180 SvxNumberFormat::SvxNumberFormat(const SvxNumberFormat& rFormat) :
181 SvxNumberType(rFormat),
182 mePositionAndSpaceMode( rFormat.mePositionAndSpaceMode )
184 *this = rFormat;
187 SvxNumberFormat::SvxNumberFormat( SvStream &rStream )
188 : nStart(0)
189 , nBulletRelSize(100)
190 , nFirstLineOffset(0)
191 , nAbsLSpace(0)
192 , nCharTextDistance(0)
194 sal_uInt16 nTmp16(0);
195 sal_Int32 nTmp32(0);
196 rStream.ReadUInt16( nTmp16 ); // Version number
198 rStream.ReadUInt16( nTmp16 ); SetNumberingType( static_cast<SvxNumType>(nTmp16) );
199 rStream.ReadUInt16( nTmp16 ); eNumAdjust = static_cast<SvxAdjust>(nTmp16);
200 rStream.ReadUInt16( nTmp16 ); nInclUpperLevels = nTmp16;
201 rStream.ReadUInt16( nStart );
202 rStream.ReadUInt16( nTmp16 ); cBullet = static_cast<sal_Unicode>(nTmp16);
204 sal_Int16 temp = 0;
205 rStream.ReadInt16( temp );
206 nFirstLineOffset = temp;
207 temp = 0;
208 rStream.ReadInt16( temp );
209 nAbsLSpace = temp;
210 rStream.SeekRel(2); //skip old now unused nLSpace;
212 rStream.ReadInt16( nCharTextDistance );
214 sPrefix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
215 sSuffix = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
216 sCharStyleName = rStream.ReadUniOrByteString( rStream.GetStreamCharSet() );
218 sal_uInt16 hasGraphicBrush = 0;
219 rStream.ReadUInt16( hasGraphicBrush );
220 if ( hasGraphicBrush )
222 pGraphicBrush.reset(new SvxBrushItem(SID_ATTR_BRUSH));
223 legacy::SvxBrush::Create(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
225 else pGraphicBrush = nullptr;
226 rStream.ReadUInt16( nTmp16 ); eVertOrient = nTmp16;
228 sal_uInt16 hasBulletFont = 0;
229 rStream.ReadUInt16( hasBulletFont );
230 if ( hasBulletFont )
232 pBulletFont.reset( new vcl::Font() );
233 ReadFont( rStream, *pBulletFont );
235 else pBulletFont = nullptr;
237 tools::GenericTypeSerializer aSerializer(rStream);
238 aSerializer.readSize(aGraphicSize);
239 aSerializer.readColor(nBulletColor);
241 rStream.ReadUInt16( nBulletRelSize );
242 rStream.ReadUInt16( nTmp16 ); SetShowSymbol( nTmp16 != 0 );
244 rStream.ReadUInt16( nTmp16 ); mePositionAndSpaceMode = static_cast<SvxNumPositionAndSpaceMode>(nTmp16);
245 rStream.ReadUInt16( nTmp16 ); meLabelFollowedBy = static_cast<LabelFollowedBy>(nTmp16);
246 rStream.ReadInt32( nTmp32 ); mnListtabPos = nTmp32;
247 rStream.ReadInt32( nTmp32 ); mnFirstLineIndent = nTmp32;
248 rStream.ReadInt32( nTmp32 ); mnIndentAt = nTmp32;
251 SvxNumberFormat::~SvxNumberFormat()
255 void SvxNumberFormat::Store(SvStream &rStream, FontToSubsFontConverter pConverter)
257 if(pConverter && pBulletFont)
259 cBullet = ConvertFontToSubsFontChar(pConverter, cBullet);
260 OUString sFontName = GetFontToSubsFontName(pConverter);
261 pBulletFont->SetFamilyName(sFontName);
264 tools::GenericTypeSerializer aSerializer(rStream);
266 rStream.WriteUInt16( NUMITEM_VERSION_04 );
268 rStream.WriteUInt16( GetNumberingType() );
269 rStream.WriteUInt16( static_cast<sal_uInt16>(eNumAdjust) );
270 rStream.WriteUInt16( nInclUpperLevels );
271 rStream.WriteUInt16( nStart );
272 rStream.WriteUInt16( cBullet );
274 rStream.WriteInt16(
275 sal_Int16(std::clamp<sal_Int32>(nFirstLineOffset, SAL_MIN_INT16, SAL_MAX_INT16)) );
276 //TODO: better way to handle out-of-bounds value?
277 rStream.WriteInt16(
278 sal_Int16(std::clamp<sal_Int32>(nAbsLSpace, SAL_MIN_INT16, SAL_MAX_INT16)) );
279 //TODO: better way to handle out-of-bounds value?
280 rStream.WriteInt16( 0 ); // write a dummy for old now unused nLSpace
282 rStream.WriteInt16( nCharTextDistance );
283 rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
284 rStream.WriteUniOrByteString(sPrefix, eEnc);
285 rStream.WriteUniOrByteString(sSuffix, eEnc);
286 rStream.WriteUniOrByteString(sCharStyleName, eEnc);
287 if(pGraphicBrush)
289 rStream.WriteUInt16( 1 );
291 // in SD or SI force bullet itself to be stored,
292 // for that purpose throw away link when link and graphic
293 // are present, so Brush save is forced
294 if(!pGraphicBrush->GetGraphicLink().isEmpty() && pGraphicBrush->GetGraphic())
296 pGraphicBrush->SetGraphicLink("");
299 legacy::SvxBrush::Store(*pGraphicBrush, rStream, BRUSH_GRAPHIC_VERSION);
301 else
302 rStream.WriteUInt16( 0 );
304 rStream.WriteUInt16( eVertOrient );
305 if(pBulletFont)
307 rStream.WriteUInt16( 1 );
308 WriteFont( rStream, *pBulletFont );
310 else
311 rStream.WriteUInt16( 0 );
313 aSerializer.writeSize(aGraphicSize);
315 Color nTempColor = nBulletColor;
316 if(COL_AUTO == nBulletColor)
317 nTempColor = COL_BLACK;
319 aSerializer.writeColor(nTempColor);
320 rStream.WriteUInt16( nBulletRelSize );
321 rStream.WriteUInt16( sal_uInt16(IsShowSymbol()) );
323 rStream.WriteUInt16( mePositionAndSpaceMode );
324 rStream.WriteUInt16( meLabelFollowedBy );
325 rStream.WriteInt32( mnListtabPos );
326 rStream.WriteInt32( mnFirstLineIndent );
327 rStream.WriteInt32( mnIndentAt );
330 SvxNumberFormat& SvxNumberFormat::operator=( const SvxNumberFormat& rFormat )
332 if (& rFormat == this) { return *this; }
334 SvxNumberType::SetNumberingType(rFormat.GetNumberingType());
335 eNumAdjust = rFormat.eNumAdjust ;
336 nInclUpperLevels = rFormat.nInclUpperLevels ;
337 nStart = rFormat.nStart ;
338 cBullet = rFormat.cBullet ;
339 mePositionAndSpaceMode = rFormat.mePositionAndSpaceMode;
340 nFirstLineOffset = rFormat.nFirstLineOffset;
341 nAbsLSpace = rFormat.nAbsLSpace ;
342 nCharTextDistance = rFormat.nCharTextDistance ;
343 meLabelFollowedBy = rFormat.meLabelFollowedBy;
344 mnListtabPos = rFormat.mnListtabPos;
345 mnFirstLineIndent = rFormat.mnFirstLineIndent;
346 mnIndentAt = rFormat.mnIndentAt;
347 eVertOrient = rFormat.eVertOrient ;
348 sPrefix = rFormat.sPrefix ;
349 sSuffix = rFormat.sSuffix ;
350 aGraphicSize = rFormat.aGraphicSize ;
351 nBulletColor = rFormat.nBulletColor ;
352 nBulletRelSize = rFormat.nBulletRelSize;
353 SetShowSymbol(rFormat.IsShowSymbol());
354 sCharStyleName = rFormat.sCharStyleName;
355 pGraphicBrush.reset();
356 if(rFormat.pGraphicBrush)
358 pGraphicBrush.reset( new SvxBrushItem(*rFormat.pGraphicBrush) );
360 pBulletFont.reset();
361 if(rFormat.pBulletFont)
362 pBulletFont.reset( new vcl::Font(*rFormat.pBulletFont) );
363 return *this;
366 bool SvxNumberFormat::operator==( const SvxNumberFormat& rFormat) const
368 if( GetNumberingType() != rFormat.GetNumberingType() ||
369 eNumAdjust != rFormat.eNumAdjust ||
370 nInclUpperLevels != rFormat.nInclUpperLevels ||
371 nStart != rFormat.nStart ||
372 cBullet != rFormat.cBullet ||
373 mePositionAndSpaceMode != rFormat.mePositionAndSpaceMode ||
374 nFirstLineOffset != rFormat.nFirstLineOffset ||
375 nAbsLSpace != rFormat.nAbsLSpace ||
376 nCharTextDistance != rFormat.nCharTextDistance ||
377 meLabelFollowedBy != rFormat.meLabelFollowedBy ||
378 mnListtabPos != rFormat.mnListtabPos ||
379 mnFirstLineIndent != rFormat.mnFirstLineIndent ||
380 mnIndentAt != rFormat.mnIndentAt ||
381 eVertOrient != rFormat.eVertOrient ||
382 sPrefix != rFormat.sPrefix ||
383 sSuffix != rFormat.sSuffix ||
384 aGraphicSize != rFormat.aGraphicSize ||
385 nBulletColor != rFormat.nBulletColor ||
386 nBulletRelSize != rFormat.nBulletRelSize ||
387 IsShowSymbol() != rFormat.IsShowSymbol() ||
388 sCharStyleName != rFormat.sCharStyleName
390 return false;
391 if (
392 (pGraphicBrush && !rFormat.pGraphicBrush) ||
393 (!pGraphicBrush && rFormat.pGraphicBrush) ||
394 (pGraphicBrush && *pGraphicBrush != *rFormat.pGraphicBrush)
397 return false;
399 if (
400 (pBulletFont && !rFormat.pBulletFont) ||
401 (!pBulletFont && rFormat.pBulletFont) ||
402 (pBulletFont && *pBulletFont != *rFormat.pBulletFont)
405 return false;
407 return true;
410 void SvxNumberFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem,
411 const Size* pSize, const sal_Int16* pOrient)
413 if(!pBrushItem)
415 pGraphicBrush.reset();
417 else if ( !pGraphicBrush || (*pBrushItem != *pGraphicBrush) )
419 pGraphicBrush.reset( static_cast<SvxBrushItem*>(pBrushItem->Clone()) );
422 if(pOrient)
423 eVertOrient = *pOrient;
424 else
425 eVertOrient = text::VertOrientation::NONE;
426 if(pSize)
427 aGraphicSize = *pSize;
428 else
430 aGraphicSize.setWidth(0);
431 aGraphicSize.setHeight(0);
435 void SvxNumberFormat::SetGraphic( const OUString& rName )
437 if( pGraphicBrush && pGraphicBrush->GetGraphicLink() == rName )
438 return ;
440 pGraphicBrush.reset( new SvxBrushItem( rName, "", GPOS_AREA, 0 ) );
441 if( eVertOrient == text::VertOrientation::NONE )
442 eVertOrient = text::VertOrientation::TOP;
444 aGraphicSize.setWidth(0);
445 aGraphicSize.setHeight(0);
448 sal_Int16 SvxNumberFormat::GetVertOrient() const
450 return eVertOrient;
453 void SvxNumberFormat::SetBulletFont(const vcl::Font* pFont)
455 pBulletFont.reset( pFont ? new vcl::Font(*pFont): nullptr );
458 void SvxNumberFormat::SetPositionAndSpaceMode( SvxNumPositionAndSpaceMode ePositionAndSpaceMode )
460 mePositionAndSpaceMode = ePositionAndSpaceMode;
463 sal_Int32 SvxNumberFormat::GetAbsLSpace() const
465 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
466 ? nAbsLSpace
467 : static_cast<sal_Int32>( GetFirstLineIndent() + GetIndentAt() );
469 sal_Int32 SvxNumberFormat::GetFirstLineOffset() const
471 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION
472 ? nFirstLineOffset
473 : static_cast<sal_Int32>( GetFirstLineIndent() );
475 short SvxNumberFormat::GetCharTextDistance() const
477 return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION ? nCharTextDistance : 0;
480 void SvxNumberFormat::SetLabelFollowedBy( const LabelFollowedBy eLabelFollowedBy )
482 meLabelFollowedBy = eLabelFollowedBy;
484 void SvxNumberFormat::SetListtabPos( const long nListtabPos )
486 mnListtabPos = nListtabPos;
488 void SvxNumberFormat::SetFirstLineIndent( const long nFirstLineIndent )
490 mnFirstLineIndent = nFirstLineIndent;
492 void SvxNumberFormat::SetIndentAt( const long nIndentAt )
494 mnIndentAt = nIndentAt;
497 Size SvxNumberFormat::GetGraphicSizeMM100(const Graphic* pGraphic)
499 const MapMode aMapMM100( MapUnit::Map100thMM );
500 const Size& rSize = pGraphic->GetPrefSize();
501 Size aRetSize;
502 if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
504 OutputDevice* pOutDev = Application::GetDefaultDevice();
505 MapMode aOldMap( pOutDev->GetMapMode() );
506 pOutDev->SetMapMode( aMapMM100 );
507 aRetSize = pOutDev->PixelToLogic( rSize );
508 pOutDev->SetMapMode( aOldMap );
510 else
511 aRetSize = OutputDevice::LogicToLogic( rSize, pGraphic->GetPrefMapMode(), aMapMM100 );
512 return aRetSize;
515 OUString SvxNumberFormat::CreateRomanString( sal_uLong nNo, bool bUpper )
517 nNo %= 4000; // more can not be displayed
518 // i, ii, iii, iv, v, vi, vii, vii, viii, ix
519 // (Dummy),1000,500,100,50,10,5,1
520 const char *cRomanArr = bUpper
521 ? "MDCLXVI--" // +2 Dummy entries!
522 : "mdclxvi--"; // +2 Dummy entries!
524 OUStringBuffer sRet;
525 sal_uInt16 nMask = 1000;
526 while( nMask )
528 sal_uInt8 nNumber = sal_uInt8(nNo / nMask);
529 sal_uInt8 nDiff = 1;
530 nNo %= nMask;
532 if( 5 < nNumber )
534 if( nNumber < 9 )
535 sRet.append(*(cRomanArr-1));
536 ++nDiff;
537 nNumber -= 5;
539 switch( nNumber )
541 case 3: { sRet.append(*cRomanArr); [[fallthrough]]; }
542 case 2: { sRet.append(*cRomanArr); [[fallthrough]]; }
543 case 1: { sRet.append(*cRomanArr); }
544 break;
546 case 4: {
547 sRet.append(*cRomanArr);
548 sRet.append(*(cRomanArr-nDiff));
550 break;
551 case 5: { sRet.append(*(cRomanArr-nDiff)); }
552 break;
555 nMask /= 10; // for the next decade
556 cRomanArr += 2;
558 return sRet.makeStringAndClear();
561 OUString SvxNumberFormat::GetCharFormatName()const
563 return sCharStyleName;
566 sal_Int32 SvxNumRule::nRefCount = 0;
567 static SvxNumberFormat* pStdNumFmt = nullptr;
568 static SvxNumberFormat* pStdOutlineNumFmt = nullptr;
569 SvxNumRule::SvxNumRule( SvxNumRuleFlags nFeatures,
570 sal_uInt16 nLevels,
571 bool bCont,
572 SvxNumRuleType eType,
573 SvxNumberFormat::SvxNumPositionAndSpaceMode
574 eDefaultNumberFormatPositionAndSpaceMode )
575 : nLevelCount(nLevels),
576 nFeatureFlags(nFeatures),
577 eNumberingType(eType),
578 bContinuousNumbering(bCont)
580 ++nRefCount;
581 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
583 if(i < nLevels)
585 aFmts[i].reset( new SvxNumberFormat(SVX_NUM_CHARS_UPPER_LETTER) );
586 // It is a distinction between writer and draw
587 if(nFeatures & SvxNumRuleFlags::CONTINUOUS)
589 if ( eDefaultNumberFormatPositionAndSpaceMode ==
590 SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
592 aFmts[i]->SetAbsLSpace( convertMm100ToTwip(DEF_WRITER_LSPACE * (i+1)) );
593 aFmts[i]->SetFirstLineOffset(convertMm100ToTwip(-DEF_WRITER_LSPACE));
595 else if ( eDefaultNumberFormatPositionAndSpaceMode ==
596 SvxNumberFormat::LABEL_ALIGNMENT )
598 // first line indent of general numbering in inch: -0,25 inch
599 const long cFirstLineIndent = -1440/4;
600 // indent values of general numbering in inch:
601 // 0,5 0,75 1,0 1,25 1,5
602 // 1,75 2,0 2,25 2,5 2,75
603 const long cIndentAt = 1440/4;
604 aFmts[i]->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT );
605 aFmts[i]->SetLabelFollowedBy( SvxNumberFormat::LISTTAB );
606 aFmts[i]->SetListtabPos( cIndentAt * (i+2) );
607 aFmts[i]->SetFirstLineIndent( cFirstLineIndent );
608 aFmts[i]->SetIndentAt( cIndentAt * (i+2) );
611 else
613 aFmts[i]->SetAbsLSpace( DEF_DRAW_LSPACE * i );
616 else
617 aFmts[i] = nullptr;
618 aFmtsSet[i] = false;
622 SvxNumRule::SvxNumRule(const SvxNumRule& rCopy)
624 ++nRefCount;
625 nLevelCount = rCopy.nLevelCount ;
626 nFeatureFlags = rCopy.nFeatureFlags ;
627 bContinuousNumbering = rCopy.bContinuousNumbering;
628 eNumberingType = rCopy.eNumberingType;
629 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
631 if(rCopy.aFmts[i])
632 aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
633 else
634 aFmts[i].reset();
635 aFmtsSet[i] = rCopy.aFmtsSet[i];
639 SvxNumRule::SvxNumRule( SvStream &rStream )
640 : nLevelCount(0)
642 sal_uInt16 nTmp16(0);
643 rStream.ReadUInt16( nTmp16 ); // NUM_ITEM_VERSION
644 rStream.ReadUInt16( nLevelCount );
646 // first nFeatureFlags of old Versions
647 rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
648 rStream.ReadUInt16( nTmp16 ); bContinuousNumbering = nTmp16;
649 rStream.ReadUInt16( nTmp16 ); eNumberingType = static_cast<SvxNumRuleType>(nTmp16);
651 for (sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
653 rStream.ReadUInt16( nTmp16 );
654 bool hasNumberingFormat = nTmp16 & 1;
655 aFmtsSet[i] = nTmp16 & 2; // fdo#68648 reset flag
656 if ( hasNumberingFormat ){
657 aFmts[i].reset( new SvxNumberFormat( rStream ) );
659 else
661 aFmts[i].reset();
662 aFmtsSet[i] = false; // actually only false is valid
665 //second nFeatureFlags for new versions
666 rStream.ReadUInt16( nTmp16 ); nFeatureFlags = static_cast<SvxNumRuleFlags>(nTmp16);
669 void SvxNumRule::Store( SvStream &rStream )
671 rStream.WriteUInt16( NUMITEM_VERSION_03 );
672 rStream.WriteUInt16( nLevelCount );
673 //first save of nFeatureFlags for old versions
674 rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
675 rStream.WriteUInt16( sal_uInt16(bContinuousNumbering) );
676 rStream.WriteUInt16( static_cast<sal_uInt16>(eNumberingType) );
678 FontToSubsFontConverter pConverter = nullptr;
679 bool bConvertBulletFont = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_50 ) && ( rStream.GetVersion() );
680 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
682 sal_uInt16 nSetFlag(aFmtsSet[i] ? 2 : 0); // fdo#68648 store that too
683 if(aFmts[i])
685 rStream.WriteUInt16( 1 | nSetFlag );
686 if(bConvertBulletFont && aFmts[i]->GetBulletFont())
688 if(!pConverter)
689 pConverter =
690 CreateFontToSubsFontConverter(aFmts[i]->GetBulletFont()->GetFamilyName(),
691 FontToSubsFontFlags::EXPORT);
693 aFmts[i]->Store(rStream, pConverter);
695 else
696 rStream.WriteUInt16( 0 | nSetFlag );
698 //second save of nFeatureFlags for new versions
699 rStream.WriteUInt16( static_cast<sal_uInt16>(nFeatureFlags) );
702 void SvxNumRule::dumpAsXml(xmlTextWriterPtr pWriter) const
704 xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumRule"));
705 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("levelCount"), BAD_CAST(OString::number(nLevelCount).getStr()));
706 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("continuousNumbering"), BAD_CAST(OString::boolean(bContinuousNumbering).getStr()));
707 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("numberingType"), BAD_CAST(OString::number(static_cast<int>(eNumberingType)).getStr()));
708 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("featureFlags"), BAD_CAST(OString::number(static_cast<int>(nFeatureFlags)).getStr()));
709 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
711 if(aFmts[i])
713 xmlTextWriterStartElement(pWriter, BAD_CAST("aFmts"));
714 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("i"), BAD_CAST(OString::number(i).getStr()));
715 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", aFmts[i].get());
716 xmlTextWriterEndElement(pWriter);
719 xmlTextWriterEndElement(pWriter);
723 SvxNumRule::~SvxNumRule()
725 if(!--nRefCount)
727 DELETEZ(pStdNumFmt);
728 DELETEZ(pStdOutlineNumFmt);
732 SvxNumRule& SvxNumRule::operator=( const SvxNumRule& rCopy )
734 if (this != &rCopy)
736 nLevelCount = rCopy.nLevelCount;
737 nFeatureFlags = rCopy.nFeatureFlags;
738 bContinuousNumbering = rCopy.bContinuousNumbering;
739 eNumberingType = rCopy.eNumberingType;
740 for(sal_uInt16 i = 0; i < SVX_MAX_NUM; i++)
742 if(rCopy.aFmts[i])
743 aFmts[i].reset( new SvxNumberFormat(*rCopy.aFmts[i]) );
744 else
745 aFmts[i].reset();
746 aFmtsSet[i] = rCopy.aFmtsSet[i];
749 return *this;
752 bool SvxNumRule::operator==( const SvxNumRule& rCopy) const
754 if(nLevelCount != rCopy.nLevelCount ||
755 nFeatureFlags != rCopy.nFeatureFlags ||
756 bContinuousNumbering != rCopy.bContinuousNumbering ||
757 eNumberingType != rCopy.eNumberingType)
758 return false;
759 for(sal_uInt16 i = 0; i < nLevelCount; i++)
761 if (
762 (aFmtsSet[i] != rCopy.aFmtsSet[i]) ||
763 (!aFmts[i] && rCopy.aFmts[i]) ||
764 (aFmts[i] && !rCopy.aFmts[i]) ||
765 (aFmts[i] && *aFmts[i] != *rCopy.aFmts[i])
768 return false;
771 return true;
774 const SvxNumberFormat* SvxNumRule::Get(sal_uInt16 nLevel)const
776 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
777 if( nLevel < SVX_MAX_NUM )
778 return aFmtsSet[nLevel] ? aFmts[nLevel].get() : nullptr;
779 else
780 return nullptr;
783 const SvxNumberFormat& SvxNumRule::GetLevel(sal_uInt16 nLevel)const
785 if(!pStdNumFmt)
787 pStdNumFmt = new SvxNumberFormat(SVX_NUM_ARABIC);
788 pStdOutlineNumFmt = new SvxNumberFormat(SVX_NUM_NUMBER_NONE);
791 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
793 return ( ( nLevel < SVX_MAX_NUM ) && aFmts[nLevel] ) ?
794 *aFmts[nLevel] : eNumberingType == SvxNumRuleType::NUMBERING ?
795 *pStdNumFmt : *pStdOutlineNumFmt;
798 void SvxNumRule::SetLevel( sal_uInt16 i, const SvxNumberFormat& rNumFmt, bool bIsValid )
800 DBG_ASSERT(i < SVX_MAX_NUM, "Wrong Level" );
802 if( i < SVX_MAX_NUM )
804 bool bReplace = !aFmtsSet[i];
805 if (!bReplace)
807 const SvxNumberFormat *pFmt = Get(i);
808 bReplace = pFmt == nullptr || rNumFmt != *pFmt;
811 if (bReplace)
813 aFmts[i].reset( new SvxNumberFormat(rNumFmt) );
814 aFmtsSet[i] = bIsValid;
819 void SvxNumRule::SetLevel(sal_uInt16 nLevel, const SvxNumberFormat* pFmt)
821 DBG_ASSERT(nLevel < SVX_MAX_NUM, "Wrong Level" );
823 if( nLevel < SVX_MAX_NUM )
825 aFmtsSet[nLevel] = nullptr != pFmt;
826 if(pFmt)
827 SetLevel(nLevel, *pFmt);
828 else
830 aFmts[nLevel].reset();
835 OUString SvxNumRule::MakeNumString( const SvxNodeNum& rNum ) const
837 OUStringBuffer aStr;
838 if( SVX_NO_NUM > rNum.GetLevel() && !( SVX_NO_NUMLEVEL & rNum.GetLevel() ) )
840 const SvxNumberFormat& rMyNFmt = GetLevel( rNum.GetLevel() );
841 aStr.append(rMyNFmt.GetPrefix());
842 if( SVX_NUM_NUMBER_NONE != rMyNFmt.GetNumberingType() )
844 sal_uInt8 i = rNum.GetLevel();
846 if( !IsContinuousNumbering() &&
847 1 < rMyNFmt.GetIncludeUpperLevels() ) // only on own level?
849 sal_uInt8 n = rMyNFmt.GetIncludeUpperLevels();
850 if( 1 < n )
852 if( i+1 >= n )
853 i -= n - 1;
854 else
855 i = 0;
859 for( ; i <= rNum.GetLevel(); ++i )
861 const SvxNumberFormat& rNFmt = GetLevel( i );
862 if( SVX_NUM_NUMBER_NONE == rNFmt.GetNumberingType() )
864 continue;
867 bool bDot = true;
868 if( rNum.GetLevelVal()[ i ] )
870 if(SVX_NUM_BITMAP != rNFmt.GetNumberingType())
872 const LanguageTag& rLang = Application::GetSettings().GetLanguageTag();
873 aStr.append(rNFmt.GetNumStr( rNum.GetLevelVal()[ i ], rLang.getLocale() ));
875 else
876 bDot = false;
878 else
879 aStr.append("0"); // all 0-levels are a 0
880 if( i != rNum.GetLevel() && bDot)
881 aStr.append(".");
885 aStr.append(rMyNFmt.GetSuffix());
887 return aStr.makeStringAndClear();
890 // changes linked to embedded bitmaps
891 void SvxNumRule::UnLinkGraphics()
893 for(sal_uInt16 i = 0; i < GetLevelCount(); i++)
895 SvxNumberFormat aFmt(GetLevel(i));
896 const SvxBrushItem* pBrush = aFmt.GetBrush();
897 if(SVX_NUM_BITMAP == aFmt.GetNumberingType())
899 const Graphic* pGraphic = nullptr;
900 if(pBrush &&
901 !pBrush->GetGraphicLink().isEmpty() &&
902 nullptr != (pGraphic = pBrush->GetGraphic()))
904 SvxBrushItem aTempItem(*pBrush);
905 aTempItem.SetGraphicLink("");
906 aTempItem.SetGraphic(*pGraphic);
907 sal_Int16 eOrient = aFmt.GetVertOrient();
908 aFmt.SetGraphicBrush( &aTempItem, &aFmt.GetGraphicSize(), &eOrient );
911 else if((SVX_NUM_BITMAP|LINK_TOKEN) == static_cast<int>(aFmt.GetNumberingType()))
912 aFmt.SetNumberingType(SVX_NUM_BITMAP);
913 SetLevel(i, aFmt);
917 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule) :
918 SfxPoolItem(SID_ATTR_NUMBERING_RULE),
919 pNumRule(new SvxNumRule(rRule))
923 SvxNumBulletItem::SvxNumBulletItem(SvxNumRule const & rRule, sal_uInt16 _nWhich ) :
924 SfxPoolItem(_nWhich),
925 pNumRule(new SvxNumRule(rRule))
929 SvxNumBulletItem::SvxNumBulletItem(const SvxNumBulletItem& rCopy) :
930 SfxPoolItem(rCopy),
931 pNumRule(new SvxNumRule(*rCopy.pNumRule))
935 SvxNumBulletItem::~SvxNumBulletItem()
939 bool SvxNumBulletItem::operator==( const SfxPoolItem& rCopy) const
941 return SfxPoolItem::operator==(rCopy) &&
942 *pNumRule == *static_cast<const SvxNumBulletItem&>(rCopy).pNumRule;
945 SfxPoolItem* SvxNumBulletItem::Clone( SfxItemPool * ) const
947 return new SvxNumBulletItem(*this);
950 bool SvxNumBulletItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
952 rVal <<= SvxCreateNumRule( pNumRule.get() );
953 return true;
956 bool SvxNumBulletItem::PutValue( const css::uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
958 uno::Reference< container::XIndexReplace > xRule;
959 if( rVal >>= xRule )
963 std::unique_ptr<SvxNumRule> pNewRule(new SvxNumRule( SvxGetNumRule( xRule ) ));
964 if( pNewRule->GetLevelCount() != pNumRule->GetLevelCount() ||
965 pNewRule->GetNumRuleType() != pNumRule->GetNumRuleType() )
967 std::unique_ptr<SvxNumRule> pConverted = SvxConvertNumRule( pNewRule.get(), pNumRule->GetLevelCount(), pNumRule->GetNumRuleType() );
968 pNewRule = std::move(pConverted);
970 pNumRule = std::move( pNewRule );
971 return true;
973 catch(const lang::IllegalArgumentException&)
977 return false;
980 void SvxNumBulletItem::dumpAsXml(xmlTextWriterPtr pWriter) const
982 xmlTextWriterStartElement(pWriter, BAD_CAST("SvxNumBulletItem"));
983 xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
984 pNumRule->dumpAsXml(pWriter);
985 xmlTextWriterEndElement(pWriter);
988 std::unique_ptr<SvxNumRule> SvxConvertNumRule( const SvxNumRule* pRule, sal_uInt16 nLevels, SvxNumRuleType eType )
990 const sal_uInt16 nSrcLevels = pRule->GetLevelCount();
991 std::unique_ptr<SvxNumRule> pNewRule(new SvxNumRule( pRule->GetFeatureFlags(), nLevels, pRule->IsContinuousNumbering(), eType ));
993 for( sal_uInt16 nLevel = 0; (nLevel < nLevels) && (nLevel < nSrcLevels); nLevel++ )
994 pNewRule->SetLevel( nLevel, pRule->GetLevel( nLevel ) );
996 return pNewRule;
999 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */