1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #include "ConversionHelper.hxx"
24 #include "NumberingManager.hxx"
25 #include "StyleSheetTable.hxx"
26 #include "PropertyIds.hxx"
27 
28 #include <doctok/resourceids.hxx>
29 #include <doctok/sprmids.hxx>
30 #include <ooxml/resourceids.hxx>
31 
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/container/XNameContainer.hpp>
34 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
35 #include <com/sun/star/style/NumberingType.hpp>
36 #include <com/sun/star/text/HoriOrientation.hpp>
37 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
38 #include <com/sun/star/text/XChapterNumberingSupplier.hpp>
39 
40 #if DEBUG
41 #include <stdio.h>
42 #endif
43 
44 #include "dmapperLoggers.hxx"
45 
46 using namespace rtl;
47 using namespace com::sun::star;
48 
49 #define MAKE_PROPVAL(NameId, Value) \
50     beans::PropertyValue(aPropNameSupplier.GetName(NameId), 0, uno::makeAny(Value), beans::PropertyState_DIRECT_VALUE )
51 
52 #define OUSTR_TO_C( x )  OUStringToOString( x, RTL_TEXTENCODING_UTF8 ).getStr( )
53 
54 #define NUMBERING_MAX_LEVELS    10
55 
56 
57 namespace writerfilter {
58 namespace dmapper {
59 
60 //---------------------------------------------------  Utility functions
61 
lcl_printProperties(uno::Sequence<beans::PropertyValue> aProps)62 void lcl_printProperties( uno::Sequence< beans::PropertyValue > aProps )
63 {
64     sal_Int32 nLen = aProps.getLength( );
65     for ( sal_Int32 i = 0; i < nLen; i++ )
66     {
67         uno::Any aValue = aProps[i].Value;
68         sal_Int32 nValue = 0;
69         OUString sValue;
70 
71         if ( !( aValue >>= sValue ) && ( aValue >>= nValue ) )
72             sValue = OUString::valueOf( nValue );
73 
74 #if DEBUG
75         fprintf( stderr, "Property %s: %s\n",
76                 OUSTR_TO_C( aProps[i].Name ),
77                 OUSTR_TO_C( sValue ) );
78 #endif
79     }
80 }
81 
lcl_findProperty(uno::Sequence<beans::PropertyValue> aProps,OUString sName)82 sal_Int32 lcl_findProperty( uno::Sequence< beans::PropertyValue > aProps, OUString sName )
83 {
84     sal_Int32 i = 0;
85     sal_Int32 nLen = aProps.getLength( );
86     sal_Int32 nPos = -1;
87 
88     while ( nPos == -1 && i < nLen )
89     {
90         if ( aProps[i].Name.equals( sName ) )
91             nPos = i;
92         else
93             i++;
94     }
95 
96     return nPos;
97 }
98 
lcl_mergeProperties(uno::Sequence<beans::PropertyValue> & aSrc,uno::Sequence<beans::PropertyValue> & aDst)99 void lcl_mergeProperties( uno::Sequence< beans::PropertyValue >& aSrc,
100         uno::Sequence< beans::PropertyValue >& aDst )
101 {
102     for ( sal_Int32 i = 0, nSrcLen = aSrc.getLength( ); i < nSrcLen; i++ )
103     {
104         // Look for the same property in aDst
105         sal_Int32 nPos = lcl_findProperty( aDst, aSrc[i].Name );
106         if ( nPos >= 0 )
107         {
108             // Replace the property value by the one in aSrc
109             aDst[nPos] = aSrc[i];
110         }
111         else
112         {
113             // Simply add the new value
114             aDst.realloc( aDst.getLength( ) + 1 );
115             aDst[ aDst.getLength( ) - 1 ] = aSrc[i];
116         }
117     }
118 }
119 
120 //--------------------------------------------  ListLevel implementation
SetValue(Id nId,sal_Int32 nValue)121 void ListLevel::SetValue( Id nId, sal_Int32 nValue )
122 {
123     switch( nId )
124     {
125         case NS_rtf::LN_ISTARTAT:
126             m_nIStartAt = nValue;
127         break;
128         case NS_rtf::LN_NFC:
129             m_nNFC = nValue;
130         break;
131         case NS_rtf::LN_JC:
132             m_nJC = nValue;
133         break;
134         case NS_rtf::LN_FLEGAL:
135             m_nFLegal = nValue;
136         break;
137         case NS_rtf::LN_FNORESTART:
138             m_nFNoRestart = nValue;
139         break;
140         case NS_rtf::LN_FIDENTSAV:
141             m_nFPrev = nValue;
142         break;
143         case NS_rtf::LN_FCONVERTED:
144             m_nFPrevSpace = nValue;
145         break;
146 #if 0
147         case NS_rtf::LN_FWORD6:
148             m_nFWord6 = nValue;
149         break;
150 #endif
151         case NS_rtf::LN_IXCHFOLLOW:
152             m_nXChFollow = nValue;
153   break;
154         case NS_ooxml::LN_CT_TabStop_pos:
155             m_nTabstop = nValue;
156         break;
157         default:
158             OSL_ENSURE( false, "this line should never be reached");
159     }
160 }
161 
GetParentNumbering(OUString sText,sal_Int16 nLevel,OUString & rPrefix,OUString & rSuffix)162 sal_Int16 ListLevel::GetParentNumbering( OUString sText, sal_Int16 nLevel,
163         OUString& rPrefix, OUString& rSuffix )
164 {
165     sal_Int16 nParentNumbering = nLevel;
166 
167     //now parse the text to find %n from %1 to %nLevel+1
168     //everything before the first % and the last %x is prefix and suffix
169     OUString sLevelText( sText );
170     sal_Int32 nCurrentIndex = 0;
171     sal_Int32 nFound = sLevelText.indexOf( '%', nCurrentIndex );
172     if( nFound > 0 )
173     {
174         rPrefix = sLevelText.copy( 0, nFound );
175         sLevelText = sLevelText.copy( nFound );
176     }
177     sal_Int32 nMinLevel = nLevel;
178     //now the text should either be empty or start with %
179     nFound = sLevelText.getLength( ) > 1 ? 0 : -1;
180     while( nFound >= 0 )
181     {
182         if( sLevelText.getLength() > 1 )
183         {
184             sal_Unicode cLevel = sLevelText.getStr()[1];
185             if( cLevel >= '1' && cLevel <= '9' )
186             {
187                 if( cLevel - '1' < nMinLevel )
188                     nMinLevel = cLevel - '1';
189                 //remove first char - next char is removed later
190                 sLevelText = sLevelText.copy( 1 );
191             }
192         }
193         //remove old '%' or number
194         sLevelText = sLevelText.copy( 1 );
195         nCurrentIndex = 0;
196         nFound = sLevelText.indexOf( '%', nCurrentIndex );
197         //remove the text before the next %
198         if(nFound > 0)
199             sLevelText = sLevelText.copy( nFound -1 );
200     }
201     if( nMinLevel < nLevel )
202     {
203         nParentNumbering = sal_Int16( nLevel - nMinLevel + 1);
204     }
205 
206     rSuffix = sLevelText;
207 
208     return nParentNumbering;
209 }
210 
GetProperties()211 uno::Sequence< beans::PropertyValue > ListLevel::GetProperties( )
212 {
213     uno::Sequence< beans::PropertyValue > aLevelProps = GetLevelProperties( );
214     if ( m_pParaStyle.get( ) )
215     {
216         // Merge with the paragraph properties
217         uno::Sequence< beans::PropertyValue > aParaProps = GetParaProperties( );
218         lcl_mergeProperties( aParaProps, aLevelProps );
219     }
220     return aLevelProps;
221 }
222 
GetCharStyleProperties()223 uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( )
224 {
225     PropertyValueVector_t rProperties;
226     PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
227 
228     _PropertyMap::const_iterator aMapIter = begin();
229     _PropertyMap::const_iterator aEndIter = end();
230     for( ; aMapIter != aEndIter; ++aMapIter )
231     {
232         switch( aMapIter->first.eId )
233         {
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:
243             {
244                 rProperties.push_back(
245                         beans::PropertyValue(
246                             aPropNameSupplier.GetName( aMapIter->first.eId ), 0,
247                             aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
248             }
249         }
250     }
251 
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)
257     {
258         pValues[nIndex] = *aIt;
259     }
260     return aRet;
261 }
262 
GetLevelProperties()263 uno::Sequence< beans::PropertyValue > ListLevel::GetLevelProperties( )
264 {
265     const sal_Int16 aWWToUnoAdjust[] =
266     {
267         text::HoriOrientation::LEFT,
268         text::HoriOrientation::CENTER,
269         text::HoriOrientation::RIGHT,
270     };
271 
272     PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
273     PropertyValueVector_t aNumberingProperties;
274 
275     if( m_nIStartAt >= 0)
276         aNumberingProperties.push_back( MAKE_PROPVAL(PROP_START_WITH, (sal_Int16)m_nIStartAt) );
277 
278     sal_Int16 nNumberFormat = ConversionHelper::ConvertNumberingType(m_nNFC);
279     if( m_nNFC >= 0)
280         aNumberingProperties.push_back( MAKE_PROPVAL(PROP_NUMBERING_TYPE, nNumberFormat ));
281 
282     if( m_nJC >= 0 && m_nJC <= sal::static_int_cast<sal_Int32>(sizeof(aWWToUnoAdjust) / sizeof(sal_Int16)) )
283         aNumberingProperties.push_back( MAKE_PROPVAL(PROP_ADJUST, aWWToUnoAdjust[m_nJC]));
284 
285     // todo: this is not the bullet char
286     if( nNumberFormat == style::NumberingType::CHAR_SPECIAL && m_sBulletChar.getLength() )
287         aNumberingProperties.push_back( MAKE_PROPVAL(PROP_BULLET_CHAR, m_sBulletChar.copy(0,1)));
288 
289     aNumberingProperties.push_back( MAKE_PROPVAL( PROP_LISTTAB_STOP_POSITION, m_nTabstop ) );
290 
291     //TODO: handling of nFLegal?
292     //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
293     //1.
294     //1.1
295     //2.2
296     //2.3
297     //3.4
298     //
299 
300     if( m_nFWord6 > 0) //Word 6 compatibility
301     {
302         if( m_nFPrev == 1)
303             aNumberingProperties.push_back( MAKE_PROPVAL( PROP_PARENT_NUMBERING, (sal_Int16) NUMBERING_MAX_LEVELS ));
304         //TODO: prefixing space     nFPrevSpace;     - has not been used in WW8 filter
305     }
306 
307 //    TODO: sRGBXchNums;     array of inherited numbers
308 
309 //    TODO: nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
310 
311     _PropertyMap::const_iterator aMapIter = begin();
312     _PropertyMap::const_iterator aEndIter = end();
313     for( ; aMapIter != aEndIter; ++aMapIter )
314     {
315         switch( aMapIter->first.eId )
316         {
317             case PROP_ADJUST:
318             case PROP_INDENT_AT:
319             case PROP_FIRST_LINE_INDENT:
320             case PROP_FIRST_LINE_OFFSET:
321             case PROP_LEFT_MARGIN:
322                 aNumberingProperties.push_back(
323                     beans::PropertyValue( aPropNameSupplier.GetName( aMapIter->first.eId ), 0, aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
324             break;
325             case PROP_CHAR_FONT_NAME:
326                 aNumberingProperties.push_back(
327                     beans::PropertyValue( aPropNameSupplier.GetName( PROP_BULLET_FONT_NAME ), 0, aMapIter->second, beans::PropertyState_DIRECT_VALUE ));
328             break;
329             default:
330             {
331                 // Handled in GetCharStyleProperties method
332             }
333 
334         }
335     }
336 
337     uno::Sequence< beans::PropertyValue > aRet(aNumberingProperties.size());
338     beans::PropertyValue* pValues = aRet.getArray();
339     PropertyValueVector_t::const_iterator aIt = aNumberingProperties.begin();
340     PropertyValueVector_t::const_iterator aEndIt = aNumberingProperties.end();
341     for(sal_uInt32 nIndex = 0; aIt != aEndIt; ++aIt,++nIndex)
342     {
343         pValues[nIndex] = *aIt;
344     }
345     return aRet;
346 }
347 
GetParaProperties()348 uno::Sequence< beans::PropertyValue > ListLevel::GetParaProperties( )
349 {
350     PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
351 
352     uno::Sequence< beans::PropertyValue > aParaProps = m_pParaStyle->pProperties->GetPropertyValues( );
353     uno::Sequence< beans::PropertyValue > aProps;
354 
355     // ParaFirstLineIndent -> FirstLineIndent
356     // ParaLeftMargin -> IndentAt
357 
358     OUString sParaIndent = aPropNameSupplier.GetName(
359             PROP_PARA_FIRST_LINE_INDENT );
360     OUString sFirstLineIndent = aPropNameSupplier.GetName(
361             PROP_FIRST_LINE_INDENT );
362     OUString sParaLeftMargin = aPropNameSupplier.GetName(
363             PROP_PARA_LEFT_MARGIN );
364     OUString sIndentAt = aPropNameSupplier.GetName(
365             PROP_INDENT_AT );
366 
367     sal_Int32 nLen = aParaProps.getLength( );
368     for ( sal_Int32 i = 0; i < nLen; i++ )
369     {
370         if ( aParaProps[i].Name.equals( sParaIndent ) )
371         {
372             aProps.realloc( aProps.getLength() + 1 );
373             aProps[aProps.getLength( ) - 1] = aParaProps[i];
374             aProps[aProps.getLength( ) - 1].Name = sFirstLineIndent;
375         }
376         else if ( aParaProps[i].Name.equals( sParaLeftMargin ) )
377         {
378             aProps.realloc( aProps.getLength() + 1 );
379             aProps[aProps.getLength( ) - 1] = aParaProps[i];
380             aProps[aProps.getLength( ) - 1].Name = sIndentAt;
381         }
382 
383     }
384 
385     return aProps;
386 }
387 
388 //--------------------------------------- AbstractListDef implementation
389 
AbstractListDef()390 AbstractListDef::AbstractListDef( ) :
391     m_nTPLC( -1 )
392     ,m_nSimpleList( -1 )
393     ,m_nRestart( -1 )
394     ,m_nUnsigned( -1 )
395     ,m_nId( -1 )
396 {
397 }
398 
~AbstractListDef()399 AbstractListDef::~AbstractListDef( )
400 {
401 }
402 
SetValue(sal_uInt32 nSprmId,sal_Int32 nValue)403 void AbstractListDef::SetValue( sal_uInt32 nSprmId, sal_Int32 nValue )
404 {
405     switch( nSprmId )
406     {
407         case NS_rtf::LN_TPLC:
408             m_nTPLC = nValue;
409         break;
410         case NS_rtf::LN_FSIMPLELIST:
411             m_nSimpleList = nValue;
412         break;
413         case NS_rtf::LN_fAutoNum:
414             m_nRestart = nValue;
415         break;
416         case NS_rtf::LN_fHybrid:
417             m_nUnsigned = nValue;
418         break;
419         default:
420             OSL_ENSURE( false, "this line should never be reached");
421     }
422 }
423 
GetLevel(sal_uInt16 nLvl)424 ListLevel::Pointer AbstractListDef::GetLevel( sal_uInt16 nLvl )
425 {
426     ListLevel::Pointer pLevel;
427     if ( m_aLevels.size( ) > nLvl )
428         pLevel = m_aLevels[ nLvl ];
429     return pLevel;
430 }
431 
AddLevel()432 void AbstractListDef::AddLevel( )
433 {
434     ListLevel::Pointer pLevel( new ListLevel );
435     m_pCurrentLevel = pLevel;
436     m_aLevels.push_back( pLevel );
437 }
438 
GetPropertyValues()439 uno::Sequence< uno::Sequence< beans::PropertyValue > > AbstractListDef::GetPropertyValues( )
440 {
441     uno::Sequence< uno::Sequence< beans::PropertyValue > > result( sal_Int32( m_aLevels.size( ) ) );
442     uno::Sequence< beans::PropertyValue >* aResult = result.getArray( );
443 
444     int nLevels = m_aLevels.size( );
445     for ( int i = 0; i < nLevels; i++ )
446     {
447         aResult[i] = m_aLevels[i]->GetProperties( );
448     }
449 
450     return result;
451 }
452 
453 //----------------------------------------------  ListDef implementation
454 
ListDef()455 ListDef::ListDef( ) : AbstractListDef( )
456 {
457 }
458 
~ListDef()459 ListDef::~ListDef( )
460 {
461 }
462 
GetStyleName(sal_Int32 nId)463 OUString ListDef::GetStyleName( sal_Int32 nId )
464 {
465     OUString sStyleName( OUString::createFromAscii( "WWNum" ) );
466     sStyleName += OUString::valueOf( nId );
467 
468     return sStyleName;
469 }
470 
GetPropertyValues()471 uno::Sequence< uno::Sequence< beans::PropertyValue > > ListDef::GetPropertyValues( )
472 {
473     // [1] Call the same method on the abstract list
474     uno::Sequence< uno::Sequence< beans::PropertyValue > > aAbstract = m_pAbstractDef->GetPropertyValues( );
475 
476     // [2] Call the upper class method
477     uno::Sequence< uno::Sequence< beans::PropertyValue > > aThis = AbstractListDef::GetPropertyValues( );
478 
479     // Merge the results of [2] in [1]
480     sal_Int32 nThisCount = aThis.getLength( );
481     for ( sal_Int32 i = 0; i < nThisCount; i++ )
482     {
483         uno::Sequence< beans::PropertyValue > level = aThis[i];
484         if ( level.getLength( ) == 0 )
485         {
486             // If the the element contains something, merge it
487             lcl_mergeProperties( level, aAbstract[i] );
488         }
489     }
490 
491     return aAbstract;
492 }
493 
lcl_getUnoNumberingStyles(uno::Reference<lang::XMultiServiceFactory> xFactory)494 uno::Reference< container::XNameContainer > lcl_getUnoNumberingStyles(
495        uno::Reference< lang::XMultiServiceFactory > xFactory )
496 {
497     uno::Reference< container::XNameContainer > xStyles;
498 
499     try
500     {
501         uno::Reference< style::XStyleFamiliesSupplier > xFamilies( xFactory, uno::UNO_QUERY_THROW );
502         uno::Any oFamily = xFamilies->getStyleFamilies( )->getByName( OUString::createFromAscii( "NumberingStyles" ) );
503 
504         oFamily >>= xStyles;
505     }
506     catch ( const uno::Exception )
507     {
508     }
509 
510     return xStyles;
511 }
512 
CreateNumberingRules(DomainMapper & rDMapper,uno::Reference<lang::XMultiServiceFactory> xFactory)513 void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
514         uno::Reference< lang::XMultiServiceFactory> xFactory )
515 {
516     // Get the UNO Numbering styles
517     uno::Reference< container::XNameContainer > xStyles = lcl_getUnoNumberingStyles( xFactory );
518 
519     // Do the whole thing
520     if( !m_xNumRules.is() && xFactory.is() && xStyles.is( ) )
521     {
522         try
523         {
524             // Create the numbering style
525             uno::Reference< beans::XPropertySet > xStyle (
526                 xFactory->createInstance(
527                     OUString::createFromAscii("com.sun.star.style.NumberingStyle")),
528                 uno::UNO_QUERY_THROW );
529 
530             rtl::OUString sStyleName = GetStyleName( GetId( ) );
531 
532             xStyles->insertByName( sStyleName, makeAny( xStyle ) );
533 
534             uno::Any oStyle = xStyles->getByName( sStyleName );
535             xStyle.set( oStyle, uno::UNO_QUERY_THROW );
536 
537             PropertyNameSupplier& aPropNameSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
538 
539             // Get the default OOo Numbering style rules
540             uno::Any aRules = xStyle->getPropertyValue( aPropNameSupplier.GetName( PROP_NUMBERING_RULES ) );
541             aRules >>= m_xNumRules;
542 
543             uno::Sequence< uno::Sequence< beans::PropertyValue > > aProps = GetPropertyValues( );
544 
545             sal_Int32 nAbstLevels = m_pAbstractDef->Size( );
546             sal_Int16 nLevel = 0;
547             while ( nLevel < nAbstLevels )
548             {
549                 ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel( nLevel );
550                 ListLevel::Pointer pLevel = GetLevel( nLevel );
551 
552                 // Get the merged level properties
553                 uno::Sequence< beans::PropertyValue > aLvlProps = aProps[sal_Int32( nLevel )];
554 
555                 lcl_printProperties( aLvlProps );
556 
557                 // Get the char style
558                 uno::Sequence< beans::PropertyValue > aAbsCharStyleProps = pAbsLevel->GetCharStyleProperties( );
559                 uno::Sequence< beans::PropertyValue >& rAbsCharStyleProps = aAbsCharStyleProps;
560                 if ( pLevel.get( ) )
561                 {
562                     uno::Sequence< beans::PropertyValue > aCharStyleProps =
563                         pLevel->GetCharStyleProperties( );
564                     uno::Sequence< beans::PropertyValue >& rCharStyleProps = aCharStyleProps;
565                     lcl_mergeProperties( rAbsCharStyleProps, rCharStyleProps );
566                 }
567 
568                 if( aAbsCharStyleProps.getLength() )
569                 {
570                     // Change the sequence into a vector
571                     PropertyValueVector_t aStyleProps;
572                     for ( sal_Int32 i = 0, nLen = aAbsCharStyleProps.getLength() ; i < nLen; i++ )
573                     {
574                         aStyleProps.push_back( aAbsCharStyleProps[i] );
575                     }
576 
577                     //create (or find) a character style containing the character
578                     // attributes of the symbol and apply it to the numbering level
579                     OUString sStyle = rDMapper.getOrCreateCharStyle( aStyleProps );
580                     aLvlProps.realloc( aLvlProps.getLength() + 1);
581                     aLvlProps[aLvlProps.getLength() - 1].Name = aPropNameSupplier.GetName( PROP_CHAR_STYLE_NAME );
582                     aLvlProps[aLvlProps.getLength() - 1].Value <<= sStyle;
583                 }
584 
585                 // Get the prefix / suffix / Parent numbering
586                 // and add them to the level properties
587                 OUString sText = pAbsLevel->GetBulletChar( );
588                 if ( pLevel.get( ) )
589                     sText = pLevel->GetBulletChar( );
590 
591                 OUString sPrefix;
592                 OUString sSuffix;
593                 OUString& rPrefix = sPrefix;
594                 OUString& rSuffix = sSuffix;
595                 sal_Int16 nParentNum = ListLevel::GetParentNumbering(
596                        sText, nLevel, rPrefix, rSuffix );
597 
598                 aLvlProps.realloc( aLvlProps.getLength( ) + 4 );
599                 aLvlProps[ aLvlProps.getLength( ) - 4 ] = MAKE_PROPVAL( PROP_PREFIX, rPrefix );
600                 aLvlProps[ aLvlProps.getLength( ) - 3 ] = MAKE_PROPVAL( PROP_SUFFIX, rSuffix );
601                 aLvlProps[ aLvlProps.getLength( ) - 2 ] = MAKE_PROPVAL( PROP_PARENT_NUMBERING, nParentNum );
602 
603                 aLvlProps[ aLvlProps.getLength( ) - 1 ] = MAKE_PROPVAL( PROP_POSITION_AND_SPACE_MODE,
604                             sal_Int16( text::PositionAndSpaceMode::LABEL_ALIGNMENT ) );
605                 // Replace the numbering rules for the level
606                 m_xNumRules->replaceByIndex( nLevel, uno::makeAny( aLvlProps ) );
607 
608                 // Handle the outline level here
609                 StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( );
610                 if ( pParaStyle.get( ) )
611                 {
612                     uno::Reference< text::XChapterNumberingSupplier > xOutlines (
613                         xFactory, uno::UNO_QUERY_THROW );
614                     uno::Reference< container::XIndexReplace > xOutlineRules =
615                         xOutlines->getChapterNumberingRules( );
616 
617                     aLvlProps.realloc( aLvlProps.getLength() + 1 );
618                     aLvlProps[aLvlProps.getLength( ) - 1] = MAKE_PROPVAL( PROP_HEADING_STYLE_NAME, pParaStyle->sConvertedStyleName );
619 
620                     xOutlineRules->replaceByIndex( nLevel, uno::makeAny( aLvlProps ) );
621                 }
622 
623                 nLevel++;
624             }
625 
626             // Create the numbering style for these rules
627             OUString sNumRulesName = aPropNameSupplier.GetName( PROP_NUMBERING_RULES );
628             xStyle->setPropertyValue( sNumRulesName, uno::makeAny( m_xNumRules ) );
629         }
630         catch( const uno::Exception& rEx)
631         {
632             OSL_ENSURE( false, "ListTable::CreateNumberingRules");
633         }
634     }
635 
636 }
637 
638 //-------------------------------------  NumberingManager implementation
639 
640 
ListsManager(DomainMapper & rDMapper,const uno::Reference<lang::XMultiServiceFactory> xFactory)641 ListsManager::ListsManager(DomainMapper& rDMapper,
642                            const uno::Reference< lang::XMultiServiceFactory > xFactory) :
643 LoggedProperties(dmapper_logger, "ListsManager"),
644 LoggedTable(dmapper_logger, "ListsManager"),
645 m_rDMapper( rDMapper ),
646 m_xFactory( xFactory )
647 {
648 }
649 
~ListsManager()650 ListsManager::~ListsManager( )
651 {
652 }
653 
lcl_attribute(Id nName,Value & rVal)654 void ListsManager::lcl_attribute( Id nName, Value& rVal )
655 {
656     OSL_ENSURE( m_pCurrentDefinition.get(), "current entry has to be set here");
657     if(!m_pCurrentDefinition.get())
658         return ;
659     int nIntValue = rVal.getInt();
660 
661     ListLevel::Pointer pCurrentLvl = m_pCurrentDefinition->GetCurrentLevel( );
662 
663 
664     /* WRITERFILTERSTATUS: table: ListTable_attributedata */
665     switch(nName)
666     {
667         /* WRITERFILTERSTATUS: done: 50, planned: 0, spent: 0 */
668         case NS_rtf::LN_RGBXCHNUMS:
669             if(pCurrentLvl.get())
670                 pCurrentLvl->AddRGBXchNums( rVal.getString( ) );
671         break;
672         /* WRITERFILTERSTATUS: done: 0, planned: 0, spent: 0 */
673         case NS_ooxml::LN_CT_LevelText_val:
674         {
675             //this strings contains the definition of the level
676             //the level number is marked as %n
677             //these numbers can be mixed randomly toghether with seperators pre- and suffixes
678             //the Writer supports only a number of upper levels to show, separators is always a dot
679             //and each level can have a prefix and a suffix
680             if(pCurrentLvl.get())
681                 pCurrentLvl->SetBulletChar( rVal.getString() );
682         }
683         break;
684 //        case NS_rtf::LN_ISTD: break;
685         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
686         case NS_rtf::LN_ISTARTAT:
687         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
688         case NS_rtf::LN_NFC:
689         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
690         case NS_rtf::LN_JC:
691         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
692         case NS_rtf::LN_FLEGAL:
693         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
694         case NS_rtf::LN_FNORESTART:
695         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
696         case NS_rtf::LN_FIDENTSAV:
697         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
698         case NS_rtf::LN_FCONVERTED:
699 #if 0
700         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
701         case NS_rtf::LN_FWORD6:
702 #endif
703         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
704         case NS_rtf::LN_IXCHFOLLOW:
705             if ( pCurrentLvl.get( ) )
706                 pCurrentLvl->SetValue( nName, sal_Int32( nIntValue ) );
707         break;
708         /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
709         case NS_rtf::LN_RGISTD:
710             m_pCurrentDefinition->AddRGISTD( rVal.getString() );
711         break;
712         case NS_ooxml::LN_CT_Num_numId:
713             m_pCurrentDefinition->SetId( rVal.getString().toInt32( ) );
714         break;
715         case NS_rtf::LN_LSID:
716             m_pCurrentDefinition->SetId( nIntValue );
717         break;
718         case NS_rtf::LN_TPLC:
719         case NS_rtf::LN_FSIMPLELIST:
720         case NS_rtf::LN_fAutoNum:
721         case NS_rtf::LN_fHybrid:
722             m_pCurrentDefinition->SetValue( nName, nIntValue );
723         break;
724         case NS_ooxml::LN_CT_NumLvl_ilvl:
725         case NS_rtf::LN_LISTLEVEL:
726         {
727             //add a new level to the level vector and make it the current one
728             m_pCurrentDefinition->AddLevel();
729 
730             writerfilter::Reference<Properties>::Pointer_t pProperties;
731             if((pProperties = rVal.getProperties()).get())
732                 pProperties->resolve(*this);
733         }
734         break;
735         /* WRITERFILTERSTATUS: done: 100, planned: 0, spent: 0 */
736         case NS_ooxml::LN_CT_AbstractNum_abstractNumId:
737         {
738             // This one corresponds to the AbstractNum Id definition
739             // The reference to the abstract num is in the sprm method
740             sal_Int32 nVal = rVal.getString().toInt32();
741             m_pCurrentDefinition->SetId( nVal );
742         }
743         break;
744         case NS_ooxml::LN_CT_Ind_left:
745             /* WRITERFILTERSTATUS: done: 100, planned: 0.5, spent: 0 */
746             pCurrentLvl->Insert(
747                 PROP_INDENT_AT, true, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
748             break;
749         case NS_ooxml::LN_CT_Ind_hanging:
750             /* WRITERFILTERSTATUS: done: 100, planned: 0.5, spent: 0 */
751             pCurrentLvl->Insert(
752                 PROP_FIRST_LINE_INDENT, true, uno::makeAny( - ConversionHelper::convertTwipToMM100( nIntValue ) ));
753         break;
754         case NS_ooxml::LN_CT_Ind_firstLine:
755             /* WRITERFILTERSTATUS: done: 100, planned: 0.5, spent: 0 */
756             pCurrentLvl->Insert(
757                 PROP_FIRST_LINE_INDENT, true, uno::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) ));
758         break;
759         case NS_ooxml::LN_CT_Lvl_ilvl: //overrides previous level - unsupported
760         case NS_ooxml::LN_CT_Lvl_tplc: //template code - unsupported
761         case NS_ooxml::LN_CT_Lvl_tentative: //marks level as unused in the document - unsupported
762         break;
763         case NS_ooxml::LN_CT_TabStop_pos:
764         {
765             //no paragraph attributes in ListTable char style sheets
766             if ( pCurrentLvl.get( ) )
767                 pCurrentLvl->SetValue( nName,
768                     ConversionHelper::convertTwipToMM100( nIntValue ) );
769         }
770         break;
771         case NS_ooxml::LN_CT_TabStop_val:
772         {
773             // TODO Do something of that
774         }
775         break;
776         default:
777         {
778 #if OSL_DEBUG_LEVEL > 0
779             ::rtl::OString sMessage( "ListTable::attribute() - Id: ");
780             sMessage += ::rtl::OString::valueOf( sal_Int32( nName ), 10 );
781             sMessage += ::rtl::OString(" / 0x");
782             sMessage += ::rtl::OString::valueOf( sal_Int32( nName ), 16 );
783             sMessage += ::rtl::OString(" value: ");
784             sMessage += ::rtl::OString::valueOf( sal_Int32( nIntValue ), 10 );
785             sMessage += ::rtl::OString(" / 0x");
786             sMessage += ::rtl::OString::valueOf( sal_Int32( nIntValue ), 16 );
787             OSL_ENSURE( false, sMessage.getStr()); //
788 #endif
789         }
790     }
791 }
792 
lcl_sprm(Sprm & rSprm)793 void ListsManager::lcl_sprm( Sprm& rSprm )
794 {
795     //fill the attributes of the style sheet
796     sal_uInt32 nSprmId = rSprm.getId();
797     if( m_pCurrentDefinition.get() ||
798         nSprmId == NS_ooxml::LN_CT_Numbering_abstractNum ||
799         nSprmId == NS_ooxml::LN_CT_Numbering_num )
800     {
801         sal_Int32 nIntValue = rSprm.getValue()->getInt();
802         /* WRITERFILTERSTATUS: table: ListTable_sprm */
803         switch( nSprmId )
804         {
805             /* WRITERFILTERSTATUS: done: 100, planned: 0, spent: 0 */
806             case NS_ooxml::LN_CT_Numbering_abstractNum:
807             {
808                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
809                 if(pProperties.get())
810                 {
811                     //create a new Abstract list entry
812                     OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
813                     m_pCurrentDefinition.reset( new AbstractListDef );
814                     pProperties->resolve( *this );
815                     //append it to the table
816                     m_aAbstractLists.push_back( m_pCurrentDefinition );
817                     m_pCurrentDefinition = AbstractListDef::Pointer();
818                 }
819             }
820             break;
821             /* WRITERFILTERSTATUS: done: 50, planned: 0, spent: 0 */
822             case NS_ooxml::LN_CT_Numbering_num:
823             {
824                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
825                 if(pProperties.get())
826                 {
827                     // Create a new list entry
828                     OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
829                     ListDef::Pointer listDef( new ListDef );
830                     m_pCurrentDefinition = listDef;
831                     pProperties->resolve( *this );
832                     //append it to the table
833                     m_aLists.push_back( listDef );
834 
835                     m_pCurrentDefinition = AbstractListDef::Pointer();
836                 }
837             }
838             break;
839             case NS_ooxml::LN_CT_Num_abstractNumId:
840             {
841                 sal_Int32 nAbstractNumId = rSprm.getValue()->getInt();
842                 ListDef* pListDef = dynamic_cast< ListDef* >( m_pCurrentDefinition.get( ) );
843                 if ( pListDef != NULL )
844                 {
845                     // The current def should be a ListDef
846                     pListDef->SetAbstractDefinition(
847                            GetAbstractList( nAbstractNumId ) );
848                 }
849             }
850             break;
851             /* WRITERFILTERSTATUS: done: 0, planned: 0, spent: 0 */
852             case NS_ooxml::LN_CT_AbstractNum_multiLevelType:
853             break;
854             /* WRITERFILTERSTATUS: done: 50, planned: 0, spent: 0 */
855             case NS_rtf::LN_TPLC:
856                 m_pCurrentDefinition->SetValue( nSprmId, nIntValue );
857             break;
858             /* WRITERFILTERSTATUS: done: 100, planned: 0, spent: 0 */
859             case NS_ooxml::LN_CT_AbstractNum_lvl:
860             {
861                 m_pCurrentDefinition->AddLevel();
862                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
863                 if(pProperties.get())
864                     pProperties->resolve(*this);
865                 }
866             break;
867             /* WRITERFILTERSTATUS: done: 0, planned: 0, spent: 0 */
868             case NS_rtf::LN_RGBXCHNUMS: break;
869             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
870             case NS_rtf::LN_ISTARTAT:
871             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
872             case NS_rtf::LN_NFC:
873             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
874             case NS_rtf::LN_JC:
875             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
876             case NS_rtf::LN_FLEGAL:
877             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
878             case NS_rtf::LN_FNORESTART:
879             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
880             case NS_rtf::LN_FIDENTSAV:
881             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
882             case NS_rtf::LN_FCONVERTED:
883 #if 0
884             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
885             case NS_rtf::LN_FWORD6:
886 #endif
887             /* WRITERFILTERSTATUS: done: 75, planned: 0, spent: 0 */
888             case NS_rtf::LN_IXCHFOLLOW:
889                 m_pCurrentDefinition->GetCurrentLevel( )->SetValue( nSprmId, nIntValue );
890             break;
891             case NS_ooxml::LN_CT_Lvl_lvlText:
892             case NS_ooxml::LN_CT_Lvl_rPr : //contains LN_EG_RPrBase_rFonts
893             {
894                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
895                 if(pProperties.get())
896                     pProperties->resolve(*this);
897             }
898             break;
899             case NS_ooxml::LN_CT_NumLvl_lvl:
900             {
901                 // overwrite level
902                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
903                 if(pProperties.get())
904                     pProperties->resolve(*this);
905             }
906             break;
907             case NS_ooxml::LN_CT_Lvl_lvlJc:
908             {
909                 static sal_Int16 aWWAlignments[ ] =
910                 {
911                     text::HoriOrientation::LEFT,
912                     text::HoriOrientation::CENTER,
913                     text::HoriOrientation::RIGHT
914                 };
915                 m_pCurrentDefinition->GetCurrentLevel( )->Insert(
916                     PROP_ADJUST, true, uno::makeAny( aWWAlignments[ nIntValue ] ) );
917                     writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
918             }
919             break;
920             case NS_ooxml::LN_CT_Lvl_pPr:
921             case NS_ooxml::LN_CT_PPrBase_ind:
922             {
923                 //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
924                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
925                 if(pProperties.get())
926                     pProperties->resolve(*this);
927             }
928             break;
929             case NS_ooxml::LN_CT_PPrBase_tabs:
930             case NS_ooxml::LN_CT_Tabs_tab:
931             {
932                 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
933                 if(pProperties.get())
934                     pProperties->resolve(*this);
935             }
936             break;
937             case NS_ooxml::LN_CT_Lvl_suff:
938                 //todo: currently unsupported suffix
939                 //can be: "none", "space", "tab"
940             break;
941             case NS_ooxml::LN_CT_Lvl_pStyle:
942             {
943                 OUString sStyleName = rSprm.getValue( )->getString( );
944                 ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel( );
945                 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
946                 const StyleSheetEntryPtr pStyle = pStylesTable->FindStyleSheetByISTD( sStyleName );
947                 pLevel->SetParaStyle( pStyle );
948             }
949             break;
950             case NS_ooxml::LN_CT_AbstractNum_numStyleLink:
951             {
952                 OUString sStyleName = rSprm.getValue( )->getString( );
953                 AbstractListDef* pAbstractListDef = dynamic_cast< AbstractListDef* >( m_pCurrentDefinition.get( ) );
954                 pAbstractListDef->SetNumStyleLink(sStyleName);
955             }
956             break;
957             case NS_ooxml::LN_EG_RPrBase_rFonts: //contains font properties
958             case NS_ooxml::LN_EG_RPrBase_color:
959             case NS_ooxml::LN_EG_RPrBase_u:
960             case NS_sprm::LN_CHps:    // sprmCHps
961             case NS_ooxml::LN_EG_RPrBase_lang:
962             case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
963                 //no break!
964             default:
965                 if( m_pCurrentDefinition->GetCurrentLevel( ).get())
966                 {
967                     m_rDMapper.PushListProperties( m_pCurrentDefinition->GetCurrentLevel( ) );
968                     m_rDMapper.sprm( rSprm );
969                     m_rDMapper.PopListProperties();
970                 }
971         }
972     }
973 }
974 
lcl_entry(int,writerfilter::Reference<Properties>::Pointer_t ref)975 void ListsManager::lcl_entry( int /* pos */,
976                           writerfilter::Reference<Properties>::Pointer_t ref )
977 {
978     if( m_rDMapper.IsOOXMLImport() )
979     {
980         ref->resolve(*this);
981     }
982     else
983     {
984         if ( m_bIsLFOImport )
985         {
986             // Create ListDef's
987             OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
988             ListDef::Pointer pList( new ListDef() );
989             m_pCurrentDefinition = pList;
990             ref->resolve(*this);
991             //append it to the table
992             m_aLists.push_back( pList );
993             m_pCurrentDefinition = AbstractListDef::Pointer();
994         }
995         else
996         {
997             // Create AbstractListDef's
998             OSL_ENSURE( !m_pCurrentDefinition.get(), "current entry has to be NULL here");
999             m_pCurrentDefinition.reset( new AbstractListDef( ) );
1000             ref->resolve(*this);
1001             //append it to the table
1002             m_aAbstractLists.push_back( m_pCurrentDefinition );
1003             m_pCurrentDefinition = AbstractListDef::Pointer();
1004         }
1005     }
1006 }
1007 
GetAbstractList(sal_Int32 nId)1008 AbstractListDef::Pointer ListsManager::GetAbstractList( sal_Int32 nId )
1009 {
1010     AbstractListDef::Pointer pAbstractList;
1011 
1012     int nLen = m_aAbstractLists.size( );
1013     int i = 0;
1014     while ( !pAbstractList.get( ) && i < nLen )
1015     {
1016         if ( m_aAbstractLists[i]->GetId( ) == nId )
1017         {
1018             if ( m_aAbstractLists[i]->GetNumStyleLink().getLength() > 0 )
1019             {
1020                 // If the abstract num has a style linked, check the linked style's number id.
1021                 StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
1022 
1023                 const StyleSheetEntryPtr pStyleSheetEntry =
1024                     pStylesTable->FindStyleSheetByISTD( m_aAbstractLists[i]->GetNumStyleLink() );
1025 
1026                 const StyleSheetPropertyMap* pStyleSheetProperties =
1027                     dynamic_cast<const StyleSheetPropertyMap*>(pStyleSheetEntry ? pStyleSheetEntry->pProperties.get() : 0);
1028 
1029                 if( pStyleSheetProperties && pStyleSheetProperties->GetNumId() >= 0 )
1030                 {
1031                     ListDef::Pointer pList = GetList( pStyleSheetProperties->GetNumId() );
1032                     if( bool(pList) )
1033                         return pList->GetAbstractDefinition();
1034                     else
1035                         pAbstractList = m_aAbstractLists[i];
1036                 }
1037 
1038             }
1039             else
1040             {
1041                 pAbstractList = m_aAbstractLists[i];
1042             }
1043         }
1044         i++;
1045     }
1046 
1047     return pAbstractList;
1048 }
1049 
GetList(sal_Int32 nId)1050 ListDef::Pointer ListsManager::GetList( sal_Int32 nId )
1051 {
1052     ListDef::Pointer pList;
1053 
1054     int nLen = m_aLists.size( );
1055     int i = 0;
1056     while ( !pList.get( ) && i < nLen )
1057     {
1058         if ( m_aLists[i]->GetId( ) == nId )
1059             pList = m_aLists[i];
1060         i++;
1061     }
1062 
1063     return pList;
1064 }
1065 
CreateNumberingRules()1066 void ListsManager::CreateNumberingRules( )
1067 {
1068     // Loop over the definitions
1069     std::vector< ListDef::Pointer >::iterator listIt = m_aLists.begin( );
1070     for ( ; listIt != m_aLists.end( ); listIt++ )
1071     {
1072         (*listIt)->CreateNumberingRules( m_rDMapper, m_xFactory );
1073     }
1074 }
1075 
1076 } }
1077