blob: c6a2b52a0a11c16964f8343c508eb4358a038676 [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"
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
#include <ctype.h>
#include <hintids.hxx>
#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
#include <com/sun/star/i18n/ScriptType.hdl>
#endif
#ifndef _GRAPH_HXX //autogen
#include <vcl/graph.hxx>
#endif
#include <svl/urihelper.hxx>
#include <svtools/rtftoken.h>
#include <svl/zforlist.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/brkitem.hxx>
#include <fmtfld.hxx>
#include <fmtinfmt.hxx>
#include <swtypes.hxx>
#include <doc.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <shellio.hxx>
#include <fldbas.hxx>
#include <swparrtf.hxx>
#include <txatbase.hxx>
#include <dbfld.hxx>
#include <usrfld.hxx>
#include <docufld.hxx>
#include <flddat.hxx>
#include <charfmt.hxx>
#ifndef _fmtruby_HXX
#include <fmtruby.hxx>
#endif
#include <breakit.hxx>
#include <reffld.hxx>
#include <SwStyleNameMapper.hxx>
#include <editeng/charhiddenitem.hxx>
// bestimme, ob es sich um ein IMPORT/TOC - Feld handelt.
// return: 0 - weder noch,
// 1 - TOC
// 2 - IMPORT
// 3 - INDEX
enum RTF_FLD_TYPES {
RTFFLD_UNKNOWN = 0,
RTFFLD_TOC,
RTFFLD_IMPORT,
RTFFLD_INDEX,
RTFFLD_SYMBOL,
RTFFLD_PAGE,
RTFFLD_NUMPAGES,
RTFFLD_DATE,
RTFFLD_TIME,
RTFFLD_DATA,
RTFFLD_MERGEFLD,
RTFFLD_HYPERLINK,
RTFFLD_REF,
RTFFLD_PAGEREF,
RTFFLD_EQ,
RTFFLD_INCLUDETEXT
};
static RTF_FLD_TYPES _WhichFld( String& rName, String& rNext )
{
// Strings sind PascalStrings; Laenge steht an 1. Stellen, dadurch wird
// sich der Aufruf von strlen erspart!!!
sal_Char __READONLY_DATA sTOC[]= "\x03""toc";
sal_Char __READONLY_DATA sIMPORT[]= "\x06""import";
sal_Char __READONLY_DATA sINDEX[]= "\x05""index";
sal_Char __READONLY_DATA sSYMBOL[]= "\x06""symbol";
sal_Char __READONLY_DATA sPAGE[]= "\x04""page";
sal_Char __READONLY_DATA sNUMPAGES[]= "\x08""numpages";
sal_Char __READONLY_DATA sDATE[]= "\x04""date";
sal_Char __READONLY_DATA sTIME[]= "\x04""time";
sal_Char __READONLY_DATA sDATA[]= "\x04""data";
sal_Char __READONLY_DATA sMERGEFLD[]= "\x0A""mergefield";
sal_Char __READONLY_DATA sIMPORT2[]= "\x0E""includepicture";
sal_Char __READONLY_DATA sHYPERLINK[]= "\x09""hyperlink";
sal_Char __READONLY_DATA sREF[]= "\x03""ref";
sal_Char __READONLY_DATA sPAGEREF[]= "\x07""pageref";
sal_Char __READONLY_DATA sEQ[]= "\x02""eq";
sal_Char __READONLY_DATA sINCLUDETEXT[]="\x0B""includetext";
struct _Dummy_RTF_FLD_TYPES
{
RTF_FLD_TYPES eFldType;
const sal_Char* pFldNm;
};
__READONLY_DATA _Dummy_RTF_FLD_TYPES aFldNmArr[RTFFLD_INCLUDETEXT + 1] = {
{RTFFLD_TOC, sTOC},
{RTFFLD_IMPORT, sIMPORT},
{RTFFLD_INDEX, sINDEX},
{RTFFLD_SYMBOL, sSYMBOL},
{RTFFLD_PAGE, sPAGE},
{RTFFLD_NUMPAGES, sNUMPAGES},
{RTFFLD_DATE, sDATE},
{RTFFLD_TIME, sTIME},
{RTFFLD_DATA, sDATA},
{RTFFLD_MERGEFLD, sMERGEFLD},
{RTFFLD_IMPORT, sIMPORT2},
{RTFFLD_HYPERLINK, sHYPERLINK},
{RTFFLD_REF, sREF},
{RTFFLD_PAGEREF, sPAGEREF},
{RTFFLD_EQ, sEQ},
{RTFFLD_INCLUDETEXT, sINCLUDETEXT}
};
if( !rName.Len() )
return RTFFLD_UNKNOWN;
String sNm( rName );
sNm = sNm.EraseLeadingChars().GetToken(0, ' ');
ASSERT( sNm.Len(), "Feldname hat keine Laenge!" );
if( !sNm.Len() )
return RTFFLD_UNKNOWN;
xub_StrLen nTokenStt = rName.Search( sNm );
sNm.ToLowerAscii();
for (size_t n = 0; n < sizeof(aFldNmArr) / sizeof(aFldNmArr[0]); ++n)
{
const sal_Char* pCmp = aFldNmArr[n].pFldNm;
int nLen = *pCmp++;
xub_StrLen nFndPos = sNm.SearchAscii( pCmp );
if( STRING_NOTFOUND != nFndPos &&
( !nFndPos || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos-1) )) ) &&
( nFndPos+nLen == sNm.Len() || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos+nLen) ) ) ) )
{
// rName = sNm.Copy( nFndPos, nLen );
rName = rName.Copy( nFndPos, static_cast< xub_StrLen >(nLen) );
nFndPos += nTokenStt + static_cast< xub_StrLen >(nLen);
while ((nFndPos < rNext.Len()) && (rNext.GetChar(nFndPos) == ' '))
{
++nFndPos;
}
rNext.Erase( 0, nFndPos );
rNext.EraseTrailingChars();
return aFldNmArr[n].eFldType;
}
}
return RTFFLD_UNKNOWN; // nichts gefunden.
}
static sal_uInt16 CheckNumberFmtStr( const String& rNStr )
{
const static sal_Char* aNumberTypeTab[] =
{
"\x0A""ALPHABETIC", /* CHARS_UPPER_LETTER*/
"\x0A""alphabetic", /* CHARS_LOWER_LETTER*/
"\x05""ROMAN", /* ROMAN_UPPER */
"\x05""roman", /* ROMAN_LOWER */
"\x06""ARABIC", /* ARABIC */
"\x04""NONE", /* NUMBER_NONE */
"\x04""CHAR", /* CHAR_SPECIAL */
"\x04""PAGE" /* PAGEDESC */
};
ASSERT(sizeof(aNumberTypeTab) / sizeof(sal_Char *)
>= SVX_NUM_PAGEDESC - SVX_NUM_CHARS_UPPER_LETTER, "impossible");
for (sal_uInt16 n = SVX_NUM_CHARS_UPPER_LETTER; n <= SVX_NUM_PAGEDESC; ++n)
{
const sal_Char* pCmp = aNumberTypeTab[n - SVX_NUM_CHARS_UPPER_LETTER];
int nLen = *pCmp++;
if( rNStr.EqualsAscii( pCmp, 0, static_cast< xub_StrLen >(nLen) ))
return static_cast< sal_uInt16 >(2 <= n ? n : (n + SVX_NUM_CHARS_UPPER_LETTER_N));
}
return SVX_NUM_PAGEDESC; // default-Wert
}
class RtfFieldSwitch
{
String sParam;
xub_StrLen nCurPos;
public:
RtfFieldSwitch( const String& rParam );
sal_Unicode GetSwitch( String& rParam );
sal_Bool IsAtEnd() const { return nCurPos >= sParam.Len(); }
xub_StrLen GetCurPos() const { return nCurPos; }
void Erase( xub_StrLen nEndPos ) { sParam.Erase( 0, nEndPos ); }
void Insert( const String& rIns ) { sParam.Insert( rIns, 0 ); }
const String& GetStr() const { return sParam; }
};
RtfFieldSwitch::RtfFieldSwitch( const String& rParam )
: sParam( rParam ), nCurPos( 0 )
{
sParam.EraseTrailingChars().EraseLeadingChars();
}
sal_Unicode RtfFieldSwitch::GetSwitch( String& rParam )
{
// beginnt ein Schalter?
sal_Unicode c, cKey = 0;
if( '\\' == (c = sParam.GetChar( nCurPos )) )
{
if( '\\' == ( c = sParam.GetChar( ++nCurPos )) )
c = sParam.GetChar( ++nCurPos );
cKey = c;
while( ++nCurPos < sParam.Len() &&
' ' == ( c = sParam.GetChar( nCurPos )) )
;
}
// dann alles in Hochkommatas oder bis zum naechsten // als
// Param returnen
sal_uInt16 nOffset;
if( '"' != c && '\'' != c )
c = '\\', nOffset = 0;
else
nOffset = 1;
sParam.Erase( 0, nCurPos + nOffset );
rParam = sParam.GetToken( 0, c );
sParam.Erase( 0, rParam.Len() + nOffset ).EraseLeadingChars();
if( '\\' == c )
rParam.EraseTrailingChars();
nCurPos = 0;
return cKey;
}
struct RTF_EquationData
{
String sFontName, sUp, sDown, sText;
sal_Int32 nJustificationCode, nFontSize, nUp, nDown, nStyleNo;
inline RTF_EquationData()
: nJustificationCode(0), nFontSize(0), nUp(0), nDown(0),
nStyleNo( -1 )
{}
};
xub_StrLen lcl_FindEndBracket( const String& rStr )
{
xub_StrLen nEnd = rStr.Len(), nRet = STRING_NOTFOUND, nPos = 0;
int nOpenCnt = 1;
sal_Unicode cCh;
for( ; nPos < nEnd; ++nPos )
if( ')' == (cCh = rStr.GetChar( nPos )) && !--nOpenCnt )
{
nRet = nPos;
break;
}
else if( '(' == cCh )
++nOpenCnt;
return nRet;
}
void lcl_ScanEquationField( const String& rStr, RTF_EquationData& rData,
sal_Unicode nSttKey )
{
int nSubSupFlag(0);
RtfFieldSwitch aRFS( rStr );
while( !aRFS.IsAtEnd() )
{
String sParam;
sal_Unicode cKey = aRFS.GetSwitch( sParam );
if( 1 == nSubSupFlag )
++nSubSupFlag;
else if( 1 < nSubSupFlag )
nSubSupFlag = 0;
sal_Bool bCheckBracket = sal_False;
switch( cKey )
{
case 0:
switch( nSttKey )
{
case 'u': rData.sUp += sParam; break;
case 'd': rData.sDown += sParam; break;
default: rData.sText += sParam; break;
}
break;
case '*':
if( sParam.Len() )
{
if( sParam.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
rData.nJustificationCode = sParam.Copy( 2 ).ToInt32();
else if( sParam.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
rData.nFontSize= sParam.Copy( 3 ).ToInt32();
else if( sParam.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
rData.sFontName = sParam.Copy( 5 );
else if( sParam.EqualsIgnoreCaseAscii( "cs", 0, 2 ) )
rData.nStyleNo = sParam.Copy( 2 ).ToInt32();
}
break;
case 's' :
++nSubSupFlag;
break;
case 'u':
if( sParam.Len() && 'p' == sParam.GetChar( 0 ) &&
2 == nSubSupFlag )
{
rData.nUp = sParam.Copy( 1 ).ToInt32();
bCheckBracket = sal_True;
}
break;
case 'd':
if( sParam.Len() && 'o' == sParam.GetChar( 0 ) &&
2 == nSubSupFlag )
{
rData.nDown = sParam.Copy( 1 ).ToInt32();
bCheckBracket = sal_True;
}
break;
default:
bCheckBracket = sal_True;
cKey = 0;
break;
}
if( bCheckBracket && sParam.Len() )
{
xub_StrLen nEnd, nStt = sParam.Search( '(' ),
nLen = sParam.Len();
if( STRING_NOTFOUND != nStt )
{
sParam.Erase( 0, nStt + 1 ) += aRFS.GetStr();
if( STRING_NOTFOUND !=
(nEnd = ::lcl_FindEndBracket( sParam )) )
{
// end in the added string?
if( (nLen - nStt - 1 ) < nEnd )
aRFS.Erase( nEnd + 1 - (nLen - nStt - 1));
else
{
// not all handled here, so set new into the RFS
aRFS.Insert( sParam.Copy( nEnd + 1,
nLen - nStt - nEnd - 2 ));
sal_Unicode cCh;
if( aRFS.GetStr().Len() &&
( ',' == (cCh = aRFS.GetStr().GetChar(0)) ||
';' == cCh ))
aRFS.Erase( 1 );
}
::lcl_ScanEquationField( sParam.Copy( 0, nEnd ),
rData, cKey );
}
}
}
}
}
int SwRTFParser::MakeFieldInst( String& rFieldStr )
{
// sicher den Original-String fuer die FeldNamen (User/Datenbank)
String aSaveStr( rFieldStr );
SwFieldType * pFldType;
int nRet = _WhichFld(rFieldStr, aSaveStr);
//Strip Mergeformat from fields
xub_StrLen nPos=0;
while (STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii("\\*", nPos)))
{
xub_StrLen nStartDel = nPos;
nPos += 2;
while ((nPos < aSaveStr.Len()) && (aSaveStr.GetChar(nPos) == ' '))
{
++nPos;
}
if (aSaveStr.EqualsIgnoreCaseAscii("MERGEFORMAT", nPos, 11))
{
xub_StrLen nNoDel = (nPos + 11 ) - nStartDel;
aSaveStr.Erase(nStartDel, nNoDel);
nPos -= (nStartDel - nPos);
}
}
nPos = 0;
switch (nRet)
{
case RTFFLD_INCLUDETEXT:
break;
case RTFFLD_IMPORT:
{
//JP 11.03.96: vertraegt sich nicht so ganz mit Internet!
// if( STRING_NOTFOUND != ( nPos = aSaveStr.Search( '.' )))
// aSaveStr.Erase( nPos+4 );
aSaveStr.EraseLeadingAndTrailingChars();
if( aSaveStr.Len() )
{
sal_Unicode c = aSaveStr.GetChar( 0 );
if( '"' == c || '\'' == c )
{
aSaveStr.Erase( 0, 1 );
aSaveStr = aSaveStr.GetToken( 0, c );
}
rFieldStr = URIHelper::SmartRel2Abs(
INetURLObject(GetBaseURL()), aSaveStr,
URIHelper::GetMaybeFileHdl() );
}
// SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_NUMPAGES:
{
SwDocStatField aFld( (SwDocStatFieldType*)pDoc->GetSysFldType( RES_DOCSTATFLD ),
DS_PAGE, SVX_NUM_ARABIC );
if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
{
nPos += 2;
while ((nPos < aSaveStr.Len()) &&
(aSaveStr.GetChar(nPos) == ' '))
{ nPos++; }
aSaveStr.Erase( 0, nPos );
// steht jetzt geanu auf dem Format-Namen
aFld.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
}
pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
SkipGroup();
}
break;
case RTFFLD_PAGE:
{
pFldType = pDoc->GetSysFldType( RES_PAGENUMBERFLD );
SwPageNumberField aPF( (SwPageNumberFieldType*)pFldType,
PG_RANDOM, SVX_NUM_ARABIC);
if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
{
nPos += 2;
while ((nPos < aSaveStr.Len()) &&
(aSaveStr.GetChar(nPos) == ' '))
{ nPos++; }
aSaveStr.Erase( 0, nPos );
// steht jetzt geanu auf dem Format-Namen
aPF.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
}
pDoc->InsertPoolItem( *pPam, SwFmtFld( aPF ), 0 );
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_DATE:
case RTFFLD_TIME:
{
if( STRING_NOTFOUND == ( nPos = aSaveStr.SearchAscii( "\\@" )) )
{
// es fehlt die Format - Angabe: defaulten auf Datum
pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDateTimeField(
static_cast<SwDateTimeFieldType*>(pFldType), DATEFLD)), 0);
}
else
{
// versuche aus dem Formatstring zu erkennen, ob es ein
// Datum oder Zeit oder Datum & Zeit Field ist
// nur das Format interressiert
aSaveStr.Erase( 0, aSaveStr.Search( '\"' )+1 );
// alles hinter dem Format interressiert auch nicht mehr.
aSaveStr.Erase( aSaveStr.Search( '\"' ) );
aSaveStr.SearchAndReplaceAscii( "AM", aEmptyStr );
aSaveStr.SearchAndReplaceAscii( "PM", aEmptyStr );
// #117892# M.M. Put the word date and time formatter stuff in a common area
// and get the rtf filter to use it
SwField *pFld = 0;
short nNumFmtType = NUMBERFORMAT_UNDEFINED;
sal_uLong nFmtIdx = NUMBERFORMAT_UNDEFINED;
sal_uInt16 rLang(0);
RES_CHRATR eLang = maPageDefaults.mbRTLdoc ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
const SvxLanguageItem *pLang = (SvxLanguageItem*)&pDoc->GetAttrPool().GetDefaultItem( static_cast< sal_uInt16 >(eLang) );
rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
SvNumberFormatter* pFormatter = pDoc->GetNumberFormatter();
bool bHijri = false;
if( pFormatter )
{
nFmtIdx = sw::ms::MSDateTimeFormatToSwFormat(aSaveStr, pFormatter, rLang, bHijri);
if (nFmtIdx)
nNumFmtType = pFormatter->GetType(nFmtIdx);
}
pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
if(nNumFmtType & NUMBERFORMAT_DATE)
pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, DATEFLD, nFmtIdx );
else if(nNumFmtType == NUMBERFORMAT_TIME)
pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, TIMEFLD, nFmtIdx );
if( pFld )
{
pDoc->InsertPoolItem( *pPam, SwFmtFld( *pFld ), 0);
delete pFld;
}
}
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_DATA:
{
// Datenbank-FileName: nur der Filename interressiert
// Zur Zeit werden nur SDF-Files verarbeitet, also suche nach
// der Extension
// im SWG geben die DATA Felder den Namen der Datenbank
// an. Dieser kann als Field oder als DBInfo interpretiert
// werden:
// \\data -> Datenbank-Name als Field
// DATA -> Datenbank-Info
bool const bField = rFieldStr.Len() && rFieldStr.GetChar(0) != 'D';
// nur der Name interressiert
if( STRING_NOTFOUND != (nPos = aSaveStr.Search( '.' )) )
aSaveStr.Erase( nPos );
SwDBData aData;
aData.sDataSource = aSaveStr;
if( bField )
{
pFldType = pDoc->GetSysFldType( RES_DBNAMEFLD );
pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDBNameField(
static_cast<SwDBNameFieldType*>(pFldType), SwDBData())), 0);
}
else
pDoc->ChgDBData( aData ); // MS: Keine DBInfo verwenden
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_MERGEFLD:
{
// ein Datenbank - Feld: nur der Name interressiert
// bis zum Ende vom String ist das der Feldname
SwDBFieldType aTmp( pDoc, aSaveStr, SwDBData() ); //
SwDBField aDBFld( (SwDBFieldType*)pDoc->InsertFldType( aTmp ));
aDBFld.ChangeFormat( UF_STRING );
pDoc->InsertPoolItem(*pPam, SwFmtFld( aDBFld ), 0);
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_SYMBOL:
{
// loesche fuehrende Blanks
if( IsNewGroup() )
GetAttrSet();
SetNewGroup( sal_True );
SfxItemSet& rSet = GetAttrSet();
sal_Bool bCharIns = sal_False;
RtfFieldSwitch aRFS( aSaveStr );
while( !aRFS.IsAtEnd() )
{
String sParam;
sal_Unicode cKey = aRFS.GetSwitch( sParam );
if( sParam.Len() )
switch( cKey )
{
case 0:
if( !bCharIns )
{
sal_Unicode nChar = (sal_Unicode)sParam.ToInt32();
if( nChar )
{
pDoc->InsertString( *pPam, nChar );
bCharIns = sal_True;
}
}
break;
case 'f': case 'F':
// Font setzen
{
SvxRTFFontTbl& rTbl = GetFontTbl();
for( Font* pFont = rTbl.First(); pFont;
pFont = rTbl.Next() )
if( pFont->GetName() == sParam )
{
rSet.Put( SvxFontItem(
pFont->GetFamily(),
sParam,
pFont->GetStyleName(),
pFont->GetPitch(),
pFont->GetCharSet(),
RES_CHRATR_FONT ));
break;
}
}
break;
case 'h': case 'H':
//??
break;
case 's': case 'S':
// Fontsize setzen
{
const sal_uInt16 nVal = (sal_uInt16)(sParam.ToInt32() * 20);
rSet.Put( SvxFontHeightItem( nVal,
100, RES_CHRATR_FONTSIZE ));
}
break;
}
}
if( !IsNewGroup() ) AttrGroupEnd();
SetNewGroup( sal_False );
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_HYPERLINK:
rFieldStr.Erase();
if( aSaveStr.Len() )
{
// return String ist URL, # Mark, \1 Frame
String sMark, sFrame;
RtfFieldSwitch aRFS( aSaveStr );
while( !aRFS.IsAtEnd() )
{
String sParam;
sal_Unicode cKey = aRFS.GetSwitch( sParam );
if( sParam.Len() )
switch( cKey )
{
case 0:
if( !rFieldStr.Len() )
rFieldStr = URIHelper::SmartRel2Abs(
INetURLObject(GetBaseURL()), sParam,
URIHelper::GetMaybeFileHdl() );
break;
case 'l': case 'L': sMark = sParam; break;
case 't': case 'T': sFrame = sParam; break;
}
}
if( sMark.Len() )
( rFieldStr += INET_MARK_TOKEN ) += sMark;
if( sFrame.Len() )
( rFieldStr += '\1' ) += sFrame;
}
break;
case RTFFLD_EQ:
rFieldStr.Erase();
if( aSaveStr.Len() )
{
RTF_EquationData aData;
::lcl_ScanEquationField( aSaveStr, aData, 0 );
// is it a ruby attr?
if( aData.sText.Len() && aData.sFontName.Len() &&
aData.nFontSize && aData.sUp.Len() && !aData.sDown.Len() )
{
//Translate and apply
switch( aData.nJustificationCode )
{
case 0: aData.nJustificationCode = 1; break;
case 1: aData.nJustificationCode = 3; break;
case 2: aData.nJustificationCode = 4; break;
case 4: aData.nJustificationCode = 2; break;
// case 3:
default: aData.nJustificationCode = 0; break;
}
SwFmtRuby aRuby( aData.sUp );
SwCharFmt * pCharFmt = -1 != aData.nStyleNo
? aCharFmtTbl.Get( aData.nStyleNo )
: 0;
if( !pCharFmt )
{
//Make a guess at which of asian of western we should be setting
sal_uInt16 nScript;
if (pBreakIt->GetBreakIter().is())
nScript = pBreakIt->GetBreakIter()->getScriptType( aData.sUp, 0);
else
nScript = i18n::ScriptType::ASIAN;
sal_uInt16 nFntHWhich = GetWhichOfScript( RES_CHRATR_FONTSIZE, nScript ),
nFntWhich = GetWhichOfScript( RES_CHRATR_FONT, nScript );
//Check to see if we already have a ruby charstyle that this fits
for(sal_uInt16 i=0; i < aRubyCharFmts.Count(); ++i )
{
SwCharFmt *pFmt = (SwCharFmt *)aRubyCharFmts[i];
const SvxFontHeightItem &rF = (const SvxFontHeightItem &)
pFmt->GetFmtAttr( nFntHWhich );
if( rF.GetHeight() == sal_uInt16(aData.nFontSize * 10 ))
{
const SvxFontItem &rFI = (const SvxFontItem &)
pFmt->GetFmtAttr( nFntWhich );
if( rFI.GetFamilyName().Equals( aData.sFontName ))
{
pCharFmt = pFmt;
break;
}
}
}
//Create a new char style if necessary
if( !pCharFmt )
{
String sNm;
//Take this as the base name
SwStyleNameMapper::FillUIName( RES_POOLCHR_RUBYTEXT, sNm );
sNm += String::CreateFromInt32( aRubyCharFmts.Count() + 1 );
pCharFmt = pDoc->MakeCharFmt( sNm,
( SwCharFmt*)pDoc->GetDfltCharFmt() );
SvxFontHeightItem aHeightItem( aData.nFontSize * 10, 100, RES_CHRATR_FONTSIZE );
aHeightItem.SetWhich( nFntHWhich );
SvxFontItem aFontItem( FAMILY_DONTKNOW, aData.sFontName,
aEmptyStr, PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, nFntWhich );
pCharFmt->SetFmtAttr( aHeightItem );
pCharFmt->SetFmtAttr( aFontItem );
void* p = pCharFmt;
aRubyCharFmts.Insert( p, aRubyCharFmts.Count() );
}
}
//Set the charstyle and justification
aRuby.SetCharFmtName( pCharFmt->GetName() );
aRuby.SetCharFmtId( pCharFmt->GetPoolFmtId() );
aRuby.SetAdjustment( (sal_uInt16)aData.nJustificationCode );
// im FieldStr steht der anzuzeigenden Text, im
pDoc->InsertString( *pPam, aData.sText );
pPam->SetMark();
pPam->GetMark()->nContent -= aData.sText.Len();
pDoc->InsertPoolItem( *pPam, aRuby,
nsSetAttrMode::SETATTR_DONTEXPAND );
pPam->DeleteMark();
}
// or a combined character field?
else if( aData.sUp.Len() && aData.sDown.Len() &&
!aData.sText.Len() && !aData.sFontName.Len() &&
!aData.nFontSize )
{
String sFld( aData.sUp );
sFld += aData.sDown;
SwCombinedCharField aFld((SwCombinedCharFieldType*)pDoc->
GetSysFldType( RES_COMBINED_CHARS ), sFld );
pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0);
}
SkipGroup(); // ueberlese den Rest
}
break;
case RTFFLD_PAGEREF:
{
String sOrigBkmName;
RtfFieldSwitch aRFS( aSaveStr );
while( !aRFS.IsAtEnd() )
{
String sParam;
sal_Unicode cKey = aRFS.GetSwitch( sParam );
switch( cKey )
{
// In the case of pageref the only parameter we are
// interested in, is the name of the bookmark
case 0:
if( !sOrigBkmName.Len() ) // get name of bookmark
sOrigBkmName = sParam;
break;
}
}
SwGetRefField aFld(
(SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
sOrigBkmName,REF_BOOKMARK,0,REF_PAGE);
if(!bNestedField)
{
pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
}
else
bNestedField = false;
}
break;
case RTFFLD_REF:
{
String sOrigBkmName;
bool bChapterNr = false;
bool bAboveBelow = false;
RtfFieldSwitch aRFS( aSaveStr );
while( !aRFS.IsAtEnd() )
{
String sParam;
sal_Unicode cKey = aRFS.GetSwitch( sParam );
switch( cKey )
{
case 0:
if( !sOrigBkmName.Len() ) // get name of bookmark
sOrigBkmName = sParam;
break;
case 'n':
case 'r':
case 'w':
bChapterNr = true; // activate flag 'Chapter Number'
break;
case 'p':
bAboveBelow = true;
break;
}
}
if (!bAboveBelow || bChapterNr)
{
if (bChapterNr)
{
SwGetRefField aFld(
(SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
sOrigBkmName,REF_BOOKMARK,0,REF_CHAPTER);
pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
}
else
{
SwGetRefField aFld(
(SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT);
pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
}
}
if( bAboveBelow )
{
SwGetRefField aFld( (SwGetRefFieldType*)
pDoc->GetSysFldType( RES_GETREFFLD ), sOrigBkmName, REF_BOOKMARK, 0,
REF_UPDOWN );
pDoc->InsertPoolItem(*pPam, SwFmtFld(aFld), 0);
}
}
break;
case RTFFLD_TOC:
case RTFFLD_INDEX:
break;
default:
{
// keines von den bekannten Feldern, also eine neues UserField
aSaveStr.EraseLeadingChars().EraseTrailingChars();
SwUserFieldType aTmp( pDoc, aSaveStr );
SwUserField aUFld( (SwUserFieldType*)pDoc->InsertFldType( aTmp ));
aUFld.ChangeFormat( UF_STRING );
pDoc->InsertPoolItem( *pPam, SwFmtFld( aUFld ), 0);
nRet = RTFFLD_UNKNOWN;
}
break;
}
return nRet;
}
void SwRTFParser::ReadXEField()
{
bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
int nNumOpenBrakets = 1;
String sFieldStr;
sal_uInt8 cCh;
int nToken;
while (nNumOpenBrakets && IsParserWorking())
{
switch (nToken = GetNextToken())
{
case '}':
{
--nNumOpenBrakets;
if( sFieldStr.Len())
{
String sXE(sFieldStr);
sXE.Insert('\"', 0);
sXE.Append('\"');
// we have to make sure the hidden text flag is not on
// otherwise the index will not see this index mark
SfxItemSet& rSet = GetAttrSet();
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
{
SvxCharHiddenItem aCharHidden(*(SvxCharHiddenItem*)pItem);
aCharHidden.SetValue(sal_False);
rSet.Put(aCharHidden);
}
sw::ms::ImportXE(*pDoc, *pPam, sXE);
sFieldStr.Erase();
}
}
break;
case '{':
if( RTF_IGNOREFLAG != GetNextToken() )
SkipToken( -1 );
// Unknown und alle bekannten nicht ausgewerteten Gruppen
// sofort ueberspringen
else if( RTF_UNKNOWNCONTROL != GetNextToken() )
SkipToken( -2 );
else
{
// gleich herausfiltern
ReadUnknownData();
if( '}' != GetNextToken() )
eState = SVPAR_ERROR;
break;
}
++nNumOpenBrakets;
break;
case RTF_U:
{
if( nTokenValue )
sFieldStr += (sal_Unicode)nTokenValue;
else
sFieldStr += aToken;
}
break;
case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
INSINGLECHAR:
sFieldStr += ByteString::ConvertToUnicode( cCh,
RTL_TEXTENCODING_MS_1252 );
break;
// kein Break, aToken wird als Text gesetzt
case RTF_TEXTTOKEN:
sFieldStr += aToken;
break;
case RTF_BKMK_KEY:
case RTF_TC:
case RTF_NEXTFILE:
case RTF_TEMPLATE:
case RTF_SHPRSLT:
SkipGroup();
break;
case RTF_PAR:
sFieldStr.Append('\x0a');
break;
default:
SvxRTFParser::NextToken( nToken );
break;
}
}
SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
}
void SwRTFParser::ReadField()
{
bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
int nRet = 0;
int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
int bFldInst = sal_False, bFldRslt = sal_False;
String sFieldStr, sFieldNm;
sal_uInt8 cCh;
int nToken;
while (nNumOpenBrakets && IsParserWorking())
{
switch (nToken = GetNextToken())
{
case '}':
{
--nNumOpenBrakets;
if( 1 != nNumOpenBrakets || !bFldInst )
break;
if( !bFldRslt )
{
// FieldInst vollstaendig eingelesen, was ist es denn?
nRet = MakeFieldInst( sFieldStr );
switch ( nRet )
{
case RTFFLD_INCLUDETEXT:
case RTFFLD_TOC:
case RTFFLD_INDEX:
// erstmal Index/Inhaltsverzeichniss ueberspringen
// und als normalen Text einfuegen. Spaeter mal auch dem
// SwPaM darum aufspannen.
return ;
case RTFFLD_IMPORT:
case RTFFLD_HYPERLINK:
sFieldNm = sFieldStr;
break;
}
sFieldStr.Erase();
}
else if (RTFFLD_UNKNOWN == nRet)
{
// FieldResult wurde eingelesen
if (SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode())
{
SwTxtAttr* const pFldAttr =
pTxtNd->GetTxtAttrForCharAt(
pPam->GetPoint()->nContent.GetIndex()-1 );
if (pFldAttr)
{
const SwField *pFld = pFldAttr->GetFmtFld().GetField();
SwFieldType *pTyp = pFld ? pFld->GetTyp() : 0;
ASSERT(pTyp->Which() == RES_USERFLD, "expected a user field");
if (pTyp->Which() == RES_USERFLD)
{
SwUserFieldType *pUsrTyp = (SwUserFieldType*)pTyp;
pUsrTyp->SetContent(sFieldStr);
}
}
}
}
else if( sFieldNm.Len() )
{
switch ( nRet )
{
case RTFFLD_IMPORT:
// Grafik einfuegen
InsPicture( sFieldNm );
nRet = INT_MAX;
break;
case RTFFLD_HYPERLINK:
if( sFieldStr.Len() )
{
if(sNestedFieldStr.Len())
sFieldStr.Insert(sNestedFieldStr);
sNestedFieldStr.Erase();
// im FieldStr steht der anzuzeigenden Text, im
pDoc->InsertString( *pPam, sFieldStr );
String sTarget( sFieldNm.GetToken( 1, '\1' ));
if( sTarget.Len() )
sFieldNm.Erase( sFieldNm.Len() - sTarget.Len() -1 );
// oder ueber den Stack setzen??
pPam->SetMark();
pPam->GetMark()->nContent -= sFieldStr.Len();
pDoc->InsertPoolItem( *pPam,
SwFmtINetFmt( sFieldNm, sTarget ),
nsSetAttrMode::SETATTR_DONTEXPAND );
pPam->DeleteMark();
// #i117947#: insert result only once in case
// field result is followed by invalid tokens
sFieldStr.Erase();
}
break;
}
}
else if(bNestedField)
{
if(nRet == RTFFLD_PAGEREF)
{
// #17371 Nasty hack to get a pageref within a hyperlink working
sNestedFieldStr = sFieldStr;
}
}
}
break;
case '{':
if( RTF_IGNOREFLAG != GetNextToken() )
SkipToken( -1 );
// Unknown und alle bekannten nicht ausgewerteten Gruppen
// sofort ueberspringen
else if( RTF_UNKNOWNCONTROL != GetNextToken() )
SkipToken( -2 );
else
{
// gleich herausfiltern
ReadUnknownData();
if( '}' != GetNextToken() )
eState = SVPAR_ERROR;
break;
}
++nNumOpenBrakets;
break;
case RTF_DATAFIELD:
SkipGroup();
break;
case RTF_FIELD:
bNestedField = true;
ReadField();
break;
case RTF_FLDINST:
bFldInst = sal_True;
break;
case RTF_FLDRSLT:
bFldRslt = sal_True;
break;
case RTF_U:
{
if( nTokenValue )
sFieldStr += (sal_Unicode)nTokenValue;
else
sFieldStr += aToken;
}
break;
case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
INSINGLECHAR:
sFieldStr += ByteString::ConvertToUnicode( cCh,
RTL_TEXTENCODING_MS_1252 );
break;
// kein Break, aToken wird als Text gesetzt
case RTF_TEXTTOKEN:
sFieldStr += aToken;
break;
case RTF_PICT: // Pic-Daten einlesen!
if( RTFFLD_IMPORT == nRet )
{
Graphic aGrf;
SvxRTFPictureType aPicType;
if( ReadBmpData( aGrf, aPicType ) )
{
InsPicture( sFieldNm, &aGrf, &aPicType );
nRet = INT_MAX;
}
SkipGroup();
}
break;
case RTF_BKMK_KEY:
case RTF_XE:
case RTF_TC:
case RTF_NEXTFILE:
case RTF_TEMPLATE:
case RTF_SHPRSLT:
SkipGroup();
break;
case RTF_CS:
// we write every time "EQ "
if( bFldInst && 0 == sFieldStr.SearchAscii( "EQ " ))
{
// insert behind the EQ the "\*cs<NO> " string. This is utilize
// in the MakeFieldInst
String sTmp;
(sTmp.AssignAscii( "\\* cs" )
+= String::CreateFromInt32( nTokenValue )) += ' ';
sFieldStr.Insert( sTmp, 3 );
}
break;
case RTF_FFNAME:
case RTF_FORMFIELD:
break;
case RTF_PAR:
sFieldStr.Append('\x0a');
break;
default:
SvxRTFParser::NextToken( nToken );
break;
}
}
// Grafik einfuegen
if (RTFFLD_IMPORT == nRet && sFieldNm.Len())
InsPicture( sFieldNm );
SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
}
/* vi:set tabstop=4 shiftwidth=4 expandtab: */