1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include "ConversionHelper.hxx"
23 #include "NumberingManager.hxx"
24 #include "StyleSheetTable.hxx"
25 #include "PropertyIds.hxx"
26 
27 #include <ooxml/resourceids.hxx>
28 
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/container/XNameContainer.hpp>
31 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
32 #include <com/sun/star/style/NumberingType.hpp>
33 #include <com/sun/star/text/HoriOrientation.hpp>
34 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
35 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
36 #include <com/sun/star/graphic/XGraphic.hpp>
37 #include <com/sun/star/awt/XBitmap.hpp>
38 
39 #include <osl/diagnose.h>
40 #include <rtl/ustring.hxx>
41 #include <sal/log.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <tools/UnitConversion.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <comphelper/propertyvalue.hxx>
46 #include <comphelper/string.hxx>
47 #include <regex>
48 
49 using namespace com::sun::star;
50 
51 namespace writerfilter::dmapper {
52 
53 //---------------------------------------------------  Utility functions
54 template <typename T>
lcl_makePropVal(PropertyIds nNameID,T const & aValue)55 static beans::PropertyValue lcl_makePropVal(PropertyIds nNameID, T const & aValue)
56 {
57     return {getPropertyName(nNameID), 0, uno::makeAny(aValue), beans::PropertyState_DIRECT_VALUE};
58 }
59 
lcl_findProperty(const uno::Sequence<beans::PropertyValue> & aProps,std::u16string_view sName)60 static sal_Int32 lcl_findProperty( const uno::Sequence< beans::PropertyValue >& aProps, std::u16string_view sName )
61 {
62     sal_Int32 i = 0;
63     sal_Int32 nLen = aProps.getLength( );
64     sal_Int32 nPos = -1;
65 
66     while ( nPos == -1 && i < nLen )
67     {
68         if ( aProps[i].Name == sName )
69             nPos = i;
70         else
71             i++;
72     }
73 
74     return nPos;
75 }
76 
lcl_mergeProperties(const uno::Sequence<beans::PropertyValue> & aSrc,uno::Sequence<beans::PropertyValue> & aDst)77 static void lcl_mergeProperties( const uno::Sequence< beans::PropertyValue >& aSrc,
78         uno::Sequence< beans::PropertyValue >& aDst )
79 {
80     for ( const auto& rProp : aSrc )
81     {
82         // Look for the same property in aDst
83         sal_Int32 nPos = lcl_findProperty( aDst, rProp.Name );
84         if ( nPos >= 0 )
85         {
86             // Replace the property value by the one in aSrc
87             aDst[nPos] = rProp;
88         }
89         else
90         {
91             // Simply add the new value
92             aDst.realloc( aDst.getLength( ) + 1 );
93             aDst[ aDst.getLength( ) - 1 ] = rProp;
94         }
95     }
96 }
97 
98 //--------------------------------------------  ListLevel implementation
SetValue(Id nId,sal_Int32 nValue)99 void ListLevel::SetValue( Id nId, sal_Int32 nValue )
100 {
101     switch( nId )
102     {
103         case NS_ooxml::LN_CT_Lvl_start:
104             m_nIStartAt = nValue;
105         break;
106         case NS_ooxml::LN_CT_NumLvl_startOverride:
107             m_nStartOverride = nValue;
108             break;
109         case NS_ooxml::LN_CT_NumFmt_val:
110             m_nNFC = nValue;
111         break;
112         case NS_ooxml::LN_CT_Lvl_isLgl:
113         break;
114         case NS_ooxml::LN_CT_Lvl_legacy:
115         break;
116         case NS_ooxml::LN_CT_Lvl_suff:
117             m_nXChFollow = nValue;
118         break;
119         case NS_ooxml::LN_CT_TabStop_pos:
120             if (nValue < 0)
121             {
122                 SAL_INFO("writerfilter",
123                         "unsupported list tab stop position " << nValue);
124             }
125             else
126                 m_nTabstop = nValue;
127         break;
128         default:
129             OSL_FAIL( "this line should never be reached");
130     }
131     m_bHasValues = true;
132 }
133 
SetCustomNumberFormat(const OUString & rValue)134 void ListLevel::SetCustomNumberFormat(const OUString& rValue) { m_aCustomNumberFormat = rValue; }
135 
HasValues() const136 bool ListLevel::HasValues() const
137 {
138     return m_bHasValues;
139 }
140 
SetParaStyle(const tools::SvRef<StyleSheetEntry> & pStyle)141 void ListLevel::SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle )
142 {
143     if (!pStyle)
144         return;
145     m_pParaStyle = pStyle;
146     // AFAICT .docx spec does not identify which numberings or paragraph
147     // styles are actually the ones to be used for outlines (chapter numbering),
148     // it only kind of says somewhere that they should be named Heading1 to Heading9.
149     const OUString styleId= pStyle->sConvertedStyleName;
150     m_outline = ( styleId.getLength() == RTL_CONSTASCII_LENGTH( "Heading 1" )
151         && styleId.match( "Heading ", 0 )
152         && styleId[ RTL_CONSTASCII_LENGTH( "Heading " ) ] >= '1'
153         && styleId[ RTL_CONSTASCII_LENGTH( "Heading " ) ] <= '9' );
154 }
155 
GetProperties(bool bDefaults)156 uno::Sequence<beans::PropertyValue> ListLevel::GetProperties(bool bDefaults)
157 {
158     uno::Sequence<beans::PropertyValue> aLevelProps = GetLevelProperties(bDefaults);
159     if (m_pParaStyle)
160         AddParaProperties( &aLevelProps );
161     return aLevelProps;
162 }
163 
IgnoreForCharStyle(std::u16string_view aStr,const bool bIsSymbol)164 static bool IgnoreForCharStyle(std::u16string_view aStr, const bool bIsSymbol)
165 {
166     //Names found in PropertyIds.cxx, Lines 56-396
167     return (aStr==u"Adjust" || aStr==u"IndentAt" || aStr==u"FirstLineIndent"
168             || aStr==u"FirstLineOffset" || aStr==u"LeftMargin"
169             // We need font names when they are different for the bullet and for the text.
170             // But leave symbols alone, we only want to keep the font style for letters and numbers.
171             || (bIsSymbol && aStr==u"CharFontName")
172         );
173 }
GetCharStyleProperties()174 uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( )
175 {
176     PropertyValueVector_t rProperties;
177 
178     uno::Sequence< beans::PropertyValue > vPropVals = PropertyMap::GetPropertyValues();
179     beans::PropertyValue* aValIter = vPropVals.begin();
180     beans::PropertyValue* aEndIter = vPropVals.end();
181     const bool bIsSymbol(GetBulletChar().getLength() <= 1);
182     for( ; aValIter != aEndIter; ++aValIter )
183         if (! IgnoreForCharStyle(aValIter->Name, bIsSymbol))
184             rProperties.emplace_back(aValIter->Name, 0, aValIter->Value, beans::PropertyState_DIRECT_VALUE);
185 
186     return comphelper::containerToSequence(rProperties);
187 }
188 
GetLevelProperties(bool bDefaults)189 uno::Sequence<beans::PropertyValue> ListLevel::GetLevelProperties(bool bDefaults)
190 {
191     std::vector<beans::PropertyValue> aNumberingProperties;
192 
193     if (m_nIStartAt >= 0)
194         aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, m_nIStartAt) );
195     else if (bDefaults)
196         aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, 0));
197 
198     sal_Int16 nNumberFormat = -1;
199     if (m_nNFC == NS_ooxml::LN_Value_ST_NumberFormat_custom)
200     {
201         nNumberFormat = ConversionHelper::ConvertCustomNumberFormat(m_aCustomNumberFormat);
202     }
203     else
204     {
205         nNumberFormat = ConversionHelper::ConvertNumberingType(m_nNFC);
206     }
207     if( m_nNFC >= 0)
208     {
209         if (m_xGraphicBitmap.is())
210             nNumberFormat = style::NumberingType::BITMAP;
211         aNumberingProperties.push_back(lcl_makePropVal(PROP_NUMBERING_TYPE, nNumberFormat));
212     }
213 
214     // todo: this is not the bullet char
215     if( nNumberFormat == style::NumberingType::CHAR_SPECIAL )
216     {
217         if (!GetBulletChar().isEmpty())
218         {
219             aNumberingProperties.push_back(lcl_makePropVal(PROP_BULLET_CHAR, m_sBulletChar->copy(0, 1)));
220         }
221         else
222         {
223             // If w:lvlText's value is null - set bullet char to zero.
224             aNumberingProperties.push_back(lcl_makePropVal<sal_Unicode>(PROP_BULLET_CHAR, 0));
225         }
226     }
227     if (m_xGraphicBitmap.is())
228     {
229         aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_BITMAP, m_xGraphicBitmap));
230         aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_SIZE, m_aGraphicSize));
231     }
232 
233     if (m_nTabstop.has_value())
234         aNumberingProperties.push_back(lcl_makePropVal(PROP_LISTTAB_STOP_POSITION, *m_nTabstop));
235     else if (bDefaults)
236         aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_LISTTAB_STOP_POSITION, 0));
237 
238     //TODO: handling of nFLegal?
239     //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
240     //1.
241     //1.1
242     //2.2
243     //2.3
244     //3.4
245 
246 //    TODO: sRGBXchNums;     array of inherited numbers
247 
248 //  nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
249     if (bDefaults || m_nXChFollow != SvxNumberFormat::LISTTAB)
250         aNumberingProperties.push_back(lcl_makePropVal(PROP_LEVEL_FOLLOW, m_nXChFollow));
251 
252     PropertyIds const aReadIds[] =
253     {
254         PROP_ADJUST, PROP_INDENT_AT, PROP_FIRST_LINE_INDENT,
255         PROP_FIRST_LINE_OFFSET, PROP_LEFT_MARGIN
256     };
257     for(PropertyIds const & rReadId : aReadIds) {
258         std::optional<PropertyMap::Property> aProp = getProperty(rReadId);
259         if (aProp)
260             aNumberingProperties.emplace_back( getPropertyName(aProp->first), 0, aProp->second, beans::PropertyState_DIRECT_VALUE );
261         else if (rReadId == PROP_FIRST_LINE_INDENT && bDefaults)
262             // Writer default is -360 twips, Word default seems to be 0.
263             aNumberingProperties.emplace_back("FirstLineIndent", 0, uno::makeAny(static_cast<sal_Int32>(0)), beans::PropertyState_DIRECT_VALUE);
264         else if (rReadId == PROP_INDENT_AT && bDefaults)
265             // Writer default is 720 twips, Word default seems to be 0.
266             aNumberingProperties.emplace_back("IndentAt", 0,
267                                               uno::makeAny(static_cast<sal_Int32>(0)),
268                                               beans::PropertyState_DIRECT_VALUE);
269     }
270 
271     std::optional<PropertyMap::Property> aPropFont = getProperty(PROP_CHAR_FONT_NAME);
272     if (aPropFont)
273         aNumberingProperties.emplace_back( getPropertyName(PROP_BULLET_FONT_NAME), 0, aPropFont->second, beans::PropertyState_DIRECT_VALUE );
274 
275     return comphelper::containerToSequence(aNumberingProperties);
276 }
277 
278 // Add the properties only if they do not already exist in the sequence.
AddParaProperties(uno::Sequence<beans::PropertyValue> * props)279 void ListLevel::AddParaProperties( uno::Sequence< beans::PropertyValue >* props )
280 {
281     uno::Sequence< beans::PropertyValue >& aProps = *props;
282 
283     OUString sFirstLineIndent = getPropertyName(
284             PROP_FIRST_LINE_INDENT );
285     OUString sIndentAt = getPropertyName(
286             PROP_INDENT_AT );
287 
288     bool hasFirstLineIndent = lcl_findProperty( aProps, sFirstLineIndent );
289     bool hasIndentAt = lcl_findProperty( aProps, sIndentAt );
290 
291     if( hasFirstLineIndent && hasIndentAt )
292         return; // has them all, nothing to add
293 
294     const uno::Sequence< beans::PropertyValue > aParaProps = m_pParaStyle->pProperties->GetPropertyValues( );
295 
296     // ParaFirstLineIndent -> FirstLineIndent
297     // ParaLeftMargin -> IndentAt
298 
299     OUString sParaIndent = getPropertyName(
300             PROP_PARA_FIRST_LINE_INDENT );
301     OUString sParaLeftMargin = getPropertyName(
302             PROP_PARA_LEFT_MARGIN );
303 
304     for ( const auto& rParaProp : aParaProps )
305     {
306         if ( !hasFirstLineIndent && rParaProp.Name == sParaIndent )
307         {
308             aProps.realloc( aProps.getLength() + 1 );
309             aProps[aProps.getLength( ) - 1] = rParaProp;
310             aProps[aProps.getLength( ) - 1].Name = sFirstLineIndent;
311         }
312         else if ( !hasIndentAt && rParaProp.Name == sParaLeftMargin )
313         {
314             aProps.realloc( aProps.getLength() + 1 );
315             aProps[aProps.getLength( ) - 1] = rParaProp;
316             aProps[aProps.getLength( ) - 1].Name = sIndentAt;
317         }
318 
319     }
320 }
321 
NumPicBullet()322 NumPicBullet::NumPicBullet()
323     : m_nId(0)
324 {
325 }
326 
~NumPicBullet()327 NumPicBullet::~NumPicBullet()
328 {
329 }
330 
SetId(sal_Int32 nId)331 void NumPicBullet::SetId(sal_Int32 nId)
332 {
333     m_nId = nId;
334 }
335 
SetShape(uno::Reference<drawing::XShape> const & xShape)336 void NumPicBullet::SetShape(uno::Reference<drawing::XShape> const& xShape)
337 {
338     m_xShape = xShape;
339 }
340 
341 
342 //--------------------------------------- AbstractListDef implementation
343 
AbstractListDef()344 AbstractListDef::AbstractListDef( ) :
345     m_nId( -1 )
346 {
347 }
348 
~AbstractListDef()349 AbstractListDef::~AbstractListDef( )
350 {
351 }
352 
SetValue(sal_uInt32 nSprmId)353 void AbstractListDef::SetValue( sal_uInt32 nSprmId )
354 {
355     switch( nSprmId )
356     {
357         case NS_ooxml::LN_CT_AbstractNum_tmpl:
358         break;
359         default:
360             OSL_FAIL( "this line should never be reached");
361     }
362 }
363 
GetLevel(sal_uInt16 nLvl)364 ListLevel::Pointer AbstractListDef::GetLevel( sal_uInt16 nLvl )
365 {
366     ListLevel::Pointer pLevel;
367     if ( m_aLevels.size( ) > nLvl )
368         pLevel = m_aLevels[ nLvl ];
369     return pLevel;
370 }
371 
AddLevel(sal_uInt16 nLvl)372 void AbstractListDef::AddLevel( sal_uInt16 nLvl )
373 {
374     if ( nLvl >= m_aLevels.size() )
375         m_aLevels.resize( nLvl+1 );
376 
377     ListLevel::Pointer pLevel( new ListLevel );
378     m_pCurrentLevel = pLevel;
379     m_aLevels[nLvl] = pLevel;
380 }
381 
GetPropertyValues(bool bDefaults)382 uno::Sequence<uno::Sequence<beans::PropertyValue>> AbstractListDef::GetPropertyValues(bool bDefaults)
383 {
384     uno::Sequence< uno::Sequence< beans::PropertyValue > > result( sal_Int32( m_aLevels.size( ) ) );
385     uno::Sequence< beans::PropertyValue >* aResult = result.getArray( );
386 
387     int nLevels = m_aLevels.size( );
388     for ( int i = 0; i < nLevels; i++ )
389     {
390         if (m_aLevels[i])
391             aResult[i] = m_aLevels[i]->GetProperties(bDefaults);
392     }
393 
394     return result;
395 }
396 
MapListId(OUString const & rId)397 const OUString& AbstractListDef::MapListId(OUString const& rId)
398 {
399     if (!m_oListId)
400     {
401         m_oListId = rId;
402     }
403     return *m_oListId;
404 }
405 
406 //----------------------------------------------  ListDef implementation
407 
ListDef()408 ListDef::ListDef( ) : AbstractListDef( )
409 {
410     m_nDefaultParentLevels = WW_OUTLINE_MAX + 1;
411 }
412 
~ListDef()413 ListDef::~ListDef( )
414 {
415 }
416 
GetStyleName(sal_Int32 const nId,uno::Reference<container::XNameContainer> const & xStyles)417 const OUString & ListDef::GetStyleName(sal_Int32 const nId,
418     uno::Reference<container::XNameContainer> const& xStyles)
419 {
420     if (xStyles.is())
421     {
422         OUString sStyleName = "WWNum" + OUString::number( nId );
423 
424         while (xStyles->hasByName(sStyleName)) // unique
425         {
426             sStyleName += "a";
427         }
428 
429         m_StyleName = sStyleName;
430     }
431     else
432     {
433 // fails in rtftok test        assert(!m_StyleName.isEmpty()); // must be inited first
434     }
435 
436     return m_StyleName;
437 }
438 
GetMergedPropertyValues()439 uno::Sequence<uno::Sequence<beans::PropertyValue>> ListDef::GetMergedPropertyValues()
440 {
441     if (!m_pAbstractDef)
442         return uno::Sequence< uno::Sequence< beans::PropertyValue > >();
443 
444     // [1] Call the same method on the abstract list
445     uno::Sequence<uno::Sequence<beans::PropertyValue>> aAbstract
446         = m_pAbstractDef->GetPropertyValues(/*bDefaults=*/true);
447 
448     // [2] Call the upper class method
449     uno::Sequence<uno::Sequence<beans::PropertyValue>> aThis
450         = AbstractListDef::GetPropertyValues(/*bDefaults=*/false);
451 
452     // Merge the results of [2] in [1]
453     sal_Int32 nThisCount = aThis.getLength( );
454     sal_Int32 nAbstractCount = aAbstract.getLength( );
455     for ( sal_Int32 i = 0; i < nThisCount && i < nAbstractCount; i++ )
456     {
457         uno::Sequence< beans::PropertyValue > level = aThis[i];
458         if (level.hasElements() && GetLevel(i)->HasValues())
459         {
460             // If the element contains something, merge it, but ignore stub overrides.
461             lcl_mergeProperties( level, aAbstract[i] );
462         }
463     }
464 
465     return aAbstract;
466 }
467 
lcl_getUnoNumberingStyles(uno::Reference<lang::XMultiServiceFactory> const & xFactory)468 static uno::Reference< container::XNameContainer > lcl_getUnoNumberingStyles(
469        uno::Reference<lang::XMultiServiceFactory> const& xFactory)
470 {
471     uno::Reference< container::XNameContainer > xStyles;
472 
473     try
474     {
475         uno::Reference< style::XStyleFamiliesSupplier > xFamilies( xFactory, uno::UNO_QUERY_THROW );
476         uno::Any oFamily = xFamilies->getStyleFamilies( )->getByName("NumberingStyles");
477 
478         oFamily >>= xStyles;
479     }
480     catch ( const uno::Exception & )
481     {
482     }
483 
484     return xStyles;
485 }
486 
CreateNumberingRules(DomainMapper & rDMapper,uno::Reference<lang::XMultiServiceFactory> const & xFactory)487 void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
488         uno::Reference<lang::XMultiServiceFactory> const& xFactory)
489 {
490     // Get the UNO Numbering styles
491     uno::Reference< container::XNameContainer > xStyles = lcl_getUnoNumberingStyles( xFactory );
492 
493     // Do the whole thing
494     if( !(!m_xNumRules.is() && xFactory.is() && xStyles.is( )) )
495         return;
496 
497     try
498     {
499         // Create the numbering style
500         uno::Reference< beans::XPropertySet > xStyle (
501             xFactory->createInstance("com.sun.star.style.NumberingStyle"),
502             uno::UNO_QUERY_THROW );
503 
504         OUString sStyleName = GetStyleName(GetId(), xStyles);
505 
506         xStyles->insertByName( sStyleName, makeAny( xStyle ) );
507 
508         uno::Any oStyle = xStyles->getByName( sStyleName );
509         xStyle.set( oStyle, uno::UNO_QUERY_THROW );
510 
511         // Get the default OOo Numbering style rules
512         uno::Any aRules = xStyle->getPropertyValue( getPropertyName( PROP_NUMBERING_RULES ) );
513         aRules >>= m_xNumRules;
514 
515         uno::Sequence<uno::Sequence<beans::PropertyValue>> aProps = GetMergedPropertyValues();
516 
517         sal_Int32 nAbstLevels = m_pAbstractDef ? m_pAbstractDef->Size() : 0;
518         sal_Int32 nLevel = 0;
519         while ( nLevel < nAbstLevels )
520         {
521             ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel( nLevel );
522             ListLevel::Pointer pLevel = GetLevel( nLevel );
523 
524             // Get the merged level properties
525             auto aLvlProps = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aProps[nLevel]);
526 
527             // Get the char style
528             auto aAbsCharStyleProps = pAbsLevel
529                                     ? pAbsLevel->GetCharStyleProperties()
530                                     : uno::Sequence<beans::PropertyValue>();
531             if ( pLevel )
532             {
533                 uno::Sequence< beans::PropertyValue >& rAbsCharStyleProps = aAbsCharStyleProps;
534                 uno::Sequence< beans::PropertyValue > aCharStyleProps =
535                     pLevel->GetCharStyleProperties( );
536                 uno::Sequence< beans::PropertyValue >& rCharStyleProps = aCharStyleProps;
537                 lcl_mergeProperties( rAbsCharStyleProps, rCharStyleProps );
538             }
539 
540             if( aAbsCharStyleProps.hasElements() )
541             {
542                 // Change the sequence into a vector
543                 auto aStyleProps = comphelper::sequenceToContainer<PropertyValueVector_t>(aAbsCharStyleProps);
544 
545                 //create (or find) a character style containing the character
546                 // attributes of the symbol and apply it to the numbering level
547                 OUString sStyle = rDMapper.getOrCreateCharStyle( aStyleProps, /*bAlwaysCreate=*/true );
548                 aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_CHAR_STYLE_NAME), sStyle));
549             }
550 
551             OUString sText = pAbsLevel
552                            ? pAbsLevel->GetBulletChar()
553                            : OUString();
554             // Inherit <w:lvlText> from the abstract level in case the override would be empty.
555             if (pLevel && pLevel->HasBulletChar())
556                 sText = pLevel->GetBulletChar( );
557 
558             aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LIST_FORMAT), sText));
559 
560             aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_POSITION_AND_SPACE_MODE), sal_Int16(text::PositionAndSpaceMode::LABEL_ALIGNMENT)));
561 
562             // Replace the numbering rules for the level
563             m_xNumRules->replaceByIndex(nLevel, uno::makeAny(comphelper::containerToSequence(aLvlProps)));
564 
565             // Handle the outline level here
566             if (pAbsLevel && pAbsLevel->isOutlineNumbering())
567             {
568                 uno::Reference< text::XChapterNumberingSupplier > xOutlines (
569                     xFactory, uno::UNO_QUERY_THROW );
570                 uno::Reference< container::XIndexReplace > xOutlineRules =
571                     xOutlines->getChapterNumberingRules( );
572 
573                 StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( );
574                 aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEADING_STYLE_NAME), pParaStyle->sConvertedStyleName));
575 
576                 xOutlineRules->replaceByIndex(nLevel, uno::makeAny(comphelper::containerToSequence(aLvlProps)));
577             }
578 
579             if (pAbsLevel)
580             {
581                 // first level without default outline paragraph style
582                 const tools::SvRef< StyleSheetEntry >& aParaStyle = pAbsLevel->GetParaStyle();
583                 if ( WW_OUTLINE_MAX + 1 == m_nDefaultParentLevels && ( !aParaStyle ||
584                     aParaStyle->sConvertedStyleName.getLength() != RTL_CONSTASCII_LENGTH( "Heading 1" ) ||
585                     !aParaStyle->sConvertedStyleName.startsWith("Heading ") ||
586                     aParaStyle->sConvertedStyleName[ RTL_CONSTASCII_LENGTH( "Heading " ) ] - u'1' != nLevel ) )
587                 {
588                     m_nDefaultParentLevels = nLevel;
589                 }
590             }
591 
592             nLevel++;
593         }
594 
595         // Create the numbering style for these rules
596         OUString sNumRulesName = getPropertyName( PROP_NUMBERING_RULES );
597         xStyle->setPropertyValue( sNumRulesName, uno::makeAny( m_xNumRules ) );
598     }
599     catch( const lang::IllegalArgumentException& )
600     {
601         TOOLS_WARN_EXCEPTION( "writerfilter", "" );
602         assert( !"Incorrect argument to UNO call" );
603     }
604     catch( const uno::RuntimeException& )
605     {
606         TOOLS_WARN_EXCEPTION( "writerfilter", "" );
607         assert( !"Incorrect argument to UNO call" );
608     }
609     catch( const uno::Exception& )
610     {
611         TOOLS_WARN_EXCEPTION( "writerfilter", "" );
612     }
613 
614 }
615 
616 //-------------------------------------  NumberingManager implementation
617 
618 
ListsManager(DomainMapper & rDMapper,const uno::Reference<lang::XMultiServiceFactory> & xFactory)619 ListsManager::ListsManager(DomainMapper& rDMapper,
620     const uno::Reference<lang::XMultiServiceFactory> & xFactory)
621     : LoggedProperties("ListsManager")
622     , LoggedTable("ListsManager")
623     , m_rDMapper(rDMapper)
624     , m_xFactory(xFactory)
625 {
626 }
627 
~ListsManager()628 ListsManager::~ListsManager( )
629 {
630     DisposeNumPicBullets();
631 }
632 
DisposeNumPicBullets()633 void ListsManager::DisposeNumPicBullets( )
634 {
635     uno::Reference<drawing::XShape> xShape;
636     for (const auto& rNumPicBullet : m_aNumPicBullets)
637     {
638         xShape = rNumPicBullet->GetShape();
639         if (xShape.is())
640         {
641             uno::Reference<lang::XComponent> xShapeComponent(xShape, uno::UNO_QUERY);
642             xShapeComponent->dispose();
643         }
644     }
645 }
646 
lcl_attribute(Id nName,Value & rVal)647 void ListsManager::lcl_attribute( Id nName, Value& rVal )
648 {
649     ListLevel::Pointer pCurrentLvl;
650 
651     if (nName != NS_ooxml::LN_CT_NumPicBullet_numPicBulletId)
652     {
653         OSL_ENSURE( m_pCurrentDefinition, "current entry has to be set here");
654         if(!m_pCurrentDefinition)
655             return ;
656         pCurrentLvl = m_pCurrentDefinition->GetCurrentLevel( );
657     }
658     else
659     {
660         SAL_WARN_IF(!m_pCurrentNumPicBullet, "writerfilter", "current entry has to be set here");
661         if (!m_pCurrentNumPicBullet)
662             return;
663     }
664     int nIntValue = rVal.getInt();
665 
666 
667     switch(nName)
668     {
669         case NS_ooxml::LN_CT_LevelText_val:
670         {
671             if(pCurrentLvl)
672             {
673                 //if the BulletChar is a soft-hyphen (0xad)
674                 //replace it with a hard-hyphen (0x2d)
675                 //-> this fixes missing hyphen export in PDF etc.
676                 // see tdf#101626
677                 std::string sLevelText = rVal.getString().replace(0xad, 0x2d).toUtf8().getStr();
678 
679                 // DOCX level-text contains levels definition in format "%1.%2.%3"
680                 // we need to convert it to LO internal representation: "%1%.%2%.%3%"
681                 static const std::regex aTokenRegex("(%\\d)");
682                 sLevelText = std::regex_replace(sLevelText, aTokenRegex, "$1%");
683                 pCurrentLvl->SetBulletChar( OUString::fromUtf8(sLevelText) );
684             }
685         }
686         break;
687         case NS_ooxml::LN_CT_Lvl_start:
688         case NS_ooxml::LN_CT_Lvl_numFmt:
689         case NS_ooxml::LN_CT_NumFmt_format:
690         case NS_ooxml::LN_CT_NumFmt_val:
691         case NS_ooxml::LN_CT_Lvl_isLgl:
692         case NS_ooxml::LN_CT_Lvl_legacy:
693             if ( pCurrentLvl )
694             {
695                 if (nName == NS_ooxml::LN_CT_NumFmt_format)
696                 {
697                     pCurrentLvl->SetCustomNumberFormat(rVal.getString());
698                 }
699                 else
700                 {
701                     pCurrentLvl->SetValue(nName, sal_Int32(nIntValue));
702                 }
703             }
704             break;
705         case NS_ooxml::LN_CT_Num_numId:
706             m_pCurrentDefinition->SetId( rVal.getString().toInt32( ) );
707         break;
708         case NS_ooxml::LN_CT_AbstractNum_nsid:
709             m_pCurrentDefinition->SetId( nIntValue );
710         break;
711         case NS_ooxml::LN_CT_AbstractNum_tmpl:
712             AbstractListDef::SetValue( nName );
713         break;
714         case NS_ooxml::LN_CT_NumLvl_ilvl:
715             //add a new level to the level vector and make it the current one
716             m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
717         break;
718         case NS_ooxml::LN_CT_Lvl_ilvl:
719             m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
720         break;
721         case NS_ooxml::LN_CT_AbstractNum_abstractNumId:
722         {
723             // This one corresponds to the AbstractNum Id definition
724             // The reference to the abstract num is in the sprm method
725             sal_Int32 nVal = rVal.getString().toInt32();
726             m_pCurrentDefinition->SetId( nVal );
727         }
728         break;
729         case NS_ooxml::LN_CT_Ind_start:
730         case NS_ooxml::LN_CT_Ind_left:
731             if ( pCurrentLvl )
732                 pCurrentLvl->Insert(
733                     PROP_INDENT_AT, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
734             break;
735         case NS_ooxml::LN_CT_Ind_hanging:
736             if ( pCurrentLvl )
737                 pCurrentLvl->Insert(
738                     PROP_FIRST_LINE_INDENT, uno::makeAny( - ConversionHelper::convertTwipToMM100( nIntValue ) ));
739         break;
740         case NS_ooxml::LN_CT_Ind_firstLine:
741             if ( pCurrentLvl )
742                 pCurrentLvl->Insert(
743                     PROP_FIRST_LINE_INDENT, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
744         break;
745         case NS_ooxml::LN_CT_Lvl_tplc: //template code - unsupported
746         case NS_ooxml::LN_CT_Lvl_tentative: //marks level as unused in the document - unsupported
747         break;
748         case NS_ooxml::LN_CT_TabStop_pos:
749         {
750             //no paragraph attributes in ListTable char style sheets
751             if ( pCurrentLvl )
752                 pCurrentLvl->SetValue( nName,
753                     ConversionHelper::convertTwipToMM100( nIntValue ) );
754         }
755         break;
756         case NS_ooxml::LN_CT_TabStop_val:
757         {
758             // TODO Do something of that
759         }
760         break;
761         case NS_ooxml::LN_CT_NumPicBullet_numPicBulletId:
762             m_pCurrentNumPicBullet->SetId(rVal.getString().toInt32());
763         break;
764         default:
765             SAL_WARN("writerfilter", "ListsManager::lcl_attribute: unhandled token: " << nName);
766     }
767 }
768 
lcl_sprm(Sprm & rSprm)769 void ListsManager::lcl_sprm( Sprm& rSprm )
770 {
771     //fill the attributes of the style sheet
772     sal_uInt32 nSprmId = rSprm.getId();
773     if( !(m_pCurrentDefinition ||
774         nSprmId == NS_ooxml::LN_CT_Numbering_abstractNum ||
775         nSprmId == NS_ooxml::LN_CT_Numbering_num ||
776         (nSprmId == NS_ooxml::LN_CT_NumPicBullet_pict && m_pCurrentNumPicBullet) ||
777         nSprmId == NS_ooxml::LN_CT_Numbering_numPicBullet))
778         return;
779 
780     static bool bIsStartVisited = false;
781     sal_Int32 nIntValue = rSprm.getValue()->getInt();
782     switch( nSprmId )
783     {
784         case NS_ooxml::LN_CT_Numbering_abstractNum:
785         {
786             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
787             if(pProperties)
788             {
789                 //create a new Abstract list entry
790                 OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
791                 m_pCurrentDefinition = new AbstractListDef;
792                 pProperties->resolve( *this );
793                 //append it to the table
794                 m_aAbstractLists.push_back( m_pCurrentDefinition );
795                 m_pCurrentDefinition = AbstractListDef::Pointer();
796             }
797         }
798         break;
799         case NS_ooxml::LN_CT_Numbering_num:
800         {
801             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
802             if(pProperties)
803             {
804                 // Create a new list entry
805                 OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
806                 ListDef::Pointer listDef( new ListDef );
807                 m_pCurrentDefinition = listDef.get();
808                 pProperties->resolve( *this );
809                 //append it to the table
810                 m_aLists.push_back( listDef );
811 
812                 m_pCurrentDefinition = AbstractListDef::Pointer();
813             }
814         }
815         break;
816         case NS_ooxml::LN_CT_Numbering_numPicBullet:
817         {
818             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
819             if (pProperties)
820             {
821                 NumPicBullet::Pointer numPicBullet(new NumPicBullet());
822                 m_pCurrentNumPicBullet = numPicBullet;
823                 pProperties->resolve(*this);
824                 m_aNumPicBullets.push_back(numPicBullet);
825                 m_pCurrentNumPicBullet = NumPicBullet::Pointer();
826             }
827         }
828         break;
829         case NS_ooxml::LN_CT_NumPicBullet_pict:
830         {
831             uno::Reference<drawing::XShape> xShape = m_rDMapper.PopPendingShape();
832 
833             m_pCurrentNumPicBullet->SetShape(xShape);
834         }
835         break;
836         case NS_ooxml::LN_CT_Lvl_lvlPicBulletId:
837         if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
838         {
839             uno::Reference<drawing::XShape> xShape;
840             for (const auto& rNumPicBullet : m_aNumPicBullets)
841             {
842                 if (rNumPicBullet->GetId() == nIntValue)
843                 {
844                     xShape = rNumPicBullet->GetShape();
845                     break;
846                 }
847             }
848             if (xShape.is())
849             {
850                 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
851                 try
852                 {
853                     uno::Any aAny = xPropertySet->getPropertyValue("Graphic");
854                     if (aAny.has<uno::Reference<graphic::XGraphic>>() && pCurrentLevel)
855                     {
856                         auto xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
857                         if (xGraphic.is())
858                         {
859                             uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
860                             pCurrentLevel->SetGraphicBitmap(xBitmap);
861                         }
862                     }
863                 }
864                 catch (const beans::UnknownPropertyException&)
865                 {}
866 
867                 // Respect only the aspect ratio of the picture, not its size.
868                 awt::Size aPrefSize = xShape->getSize();
869                 if ( aPrefSize.Height * aPrefSize.Width != 0 )
870                 {
871                     // See SwDefBulletConfig::InitFont(), default height is 14.
872                     const int nFontHeight = 14;
873                     // Point -> mm100.
874                     const int nHeight = nFontHeight * 35;
875                     int nWidth = (nHeight * aPrefSize.Width) / aPrefSize.Height;
876 
877                     awt::Size aSize( convertMm100ToTwip(nWidth), convertMm100ToTwip(nHeight) );
878                     pCurrentLevel->SetGraphicSize( aSize );
879                 }
880                 else
881                 {
882                     awt::Size aSize( convertMm100ToTwip(aPrefSize.Width), convertMm100ToTwip(aPrefSize.Height) );
883                     pCurrentLevel->SetGraphicSize( aSize );
884                 }
885             }
886         }
887         break;
888         case NS_ooxml::LN_CT_Num_abstractNumId:
889         {
890             sal_Int32 nAbstractNumId = rSprm.getValue()->getInt();
891             ListDef* pListDef = dynamic_cast< ListDef* >( m_pCurrentDefinition.get( ) );
892             if ( pListDef != nullptr )
893             {
894                 // The current def should be a ListDef
895                 pListDef->SetAbstractDefinition(
896                        GetAbstractList( nAbstractNumId ) );
897             }
898         }
899         break;
900         case NS_ooxml::LN_CT_AbstractNum_multiLevelType:
901         break;
902         case NS_ooxml::LN_CT_AbstractNum_tmpl:
903             AbstractListDef::SetValue( nSprmId );
904         break;
905         case NS_ooxml::LN_CT_AbstractNum_lvl:
906         {
907             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
908             if(pProperties)
909                 pProperties->resolve(*this);
910         }
911         break;
912         case NS_ooxml::LN_CT_Lvl_start:
913             if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
914                 pCurrentLevel->SetValue( nSprmId, nIntValue );
915             bIsStartVisited = true;
916         break;
917         case NS_ooxml::LN_CT_Lvl_numFmt:
918         {
919             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
920             if (pProperties)
921             {
922                 pProperties->resolve(*this);
923             }
924             if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
925             {
926                 if( !bIsStartVisited )
927                 {
928                     pCurrentLevel->SetValue( NS_ooxml::LN_CT_Lvl_start, 0 );
929                     bIsStartVisited = true;
930                 }
931             }
932         }
933         break;
934         case NS_ooxml::LN_CT_Lvl_isLgl:
935         case NS_ooxml::LN_CT_Lvl_legacy:
936             if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
937             {
938                 pCurrentLevel->SetValue(nSprmId, nIntValue);
939             }
940             break;
941         case NS_ooxml::LN_CT_Lvl_suff:
942         {
943             if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
944             {
945                 SvxNumberFormat::LabelFollowedBy value = SvxNumberFormat::LISTTAB;
946                 if( rSprm.getValue()->getString() == "tab" )
947                     value = SvxNumberFormat::LISTTAB;
948                 else if( rSprm.getValue()->getString() == "space" )
949                     value = SvxNumberFormat::SPACE;
950                 else if( rSprm.getValue()->getString() == "nothing" )
951                     value = SvxNumberFormat::NOTHING;
952                 else
953                     SAL_WARN( "writerfilter", "Unknown ST_LevelSuffix value "
954                         << rSprm.getValue()->getString());
955                 pCurrentLevel->SetValue( nSprmId, value );
956             }
957         }
958         break;
959         case NS_ooxml::LN_CT_Lvl_lvlText:
960         case NS_ooxml::LN_CT_Lvl_rPr : //contains LN_EG_RPrBase_rFonts
961         {
962             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
963             if(pProperties)
964                 pProperties->resolve(*this);
965         }
966         break;
967         case NS_ooxml::LN_CT_NumLvl_lvl:
968         {
969             // overwrite level
970             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
971             if(pProperties)
972                 pProperties->resolve(*this);
973         }
974         break;
975         case NS_ooxml::LN_CT_Lvl_lvlJc:
976         {
977             sal_Int16 nValue = text::HoriOrientation::NONE;
978             switch (nIntValue)
979             {
980             case NS_ooxml::LN_Value_ST_Jc_left:
981             case NS_ooxml::LN_Value_ST_Jc_start:
982                 nValue = text::HoriOrientation::LEFT;
983                 break;
984             case NS_ooxml::LN_Value_ST_Jc_center:
985                 nValue = text::HoriOrientation::CENTER;
986                 break;
987             case NS_ooxml::LN_Value_ST_Jc_right:
988             case NS_ooxml::LN_Value_ST_Jc_end:
989                 nValue = text::HoriOrientation::RIGHT;
990                 break;
991             }
992 
993             if (nValue != text::HoriOrientation::NONE)
994             {
995                 if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
996                 {
997                     pLevel->Insert(
998                         PROP_ADJUST, uno::makeAny( nValue ) );
999                 }
1000             }
1001         }
1002         break;
1003         case NS_ooxml::LN_CT_Lvl_pPr:
1004         case NS_ooxml::LN_CT_PPrBase_ind:
1005         {
1006             //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
1007             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1008             if(pProperties)
1009                 pProperties->resolve(*this);
1010         }
1011         break;
1012         case NS_ooxml::LN_CT_PPrBase_tabs:
1013         case NS_ooxml::LN_CT_Tabs_tab:
1014         {
1015             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1016             if(pProperties)
1017                 pProperties->resolve(*this);
1018         }
1019         break;
1020         case NS_ooxml::LN_CT_Lvl_pStyle:
1021         {
1022             OUString sStyleName = rSprm.getValue( )->getString( );
1023             if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
1024             {
1025                 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
1026                 const StyleSheetEntryPtr pStyle = pStylesTable->FindStyleSheetByISTD( sStyleName );
1027                 pLevel->SetParaStyle( pStyle );
1028             }
1029         }
1030         break;
1031         case NS_ooxml::LN_CT_Num_lvlOverride:
1032         {
1033             writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1034             if (pProperties)
1035                 pProperties->resolve(*this);
1036         }
1037         break;
1038         case NS_ooxml::LN_CT_NumLvl_startOverride:
1039         {
1040             if(m_pCurrentDefinition)
1041             {
1042                 if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
1043                 {
1044                     pCurrentLevel->SetValue(NS_ooxml::LN_CT_NumLvl_startOverride, nIntValue);
1045                 }
1046             }
1047         }
1048         break;
1049         case NS_ooxml::LN_CT_AbstractNum_numStyleLink:
1050         {
1051             OUString sStyleName = rSprm.getValue( )->getString( );
1052             m_pCurrentDefinition->SetNumStyleLink(sStyleName);
1053         }
1054         break;
1055         case NS_ooxml::LN_CT_AbstractNum_styleLink:
1056         {
1057             OUString sStyleName = rSprm.getValue()->getString();
1058             m_pCurrentDefinition->SetStyleLink(sStyleName);
1059         }
1060         break;
1061         case NS_ooxml::LN_EG_RPrBase_rFonts: //contains font properties
1062         case NS_ooxml::LN_EG_RPrBase_color:
1063         case NS_ooxml::LN_EG_RPrBase_u:
1064         case NS_ooxml::LN_EG_RPrBase_sz:
1065         case NS_ooxml::LN_EG_RPrBase_lang:
1066         case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
1067             //no break!
1068         default:
1069             if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
1070             {
1071                 m_rDMapper.PushListProperties(pCurrentLevel.get());
1072                 m_rDMapper.sprm( rSprm );
1073                 m_rDMapper.PopListProperties();
1074             }
1075     }
1076 }
1077 
lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)1078 void ListsManager::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref )
1079 {
1080     if( m_rDMapper.IsOOXMLImport() || m_rDMapper.IsRTFImport() )
1081     {
1082         ref->resolve(*this);
1083     }
1084     else
1085     {
1086         // Create AbstractListDef's
1087         OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
1088         m_pCurrentDefinition = new AbstractListDef( );
1089         ref->resolve(*this);
1090         //append it to the table
1091         m_aAbstractLists.push_back( m_pCurrentDefinition );
1092         m_pCurrentDefinition = AbstractListDef::Pointer();
1093     }
1094 }
1095 
GetAbstractList(sal_Int32 nId)1096 AbstractListDef::Pointer ListsManager::GetAbstractList( sal_Int32 nId )
1097 {
1098     for (const auto& listDef : m_aAbstractLists)
1099     {
1100         if (listDef->GetId( ) == nId)
1101         {
1102             if (listDef->GetNumStyleLink().getLength() > 0)
1103             {
1104                 // If the abstract num has a style linked, check the linked style's number id.
1105                 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
1106 
1107                 const StyleSheetEntryPtr pStyleSheetEntry =
1108                     pStylesTable->FindStyleSheetByISTD(listDef->GetNumStyleLink() );
1109 
1110                 const StyleSheetPropertyMap* pStyleSheetProperties =
1111                     dynamic_cast<const StyleSheetPropertyMap*>(pStyleSheetEntry ? pStyleSheetEntry->pProperties.get() : nullptr);
1112 
1113                 if( pStyleSheetProperties && pStyleSheetProperties->GetListId() >= 0 )
1114                 {
1115                     ListDef::Pointer pList = GetList( pStyleSheetProperties->GetListId() );
1116                     if ( pList!=nullptr )
1117                         return pList->GetAbstractDefinition();
1118                 }
1119 
1120                 // In stylesheet we did not found anything useful. Try to find base abstractnum having this stylelink
1121                 for (const auto & baseListDef : m_aAbstractLists)
1122                 {
1123                     if (baseListDef->GetStyleLink() == listDef->GetNumStyleLink())
1124                     {
1125                         return baseListDef;
1126                     }
1127                 }
1128             }
1129 
1130             // Standalone abstract list
1131             return listDef;
1132         }
1133     }
1134 
1135     return nullptr;
1136 }
1137 
GetList(sal_Int32 nId)1138 ListDef::Pointer ListsManager::GetList( sal_Int32 nId )
1139 {
1140     ListDef::Pointer pList;
1141 
1142     int nLen = m_aLists.size( );
1143     int i = 0;
1144     while ( !pList && i < nLen )
1145     {
1146         if ( m_aLists[i]->GetId( ) == nId )
1147             pList = m_aLists[i];
1148         i++;
1149     }
1150 
1151     return pList;
1152 }
1153 
CreateNumberingRules()1154 void ListsManager::CreateNumberingRules( )
1155 {
1156     // Loop over the definitions
1157     for ( const auto& rList : m_aLists )
1158     {
1159         rList->CreateNumberingRules( m_rDMapper, m_xFactory );
1160     }
1161     m_rDMapper.GetStyleSheetTable()->ApplyNumberingStyleNameToParaStyles();
1162 }
1163 
1164 }
1165 
1166 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1167