xref: /AOO41X/main/sw/source/filter/rtf/rtfnum.cxx (revision c43a074bcb3028e78ea20162afdadb1ff1448427)
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 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 #include <hintids.hxx>
27 #include <tools/stream.hxx>
28 #include <svtools/rtftoken.h>
29 #include <svtools/rtfkeywd.hxx>
30 #include <svl/intitem.hxx>
31 #include <svtools/rtfout.hxx>
32 #include <editeng/lrspitem.hxx>
33 #include <editeng/fontitem.hxx>
34 #include <editeng/fhgtitem.hxx>
35 #include <editeng/wghtitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/cmapitem.hxx>
38 #include <editeng/crsditem.hxx>
39 #include <editeng/colritem.hxx>
40 #include <editeng/udlnitem.hxx>
41 #include <editeng/wrlmitem.hxx>
42 #include <shellio.hxx>
43 #include <fltini.hxx>
44 #include <swtypes.hxx>
45 #include <swparrtf.hxx>
46 #include <ndtxt.hxx>
47 #include <doc.hxx>
48 #include <docary.hxx>
49 #include <pam.hxx>
50 #include <charfmt.hxx>
51 #include <charatr.hxx>
52 #include <paratr.hxx>
53 #ifndef _CMDID_H
54 #include <cmdid.h>
55 #endif
56 #include <numrule.hxx>
57 
58 #define RTF_NUMRULE_NAME "RTF_Num"
59 
lcl_GetStyleForNFC(sal_Int16 nNFC)60 static sal_Int16 lcl_GetStyleForNFC( sal_Int16 nNFC)
61 {
62     static const sal_Int16 aMap[] =
63     {
64     style::NumberingType::ARABIC,                   // 0 - Arabic (1, 2, 3)
65     style::NumberingType::ROMAN_UPPER,              // 1 - Uppercase Roman numeral (I, II, III)
66     style::NumberingType::ROMAN_LOWER,              // 2 - Lowercase Roman numeral (i, ii, iii)
67     style::NumberingType::CHARS_UPPER_LETTER_N,     // 3 - Uppercase letter (A, B, C)
68     style::NumberingType::CHARS_LOWER_LETTER_N,     // 4 - Lowercase letter (a, b, c)
69     style::NumberingType::ARABIC,                   // 5 - Ordinal number (1st, 2nd, 3rd)
70     style::NumberingType::ARABIC,                   // 6 - Cardinal text number (One, Two Three)
71     style::NumberingType::ARABIC,                   // 7 - Ordinal text number (First, Second, Third)
72     style::NumberingType::NUMBER_NONE,              // 8 - Not defined
73     style::NumberingType::NUMBER_NONE,              // 9 - Not defined
74     style::NumberingType::NUMBER_LOWER_ZH,          // 10 - Kanji numbering without the digit character (*dbnum1).
75     style::NumberingType::NUMBER_LOWER_ZH,          // 11 - Kanji numbering with the digit character (*dbnum2).
76     style::NumberingType::AIU_HALFWIDTH_JA,         // 12 - phonetic Katakana characters in "aiueo" order (*aiueo).
77     style::NumberingType::IROHA_HALFWIDTH_JA,       // 13 - phonetic katakana characters in "iroha" order (*iroha).
78     style::NumberingType::FULLWIDTH_ARABIC,         // 14 - Double Byte character
79     style::NumberingType::ARABIC,                   // 15 - Single Byte character
80     style::NumberingType::NUMBER_TRADITIONAL_JA,    // 16 - Kanji numbering 3 (*dbnum3).
81     style::NumberingType::ARABIC,                   // 17 - Kanji numbering 4 (*dbnum4).
82     style::NumberingType::ARABIC,                   // 18 - Circle numbering (*circlenum). - decimalEnclosedCircleChinese
83     style::NumberingType::FULLWIDTH_ARABIC,         // 19 - Double-byte Arabic numbering
84     style::NumberingType::AIU_FULLWIDTH_JA,         // 20 - phonetic double-byte Katakana characters (*aiueo*dbchar).
85     style::NumberingType::IROHA_FULLWIDTH_JA,       // 21 - phonetic double-byte katakana characters (*iroha*dbchar).
86     style::NumberingType::ARABIC,                   // 22 - Arabic with leading zero (01, 02, 03, ..., 10, 11)
87     style::NumberingType::CHAR_SPECIAL,             // 23 - Bullet (no number at all)
88     style::NumberingType::HANGUL_SYLLABLE_KO,       // 24 - Korean numbering 2 (*ganada).
89     style::NumberingType::HANGUL_JAMO_KO,           // 25 - Korean numbering 1 (*chosung).
90     style::NumberingType::ARABIC,                   // 26 - Chinese numbering 1 (*gb1). - decimalEnclosedFullstop
91     style::NumberingType::ARABIC,                   // 27 - Chinese numbering 2 (*gb2). - decimalEnclosedParen
92     style::NumberingType::ARABIC,                   // 28 - Chinese numbering 3 (*gb3). - decimalEnclosedCircleChinese
93     style::NumberingType::ARABIC,                   // 29 - Chinese numbering 4 (*gb4). - ideographEnclosedCircle
94     style::NumberingType::TIAN_GAN_ZH,              // 30 - Chinese Zodiac numbering 1 (* zodiac1)
95     style::NumberingType::DI_ZI_ZH,                 // 31 - Chinese Zodiac numbering 2 (* zodiac2)
96     style::NumberingType::ARABIC,                   // 32 - Chinese Zodiac numbering 3 (* zodiac3)
97     style::NumberingType::NUMBER_LOWER_ZH,          // 33 - Taiwanese double-byte numbering 1
98     style::NumberingType::NUMBER_UPPER_ZH_TW,       // 34 - Taiwanese double-byte numbering 2
99     style::NumberingType::NUMBER_LOWER_ZH,          // 35 - Taiwanese double-byte numbering 3
100     style::NumberingType::ARABIC,                   // 36 - Taiwanese double-byte numbering 4
101     style::NumberingType::NUMBER_LOWER_ZH,          // 37 - Chinese double-byte numbering 1
102     style::NumberingType::NUMBER_UPPER_ZH,          // 38 - Chinese double-byte numbering 2
103     style::NumberingType::NUMBER_LOWER_ZH,          // 39 - Chinese double-byte numbering 3
104     style::NumberingType::ARABIC,                   // 40 - Chinese double-byte numbering 4
105     style::NumberingType::NUMBER_HANGUL_KO,         // 41 - Korean double-byte numbering 1
106     style::NumberingType::NUMBER_HANGUL_KO,         // 42 - Korean double-byte numbering 2
107     style::NumberingType::NUMBER_HANGUL_KO,         // 43 - Korean double-byte numbering 3
108     style::NumberingType::NUMBER_LOWER_ZH,          // 44 - Korean double-byte numbering 4
109     style::NumberingType::CHARS_HEBREW,             // 45 - Hebrew non-standard decimal
110     style::NumberingType::CHARS_ARABIC,             // 46 - Arabic Alif Ba Tah
111     style::NumberingType::CHARS_HEBREW,             // 47 - Hebrew Biblical standard
112     style::NumberingType::ARABIC                    // 48 - Arabic Abjad style
113 
114     };
115     const int nLen = sizeof(aMap)/sizeof(aMap[0]);
116     sal_Int16 nRet = style::NumberingType::NUMBER_NONE;
117     if (nNFC>=0 && nNFC<nLen)
118         nRet = aMap[nNFC];
119     else if (nNFC==255)
120         nRet = style::NumberingType::CHAR_SPECIAL;
121     return nRet;
122 }
123 
lcl_ExpandNumFmts(SwNumRule & rRule)124 void lcl_ExpandNumFmts( SwNumRule& rRule )
125 {
126     // dann noch das NumFormat in alle Ebenen setzen
127     for( sal_uInt8 n = 1; n < MAXLEVEL; ++n )
128         if( !rRule.GetNumFmt( n ) )
129         {
130             SwNumFmt aNumFmt( rRule.Get( 0 ));
131             aNumFmt.SetAbsLSpace( aNumFmt.GetAbsLSpace() * ( n + 1 ) );
132             rRule.Set( n, aNumFmt );
133         }
134 }
135 
GetNumChrFmt(SwDoc & rDoc,SwNumRule & rRule,sal_uInt8 nNumLvl)136 SfxItemSet& GetNumChrFmt( SwDoc& rDoc, SwNumRule& rRule, sal_uInt8 nNumLvl )
137 {
138     SwCharFmt* pChrFmt = rRule.Get( nNumLvl ).GetCharFmt();
139     if( !pChrFmt )
140     {
141         String sNm( rRule.GetName() );
142         ( sNm += ' ' ) += String::CreateFromInt32( nNumLvl + 1 );
143         pChrFmt = rDoc.MakeCharFmt( sNm, rDoc.GetDfltCharFmt() );
144         if( !rRule.GetNumFmt( nNumLvl ))
145             rRule.Set( nNumLvl, rRule.Get( nNumLvl ) );
146         ((SwNumFmt*)rRule.GetNumFmt( nNumLvl ))->SetCharFmt( pChrFmt );
147     }
148     return (SfxItemSet&)pChrFmt->GetAttrSet();
149 }
150 
ReadListLevel(SwNumRule & rRule,sal_uInt8 nNumLvl)151 void SwRTFParser::ReadListLevel( SwNumRule& rRule, sal_uInt8 nNumLvl )
152 {
153     int nToken;
154     int nNumOpenBrakets = 1;        // die erste wurde schon vorher erkannt !!
155     int nLvlTxtLevel = 0, nLvlNumberLevel = 0;
156     String sLvlText, sLvlNumber;
157     SwNumFmt* pCurNumFmt;
158     String aStringFollow = aEmptyStr;
159 
160     if( MAXLEVEL >= nNumLvl )
161     {
162         pCurNumFmt = (SwNumFmt*)rRule.GetNumFmt( nNumLvl );
163         pCurNumFmt->SetAbsLSpace( 0 );
164         pCurNumFmt->SetFirstLineOffset( 0 );
165     }
166     else
167         pCurNumFmt = 0;
168 
169     while( nNumOpenBrakets && IsParserWorking() )
170     {
171         switch( ( nToken = GetNextToken() ))
172         {
173         case '}':
174             if( nNumOpenBrakets )
175             {
176                 if( nLvlTxtLevel == nNumOpenBrakets )
177                 {
178                     if( DelCharAtEnd( sLvlText, ';' ).Len() &&
179                         sLvlText.Len() && sLvlText.Len() ==
180                         (sal_uInt16)(sLvlText.GetChar( 0 )) + 1 )
181                         sLvlText.Erase( 0, 1 );
182                     nLvlTxtLevel = 0;
183                 }
184                 if( nLvlNumberLevel == nNumOpenBrakets )
185                 {
186                     DelCharAtEnd( sLvlNumber, ';' );
187                     nLvlNumberLevel = 0;
188                 }
189             }
190             --nNumOpenBrakets;
191             break;
192 
193         case '{':
194             {
195                 if( RTF_IGNOREFLAG != GetNextToken() )
196                     nToken = SkipToken( -1 );
197                 // Unknown und alle bekannten nicht ausgewerteten Gruppen
198                 // sofort ueberspringen
199                 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
200 //                      RTF_PANOSE != nToken && RTF_FALT != nToken &&
201 //                      RTF_FALT != nToken && RTF_FNAME != nToken &&
202 //                      RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
203                     nToken = SkipToken( -2 );
204                 else
205                 {
206                     // gleich herausfiltern
207                     ReadUnknownData();
208                     nToken = GetNextToken();
209                     if( '}' != nToken )
210                         eState = SVPAR_ERROR;
211                     break;
212                 }
213                 ++nNumOpenBrakets;
214             }
215             break;
216 
217         case RTF_LEVELNFC:
218             {
219                 sal_Int16 eType = lcl_GetStyleForNFC( nTokenValue ) ;
220 
221                 if( pCurNumFmt )
222                     pCurNumFmt->SetNumberingType(eType);
223             }
224             break;
225 
226         case RTF_LEVELJC:
227             {
228                 SvxAdjust eAdj = SVX_ADJUST_LEFT;
229                 switch( nTokenValue )
230                 {
231                 case 1:     eAdj = SVX_ADJUST_CENTER;   break;
232                 case 2:     eAdj = SVX_ADJUST_RIGHT;    break;
233                 }
234                 if( pCurNumFmt )
235                     pCurNumFmt->SetNumAdjust( eAdj );
236             }
237             break;
238 
239         case RTF_LEVELSTARTAT:
240             if( pCurNumFmt && -1 != nTokenValue )
241                 pCurNumFmt->SetStart( sal_uInt16( nTokenValue ));
242             break;
243 
244         case RTF_LEVELTEXT:
245             nLvlTxtLevel = nNumOpenBrakets;
246             break;
247 
248         case RTF_LEVELNUMBERS:
249             nLvlNumberLevel = nNumOpenBrakets;
250             break;
251 
252 
253         case RTF_TEXTTOKEN:
254             if( nLvlTxtLevel == nNumOpenBrakets )
255                 sLvlText += aToken;
256             else if( nLvlNumberLevel == nNumOpenBrakets )
257                 sLvlNumber += aToken;
258             break;
259 
260         case RTF_LEVELFOLLOW:
261           /* removed; waiting for swnum02 to be integrated!
262             switch (nTokenValue)
263             {
264             case 0:
265                 aStringFollow=String('\t');
266                 break;
267             case 1:
268                 aStringFollow=String(' ');
269                 break;
270             }
271             */
272             break;
273 
274         case RTF_LEVELOLD:
275         case RTF_LEVELPREV:
276         case RTF_LEVELPREVSPACE:
277         case RTF_LEVELINDENT:
278         case RTF_LEVELSPACE:
279         case RTF_LEVELLEGAL:
280         case RTF_LEVELNORESTART:
281             break;
282 
283         default:
284             if( pCurNumFmt && (
285                 RTF_CHRFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ||
286                 RTF_PARFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ))
287             {
288                 SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
289                 // put the current CharFmtAttr into the set
290                 SfxItemSet& rCFmtSet = GetNumChrFmt( *pDoc, rRule, nNumLvl );
291                 aSet.Put( rCFmtSet );
292                 // and put the current "LRSpace" into the set
293                 {
294                     SvxLRSpaceItem aLR( RES_LR_SPACE );
295                     aLR.SetTxtLeft( pCurNumFmt->GetAbsLSpace() );
296                     aLR.SetTxtFirstLineOfst(pCurNumFmt->GetFirstLineOffset());
297                     aSet.Put( aLR );
298                 }
299 
300                 ReadAttr( nToken, &aSet );
301 
302                 //#i24880# Word appears to ignore char background for numbering
303                 aSet.ClearItem(RES_CHRATR_BACKGROUND);
304 
305                 // put all CharFmt Items into the charfmt
306                 rCFmtSet.Put( aSet );
307 
308                 // test for LRSpace Item. If exist then set all relevant
309                 // values on the numrule format
310                 const SfxPoolItem* pItem;
311                 if( SFX_ITEM_SET == aSet.GetItemState( RES_LR_SPACE,
312                         sal_False, &pItem ))
313                 {
314                     const SvxLRSpaceItem& rLR = *(SvxLRSpaceItem*)pItem;
315                     pCurNumFmt->SetAbsLSpace( static_cast< short >(rLR.GetTxtLeft()) );
316                     pCurNumFmt->SetFirstLineOffset( rLR.GetTxtFirstLineOfst());
317                 }
318 
319                 // dann aus der Vorlage den Font holen
320                 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
321                     pCurNumFmt->SetBulletFont( FindFontOfItem(
322                                 pCurNumFmt->GetCharFmt()->GetFont() ) );
323             }
324             break;
325         }
326     }
327 
328     if( IsParserWorking() && pCurNumFmt )
329     {
330         // dann erzeuge mal die Pre/Postfix-Strings
331         if( sLvlText.Len() &&
332             SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
333         {
334             pCurNumFmt->SetBulletChar( sLvlText.GetChar( 0 ) );
335             // dann aus der Vorlage den Font holen
336             if( pCurNumFmt->GetCharFmt() )
337                 pCurNumFmt->SetBulletFont( FindFontOfItem(
338                         pCurNumFmt->GetCharFmt()->GetFont() ) );
339         }
340         else if( sLvlNumber.Len() && sLvlText.Len() )
341         {
342             // in sLvlText steht der Text, in sLvlNumber die Position
343             // der Ebenen in sLvlText
344             pCurNumFmt->SetPrefix(
345                 sLvlText.Copy( 0, sal_uInt16( sLvlNumber.GetChar( 0 ))-1 ));
346             pCurNumFmt->SetSuffix( sLvlText.Copy(
347                     sal_uInt16( sLvlNumber.GetChar( sLvlNumber.Len()-1 )) ));
348             // wieviele Levels stehen im String?
349             pCurNumFmt->SetIncludeUpperLevels( (sal_uInt8)sLvlNumber.Len() );
350         }
351         else
352         {
353             pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
354             pCurNumFmt->SetSuffix( sLvlText );
355         }
356 
357         String newSuffix=pCurNumFmt->GetSuffix();
358         newSuffix+=aStringFollow;
359         pCurNumFmt->SetSuffix(newSuffix);
360         /* removed; waiting for swnum02 to be integrated!
361         if (aStringFollow.GetChar(0)=='\t' && !pCurNumFmt->IsItemize())
362         {
363             pCurNumFmt->SetAbsLSpace(0);
364             pCurNumFmt->SetFirstLineOffset(0);
365         }
366         */
367     }
368 
369     SkipToken( -1 );
370 }
371 
ReadListTable()372 void SwRTFParser::ReadListTable()
373 {
374     int nToken;
375     int nNumOpenBrakets = 1;        // die erste wurde schon vorher erkannt !!
376     bNewNumList = sal_True;
377 
378     sal_uInt8 nNumLvl = 0;
379     SwNumRule* pCurRule = 0;
380     SwListEntry aEntry;
381 
382     while( nNumOpenBrakets && IsParserWorking() )
383     {
384         switch( ( nToken = GetNextToken() ))
385         {
386         case '}':       if( --nNumOpenBrakets && IsParserWorking() )
387                         {
388                             // Style konnte vollstaendig gelesen werden,
389                             // also ist das noch ein stabiler Status
390                             SaveState( RTF_LISTTABLE );
391                             if( 1 == nNumOpenBrakets )
392                             {
393                                 if( aEntry.nListId )
394                                     aListArr.push_back( aEntry );
395                                 aEntry.Clear();
396                             }
397                         }
398                         break;
399 
400         case '{':
401             {
402                 if( RTF_IGNOREFLAG != GetNextToken() )
403                     nToken = SkipToken( -1 );
404                 // Unknown und alle bekannten nicht ausgewerteten Gruppen
405                 // sofort ueberspringen
406                 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
407 //                      RTF_PANOSE != nToken && RTF_FALT != nToken &&
408 //                      RTF_FALT != nToken && RTF_FNAME != nToken &&
409 //                      RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
410                     nToken = SkipToken( -2 );
411                 else
412                 {
413                     // gleich herausfiltern
414                     ReadUnknownData();
415                     nToken = GetNextToken();
416                     if( '}' != nToken )
417                         eState = SVPAR_ERROR;
418                     break;
419                 }
420                 ++nNumOpenBrakets;
421             }
422             break;
423 
424         case RTF_LIST:
425             {
426                 if( pCurRule && pCurRule->IsContinusNum() )
427                     lcl_ExpandNumFmts( *pCurRule );
428 
429                 String sTmp( String::CreateFromAscii(
430                     RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
431                 aEntry.nListDocPos = pDoc->MakeNumRule( sTmp );
432                 pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
433                 // --> OD 2008-07-08 #i91400#
434                 pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ),
435                                    *pDoc );
436                 // <--
437                 pCurRule->SetAutoRule( sal_False );
438                 nNumLvl = (sal_uInt8)-1;
439             }
440             break;
441 
442         case RTF_LISTID:            aEntry.nListId = nTokenValue;       break;
443         case RTF_LISTTEMPLATEID:    aEntry.nListTemplateId = nTokenValue; break;
444 
445         case RTF_LISTRESTARTHDN:
446             break;
447         case RTF_LISTNAME:
448             if (nNextCh=='}') break;  // #118989# empty listnames
449             if( RTF_TEXTTOKEN == GetNextToken() )
450             {
451                 String sTmp( DelCharAtEnd( aToken, ';' ));
452                 if( sTmp.Len() && !pDoc->FindNumRulePtr( sTmp ))
453                 {
454                     // --> OD 2008-07-08 #i91400#
455                     pCurRule->SetName( sTmp, *pDoc );
456                     // <--
457                 }
458             }
459             SkipGroup();
460             break;
461 
462         case RTF_LISTSIMPLE:
463             pCurRule->SetContinusNum( sal_True );
464             break;
465 
466         case RTF_LISTLEVEL:
467             {
468                 if( ++nNumLvl < MAXLEVEL )
469                     pCurRule->Set( nNumLvl, pCurRule->Get( nNumLvl ));
470                 ReadListLevel( *pCurRule, nNumLvl );
471             }
472             break;
473         }
474     }
475 
476     if( pCurRule && pCurRule->IsContinusNum() )
477         lcl_ExpandNumFmts( *pCurRule );
478 
479     SkipToken( -1 );        // die schliesende Klammer wird "oben" ausgewertet
480 }
481 
lcl_IsEqual(SwNumRule * pOrigRule,SwNumRule * pRule)482 sal_Bool lcl_IsEqual( SwNumRule* pOrigRule, SwNumRule* pRule )
483 {
484     sal_Bool bRet = 0;
485     if( pOrigRule && pRule )
486     {
487         bRet =  pOrigRule->GetRuleType() == pRule->GetRuleType() &&
488                 pOrigRule->IsContinusNum() == pRule->IsContinusNum() &&
489                 pOrigRule->IsAbsSpaces() == pRule->IsAbsSpaces();
490         if( bRet )
491             for( sal_uInt8 n = 0; bRet && n < MAXLEVEL; ++n )
492             {
493                 const SwNumFmt* pOFmt = pOrigRule->GetNumFmt( n ),
494                               * pFmt = pRule->GetNumFmt( n );
495                 if( pFmt && pOFmt )
496                 {
497                     SwCharFmt* pOCFmt = pOFmt->GetCharFmt(),
498                              * pCFmt = pFmt->GetCharFmt();
499                     if( pOCFmt && pCFmt )
500                     {
501                         bRet = 0 != (pCFmt->GetAttrSet() == pOCFmt->GetAttrSet());
502                     }
503                     else
504                         bRet = !pCFmt && !pOCFmt;
505                     if( bRet )
506                     {
507                         ((SwNumFmt*)pOFmt)->SetCharFmt( 0 );
508                         ((SwNumFmt*)pFmt)->SetCharFmt( 0 );
509                         bRet = *pOFmt == *pFmt;
510                         ((SwNumFmt*)pOFmt)->SetCharFmt( pOCFmt );
511                         ((SwNumFmt*)pFmt)->SetCharFmt( pCFmt );
512                     }
513                 }
514                 else
515                     bRet = !pFmt && !pOFmt;
516             }
517     }
518     return bRet;
519 }
520 
ReadListOverrideTable()521 void SwRTFParser::ReadListOverrideTable()
522 {
523     int nToken;
524     int nNumOpenBrakets = 1;        // die erste wurde schon vorher erkannt !!
525     SwListEntry aEntry;
526     SwNumRule* pRule = 0, *pOrigRule = 0;
527     sal_uInt8 nNumLvl = 0;
528     sal_Bool bOverrideFormat = sal_False, bOverrideStart = sal_False;
529 
530     while( nNumOpenBrakets && IsParserWorking() )
531     {
532         switch( ( nToken = GetNextToken() ))
533         {
534         case '}':
535             if( --nNumOpenBrakets && IsParserWorking() )
536             {
537                 // Style konnte vollstaendig gelesen werden,
538                 // also ist das noch ein stabiler Status
539                 SaveState( RTF_LISTOVERRIDETABLE );
540 
541                 if( 1 == nNumOpenBrakets )
542                 {
543                     bOverrideFormat = sal_False, bOverrideStart = sal_False;
544                     if( pRule )
545                     {
546                         if( lcl_IsEqual( pOrigRule, pRule ))
547                         {
548                             // no changes on the rule -> use the original rule
549                             aEntry.nListDocPos = pDoc->FindNumRule(
550                                                     pOrigRule->GetName() );
551                             // delete the temp Rule
552                             RemoveUnusedNumRule( pRule );
553                         }
554                         else if( pRule->IsContinusNum() )
555                             lcl_ExpandNumFmts( *pRule );
556                     }
557 
558                     if( aEntry.nListId && aEntry.nListNo )
559                     {
560                         int nMatch=-1;
561                         for( size_t n = aListArr.size(); n; )
562                         {
563                             if( aListArr[ --n ].nListId == aEntry.nListId)
564                             {
565                                 nMatch=n;
566                                 break;
567                             }
568                         }
569                         if(nMatch>=0)
570                         {
571                             sal_uInt16 nMatch2 = static_cast< sal_uInt16 >(nMatch);
572                             if (!aListArr[nMatch2].nListNo )
573                             {
574                                 aListArr[nMatch2].nListNo = aEntry.nListNo;
575                             }
576                             else
577                             {
578                                 aEntry.nListDocPos=aListArr[nMatch2].nListDocPos;
579                                 aEntry.nListTemplateId=aListArr[nMatch2].nListTemplateId;
580                                 aListArr.push_back( aEntry );
581                             }
582                             if(pOrigRule)
583                                 aListArr[nMatch2].nListDocPos = aEntry.nListDocPos;
584                         }
585                     }
586                     aEntry.Clear();
587                     pOrigRule = 0;
588                     pRule = 0;
589                 }
590             }
591             break;
592 
593         case '{':
594             {
595                 if( RTF_IGNOREFLAG != GetNextToken() )
596                     nToken = SkipToken( -1 );
597                 // Unknown und alle bekannten nicht ausgewerteten Gruppen
598                 // sofort ueberspringen
599                 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
600                     nToken = SkipToken( -2 );
601                 else
602                 {
603                     // gleich herausfiltern
604                     ReadUnknownData();
605                     nToken = GetNextToken();
606                     if( '}' != nToken )
607                         eState = SVPAR_ERROR;
608                     break;
609                 }
610                 ++nNumOpenBrakets;
611             }
612             break;
613 
614         case RTF_LISTOVERRIDE:      aEntry.Clear();                 break;
615         case RTF_LISTID:            aEntry.nListId = nTokenValue;   break;
616         case RTF_LS:                aEntry.nListNo = nTokenValue;   break;
617         case RTF_LISTOVERRIDECOUNT:
618             if( nTokenValue )
619             {
620                 pRule = 0;
621                 // dann erzeugen wir mal schnell eine Kopie von der NumRule,
622                 // denn diese wird jetzt mal kurz veraendert.
623                 if( aEntry.nListId )
624                     for( size_t n = 0; n < aListArr.size(); ++n )
625                         if( aListArr[ n ].nListId == aEntry.nListId )
626                         {
627                             pRule = pDoc->GetNumRuleTbl()[
628                                                 aListArr[ n ].nListDocPos ];
629                             pOrigRule = pRule;
630 
631                             String sTmp( String::CreateFromAscii(
632                                 RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
633                             aEntry.nListDocPos = pDoc->MakeNumRule( sTmp, pRule );
634                             pRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
635                             // --> OD 2008-07-08 #i91400#
636                             pRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ),
637                                             *pDoc );
638                             // <--
639                             pRule->SetAutoRule( sal_False );
640                             nNumLvl = (sal_uInt8)-1;
641                             aListArr.push_back( aEntry );
642                             break;
643                         }
644 
645             }
646             break;
647 
648         case RTF_LISTLEVEL:
649             if( pRule && bOverrideFormat )
650             {
651                 if( ++nNumLvl < MAXLEVEL )
652                     pRule->Set( nNumLvl, pRule->Get( nNumLvl ));
653                 ReadListLevel( *pRule, nNumLvl );
654             }
655             break;
656 
657         case RTF_LEVELSTARTAT:
658             if( pRule && bOverrideStart )
659             {
660             }
661             break;
662 
663         case RTF_LISTOVERRIDESTART:
664             bOverrideStart = sal_True;
665             break;
666 
667         case RTF_LISTOVERRIDEFORMAT:
668             bOverrideFormat = sal_True;
669             break;
670 
671         case RTF_LFOLEVEL:
672             // was fehlt noch?
673             break;
674         }
675     }
676 
677     // search the outline numrule and set it into the doc
678     if( GetStyleTbl().Count() )
679     {
680         if( !bStyleTabValid )
681             MakeStyleTab();
682 
683         const SfxPoolItem* pItem( 0 );
684         const SwTxtFmtColl* pColl( 0 );
685         sal_uInt16 nRulePos( USHRT_MAX );
686         const SwNumRule *pNumRule = 0;
687         SvxRTFStyleType* pStyle = GetStyleTbl().First();
688         do {
689             // --> OD 2007-12-17 #151213#
690             // suppress deletion of outline list style.
691             // refactoring of code: no assignments in if-condition
692 //            if( MAXLEVEL > pStyle->nOutlineNo &&
693 //                0 != ( pColl = aTxtCollTbl.Get( (sal_uInt16)GetStyleTbl().
694 //                                                        GetCurKey() )) &&
695 //                SFX_ITEM_SET == pColl->GetItemState( RES_PARATR_NUMRULE,
696 //                                                    sal_False, &pItem ) &&
697 //                USHRT_MAX != (nRulePos = pDoc->FindNumRule(
698 //                                ((SwNumRuleItem*)pItem)->GetValue() )) &&
699 //                (pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ])->IsAutoRule() )
700             if ( MAXLEVEL > pStyle->nOutlineNo )
701             {
702                 pColl = aTxtCollTbl.Get( (sal_uInt16)GetStyleTbl().GetCurKey() );
703                 if ( pColl )
704                 {
705                     const SfxItemState eItemState =
706                         pColl->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem );
707                     if ( eItemState == SFX_ITEM_SET )
708                     {
709                         nRulePos = pDoc->FindNumRule( ((SwNumRuleItem*)pItem)->GetValue() );
710                         if ( nRulePos != USHRT_MAX )
711                         {
712                             pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ];
713                             if ( pNumRule->IsAutoRule() &&
714                                  pNumRule != pDoc->GetOutlineNumRule() )
715                             {
716                                 pDoc->SetOutlineNumRule( *pNumRule );
717                                 pDoc->DelNumRule( pNumRule->GetName() );
718                                 // now pNumRule pointer is invalid !!!
719 
720                                 // now decrement all position in the listtable, which will
721                                 // behind the doc-rule position
722                                 for( size_t n = aListArr.size(); n; )
723                                 {
724                                     SwListEntry& rEntry = aListArr[ --n ];
725                                     if( rEntry.nListDocPos == nRulePos )
726                                         aListArr.erase( aListArr.begin()+n );
727                                     else if( rEntry.nListDocPos > nRulePos )
728                                         --rEntry.nListDocPos;
729                                 }
730                                 break;
731                             }
732                         }
733                     }
734                 }
735             }
736             // <--
737 
738             pStyle->aAttrSet.ClearItem( FN_PARAM_NUM_LEVEL );
739 
740         } while( 0 != (pStyle = GetStyleTbl().Next()) );
741     }
742 
743     SkipToken( -1 );        // die schliesende Klammer wird "oben" ausgewertet
744 }
745 
GetNumRuleOfListNo(long nListNo,sal_Bool bRemoveFromList)746 SwNumRule* SwRTFParser::GetNumRuleOfListNo( long nListNo, sal_Bool bRemoveFromList )
747 {
748     SwNumRule* pRet = 0;
749     SwListEntry* pEntry;
750     for( size_t n = aListArr.size(); n; )
751         if( ( pEntry = &aListArr[ --n ])->nListNo == nListNo )
752         {
753             if( bRemoveFromList )
754                 aListArr.erase( aListArr.begin()+n );
755             else
756             {
757                 pEntry->bRuleUsed = sal_True;
758                 pRet = pDoc->GetNumRuleTbl()[ pEntry->nListDocPos ];
759             }
760             break;
761         }
762     return pRet;
763 }
764 
RemoveUnusedNumRule(SwNumRule * pRule)765 void SwRTFParser::RemoveUnusedNumRule( SwNumRule* pRule )
766 {
767     if( pRule )
768     {
769         for ( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
770         {
771             SwNumFmt& rNFmt = (SwNumFmt&)pRule->Get( nLvl );
772             SwCharFmt* pCFmt = rNFmt.GetCharFmt();
773             if( pCFmt )
774             {
775                 rNFmt.ForgetCharFmt();
776                 if( !pCFmt->GetDepends() )
777                     pDoc->DelCharFmt( pCFmt );
778             }
779         }
780         pDoc->DelNumRule( pRule->GetName() );
781     }
782 #ifdef DBG_UTIL
783     else
784     {
785         ASSERT( pRule, "NumRulePointer 0 kann nicht geloescht werden" );
786     }
787 #endif
788 }
789 
RemoveUnusedNumRules()790 void SwRTFParser::RemoveUnusedNumRules()
791 {
792     SwListEntry* pEntry;
793     SvPtrarr aDelArr;
794     size_t n;
795     for( n = aListArr.size(); n; )
796     {
797         if( !( pEntry = &aListArr[ --n ])->bRuleUsed )
798         {
799             // really *NOT* used by anyone else?
800             sal_Bool unused=sal_True;
801             for(size_t j = 0;  j < aListArr.size();  ++j)
802             {
803                 if (aListArr[n].nListNo==aListArr[j].nListNo)
804                     unused&=!aListArr[j].bRuleUsed;
805             }
806             if (unused)
807             {
808                 void * p = pDoc->GetNumRuleTbl()[pEntry->nListDocPos];
809                 // dont delete named char formats
810                 if( USHRT_MAX == aDelArr.GetPos( p ) &&
811                     ((SwNumRule*)p)->GetName().EqualsAscii( RTF_NUMRULE_NAME, 0,
812                                     sizeof( RTF_NUMRULE_NAME )) )
813                     aDelArr.Insert( p, aDelArr.Count() );
814             }
815         }
816     }
817 
818     for( n = aDelArr.Count(); n; )
819     {
820         SwNumRule* pDel = (SwNumRule*)aDelArr[ --n ];
821         RemoveUnusedNumRule( pDel );
822     }
823 }
824 
FindFontOfItem(const SvxFontItem & rItem) const825 const Font* SwRTFParser::FindFontOfItem( const SvxFontItem& rItem ) const
826 {
827     SvxRTFFontTbl& rFntTbl = ((SwRTFParser*)this)->GetFontTbl();
828     const Font* pFnt = rFntTbl.First();
829     while( pFnt )
830     {
831         if( pFnt->GetFamily() == rItem.GetFamily() &&
832             pFnt->GetName() == rItem.GetFamilyName() &&
833             pFnt->GetStyleName() == rItem.GetStyleName() &&
834             pFnt->GetPitch() == rItem.GetPitch() &&
835             pFnt->GetCharSet() == rItem.GetCharSet() )
836             return pFnt;
837 
838         pFnt = rFntTbl.Next();
839     }
840     return 0;
841 }
842 
843 
ReadNumSecLevel(int nToken)844 SwNumRule *SwRTFParser::ReadNumSecLevel( int nToken )
845 {
846     // lese die \pnseclvl - Gruppe
847     // nTokenValue gibt schon den richtigen Level vor 1 - 9!
848     sal_uInt8 nLevel = 0;
849     long nListNo = 0;
850     sal_Bool bContinus = sal_True;
851 
852     if( RTF_PNSECLVL == nToken )
853     {
854         // suche die Rule - steht unter Nummer 3
855         nListNo = 3;
856         bContinus = sal_False;
857         nLevel = MAXLEVEL <= (unsigned long) nTokenValue ? MAXLEVEL - 1
858             : (!nTokenValue ? 0 : sal_uInt8( nTokenValue - 1 ));
859     }
860     else
861     {
862         switch( nToken = GetNextToken() )
863         {
864         case RTF_PNLVL:         nListNo = 3;
865                                 bContinus = sal_False;
866                                 nLevel = MAXLEVEL <= (unsigned long) nTokenValue
867                                                     ? MAXLEVEL - 1
868                                     : (!nTokenValue ? 0 : sal_uInt8( nTokenValue-1 ));
869                                 break;
870 
871         case RTF_PNLVLBODY:
872             nListNo = 2;
873             break;
874         case RTF_PNLVLBLT:
875             nListNo = 1;
876             break;
877         case RTF_PNLVLCONT:
878             SkipGroup();
879             return 0;
880         default:
881             SkipGroup();
882             return 0;
883         }
884     }
885 
886     // suche die Rule - steht unter Nummer 3
887     sal_uInt16 nNewFlag = static_cast< sal_uInt16 >(1 << nListNo);
888     SwNumRule* pCurRule = GetNumRuleOfListNo( nListNo,
889                                         0 != ( nNewNumSectDef & nNewFlag ) );
890     if( !pCurRule )
891     {
892         // dann muessen wir die mal anlegen
893         nNewNumSectDef &= ~nNewFlag;
894         String sTmp( String::CreateFromAscii(
895                         RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
896         SwListEntry aEntry( nListNo, 0, pDoc->MakeNumRule( sTmp ));
897         aEntry.nListNo = nListNo;
898         aListArr.push_back( aEntry );
899         pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
900         // --> OD 2008-07-08 #i91400#
901         pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ), *pDoc );
902         // <--
903         pCurRule->SetAutoRule( sal_False );
904         pCurRule->SetContinusNum( bContinus );
905     }
906 
907     if( !pCurRule->GetNumFmt( nLevel ))
908         pCurRule->Set( nLevel, pCurRule->Get( nLevel ));
909     SwNumFmt* pCurNumFmt = (SwNumFmt*)pCurRule->GetNumFmt( nLevel );
910     if( RTF_PNLVLBLT == nToken )
911         pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
912     pCurNumFmt->SetSuffix( aEmptyStr );
913     pCurNumFmt->SetPrefix( aEmptyStr );
914     pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
915 
916     if( bStyleTabValid && RTF_PNSECLVL != nToken )
917     {
918         // dann den akt. Lvl und Rule am Absatz setzen.
919         // Dieses muss aber in den vorherigen "Kontext", sprich in den vor
920         // der Klammer offenen Attrset. Darum das SetNewGroup davor und dahinter
921         SetNewGroup( sal_False );
922         GetAttrSet().Put( SfxUInt16Item( FN_PARAM_NUM_LEVEL, nLevel ));
923         GetAttrSet().Put( SwNumRuleItem( pCurRule->GetName() ));
924         SetNewGroup( sal_True );
925     }
926 
927     FontUnderline eUnderline;
928     int nNumOpenBrakets = 1;        // die erste wurde schon vorher erkannt !!
929     while( nNumOpenBrakets && IsParserWorking() )
930     {
931         switch( ( nToken = GetNextToken() ))
932         {
933         case '}':
934             if( --nNumOpenBrakets && IsParserWorking() )
935             {
936                 // Style konnte vollstaendig gelesen werden,
937                 // also ist das noch ein stabiler Status
938                 SaveState( RTF_PNSECLVL );
939             }
940             break;
941 
942         case '{':
943             {
944                 if( RTF_IGNOREFLAG != GetNextToken() )
945                     nToken = SkipToken( -1 );
946                 // Unknown und alle bekannten nicht ausgewerteten Gruppen
947                 // sofort ueberspringen
948                 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
949                     nToken = SkipToken( -2 );
950                 else
951                 {
952                     // gleich herausfiltern
953                     ReadUnknownData();
954                     nToken = GetNextToken();
955                     if( '}' != nToken )
956                         eState = SVPAR_ERROR;
957                     break;
958                 }
959                 ++nNumOpenBrakets;
960             }
961             break;
962 
963         case RTF_PNCARD:
964         case RTF_PNORD:
965         case RTF_PNORDT:
966         case RTF_PNDEC:     pCurNumFmt->SetNumberingType(SVX_NUM_ARABIC);               break;
967         case RTF_PNUCLTR:   pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER_N); break;
968         case RTF_PNUCRM:    pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_UPPER);          break;
969         case RTF_PNLCLTR:   pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER_N); break;
970         case RTF_PNLCRM:    pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_LOWER);          break;
971 
972         case RTF_PNF:
973             {
974                 const Font& rSVFont = GetFont( sal_uInt16(nTokenValue) );
975                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
976                             SvxFontItem( rSVFont.GetFamily(),
977                                 rSVFont.GetName(), rSVFont.GetStyleName(),
978                                 rSVFont.GetPitch(), rSVFont.GetCharSet(),
979                                             RES_CHRATR_FONT ));
980                 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
981                     pCurNumFmt->SetBulletFont( &rSVFont );
982             }
983             break;
984         case RTF_PNFS:
985             {
986                 if( -1 == nTokenValue )
987                     nTokenValue = 240;
988                 else
989                     nTokenValue *= 10;
990                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
991                             SvxFontHeightItem( (const sal_uInt16)nTokenValue, 100, RES_CHRATR_FONTSIZE ));
992             }
993             break;
994 
995         case RTF_PNB:
996             {
997                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxWeightItem(
998                                 nTokenValue ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT ));
999             }
1000             break;
1001 
1002         case RTF_PNI:
1003             {
1004                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxPostureItem(
1005                             nTokenValue ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE ));
1006             }
1007             break;
1008 
1009         case RTF_PNCAPS:
1010         case RTF_PNSCAPS:
1011             {
1012                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCaseMapItem(
1013                                 nTokenValue ? SVX_CASEMAP_KAPITAELCHEN
1014                                             : SVX_CASEMAP_NOT_MAPPED, RES_CHRATR_CASEMAP ));
1015             }
1016             break;
1017         case RTF_PNSTRIKE:
1018             {
1019                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCrossedOutItem(
1020                         nTokenValue ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ));
1021             }
1022             break;
1023 
1024         case RTF_PNCF:
1025             {
1026                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxColorItem(
1027                             GetColor( sal_uInt16(nTokenValue) ), RES_CHRATR_COLOR ));
1028             }
1029             break;
1030 
1031 
1032         case RTF_PNUL:
1033             eUnderline = nTokenValue ? UNDERLINE_SINGLE : UNDERLINE_NONE;
1034             goto NUMATTR_SETUNDERLINE;
1035         case RTF_PNULD:
1036             eUnderline = UNDERLINE_DOTTED;
1037             goto NUMATTR_SETUNDERLINE;
1038         case RTF_PNULDB:
1039             eUnderline = UNDERLINE_DOUBLE;
1040             goto NUMATTR_SETUNDERLINE;
1041         case RTF_PNULNONE:
1042             eUnderline = UNDERLINE_NONE;
1043             goto NUMATTR_SETUNDERLINE;
1044         case RTF_PNULW:
1045             {
1046                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
1047                                     SvxWordLineModeItem( sal_True, RES_CHRATR_WORDLINEMODE ));
1048             }
1049             eUnderline = UNDERLINE_SINGLE;
1050             goto NUMATTR_SETUNDERLINE;
1051 
1052 NUMATTR_SETUNDERLINE:
1053             {
1054                 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
1055                         SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
1056             }
1057             break;
1058 
1059         case RTF_PNINDENT:
1060             if( 0 > short( nTokenValue ) )
1061                 nTokenValue = - (short)nTokenValue;
1062             pCurNumFmt->SetFirstLineOffset( - short( nTokenValue ));
1063             pCurNumFmt->SetAbsLSpace( (nLevel + 1 ) * sal_uInt16( nTokenValue ));
1064             break;
1065         case RTF_PNSP:
1066             pCurNumFmt->SetCharTextDistance( sal_uInt16( nTokenValue ));
1067             break;
1068 
1069         case RTF_PNPREV:
1070             if( nLevel )
1071             {
1072                 sal_uInt8 nPrev = 2, nLast = nLevel;
1073                 while( nLast && 1 < pCurRule->Get( --nLast ).GetIncludeUpperLevels() )
1074                     ++nPrev;
1075                 pCurNumFmt->SetIncludeUpperLevels( nPrev );
1076             }
1077             break;
1078 
1079         case RTF_PNQC:  pCurNumFmt->SetNumAdjust( SVX_ADJUST_CENTER );  break;
1080         case RTF_PNQL:  pCurNumFmt->SetNumAdjust( SVX_ADJUST_LEFT );        break;
1081         case RTF_PNQR:  pCurNumFmt->SetNumAdjust( SVX_ADJUST_RIGHT );       break;
1082 
1083         case RTF_PNSTART:
1084             pCurNumFmt->SetStart( sal_uInt16( nTokenValue ));
1085             break;
1086 
1087         case RTF_PNNUMONCE:
1088         case RTF_PNACROSS:
1089         case RTF_PNHANG:
1090         case RTF_PNRESTART:     break;
1091 
1092         case RTF_PNTXTA:
1093             {
1094                 String sTmp;
1095                 GetTextToEndGroup( sTmp );
1096                 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
1097                 {
1098                     pCurNumFmt->SetBulletChar( sTmp.GetChar( 0 ) );
1099                     if( pCurNumFmt->GetCharFmt() )
1100                         pCurNumFmt->SetBulletFont( FindFontOfItem(
1101                                     pCurNumFmt->GetCharFmt()->GetFont() ) );
1102                     sTmp.Erase();
1103                 }
1104                 pCurNumFmt->SetSuffix( sTmp );
1105             }
1106             break;
1107 
1108         case RTF_PNTXTB:
1109             {
1110                 String sTmp;
1111                 pCurNumFmt->SetPrefix( GetTextToEndGroup( sTmp ) );
1112             }
1113             break;
1114         }
1115     }
1116 
1117     // falls vollstaendige Numerierung an ist und das Zeichen davor ein
1118     // Punkt ist, dann will RTF den Punkt als Trenner zwischen den Ebenen
1119     // haben - das haben wir aber schon als default
1120     if( 1 < pCurNumFmt->GetIncludeUpperLevels() &&
1121         1 == pCurNumFmt->GetPrefix().Len() &&
1122         '.' == pCurNumFmt->GetPrefix().GetChar( 0 ) &&
1123         SVX_NUM_CHAR_SPECIAL != pCurNumFmt->GetNumberingType() )
1124         pCurNumFmt->SetPrefix( aEmptyStr );
1125 
1126     // falls das ein nicht numerierter Absatz mit ein Prefix-Text mit
1127     // einem Zeichen ist, dann setze den als Bulletzeichen
1128     if( pCurNumFmt->GetCharFmt() && SVX_NUM_NUMBER_NONE == pCurNumFmt->GetNumberingType() &&
1129         3 == nListNo && 1 == pCurNumFmt->GetPrefix().Len() )
1130     {
1131         SwCharFmt* pChFmt = pCurNumFmt->GetCharFmt();
1132         pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1133         pCurNumFmt->SetBulletFont( FindFontOfItem( pChFmt->GetFont() ) );
1134 
1135         pCurNumFmt->SetBulletChar( pCurNumFmt->GetPrefix().GetChar( 0 ) );
1136         pCurNumFmt->SetPrefix( aEmptyStr );
1137 
1138         // den Font oder sogar das gesamte CharFormat loeschen?
1139         if( SFX_ITEM_SET == pChFmt->GetItemState( RES_CHRATR_FONT, sal_False ))
1140         {
1141             if( 1 == pChFmt->GetAttrSet().Count() )
1142             {
1143                 pCurNumFmt->SetCharFmt( 0 );
1144                 pDoc->DelCharFmt( pChFmt );
1145             }
1146             else
1147                 pChFmt->ResetFmtAttr( RES_CHRATR_FONT );
1148         }
1149     }
1150 
1151     SkipToken( -1 );        // die schliesende Klammer wird "oben" ausgewertet
1152     return pCurRule;
1153 }
1154 
1155 
1156 /*  */
1157 
1158 // dann noch die Ausgabe-Funktionen (nur fuer WinWord 97)
1159 
lcl_IsExportNumRule(const SwNumRule & rRule,sal_uInt8 * pEnd=0)1160 sal_Bool lcl_IsExportNumRule( const SwNumRule& rRule, sal_uInt8* pEnd = 0 )
1161 {
1162     sal_uInt8 nEnd = MAXLEVEL;
1163     while( nEnd-- && !rRule.GetNumFmt( nEnd ))
1164         ;
1165     ++nEnd;
1166 
1167     const SwNumFmt* pNFmt;
1168     sal_uInt8 nLvl;
1169 
1170     for( nLvl = 0; nLvl < nEnd; ++nLvl )
1171         if( SVX_NUM_NUMBER_NONE != ( pNFmt = &rRule.Get( nLvl ))
1172             ->GetNumberingType() || pNFmt->GetPrefix().Len() ||
1173             (pNFmt->GetSuffix().Len() && pNFmt->GetSuffix() != aDotStr ))
1174             break;
1175 
1176     if( pEnd )
1177         *pEnd = nEnd;
1178     return nLvl != nEnd;
1179 }
1180