blob: d3fabe56d78c152dc4ac2598895285554fc8978a [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// 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 <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>
#ifndef _CMDID_H
#include <cmdid.h>
#endif
#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.SetAbsLSpace( aNumFmt.GetAbsLSpace() * ( 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;
String aStringFollow = aEmptyStr;
if( MAXLEVEL >= nNumLvl )
{
pCurNumFmt = (SwNumFmt*)rRule.GetNumFmt( nNumLvl );
pCurNumFmt->SetAbsLSpace( 0 );
pCurNumFmt->SetFirstLineOffset( 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() ))
// RTF_PANOSE != nToken && RTF_FALT != nToken &&
// RTF_FALT != nToken && RTF_FNAME != nToken &&
// RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
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:
aStringFollow=String('\t');
break;
case 1:
aStringFollow=String(' ');
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->GetAbsLSpace() );
aLR.SetTxtFirstLineOfst(pCurNumFmt->GetFirstLineOffset());
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->SetAbsLSpace( static_cast< short >(rLR.GetTxtLeft()) );
pCurNumFmt->SetFirstLineOffset( 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 );
}
String newSuffix=pCurNumFmt->GetSuffix();
newSuffix+=aStringFollow;
pCurNumFmt->SetSuffix(newSuffix);
/* removed; waiting for swnum02 to be integrated!
if (aStringFollow.GetChar(0)=='\t' && !pCurNumFmt->IsItemize())
{
pCurNumFmt->SetAbsLSpace(0);
pCurNumFmt->SetFirstLineOffset(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() ))
// RTF_PANOSE != nToken && RTF_FALT != nToken &&
// RTF_FALT != nToken && RTF_FNAME != nToken &&
// RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
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 );
pCurRule = pDoc->GetNumRuleTbl()[ aEntry.nListDocPos ];
// --> OD 2008-07-08 #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; // #118989# empty listnames
if( RTF_TEXTTOKEN == GetNextToken() )
{
String sTmp( DelCharAtEnd( aToken, ';' ));
if( sTmp.Len() && !pDoc->FindNumRulePtr( sTmp ))
{
// --> OD 2008-07-08 #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 ];
// --> OD 2008-07-08 #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 {
// --> OD 2007-12-17 #151213#
// suppress deletion of outline list style.
// refactoring of code: no assignments in if-condition
// if( MAXLEVEL > pStyle->nOutlineNo &&
// 0 != ( pColl = aTxtCollTbl.Get( (sal_uInt16)GetStyleTbl().
// GetCurKey() )) &&
// SFX_ITEM_SET == pColl->GetItemState( RES_PARATR_NUMRULE,
// sal_False, &pItem ) &&
// USHRT_MAX != (nRulePos = pDoc->FindNumRule(
// ((SwNumRuleItem*)pItem)->GetValue() )) &&
// (pNumRule = pDoc->GetNumRuleTbl()[ nRulePos ])->IsAutoRule() )
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() );
}
#ifdef DBG_UTIL
else
{
ASSERT( 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 ];
// --> OD 2008-07-08 #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->SetFirstLineOffset( - short( nTokenValue ));
pCurNumFmt->SetAbsLSpace( (nLevel + 1 ) * sal_uInt16( 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;
}
/* */
// dann noch die Ausgabe-Funktionen (nur fuer WinWord 97)
sal_Bool lcl_IsExportNumRule( const SwNumRule& rRule, sal_uInt8* pEnd = 0 )
{
sal_uInt8 nEnd = MAXLEVEL;
while( nEnd-- && !rRule.GetNumFmt( nEnd ))
;
++nEnd;
const SwNumFmt* pNFmt;
sal_uInt8 nLvl;
for( nLvl = 0; nLvl < nEnd; ++nLvl )
if( SVX_NUM_NUMBER_NONE != ( pNFmt = &rRule.Get( nLvl ))
->GetNumberingType() || pNFmt->GetPrefix().Len() ||
(pNFmt->GetSuffix().Len() && pNFmt->GetSuffix() != aDotStr ))
break;
if( pEnd )
*pEnd = nEnd;
return nLvl != nEnd;
}