fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / writerfilter / source / dmapper / NumberingManager.cxx
blob98dacdf9a6a068cd4bb4ac6607d616727800260f
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 .
19 #include "ConversionHelper.hxx"
20 #include "NumberingManager.hxx"
21 #include "StyleSheetTable.hxx"
22 #include "PropertyIds.hxx"
24 #include <doctok/resourceids.hxx>
25 #include <doctok/sprmids.hxx>
26 #include <ooxml/resourceids.hxx>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/container/XNameContainer.hpp>
30 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
31 #include <com/sun/star/style/NumberingType.hpp>
32 #include <com/sun/star/text/HoriOrientation.hpp>
33 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
34 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
36 #include <rtl/ustring.hxx>
38 #include "dmapperLoggers.hxx"
40 using namespace com::sun::star;
42 #define MAKE_PROPVAL(NameId, Value) \
43 beans::PropertyValue(aPropNameSupplier.GetName(NameId), 0, uno::makeAny(Value), beans::PropertyState_DIRECT_VALUE )
45 #define NUMBERING_MAX_LEVELS 10
48 namespace writerfilter {
49 namespace dmapper {
51 //--------------------------------------------------- Utility functions
53 void lcl_printProperties( uno::Sequence< beans::PropertyValue > aProps )
55 sal_Int32 nLen = aProps.getLength( );
56 for ( sal_Int32 i = 0; i < nLen; i++ )
58 uno::Any aValue = aProps[i].Value;
59 sal_Int32 nValue = 0;
60 OUString sValue;
62 if ( !( aValue >>= sValue ) && ( aValue >>= nValue ) )
63 sValue = OUString::valueOf( nValue );
65 SAL_INFO("writerfilter", "Property " << aProps[i].Name << ": " << sValue);
69 sal_Int32 lcl_findProperty( uno::Sequence< beans::PropertyValue > aProps, OUString sName )
71 sal_Int32 i = 0;
72 sal_Int32 nLen = aProps.getLength( );
73 sal_Int32 nPos = -1;
75 while ( nPos == -1 && i < nLen )
77 if ( aProps[i].Name.equals( sName ) )
78 nPos = i;
79 else
80 i++;
83 return nPos;
86 void lcl_mergeProperties( uno::Sequence< beans::PropertyValue >& aSrc,
87 uno::Sequence< beans::PropertyValue >& aDst )
89 for ( sal_Int32 i = 0, nSrcLen = aSrc.getLength( ); i < nSrcLen; i++ )
91 // Look for the same property in aDst
92 sal_Int32 nPos = lcl_findProperty( aDst, aSrc[i].Name );
93 if ( nPos >= 0 )
95 // Replace the property value by the one in aSrc
96 aDst[nPos] = aSrc[i];
98 else
100 // Simply add the new value
101 aDst.realloc( aDst.getLength( ) + 1 );
102 aDst[ aDst.getLength( ) - 1 ] = aSrc[i];
107 //-------------------------------------------- ListLevel implementation
108 void ListLevel::SetValue( Id nId, sal_Int32 nValue )
110 switch( nId )
112 case NS_rtf::LN_ISTARTAT:
113 m_nIStartAt = nValue;
114 break;
115 case NS_rtf::LN_NFC:
116 m_nNFC = nValue;
117 break;
118 case NS_rtf::LN_JC:
119 m_nJC = nValue;
120 break;
121 case NS_rtf::LN_FLEGAL:
122 m_nFLegal = nValue;
123 break;
124 case NS_rtf::LN_FNORESTART:
125 m_nFNoRestart = nValue;
126 break;
127 case NS_rtf::LN_FIDENTSAV:
128 m_nFPrev = nValue;
129 break;
130 case NS_rtf::LN_FCONVERTED:
131 m_nFPrevSpace = nValue;
132 break;
133 case NS_rtf::LN_IXCHFOLLOW:
134 case NS_ooxml::LN_CT_Lvl_suff:
135 m_nXChFollow = nValue;
136 break;
137 case NS_ooxml::LN_CT_TabStop_pos:
138 if (nValue < 0)
140 SAL_INFO("writerfilter",
141 "unsupported list tab stop position " << nValue);
143 else
144 m_nTabstop = nValue;
145 break;
146 default:
147 OSL_FAIL( "this line should never be reached");
151 void ListLevel::SetParaStyle( boost::shared_ptr< StyleSheetEntry > pStyle )
153 if (!pStyle)
154 return;
155 m_pParaStyle = pStyle;
156 // AFAICT .docx spec does not identify which numberings or paragraph
157 // styles are actually the ones to be used for outlines (chapter numbering),
158 // it only kind of says somewhere that they should be named Heading1 to Heading9.
159 const OUString styleId = pStyle->sStyleIdentifierD;
160 m_outline = ( styleId.getLength() == RTL_CONSTASCII_LENGTH( "Heading1" )
161 && styleId.match( "Heading", 0 )
162 && styleId[ RTL_CONSTASCII_LENGTH( "Heading" ) ] >= '1'
163 && styleId[ RTL_CONSTASCII_LENGTH( "Heading" ) ] <= '9' );
166 sal_Int16 ListLevel::GetParentNumbering( OUString sText, sal_Int16 nLevel,
167 OUString& rPrefix, OUString& rSuffix )
169 sal_Int16 nParentNumbering = 1;
171 //now parse the text to find %n from %1 to %nLevel+1
172 //everything before the first % and the last %x is prefix and suffix
173 OUString sLevelText( sText );
174 sal_Int32 nCurrentIndex = 0;
175 sal_Int32 nFound = sLevelText.indexOf( '%', nCurrentIndex );
176 if( nFound > 0 )
178 rPrefix = sLevelText.copy( 0, nFound );
179 sLevelText = sLevelText.copy( nFound );
181 sal_Int32 nMinLevel = nLevel;
182 //now the text should either be empty or start with %
183 nFound = sLevelText.getLength( ) > 1 ? 0 : -1;
184 while( nFound >= 0 )
186 if( sLevelText.getLength() > 1 )
188 sal_Unicode cLevel = sLevelText.getStr()[1];
189 if( cLevel >= '1' && cLevel <= '9' )
191 if( cLevel - '1' < nMinLevel )
192 nMinLevel = cLevel - '1';
193 //remove first char - next char is removed later
194 sLevelText = sLevelText.copy( 1 );
197 //remove old '%' or number
198 sLevelText = sLevelText.copy( 1 );
199 nCurrentIndex = 0;
200 nFound = sLevelText.indexOf( '%', nCurrentIndex );
201 //remove the text before the next %
202 if(nFound > 0)
203 sLevelText = sLevelText.copy( nFound -1 );
205 if( nMinLevel < nLevel )
207 nParentNumbering = sal_Int16( nLevel - nMinLevel + 1);
210 rSuffix = sLevelText;
212 return nParentNumbering;
215 uno::Sequence< beans::PropertyValue > ListLevel::GetProperties( )
217 uno::Sequence< beans::PropertyValue > aLevelProps = GetLevelProperties( );
218 if ( m_pParaStyle.get( ) )
219 AddParaProperties( &aLevelProps );
220 return aLevelProps;
223 uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( )
225 PropertyValueVector_t rProperties;
226 PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
228 _PropertyMap::const_iterator aMapIter = begin();
229 _PropertyMap::const_iterator aEndIter = end();
230 for( ; aMapIter != aEndIter; ++aMapIter )
232 switch( aMapIter->first.eId )
234 case PROP_ADJUST:
235 case PROP_INDENT_AT:
236 case PROP_FIRST_LINE_INDENT:
237 case PROP_FIRST_LINE_OFFSET:
238 case PROP_LEFT_MARGIN:
239 case PROP_CHAR_FONT_NAME:
240 // Do nothing: handled in the GetPropertyValues method
241 break;
242 default:
244 rProperties.push_back(
245 beans::PropertyValue(
246 aPropNameSupplier.GetName( aMapIter->first.eId ), 0,
247 aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
252 uno::Sequence< beans::PropertyValue > aRet( rProperties.size() );
253 beans::PropertyValue* pValues = aRet.getArray();
254 PropertyValueVector_t::const_iterator aIt = rProperties.begin();
255 PropertyValueVector_t::const_iterator aEndIt = rProperties.end();
256 for(sal_uInt32 nIndex = 0; aIt != aEndIt; ++aIt,++nIndex)
258 pValues[nIndex] = *aIt;
260 return aRet;
263 uno::Sequence< beans::PropertyValue > ListLevel::GetLevelProperties( )
265 const sal_Int16 aWWToUnoAdjust[] =
267 text::HoriOrientation::LEFT,
268 text::HoriOrientation::CENTER,
269 text::HoriOrientation::RIGHT,
272 PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
273 PropertyValueVector_t aNumberingProperties;
275 if( m_nIStartAt >= 0)
276 aNumberingProperties.push_back( MAKE_PROPVAL(PROP_START_WITH, (sal_Int16)m_nIStartAt) );
278 sal_Int16 nNumberFormat = ConversionHelper::ConvertNumberingType(m_nNFC);
279 if( m_nNFC >= 0)
281 if (!m_sGraphicURL.isEmpty() || m_sGraphicBitmap.is())
282 nNumberFormat = style::NumberingType::BITMAP;
283 aNumberingProperties.push_back( MAKE_PROPVAL(PROP_NUMBERING_TYPE, nNumberFormat ));
286 if( m_nJC >= 0 && m_nJC <= sal::static_int_cast<sal_Int32>(sizeof(aWWToUnoAdjust) / sizeof(sal_Int16)) )
287 aNumberingProperties.push_back( MAKE_PROPVAL(PROP_ADJUST, aWWToUnoAdjust[m_nJC]));
289 if( !isOutlineNumbering())
291 // todo: this is not the bullet char
292 if( nNumberFormat == style::NumberingType::CHAR_SPECIAL && !m_sBulletChar.isEmpty() )
293 aNumberingProperties.push_back( MAKE_PROPVAL(PROP_BULLET_CHAR, m_sBulletChar.copy(0,1)));
294 if (!m_sGraphicURL.isEmpty())
295 aNumberingProperties.push_back(MAKE_PROPVAL(PROP_GRAPHIC_URL, m_sGraphicURL));
296 if (m_sGraphicBitmap.is())
297 aNumberingProperties.push_back(MAKE_PROPVAL(PROP_GRAPHIC_BITMAP, m_sGraphicBitmap));
300 aNumberingProperties.push_back( MAKE_PROPVAL( PROP_LISTTAB_STOP_POSITION, m_nTabstop ) );
302 //TODO: handling of nFLegal?
303 //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
304 //1.
305 //1.1
306 //2.2
307 //2.3
308 //3.4
311 if( m_nFWord6 > 0) //Word 6 compatibility
313 if( m_nFPrev == 1)
314 aNumberingProperties.push_back( MAKE_PROPVAL( PROP_PARENT_NUMBERING, (sal_Int16) NUMBERING_MAX_LEVELS ));
315 //TODO: prefixing space nFPrevSpace; - has not been used in WW8 filter
318 // TODO: sRGBXchNums; array of inherited numbers
320 // nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
321 aNumberingProperties.push_back( MAKE_PROPVAL( PROP_LEVEL_FOLLOW, m_nXChFollow ));
324 _PropertyMap::const_iterator aMapIter = begin();
325 _PropertyMap::const_iterator aEndIter = end();
326 for( ; aMapIter != aEndIter; ++aMapIter )
328 switch( aMapIter->first.eId )
330 case PROP_ADJUST:
331 case PROP_INDENT_AT:
332 case PROP_FIRST_LINE_INDENT:
333 case PROP_FIRST_LINE_OFFSET:
334 case PROP_LEFT_MARGIN:
335 aNumberingProperties.push_back(
336 beans::PropertyValue( aPropNameSupplier.GetName( aMapIter->first.eId ), 0, aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
337 break;
338 case PROP_CHAR_FONT_NAME:
339 if( !isOutlineNumbering())
341 aNumberingProperties.push_back(
342 beans::PropertyValue( aPropNameSupplier.GetName( PROP_BULLET_FONT_NAME ), 0, aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
344 break;
345 default:
347 // Handled in GetCharStyleProperties method
353 uno::Sequence< beans::PropertyValue > aRet(aNumberingProperties.size());
354 beans::PropertyValue* pValues = aRet.getArray();
355 PropertyValueVector_t::const_iterator aIt = aNumberingProperties.begin();
356 PropertyValueVector_t::const_iterator aEndIt = aNumberingProperties.end();
357 for(sal_uInt32 nIndex = 0; aIt != aEndIt; ++aIt,++nIndex)
359 pValues[nIndex] = *aIt;
361 return aRet;
364 // Add the properties only if they do not already exist in the sequence.
365 void ListLevel::AddParaProperties( uno::Sequence< beans::PropertyValue >* props )
367 uno::Sequence< beans::PropertyValue >& aProps = *props;
368 PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
370 OUString sFirstLineIndent = aPropNameSupplier.GetName(
371 PROP_FIRST_LINE_INDENT );
372 OUString sIndentAt = aPropNameSupplier.GetName(
373 PROP_INDENT_AT );
375 bool hasFirstLineIndent = lcl_findProperty( aProps, sFirstLineIndent );
376 bool hasIndentAt = lcl_findProperty( aProps, sIndentAt );
378 if( hasFirstLineIndent && hasIndentAt )
379 return; // has them all, nothing to add
381 uno::Sequence< beans::PropertyValue > aParaProps = m_pParaStyle->pProperties->GetPropertyValues( );
383 // ParaFirstLineIndent -> FirstLineIndent
384 // ParaLeftMargin -> IndentAt
386 OUString sParaIndent = aPropNameSupplier.GetName(
387 PROP_PARA_FIRST_LINE_INDENT );
388 OUString sParaLeftMargin = aPropNameSupplier.GetName(
389 PROP_PARA_LEFT_MARGIN );
391 sal_Int32 nLen = aParaProps.getLength( );
392 for ( sal_Int32 i = 0; i < nLen; i++ )
394 if ( !hasFirstLineIndent && aParaProps[i].Name.equals( sParaIndent ) )
396 aProps.realloc( aProps.getLength() + 1 );
397 aProps[aProps.getLength( ) - 1] = aParaProps[i];
398 aProps[aProps.getLength( ) - 1].Name = sFirstLineIndent;
400 else if ( !hasIndentAt && aParaProps[i].Name.equals( sParaLeftMargin ) )
402 aProps.realloc( aProps.getLength() + 1 );
403 aProps[aProps.getLength( ) - 1] = aParaProps[i];
404 aProps[aProps.getLength( ) - 1].Name = sIndentAt;
410 NumPicBullet::NumPicBullet()
411 : m_nId(0)
415 NumPicBullet::~NumPicBullet()
419 void NumPicBullet::SetId(sal_Int32 nId)
421 m_nId = nId;
424 void NumPicBullet::SetShape(uno::Reference<drawing::XShape> xShape)
426 m_xShape = xShape;
429 sal_Int32 NumPicBullet::GetId()
431 return m_nId;
434 uno::Reference<drawing::XShape> NumPicBullet::GetShape()
436 return m_xShape;
439 //--------------------------------------- AbstractListDef implementation
441 AbstractListDef::AbstractListDef( ) :
442 m_nTPLC( -1 )
443 ,m_nSimpleList( -1 )
444 ,m_nRestart( -1 )
445 ,m_nUnsigned( -1 )
446 ,m_nId( -1 )
450 AbstractListDef::~AbstractListDef( )
454 void AbstractListDef::SetValue( sal_uInt32 nSprmId, sal_Int32 nValue )
456 switch( nSprmId )
458 case NS_rtf::LN_TPLC:
459 m_nTPLC = nValue;
460 break;
461 case NS_rtf::LN_FSIMPLELIST:
462 m_nSimpleList = nValue;
463 break;
464 case NS_rtf::LN_fAutoNum:
465 m_nRestart = nValue;
466 break;
467 case NS_rtf::LN_fHybrid:
468 m_nUnsigned = nValue;
469 break;
470 default:
471 OSL_FAIL( "this line should never be reached");
475 ListLevel::Pointer AbstractListDef::GetLevel( sal_uInt16 nLvl )
477 ListLevel::Pointer pLevel;
478 if ( m_aLevels.size( ) > nLvl )
479 pLevel = m_aLevels[ nLvl ];
480 return pLevel;
483 void AbstractListDef::AddLevel( )
485 ListLevel::Pointer pLevel( new ListLevel );
486 m_pCurrentLevel = pLevel;
487 m_aLevels.push_back( pLevel );
490 uno::Sequence< uno::Sequence< beans::PropertyValue > > AbstractListDef::GetPropertyValues( )
492 uno::Sequence< uno::Sequence< beans::PropertyValue > > result( sal_Int32( m_aLevels.size( ) ) );
493 uno::Sequence< beans::PropertyValue >* aResult = result.getArray( );
495 int nLevels = m_aLevels.size( );
496 for ( int i = 0; i < nLevels; i++ )
498 aResult[i] = m_aLevels[i]->GetProperties( );
501 return result;
504 //---------------------------------------------- ListDef implementation
506 ListDef::ListDef( ) : AbstractListDef( )
510 ListDef::~ListDef( )
514 OUString ListDef::GetStyleName( sal_Int32 nId )
516 OUString sStyleName( "WWNum" );
517 sStyleName += OUString::valueOf( nId );
519 return sStyleName;
522 uno::Sequence< uno::Sequence< beans::PropertyValue > > ListDef::GetPropertyValues( )
524 // [1] Call the same method on the abstract list
525 uno::Sequence< uno::Sequence< beans::PropertyValue > > aAbstract = m_pAbstractDef->GetPropertyValues( );
527 // [2] Call the upper class method
528 uno::Sequence< uno::Sequence< beans::PropertyValue > > aThis = AbstractListDef::GetPropertyValues( );
530 // Merge the results of [2] in [1]
531 sal_Int32 nThisCount = aThis.getLength( );
532 sal_Int32 nAbstractCount = aAbstract.getLength( );
533 for ( sal_Int32 i = 0; i < nThisCount && i < nAbstractCount; i++ )
535 uno::Sequence< beans::PropertyValue > level = aThis[i];
536 if ( level.hasElements() )
538 // If the element contains something, merge it
539 lcl_mergeProperties( level, aAbstract[i] );
543 return aAbstract;
546 uno::Reference< container::XNameContainer > lcl_getUnoNumberingStyles(
547 uno::Reference< lang::XMultiServiceFactory > xFactory )
549 uno::Reference< container::XNameContainer > xStyles;
553 uno::Reference< style::XStyleFamiliesSupplier > xFamilies( xFactory, uno::UNO_QUERY_THROW );
554 uno::Any oFamily = xFamilies->getStyleFamilies( )->getByName("NumberingStyles");
556 oFamily >>= xStyles;
558 catch ( const uno::Exception & )
562 return xStyles;
565 void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
566 uno::Reference< lang::XMultiServiceFactory> xFactory )
568 // Get the UNO Numbering styles
569 uno::Reference< container::XNameContainer > xStyles = lcl_getUnoNumberingStyles( xFactory );
571 // Do the whole thing
572 if( !m_xNumRules.is() && xFactory.is() && xStyles.is( ) )
576 // Create the numbering style
577 uno::Reference< beans::XPropertySet > xStyle (
578 xFactory->createInstance("com.sun.star.style.NumberingStyle"),
579 uno::UNO_QUERY_THROW );
581 OUString sStyleName = GetStyleName( GetId( ) );
583 xStyles->insertByName( sStyleName, makeAny( xStyle ) );
585 uno::Any oStyle = xStyles->getByName( sStyleName );
586 xStyle.set( oStyle, uno::UNO_QUERY_THROW );
588 PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
590 // Get the default OOo Numbering style rules
591 uno::Any aRules = xStyle->getPropertyValue( aPropNameSupplier.GetName( PROP_NUMBERING_RULES ) );
592 aRules >>= m_xNumRules;
594 uno::Sequence< uno::Sequence< beans::PropertyValue > > aProps = GetPropertyValues( );
596 sal_Int32 nAbstLevels = m_pAbstractDef->Size( );
597 sal_Int16 nLevel = 0;
598 while ( nLevel < nAbstLevels )
600 ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel( nLevel );
601 ListLevel::Pointer pLevel = GetLevel( nLevel );
603 // Get the merged level properties
604 uno::Sequence< beans::PropertyValue > aLvlProps = aProps[sal_Int32( nLevel )];
606 #if OSL_DEBUG_LEVEL > 1
607 lcl_printProperties( aLvlProps );
608 #endif
610 // Get the char style
611 uno::Sequence< beans::PropertyValue > aAbsCharStyleProps = pAbsLevel->GetCharStyleProperties( );
612 uno::Sequence< beans::PropertyValue >& rAbsCharStyleProps = aAbsCharStyleProps;
613 if ( pLevel.get( ) )
615 uno::Sequence< beans::PropertyValue > aCharStyleProps =
616 pLevel->GetCharStyleProperties( );
617 uno::Sequence< beans::PropertyValue >& rCharStyleProps = aCharStyleProps;
618 lcl_mergeProperties( rAbsCharStyleProps, rCharStyleProps );
621 if( aAbsCharStyleProps.getLength() )
623 // Change the sequence into a vector
624 PropertyValueVector_t aStyleProps;
625 for ( sal_Int32 i = 0, nLen = aAbsCharStyleProps.getLength() ; i < nLen; i++ )
627 aStyleProps.push_back( aAbsCharStyleProps[i] );
630 //create (or find) a character style containing the character
631 // attributes of the symbol and apply it to the numbering level
632 OUString sStyle = rDMapper.getOrCreateCharStyle( aStyleProps );
633 aLvlProps.realloc( aLvlProps.getLength() + 1);
634 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 1].Name = aPropNameSupplier.GetName( PROP_CHAR_STYLE_NAME );
635 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 1].Value <<= sStyle;
638 // Get the prefix / suffix / Parent numbering
639 // and add them to the level properties
640 OUString sText = pAbsLevel->GetBulletChar( );
641 if ( pLevel.get( ) )
642 sText = pLevel->GetBulletChar( );
644 OUString sPrefix;
645 OUString sSuffix;
646 OUString& rPrefix = sPrefix;
647 OUString& rSuffix = sSuffix;
648 sal_Int16 nParentNum = ListLevel::GetParentNumbering(
649 sText, nLevel, rPrefix, rSuffix );
651 aLvlProps.realloc( aLvlProps.getLength( ) + 4 );
652 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 4] = MAKE_PROPVAL( PROP_PREFIX, rPrefix );
653 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 3] = MAKE_PROPVAL( PROP_SUFFIX, rSuffix );
654 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 2] = MAKE_PROPVAL( PROP_PARENT_NUMBERING, nParentNum );
656 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 1] = MAKE_PROPVAL( PROP_POSITION_AND_SPACE_MODE,
657 sal_Int16( text::PositionAndSpaceMode::LABEL_ALIGNMENT ) );
659 StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( );
660 if( pParaStyle.get())
662 aLvlProps.realloc( aLvlProps.getLength() + 1 );
663 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 1] = MAKE_PROPVAL( PROP_PARAGRAPH_STYLE_NAME,
664 pParaStyle->sConvertedStyleName );
667 // Replace the numbering rules for the level
668 m_xNumRules->replaceByIndex( nLevel, uno::makeAny( aLvlProps ) );
670 // Handle the outline level here
671 if ( pAbsLevel->isOutlineNumbering())
673 uno::Reference< text::XChapterNumberingSupplier > xOutlines (
674 xFactory, uno::UNO_QUERY_THROW );
675 uno::Reference< container::XIndexReplace > xOutlineRules =
676 xOutlines->getChapterNumberingRules( );
678 aLvlProps.realloc( aLvlProps.getLength() + 1 );
679 aLvlProps[sal::static_int_cast<sal_uInt32>(aLvlProps.getLength()) - 1] = MAKE_PROPVAL( PROP_HEADING_STYLE_NAME,
680 pParaStyle->sConvertedStyleName );
682 xOutlineRules->replaceByIndex( nLevel, uno::makeAny( aLvlProps ) );
685 nLevel++;
688 // Create the numbering style for these rules
689 OUString sNumRulesName = aPropNameSupplier.GetName( PROP_NUMBERING_RULES );
690 xStyle->setPropertyValue( sNumRulesName, uno::makeAny( m_xNumRules ) );
692 catch( const lang::IllegalArgumentException& e )
694 SAL_WARN( "writerfilter", "Exception: " << e.Message );
695 assert( !"Incorrect argument to UNO call" );
697 catch( const uno::RuntimeException& e )
699 SAL_WARN( "writerfilter", "Exception: " << e.Message );
700 assert( !"Incorrect argument to UNO call" );
702 catch( const uno::Exception& e )
704 SAL_WARN( "writerfilter", "Exception: " << e.Message );
710 //------------------------------------- NumberingManager implementation
713 ListsManager::ListsManager(DomainMapper& rDMapper,
714 const uno::Reference< lang::XMultiServiceFactory > xFactory) :
715 LoggedProperties(dmapper_logger, "ListsManager"),
716 LoggedTable(dmapper_logger, "ListsManager"),
717 m_rDMapper( rDMapper ),
718 m_xFactory( xFactory )
722 ListsManager::~ListsManager( )
726 void ListsManager::lcl_attribute( Id nName, Value& rVal )
728 ListLevel::Pointer pCurrentLvl;
730 if (nName != NS_ooxml::LN_CT_NumPicBullet_numPicBulletId)
732 OSL_ENSURE( m_pCurrentDefinition.get(), "current entry has to be set here");
733 if(!m_pCurrentDefinition.get())
734 return ;
735 pCurrentLvl = m_pCurrentDefinition->GetCurrentLevel( );
737 else
739 SAL_WARN_IF(!m_pCurrentNumPicBullet.get(), "writerfilter", "current entry has to be set here");
740 if (!m_pCurrentNumPicBullet.get())
741 return;
743 int nIntValue = rVal.getInt();
747 switch(nName)
749 case NS_rtf::LN_RGBXCHNUMS:
750 if(pCurrentLvl.get())
751 pCurrentLvl->AddRGBXchNums( rVal.getString( ) );
752 break;
753 case NS_ooxml::LN_CT_LevelText_val:
755 //this strings contains the definition of the level
756 //the level number is marked as %n
757 //these numbers can be mixed randomly toghether with separators pre- and suffixes
758 //the Writer supports only a number of upper levels to show, separators is always a dot
759 //and each level can have a prefix and a suffix
760 if(pCurrentLvl.get())
761 pCurrentLvl->SetBulletChar( rVal.getString() );
763 break;
764 case NS_rtf::LN_ISTARTAT:
765 case NS_rtf::LN_NFC:
766 case NS_rtf::LN_JC:
767 case NS_rtf::LN_FLEGAL:
768 case NS_rtf::LN_FNORESTART:
769 case NS_rtf::LN_FIDENTSAV:
770 case NS_rtf::LN_FCONVERTED:
771 case NS_rtf::LN_IXCHFOLLOW:
772 if ( pCurrentLvl.get( ) )
773 pCurrentLvl->SetValue( nName, sal_Int32( nIntValue ) );
774 break;
775 case NS_rtf::LN_RGISTD:
776 m_pCurrentDefinition->AddRGISTD( rVal.getString() );
777 break;
778 case NS_ooxml::LN_CT_Num_numId:
779 m_pCurrentDefinition->SetId( rVal.getString().toInt32( ) );
780 break;
781 case NS_rtf::LN_LSID:
782 m_pCurrentDefinition->SetId( nIntValue );
783 break;
784 case NS_rtf::LN_TPLC:
785 case NS_rtf::LN_FSIMPLELIST:
786 case NS_rtf::LN_fAutoNum:
787 case NS_rtf::LN_fHybrid:
788 m_pCurrentDefinition->SetValue( nName, nIntValue );
789 break;
790 case NS_ooxml::LN_CT_NumLvl_ilvl:
791 case NS_rtf::LN_LISTLEVEL:
793 //add a new level to the level vector and make it the current one
794 m_pCurrentDefinition->AddLevel();
796 writerfilter::Reference<Properties>::Pointer_t pProperties;
797 if((pProperties = rVal.getProperties()).get())
798 pProperties->resolve(*this);
800 break;
801 case NS_ooxml::LN_CT_AbstractNum_abstractNumId:
803 // This one corresponds to the AbstractNum Id definition
804 // The reference to the abstract num is in the sprm method
805 sal_Int32 nVal = rVal.getString().toInt32();
806 m_pCurrentDefinition->SetId( nVal );
808 break;
809 case NS_ooxml::LN_CT_Ind_left:
810 pCurrentLvl->Insert(
811 PROP_INDENT_AT, true, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
812 break;
813 case NS_ooxml::LN_CT_Ind_hanging:
814 pCurrentLvl->Insert(
815 PROP_FIRST_LINE_INDENT, true, uno::makeAny( - ConversionHelper::convertTwipToMM100( nIntValue ) ));
816 break;
817 case NS_ooxml::LN_CT_Ind_firstLine:
818 pCurrentLvl->Insert(
819 PROP_FIRST_LINE_INDENT, true, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
820 break;
821 case NS_ooxml::LN_CT_Lvl_ilvl: //overrides previous level - unsupported
822 case NS_ooxml::LN_CT_Lvl_tplc: //template code - unsupported
823 case NS_ooxml::LN_CT_Lvl_tentative: //marks level as unused in the document - unsupported
824 break;
825 case NS_ooxml::LN_CT_TabStop_pos:
827 //no paragraph attributes in ListTable char style sheets
828 if ( pCurrentLvl.get( ) )
829 pCurrentLvl->SetValue( nName,
830 ConversionHelper::convertTwipToMM100( nIntValue ) );
832 break;
833 case NS_ooxml::LN_CT_TabStop_val:
835 // TODO Do something of that
837 break;
838 case NS_ooxml::LN_CT_NumPicBullet_numPicBulletId:
839 m_pCurrentNumPicBullet->SetId(rVal.getString().toInt32());
840 break;
841 default:
843 #if OSL_DEBUG_LEVEL > 0
844 OString sMessage( "ListTable::attribute() - Id: ");
845 sMessage += OString::valueOf( sal_Int32( nName ), 10 );
846 sMessage += " / 0x";
847 sMessage += OString::valueOf( sal_Int32( nName ), 16 );
848 sMessage += " value: ";
849 sMessage += OString::valueOf( sal_Int32( nIntValue ), 10 );
850 sMessage += " / 0x";
851 sMessage += OString::valueOf( sal_Int32( nIntValue ), 16 );
852 SAL_WARN("writerfilter", sMessage.getStr());
853 #endif
858 void ListsManager::lcl_sprm( Sprm& rSprm )
860 //fill the attributes of the style sheet
861 sal_uInt32 nSprmId = rSprm.getId();
862 if( m_pCurrentDefinition.get() ||
863 nSprmId == NS_ooxml::LN_CT_Numbering_abstractNum ||
864 nSprmId == NS_ooxml::LN_CT_Numbering_num ||
865 (nSprmId == NS_ooxml::LN_CT_NumPicBullet_pict && m_pCurrentNumPicBullet.get()) ||
866 nSprmId == NS_ooxml::LN_CT_Numbering_numPicBullet)
868 sal_Int32 nIntValue = rSprm.getValue()->getInt();
869 switch( nSprmId )
871 case NS_ooxml::LN_CT_Numbering_abstractNum:
873 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
874 if(pProperties.get())
876 //create a new Abstract list entry
877 OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
878 m_pCurrentDefinition.reset( new AbstractListDef );
879 pProperties->resolve( *this );
880 //append it to the table
881 m_aAbstractLists.push_back( m_pCurrentDefinition );
882 m_pCurrentDefinition = AbstractListDef::Pointer();
885 break;
886 case NS_ooxml::LN_CT_Numbering_num:
888 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
889 if(pProperties.get())
891 // Create a new list entry
892 OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
893 ListDef::Pointer listDef( new ListDef );
894 m_pCurrentDefinition = listDef;
895 pProperties->resolve( *this );
896 //append it to the table
897 m_aLists.push_back( listDef );
899 m_pCurrentDefinition = AbstractListDef::Pointer();
902 break;
903 case NS_ooxml::LN_CT_Numbering_numPicBullet:
905 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
906 if (pProperties.get())
908 NumPicBullet::Pointer numPicBullet(new NumPicBullet());
909 m_pCurrentNumPicBullet = numPicBullet;
910 pProperties->resolve(*this);
911 m_aNumPicBullets.push_back(numPicBullet);
912 m_pCurrentNumPicBullet = NumPicBullet::Pointer();
915 break;
916 case NS_ooxml::LN_CT_NumPicBullet_pict:
918 uno::Reference<drawing::XShape> xShape = m_rDMapper.PopPendingShape();
919 m_pCurrentNumPicBullet->SetShape(xShape);
921 break;
922 case NS_ooxml::LN_CT_Lvl_lvlPicBulletId:
924 uno::Reference<drawing::XShape> xShape;
925 for (std::vector<NumPicBullet::Pointer>::iterator it = m_aNumPicBullets.begin(); it != m_aNumPicBullets.end(); ++it)
927 if ((*it)->GetId() == nIntValue)
929 xShape = (*it)->GetShape();
930 break;
933 if (xShape.is())
935 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
936 uno::Reference<beans::XPropertySetInfo> info = xPropertySet->getPropertySetInfo();
937 uno::Sequence<beans::Property> properties = info->getProperties();
940 uno::Any aAny = xPropertySet->getPropertyValue("GraphicURL");
941 if (aAny.has<OUString>())
942 m_pCurrentDefinition->GetCurrentLevel()->SetGraphicURL(aAny.get<OUString>());
943 } catch(const beans::UnknownPropertyException&)
947 uno::Reference< graphic::XGraphic > gr;
948 xPropertySet->getPropertyValue("Bitmap") >>= gr;
949 m_pCurrentDefinition->GetCurrentLevel()->SetGraphicBitmap( gr );
950 } catch(const beans::UnknownPropertyException&)
953 // Now that we saved the URL of the graphic, remove it from the document.
954 uno::Reference<lang::XComponent> xShapeComponent(xShape, uno::UNO_QUERY);
955 xShapeComponent->dispose();
958 break;
959 case NS_ooxml::LN_CT_Num_abstractNumId:
961 sal_Int32 nAbstractNumId = rSprm.getValue()->getInt();
962 ListDef* pListDef = dynamic_cast< ListDef* >( m_pCurrentDefinition.get( ) );
963 if ( pListDef != NULL )
965 // The current def should be a ListDef
966 pListDef->SetAbstractDefinition(
967 GetAbstractList( nAbstractNumId ) );
970 break;
971 case NS_ooxml::LN_CT_AbstractNum_multiLevelType:
972 break;
973 case NS_rtf::LN_TPLC:
974 m_pCurrentDefinition->SetValue( nSprmId, nIntValue );
975 break;
976 case NS_ooxml::LN_CT_AbstractNum_lvl:
978 m_pCurrentDefinition->AddLevel();
979 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
980 if(pProperties.get())
981 pProperties->resolve(*this);
983 break;
984 case NS_rtf::LN_RGBXCHNUMS: break;
985 case NS_rtf::LN_ISTARTAT:
986 case NS_rtf::LN_NFC:
987 case NS_rtf::LN_JC:
988 case NS_rtf::LN_FLEGAL:
989 case NS_rtf::LN_FNORESTART:
990 case NS_rtf::LN_FIDENTSAV:
991 case NS_rtf::LN_FCONVERTED:
992 case NS_rtf::LN_IXCHFOLLOW:
993 if (m_pCurrentDefinition->GetCurrentLevel().get())
994 m_pCurrentDefinition->GetCurrentLevel( )->SetValue( nSprmId, nIntValue );
995 break;
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;
1007 else
1008 SAL_WARN( "writerfilter", "Unknown ST_LevelSuffix value "
1009 << rSprm.getValue()->getString());
1010 m_pCurrentDefinition->GetCurrentLevel()->SetValue( nSprmId, value );
1013 break;
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);
1021 break;
1022 case NS_ooxml::LN_CT_NumLvl_lvl:
1024 // overwrite level
1025 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1026 if(pProperties.get())
1027 pProperties->resolve(*this);
1029 break;
1030 case NS_ooxml::LN_CT_Lvl_lvlJc:
1032 static sal_Int16 aWWAlignments[ ] =
1034 text::HoriOrientation::LEFT,
1035 text::HoriOrientation::CENTER,
1036 text::HoriOrientation::RIGHT
1038 m_pCurrentDefinition->GetCurrentLevel( )->Insert(
1039 PROP_ADJUST, true, uno::makeAny( aWWAlignments[ nIntValue ] ) );
1040 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1042 break;
1043 case NS_ooxml::LN_CT_Lvl_pPr:
1044 case NS_ooxml::LN_CT_PPrBase_ind:
1046 //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
1047 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1048 if(pProperties.get())
1049 pProperties->resolve(*this);
1051 break;
1052 case NS_ooxml::LN_CT_PPrBase_tabs:
1053 case NS_ooxml::LN_CT_Tabs_tab:
1055 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1056 if(pProperties.get())
1057 pProperties->resolve(*this);
1059 break;
1060 case NS_ooxml::LN_CT_Lvl_pStyle:
1062 OUString sStyleName = rSprm.getValue( )->getString( );
1063 ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel( );
1064 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
1065 const StyleSheetEntryPtr pStyle = pStylesTable->FindStyleSheetByISTD( sStyleName );
1066 pLevel->SetParaStyle( pStyle );
1068 break;
1069 case NS_ooxml::LN_CT_Num_lvlOverride:
1071 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1072 if (pProperties.get())
1073 pProperties->resolve(*this);
1075 break;
1076 case NS_ooxml::LN_CT_AbstractNum_numStyleLink:
1078 OUString sStyleName = rSprm.getValue( )->getString( );
1079 AbstractListDef* pAbstractListDef = dynamic_cast< AbstractListDef* >( m_pCurrentDefinition.get( ) );
1080 pAbstractListDef->SetNumStyleLink(sStyleName);
1082 break;
1083 case NS_ooxml::LN_EG_RPrBase_rFonts: //contains font properties
1084 case NS_ooxml::LN_EG_RPrBase_color:
1085 case NS_ooxml::LN_EG_RPrBase_u:
1086 case NS_sprm::LN_CHps: // sprmCHps
1087 case NS_ooxml::LN_EG_RPrBase_lang:
1088 case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
1089 //no break!
1090 default:
1091 if( m_pCurrentDefinition->GetCurrentLevel( ).get())
1093 m_rDMapper.PushListProperties( m_pCurrentDefinition->GetCurrentLevel( ) );
1094 m_rDMapper.sprm( rSprm );
1095 m_rDMapper.PopListProperties();
1101 void ListsManager::lcl_entry( int /* pos */,
1102 writerfilter::Reference<Properties>::Pointer_t ref )
1104 if( m_rDMapper.IsOOXMLImport() || m_rDMapper.IsRTFImport() )
1106 ref->resolve(*this);
1108 else
1110 if ( m_bIsLFOImport )
1112 // Create ListDef's
1113 OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
1114 ListDef::Pointer pList( new ListDef() );
1115 m_pCurrentDefinition = pList;
1116 ref->resolve(*this);
1117 //append it to the table
1118 m_aLists.push_back( pList );
1119 m_pCurrentDefinition = AbstractListDef::Pointer();
1121 else
1123 // Create AbstractListDef's
1124 OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
1125 m_pCurrentDefinition.reset( new AbstractListDef( ) );
1126 ref->resolve(*this);
1127 //append it to the table
1128 m_aAbstractLists.push_back( m_pCurrentDefinition );
1129 m_pCurrentDefinition = AbstractListDef::Pointer();
1134 AbstractListDef::Pointer ListsManager::GetAbstractList( sal_Int32 nId )
1136 AbstractListDef::Pointer pAbstractList;
1138 int nLen = m_aAbstractLists.size( );
1139 int i = 0;
1140 while ( !pAbstractList.get( ) && i < nLen )
1142 if ( m_aAbstractLists[i]->GetId( ) == nId )
1144 if ( m_aAbstractLists[i]->GetNumStyleLink().getLength() > 0 )
1146 // If the abstract num has a style linked, check the linked style's number id.
1147 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
1149 const StyleSheetEntryPtr pStyleSheetEntry =
1150 pStylesTable->FindStyleSheetByISTD( m_aAbstractLists[i]->GetNumStyleLink() );
1152 const StyleSheetPropertyMap* pStyleSheetProperties =
1153 dynamic_cast<const StyleSheetPropertyMap*>(pStyleSheetEntry ? pStyleSheetEntry->pProperties.get() : 0);
1155 if( pStyleSheetProperties && pStyleSheetProperties->GetNumId() >= 0 )
1157 ListDef::Pointer pList = GetList( pStyleSheetProperties->GetNumId() );
1158 if ( pList!=NULL )
1159 return pList->GetAbstractDefinition();
1160 else
1161 pAbstractList = m_aAbstractLists[i];
1165 else
1167 pAbstractList = m_aAbstractLists[i];
1170 i++;
1173 return pAbstractList;
1176 ListDef::Pointer ListsManager::GetList( sal_Int32 nId )
1178 ListDef::Pointer pList;
1180 int nLen = m_aLists.size( );
1181 int i = 0;
1182 while ( !pList.get( ) && i < nLen )
1184 if ( m_aLists[i]->GetId( ) == nId )
1185 pList = m_aLists[i];
1186 i++;
1189 return pList;
1192 void ListsManager::CreateNumberingRules( )
1194 // Loop over the definitions
1195 std::vector< ListDef::Pointer >::iterator listIt = m_aLists.begin( );
1196 for ( ; listIt != m_aLists.end( ); ++listIt )
1198 (*listIt)->CreateNumberingRules( m_rDMapper, m_xFactory );
1204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */