merge the formfield patch from ooo-build
[ooovba.git] / sw / source / filter / rtf / rtfnum.cxx
blobdf96878b38b6be5bfb125a17b0f66f86cae00f24
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rtfnum.cxx,v $
10 * $Revision: 1.26 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <hintids.hxx>
34 #include <tools/stream.hxx>
35 #include <svtools/rtftoken.h>
36 #include <svtools/rtfkeywd.hxx>
37 #include <svtools/intitem.hxx>
38 #include <svtools/rtfout.hxx>
39 #include <svx/lrspitem.hxx>
40 #include <svx/fontitem.hxx>
41 #include <svx/fhgtitem.hxx>
42 #include <svx/wghtitem.hxx>
43 #include <svx/postitem.hxx>
44 #include <svx/cmapitem.hxx>
45 #include <svx/crsditem.hxx>
46 #include <svx/colritem.hxx>
47 #include <svx/udlnitem.hxx>
48 #include <svx/wrlmitem.hxx>
49 #include <shellio.hxx>
50 #include <fltini.hxx>
51 #include <swtypes.hxx>
52 #include <swparrtf.hxx>
53 #include <wrtrtf.hxx>
54 #include <ndtxt.hxx>
55 #include <doc.hxx>
56 #include <docary.hxx>
57 #include <pam.hxx>
58 #include <charfmt.hxx>
59 #include <charatr.hxx>
60 #include <paratr.hxx>
61 #ifndef _CMDID_H
62 #include <cmdid.h>
63 #endif
64 #include <numrule.hxx>
66 #define RTF_NUMRULE_NAME "RTF_Num"
68 SV_IMPL_VARARR( SwListArr, SwListEntry )
71 void lcl_ExpandNumFmts( SwNumRule& rRule )
73 // dann noch das NumFormat in alle Ebenen setzen
74 for( BYTE n = 1; n < MAXLEVEL; ++n )
75 if( !rRule.GetNumFmt( n ) )
77 SwNumFmt aNumFmt( rRule.Get( 0 ));
78 aNumFmt.SetAbsLSpace( aNumFmt.GetAbsLSpace() * ( n + 1 ) );
79 rRule.Set( n, aNumFmt );
83 SfxItemSet& GetNumChrFmt( SwDoc& rDoc, SwNumRule& rRule, BYTE nNumLvl )
85 SwCharFmt* pChrFmt = rRule.Get( nNumLvl ).GetCharFmt();
86 if( !pChrFmt )
88 String sNm( rRule.GetName() );
89 ( sNm += ' ' ) += String::CreateFromInt32( nNumLvl + 1 );
90 pChrFmt = rDoc.MakeCharFmt( sNm, rDoc.GetDfltCharFmt() );
91 if( !rRule.GetNumFmt( nNumLvl ))
92 rRule.Set( nNumLvl, rRule.Get( nNumLvl ) );
93 ((SwNumFmt*)rRule.GetNumFmt( nNumLvl ))->SetCharFmt( pChrFmt );
95 return (SfxItemSet&)pChrFmt->GetAttrSet();
98 void SwRTFParser::ReadListLevel( SwNumRule& rRule, BYTE nNumLvl )
100 int nToken;
101 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
102 int nLvlTxtLevel = 0, nLvlNumberLevel = 0;
103 String sLvlText, sLvlNumber;
104 SwNumFmt* pCurNumFmt;
105 String aStringFollow = aEmptyStr;
107 if( MAXLEVEL >= nNumLvl )
109 pCurNumFmt = (SwNumFmt*)rRule.GetNumFmt( nNumLvl );
110 pCurNumFmt->SetAbsLSpace( 0 );
111 pCurNumFmt->SetFirstLineOffset( 0 );
113 else
114 pCurNumFmt = 0;
116 while( nNumOpenBrakets && IsParserWorking() )
118 switch( ( nToken = GetNextToken() ))
120 case '}':
121 if( nNumOpenBrakets )
123 if( nLvlTxtLevel == nNumOpenBrakets )
125 if( DelCharAtEnd( sLvlText, ';' ).Len() &&
126 sLvlText.Len() && sLvlText.Len() ==
127 (USHORT)(sLvlText.GetChar( 0 )) + 1 )
128 sLvlText.Erase( 0, 1 );
129 nLvlTxtLevel = 0;
131 if( nLvlNumberLevel == nNumOpenBrakets )
133 DelCharAtEnd( sLvlNumber, ';' );
134 nLvlNumberLevel = 0;
137 --nNumOpenBrakets;
138 break;
140 case '{':
142 if( RTF_IGNOREFLAG != GetNextToken() )
143 nToken = SkipToken( -1 );
144 // Unknown und alle bekannten nicht ausgewerteten Gruppen
145 // sofort ueberspringen
146 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
147 // RTF_PANOSE != nToken && RTF_FALT != nToken &&
148 // RTF_FALT != nToken && RTF_FNAME != nToken &&
149 // RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
150 nToken = SkipToken( -2 );
151 else
153 // gleich herausfiltern
154 ReadUnknownData();
155 nToken = GetNextToken();
156 if( '}' != nToken )
157 eState = SVPAR_ERROR;
158 break;
160 ++nNumOpenBrakets;
162 break;
164 case RTF_LEVELNFC:
166 sal_Int16 eType = SVX_NUM_ARABIC;
167 switch( nTokenValue )
169 case 1: eType = SVX_NUM_ROMAN_UPPER; break;
170 case 2: eType = SVX_NUM_ROMAN_LOWER; break;
171 case 3: eType = SVX_NUM_CHARS_UPPER_LETTER_N; break;
172 case 4: eType = SVX_NUM_CHARS_LOWER_LETTER_N; break;
173 case 255:
174 case 23: eType = SVX_NUM_CHAR_SPECIAL; break;
176 if( pCurNumFmt )
177 pCurNumFmt->SetNumberingType(eType);
179 break;
181 case RTF_LEVELJC:
183 SvxAdjust eAdj = SVX_ADJUST_LEFT;
184 switch( nTokenValue )
186 case 1: eAdj = SVX_ADJUST_CENTER; break;
187 case 2: eAdj = SVX_ADJUST_RIGHT; break;
189 if( pCurNumFmt )
190 pCurNumFmt->SetNumAdjust( eAdj );
192 break;
194 case RTF_LEVELSTARTAT:
195 if( pCurNumFmt && -1 != nTokenValue )
196 pCurNumFmt->SetStart( USHORT( nTokenValue ));
197 break;
199 case RTF_LEVELTEXT:
200 nLvlTxtLevel = nNumOpenBrakets;
201 break;
203 case RTF_LEVELNUMBERS:
204 nLvlNumberLevel = nNumOpenBrakets;
205 break;
208 case RTF_TEXTTOKEN:
209 if( nLvlTxtLevel == nNumOpenBrakets )
210 sLvlText += aToken;
211 else if( nLvlNumberLevel == nNumOpenBrakets )
212 sLvlNumber += aToken;
213 break;
215 case RTF_LEVELFOLLOW:
216 /* removed; waiting for swnum02 to be integrated!
217 switch (nTokenValue)
219 case 0:
220 aStringFollow=String('\t');
221 break;
222 case 1:
223 aStringFollow=String(' ');
224 break;
227 break;
229 case RTF_LEVELOLD:
230 case RTF_LEVELPREV:
231 case RTF_LEVELPREVSPACE:
232 case RTF_LEVELINDENT:
233 case RTF_LEVELSPACE:
234 case RTF_LEVELLEGAL:
235 case RTF_LEVELNORESTART:
236 break;
238 default:
239 if( pCurNumFmt && (
240 RTF_CHRFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ||
241 RTF_PARFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ))
243 SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
244 // put the current CharFmtAttr into the set
245 SfxItemSet& rCFmtSet = GetNumChrFmt( *pDoc, rRule, nNumLvl );
246 aSet.Put( rCFmtSet );
247 // and put the current "LRSpace" into the set
249 SvxLRSpaceItem aLR( RES_LR_SPACE );
250 aLR.SetTxtLeft( pCurNumFmt->GetAbsLSpace() );
251 aLR.SetTxtFirstLineOfst(pCurNumFmt->GetFirstLineOffset());
252 aSet.Put( aLR );
255 ReadAttr( nToken, &aSet );
257 //#i24880# Word appears to ignore char background for numbering
258 aSet.ClearItem(RES_CHRATR_BACKGROUND);
260 // put all CharFmt Items into the charfmt
261 rCFmtSet.Put( aSet );
263 // test for LRSpace Item. If exist then set all relevant
264 // values on the numrule format
265 const SfxPoolItem* pItem;
266 if( SFX_ITEM_SET == aSet.GetItemState( RES_LR_SPACE,
267 FALSE, &pItem ))
269 const SvxLRSpaceItem& rLR = *(SvxLRSpaceItem*)pItem;
270 pCurNumFmt->SetAbsLSpace( static_cast< short >(rLR.GetTxtLeft()) );
271 pCurNumFmt->SetFirstLineOffset( rLR.GetTxtFirstLineOfst());
274 // dann aus der Vorlage den Font holen
275 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
276 pCurNumFmt->SetBulletFont( FindFontOfItem(
277 pCurNumFmt->GetCharFmt()->GetFont() ) );
279 break;
283 if( IsParserWorking() && pCurNumFmt )
285 // dann erzeuge mal die Pre/Postfix-Strings
286 if( sLvlText.Len() &&
287 SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
289 pCurNumFmt->SetBulletChar( sLvlText.GetChar( 0 ) );
290 // dann aus der Vorlage den Font holen
291 if( pCurNumFmt->GetCharFmt() )
292 pCurNumFmt->SetBulletFont( FindFontOfItem(
293 pCurNumFmt->GetCharFmt()->GetFont() ) );
295 else if( sLvlNumber.Len() && sLvlText.Len() )
297 // in sLvlText steht der Text, in sLvlNumber die Position
298 // der Ebenen in sLvlText
299 pCurNumFmt->SetPrefix(
300 sLvlText.Copy( 0, USHORT( sLvlNumber.GetChar( 0 ))-1 ));
301 pCurNumFmt->SetSuffix( sLvlText.Copy(
302 USHORT( sLvlNumber.GetChar( sLvlNumber.Len()-1 )) ));
303 // wieviele Levels stehen im String?
304 pCurNumFmt->SetIncludeUpperLevels( (BYTE)sLvlNumber.Len() );
306 else
308 pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
309 pCurNumFmt->SetSuffix( sLvlText );
312 String newSuffix=pCurNumFmt->GetSuffix();
313 newSuffix+=aStringFollow;
314 pCurNumFmt->SetSuffix(newSuffix);
315 /* removed; waiting for swnum02 to be integrated!
316 if (aStringFollow.GetChar(0)=='\t' && !pCurNumFmt->IsItemize())
318 pCurNumFmt->SetAbsLSpace(0);
319 pCurNumFmt->SetFirstLineOffset(0);
324 SkipToken( -1 );
327 void SwRTFParser::ReadListTable()
329 int nToken;
330 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
331 bNewNumList = TRUE;
333 BYTE nNumLvl = 0;
334 SwNumRule* pCurRule = 0;
335 SwListEntry aEntry;
337 while( nNumOpenBrakets && IsParserWorking() )
339 switch( ( nToken = GetNextToken() ))
341 case '}': if( --nNumOpenBrakets && IsParserWorking() )
343 // Style konnte vollstaendig gelesen werden,
344 // also ist das noch ein stabiler Status
345 SaveState( RTF_LISTTABLE );
346 if( 1 == nNumOpenBrakets )
348 if( aEntry.nListId )
349 aListArr.Insert( aEntry, aListArr.Count() );
350 aEntry.Clear();
353 break;
355 case '{':
357 if( RTF_IGNOREFLAG != GetNextToken() )
358 nToken = SkipToken( -1 );
359 // Unknown und alle bekannten nicht ausgewerteten Gruppen
360 // sofort ueberspringen
361 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
362 // RTF_PANOSE != nToken && RTF_FALT != nToken &&
363 // RTF_FALT != nToken && RTF_FNAME != nToken &&
364 // RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
365 nToken = SkipToken( -2 );
366 else
368 // gleich herausfiltern
369 ReadUnknownData();
370 nToken = GetNextToken();
371 if( '}' != nToken )
372 eState = SVPAR_ERROR;
373 break;
375 ++nNumOpenBrakets;
377 break;
379 case RTF_LIST:
381 if( pCurRule && pCurRule->IsContinusNum() )
382 lcl_ExpandNumFmts( *pCurRule );
384 String sTmp( String::CreateFromAscii(
385 RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
386 aEntry.nListDocPos = pDoc->MakeNumRule( sTmp );
387 pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
388 // --> OD 2008-07-08 #i91400#
389 pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, FALSE ),
390 *pDoc );
391 // <--
392 pCurRule->SetAutoRule( FALSE );
393 nNumLvl = (BYTE)-1;
395 break;
397 case RTF_LISTID: aEntry.nListId = nTokenValue; break;
398 case RTF_LISTTEMPLATEID: aEntry.nListTemplateId = nTokenValue; break;
400 case RTF_LISTRESTARTHDN:
401 break;
402 case RTF_LISTNAME:
403 if (nNextCh=='}') break; // #118989# empty listnames
404 if( RTF_TEXTTOKEN == GetNextToken() )
406 String sTmp( DelCharAtEnd( aToken, ';' ));
407 if( sTmp.Len() && !pDoc->FindNumRulePtr( sTmp ))
409 // --> OD 2008-07-08 #i91400#
410 pCurRule->SetName( sTmp, *pDoc );
411 // <--
414 SkipGroup();
415 break;
417 case RTF_LISTSIMPLE:
418 pCurRule->SetContinusNum( TRUE );
419 break;
421 case RTF_LISTLEVEL:
423 if( ++nNumLvl < MAXLEVEL )
424 pCurRule->Set( nNumLvl, pCurRule->Get( nNumLvl ));
425 ReadListLevel( *pCurRule, nNumLvl );
427 break;
431 if( pCurRule && pCurRule->IsContinusNum() )
432 lcl_ExpandNumFmts( *pCurRule );
434 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
437 BOOL lcl_IsEqual( SwNumRule* pOrigRule, SwNumRule* pRule )
439 BOOL bRet = 0;
440 if( pOrigRule && pRule )
442 bRet = pOrigRule->GetRuleType() == pRule->GetRuleType() &&
443 pOrigRule->IsContinusNum() == pRule->IsContinusNum() &&
444 pOrigRule->IsAbsSpaces() == pRule->IsAbsSpaces();
445 if( bRet )
446 for( BYTE n = 0; bRet && n < MAXLEVEL; ++n )
448 const SwNumFmt* pOFmt = pOrigRule->GetNumFmt( n ),
449 * pFmt = pRule->GetNumFmt( n );
450 if( pFmt && pOFmt )
452 SwCharFmt* pOCFmt = pOFmt->GetCharFmt(),
453 * pCFmt = pFmt->GetCharFmt();
454 if( pOCFmt && pCFmt )
456 bRet = 0 != (pCFmt->GetAttrSet() == pOCFmt->GetAttrSet());
458 else
459 bRet = !pCFmt && !pOCFmt;
460 if( bRet )
462 ((SwNumFmt*)pOFmt)->SetCharFmt( 0 );
463 ((SwNumFmt*)pFmt)->SetCharFmt( 0 );
464 bRet = *pOFmt == *pFmt;
465 ((SwNumFmt*)pOFmt)->SetCharFmt( pOCFmt );
466 ((SwNumFmt*)pFmt)->SetCharFmt( pCFmt );
469 else
470 bRet = !pFmt && !pOFmt;
473 return bRet;
476 void SwRTFParser::ReadListOverrideTable()
478 int nToken;
479 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
480 SwListEntry aEntry;
481 SwNumRule* pRule = 0, *pOrigRule = 0;
482 BYTE nNumLvl = 0;
483 BOOL bOverrideFormat = FALSE, bOverrideStart = FALSE;
485 while( nNumOpenBrakets && IsParserWorking() )
487 switch( ( nToken = GetNextToken() ))
489 case '}':
490 if( --nNumOpenBrakets && IsParserWorking() )
492 // Style konnte vollstaendig gelesen werden,
493 // also ist das noch ein stabiler Status
494 SaveState( RTF_LISTOVERRIDETABLE );
496 if( 1 == nNumOpenBrakets )
498 bOverrideFormat = FALSE, bOverrideStart = FALSE;
499 if( pRule )
501 if( lcl_IsEqual( pOrigRule, pRule ))
503 // no changes on the rule -> use the original rule
504 aEntry.nListDocPos = pDoc->FindNumRule(
505 pOrigRule->GetName() );
506 // delete the temp Rule
507 RemoveUnusedNumRule( pRule );
509 else if( pRule->IsContinusNum() )
510 lcl_ExpandNumFmts( *pRule );
513 if( aEntry.nListId && aEntry.nListNo )
515 int nMatch=-1;
516 for( USHORT n = aListArr.Count(); n; )
518 if( aListArr[ --n ].nListId == aEntry.nListId)
520 nMatch=n;
521 break;
524 if(nMatch>=0)
526 USHORT nMatch2 = static_cast< USHORT >(nMatch);
527 if (!aListArr[nMatch2].nListNo )
529 aListArr[nMatch2].nListNo = aEntry.nListNo;
531 else
533 aEntry.nListDocPos=aListArr[nMatch2].nListDocPos;
534 aEntry.nListTemplateId=aListArr[nMatch2].nListTemplateId;
535 aListArr.Insert(aEntry, aListArr.Count());
537 if(pOrigRule)
538 aListArr[nMatch2].nListDocPos = aEntry.nListDocPos;
541 aEntry.Clear();
542 pOrigRule = 0;
543 pRule = 0;
546 break;
548 case '{':
550 if( RTF_IGNOREFLAG != GetNextToken() )
551 nToken = SkipToken( -1 );
552 // Unknown und alle bekannten nicht ausgewerteten Gruppen
553 // sofort ueberspringen
554 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
555 nToken = SkipToken( -2 );
556 else
558 // gleich herausfiltern
559 ReadUnknownData();
560 nToken = GetNextToken();
561 if( '}' != nToken )
562 eState = SVPAR_ERROR;
563 break;
565 ++nNumOpenBrakets;
567 break;
569 case RTF_LISTOVERRIDE: aEntry.Clear(); break;
570 case RTF_LISTID: aEntry.nListId = nTokenValue; break;
571 case RTF_LS: aEntry.nListNo = nTokenValue; break;
572 case RTF_LISTOVERRIDECOUNT:
573 if( nTokenValue )
575 pRule = 0;
576 // dann erzeugen wir mal schnell eine Kopie von der NumRule,
577 // denn diese wird jetzt mal kurz veraendert.
578 if( aEntry.nListId )
579 for( USHORT n = 0; n < aListArr.Count(); ++n )
580 if( aListArr[ n ].nListId == aEntry.nListId )
582 pRule = pDoc->GetNumRuleTbl()[
583 aListArr[ n ].nListDocPos ];
584 pOrigRule = pRule;
586 String sTmp( String::CreateFromAscii(
587 RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
588 aEntry.nListDocPos = pDoc->MakeNumRule( sTmp, pRule );
589 pRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
590 // --> OD 2008-07-08 #i91400#
591 pRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, FALSE ),
592 *pDoc );
593 // <--
594 pRule->SetAutoRule( FALSE );
595 nNumLvl = (BYTE)-1;
596 aListArr.Insert( aEntry, aListArr.Count() );
597 break;
601 break;
603 case RTF_LISTLEVEL:
604 if( pRule && bOverrideFormat )
606 if( ++nNumLvl < MAXLEVEL )
607 pRule->Set( nNumLvl, pRule->Get( nNumLvl ));
608 ReadListLevel( *pRule, nNumLvl );
610 break;
612 case RTF_LEVELSTARTAT:
613 if( pRule && bOverrideStart )
616 break;
618 case RTF_LISTOVERRIDESTART:
619 bOverrideStart = TRUE;
620 break;
622 case RTF_LISTOVERRIDEFORMAT:
623 bOverrideFormat = TRUE;
624 break;
626 case RTF_LFOLEVEL:
627 // was fehlt noch?
628 break;
632 // search the outline numrule and set it into the doc
633 if( GetStyleTbl().Count() )
635 if( !bStyleTabValid )
636 MakeStyleTab();
638 const SfxPoolItem* pItem( 0 );
639 const SwTxtFmtColl* pColl( 0 );
640 USHORT nRulePos( USHRT_MAX );
641 const SwNumRule *pNumRule = 0;
642 SvxRTFStyleType* pStyle = GetStyleTbl().First();
643 do {
644 // --> OD 2007-12-17 #151213#
645 // suppress deletion of outline list style.
646 // refactoring of code: no assignments in if-condition
647 // if( MAXLEVEL > pStyle->nOutlineNo &&
648 // 0 != ( pColl = aTxtCollTbl.Get( (USHORT)GetStyleTbl().
649 // GetCurKey() )) &&
650 // SFX_ITEM_SET == pColl->GetItemState( RES_PARATR_NUMRULE,
651 // FALSE, &pItem ) &&
652 // USHRT_MAX != (nRulePos = pDoc->FindNumRule(
653 // ((SwNumRuleItem*)pItem)->GetValue() )) &&
654 // (pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ])->IsAutoRule() )
655 if ( MAXLEVEL > pStyle->nOutlineNo )
657 pColl = aTxtCollTbl.Get( (USHORT)GetStyleTbl().GetCurKey() );
658 if ( pColl )
660 const SfxItemState eItemState =
661 pColl->GetItemState( RES_PARATR_NUMRULE, FALSE, &pItem );
662 if ( eItemState == SFX_ITEM_SET )
664 nRulePos = pDoc->FindNumRule( ((SwNumRuleItem*)pItem)->GetValue() );
665 if ( nRulePos != USHRT_MAX )
667 pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ];
668 if ( pNumRule->IsAutoRule() &&
669 pNumRule != pDoc->GetOutlineNumRule() )
671 pDoc->SetOutlineNumRule( *pNumRule );
672 pDoc->DelNumRule( pNumRule->GetName() );
673 // now pNumRule pointer is invalid !!!
675 // now decrement all position in the listtable, which will
676 // behind the doc-rule position
677 for( USHORT n = aListArr.Count(); n; )
679 SwListEntry& rEntry = aListArr[ --n ];
680 if( rEntry.nListDocPos == nRulePos )
681 aListArr.Remove( n );
682 else if( rEntry.nListDocPos > nRulePos )
683 --rEntry.nListDocPos;
685 break;
691 // <--
693 pStyle->aAttrSet.ClearItem( FN_PARAM_NUM_LEVEL );
695 } while( 0 != (pStyle = GetStyleTbl().Next()) );
698 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
701 SwNumRule* SwRTFParser::GetNumRuleOfListNo( long nListNo, BOOL bRemoveFromList )
703 SwNumRule* pRet = 0;
704 SwListEntry* pEntry;
705 for( USHORT n = aListArr.Count(); n; )
706 if( ( pEntry = &aListArr[ --n ])->nListNo == nListNo )
708 if( bRemoveFromList )
709 aListArr.Remove( n );
710 else
712 pEntry->bRuleUsed = TRUE;
713 pRet = pDoc->GetNumRuleTbl()[ pEntry->nListDocPos ];
715 break;
717 return pRet;
720 void SwRTFParser::RemoveUnusedNumRule( SwNumRule* pRule )
722 if( pRule )
724 for ( BYTE nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
726 SwNumFmt& rNFmt = (SwNumFmt&)pRule->Get( nLvl );
727 SwCharFmt* pCFmt = rNFmt.GetCharFmt();
728 if( pCFmt )
730 pCFmt->Remove( &rNFmt );
731 if( !pCFmt->GetDepends() )
732 pDoc->DelCharFmt( pCFmt );
735 pDoc->DelNumRule( pRule->GetName() );
737 #ifndef PRODUCT
738 else
740 ASSERT( pRule, "NumRulePointer 0 kann nicht geloescht werden" );
742 #endif
745 void SwRTFParser::RemoveUnusedNumRules()
747 SwListEntry* pEntry;
748 SvPtrarr aDelArr;
749 USHORT n;
750 for( n = aListArr.Count(); n; )
752 if( !( pEntry = &aListArr[ --n ])->bRuleUsed )
754 // really *NOT* used by anyone else?
755 BOOL unused=TRUE;
756 for(USHORT j = 0; j < aListArr.Count(); ++j)
758 if (aListArr[n].nListNo==aListArr[j].nListNo)
759 unused&=!aListArr[j].bRuleUsed;
761 if (unused)
763 void * p = pDoc->GetNumRuleTbl()[pEntry->nListDocPos];
764 // dont delete named char formats
765 if( USHRT_MAX == aDelArr.GetPos( p ) &&
766 ((SwNumRule*)p)->GetName().EqualsAscii( RTF_NUMRULE_NAME, 0,
767 sizeof( RTF_NUMRULE_NAME )) )
768 aDelArr.Insert( p, aDelArr.Count() );
773 for( n = aDelArr.Count(); n; )
775 SwNumRule* pDel = (SwNumRule*)aDelArr[ --n ];
776 RemoveUnusedNumRule( pDel );
780 const Font* SwRTFParser::FindFontOfItem( const SvxFontItem& rItem ) const
782 SvxRTFFontTbl& rFntTbl = ((SwRTFParser*)this)->GetFontTbl();
783 const Font* pFnt = rFntTbl.First();
784 while( pFnt )
786 if( pFnt->GetFamily() == rItem.GetFamily() &&
787 pFnt->GetName() == rItem.GetFamilyName() &&
788 pFnt->GetStyleName() == rItem.GetStyleName() &&
789 pFnt->GetPitch() == rItem.GetPitch() &&
790 pFnt->GetCharSet() == rItem.GetCharSet() )
791 return pFnt;
793 pFnt = rFntTbl.Next();
795 return 0;
799 SwNumRule *SwRTFParser::ReadNumSecLevel( int nToken )
801 // lese die \pnseclvl - Gruppe
802 // nTokenValue gibt schon den richtigen Level vor 1 - 9!
803 BYTE nLevel = 0;
804 long nListNo = 0;
805 BOOL bContinus = TRUE;
807 if( RTF_PNSECLVL == nToken )
809 // suche die Rule - steht unter Nummer 3
810 nListNo = 3;
811 bContinus = FALSE;
812 nLevel = MAXLEVEL <= nTokenValue ? MAXLEVEL - 1
813 : BYTE( nTokenValue - 1 );
815 else
817 switch( nToken = GetNextToken() )
819 case RTF_PNLVL: nListNo = 3;
820 bContinus = FALSE;
821 nLevel = MAXLEVEL <= nTokenValue
822 ? MAXLEVEL - 1
823 : BYTE( nTokenValue-1 );
824 break;
826 case RTF_PNLVLBODY:
827 nListNo = 2;
828 break;
829 case RTF_PNLVLBLT:
830 nListNo = 1;
831 break;
832 case RTF_PNLVLCONT:
833 SkipGroup();
834 return 0;
835 default:
836 SkipGroup();
837 return 0;
841 // suche die Rule - steht unter Nummer 3
842 USHORT nNewFlag = static_cast< USHORT >(1 << nListNo);
843 SwNumRule* pCurRule = GetNumRuleOfListNo( nListNo,
844 0 != ( nNewNumSectDef & nNewFlag ) );
845 if( !pCurRule )
847 // dann muessen wir die mal anlegen
848 nNewNumSectDef &= ~nNewFlag;
849 String sTmp( String::CreateFromAscii(
850 RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
851 SwListEntry aEntry( nListNo, 0, pDoc->MakeNumRule( sTmp ));
852 aEntry.nListNo = nListNo;
853 aListArr.Insert( aEntry, aListArr.Count() );
854 pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
855 // --> OD 2008-07-08 #i91400#
856 pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, FALSE ), *pDoc );
857 // <--
858 pCurRule->SetAutoRule( FALSE );
859 pCurRule->SetContinusNum( bContinus );
862 if( !pCurRule->GetNumFmt( nLevel ))
863 pCurRule->Set( nLevel, pCurRule->Get( nLevel ));
864 SwNumFmt* pCurNumFmt = (SwNumFmt*)pCurRule->GetNumFmt( nLevel );
865 if( RTF_PNLVLBLT == nToken )
866 pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
867 pCurNumFmt->SetSuffix( aEmptyStr );
868 pCurNumFmt->SetPrefix( aEmptyStr );
869 pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
871 if( bStyleTabValid && RTF_PNSECLVL != nToken )
873 // dann den akt. Lvl und Rule am Absatz setzen.
874 // Dieses muss aber in den vorherigen "Kontext", sprich in den vor
875 // der Klammer offenen Attrset. Darum das SetNewGroup davor und dahinter
876 SetNewGroup( FALSE );
877 GetAttrSet().Put( SfxUInt16Item( FN_PARAM_NUM_LEVEL, nLevel ));
878 GetAttrSet().Put( SwNumRuleItem( pCurRule->GetName() ));
879 SetNewGroup( TRUE );
882 FontUnderline eUnderline;
883 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
884 while( nNumOpenBrakets && IsParserWorking() )
886 switch( ( nToken = GetNextToken() ))
888 case '}':
889 if( --nNumOpenBrakets && IsParserWorking() )
891 // Style konnte vollstaendig gelesen werden,
892 // also ist das noch ein stabiler Status
893 SaveState( RTF_PNSECLVL );
895 break;
897 case '{':
899 if( RTF_IGNOREFLAG != GetNextToken() )
900 nToken = SkipToken( -1 );
901 // Unknown und alle bekannten nicht ausgewerteten Gruppen
902 // sofort ueberspringen
903 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
904 nToken = SkipToken( -2 );
905 else
907 // gleich herausfiltern
908 ReadUnknownData();
909 nToken = GetNextToken();
910 if( '}' != nToken )
911 eState = SVPAR_ERROR;
912 break;
914 ++nNumOpenBrakets;
916 break;
918 case RTF_PNCARD:
919 case RTF_PNORD:
920 case RTF_PNORDT:
921 case RTF_PNDEC: pCurNumFmt->SetNumberingType(SVX_NUM_ARABIC); break;
922 case RTF_PNUCLTR: pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER_N); break;
923 case RTF_PNUCRM: pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_UPPER); break;
924 case RTF_PNLCLTR: pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER_N); break;
925 case RTF_PNLCRM: pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_LOWER); break;
927 case RTF_PNF:
929 const Font& rSVFont = GetFont( USHORT(nTokenValue) );
930 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
931 SvxFontItem( rSVFont.GetFamily(),
932 rSVFont.GetName(), rSVFont.GetStyleName(),
933 rSVFont.GetPitch(), rSVFont.GetCharSet(),
934 RES_CHRATR_FONT ));
935 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
936 pCurNumFmt->SetBulletFont( &rSVFont );
938 break;
939 case RTF_PNFS:
941 if( -1 == nTokenValue )
942 nTokenValue = 240;
943 else
944 nTokenValue *= 10;
945 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
946 SvxFontHeightItem( (const USHORT)nTokenValue, 100, RES_CHRATR_FONTSIZE ));
948 break;
950 case RTF_PNB:
952 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxWeightItem(
953 nTokenValue ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT ));
955 break;
957 case RTF_PNI:
959 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxPostureItem(
960 nTokenValue ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE ));
962 break;
964 case RTF_PNCAPS:
965 case RTF_PNSCAPS:
967 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCaseMapItem(
968 nTokenValue ? SVX_CASEMAP_KAPITAELCHEN
969 : SVX_CASEMAP_NOT_MAPPED, RES_CHRATR_CASEMAP ));
971 break;
972 case RTF_PNSTRIKE:
974 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCrossedOutItem(
975 nTokenValue ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ));
977 break;
979 case RTF_PNCF:
981 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxColorItem(
982 GetColor( USHORT(nTokenValue) ), RES_CHRATR_COLOR ));
984 break;
987 case RTF_PNUL:
988 eUnderline = nTokenValue ? UNDERLINE_SINGLE : UNDERLINE_NONE;
989 goto NUMATTR_SETUNDERLINE;
990 case RTF_PNULD:
991 eUnderline = UNDERLINE_DOTTED;
992 goto NUMATTR_SETUNDERLINE;
993 case RTF_PNULDB:
994 eUnderline = UNDERLINE_DOUBLE;
995 goto NUMATTR_SETUNDERLINE;
996 case RTF_PNULNONE:
997 eUnderline = UNDERLINE_NONE;
998 goto NUMATTR_SETUNDERLINE;
999 case RTF_PNULW:
1001 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
1002 SvxWordLineModeItem( TRUE, RES_CHRATR_WORDLINEMODE ));
1004 eUnderline = UNDERLINE_SINGLE;
1005 goto NUMATTR_SETUNDERLINE;
1007 NUMATTR_SETUNDERLINE:
1009 GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
1010 SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
1012 break;
1014 case RTF_PNINDENT:
1015 if( 0 > short( nTokenValue ) )
1016 nTokenValue = - (short)nTokenValue;
1017 pCurNumFmt->SetFirstLineOffset( - short( nTokenValue ));
1018 pCurNumFmt->SetAbsLSpace( (nLevel + 1 ) * USHORT( nTokenValue ));
1019 break;
1020 case RTF_PNSP:
1021 pCurNumFmt->SetCharTextDistance( USHORT( nTokenValue ));
1022 break;
1024 case RTF_PNPREV:
1025 if( nLevel )
1027 BYTE nPrev = 2, nLast = nLevel;
1028 while( nLast && 1 < pCurRule->Get( --nLast ).GetIncludeUpperLevels() )
1029 ++nPrev;
1030 pCurNumFmt->SetIncludeUpperLevels( nPrev );
1032 break;
1034 case RTF_PNQC: pCurNumFmt->SetNumAdjust( SVX_ADJUST_CENTER ); break;
1035 case RTF_PNQL: pCurNumFmt->SetNumAdjust( SVX_ADJUST_LEFT ); break;
1036 case RTF_PNQR: pCurNumFmt->SetNumAdjust( SVX_ADJUST_RIGHT ); break;
1038 case RTF_PNSTART:
1039 pCurNumFmt->SetStart( USHORT( nTokenValue ));
1040 break;
1042 case RTF_PNNUMONCE:
1043 case RTF_PNACROSS:
1044 case RTF_PNHANG:
1045 case RTF_PNRESTART: break;
1047 case RTF_PNTXTA:
1049 String sTmp;
1050 GetTextToEndGroup( sTmp );
1051 if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
1053 pCurNumFmt->SetBulletChar( sTmp.GetChar( 0 ) );
1054 if( pCurNumFmt->GetCharFmt() )
1055 pCurNumFmt->SetBulletFont( FindFontOfItem(
1056 pCurNumFmt->GetCharFmt()->GetFont() ) );
1057 sTmp.Erase();
1059 pCurNumFmt->SetSuffix( sTmp );
1061 break;
1063 case RTF_PNTXTB:
1065 String sTmp;
1066 pCurNumFmt->SetPrefix( GetTextToEndGroup( sTmp ) );
1068 break;
1072 // falls vollstaendige Numerierung an ist und das Zeichen davor ein
1073 // Punkt ist, dann will RTF den Punkt als Trenner zwischen den Ebenen
1074 // haben - das haben wir aber schon als default
1075 if( 1 < pCurNumFmt->GetIncludeUpperLevels() &&
1076 1 == pCurNumFmt->GetPrefix().Len() &&
1077 '.' == pCurNumFmt->GetPrefix().GetChar( 0 ) &&
1078 SVX_NUM_CHAR_SPECIAL != pCurNumFmt->GetNumberingType() )
1079 pCurNumFmt->SetPrefix( aEmptyStr );
1081 // falls das ein nicht numerierter Absatz mit ein Prefix-Text mit
1082 // einem Zeichen ist, dann setze den als Bulletzeichen
1083 if( pCurNumFmt->GetCharFmt() && SVX_NUM_NUMBER_NONE == pCurNumFmt->GetNumberingType() &&
1084 3 == nListNo && 1 == pCurNumFmt->GetPrefix().Len() )
1086 SwCharFmt* pChFmt = pCurNumFmt->GetCharFmt();
1087 pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
1088 pCurNumFmt->SetBulletFont( FindFontOfItem( pChFmt->GetFont() ) );
1090 pCurNumFmt->SetBulletChar( pCurNumFmt->GetPrefix().GetChar( 0 ) );
1091 pCurNumFmt->SetPrefix( aEmptyStr );
1093 // den Font oder sogar das gesamte CharFormat loeschen?
1094 if( SFX_ITEM_SET == pChFmt->GetItemState( RES_CHRATR_FONT, FALSE ))
1096 if( 1 == pChFmt->GetAttrSet().Count() )
1098 pCurNumFmt->SetCharFmt( 0 );
1099 pDoc->DelCharFmt( pChFmt );
1101 else
1102 pChFmt->ResetFmtAttr( RES_CHRATR_FONT );
1106 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1107 return pCurRule;
1111 /* \f */
1113 // dann noch die Ausgabe-Funktionen (nur fuer WinWord 97)
1115 BOOL lcl_IsExportNumRule( const SwNumRule& rRule, BYTE* pEnd = 0 )
1117 BYTE nEnd = MAXLEVEL;
1118 while( nEnd-- && !rRule.GetNumFmt( nEnd ))
1120 ++nEnd;
1122 const SwNumFmt* pNFmt;
1123 BYTE nLvl;
1125 for( nLvl = 0; nLvl < nEnd; ++nLvl )
1126 if( SVX_NUM_NUMBER_NONE != ( pNFmt = &rRule.Get( nLvl ))
1127 ->GetNumberingType() || pNFmt->GetPrefix().Len() ||
1128 (pNFmt->GetSuffix().Len() && pNFmt->GetSuffix() != aDotStr ))
1129 break;
1131 if( pEnd )
1132 *pEnd = nEnd;
1133 return nLvl != nEnd;
1136 void SwRTFWriter::OutRTFListTab()
1138 ByteString sOverrideList;
1139 USHORT nId = 1, nTmplId = 1, n;
1141 // prepare the NodeNum to generate the NumString
1142 SwNumberTree::tNumberVector aNumVector;
1143 for( n = 0; n < MAXLEVEL; ++n )
1144 aNumVector.push_back(n);
1145 BYTE aNumLvlPos[ MAXLEVEL ];
1147 if( !pNumRuleTbl )
1148 BuildNumRuleTbl();
1150 for( n = 0; n < pNumRuleTbl->Count(); ++n )
1152 const SwNumRule* pRule = (*pNumRuleTbl)[ n ];
1154 // mit der ersten Rule wird auch die ListTable geschrieben
1155 if( !sOverrideList.Len() )
1156 OutComment( *this, OOO_STRING_SVTOOLS_RTF_LISTTABLE );
1158 Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LIST << OOO_STRING_SVTOOLS_RTF_LISTTEMPLATEID;
1159 OutULong( nTmplId );
1160 ByteString sTmp;
1162 if( pRule->IsContinusNum() )
1163 Strm() << OOO_STRING_SVTOOLS_RTF_LISTSIMPLE;
1165 BYTE nLvl, nEnd;
1166 lcl_IsExportNumRule( *pRule, &nEnd );
1168 for( nLvl = 0; nLvl < nEnd; ++nLvl )
1170 const SwNumFmt& rFmt = pRule->Get( nLvl );
1171 Strm() << sNewLine;
1172 if( nLvl > 8 ) // RTF-kennt nur 9 Ebenen
1173 OutComment( *this, OOO_STRING_SVTOOLS_RTF_SOUTLVL );
1175 Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTLEVEL << OOO_STRING_SVTOOLS_RTF_LEVELNFC;
1177 USHORT nVal = 0;
1178 switch( rFmt.GetNumberingType() )
1180 case SVX_NUM_ROMAN_UPPER: nVal = 1; break;
1181 case SVX_NUM_ROMAN_LOWER: nVal = 2; break;
1182 case SVX_NUM_CHARS_UPPER_LETTER:
1183 case SVX_NUM_CHARS_UPPER_LETTER_N: nVal = 3; break;
1184 case SVX_NUM_CHARS_LOWER_LETTER:
1185 case SVX_NUM_CHARS_LOWER_LETTER_N: nVal = 4; break;
1187 case SVX_NUM_BITMAP:
1188 case SVX_NUM_CHAR_SPECIAL: nVal = 23; break;
1190 OutLong( nVal ) << OOO_STRING_SVTOOLS_RTF_LEVELJC;
1192 switch( rFmt.GetNumAdjust() )
1194 case SVX_ADJUST_CENTER: nVal = 1; break;
1195 case SVX_ADJUST_RIGHT: nVal = 2; break;
1196 default: nVal = 0; break;
1198 OutLong( nVal ) << OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT;
1199 OutLong( rFmt.GetStart() )
1200 << OOO_STRING_SVTOOLS_RTF_LEVELFOLLOW << "0{" << OOO_STRING_SVTOOLS_RTF_LEVELTEXT << ' ';
1202 BOOL bWriteBulletFont = FALSE;
1203 memset( aNumLvlPos, 0, MAXLEVEL );
1204 if( SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType() ||
1205 SVX_NUM_BITMAP == rFmt.GetNumberingType() )
1207 Strm() << "\\'01";
1208 ByteString sNo( ByteString::CreateFromInt32( rFmt.GetBulletChar()));
1209 Strm() << "\\u" << sNo.GetBuffer() << " ?";
1210 bWriteBulletFont = TRUE;
1212 else if( SVX_NUM_NUMBER_NONE == rFmt.GetNumberingType() )
1214 String sOut( rFmt.GetPrefix() ); sOut += rFmt.GetSuffix();
1215 if( sOut.Len() )
1217 Strm() << "\\'";
1218 OutHex( sOut.Len() );
1219 RTFOutFuncs::Out_String( Strm(), sOut,
1220 eDefaultEncoding, bWriteHelpFmt );
1223 else
1225 memset( aNumLvlPos, 0, MAXLEVEL );
1226 BYTE* pLvlPos = aNumLvlPos;
1227 // --> OD 2005-11-18 #128056#
1228 // correction of refactoring done by cws swnumtree:
1229 // - the numbering string has to be restrict to the level
1230 // currently working on.
1231 String sNumStr( pRule->MakeNumString( aNumVector, FALSE, TRUE, nLvl ));
1232 // <--
1234 // now search the nums in the string
1235 for( BYTE i = 0; i <= nLvl; ++i )
1237 String sSrch( String::CreateFromInt32( i ));
1238 xub_StrLen nFnd = sNumStr.Search( sSrch );
1239 if( STRING_NOTFOUND != nFnd )
1241 *pLvlPos = (BYTE)(nFnd + rFmt.GetPrefix().Len() + 1 );
1242 ++pLvlPos;
1243 sNumStr.SetChar( nFnd, (sal_Unicode)i );
1247 Strm() << "\\'";
1248 OutHex( sNumStr.Len() + rFmt.GetPrefix().Len() +
1249 rFmt.GetSuffix().Len() );
1251 if( rFmt.GetPrefix().Len() )
1252 RTFOutFuncs::Out_String( Strm(), rFmt.GetPrefix(),
1253 eDefaultEncoding, bWriteHelpFmt );
1256 for( xub_StrLen x = 0; x < sNumStr.Len(); ++x )
1257 if( sNumStr.GetChar( x ) < 0x20 ||
1258 sNumStr.GetChar( x ) > 0xFF )
1260 Strm() << "\\'"; OutHex( sNumStr.GetChar( x ) );
1262 else
1263 Strm() << (sal_Char)sNumStr.GetChar( x );
1265 if( rFmt.GetSuffix().Len() )
1266 RTFOutFuncs::Out_String( Strm(), rFmt.GetSuffix(),
1267 eDefaultEncoding, bWriteHelpFmt );
1270 // write the levelnumbers
1271 Strm() << ";}{" << OOO_STRING_SVTOOLS_RTF_LEVELNUMBERS;
1272 for( BYTE i = 0; i <= nLvl && aNumLvlPos[ i ]; ++i )
1274 Strm() << "\\'"; OutHex( aNumLvlPos[ i ] );
1276 Strm() << ";}";
1278 if( rFmt.GetCharFmt() )
1279 Out_SfxItemSet( aRTFAttrFnTab, *this,
1280 rFmt.GetCharFmt()->GetAttrSet(), TRUE );
1282 if( bWriteBulletFont )
1284 Strm() << OOO_STRING_SVTOOLS_RTF_F;
1285 const Font* pFont = rFmt.GetBulletFont();
1286 if( !pFont )
1287 // --> OD 2006-06-27 #b6440955#
1288 pFont = &numfunc::GetDefBulletFont();
1289 // <--
1290 OutULong( GetId( *pFont ));
1293 Strm() << OOO_STRING_SVTOOLS_RTF_FI;
1294 OutLong( rFmt.GetFirstLineOffset() ) << OOO_STRING_SVTOOLS_RTF_LI;
1295 OutLong( rFmt.GetAbsLSpace() );
1297 Strm() << '}';
1299 if( nLvl > 8 ) // RTF-kennt nur 9 Ebenen
1300 Strm() << '}';
1303 if( !pRule->IsAutoRule() )
1305 Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTNAME << ' ';
1306 RTFOutFuncs::Out_String( Strm(), pRule->GetName(), eDefaultEncoding,
1307 bWriteHelpFmt ) << ";}" ;
1309 Strm() << OOO_STRING_SVTOOLS_RTF_LISTID;
1310 OutULong( nId ) << '}' << sNewLine;
1312 sTmp = '{';
1313 ((((((( sTmp += OOO_STRING_SVTOOLS_RTF_LISTOVERRIDE ) +=
1314 OOO_STRING_SVTOOLS_RTF_LISTID ) += ByteString::CreateFromInt32( nId )) +=
1315 OOO_STRING_SVTOOLS_RTF_LISTOVERRIDECOUNT ) += '0' ) +=
1316 OOO_STRING_SVTOOLS_RTF_LS ) += ByteString::CreateFromInt32( n )) += '}';
1317 sOverrideList += sTmp;
1319 ++nId, ++nTmplId;
1322 if( sOverrideList.Len() )
1323 Strm() << "}{" << OOO_STRING_SVTOOLS_RTF_LISTOVERRIDETABLE
1324 << sOverrideList.GetBuffer() << '}' << sNewLine;
1327 USHORT SwRTFWriter::GetId( const SwNumRuleItem& rItem ) const
1329 USHORT n, nId = USHRT_MAX;
1330 if( !pNumRuleTbl )
1332 SwRTFWriter* pThis = (SwRTFWriter*)this;
1333 pThis->BuildNumRuleTbl();
1335 const String& rNm = rItem.GetValue();
1336 for( n = pNumRuleTbl->Count(); n; )
1337 if( (*pNumRuleTbl)[ --n ]->GetName() == rNm )
1339 nId = n;
1340 break;
1343 return nId;
1346 USHORT SwRTFWriter::GetNumRuleId( const SwNumRule& rRule )
1348 if( !pNumRuleTbl )
1349 BuildNumRuleTbl();
1350 SwNumRulePtr pR = (SwNumRulePtr)&rRule;
1351 return pNumRuleTbl->GetPos( pR );
1354 void SwRTFWriter::BuildNumRuleTbl()
1356 const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
1357 if( !pNumRuleTbl )
1358 pNumRuleTbl = new SwNumRuleTbl( (BYTE)rListTbl.Count() );
1359 for( USHORT n = rListTbl.Count()+1; n; )
1361 SwNumRule* pRule;
1362 --n;
1363 if( n == rListTbl.Count() )
1364 pRule = (SwNumRule*)pDoc->GetOutlineNumRule();
1365 else
1367 pRule = rListTbl[ n ];
1368 if( !pDoc->IsUsed( *pRule ))
1369 continue;
1372 if( lcl_IsExportNumRule( *pRule ))
1373 pNumRuleTbl->Insert( pRule, pNumRuleTbl->Count() );
1377 BOOL SwRTFWriter::OutListNum( const SwTxtNode& rNd )
1379 BOOL bRet = FALSE;
1380 const SwNumRule* pRule = rNd.GetNumRule();
1382 // --> OD 2008-03-18 #refactorlists#
1383 // if( pRule && MAXLEVEL > rNd.GetActualListLevel() )
1384 if( pRule && rNd.IsInList() )
1385 // <--
1387 // --> OD 2008-03-18 #refactorlists#
1388 ASSERT( rNd.GetActualListLevel() >= 0 && rNd.GetActualListLevel() < MAXLEVEL,
1389 "<SwRTFWriter::OutListNum(..)> - text node does not have valid list level. Serious defect -> please inform OD" );
1390 // <--
1392 bOutFmtAttr = FALSE;
1393 bOutListNumTxt = TRUE;
1394 bRet = TRUE;
1396 const bool bExportNumRule = USHRT_MAX != GetNumRuleId( *pRule );
1397 const BYTE nLvl = static_cast< BYTE >(rNd.GetActualListLevel());
1398 const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl );
1399 if( !pFmt )
1400 pFmt = &pRule->Get( nLvl );
1402 const SfxItemSet& rNdSet = rNd.GetSwAttrSet();
1404 SfxItemSet aSet( *rNdSet.GetPool(), rNdSet.GetRanges() );
1405 aSet.SetParent( &rNdSet );
1406 SvxLRSpaceItem aLR( (SvxLRSpaceItem&)rNdSet.Get( RES_LR_SPACE ) );
1407 aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() );
1409 aLR.SetTxtFirstLineOfst( pFmt->GetFirstLineOffset() );
1410 if ( bExportNumRule )
1411 Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTTEXT << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN << ' ';
1413 aSet.Put( aLR );
1414 Out_SfxItemSet( aRTFAttrFnTab, *this, aSet, TRUE );
1416 if( pFmt->GetCharFmt() )
1417 Out_SfxItemSet( aRTFAttrFnTab, *this,
1418 pFmt->GetCharFmt()->GetAttrSet(), TRUE );
1421 String sTxt;
1422 if( SVX_NUM_CHAR_SPECIAL == pFmt->GetNumberingType() || SVX_NUM_BITMAP == pFmt->GetNumberingType() )
1423 sTxt = pFmt->GetBulletChar();
1424 else
1425 sTxt = rNd.GetNumString();
1427 if( bOutFmtAttr )
1429 Strm() << ' ';
1430 bOutFmtAttr = FALSE;
1433 if (sTxt.Len())
1435 RTFOutFuncs::Out_String(Strm(), sTxt, eDefaultEncoding,
1436 bWriteHelpFmt);
1439 if( bExportNumRule )
1441 if( OUTLINE_RULE != pRule->GetRuleType() )
1443 Strm() << OOO_STRING_SVTOOLS_RTF_TAB << '}' << OOO_STRING_SVTOOLS_RTF_ILVL;
1444 if( nLvl > 8 ) // RTF-kennt nur 9 Ebenen
1446 OutULong( 8 );
1447 OutComment( *this, OOO_STRING_SVTOOLS_RTF_SOUTLVL );
1448 OutULong( nLvl ) << '}';
1450 else
1451 OutULong( nLvl );
1452 Strm() << ' ';
1454 else
1455 Strm() << OOO_STRING_SVTOOLS_RTF_TAB << '}';
1457 else if( sTxt.Len() )
1458 Strm() << OOO_STRING_SVTOOLS_RTF_TAB;
1460 bOutListNumTxt = FALSE;
1462 return bRet;