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