android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / doc / number.cxx
blobf953a93dbde491e151c321101dca6daa1d593581
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 <memory>
21 #include <hintids.hxx>
23 #include <utility>
24 #include <vcl/font.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <editeng/numitem.hxx>
27 #include <svl/grabbagitem.hxx>
28 #include <fmtornt.hxx>
29 #include <doc.hxx>
30 #include <charfmt.hxx>
31 #include <ndtxt.hxx>
32 #include <docary.hxx>
33 #include <SwStyleNameMapper.hxx>
35 // Needed to load default bullet list configuration
36 #include <unotools/configmgr.hxx>
37 #include <unotools/configitem.hxx>
39 #include <numrule.hxx>
40 #include <SwNodeNum.hxx>
42 #include <list.hxx>
44 #include <algorithm>
45 #include <unordered_map>
46 #include <libxml/xmlwriter.h>
48 #include <rtl/ustrbuf.hxx>
49 #include <i18nlangtag/languagetag.hxx>
50 #include <unotools/saveopt.hxx>
51 #include <osl/diagnose.h>
53 #include <IDocumentListsAccess.hxx>
54 #include <IDocumentStylePoolAccess.hxx>
55 #include <IDocumentState.hxx>
57 #include <com/sun/star/beans/PropertyValue.hpp>
58 #include <wrtsh.hxx>
60 using namespace ::com::sun::star;
62 sal_uInt16 SwNumRule::snRefCount = 0;
63 SwNumFormat* SwNumRule::saBaseFormats[ RULE_END ][ MAXLEVEL ] = {
64 {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } };
66 SwNumFormat* SwNumRule::saLabelAlignmentBaseFormats[ RULE_END ][ MAXLEVEL ] = {
67 {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } };
69 const sal_uInt16 SwNumRule::saDefNumIndents[ MAXLEVEL ] = {
70 o3tl::toTwips(25, o3tl::Length::in100),
71 o3tl::toTwips(50, o3tl::Length::in100),
72 o3tl::toTwips(75, o3tl::Length::in100),
73 o3tl::toTwips(100, o3tl::Length::in100),
74 o3tl::toTwips(125, o3tl::Length::in100),
75 o3tl::toTwips(150, o3tl::Length::in100),
76 o3tl::toTwips(175, o3tl::Length::in100),
77 o3tl::toTwips(200, o3tl::Length::in100),
78 o3tl::toTwips(225, o3tl::Length::in100),
79 o3tl::toTwips(250, o3tl::Length::in100),
82 OUString SwNumRule::GetOutlineRuleName()
84 return "Outline";
87 const SwNumFormat& SwNumRule::Get( sal_uInt16 i ) const
89 assert( i < MAXLEVEL && meRuleType < RULE_END );
90 return maFormats[ i ]
91 ? *maFormats[ i ]
92 : ( meDefaultNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION
93 ? *saBaseFormats[ meRuleType ][ i ]
94 : *saLabelAlignmentBaseFormats[ meRuleType ][ i ] );
97 const SwNumFormat* SwNumRule::GetNumFormat( sal_uInt16 i ) const
99 const SwNumFormat * pResult = nullptr;
101 assert( i < MAXLEVEL && meRuleType < RULE_END );
102 if ( i < MAXLEVEL && meRuleType < RULE_END)
104 pResult = maFormats[ i ].get();
107 return pResult;
110 // #i91400#
111 void SwNumRule::SetName( const OUString & rName,
112 IDocumentListsAccess& rDocListAccess)
114 if ( msName == rName )
115 return;
117 if (mpNumRuleMap)
119 mpNumRuleMap->erase(msName);
120 (*mpNumRuleMap)[rName] = this;
122 if ( !GetDefaultListId().isEmpty() )
124 rDocListAccess.trackChangeOfListStyleName( msName, rName );
128 msName = rName;
131 void SwNumRule::GetTextNodeList( SwNumRule::tTextNodeList& rTextNodeList ) const
133 rTextNodeList = maTextNodeList;
136 SwNumRule::tTextNodeList::size_type SwNumRule::GetTextNodeListSize() const
138 return maTextNodeList.size();
141 void SwNumRule::AddTextNode( SwTextNode& rTextNode )
143 tTextNodeList::iterator aIter =
144 std::find( maTextNodeList.begin(), maTextNodeList.end(), &rTextNode );
146 if ( aIter == maTextNodeList.end() )
148 maTextNodeList.push_back( &rTextNode );
152 void SwNumRule::RemoveTextNode( SwTextNode& rTextNode )
154 tTextNodeList::iterator aIter =
155 std::find( maTextNodeList.begin(), maTextNodeList.end(), &rTextNode );
157 if ( aIter != maTextNodeList.end() )
159 maTextNodeList.erase( aIter );
163 void SwNumRule::SetNumRuleMap(std::unordered_map<OUString, SwNumRule *> *
164 pNumRuleMap)
166 mpNumRuleMap = pNumRuleMap;
169 sal_uInt16 SwNumRule::GetNumIndent( sal_uInt8 nLvl )
171 OSL_ENSURE( MAXLEVEL > nLvl, "NumLevel is out of range" );
172 return saDefNumIndents[ nLvl ];
175 sal_uInt16 SwNumRule::GetBullIndent( sal_uInt8 nLvl )
177 OSL_ENSURE( MAXLEVEL > nLvl, "NumLevel is out of range" );
178 return saDefNumIndents[ nLvl ];
181 static void lcl_SetRuleChgd( SwTextNode& rNd, sal_uInt8 nLevel )
183 if( rNd.GetActualListLevel() == nLevel )
184 rNd.NumRuleChgd();
187 SwNumFormat::SwNumFormat() :
188 SvxNumberFormat(SVX_NUM_ARABIC),
189 SwClient( nullptr ),
190 m_aVertOrient( 0, text::VertOrientation::NONE )
191 ,m_cGrfBulletCP(USHRT_MAX)//For i120928,record the cp info of graphic within bullet
195 SwNumFormat::SwNumFormat( const SwNumFormat& rFormat) :
196 SvxNumberFormat(rFormat),
197 SwClient( rFormat.GetRegisteredInNonConst() ),
198 m_aVertOrient( 0, rFormat.GetVertOrient() )
199 ,m_cGrfBulletCP(rFormat.m_cGrfBulletCP)//For i120928,record the cp info of graphic within bullet
201 sal_Int16 eMyVertOrient = rFormat.GetVertOrient();
202 SetGraphicBrush( rFormat.GetBrush(), &rFormat.GetGraphicSize(),
203 &eMyVertOrient);
206 SwNumFormat::SwNumFormat(const SvxNumberFormat& rNumFormat, SwDoc* pDoc)
207 : SvxNumberFormat(rNumFormat)
208 , m_aVertOrient( 0, rNumFormat.GetVertOrient() )
209 , m_cGrfBulletCP(USHRT_MAX)
211 sal_Int16 eMyVertOrient = rNumFormat.GetVertOrient();
212 SetGraphicBrush( rNumFormat.GetBrush(), &rNumFormat.GetGraphicSize(),
213 &eMyVertOrient);
214 const OUString rCharStyleName = rNumFormat.SvxNumberFormat::GetCharFormatName();
215 if( !rCharStyleName.isEmpty() )
217 SwCharFormat* pCFormat = pDoc->FindCharFormatByName( rCharStyleName );
218 if( !pCFormat )
220 sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCharStyleName,
221 SwGetPoolIdFromName::ChrFmt );
222 pCFormat = nId != USHRT_MAX
223 ? pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( nId )
224 : pDoc->MakeCharFormat( rCharStyleName, nullptr );
226 pCFormat->Add( this );
228 else
229 EndListeningAll();
232 SwNumFormat::~SwNumFormat()
236 // #i22362#
237 bool SwNumFormat::IsEnumeration() const
239 // #i30655# native numbering did not work any longer
240 // using this code. Therefore HBRINKM and I agreed upon defining
241 // IsEnumeration() as !IsItemize()
242 return !IsItemize();
245 bool SwNumFormat::IsItemize() const
247 bool bResult;
249 switch(GetNumberingType())
251 case SVX_NUM_CHAR_SPECIAL:
252 case SVX_NUM_BITMAP:
253 bResult = true;
255 break;
257 default:
258 bResult = false;
261 return bResult;
265 SwNumFormat& SwNumFormat::operator=( const SwNumFormat& rNumFormat)
267 SvxNumberFormat::operator=(rNumFormat);
268 StartListeningToSameModifyAs(rNumFormat);
269 //For i120928,record the cp info of graphic within bullet
270 m_cGrfBulletCP = rNumFormat.m_cGrfBulletCP;
271 return *this;
274 bool SwNumFormat::operator==( const SwNumFormat& rNumFormat) const
276 bool bRet = SvxNumberFormat::operator==(rNumFormat) &&
277 GetRegisteredIn() == rNumFormat.GetRegisteredIn();
278 return bRet;
281 void SwNumFormat::SetCharFormat( SwCharFormat* pChFormat)
283 if( pChFormat )
284 pChFormat->Add( this );
285 else
286 EndListeningAll();
289 void SwNumFormat::SwClientNotify(const SwModify&, const SfxHint& rHint)
291 if (rHint.GetId() != SfxHintId::SwLegacyModify)
292 return;
293 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
294 // Look for the NumRules object in the Doc where this NumFormat is set.
295 // The format does not need to exist!
296 const SwCharFormat* pFormat = nullptr;
297 switch(pLegacy->GetWhich())
299 case RES_ATTRSET_CHG:
300 case RES_FMT_CHG:
301 pFormat = GetCharFormat();
302 break;
305 if(pFormat && !pFormat->GetDoc()->IsInDtor())
306 UpdateNumNodes(*const_cast<SwDoc*>(pFormat->GetDoc()));
307 else
308 CheckRegistration(pLegacy->m_pOld);
311 OUString SwNumFormat::GetCharFormatName() const
313 if(static_cast<const SwCharFormat*>(GetRegisteredIn()))
314 return static_cast<const SwCharFormat*>(GetRegisteredIn())->GetName();
316 return OUString();
319 void SwNumFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem, const Size* pSize,
320 const sal_Int16* pOrient)
322 if(pOrient)
323 m_aVertOrient.SetVertOrient( *pOrient );
324 SvxNumberFormat::SetGraphicBrush( pBrushItem, pSize, pOrient);
327 void SwNumFormat::UpdateNumNodes( SwDoc& rDoc )
329 bool bDocIsModified = rDoc.getIDocumentState().IsModified();
330 bool bFnd = false;
331 for( SwNumRuleTable::size_type n = rDoc.GetNumRuleTable().size(); !bFnd && n; )
333 const SwNumRule* pRule = rDoc.GetNumRuleTable()[ --n ];
334 for( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
335 if( pRule->GetNumFormat( i ) == this )
337 SwNumRule::tTextNodeList aTextNodeList;
338 pRule->GetTextNodeList( aTextNodeList );
339 for ( auto& rpTextNode : aTextNodeList )
341 lcl_SetRuleChgd( *rpTextNode, i );
343 bFnd = true;
344 break;
348 if( bFnd && !bDocIsModified )
349 rDoc.getIDocumentState().ResetModified();
352 const SwFormatVertOrient* SwNumFormat::GetGraphicOrientation() const
354 sal_Int16 eOrient = SvxNumberFormat::GetVertOrient();
355 if(text::VertOrientation::NONE == eOrient)
356 return nullptr;
357 else
359 const_cast<SwFormatVertOrient&>(m_aVertOrient).SetVertOrient(eOrient);
360 return &m_aVertOrient;
364 SwNumRule::SwNumRule( OUString aNm,
365 const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode,
366 SwNumRuleType eType )
367 : mpNumRuleMap(nullptr),
368 msName( std::move(aNm) ),
369 meRuleType( eType ),
370 mnPoolFormatId( USHRT_MAX ),
371 mnPoolHelpId( USHRT_MAX ),
372 mnPoolHlpFileId( UCHAR_MAX ),
373 mbAutoRuleFlag( true ),
374 mbInvalidRuleFlag( true ),
375 mbContinusNum( false ),
376 mbAbsSpaces( false ),
377 mbHidden( false ),
378 mbCountPhantoms( true ),
379 mbUsedByRedline( false ),
380 meDefaultNumberFormatPositionAndSpaceMode( eDefaultNumberFormatPositionAndSpaceMode )
382 if( !snRefCount++ ) // for the first time, initialize
384 SwNumFormat* pFormat;
385 sal_uInt8 n;
387 // numbering:
388 // position-and-space mode LABEL_WIDTH_AND_POSITION:
389 for( n = 0; n < MAXLEVEL; ++n )
391 pFormat = new SwNumFormat;
392 pFormat->SetIncludeUpperLevels( 1 );
393 pFormat->SetStart( 1 );
394 pFormat->SetAbsLSpace( lNumberIndent + SwNumRule::GetNumIndent( n ) );
395 pFormat->SetFirstLineOffset( lNumberFirstLineOffset );
396 pFormat->SetListFormat("%" + OUString::number(n + 1) + "%.");
397 pFormat->SetBulletChar(numfunc::GetBulletChar(n));
398 SwNumRule::saBaseFormats[ NUM_RULE ][ n ] = pFormat;
400 // position-and-space mode LABEL_ALIGNMENT
401 // first line indent of general numbering in inch: -0,25 inch
402 const tools::Long cFirstLineIndent = o3tl::toTwips(-0.25, o3tl::Length::in);
403 // indent values of general numbering in inch:
404 const tools::Long cIndentAt[ MAXLEVEL ] = {
405 o3tl::toTwips(50, o3tl::Length::in100),
406 o3tl::toTwips(75, o3tl::Length::in100),
407 o3tl::toTwips(100, o3tl::Length::in100),
408 o3tl::toTwips(125, o3tl::Length::in100),
409 o3tl::toTwips(150, o3tl::Length::in100),
410 o3tl::toTwips(175, o3tl::Length::in100),
411 o3tl::toTwips(200, o3tl::Length::in100),
412 o3tl::toTwips(225, o3tl::Length::in100),
413 o3tl::toTwips(250, o3tl::Length::in100),
414 o3tl::toTwips(275, o3tl::Length::in100),
416 for( n = 0; n < MAXLEVEL; ++n )
418 pFormat = new SwNumFormat;
419 pFormat->SetIncludeUpperLevels( 1 );
420 pFormat->SetStart( 1 );
421 pFormat->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT );
422 pFormat->SetLabelFollowedBy( SvxNumberFormat::LISTTAB );
423 pFormat->SetListtabPos( cIndentAt[ n ] );
424 pFormat->SetFirstLineIndent( cFirstLineIndent );
425 pFormat->SetIndentAt( cIndentAt[ n ] );
426 pFormat->SetListFormat( "%" + OUString::number(n + 1) + "%.");
427 pFormat->SetBulletChar( numfunc::GetBulletChar(n));
428 SwNumRule::saLabelAlignmentBaseFormats[ NUM_RULE ][ n ] = pFormat;
431 // outline:
432 // position-and-space mode LABEL_WIDTH_AND_POSITION:
433 for( n = 0; n < MAXLEVEL; ++n )
435 pFormat = new SwNumFormat;
436 pFormat->SetNumberingType(SVX_NUM_NUMBER_NONE);
437 pFormat->SetIncludeUpperLevels( MAXLEVEL );
438 pFormat->SetStart( 1 );
439 pFormat->SetCharTextDistance( lOutlineMinTextDistance );
440 pFormat->SetBulletChar( numfunc::GetBulletChar(n));
441 SwNumRule::saBaseFormats[ OUTLINE_RULE ][ n ] = pFormat;
443 // position-and-space mode LABEL_ALIGNMENT:
444 for( n = 0; n < MAXLEVEL; ++n )
446 pFormat = new SwNumFormat;
447 pFormat->SetNumberingType(SVX_NUM_NUMBER_NONE);
448 pFormat->SetIncludeUpperLevels( MAXLEVEL );
449 pFormat->SetStart( 1 );
450 pFormat->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT );
451 pFormat->SetBulletChar( numfunc::GetBulletChar(n));
452 SwNumRule::saLabelAlignmentBaseFormats[ OUTLINE_RULE ][ n ] = pFormat;
455 OSL_ENSURE( !msName.isEmpty(), "NumRule without a name!" );
458 SwNumRule::SwNumRule( const SwNumRule& rNumRule )
459 : mpNumRuleMap(nullptr),
460 msName( rNumRule.msName ),
461 meRuleType( rNumRule.meRuleType ),
462 mnPoolFormatId( rNumRule.GetPoolFormatId() ),
463 mnPoolHelpId( rNumRule.GetPoolHelpId() ),
464 mnPoolHlpFileId( rNumRule.GetPoolHlpFileId() ),
465 mbAutoRuleFlag( rNumRule.mbAutoRuleFlag ),
466 mbInvalidRuleFlag( true ),
467 mbContinusNum( rNumRule.mbContinusNum ),
468 mbAbsSpaces( rNumRule.mbAbsSpaces ),
469 mbHidden( rNumRule.mbHidden ),
470 mbCountPhantoms( true ),
471 mbUsedByRedline( false ),
472 meDefaultNumberFormatPositionAndSpaceMode( rNumRule.meDefaultNumberFormatPositionAndSpaceMode ),
473 msDefaultListId( rNumRule.msDefaultListId )
475 ++snRefCount;
476 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
477 if( rNumRule.maFormats[ n ] )
478 Set( n, *rNumRule.maFormats[ n ] );
481 SwNumRule::~SwNumRule()
483 for (auto & i : maFormats)
484 i.reset();
486 if (mpNumRuleMap)
488 mpNumRuleMap->erase(GetName());
491 if( !--snRefCount ) // the last one closes the door (?)
493 // Numbering:
494 SwNumFormat** ppFormats = &SwNumRule::saBaseFormats[0][0];
495 int n;
497 for( n = 0; n < MAXLEVEL; ++n, ++ppFormats )
499 delete *ppFormats;
500 *ppFormats = nullptr;
503 // Outline:
504 for( n = 0; n < MAXLEVEL; ++n, ++ppFormats )
506 delete *ppFormats;
507 *ppFormats = nullptr;
510 ppFormats = &SwNumRule::saLabelAlignmentBaseFormats[0][0];
511 for( n = 0; n < MAXLEVEL; ++n, ++ppFormats )
513 delete *ppFormats;
514 *ppFormats = nullptr;
516 for( n = 0; n < MAXLEVEL; ++n, ++ppFormats )
518 delete *ppFormats;
519 *ppFormats = nullptr;
523 maTextNodeList.clear();
524 maParagraphStyleList.clear();
527 void SwNumRule::CheckCharFormats( SwDoc& rDoc )
529 for(auto& rpNumFormat : maFormats)
531 if( rpNumFormat )
533 SwCharFormat* pFormat = rpNumFormat->GetCharFormat();
534 if( pFormat && pFormat->GetDoc() != &rDoc )
536 // copy
537 SwNumFormat* pNew = new SwNumFormat( *rpNumFormat );
538 pNew->SetCharFormat( rDoc.CopyCharFormat( *pFormat ) );
539 rpNumFormat.reset(pNew);
545 SwNumRule& SwNumRule::operator=( const SwNumRule& rNumRule )
547 if( this != &rNumRule )
549 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
550 Set( n, rNumRule.maFormats[ n ].get() );
552 meRuleType = rNumRule.meRuleType;
553 msName = rNumRule.msName;
554 mbAutoRuleFlag = rNumRule.mbAutoRuleFlag;
555 mbInvalidRuleFlag = true;
556 mbContinusNum = rNumRule.mbContinusNum;
557 mbAbsSpaces = rNumRule.mbAbsSpaces;
558 mbHidden = rNumRule.mbHidden;
559 mnPoolFormatId = rNumRule.GetPoolFormatId();
560 mnPoolHelpId = rNumRule.GetPoolHelpId();
561 mnPoolHlpFileId = rNumRule.GetPoolHlpFileId();
563 return *this;
566 void SwNumRule::Reset( const OUString& rName )
568 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
569 Set( n, nullptr);
571 meRuleType = NUM_RULE;
572 msName = rName;
573 mbAutoRuleFlag = true;
574 mbInvalidRuleFlag = true;
575 mbContinusNum = false;
576 mbAbsSpaces = false;
577 mbHidden = false;
578 mnPoolFormatId = USHRT_MAX;
579 mnPoolHelpId = USHRT_MAX;
580 mnPoolHlpFileId = UCHAR_MAX;
583 bool SwNumRule::operator==( const SwNumRule& rRule ) const
585 bool bRet = meRuleType == rRule.meRuleType &&
586 msName == rRule.msName &&
587 mbAutoRuleFlag == rRule.mbAutoRuleFlag &&
588 mbContinusNum == rRule.mbContinusNum &&
589 mbAbsSpaces == rRule.mbAbsSpaces &&
590 mnPoolFormatId == rRule.GetPoolFormatId() &&
591 mnPoolHelpId == rRule.GetPoolHelpId() &&
592 mnPoolHlpFileId == rRule.GetPoolHlpFileId();
593 if( bRet )
595 for( sal_uInt8 n = 0; n < MAXLEVEL; ++n )
596 if( rRule.Get( n ) != Get( n ) )
598 bRet = false;
599 break;
602 return bRet;
605 void SwNumRule::Set( sal_uInt16 i, const SwNumFormat& rNumFormat )
607 OSL_ENSURE( i < MAXLEVEL, "Serious defect" );
608 if( i < MAXLEVEL )
610 if( !maFormats[ i ] || (rNumFormat != Get( i )) )
612 maFormats[ i ].reset(new SwNumFormat( rNumFormat ));
613 mbInvalidRuleFlag = true;
618 void SwNumRule::Set( sal_uInt16 i, const SwNumFormat* pNumFormat )
620 OSL_ENSURE( i < MAXLEVEL, "Serious defect" );
621 if( i >= MAXLEVEL )
622 return;
623 if( !maFormats[ i ] )
625 if( pNumFormat )
627 maFormats[ i ].reset(new SwNumFormat( *pNumFormat ));
628 mbInvalidRuleFlag = true;
631 else if( !pNumFormat )
633 maFormats[ i ].reset();
634 mbInvalidRuleFlag = true;
636 else if( *maFormats[i] != *pNumFormat )
638 *maFormats[ i ] = *pNumFormat;
639 mbInvalidRuleFlag = true;
643 OUString SwNumRule::MakeNumString( const SwNodeNum& rNum, bool bInclStrings ) const
645 if (rNum.IsCounted())
646 return MakeNumString(rNum.GetNumberVector(), bInclStrings);
648 return OUString();
651 OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVector,
652 const bool bInclStrings,
653 const unsigned int _nRestrictToThisLevel,
654 SwNumRule::Extremities* pExtremities,
655 LanguageType nLang ) const
657 OUStringBuffer aStr;
659 SwNumberTree::tNumberVector::size_type nLevel = rNumVector.size() - 1;
661 if ( pExtremities )
662 pExtremities->nPrefixChars = pExtremities->nSuffixChars = 0;
664 if ( nLevel > _nRestrictToThisLevel )
666 nLevel = _nRestrictToThisLevel;
669 assert(nLevel < MAXLEVEL);
671 const SwNumFormat& rMyNFormat = Get( o3tl::narrowing<sal_uInt16>(nLevel) );
673 if (rMyNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE)
675 if (!rMyNFormat.HasListFormat())
676 return bInclStrings ? rMyNFormat.GetPrefix() + rMyNFormat.GetSuffix() : OUString();
678 // If numbering is disabled for this level we should emit just prefix/suffix
679 // Remove everything between first %1% and last %n% (including markers)
680 OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings);
681 sal_Int32 nFirstPosition = sLevelFormat.indexOf("%");
682 sal_Int32 nLastPosition = sLevelFormat.lastIndexOf("%");
683 if (nFirstPosition >= 0 && nLastPosition >= nFirstPosition)
684 sLevelFormat = sLevelFormat.replaceAt(nFirstPosition, nLastPosition - nFirstPosition + 1, u"");
685 return sLevelFormat;
688 css::lang::Locale aLocale( LanguageTag::convertToLocale(nLang));
690 if (rMyNFormat.HasListFormat())
692 OUString sLevelFormat = rMyNFormat.GetListFormat(bInclStrings);
694 // In this case we are ignoring GetIncludeUpperLevels: we put all
695 // level numbers requested by level format
696 for (SwNumberTree::tNumberVector::size_type i=0; i <= nLevel; ++i)
698 OUString sReplacement;
699 const SwNumFormat& rNFormat = Get(i);
700 if (rNFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE)
702 // Numbering disabled - replacement is empty
703 // And we should skip all level string content until next level marker:
704 // so %1%.%2%.%3% with second level as NONE will result 1.1, not 1..1
705 OUString sFind("%" + OUString::number(i + 1) + "%");
706 sal_Int32 nPositionToken = sLevelFormat.indexOf(sFind);
707 sal_Int32 nPositionNextToken = sLevelFormat.indexOf('%', nPositionToken + sFind.getLength());
708 if (nPositionToken >= 0 && nPositionNextToken >= nPositionToken)
710 sLevelFormat = sLevelFormat.replaceAt(nPositionToken, nPositionNextToken - nPositionToken, u"");
713 else if (rNumVector[i])
714 sReplacement = Get(i).GetNumStr(rNumVector[i], aLocale);
715 else
716 sReplacement = "0"; // all 0 level are a 0
718 OUString sFind("%" + OUString::number(i + 1) + "%");
719 sal_Int32 nPosition = sLevelFormat.indexOf(sFind);
720 if (nPosition >= 0)
721 sLevelFormat = sLevelFormat.replaceAt(nPosition, sFind.getLength(), sReplacement);
724 aStr = sLevelFormat;
726 else
728 // Fallback case: level format is not defined
729 // So use old way with levels joining by dot "."
730 SwNumberTree::tNumberVector::size_type i = nLevel;
732 if (!IsContinusNum() &&
733 // - do not include upper levels, if level isn't numbered.
734 rMyNFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE &&
735 rMyNFormat.GetIncludeUpperLevels()) // Just the own level?
737 sal_uInt8 n = rMyNFormat.GetIncludeUpperLevels();
738 if (1 < n)
740 if (i + 1 >= n)
741 i -= n - 1;
742 else
743 i = 0;
747 for (; i <= nLevel; ++i)
749 const SwNumFormat& rNFormat = Get(i);
750 if (SVX_NUM_NUMBER_NONE == rNFormat.GetNumberingType())
752 // Should 1.1.1 --> 2. NoNum --> 1..1 or 1.1 ??
753 // if( i != rNum.nMyLevel )
754 // aStr += ".";
755 continue;
758 if (rNumVector[i])
759 aStr.append(rNFormat.GetNumStr(rNumVector[i], aLocale));
760 else
761 aStr.append("0"); // all 0 level are a 0
762 if (i != nLevel && !aStr.isEmpty())
763 aStr.append(".");
766 // The type doesn't have any number, so don't append
767 // the post-/prefix string
768 if (bInclStrings &&
769 SVX_NUM_CHAR_SPECIAL != rMyNFormat.GetNumberingType() &&
770 SVX_NUM_BITMAP != rMyNFormat.GetNumberingType())
772 const OUString& sPrefix = rMyNFormat.GetPrefix();
773 const OUString& sSuffix = rMyNFormat.GetSuffix();
775 aStr.insert(0, sPrefix);
776 aStr.append(sSuffix);
777 if (pExtremities)
779 pExtremities->nPrefixChars = sPrefix.getLength();
780 pExtremities->nSuffixChars = sSuffix.getLength();
785 return aStr.makeStringAndClear();
788 OUString SwNumRule::MakeRefNumString( const SwNodeNum& rNodeNum,
789 const bool bInclSuperiorNumLabels,
790 const int nRestrictInclToThisLevel ) const
792 OUString aRefNumStr;
794 if ( rNodeNum.GetLevelInListTree() >= 0 )
796 bool bOldHadPrefix = true;
798 const SwNodeNum* pWorkingNodeNum( &rNodeNum );
801 bool bMakeNumStringForPhantom( false );
802 if ( pWorkingNodeNum->IsPhantom() )
804 int nListLevel = pWorkingNodeNum->GetLevelInListTree();
806 if (nListLevel < 0)
807 nListLevel = 0;
809 if (nListLevel >= MAXLEVEL)
810 nListLevel = MAXLEVEL - 1;
812 SwNumFormat aFormat( Get( o3tl::narrowing<sal_uInt16>(nListLevel) ) );
813 bMakeNumStringForPhantom = aFormat.IsEnumeration() &&
814 SVX_NUM_NUMBER_NONE != aFormat.GetNumberingType();
817 if ( bMakeNumStringForPhantom ||
818 ( !pWorkingNodeNum->IsPhantom() &&
819 pWorkingNodeNum->GetTextNode() &&
820 pWorkingNodeNum->GetTextNode()->HasNumber() ) )
822 Extremities aExtremities;
823 OUString aPrevStr = MakeNumString( pWorkingNodeNum->GetNumberVector(),
824 true, MAXLEVEL,
825 &aExtremities);
826 sal_Int32 nStrip = 0;
827 while ( nStrip < aExtremities.nPrefixChars )
829 const sal_Unicode c = aPrevStr[nStrip];
830 if ( c!='\t' && c!=' ')
831 break;
832 ++nStrip;
835 if (nStrip)
837 aPrevStr = aPrevStr.copy( nStrip );
838 aExtremities.nPrefixChars -= nStrip;
841 if (bOldHadPrefix &&
842 aExtremities.nSuffixChars &&
843 !aExtremities.nPrefixChars
846 aPrevStr = aPrevStr.copy(0,
847 aPrevStr.getLength() - aExtremities.nSuffixChars);
850 bOldHadPrefix = ( aExtremities.nPrefixChars > 0);
852 aRefNumStr = aPrevStr + aRefNumStr;
855 if ( bInclSuperiorNumLabels && pWorkingNodeNum->GetLevelInListTree() > 0 )
857 sal_uInt8 n = Get( o3tl::narrowing<sal_uInt16>(pWorkingNodeNum->GetLevelInListTree()) ).GetIncludeUpperLevels();
858 pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent());
859 // skip parents, whose list label is already contained in the actual list label.
860 while ( pWorkingNodeNum && n > 1 )
862 pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent());
863 --n;
866 else
868 break;
870 } while ( pWorkingNodeNum &&
871 pWorkingNodeNum->GetLevelInListTree() >= 0 &&
872 pWorkingNodeNum->GetLevelInListTree() >= nRestrictInclToThisLevel );
875 if (aRefNumStr.endsWith("."))
877 // tdf#144563: looks like a special case for refs by MS Word: if numbering is ending with dot, this dot is removed
878 aRefNumStr = aRefNumStr.copy(0, aRefNumStr.getLength() - 1);
881 return aRefNumStr;
884 OUString SwNumRule::MakeParagraphStyleListString() const
886 OUString aParagraphStyleListString;
887 for (const auto& rParagraphStyle : maParagraphStyleList)
889 if (!aParagraphStyleListString.isEmpty())
890 aParagraphStyleListString += ", ";
891 aParagraphStyleListString += rParagraphStyle->GetName();
893 return aParagraphStyleListString;
896 /** Copy method of SwNumRule
898 A kind of copy constructor, so that the num formats are attached to the
899 right CharFormats of a Document.
900 Copies the NumFormats and returns itself. */
901 SwNumRule& SwNumRule::CopyNumRule( SwDoc& rDoc, const SwNumRule& rNumRule )
903 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
905 Set( n, rNumRule.maFormats[ n ].get() );
906 if( maFormats[ n ] && maFormats[ n ]->GetCharFormat() &&
907 !rDoc.GetCharFormats()->ContainsFormat(maFormats[n]->GetCharFormat()))
909 // If we copy across different Documents, then copy the
910 // corresponding CharFormat into the new Document.
911 maFormats[n]->SetCharFormat( rDoc.CopyCharFormat( *maFormats[n]->
912 GetCharFormat() ) );
915 meRuleType = rNumRule.meRuleType;
916 msName = rNumRule.msName;
917 mbAutoRuleFlag = rNumRule.mbAutoRuleFlag;
918 mnPoolFormatId = rNumRule.GetPoolFormatId();
919 mnPoolHelpId = rNumRule.GetPoolHelpId();
920 mnPoolHlpFileId = rNumRule.GetPoolHlpFileId();
921 mbInvalidRuleFlag = true;
922 return *this;
925 void SwNumRule::SetSvxRule(const SvxNumRule& rNumRule, SwDoc* pDoc)
927 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
929 const SvxNumberFormat* pSvxFormat = rNumRule.Get(n);
930 maFormats[n].reset( pSvxFormat ? new SwNumFormat(*pSvxFormat, pDoc) : nullptr );
933 mbInvalidRuleFlag = true;
934 mbContinusNum = rNumRule.IsContinuousNumbering();
937 SvxNumRule SwNumRule::MakeSvxNumRule() const
939 SvxNumRule aRule(SvxNumRuleFlags::CONTINUOUS | SvxNumRuleFlags::CHAR_STYLE |
940 SvxNumRuleFlags::ENABLE_LINKED_BMP | SvxNumRuleFlags::ENABLE_EMBEDDED_BMP,
941 MAXLEVEL, mbContinusNum,
942 meRuleType == NUM_RULE ? SvxNumRuleType::NUMBERING : SvxNumRuleType::OUTLINE_NUMBERING );
943 for( sal_uInt16 n = 0; n < MAXLEVEL; ++n )
945 const SwNumFormat & rNumFormat = Get(n);
946 if(rNumFormat.GetCharFormat())
948 SwNumFormat aNewFormat = rNumFormat;
949 aNewFormat.SetCharFormatName(rNumFormat.GetCharFormat()->GetName());
950 aRule.SetLevel(n, aNewFormat, maFormats[n] != nullptr);
952 else
953 aRule.SetLevel(n, rNumFormat, maFormats[n] != nullptr);
955 return aRule;
958 void SwNumRule::SetInvalidRule(bool bFlag)
960 if (mbInvalidRuleFlag == bFlag)
961 return;
963 if (bFlag)
965 o3tl::sorted_vector< SwList* > aLists;
966 for ( const SwTextNode* pTextNode : maTextNodeList )
968 // #i111681# - applying patch from cmc
969 SwList* pList = pTextNode->GetDoc().getIDocumentListsAccess().getListByName( pTextNode->GetListId() );
970 OSL_ENSURE( pList, "<SwNumRule::SetInvalidRule(..)> - list at which the text node is registered at does not exist. This is a serious issue.");
971 if ( pList )
973 aLists.insert( pList );
976 for ( auto aList : aLists )
977 aList->InvalidateListTree();
980 mbInvalidRuleFlag = bFlag;
983 /// change indent of all list levels by given difference
984 void SwNumRule::ChangeIndent( const sal_Int32 nDiff )
986 for ( sal_uInt16 i = 0; i < MAXLEVEL; ++i )
988 SwNumFormat aTmpNumFormat( Get(i) );
990 const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
991 aTmpNumFormat.GetPositionAndSpaceMode() );
992 if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
994 auto nNewIndent = nDiff +
995 aTmpNumFormat.GetAbsLSpace();
996 if ( nNewIndent < 0 )
998 nNewIndent = 0;
1000 aTmpNumFormat.SetAbsLSpace( nNewIndent );
1002 else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
1004 // adjust also the list tab position, if a list tab stop is applied
1005 if ( aTmpNumFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
1007 const tools::Long nNewListTab = aTmpNumFormat.GetListtabPos() + nDiff;
1008 aTmpNumFormat.SetListtabPos( nNewListTab );
1011 const tools::Long nNewIndent = nDiff +
1012 aTmpNumFormat.GetIndentAt();
1013 aTmpNumFormat.SetIndentAt( nNewIndent );
1016 Set( i, aTmpNumFormat );
1019 SetInvalidRule( true );
1022 /// set indent of certain list level to given value
1023 void SwNumRule::SetIndent( const short nNewIndent,
1024 const sal_uInt16 nListLevel )
1026 SwNumFormat aTmpNumFormat( Get(nListLevel) );
1028 const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
1029 aTmpNumFormat.GetPositionAndSpaceMode() );
1030 if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1032 aTmpNumFormat.SetAbsLSpace( nNewIndent );
1034 else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
1036 // adjust also the list tab position, if a list tab stop is applied
1037 if ( aTmpNumFormat.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB )
1039 const tools::Long nNewListTab = aTmpNumFormat.GetListtabPos() +
1040 ( nNewIndent - aTmpNumFormat.GetIndentAt() );
1041 aTmpNumFormat.SetListtabPos( nNewListTab );
1044 aTmpNumFormat.SetIndentAt( nNewIndent );
1047 SetInvalidRule( true );
1050 /// set indent of first list level to given value and change other list level's
1051 /// indents accordingly
1052 void SwNumRule::SetIndentOfFirstListLevelAndChangeOthers( const short nNewIndent )
1054 SwNumFormat aTmpNumFormat( Get(0) );
1056 sal_Int32 nDiff( 0 );
1057 const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
1058 aTmpNumFormat.GetPositionAndSpaceMode() );
1059 if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
1061 nDiff = nNewIndent
1062 - aTmpNumFormat.GetFirstLineOffset()
1063 - aTmpNumFormat.GetAbsLSpace();
1065 else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
1067 nDiff = nNewIndent - aTmpNumFormat.GetIndentAt();
1069 if ( nDiff != 0 )
1071 ChangeIndent( nDiff );
1075 void SwNumRule::Validate(const SwDoc& rDoc)
1077 o3tl::sorted_vector< SwList* > aLists;
1078 for ( const SwTextNode* pTextNode : maTextNodeList )
1080 aLists.insert( pTextNode->GetDoc().getIDocumentListsAccess().getListByName( pTextNode->GetListId() ) );
1082 for ( auto aList : aLists )
1083 aList->ValidateListTree(rDoc);
1085 SetInvalidRule(false);
1088 void SwNumRule::SetCountPhantoms(bool bCountPhantoms)
1090 mbCountPhantoms = bCountPhantoms;
1093 SwNumRule::tParagraphStyleList::size_type SwNumRule::GetParagraphStyleListSize() const
1095 return maParagraphStyleList.size();
1098 void SwNumRule::AddParagraphStyle( SwTextFormatColl& rTextFormatColl )
1100 tParagraphStyleList::iterator aIter =
1101 std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTextFormatColl );
1103 if ( aIter == maParagraphStyleList.end() )
1105 maParagraphStyleList.push_back( &rTextFormatColl );
1109 void SwNumRule::RemoveParagraphStyle( SwTextFormatColl& rTextFormatColl )
1111 tParagraphStyleList::iterator aIter =
1112 std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTextFormatColl );
1114 if ( aIter != maParagraphStyleList.end() )
1116 maParagraphStyleList.erase( aIter );
1120 void SwNumRule::dumpAsXml(xmlTextWriterPtr pWriter) const
1122 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwNumRule"));
1123 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("msName"), BAD_CAST(msName.toUtf8().getStr()));
1124 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mnPoolFormatId"), BAD_CAST(OString::number(mnPoolFormatId).getStr()));
1125 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("mbAutoRuleFlag"), BAD_CAST(OString::boolean(mbAutoRuleFlag).getStr()));
1127 for (const auto& pFormat : maFormats)
1129 if (!pFormat)
1131 continue;
1134 pFormat->dumpAsXml(pWriter);
1137 (void)xmlTextWriterEndElement(pWriter);
1140 void SwNumRule::GetGrabBagItem(uno::Any& rVal) const
1142 if (mpGrabBagItem)
1143 mpGrabBagItem->QueryValue(rVal);
1144 else
1145 rVal <<= uno::Sequence<beans::PropertyValue>();
1148 void SwNumRule::SetGrabBagItem(const uno::Any& rVal)
1150 if (!mpGrabBagItem)
1151 mpGrabBagItem = std::make_shared<SfxGrabBagItem>();
1153 mpGrabBagItem->PutValue(rVal, 0);
1156 namespace numfunc
1158 namespace {
1160 /** class containing default bullet list configuration data */
1161 class SwDefBulletConfig : private utl::ConfigItem
1163 public:
1164 static SwDefBulletConfig& getInstance();
1166 const OUString& GetFontname() const
1168 return msFontname;
1171 bool IsFontnameUserDefined() const
1173 return mbUserDefinedFontname;
1176 const vcl::Font& GetFont() const
1178 return *mpFont;
1181 sal_Unicode GetChar( sal_uInt8 p_nListLevel ) const
1183 if (p_nListLevel >= MAXLEVEL)
1185 p_nListLevel = MAXLEVEL - 1;
1188 return mnLevelChars[p_nListLevel];
1191 SwDefBulletConfig();
1193 private:
1194 /** sets internal default bullet configuration data to default values */
1195 void SetToDefault();
1197 /** returns sequence of default bullet configuration property names */
1198 static uno::Sequence<OUString> GetPropNames();
1200 /** loads default bullet configuration properties and applies
1201 values to internal data */
1202 void LoadConfig();
1204 /** initialize font instance for default bullet list */
1205 void InitFont();
1207 /** catches notification about changed default bullet configuration data */
1208 virtual void Notify( const uno::Sequence<OUString>& aPropertyNames ) override;
1209 virtual void ImplCommit() override;
1211 // default bullet list configuration data
1212 OUString msFontname;
1213 bool mbUserDefinedFontname;
1214 FontWeight meFontWeight;
1215 FontItalic meFontItalic;
1216 sal_Unicode mnLevelChars[MAXLEVEL];
1218 // default bullet list font instance
1219 std::optional<vcl::Font> mpFont;
1224 SwDefBulletConfig& SwDefBulletConfig::getInstance()
1226 static SwDefBulletConfig theSwDefBulletConfig;
1227 return theSwDefBulletConfig;
1230 SwDefBulletConfig::SwDefBulletConfig()
1231 : ConfigItem( "Office.Writer/Numbering/DefaultBulletList" ),
1232 // default bullet font is now OpenSymbol
1233 msFontname( OUString("OpenSymbol") ),
1234 mbUserDefinedFontname( false ),
1235 meFontWeight( WEIGHT_DONTKNOW ),
1236 meFontItalic( ITALIC_NONE )
1238 SetToDefault();
1239 LoadConfig();
1240 InitFont();
1242 // enable notification for changes on default bullet configuration change
1243 EnableNotification( GetPropNames() );
1246 void SwDefBulletConfig::SetToDefault()
1248 msFontname = "OpenSymbol";
1249 mbUserDefinedFontname = false;
1250 meFontWeight = WEIGHT_DONTKNOW;
1251 meFontItalic = ITALIC_NONE;
1253 mnLevelChars[0] = 0x2022;
1254 mnLevelChars[1] = 0x25e6;
1255 mnLevelChars[2] = 0x25aa;
1256 mnLevelChars[3] = 0x2022;
1257 mnLevelChars[4] = 0x25e6;
1258 mnLevelChars[5] = 0x25aa;
1259 mnLevelChars[6] = 0x2022;
1260 mnLevelChars[7] = 0x25e6;
1261 mnLevelChars[8] = 0x25aa;
1262 mnLevelChars[9] = 0x2022;
1265 uno::Sequence<OUString> SwDefBulletConfig::GetPropNames()
1267 uno::Sequence<OUString> aPropNames(13);
1268 OUString* pNames = aPropNames.getArray();
1269 pNames[0] = "BulletFont/FontFamilyname";
1270 pNames[1] = "BulletFont/FontWeight";
1271 pNames[2] = "BulletFont/FontItalic";
1272 pNames[3] = "BulletCharLvl1";
1273 pNames[4] = "BulletCharLvl2";
1274 pNames[5] = "BulletCharLvl3";
1275 pNames[6] = "BulletCharLvl4";
1276 pNames[7] = "BulletCharLvl5";
1277 pNames[8] = "BulletCharLvl6";
1278 pNames[9] = "BulletCharLvl7";
1279 pNames[10] = "BulletCharLvl8";
1280 pNames[11] = "BulletCharLvl9";
1281 pNames[12] = "BulletCharLvl10";
1283 return aPropNames;
1286 void SwDefBulletConfig::LoadConfig()
1288 uno::Sequence<OUString> aPropNames = GetPropNames();
1289 uno::Sequence<uno::Any> aValues = GetProperties( aPropNames );
1290 const uno::Any* pValues = aValues.getConstArray();
1291 OSL_ENSURE( aValues.getLength() == aPropNames.getLength(),
1292 "<SwDefBulletConfig::SwDefBulletConfig()> - GetProperties failed");
1293 if ( aValues.getLength() != aPropNames.getLength() )
1294 return;
1296 for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp )
1298 if ( pValues[nProp].hasValue() )
1300 switch ( nProp )
1302 case 0:
1304 OUString aStr;
1305 pValues[nProp] >>= aStr;
1306 msFontname = aStr;
1307 mbUserDefinedFontname = true;
1309 break;
1310 case 1:
1311 case 2:
1313 sal_Int16 nTmp = 0;
1314 pValues[nProp] >>= nTmp;
1315 if ( nProp == 1 )
1316 meFontWeight = static_cast<FontWeight>(nTmp);
1317 else if ( nProp == 2 )
1318 meFontItalic = static_cast<FontItalic>(nTmp);
1320 break;
1321 case 3:
1322 case 4:
1323 case 5:
1324 case 6:
1325 case 7:
1326 case 8:
1327 case 9:
1328 case 10:
1329 case 11:
1330 case 12:
1332 sal_Unicode cChar = sal_Unicode();
1333 pValues[nProp] >>= cChar;
1334 mnLevelChars[nProp-3] = cChar;
1336 break;
1343 void SwDefBulletConfig::InitFont()
1345 mpFont.emplace( msFontname, OUString(), Size( 0, 14 ) );
1346 mpFont->SetWeight( meFontWeight );
1347 mpFont->SetItalic( meFontItalic );
1348 mpFont->SetCharSet( RTL_TEXTENCODING_SYMBOL );
1351 void SwDefBulletConfig::Notify( const uno::Sequence<OUString>& )
1353 SetToDefault();
1354 LoadConfig();
1355 InitFont();
1358 void SwDefBulletConfig::ImplCommit()
1362 OUString const & GetDefBulletFontname()
1364 return SwDefBulletConfig::getInstance().GetFontname();
1367 bool IsDefBulletFontUserDefined()
1369 return SwDefBulletConfig::getInstance().IsFontnameUserDefined();
1372 const vcl::Font& GetDefBulletFont()
1374 return SwDefBulletConfig::getInstance().GetFont();
1377 sal_Unicode GetBulletChar( sal_uInt8 nLevel )
1379 return SwDefBulletConfig::getInstance().GetChar( nLevel );
1382 namespace {
1384 /** class containing configuration data about user interface behavior
1385 regarding lists and list items.
1386 configuration item about behavior of <TAB>/<SHIFT-TAB>-key at first
1387 position of first list item
1389 class SwNumberingUIBehaviorConfig : private utl::ConfigItem
1391 public:
1392 static SwNumberingUIBehaviorConfig& getInstance();
1394 bool ChangeIndentOnTabAtFirstPosOfFirstListItem() const
1396 return mbChangeIndentOnTabAtFirstPosOfFirstListItem;
1399 SwNumberingUIBehaviorConfig();
1401 private:
1403 /** sets internal configuration data to default values */
1404 void SetToDefault();
1406 /** returns sequence of configuration property names */
1407 static css::uno::Sequence<OUString> GetPropNames();
1409 /** loads configuration properties and applies values to internal data */
1410 void LoadConfig();
1412 /** catches notification about changed configuration data */
1413 virtual void Notify( const css::uno::Sequence<OUString>& aPropertyNames ) override;
1414 virtual void ImplCommit() override;
1416 // configuration data
1417 bool mbChangeIndentOnTabAtFirstPosOfFirstListItem;
1422 SwNumberingUIBehaviorConfig& SwNumberingUIBehaviorConfig::getInstance()
1424 static SwNumberingUIBehaviorConfig theSwNumberingUIBehaviorConfig;
1425 return theSwNumberingUIBehaviorConfig;
1428 SwNumberingUIBehaviorConfig::SwNumberingUIBehaviorConfig()
1429 : ConfigItem( "Office.Writer/Numbering/UserInterfaceBehavior" ),
1430 mbChangeIndentOnTabAtFirstPosOfFirstListItem( true )
1432 SetToDefault();
1433 LoadConfig();
1435 // enable notification for changes on configuration change
1436 EnableNotification( GetPropNames() );
1439 void SwNumberingUIBehaviorConfig::SetToDefault()
1441 mbChangeIndentOnTabAtFirstPosOfFirstListItem = true;
1444 css::uno::Sequence<OUString> SwNumberingUIBehaviorConfig::GetPropNames()
1446 css::uno::Sequence<OUString> aPropNames { "ChangeIndentOnTabAtFirstPosOfFirstListItem" };
1448 return aPropNames;
1451 void SwNumberingUIBehaviorConfig::ImplCommit() {}
1453 void SwNumberingUIBehaviorConfig::LoadConfig()
1455 css::uno::Sequence<OUString> aPropNames = GetPropNames();
1456 css::uno::Sequence<css::uno::Any> aValues = GetProperties( aPropNames );
1457 const css::uno::Any* pValues = aValues.getConstArray();
1458 OSL_ENSURE( aValues.getLength() == aPropNames.getLength(),
1459 "<SwNumberingUIBehaviorConfig::LoadConfig()> - GetProperties failed");
1460 if ( aValues.getLength() != aPropNames.getLength() )
1461 return;
1463 for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp )
1465 if ( pValues[nProp].hasValue() )
1467 switch ( nProp )
1469 case 0:
1471 pValues[nProp] >>= mbChangeIndentOnTabAtFirstPosOfFirstListItem;
1473 break;
1474 default:
1476 OSL_FAIL( "<SwNumberingUIBehaviorConfig::LoadConfig()> - unknown configuration property");
1483 void SwNumberingUIBehaviorConfig::Notify( const css::uno::Sequence<OUString>& )
1485 SetToDefault();
1486 LoadConfig();
1489 bool ChangeIndentOnTabAtFirstPosOfFirstListItem()
1491 return SwNumberingUIBehaviorConfig::getInstance().ChangeIndentOnTabAtFirstPosOfFirstListItem();
1494 bool NumDownChangesIndent(const SwWrtShell& rShell)
1496 SwPaM* pCursor = rShell.GetCursor();
1497 if (!pCursor)
1499 return true;
1502 SwTextNode* pTextNode = pCursor->GetPointNode().GetTextNode();
1503 if (!pTextNode)
1505 return true;
1508 const SwNumRule* pNumRule = pTextNode->GetNumRule();
1509 if (!pNumRule)
1511 return true;
1514 int nOldLevel = pTextNode->GetActualListLevel();
1515 int nNewLevel = nOldLevel + 1;
1516 if (nNewLevel >= MAXLEVEL)
1518 return true;
1521 const SwNumFormat& rOldFormat = pNumRule->Get(nOldLevel);
1522 if (rOldFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE)
1524 return true;
1527 const SwNumFormat& rNewFormat = pNumRule->Get(nNewLevel);
1528 if (rNewFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE)
1530 return true;
1533 // This is the case when the numbering levels don't differ, so changing between them is not
1534 // a better alternative to inserting a tab character.
1535 return rOldFormat.GetIndentAt() != rNewFormat.GetIndentAt();
1538 SvxNumberFormat::SvxNumPositionAndSpaceMode GetDefaultPositionAndSpaceMode()
1540 if (utl::ConfigManager::IsFuzzing())
1541 return SvxNumberFormat::LABEL_ALIGNMENT;
1543 SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode;
1544 switch (GetODFSaneDefaultVersion())
1546 case SvtSaveOptions::ODFSVER_010:
1547 case SvtSaveOptions::ODFSVER_011:
1549 ePosAndSpaceMode = SvxNumberFormat::LABEL_WIDTH_AND_POSITION;
1551 break;
1552 default: // >= ODFSVER_012
1554 ePosAndSpaceMode = SvxNumberFormat::LABEL_ALIGNMENT;
1558 return ePosAndSpaceMode;
1562 void SwNumRuleTable::dumpAsXml(xmlTextWriterPtr pWriter) const
1564 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwNumRuleTable"));
1565 for (SwNumRule* pNumRule : *this)
1566 pNumRule->dumpAsXml(pWriter);
1567 (void)xmlTextWriterEndElement(pWriter);
1570 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */