1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include "ConversionHelper.hxx"
20 #include "NumberingManager.hxx"
21 #include "StyleSheetTable.hxx"
22 #include "PropertyIds.hxx"
24 #include <ooxml/resourceids.hxx>
26 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
27 #include <com/sun/star/container/XNameContainer.hpp>
28 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
29 #include <com/sun/star/style/NumberingType.hpp>
30 #include <com/sun/star/text/HoriOrientation.hpp>
31 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
32 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
34 #include <osl/diagnose.h>
35 #include <rtl/ustring.hxx>
36 #include <comphelper/sequenceashashmap.hxx>
37 #include <comphelper/sequence.hxx>
39 using namespace com::sun::star
;
41 #define MAKE_PROPVAL(NameId, Value) \
42 beans::PropertyValue(aPropNameSupplier.GetName(NameId), 0, uno::makeAny(Value), beans::PropertyState_DIRECT_VALUE )
44 #define NUMBERING_MAX_LEVELS 10
47 namespace writerfilter
{
50 //--------------------------------------------------- Utility functions
52 #ifdef DEBUG_WRITERFILTER
53 void lcl_printProperties( uno::Sequence
< beans::PropertyValue
> const & aProps
)
55 sal_Int32 nLen
= aProps
.getLength( );
56 for ( sal_Int32 i
= 0; i
< nLen
; i
++ )
58 uno::Any aValue
= aProps
[i
].Value
;
62 if ( !( aValue
>>= sValue
) && ( aValue
>>= nValue
) )
63 sValue
= OUString::number( nValue
);
65 SAL_INFO("writerfilter", "Property " << aProps
[i
].Name
<< ": " << sValue
);
70 sal_Int32
lcl_findProperty( const uno::Sequence
< beans::PropertyValue
>& aProps
, const OUString
& sName
)
73 sal_Int32 nLen
= aProps
.getLength( );
76 while ( nPos
== -1 && i
< nLen
)
78 if ( aProps
[i
].Name
.equals( sName
) )
87 void lcl_mergeProperties( uno::Sequence
< beans::PropertyValue
>& aSrc
,
88 uno::Sequence
< beans::PropertyValue
>& aDst
)
90 for ( sal_Int32 i
= 0, nSrcLen
= aSrc
.getLength( ); i
< nSrcLen
; i
++ )
92 // Look for the same property in aDst
93 sal_Int32 nPos
= lcl_findProperty( aDst
, aSrc
[i
].Name
);
96 // Replace the property value by the one in aSrc
101 // Simply add the new value
102 aDst
.realloc( aDst
.getLength( ) + 1 );
103 aDst
[ aDst
.getLength( ) - 1 ] = aSrc
[i
];
108 //-------------------------------------------- ListLevel implementation
109 void ListLevel::SetValue( Id nId
, sal_Int32 nValue
)
113 case NS_ooxml::LN_CT_Lvl_start
:
114 m_nIStartAt
= nValue
;
116 case NS_ooxml::LN_CT_Lvl_numFmt
:
119 case NS_ooxml::LN_CT_Lvl_isLgl
:
122 case NS_ooxml::LN_CT_Lvl_legacy
:
123 m_nFPrevSpace
= nValue
;
125 case NS_ooxml::LN_CT_Lvl_suff
:
126 m_nXChFollow
= nValue
;
128 case NS_ooxml::LN_CT_TabStop_pos
:
131 SAL_INFO("writerfilter",
132 "unsupported list tab stop position " << nValue
);
138 OSL_FAIL( "this line should never be reached");
142 void ListLevel::SetParaStyle( std::shared_ptr
< StyleSheetEntry
> pStyle
)
146 m_pParaStyle
= pStyle
;
147 // AFAICT .docx spec does not identify which numberings or paragraph
148 // styles are actually the ones to be used for outlines (chapter numbering),
149 // it only kind of says somewhere that they should be named Heading1 to Heading9.
150 const OUString styleId
= pStyle
->sConvertedStyleName
;
151 m_outline
= ( styleId
.getLength() == RTL_CONSTASCII_LENGTH( "Heading 1" )
152 && styleId
.match( "Heading ", 0 )
153 && styleId
[ RTL_CONSTASCII_LENGTH( "Heading " ) ] >= '1'
154 && styleId
[ RTL_CONSTASCII_LENGTH( "Heading " ) ] <= '9' );
157 sal_Int16
ListLevel::GetParentNumbering( const OUString
& sText
, sal_Int16 nLevel
,
158 OUString
& rPrefix
, OUString
& rSuffix
)
160 sal_Int16 nParentNumbering
= 1;
162 //now parse the text to find %n from %1 to %nLevel+1
163 //everything before the first % and the last %x is prefix and suffix
164 OUString
sLevelText( sText
);
165 sal_Int32 nCurrentIndex
= 0;
166 sal_Int32 nFound
= sLevelText
.indexOf( '%', nCurrentIndex
);
169 rPrefix
= sLevelText
.copy( 0, nFound
);
170 sLevelText
= sLevelText
.copy( nFound
);
172 sal_Int32 nMinLevel
= nLevel
;
173 //now the text should either be empty or start with %
174 nFound
= sLevelText
.getLength( ) > 1 ? 0 : -1;
177 if( sLevelText
.getLength() > 1 )
179 sal_Unicode cLevel
= sLevelText
[1];
180 if( cLevel
>= '1' && cLevel
<= '9' )
182 if( cLevel
- '1' < nMinLevel
)
183 nMinLevel
= cLevel
- '1';
184 //remove first char - next char is removed later
185 sLevelText
= sLevelText
.copy( 1 );
188 //remove old '%' or number
189 sLevelText
= sLevelText
.copy( 1 );
191 nFound
= sLevelText
.indexOf( '%', nCurrentIndex
);
192 //remove the text before the next %
194 sLevelText
= sLevelText
.copy( nFound
-1 );
196 if( nMinLevel
< nLevel
)
198 nParentNumbering
= sal_Int16( nLevel
- nMinLevel
+ 1);
201 rSuffix
= sLevelText
;
203 return nParentNumbering
;
206 uno::Sequence
< beans::PropertyValue
> ListLevel::GetProperties( )
208 uno::Sequence
< beans::PropertyValue
> aLevelProps
= GetLevelProperties( );
209 if ( m_pParaStyle
.get( ) )
210 AddParaProperties( &aLevelProps
);
214 static bool IgnoreForCharStyle(const OUString
& aStr
)
216 //Names found in PropertyIds.cxx, Lines 56-396
217 return (aStr
=="Adjust" || aStr
=="IndentAt" || aStr
=="FirstLineIndent"
218 || aStr
=="FirstLineOffset" || aStr
=="LeftMargin" || aStr
=="CharFontName"
221 uno::Sequence
< beans::PropertyValue
> ListLevel::GetCharStyleProperties( )
223 PropertyValueVector_t rProperties
;
225 uno::Sequence
< beans::PropertyValue
> vPropVals
= PropertyMap::GetPropertyValues();
226 beans::PropertyValue
* aValIter
= vPropVals
.begin();
227 beans::PropertyValue
* aEndIter
= vPropVals
.end();
228 for( ; aValIter
!= aEndIter
; ++aValIter
)
230 if (IgnoreForCharStyle(aValIter
->Name
))
232 else if(aValIter
->Name
=="CharInteropGrabBag" || aValIter
->Name
=="ParaInteropGrabBag") {
233 uno::Sequence
<beans::PropertyValue
> vGrabVals
;
234 aValIter
->Value
>>= vGrabVals
;
235 beans::PropertyValue
* aGrabIter
= vGrabVals
.begin();
236 for(; aGrabIter
!=vGrabVals
.end(); ++aGrabIter
) {
237 if(!IgnoreForCharStyle(aGrabIter
->Name
))
238 rProperties
.push_back(beans::PropertyValue(aGrabIter
->Name
, 0, aGrabIter
->Value
, beans::PropertyState_DIRECT_VALUE
));
242 rProperties
.push_back(beans::PropertyValue(aValIter
->Name
, 0, aValIter
->Value
, beans::PropertyState_DIRECT_VALUE
));
245 uno::Sequence
< beans::PropertyValue
> aRet( rProperties
.size() );
246 beans::PropertyValue
* pValues
= aRet
.getArray();
247 PropertyValueVector_t::const_iterator aIt
= rProperties
.begin();
248 PropertyValueVector_t::const_iterator aEndIt
= rProperties
.end();
249 for(sal_uInt32 nIndex
= 0; aIt
!= aEndIt
; ++aIt
,++nIndex
)
251 pValues
[nIndex
] = *aIt
;
256 uno::Sequence
< beans::PropertyValue
> ListLevel::GetLevelProperties( )
258 const sal_Int16 aWWToUnoAdjust
[] =
260 text::HoriOrientation::LEFT
,
261 text::HoriOrientation::CENTER
,
262 text::HoriOrientation::RIGHT
,
265 PropertyNameSupplier
& aPropNameSupplier
= PropertyNameSupplier::GetPropertyNameSupplier();
266 std::vector
<beans::PropertyValue
> aNumberingProperties
;
268 if( m_nIStartAt
>= 0)
269 aNumberingProperties
.push_back( MAKE_PROPVAL(PROP_START_WITH
, (sal_Int16
)m_nIStartAt
) );
271 sal_Int16 nNumberFormat
= ConversionHelper::ConvertNumberingType(m_nNFC
);
274 if (!m_sGraphicURL
.isEmpty() || m_sGraphicBitmap
.is())
275 nNumberFormat
= style::NumberingType::BITMAP
;
276 else if (m_sBulletChar
.isEmpty() && nNumberFormat
!= style::NumberingType::CHAR_SPECIAL
)
277 // w:lvlText is empty, that means no numbering in Word.
278 // CHAR_SPECIAL is handled separately below.
279 nNumberFormat
= style::NumberingType::NUMBER_NONE
;
280 aNumberingProperties
.push_back( MAKE_PROPVAL(PROP_NUMBERING_TYPE
, nNumberFormat
));
283 if( m_nJC
>= 0 && m_nJC
<= sal::static_int_cast
<sal_Int32
>(sizeof(aWWToUnoAdjust
) / sizeof(sal_Int16
)) )
284 aNumberingProperties
.push_back( MAKE_PROPVAL(PROP_ADJUST
, aWWToUnoAdjust
[m_nJC
]));
286 if( !isOutlineNumbering())
288 // todo: this is not the bullet char
289 if( nNumberFormat
== style::NumberingType::CHAR_SPECIAL
)
291 if (!m_sBulletChar
.isEmpty())
293 aNumberingProperties
.push_back( MAKE_PROPVAL(PROP_BULLET_CHAR
, m_sBulletChar
.copy(0,1)));
297 // If w:lvlText's value is null - set bullet char to zero.
298 aNumberingProperties
.push_back( MAKE_PROPVAL(PROP_BULLET_CHAR
, sal_Unicode(0x0)));
301 if (!m_sGraphicURL
.isEmpty())
302 aNumberingProperties
.push_back(MAKE_PROPVAL(PROP_GRAPHIC_URL
, m_sGraphicURL
));
303 if (m_sGraphicBitmap
.is())
304 aNumberingProperties
.push_back(MAKE_PROPVAL(PROP_GRAPHIC_BITMAP
, m_sGraphicBitmap
));
307 aNumberingProperties
.push_back( MAKE_PROPVAL( PROP_LISTTAB_STOP_POSITION
, m_nTabstop
) );
309 //TODO: handling of nFLegal?
310 //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
318 if( m_nFWord6
> 0) //Word 6 compatibility
321 aNumberingProperties
.push_back( MAKE_PROPVAL( PROP_PARENT_NUMBERING
, (sal_Int16
) NUMBERING_MAX_LEVELS
));
322 //TODO: prefixing space nFPrevSpace; - has not been used in WW8 filter
325 // TODO: sRGBXchNums; array of inherited numbers
327 // nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
328 aNumberingProperties
.push_back( MAKE_PROPVAL( PROP_LEVEL_FOLLOW
, m_nXChFollow
));
331 PropertyIds aReadIds
[nIds
] =
333 PROP_ADJUST
, PROP_INDENT_AT
, PROP_FIRST_LINE_INDENT
,
334 PROP_FIRST_LINE_OFFSET
, PROP_LEFT_MARGIN
336 for(int i
=0; i
<nIds
; ++i
) {
337 boost::optional
<PropertyMap::Property
> aProp
= getProperty(aReadIds
[i
]);
339 aNumberingProperties
.push_back(
340 beans::PropertyValue( aPropNameSupplier
.GetName(aProp
->first
), 0, aProp
->second
, beans::PropertyState_DIRECT_VALUE
)
344 boost::optional
<PropertyMap::Property
> aPropFont
= getProperty(PROP_CHAR_FONT_NAME
);
345 if(aPropFont
&& !isOutlineNumbering())
346 aNumberingProperties
.push_back(
347 beans::PropertyValue( aPropNameSupplier
.GetName(PROP_BULLET_FONT_NAME
), 0, aPropFont
->second
, beans::PropertyState_DIRECT_VALUE
)
350 return comphelper::containerToSequence(aNumberingProperties
);
353 // Add the properties only if they do not already exist in the sequence.
354 void ListLevel::AddParaProperties( uno::Sequence
< beans::PropertyValue
>* props
)
356 uno::Sequence
< beans::PropertyValue
>& aProps
= *props
;
357 PropertyNameSupplier
& aPropNameSupplier
= PropertyNameSupplier::GetPropertyNameSupplier();
359 OUString sFirstLineIndent
= aPropNameSupplier
.GetName(
360 PROP_FIRST_LINE_INDENT
);
361 OUString sIndentAt
= aPropNameSupplier
.GetName(
364 bool hasFirstLineIndent
= lcl_findProperty( aProps
, sFirstLineIndent
);
365 bool hasIndentAt
= lcl_findProperty( aProps
, sIndentAt
);
367 if( hasFirstLineIndent
&& hasIndentAt
)
368 return; // has them all, nothing to add
370 uno::Sequence
< beans::PropertyValue
> aParaProps
= m_pParaStyle
->pProperties
->GetPropertyValues( );
372 // ParaFirstLineIndent -> FirstLineIndent
373 // ParaLeftMargin -> IndentAt
375 OUString sParaIndent
= aPropNameSupplier
.GetName(
376 PROP_PARA_FIRST_LINE_INDENT
);
377 OUString sParaLeftMargin
= aPropNameSupplier
.GetName(
378 PROP_PARA_LEFT_MARGIN
);
380 sal_Int32 nLen
= aParaProps
.getLength( );
381 for ( sal_Int32 i
= 0; i
< nLen
; i
++ )
383 if ( !hasFirstLineIndent
&& aParaProps
[i
].Name
.equals( sParaIndent
) )
385 aProps
.realloc( aProps
.getLength() + 1 );
386 aProps
[aProps
.getLength( ) - 1] = aParaProps
[i
];
387 aProps
[aProps
.getLength( ) - 1].Name
= sFirstLineIndent
;
389 else if ( !hasIndentAt
&& aParaProps
[i
].Name
.equals( sParaLeftMargin
) )
391 aProps
.realloc( aProps
.getLength() + 1 );
392 aProps
[aProps
.getLength( ) - 1] = aParaProps
[i
];
393 aProps
[aProps
.getLength( ) - 1].Name
= sIndentAt
;
399 NumPicBullet::NumPicBullet()
404 NumPicBullet::~NumPicBullet()
408 void NumPicBullet::SetId(sal_Int32 nId
)
413 void NumPicBullet::SetShape(uno::Reference
<drawing::XShape
> const& xShape
)
420 //--------------------------------------- AbstractListDef implementation
422 AbstractListDef::AbstractListDef( ) :
428 AbstractListDef::~AbstractListDef( )
432 void AbstractListDef::SetValue( sal_uInt32 nSprmId
, sal_Int32 nValue
)
436 case NS_ooxml::LN_CT_AbstractNum_tmpl
:
440 OSL_FAIL( "this line should never be reached");
444 ListLevel::Pointer
AbstractListDef::GetLevel( sal_uInt16 nLvl
)
446 ListLevel::Pointer pLevel
;
447 if ( m_aLevels
.size( ) > nLvl
)
448 pLevel
= m_aLevels
[ nLvl
];
452 void AbstractListDef::AddLevel( )
454 ListLevel::Pointer
pLevel( new ListLevel
);
455 m_pCurrentLevel
= pLevel
;
456 m_aLevels
.push_back( pLevel
);
459 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > AbstractListDef::GetPropertyValues( )
461 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > result( sal_Int32( m_aLevels
.size( ) ) );
462 uno::Sequence
< beans::PropertyValue
>* aResult
= result
.getArray( );
464 int nLevels
= m_aLevels
.size( );
465 for ( int i
= 0; i
< nLevels
; i
++ )
467 aResult
[i
] = m_aLevels
[i
]->GetProperties( );
473 //---------------------------------------------- ListDef implementation
475 ListDef::ListDef( ) : AbstractListDef( )
483 OUString
ListDef::GetStyleName( sal_Int32 nId
)
485 OUString
sStyleName( "WWNum" );
486 sStyleName
+= OUString::number( nId
);
491 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > ListDef::GetPropertyValues( )
494 return uno::Sequence
< uno::Sequence
< beans::PropertyValue
> >();
496 // [1] Call the same method on the abstract list
497 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > aAbstract
= m_pAbstractDef
->GetPropertyValues( );
499 // [2] Call the upper class method
500 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > aThis
= AbstractListDef::GetPropertyValues( );
502 // Merge the results of [2] in [1]
503 sal_Int32 nThisCount
= aThis
.getLength( );
504 sal_Int32 nAbstractCount
= aAbstract
.getLength( );
505 for ( sal_Int32 i
= 0; i
< nThisCount
&& i
< nAbstractCount
; i
++ )
507 uno::Sequence
< beans::PropertyValue
> level
= aThis
[i
];
508 if ( level
.hasElements() )
510 // If the element contains something, merge it
511 lcl_mergeProperties( level
, aAbstract
[i
] );
518 uno::Reference
< container::XNameContainer
> lcl_getUnoNumberingStyles(
519 uno::Reference
<lang::XMultiServiceFactory
> const& xFactory
)
521 uno::Reference
< container::XNameContainer
> xStyles
;
525 uno::Reference
< style::XStyleFamiliesSupplier
> xFamilies( xFactory
, uno::UNO_QUERY_THROW
);
526 uno::Any oFamily
= xFamilies
->getStyleFamilies( )->getByName("NumberingStyles");
530 catch ( const uno::Exception
& )
537 void ListDef::CreateNumberingRules( DomainMapper
& rDMapper
,
538 uno::Reference
<lang::XMultiServiceFactory
> const& xFactory
)
540 // Get the UNO Numbering styles
541 uno::Reference
< container::XNameContainer
> xStyles
= lcl_getUnoNumberingStyles( xFactory
);
543 // Do the whole thing
544 if( !m_xNumRules
.is() && xFactory
.is() && xStyles
.is( ) )
548 // Create the numbering style
549 uno::Reference
< beans::XPropertySet
> xStyle (
550 xFactory
->createInstance("com.sun.star.style.NumberingStyle"),
551 uno::UNO_QUERY_THROW
);
553 OUString sStyleName
= GetStyleName( GetId( ) );
555 xStyles
->insertByName( sStyleName
, makeAny( xStyle
) );
557 uno::Any oStyle
= xStyles
->getByName( sStyleName
);
558 xStyle
.set( oStyle
, uno::UNO_QUERY_THROW
);
560 PropertyNameSupplier
& aPropNameSupplier
= PropertyNameSupplier::GetPropertyNameSupplier();
562 // Get the default OOo Numbering style rules
563 uno::Any aRules
= xStyle
->getPropertyValue( aPropNameSupplier
.GetName( PROP_NUMBERING_RULES
) );
564 aRules
>>= m_xNumRules
;
566 uno::Sequence
< uno::Sequence
< beans::PropertyValue
> > aProps
= GetPropertyValues( );
568 sal_Int32 nAbstLevels
= m_pAbstractDef
? m_pAbstractDef
->Size() : 0;
569 sal_Int16 nLevel
= 0;
570 while ( nLevel
< nAbstLevels
)
572 ListLevel::Pointer pAbsLevel
= m_pAbstractDef
->GetLevel( nLevel
);
573 ListLevel::Pointer pLevel
= GetLevel( nLevel
);
575 // Get the merged level properties
576 uno::Sequence
< beans::PropertyValue
> aLvlProps
= aProps
[sal_Int32( nLevel
)];
578 #ifdef DEBUG_WRITERFILTER
579 lcl_printProperties( aLvlProps
);
582 // Get the char style
583 uno::Sequence
< beans::PropertyValue
> aAbsCharStyleProps
= pAbsLevel
->GetCharStyleProperties( );
584 uno::Sequence
< beans::PropertyValue
>& rAbsCharStyleProps
= aAbsCharStyleProps
;
587 uno::Sequence
< beans::PropertyValue
> aCharStyleProps
=
588 pLevel
->GetCharStyleProperties( );
589 uno::Sequence
< beans::PropertyValue
>& rCharStyleProps
= aCharStyleProps
;
590 lcl_mergeProperties( rAbsCharStyleProps
, rCharStyleProps
);
593 if( aAbsCharStyleProps
.getLength() )
595 // Change the sequence into a vector
596 PropertyValueVector_t aStyleProps
;
597 for ( sal_Int32 i
= 0, nLen
= aAbsCharStyleProps
.getLength() ; i
< nLen
; i
++ )
599 aStyleProps
.push_back( aAbsCharStyleProps
[i
] );
602 //create (or find) a character style containing the character
603 // attributes of the symbol and apply it to the numbering level
604 OUString sStyle
= rDMapper
.getOrCreateCharStyle( aStyleProps
);
605 aLvlProps
.realloc( aLvlProps
.getLength() + 1);
606 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 1].Name
= aPropNameSupplier
.GetName( PROP_CHAR_STYLE_NAME
);
607 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 1].Value
<<= sStyle
;
610 // Get the prefix / suffix / Parent numbering
611 // and add them to the level properties
612 OUString sText
= pAbsLevel
->GetBulletChar( );
613 // Inherit <w:lvlText> from the abstract level in case the override would be empty.
614 if (pLevel
.get() && !pLevel
->GetBulletChar().isEmpty())
615 sText
= pLevel
->GetBulletChar( );
619 OUString
& rPrefix
= sPrefix
;
620 OUString
& rSuffix
= sSuffix
;
621 sal_Int16 nParentNum
= ListLevel::GetParentNumbering(
622 sText
, nLevel
, rPrefix
, rSuffix
);
624 aLvlProps
.realloc( aLvlProps
.getLength( ) + 4 );
625 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 4] = MAKE_PROPVAL( PROP_PREFIX
, rPrefix
);
629 // Empty <w:lvlText>? Then put a Unicode "zero width space" as a suffix, so LabelFollowedBy is still shown, as in Word.
630 // With empty suffix, Writer does not show LabelFollowedBy, either.
631 comphelper::SequenceAsHashMap
aMap(aLvlProps
);
632 if (aMap
.find("NumberingType") != aMap
.end())
634 sal_Int16 nNumberFormat
= aMap
["NumberingType"].get
<sal_Int16
>();
636 // No need for a zero width space without a real LabelFollowedBy.
637 bool bLabelFollowedBy
= true;
638 auto it
= std::find_if(aLvlProps
.begin(), aLvlProps
.end(), [](const beans::PropertyValue
& rValue
) { return rValue
.Name
== "LabelFollowedBy"; });
639 if (it
!= aLvlProps
.end())
642 if (it
->Value
>>= nValue
)
643 bLabelFollowedBy
= nValue
!= SvxNumberFormat::NOTHING
;
646 if (bLabelFollowedBy
&& nNumberFormat
== style::NumberingType::NUMBER_NONE
)
647 rSuffix
= OUString(static_cast<sal_Unicode
>(0x200B));
651 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 3] = MAKE_PROPVAL( PROP_SUFFIX
, rSuffix
);
652 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 2] = MAKE_PROPVAL( PROP_PARENT_NUMBERING
, nParentNum
);
654 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 1] = MAKE_PROPVAL( PROP_POSITION_AND_SPACE_MODE
,
655 sal_Int16( text::PositionAndSpaceMode::LABEL_ALIGNMENT
) );
658 // Replace the numbering rules for the level
659 m_xNumRules
->replaceByIndex( nLevel
, uno::makeAny( aLvlProps
) );
661 // Handle the outline level here
662 if ( pAbsLevel
->isOutlineNumbering())
664 uno::Reference
< text::XChapterNumberingSupplier
> xOutlines (
665 xFactory
, uno::UNO_QUERY_THROW
);
666 uno::Reference
< container::XIndexReplace
> xOutlineRules
=
667 xOutlines
->getChapterNumberingRules( );
669 StyleSheetEntryPtr pParaStyle
= pAbsLevel
->GetParaStyle( );
670 aLvlProps
.realloc( aLvlProps
.getLength() + 1 );
671 aLvlProps
[sal::static_int_cast
<sal_uInt32
>(aLvlProps
.getLength()) - 1] = MAKE_PROPVAL( PROP_HEADING_STYLE_NAME
,
672 pParaStyle
->sConvertedStyleName
);
674 xOutlineRules
->replaceByIndex( nLevel
, uno::makeAny( aLvlProps
) );
680 // Create the numbering style for these rules
681 OUString sNumRulesName
= aPropNameSupplier
.GetName( PROP_NUMBERING_RULES
);
682 xStyle
->setPropertyValue( sNumRulesName
, uno::makeAny( m_xNumRules
) );
684 catch( const lang::IllegalArgumentException
& e
)
686 SAL_WARN( "writerfilter", "Exception: " << e
.Message
);
687 assert( !"Incorrect argument to UNO call" );
689 catch( const uno::RuntimeException
& e
)
691 SAL_WARN( "writerfilter", "Exception: " << e
.Message
);
692 assert( !"Incorrect argument to UNO call" );
694 catch( const uno::Exception
& e
)
696 SAL_WARN( "writerfilter", "Exception: " << e
.Message
);
702 //------------------------------------- NumberingManager implementation
705 ListsManager::ListsManager(DomainMapper
& rDMapper
,
706 const uno::Reference
<lang::XMultiServiceFactory
> & xFactory
)
707 : LoggedProperties("ListsManager")
708 , LoggedTable("ListsManager")
709 , m_rDMapper(rDMapper
)
710 , m_xFactory(xFactory
)
711 , m_bIsLFOImport(false)
715 ListsManager::~ListsManager( )
717 DisposeNumPicBullets();
720 void ListsManager::DisposeNumPicBullets( )
722 uno::Reference
<drawing::XShape
> xShape
;
723 for (std::vector
<NumPicBullet::Pointer
>::iterator it
= m_aNumPicBullets
.begin(); it
!= m_aNumPicBullets
.end(); ++it
)
725 xShape
= (*it
)->GetShape();
728 uno::Reference
<lang::XComponent
> xShapeComponent(xShape
, uno::UNO_QUERY
);
729 xShapeComponent
->dispose();
734 void ListsManager::lcl_attribute( Id nName
, Value
& rVal
)
736 ListLevel::Pointer pCurrentLvl
;
738 if (nName
!= NS_ooxml::LN_CT_NumPicBullet_numPicBulletId
)
740 OSL_ENSURE( m_pCurrentDefinition
.get(), "current entry has to be set here");
741 if(!m_pCurrentDefinition
.get())
743 pCurrentLvl
= m_pCurrentDefinition
->GetCurrentLevel( );
747 SAL_WARN_IF(!m_pCurrentNumPicBullet
.get(), "writerfilter", "current entry has to be set here");
748 if (!m_pCurrentNumPicBullet
.get())
751 int nIntValue
= rVal
.getInt();
757 case NS_ooxml::LN_CT_LevelText_val
:
759 //this strings contains the definition of the level
760 //the level number is marked as %n
761 //these numbers can be mixed randomly together with separators pre- and suffixes
762 //the Writer supports only a number of upper levels to show, separators is always a dot
763 //and each level can have a prefix and a suffix
764 if(pCurrentLvl
.get())
765 pCurrentLvl
->SetBulletChar( rVal
.getString() );
768 case NS_ooxml::LN_CT_Lvl_start
:
769 case NS_ooxml::LN_CT_Lvl_numFmt
:
770 case NS_ooxml::LN_CT_Lvl_isLgl
:
771 case NS_ooxml::LN_CT_Lvl_legacy
:
772 if ( pCurrentLvl
.get( ) )
773 pCurrentLvl
->SetValue( nName
, sal_Int32( nIntValue
) );
775 case NS_ooxml::LN_CT_Num_numId
:
776 m_pCurrentDefinition
->SetId( rVal
.getString().toInt32( ) );
778 case NS_ooxml::LN_CT_AbstractNum_nsid
:
779 m_pCurrentDefinition
->SetId( nIntValue
);
781 case NS_ooxml::LN_CT_AbstractNum_tmpl
:
782 m_pCurrentDefinition
->SetValue( nName
, nIntValue
);
784 case NS_ooxml::LN_CT_NumLvl_ilvl
:
786 //add a new level to the level vector and make it the current one
787 m_pCurrentDefinition
->AddLevel();
789 writerfilter::Reference
<Properties
>::Pointer_t pProperties
;
790 if((pProperties
= rVal
.getProperties()).get())
791 pProperties
->resolve(*this);
794 case NS_ooxml::LN_CT_AbstractNum_abstractNumId
:
796 // This one corresponds to the AbstractNum Id definition
797 // The reference to the abstract num is in the sprm method
798 sal_Int32 nVal
= rVal
.getString().toInt32();
799 m_pCurrentDefinition
->SetId( nVal
);
802 case NS_ooxml::LN_CT_Ind_left
:
804 PROP_INDENT_AT
, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue
) ));
806 case NS_ooxml::LN_CT_Ind_hanging
:
808 PROP_FIRST_LINE_INDENT
, uno::makeAny( - ConversionHelper::convertTwipToMM100( nIntValue
) ));
810 case NS_ooxml::LN_CT_Ind_firstLine
:
812 PROP_FIRST_LINE_INDENT
, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue
) ));
814 case NS_ooxml::LN_CT_Lvl_ilvl
: //overrides previous level - unsupported
815 case NS_ooxml::LN_CT_Lvl_tplc
: //template code - unsupported
816 case NS_ooxml::LN_CT_Lvl_tentative
: //marks level as unused in the document - unsupported
818 case NS_ooxml::LN_CT_TabStop_pos
:
820 //no paragraph attributes in ListTable char style sheets
821 if ( pCurrentLvl
.get( ) )
822 pCurrentLvl
->SetValue( nName
,
823 ConversionHelper::convertTwipToMM100( nIntValue
) );
826 case NS_ooxml::LN_CT_TabStop_val
:
828 // TODO Do something of that
831 case NS_ooxml::LN_CT_NumPicBullet_numPicBulletId
:
832 m_pCurrentNumPicBullet
->SetId(rVal
.getString().toInt32());
835 SAL_WARN("writerfilter", "ListsManager::lcl_attribute: unhandled token: " << nName
);
839 void ListsManager::lcl_sprm( Sprm
& rSprm
)
841 //fill the attributes of the style sheet
842 sal_uInt32 nSprmId
= rSprm
.getId();
843 if( m_pCurrentDefinition
.get() ||
844 nSprmId
== NS_ooxml::LN_CT_Numbering_abstractNum
||
845 nSprmId
== NS_ooxml::LN_CT_Numbering_num
||
846 (nSprmId
== NS_ooxml::LN_CT_NumPicBullet_pict
&& m_pCurrentNumPicBullet
.get()) ||
847 nSprmId
== NS_ooxml::LN_CT_Numbering_numPicBullet
)
849 static bool bIsStartVisited
= false;
850 sal_Int32 nIntValue
= rSprm
.getValue()->getInt();
853 case NS_ooxml::LN_CT_Numbering_abstractNum
:
855 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
856 if(pProperties
.get())
858 //create a new Abstract list entry
859 OSL_ENSURE( !m_pCurrentDefinition
.get(), "current entry has to be NULL here");
860 m_pCurrentDefinition
.reset( new AbstractListDef
);
861 pProperties
->resolve( *this );
862 //append it to the table
863 m_aAbstractLists
.push_back( m_pCurrentDefinition
);
864 m_pCurrentDefinition
= AbstractListDef::Pointer();
868 case NS_ooxml::LN_CT_Numbering_num
:
870 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
871 if(pProperties
.get())
873 // Create a new list entry
874 OSL_ENSURE( !m_pCurrentDefinition
.get(), "current entry has to be NULL here");
875 ListDef::Pointer
listDef( new ListDef
);
876 m_pCurrentDefinition
= listDef
;
877 pProperties
->resolve( *this );
878 //append it to the table
879 m_aLists
.push_back( listDef
);
881 m_pCurrentDefinition
= AbstractListDef::Pointer();
885 case NS_ooxml::LN_CT_Numbering_numPicBullet
:
887 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
888 if (pProperties
.get())
890 NumPicBullet::Pointer
numPicBullet(new NumPicBullet());
891 m_pCurrentNumPicBullet
= numPicBullet
;
892 pProperties
->resolve(*this);
893 m_aNumPicBullets
.push_back(numPicBullet
);
894 m_pCurrentNumPicBullet
= NumPicBullet::Pointer();
898 case NS_ooxml::LN_CT_NumPicBullet_pict
:
900 uno::Reference
<drawing::XShape
> xShape
= m_rDMapper
.PopPendingShape();
902 // Respect only the aspect ratio of the picture, not its size.
903 awt::Size aPrefSize
= xShape
->getSize();
904 // See SwDefBulletConfig::InitFont(), default height is 14.
905 const int nFontHeight
= 14;
907 const int nHeight
= nFontHeight
* 35;
908 if (aPrefSize
.Height
* aPrefSize
.Width
!= 0)
910 int nWidth
= (nHeight
* aPrefSize
.Width
) / aPrefSize
.Height
;
911 awt::Size
aSize(nWidth
, nHeight
);
912 xShape
->setSize(aSize
);
915 m_pCurrentNumPicBullet
->SetShape(xShape
);
918 case NS_ooxml::LN_CT_Lvl_lvlPicBulletId
:
920 uno::Reference
<drawing::XShape
> xShape
;
921 for (std::vector
<NumPicBullet::Pointer
>::iterator it
= m_aNumPicBullets
.begin(); it
!= m_aNumPicBullets
.end(); ++it
)
923 if ((*it
)->GetId() == nIntValue
)
925 xShape
= (*it
)->GetShape();
931 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
934 uno::Any aAny
= xPropertySet
->getPropertyValue("GraphicURL");
935 if (aAny
.has
<OUString
>())
936 m_pCurrentDefinition
->GetCurrentLevel()->SetGraphicURL(aAny
.get
<OUString
>());
937 } catch(const beans::UnknownPropertyException
&)
941 uno::Reference
< graphic::XGraphic
> gr
;
942 xPropertySet
->getPropertyValue("Bitmap") >>= gr
;
943 m_pCurrentDefinition
->GetCurrentLevel()->SetGraphicBitmap( gr
);
944 } catch(const beans::UnknownPropertyException
&)
947 // Now that we saved the URL of the graphic, remove it from the document.
948 uno::Reference
<lang::XComponent
> xShapeComponent(xShape
, uno::UNO_QUERY
);
949 xShapeComponent
->dispose();
953 case NS_ooxml::LN_CT_Num_abstractNumId
:
955 sal_Int32 nAbstractNumId
= rSprm
.getValue()->getInt();
956 ListDef
* pListDef
= dynamic_cast< ListDef
* >( m_pCurrentDefinition
.get( ) );
957 if ( pListDef
!= nullptr )
959 // The current def should be a ListDef
960 pListDef
->SetAbstractDefinition(
961 GetAbstractList( nAbstractNumId
) );
965 case NS_ooxml::LN_CT_AbstractNum_multiLevelType
:
967 case NS_ooxml::LN_CT_AbstractNum_tmpl
:
968 m_pCurrentDefinition
->SetValue( nSprmId
, nIntValue
);
970 case NS_ooxml::LN_CT_AbstractNum_lvl
:
972 m_pCurrentDefinition
->AddLevel();
973 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
974 if(pProperties
.get())
975 pProperties
->resolve(*this);
978 case NS_ooxml::LN_CT_Lvl_start
:
979 if (m_pCurrentDefinition
->GetCurrentLevel().get())
980 m_pCurrentDefinition
->GetCurrentLevel( )->SetValue( nSprmId
, nIntValue
);
981 bIsStartVisited
= true;
983 case NS_ooxml::LN_CT_Lvl_numFmt
:
984 case NS_ooxml::LN_CT_Lvl_isLgl
:
985 case NS_ooxml::LN_CT_Lvl_legacy
:
986 if (m_pCurrentDefinition
->GetCurrentLevel().get())
988 m_pCurrentDefinition
->GetCurrentLevel( )->SetValue( nSprmId
, nIntValue
);
989 if( !bIsStartVisited
)
991 m_pCurrentDefinition
->GetCurrentLevel( )->SetValue( NS_ooxml::LN_CT_Lvl_start
, 0 );
992 bIsStartVisited
= true;
996 case NS_ooxml::LN_CT_Lvl_suff
:
998 if (m_pCurrentDefinition
->GetCurrentLevel().get())
1000 SvxNumberFormat::LabelFollowedBy value
= SvxNumberFormat::LISTTAB
;
1001 if( rSprm
.getValue()->getString() == "tab" )
1002 value
= SvxNumberFormat::LISTTAB
;
1003 else if( rSprm
.getValue()->getString() == "space" )
1004 value
= SvxNumberFormat::SPACE
;
1005 else if( rSprm
.getValue()->getString() == "nothing" )
1006 value
= SvxNumberFormat::NOTHING
;
1008 SAL_WARN( "writerfilter", "Unknown ST_LevelSuffix value "
1009 << rSprm
.getValue()->getString());
1010 m_pCurrentDefinition
->GetCurrentLevel()->SetValue( nSprmId
, value
);
1014 case NS_ooxml::LN_CT_Lvl_lvlText
:
1015 case NS_ooxml::LN_CT_Lvl_rPr
: //contains LN_EG_RPrBase_rFonts
1017 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1018 if(pProperties
.get())
1019 pProperties
->resolve(*this);
1022 case NS_ooxml::LN_CT_NumLvl_lvl
:
1025 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1026 if(pProperties
.get())
1027 pProperties
->resolve(*this);
1030 case NS_ooxml::LN_CT_Lvl_lvlJc
:
1032 sal_Int16 nValue
= 0;
1035 case NS_ooxml::LN_Value_ST_Jc_left
:
1036 case NS_ooxml::LN_Value_ST_Jc_start
:
1037 nValue
= text::HoriOrientation::LEFT
;
1039 case NS_ooxml::LN_Value_ST_Jc_center
:
1040 nValue
= text::HoriOrientation::CENTER
;
1042 case NS_ooxml::LN_Value_ST_Jc_right
:
1043 case NS_ooxml::LN_Value_ST_Jc_end
:
1044 nValue
= text::HoriOrientation::RIGHT
;
1047 m_pCurrentDefinition
->GetCurrentLevel( )->Insert(
1048 PROP_ADJUST
, uno::makeAny( nValue
) );
1049 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1052 case NS_ooxml::LN_CT_Lvl_pPr
:
1053 case NS_ooxml::LN_CT_PPrBase_ind
:
1055 //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
1056 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1057 if(pProperties
.get())
1058 pProperties
->resolve(*this);
1061 case NS_ooxml::LN_CT_PPrBase_tabs
:
1062 case NS_ooxml::LN_CT_Tabs_tab
:
1064 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1065 if(pProperties
.get())
1066 pProperties
->resolve(*this);
1069 case NS_ooxml::LN_CT_Lvl_pStyle
:
1071 OUString sStyleName
= rSprm
.getValue( )->getString( );
1072 ListLevel::Pointer pLevel
= m_pCurrentDefinition
->GetCurrentLevel( );
1073 StyleSheetTablePtr pStylesTable
= m_rDMapper
.GetStyleSheetTable( );
1074 const StyleSheetEntryPtr pStyle
= pStylesTable
->FindStyleSheetByISTD( sStyleName
);
1075 pLevel
->SetParaStyle( pStyle
);
1078 case NS_ooxml::LN_CT_Num_lvlOverride
:
1080 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
1081 if (pProperties
.get())
1082 pProperties
->resolve(*this);
1085 case NS_ooxml::LN_CT_NumLvl_startOverride
:
1087 if(m_pCurrentDefinition
)
1089 if (ListLevel::Pointer pCurrentLevel
= m_pCurrentDefinition
->GetCurrentLevel())
1090 // <w:num> -> <w:lvlOverride> -> <w:startOverride> is the non-abstract equivalent of
1091 // <w:abstractNum> -> <w:lvl> -> <w:start>
1092 pCurrentLevel
->SetValue(NS_ooxml::LN_CT_Lvl_start
, nIntValue
);
1096 case NS_ooxml::LN_CT_AbstractNum_numStyleLink
:
1098 OUString sStyleName
= rSprm
.getValue( )->getString( );
1099 AbstractListDef
* pAbstractListDef
= dynamic_cast< AbstractListDef
* >( m_pCurrentDefinition
.get( ) );
1100 pAbstractListDef
->SetNumStyleLink(sStyleName
);
1103 case NS_ooxml::LN_EG_RPrBase_rFonts
: //contains font properties
1104 case NS_ooxml::LN_EG_RPrBase_color
:
1105 case NS_ooxml::LN_EG_RPrBase_u
:
1106 case NS_ooxml::LN_EG_RPrBase_sz
:
1107 case NS_ooxml::LN_EG_RPrBase_lang
:
1108 case NS_ooxml::LN_EG_RPrBase_eastAsianLayout
:
1111 if( m_pCurrentDefinition
->GetCurrentLevel( ).get())
1113 m_rDMapper
.PushListProperties( m_pCurrentDefinition
->GetCurrentLevel( ) );
1114 m_rDMapper
.sprm( rSprm
);
1115 m_rDMapper
.PopListProperties();
1121 void ListsManager::lcl_entry( int /* pos */,
1122 writerfilter::Reference
<Properties
>::Pointer_t ref
)
1124 if( m_rDMapper
.IsOOXMLImport() || m_rDMapper
.IsRTFImport() )
1126 ref
->resolve(*this);
1130 if ( m_bIsLFOImport
)
1133 OSL_ENSURE( !m_pCurrentDefinition
.get(), "current entry has to be NULL here");
1134 ListDef::Pointer
pList( new ListDef() );
1135 m_pCurrentDefinition
= pList
;
1136 ref
->resolve(*this);
1137 //append it to the table
1138 m_aLists
.push_back( pList
);
1139 m_pCurrentDefinition
= AbstractListDef::Pointer();
1143 // Create AbstractListDef's
1144 OSL_ENSURE( !m_pCurrentDefinition
.get(), "current entry has to be NULL here");
1145 m_pCurrentDefinition
.reset( new AbstractListDef( ) );
1146 ref
->resolve(*this);
1147 //append it to the table
1148 m_aAbstractLists
.push_back( m_pCurrentDefinition
);
1149 m_pCurrentDefinition
= AbstractListDef::Pointer();
1154 AbstractListDef::Pointer
ListsManager::GetAbstractList( sal_Int32 nId
)
1156 AbstractListDef::Pointer pAbstractList
;
1158 int nLen
= m_aAbstractLists
.size( );
1160 while ( !pAbstractList
.get( ) && i
< nLen
)
1162 if ( m_aAbstractLists
[i
]->GetId( ) == nId
)
1164 if ( m_aAbstractLists
[i
]->GetNumStyleLink().getLength() > 0 )
1166 // If the abstract num has a style linked, check the linked style's number id.
1167 StyleSheetTablePtr pStylesTable
= m_rDMapper
.GetStyleSheetTable( );
1169 const StyleSheetEntryPtr pStyleSheetEntry
=
1170 pStylesTable
->FindStyleSheetByISTD( m_aAbstractLists
[i
]->GetNumStyleLink() );
1172 const StyleSheetPropertyMap
* pStyleSheetProperties
=
1173 dynamic_cast<const StyleSheetPropertyMap
*>(pStyleSheetEntry
? pStyleSheetEntry
->pProperties
.get() : nullptr);
1175 if( pStyleSheetProperties
&& pStyleSheetProperties
->GetNumId() >= 0 )
1177 ListDef::Pointer pList
= GetList( pStyleSheetProperties
->GetNumId() );
1178 if ( pList
!=nullptr )
1179 return pList
->GetAbstractDefinition();
1181 pAbstractList
= m_aAbstractLists
[i
];
1187 pAbstractList
= m_aAbstractLists
[i
];
1193 return pAbstractList
;
1196 ListDef::Pointer
ListsManager::GetList( sal_Int32 nId
)
1198 ListDef::Pointer pList
;
1200 int nLen
= m_aLists
.size( );
1202 while ( !pList
.get( ) && i
< nLen
)
1204 if ( m_aLists
[i
]->GetId( ) == nId
)
1205 pList
= m_aLists
[i
];
1212 void ListsManager::CreateNumberingRules( )
1214 // Loop over the definitions
1215 std::vector
< ListDef::Pointer
>::iterator listIt
= m_aLists
.begin( );
1216 for ( ; listIt
!= m_aLists
.end( ); ++listIt
)
1218 (*listIt
)->CreateNumberingRules( m_rDMapper
, m_xFactory
);
1224 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */