xref: /aoo4110/main/sw/source/filter/rtf/rtfnum.cxx (revision b1cdbd2c)
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