summaryrefslogtreecommitdiff
path: root/sw/source/filter/rtf/rtfnum.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/rtf/rtfnum.cxx')
-rw-r--r--sw/source/filter/rtf/rtfnum.cxx1056
1 files changed, 1056 insertions, 0 deletions
diff --git a/sw/source/filter/rtf/rtfnum.cxx b/sw/source/filter/rtf/rtfnum.cxx
new file mode 100644
index 000000000000..b91c26d1c763
--- /dev/null
+++ b/sw/source/filter/rtf/rtfnum.cxx
@@ -0,0 +1,1056 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+#include <hintids.hxx>
+#include <tools/stream.hxx>
+#include <svtools/rtftoken.h>
+#include <svtools/rtfkeywd.hxx>
+#include <svl/intitem.hxx>
+#include <svtools/rtfout.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/crsditem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/numitem.hxx>
+#include <shellio.hxx>
+#include <fltini.hxx>
+#include <swtypes.hxx>
+#include <swparrtf.hxx>
+#include <ndtxt.hxx>
+#include <doc.hxx>
+#include <docary.hxx>
+#include <pam.hxx>
+#include <charfmt.hxx>
+#include <charatr.hxx>
+#include <paratr.hxx>
+#include <cmdid.h>
+#include <numrule.hxx>
+
+#define RTF_NUMRULE_NAME "RTF_Num"
+
+void lcl_ExpandNumFmts( SwNumRule& rRule )
+{
+ // dann noch das NumFormat in alle Ebenen setzen
+ for( sal_uInt8 n = 1; n < MAXLEVEL; ++n )
+ if( !rRule.GetNumFmt( n ) )
+ {
+ SwNumFmt aNumFmt( rRule.Get( 0 ));
+ aNumFmt.SetIndentAt( aNumFmt.GetIndentAt() * ( n + 1 ) );
+ rRule.Set( n, aNumFmt );
+ }
+}
+
+SfxItemSet& GetNumChrFmt( SwDoc& rDoc, SwNumRule& rRule, sal_uInt8 nNumLvl )
+{
+ SwCharFmt* pChrFmt = rRule.Get( nNumLvl ).GetCharFmt();
+ if( !pChrFmt )
+ {
+ String sNm( rRule.GetName() );
+ ( sNm += ' ' ) += String::CreateFromInt32( nNumLvl + 1 );
+ pChrFmt = rDoc.MakeCharFmt( sNm, rDoc.GetDfltCharFmt() );
+ if( !rRule.GetNumFmt( nNumLvl ))
+ rRule.Set( nNumLvl, rRule.Get( nNumLvl ) );
+ ((SwNumFmt*)rRule.GetNumFmt( nNumLvl ))->SetCharFmt( pChrFmt );
+ }
+ return (SfxItemSet&)pChrFmt->GetAttrSet();
+}
+
+void SwRTFParser::ReadListLevel( SwNumRule& rRule, sal_uInt8 nNumLvl )
+{
+ int nToken;
+ int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
+ int nLvlTxtLevel = 0, nLvlNumberLevel = 0;
+ String sLvlText, sLvlNumber;
+ SwNumFmt* pCurNumFmt;
+ SvxNumberFormat::SvxNumLabelFollowedBy eFollowedBy = SvxNumberFormat::NOTHING;
+
+ if( MAXLEVEL >= nNumLvl )
+ {
+ pCurNumFmt = (SwNumFmt*)rRule.GetNumFmt( nNumLvl );
+ pCurNumFmt->SetIndentAt( 0 );
+ pCurNumFmt->SetFirstLineIndent( 0 );
+ }
+ else
+ pCurNumFmt = 0;
+
+ while( nNumOpenBrakets && IsParserWorking() )
+ {
+ switch( ( nToken = GetNextToken() ))
+ {
+ case '}':
+ if( nNumOpenBrakets )
+ {
+ if( nLvlTxtLevel == nNumOpenBrakets )
+ {
+ if( DelCharAtEnd( sLvlText, ';' ).Len() &&
+ sLvlText.Len() && sLvlText.Len() ==
+ (sal_uInt16)(sLvlText.GetChar( 0 )) + 1 )
+ sLvlText.Erase( 0, 1 );
+ nLvlTxtLevel = 0;
+ }
+ if( nLvlNumberLevel == nNumOpenBrakets )
+ {
+ DelCharAtEnd( sLvlNumber, ';' );
+ nLvlNumberLevel = 0;
+ }
+ }
+ --nNumOpenBrakets;
+ break;
+
+ case '{':
+ {
+ if( RTF_IGNOREFLAG != GetNextToken() )
+ nToken = SkipToken( -1 );
+ // Unknown und alle bekannten nicht ausgewerteten Gruppen
+ // sofort ueberspringen
+ else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
+ nToken = SkipToken( -2 );
+ else
+ {
+ // gleich herausfiltern
+ ReadUnknownData();
+ nToken = GetNextToken();
+ if( '}' != nToken )
+ eState = SVPAR_ERROR;
+ break;
+ }
+ ++nNumOpenBrakets;
+ }
+ break;
+
+ case RTF_LEVELNFC:
+ {
+ sal_Int16 eType = SVX_NUM_ARABIC;
+ switch( nTokenValue )
+ {
+ case 1: eType = SVX_NUM_ROMAN_UPPER; break;
+ case 2: eType = SVX_NUM_ROMAN_LOWER; break;
+ case 3: eType = SVX_NUM_CHARS_UPPER_LETTER_N; break;
+ case 4: eType = SVX_NUM_CHARS_LOWER_LETTER_N; break;
+ case 255:
+ case 23: eType = SVX_NUM_CHAR_SPECIAL; break;
+ }
+ if( pCurNumFmt )
+ pCurNumFmt->SetNumberingType(eType);
+ }
+ break;
+
+ case RTF_LEVELJC:
+ {
+ SvxAdjust eAdj = SVX_ADJUST_LEFT;
+ switch( nTokenValue )
+ {
+ case 1: eAdj = SVX_ADJUST_CENTER; break;
+ case 2: eAdj = SVX_ADJUST_RIGHT; break;
+ }
+ if( pCurNumFmt )
+ pCurNumFmt->SetNumAdjust( eAdj );
+ }
+ break;
+
+ case RTF_LEVELSTARTAT:
+ if( pCurNumFmt && -1 != nTokenValue )
+ pCurNumFmt->SetStart( sal_uInt16( nTokenValue ));
+ break;
+
+ case RTF_LEVELTEXT:
+ nLvlTxtLevel = nNumOpenBrakets;
+ break;
+
+ case RTF_LEVELNUMBERS:
+ nLvlNumberLevel = nNumOpenBrakets;
+ break;
+
+
+ case RTF_TEXTTOKEN:
+ if( nLvlTxtLevel == nNumOpenBrakets )
+ sLvlText += aToken;
+ else if( nLvlNumberLevel == nNumOpenBrakets )
+ sLvlNumber += aToken;
+ break;
+
+ case RTF_LEVELFOLLOW:
+ /* removed; waiting for swnum02 to be integrated! */
+ switch (nTokenValue)
+ {
+ case 0:
+ eFollowedBy = SvxNumberFormat::LISTTAB;
+ break;
+ case 1:
+ eFollowedBy = SvxNumberFormat::SPACE;
+ break;
+ }
+ break;
+
+ case RTF_LEVELOLD:
+ case RTF_LEVELPREV:
+ case RTF_LEVELPREVSPACE:
+ case RTF_LEVELINDENT:
+ case RTF_LEVELSPACE:
+ case RTF_LEVELLEGAL:
+ case RTF_LEVELNORESTART:
+ break;
+
+ default:
+ if( pCurNumFmt && (
+ RTF_CHRFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ||
+ RTF_PARFMT == (nToken & ~(0xff | RTF_SWGDEFS) ) ))
+ {
+ SfxItemSet aSet( pDoc->GetAttrPool(), aTxtNodeSetRange );
+ // put the current CharFmtAttr into the set
+ SfxItemSet& rCFmtSet = GetNumChrFmt( *pDoc, rRule, nNumLvl );
+ aSet.Put( rCFmtSet );
+ // and put the current "LRSpace" into the set
+ {
+ SvxLRSpaceItem aLR( RES_LR_SPACE );
+ aLR.SetTxtLeft( pCurNumFmt->GetIndentAt() );
+ aLR.SetTxtFirstLineOfst(pCurNumFmt->GetFirstLineIndent());
+ aSet.Put( aLR );
+ }
+
+ ReadAttr( nToken, &aSet );
+
+ //#i24880# Word appears to ignore char background for numbering
+ aSet.ClearItem(RES_CHRATR_BACKGROUND);
+
+ // put all CharFmt Items into the charfmt
+ rCFmtSet.Put( aSet );
+
+ // test for LRSpace Item. If exist then set all relevant
+ // values on the numrule format
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == aSet.GetItemState( RES_LR_SPACE,
+ sal_False, &pItem ))
+ {
+ const SvxLRSpaceItem& rLR = *(SvxLRSpaceItem*)pItem;
+ pCurNumFmt->SetListtabPos( rLR.GetTxtLeft( ) );
+ pCurNumFmt->SetIndentAt( rLR.GetTxtLeft() );
+ pCurNumFmt->SetFirstLineIndent( rLR.GetTxtFirstLineOfst());
+ }
+
+ // dann aus der Vorlage den Font holen
+ if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
+ pCurNumFmt->SetBulletFont( FindFontOfItem(
+ pCurNumFmt->GetCharFmt()->GetFont() ) );
+ }
+ break;
+ }
+ }
+
+ if( IsParserWorking() && pCurNumFmt )
+ {
+ // dann erzeuge mal die Pre/Postfix-Strings
+ if( sLvlText.Len() &&
+ SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
+ {
+ pCurNumFmt->SetBulletChar( sLvlText.GetChar( 0 ) );
+ // dann aus der Vorlage den Font holen
+ if( pCurNumFmt->GetCharFmt() )
+ pCurNumFmt->SetBulletFont( FindFontOfItem(
+ pCurNumFmt->GetCharFmt()->GetFont() ) );
+ }
+ else if( sLvlNumber.Len() && sLvlText.Len() )
+ {
+ // in sLvlText steht der Text, in sLvlNumber die Position
+ // der Ebenen in sLvlText
+ pCurNumFmt->SetPrefix(
+ sLvlText.Copy( 0, sal_uInt16( sLvlNumber.GetChar( 0 ))-1 ));
+ pCurNumFmt->SetSuffix( sLvlText.Copy(
+ sal_uInt16( sLvlNumber.GetChar( sLvlNumber.Len()-1 )) ));
+ // wieviele Levels stehen im String?
+ pCurNumFmt->SetIncludeUpperLevels( (sal_uInt8)sLvlNumber.Len() );
+ }
+ else
+ {
+ pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
+ pCurNumFmt->SetSuffix( sLvlText );
+ }
+
+ /* removed; waiting for swnum02 to be integrated!*/
+ pCurNumFmt->SetLabelFollowedBy( eFollowedBy );
+ if (eFollowedBy == SvxNumberFormat::LISTTAB && !pCurNumFmt->IsItemize())
+ {
+ pCurNumFmt->SetIndentAt(0);
+ pCurNumFmt->SetFirstLineIndent(0);
+ }
+ }
+
+ SkipToken( -1 );
+}
+
+void SwRTFParser::ReadListTable()
+{
+ int nToken;
+ int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
+ bNewNumList = sal_True;
+
+ sal_uInt8 nNumLvl = 0;
+ SwNumRule* pCurRule = 0;
+ SwListEntry aEntry;
+
+ while( nNumOpenBrakets && IsParserWorking() )
+ {
+ switch( ( nToken = GetNextToken() ))
+ {
+ case '}': if( --nNumOpenBrakets && IsParserWorking() )
+ {
+ // Style konnte vollstaendig gelesen werden,
+ // also ist das noch ein stabiler Status
+ SaveState( RTF_LISTTABLE );
+ if( 1 == nNumOpenBrakets )
+ {
+ if( aEntry.nListId )
+ aListArr.push_back( aEntry );
+ aEntry.Clear();
+ }
+ }
+ break;
+
+ case '{':
+ {
+ if( RTF_IGNOREFLAG != GetNextToken() )
+ nToken = SkipToken( -1 );
+ // Unknown und alle bekannten nicht ausgewerteten Gruppen
+ // sofort ueberspringen
+ else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
+ nToken = SkipToken( -2 );
+ else
+ {
+ // gleich herausfiltern
+ ReadUnknownData();
+ nToken = GetNextToken();
+ if( '}' != nToken )
+ eState = SVPAR_ERROR;
+ break;
+ }
+ ++nNumOpenBrakets;
+ }
+ break;
+
+ case RTF_LIST:
+ {
+ if( pCurRule && pCurRule->IsContinusNum() )
+ lcl_ExpandNumFmts( *pCurRule );
+
+ String sTmp( String::CreateFromAscii(
+ RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
+ aEntry.nListDocPos = pDoc->MakeNumRule( sTmp, 0, sal_False, SvxNumberFormat::LABEL_ALIGNMENT );
+ pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
+ // #i91400#
+ pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ),
+ *pDoc );
+
+ pCurRule->SetAutoRule( sal_False );
+ nNumLvl = (sal_uInt8)-1;
+ }
+ break;
+
+ case RTF_LISTID: aEntry.nListId = nTokenValue; break;
+ case RTF_LISTTEMPLATEID: aEntry.nListTemplateId = nTokenValue; break;
+
+ case RTF_LISTRESTARTHDN:
+ break;
+ case RTF_LISTNAME:
+ if (nNextCh=='}') break; // empty listnames
+ if( RTF_TEXTTOKEN == GetNextToken() )
+ {
+ String sTmp( DelCharAtEnd( aToken, ';' ));
+ if( sTmp.Len() && !pDoc->FindNumRulePtr( sTmp ))
+ {
+ // #i91400#
+ pCurRule->SetName( sTmp, *pDoc );
+ }
+ }
+ SkipGroup();
+ break;
+
+ case RTF_LISTSIMPLE:
+ pCurRule->SetContinusNum( sal_True );
+ break;
+
+ case RTF_LISTLEVEL:
+ {
+ if( ++nNumLvl < MAXLEVEL )
+ pCurRule->Set( nNumLvl, pCurRule->Get( nNumLvl ));
+ ReadListLevel( *pCurRule, nNumLvl );
+ }
+ break;
+ }
+ }
+
+ if( pCurRule && pCurRule->IsContinusNum() )
+ lcl_ExpandNumFmts( *pCurRule );
+
+ SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
+}
+
+sal_Bool lcl_IsEqual( SwNumRule* pOrigRule, SwNumRule* pRule )
+{
+ sal_Bool bRet = 0;
+ if( pOrigRule && pRule )
+ {
+ bRet = pOrigRule->GetRuleType() == pRule->GetRuleType() &&
+ pOrigRule->IsContinusNum() == pRule->IsContinusNum() &&
+ pOrigRule->IsAbsSpaces() == pRule->IsAbsSpaces();
+ if( bRet )
+ for( sal_uInt8 n = 0; bRet && n < MAXLEVEL; ++n )
+ {
+ const SwNumFmt* pOFmt = pOrigRule->GetNumFmt( n ),
+ * pFmt = pRule->GetNumFmt( n );
+ if( pFmt && pOFmt )
+ {
+ SwCharFmt* pOCFmt = pOFmt->GetCharFmt(),
+ * pCFmt = pFmt->GetCharFmt();
+ if( pOCFmt && pCFmt )
+ {
+ bRet = 0 != (pCFmt->GetAttrSet() == pOCFmt->GetAttrSet());
+ }
+ else
+ bRet = !pCFmt && !pOCFmt;
+ if( bRet )
+ {
+ ((SwNumFmt*)pOFmt)->SetCharFmt( 0 );
+ ((SwNumFmt*)pFmt)->SetCharFmt( 0 );
+ bRet = *pOFmt == *pFmt;
+ ((SwNumFmt*)pOFmt)->SetCharFmt( pOCFmt );
+ ((SwNumFmt*)pFmt)->SetCharFmt( pCFmt );
+ }
+ }
+ else
+ bRet = !pFmt && !pOFmt;
+ }
+ }
+ return bRet;
+}
+
+void SwRTFParser::ReadListOverrideTable()
+{
+ int nToken;
+ int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
+ SwListEntry aEntry;
+ SwNumRule* pRule = 0, *pOrigRule = 0;
+ sal_uInt8 nNumLvl = 0;
+ sal_Bool bOverrideFormat = sal_False, bOverrideStart = sal_False;
+
+ while( nNumOpenBrakets && IsParserWorking() )
+ {
+ switch( ( nToken = GetNextToken() ))
+ {
+ case '}':
+ if( --nNumOpenBrakets && IsParserWorking() )
+ {
+ // Style konnte vollstaendig gelesen werden,
+ // also ist das noch ein stabiler Status
+ SaveState( RTF_LISTOVERRIDETABLE );
+
+ if( 1 == nNumOpenBrakets )
+ {
+ bOverrideFormat = sal_False, bOverrideStart = sal_False;
+ if( pRule )
+ {
+ if( lcl_IsEqual( pOrigRule, pRule ))
+ {
+ // no changes on the rule -> use the original rule
+ aEntry.nListDocPos = pDoc->FindNumRule(
+ pOrigRule->GetName() );
+ // delete the temp Rule
+ RemoveUnusedNumRule( pRule );
+ }
+ else if( pRule->IsContinusNum() )
+ lcl_ExpandNumFmts( *pRule );
+ }
+
+ if( aEntry.nListId && aEntry.nListNo )
+ {
+ int nMatch=-1;
+ for( size_t n = aListArr.size(); n; )
+ {
+ if( aListArr[ --n ].nListId == aEntry.nListId)
+ {
+ nMatch=n;
+ break;
+ }
+ }
+ if(nMatch>=0)
+ {
+ sal_uInt16 nMatch2 = static_cast< sal_uInt16 >(nMatch);
+ if (!aListArr[nMatch2].nListNo )
+ {
+ aListArr[nMatch2].nListNo = aEntry.nListNo;
+ }
+ else
+ {
+ aEntry.nListDocPos=aListArr[nMatch2].nListDocPos;
+ aEntry.nListTemplateId=aListArr[nMatch2].nListTemplateId;
+ aListArr.push_back( aEntry );
+ }
+ if(pOrigRule)
+ aListArr[nMatch2].nListDocPos = aEntry.nListDocPos;
+ }
+ }
+ aEntry.Clear();
+ pOrigRule = 0;
+ pRule = 0;
+ }
+ }
+ break;
+
+ case '{':
+ {
+ if( RTF_IGNOREFLAG != GetNextToken() )
+ nToken = SkipToken( -1 );
+ // Unknown und alle bekannten nicht ausgewerteten Gruppen
+ // sofort ueberspringen
+ else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
+ nToken = SkipToken( -2 );
+ else
+ {
+ // gleich herausfiltern
+ ReadUnknownData();
+ nToken = GetNextToken();
+ if( '}' != nToken )
+ eState = SVPAR_ERROR;
+ break;
+ }
+ ++nNumOpenBrakets;
+ }
+ break;
+
+ case RTF_LISTOVERRIDE: aEntry.Clear(); break;
+ case RTF_LISTID: aEntry.nListId = nTokenValue; break;
+ case RTF_LS: aEntry.nListNo = nTokenValue; break;
+ case RTF_LISTOVERRIDECOUNT:
+ if( nTokenValue )
+ {
+ pRule = 0;
+ // dann erzeugen wir mal schnell eine Kopie von der NumRule,
+ // denn diese wird jetzt mal kurz veraendert.
+ if( aEntry.nListId )
+ for( size_t n = 0; n < aListArr.size(); ++n )
+ if( aListArr[ n ].nListId == aEntry.nListId )
+ {
+ pRule = pDoc->GetNumRuleTbl()[
+ aListArr[ n ].nListDocPos ];
+ pOrigRule = pRule;
+
+ String sTmp( String::CreateFromAscii(
+ RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
+ aEntry.nListDocPos = pDoc->MakeNumRule( sTmp, pRule );
+ pRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
+ // #i91400#
+ pRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ),
+ *pDoc );
+
+ pRule->SetAutoRule( sal_False );
+ nNumLvl = (sal_uInt8)-1;
+ aListArr.push_back( aEntry );
+ break;
+ }
+
+ }
+ break;
+
+ case RTF_LISTLEVEL:
+ if( pRule && bOverrideFormat )
+ {
+ if( ++nNumLvl < MAXLEVEL )
+ pRule->Set( nNumLvl, pRule->Get( nNumLvl ));
+ ReadListLevel( *pRule, nNumLvl );
+ }
+ break;
+
+ case RTF_LEVELSTARTAT:
+ if( pRule && bOverrideStart )
+ {
+ }
+ break;
+
+ case RTF_LISTOVERRIDESTART:
+ bOverrideStart = sal_True;
+ break;
+
+ case RTF_LISTOVERRIDEFORMAT:
+ bOverrideFormat = sal_True;
+ break;
+
+ case RTF_LFOLEVEL:
+ // was fehlt noch?
+ break;
+ }
+ }
+
+ // search the outline numrule and set it into the doc
+ if( GetStyleTbl().Count() )
+ {
+ if( !bStyleTabValid )
+ MakeStyleTab();
+
+ const SfxPoolItem* pItem( 0 );
+ const SwTxtFmtColl* pColl( 0 );
+ sal_uInt16 nRulePos( USHRT_MAX );
+ const SwNumRule *pNumRule = 0;
+ SvxRTFStyleType* pStyle = GetStyleTbl().First();
+ do {
+ if ( MAXLEVEL > pStyle->nOutlineNo )
+ {
+ pColl = aTxtCollTbl.Get( (sal_uInt16)GetStyleTbl().GetCurKey() );
+ if ( pColl )
+ {
+ const SfxItemState eItemState =
+ pColl->GetItemState( RES_PARATR_NUMRULE, sal_False, &pItem );
+ if ( eItemState == SFX_ITEM_SET )
+ {
+ nRulePos = pDoc->FindNumRule( ((SwNumRuleItem*)pItem)->GetValue() );
+ if ( nRulePos != USHRT_MAX )
+ {
+ pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ];
+ if ( pNumRule->IsAutoRule() &&
+ pNumRule != pDoc->GetOutlineNumRule() )
+ {
+ pDoc->SetOutlineNumRule( *pNumRule );
+ pDoc->DelNumRule( pNumRule->GetName() );
+ // now pNumRule pointer is invalid !!!
+
+ // now decrement all position in the listtable, which will
+ // behind the doc-rule position
+ for( size_t n = aListArr.size(); n; )
+ {
+ SwListEntry& rEntry = aListArr[ --n ];
+ if( rEntry.nListDocPos == nRulePos )
+ aListArr.erase( aListArr.begin()+n );
+ else if( rEntry.nListDocPos > nRulePos )
+ --rEntry.nListDocPos;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // <--
+
+ pStyle->aAttrSet.ClearItem( FN_PARAM_NUM_LEVEL );
+
+ } while( 0 != (pStyle = GetStyleTbl().Next()) );
+ }
+
+ SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
+}
+
+SwNumRule* SwRTFParser::GetNumRuleOfListNo( long nListNo, sal_Bool bRemoveFromList )
+{
+ SwNumRule* pRet = 0;
+ SwListEntry* pEntry;
+ for( size_t n = aListArr.size(); n; )
+ if( ( pEntry = &aListArr[ --n ])->nListNo == nListNo )
+ {
+ if( bRemoveFromList )
+ aListArr.erase( aListArr.begin()+n );
+ else
+ {
+ pEntry->bRuleUsed = sal_True;
+ pRet = pDoc->GetNumRuleTbl()[ pEntry->nListDocPos ];
+ }
+ break;
+ }
+ return pRet;
+}
+
+void SwRTFParser::RemoveUnusedNumRule( SwNumRule* pRule )
+{
+ if( pRule )
+ {
+ for ( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
+ {
+ SwNumFmt& rNFmt = (SwNumFmt&)pRule->Get( nLvl );
+ SwCharFmt* pCFmt = rNFmt.GetCharFmt();
+ if( pCFmt )
+ {
+ rNFmt.ForgetCharFmt();
+ if( !pCFmt->GetDepends() )
+ pDoc->DelCharFmt( pCFmt );
+ }
+ }
+ pDoc->DelNumRule( pRule->GetName() );
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ OSL_ENSURE( pRule, "NumRulePointer 0 kann nicht geloescht werden" );
+ }
+#endif
+}
+
+void SwRTFParser::RemoveUnusedNumRules()
+{
+ SwListEntry* pEntry;
+ SvPtrarr aDelArr;
+ size_t n;
+ for( n = aListArr.size(); n; )
+ {
+ if( !( pEntry = &aListArr[ --n ])->bRuleUsed )
+ {
+ // really *NOT* used by anyone else?
+ sal_Bool unused=sal_True;
+ for(size_t j = 0; j < aListArr.size(); ++j)
+ {
+ if (aListArr[n].nListNo==aListArr[j].nListNo)
+ unused&=!aListArr[j].bRuleUsed;
+ }
+ if (unused)
+ {
+ void * p = pDoc->GetNumRuleTbl()[pEntry->nListDocPos];
+ // dont delete named char formats
+ if( USHRT_MAX == aDelArr.GetPos( p ) &&
+ ((SwNumRule*)p)->GetName().EqualsAscii( RTF_NUMRULE_NAME, 0,
+ sizeof( RTF_NUMRULE_NAME )) )
+ aDelArr.Insert( p, aDelArr.Count() );
+ }
+ }
+ }
+
+ for( n = aDelArr.Count(); n; )
+ {
+ SwNumRule* pDel = (SwNumRule*)aDelArr[ --n ];
+ RemoveUnusedNumRule( pDel );
+ }
+}
+
+const Font* SwRTFParser::FindFontOfItem( const SvxFontItem& rItem ) const
+{
+ SvxRTFFontTbl& rFntTbl = ((SwRTFParser*)this)->GetFontTbl();
+ const Font* pFnt = rFntTbl.First();
+ while( pFnt )
+ {
+ if( pFnt->GetFamily() == rItem.GetFamily() &&
+ pFnt->GetName() == rItem.GetFamilyName() &&
+ pFnt->GetStyleName() == rItem.GetStyleName() &&
+ pFnt->GetPitch() == rItem.GetPitch() &&
+ pFnt->GetCharSet() == rItem.GetCharSet() )
+ return pFnt;
+
+ pFnt = rFntTbl.Next();
+ }
+ return 0;
+}
+
+
+SwNumRule *SwRTFParser::ReadNumSecLevel( int nToken )
+{
+ // lese die \pnseclvl - Gruppe
+ // nTokenValue gibt schon den richtigen Level vor 1 - 9!
+ sal_uInt8 nLevel = 0;
+ long nListNo = 0;
+ sal_Bool bContinus = sal_True;
+
+ if( RTF_PNSECLVL == nToken )
+ {
+ // suche die Rule - steht unter Nummer 3
+ nListNo = 3;
+ bContinus = sal_False;
+ nLevel = MAXLEVEL <= (unsigned long) nTokenValue ? MAXLEVEL - 1
+ : (!nTokenValue ? 0 : sal_uInt8( nTokenValue - 1 ));
+ }
+ else
+ {
+ switch( nToken = GetNextToken() )
+ {
+ case RTF_PNLVL: nListNo = 3;
+ bContinus = sal_False;
+ nLevel = MAXLEVEL <= (unsigned long) nTokenValue
+ ? MAXLEVEL - 1
+ : (!nTokenValue ? 0 : sal_uInt8( nTokenValue-1 ));
+ break;
+
+ case RTF_PNLVLBODY:
+ nListNo = 2;
+ break;
+ case RTF_PNLVLBLT:
+ nListNo = 1;
+ break;
+ case RTF_PNLVLCONT:
+ SkipGroup();
+ return 0;
+ default:
+ SkipGroup();
+ return 0;
+ }
+ }
+
+ // suche die Rule - steht unter Nummer 3
+ sal_uInt16 nNewFlag = static_cast< sal_uInt16 >(1 << nListNo);
+ SwNumRule* pCurRule = GetNumRuleOfListNo( nListNo,
+ 0 != ( nNewNumSectDef & nNewFlag ) );
+ if( !pCurRule )
+ {
+ // dann muessen wir die mal anlegen
+ nNewNumSectDef &= ~nNewFlag;
+ String sTmp( String::CreateFromAscii(
+ RTL_CONSTASCII_STRINGPARAM( RTF_NUMRULE_NAME " 1" )));
+ SwListEntry aEntry( nListNo, 0, pDoc->MakeNumRule( sTmp ));
+ aEntry.nListNo = nListNo;
+ aListArr.push_back( aEntry );
+ pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
+ // #i91400#
+ pCurRule->SetName( pDoc->GetUniqueNumRuleName( &sTmp, sal_False ), *pDoc );
+
+ pCurRule->SetAutoRule( sal_False );
+ pCurRule->SetContinusNum( bContinus );
+ }
+
+ if( !pCurRule->GetNumFmt( nLevel ))
+ pCurRule->Set( nLevel, pCurRule->Get( nLevel ));
+ SwNumFmt* pCurNumFmt = (SwNumFmt*)pCurRule->GetNumFmt( nLevel );
+ if( RTF_PNLVLBLT == nToken )
+ pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ pCurNumFmt->SetSuffix( aEmptyStr );
+ pCurNumFmt->SetPrefix( aEmptyStr );
+ pCurNumFmt->SetNumberingType(SVX_NUM_NUMBER_NONE);
+
+ if( bStyleTabValid && RTF_PNSECLVL != nToken )
+ {
+ // dann den akt. Lvl und Rule am Absatz setzen.
+ // Dieses muss aber in den vorherigen "Kontext", sprich in den vor
+ // der Klammer offenen Attrset. Darum das SetNewGroup davor und dahinter
+ SetNewGroup( sal_False );
+ GetAttrSet().Put( SfxUInt16Item( FN_PARAM_NUM_LEVEL, nLevel ));
+ GetAttrSet().Put( SwNumRuleItem( pCurRule->GetName() ));
+ SetNewGroup( sal_True );
+ }
+
+ FontUnderline eUnderline;
+ int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
+ while( nNumOpenBrakets && IsParserWorking() )
+ {
+ switch( ( nToken = GetNextToken() ))
+ {
+ case '}':
+ if( --nNumOpenBrakets && IsParserWorking() )
+ {
+ // Style konnte vollstaendig gelesen werden,
+ // also ist das noch ein stabiler Status
+ SaveState( RTF_PNSECLVL );
+ }
+ break;
+
+ case '{':
+ {
+ if( RTF_IGNOREFLAG != GetNextToken() )
+ nToken = SkipToken( -1 );
+ // Unknown und alle bekannten nicht ausgewerteten Gruppen
+ // sofort ueberspringen
+ else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ))
+ nToken = SkipToken( -2 );
+ else
+ {
+ // gleich herausfiltern
+ ReadUnknownData();
+ nToken = GetNextToken();
+ if( '}' != nToken )
+ eState = SVPAR_ERROR;
+ break;
+ }
+ ++nNumOpenBrakets;
+ }
+ break;
+
+ case RTF_PNCARD:
+ case RTF_PNORD:
+ case RTF_PNORDT:
+ case RTF_PNDEC: pCurNumFmt->SetNumberingType(SVX_NUM_ARABIC); break;
+ case RTF_PNUCLTR: pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER_N); break;
+ case RTF_PNUCRM: pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_UPPER); break;
+ case RTF_PNLCLTR: pCurNumFmt->SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER_N); break;
+ case RTF_PNLCRM: pCurNumFmt->SetNumberingType(SVX_NUM_ROMAN_LOWER); break;
+
+ case RTF_PNF:
+ {
+ const Font& rSVFont = GetFont( sal_uInt16(nTokenValue) );
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
+ SvxFontItem( rSVFont.GetFamily(),
+ rSVFont.GetName(), rSVFont.GetStyleName(),
+ rSVFont.GetPitch(), rSVFont.GetCharSet(),
+ RES_CHRATR_FONT ));
+ if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
+ pCurNumFmt->SetBulletFont( &rSVFont );
+ }
+ break;
+ case RTF_PNFS:
+ {
+ if( -1 == nTokenValue )
+ nTokenValue = 240;
+ else
+ nTokenValue *= 10;
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
+ SvxFontHeightItem( (const sal_uInt16)nTokenValue, 100, RES_CHRATR_FONTSIZE ));
+ }
+ break;
+
+ case RTF_PNB:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxWeightItem(
+ nTokenValue ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT ));
+ }
+ break;
+
+ case RTF_PNI:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxPostureItem(
+ nTokenValue ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE ));
+ }
+ break;
+
+ case RTF_PNCAPS:
+ case RTF_PNSCAPS:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCaseMapItem(
+ nTokenValue ? SVX_CASEMAP_KAPITAELCHEN
+ : SVX_CASEMAP_NOT_MAPPED, RES_CHRATR_CASEMAP ));
+ }
+ break;
+ case RTF_PNSTRIKE:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxCrossedOutItem(
+ nTokenValue ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ));
+ }
+ break;
+
+ case RTF_PNCF:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put( SvxColorItem(
+ GetColor( sal_uInt16(nTokenValue) ), RES_CHRATR_COLOR ));
+ }
+ break;
+
+
+ case RTF_PNUL:
+ eUnderline = nTokenValue ? UNDERLINE_SINGLE : UNDERLINE_NONE;
+ goto NUMATTR_SETUNDERLINE;
+ case RTF_PNULD:
+ eUnderline = UNDERLINE_DOTTED;
+ goto NUMATTR_SETUNDERLINE;
+ case RTF_PNULDB:
+ eUnderline = UNDERLINE_DOUBLE;
+ goto NUMATTR_SETUNDERLINE;
+ case RTF_PNULNONE:
+ eUnderline = UNDERLINE_NONE;
+ goto NUMATTR_SETUNDERLINE;
+ case RTF_PNULW:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
+ SvxWordLineModeItem( sal_True, RES_CHRATR_WORDLINEMODE ));
+ }
+ eUnderline = UNDERLINE_SINGLE;
+ goto NUMATTR_SETUNDERLINE;
+
+NUMATTR_SETUNDERLINE:
+ {
+ GetNumChrFmt( *pDoc, *pCurRule, nLevel ).Put(
+ SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
+ }
+ break;
+
+ case RTF_PNINDENT:
+ if( 0 > short( nTokenValue ) )
+ nTokenValue = - (short)nTokenValue;
+ pCurNumFmt->SetFirstLineIndent( - nTokenValue );
+ pCurNumFmt->SetIndentAt( (nLevel + 1 ) * nTokenValue );
+ break;
+ case RTF_PNSP:
+ pCurNumFmt->SetCharTextDistance( sal_uInt16( nTokenValue ));
+ break;
+
+ case RTF_PNPREV:
+ if( nLevel )
+ {
+ sal_uInt8 nPrev = 2, nLast = nLevel;
+ while( nLast && 1 < pCurRule->Get( --nLast ).GetIncludeUpperLevels() )
+ ++nPrev;
+ pCurNumFmt->SetIncludeUpperLevels( nPrev );
+ }
+ break;
+
+ case RTF_PNQC: pCurNumFmt->SetNumAdjust( SVX_ADJUST_CENTER ); break;
+ case RTF_PNQL: pCurNumFmt->SetNumAdjust( SVX_ADJUST_LEFT ); break;
+ case RTF_PNQR: pCurNumFmt->SetNumAdjust( SVX_ADJUST_RIGHT ); break;
+
+ case RTF_PNSTART:
+ pCurNumFmt->SetStart( sal_uInt16( nTokenValue ));
+ break;
+
+ case RTF_PNNUMONCE:
+ case RTF_PNACROSS:
+ case RTF_PNHANG:
+ case RTF_PNRESTART: break;
+
+ case RTF_PNTXTA:
+ {
+ String sTmp;
+ GetTextToEndGroup( sTmp );
+ if( SVX_NUM_CHAR_SPECIAL == pCurNumFmt->GetNumberingType() )
+ {
+ pCurNumFmt->SetBulletChar( sTmp.GetChar( 0 ) );
+ if( pCurNumFmt->GetCharFmt() )
+ pCurNumFmt->SetBulletFont( FindFontOfItem(
+ pCurNumFmt->GetCharFmt()->GetFont() ) );
+ sTmp.Erase();
+ }
+ pCurNumFmt->SetSuffix( sTmp );
+ }
+ break;
+
+ case RTF_PNTXTB:
+ {
+ String sTmp;
+ pCurNumFmt->SetPrefix( GetTextToEndGroup( sTmp ) );
+ }
+ break;
+ }
+ }
+
+ // falls vollstaendige Numerierung an ist und das Zeichen davor ein
+ // Punkt ist, dann will RTF den Punkt als Trenner zwischen den Ebenen
+ // haben - das haben wir aber schon als default
+ if( 1 < pCurNumFmt->GetIncludeUpperLevels() &&
+ 1 == pCurNumFmt->GetPrefix().Len() &&
+ '.' == pCurNumFmt->GetPrefix().GetChar( 0 ) &&
+ SVX_NUM_CHAR_SPECIAL != pCurNumFmt->GetNumberingType() )
+ pCurNumFmt->SetPrefix( aEmptyStr );
+
+ // falls das ein nicht numerierter Absatz mit ein Prefix-Text mit
+ // einem Zeichen ist, dann setze den als Bulletzeichen
+ if( pCurNumFmt->GetCharFmt() && SVX_NUM_NUMBER_NONE == pCurNumFmt->GetNumberingType() &&
+ 3 == nListNo && 1 == pCurNumFmt->GetPrefix().Len() )
+ {
+ SwCharFmt* pChFmt = pCurNumFmt->GetCharFmt();
+ pCurNumFmt->SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ pCurNumFmt->SetBulletFont( FindFontOfItem( pChFmt->GetFont() ) );
+
+ pCurNumFmt->SetBulletChar( pCurNumFmt->GetPrefix().GetChar( 0 ) );
+ pCurNumFmt->SetPrefix( aEmptyStr );
+
+ // den Font oder sogar das gesamte CharFormat loeschen?
+ if( SFX_ITEM_SET == pChFmt->GetItemState( RES_CHRATR_FONT, sal_False ))
+ {
+ if( 1 == pChFmt->GetAttrSet().Count() )
+ {
+ pCurNumFmt->SetCharFmt( 0 );
+ pDoc->DelCharFmt( pChFmt );
+ }
+ else
+ pChFmt->ResetFmtAttr( RES_CHRATR_FONT );
+ }
+ }
+
+ SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
+ return pCurRule;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */