1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
33 #include <hintids.hxx>
35 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
36 #include <com/sun/star/i18n/ScriptType.hdl>
38 #ifndef _GRAPH_HXX //autogen
39 #include <vcl/graph.hxx>
41 #include <svl/urihelper.hxx>
42 #include <svtools/rtftoken.h>
43 #include <svl/zforlist.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/langitem.hxx>
47 #include <editeng/brkitem.hxx>
49 #include <fmtinfmt.hxx>
50 #include <swtypes.hxx>
54 #include <shellio.hxx>
56 #include <swparrtf.hxx>
57 #include <txatbase.hxx>
60 #include <docufld.hxx>
62 #include <charfmt.hxx>
64 #include <fmtruby.hxx>
66 #include <breakit.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <editeng/charhiddenitem.hxx>
72 // bestimme, ob es sich um ein IMPORT/TOC - Feld handelt.
73 // return: 0 - weder noch,
96 static RTF_FLD_TYPES
_WhichFld( String
& rName
, String
& rNext
)
98 // Strings sind PascalStrings; Laenge steht an 1. Stellen, dadurch wird
99 // sich der Aufruf von strlen erspart!!!
100 sal_Char __READONLY_DATA sTOC
[]= "\x03""toc";
101 sal_Char __READONLY_DATA sIMPORT
[]= "\x06""import";
102 sal_Char __READONLY_DATA sINDEX
[]= "\x05""index";
103 sal_Char __READONLY_DATA sSYMBOL
[]= "\x06""symbol";
104 sal_Char __READONLY_DATA sPAGE
[]= "\x04""page";
105 sal_Char __READONLY_DATA sNUMPAGES
[]= "\x08""numpages";
106 sal_Char __READONLY_DATA sDATE
[]= "\x04""date";
107 sal_Char __READONLY_DATA sTIME
[]= "\x04""time";
108 sal_Char __READONLY_DATA sDATA
[]= "\x04""data";
109 sal_Char __READONLY_DATA sMERGEFLD
[]= "\x0A""mergefield";
110 sal_Char __READONLY_DATA sIMPORT2
[]= "\x0E""includepicture";
111 sal_Char __READONLY_DATA sHYPERLINK
[]= "\x09""hyperlink";
112 sal_Char __READONLY_DATA sREF
[]= "\x03""ref";
113 sal_Char __READONLY_DATA sPAGEREF
[]= "\x07""pageref";
114 sal_Char __READONLY_DATA sEQ
[]= "\x02""eq";
115 sal_Char __READONLY_DATA sINCLUDETEXT
[]="\x0B""includetext";
117 struct _Dummy_RTF_FLD_TYPES
119 RTF_FLD_TYPES eFldType
;
120 const sal_Char
* pFldNm
;
122 __READONLY_DATA _Dummy_RTF_FLD_TYPES aFldNmArr
[RTFFLD_INCLUDETEXT
+ 1] = {
124 {RTFFLD_IMPORT
, sIMPORT
},
125 {RTFFLD_INDEX
, sINDEX
},
126 {RTFFLD_SYMBOL
, sSYMBOL
},
127 {RTFFLD_PAGE
, sPAGE
},
128 {RTFFLD_NUMPAGES
, sNUMPAGES
},
129 {RTFFLD_DATE
, sDATE
},
130 {RTFFLD_TIME
, sTIME
},
131 {RTFFLD_DATA
, sDATA
},
132 {RTFFLD_MERGEFLD
, sMERGEFLD
},
133 {RTFFLD_IMPORT
, sIMPORT2
},
134 {RTFFLD_HYPERLINK
, sHYPERLINK
},
136 {RTFFLD_PAGEREF
, sPAGEREF
},
138 {RTFFLD_INCLUDETEXT
, sINCLUDETEXT
}
143 return RTFFLD_UNKNOWN
;
146 sNm
= sNm
.EraseLeadingChars().GetToken(0, ' ');
147 ASSERT( sNm
.Len(), "Feldname hat keine Laenge!" );
149 return RTFFLD_UNKNOWN
;
151 xub_StrLen nTokenStt
= rName
.Search( sNm
);
154 for (size_t n
= 0; n
< sizeof(aFldNmArr
) / sizeof(aFldNmArr
[0]); ++n
)
156 const sal_Char
* pCmp
= aFldNmArr
[n
].pFldNm
;
158 xub_StrLen nFndPos
= sNm
.SearchAscii( pCmp
);
159 if( STRING_NOTFOUND
!= nFndPos
&&
160 ( !nFndPos
|| !isalpha(sNm
.GetChar( static_cast< xub_StrLen
>(nFndPos
-1) )) ) &&
161 ( nFndPos
+nLen
== sNm
.Len() || !isalpha(sNm
.GetChar( static_cast< xub_StrLen
>(nFndPos
+nLen
) ) ) ) )
163 // rName = sNm.Copy( nFndPos, nLen );
164 rName
= rName
.Copy( nFndPos
, static_cast< xub_StrLen
>(nLen
) );
165 nFndPos
+= nTokenStt
+ static_cast< xub_StrLen
>(nLen
);
166 while( rNext
.GetChar( nFndPos
) == ' ' ) ++nFndPos
;
167 rNext
.Erase( 0, nFndPos
);
168 rNext
.EraseTrailingChars();
169 return aFldNmArr
[n
].eFldType
;
172 return RTFFLD_UNKNOWN
; // nichts gefunden.
175 static USHORT
CheckNumberFmtStr( const String
& rNStr
)
177 const static sal_Char
* aNumberTypeTab
[] =
179 "\x0A""ALPHABETIC", /* CHARS_UPPER_LETTER*/
180 "\x0A""alphabetic", /* CHARS_LOWER_LETTER*/
181 "\x05""ROMAN", /* ROMAN_UPPER */
182 "\x05""roman", /* ROMAN_LOWER */
183 "\x06""ARABIC", /* ARABIC */
184 "\x04""NONE", /* NUMBER_NONE */
185 "\x04""CHAR", /* CHAR_SPECIAL */
186 "\x04""PAGE" /* PAGEDESC */
189 ASSERT(sizeof(aNumberTypeTab
) / sizeof(sal_Char
*)
190 >= SVX_NUM_PAGEDESC
- SVX_NUM_CHARS_UPPER_LETTER
, "impossible");
192 for (USHORT n
= SVX_NUM_CHARS_UPPER_LETTER
; n
<= SVX_NUM_PAGEDESC
; ++n
)
194 const sal_Char
* pCmp
= aNumberTypeTab
[n
- SVX_NUM_CHARS_UPPER_LETTER
];
196 if( rNStr
.EqualsAscii( pCmp
, 0, static_cast< xub_StrLen
>(nLen
) ))
197 return static_cast< USHORT
>(2 <= n
? n
: (n
+ SVX_NUM_CHARS_UPPER_LETTER_N
));
199 return SVX_NUM_PAGEDESC
; // default-Wert
207 RtfFieldSwitch( const String
& rParam
);
208 sal_Unicode
GetSwitch( String
& rParam
);
210 BOOL
IsAtEnd() const { return nCurPos
>= sParam
.Len(); }
211 xub_StrLen
GetCurPos() const { return nCurPos
; }
212 void Erase( xub_StrLen nEndPos
) { sParam
.Erase( 0, nEndPos
); }
213 void Insert( const String
& rIns
) { sParam
.Insert( rIns
, 0 ); }
214 const String
& GetStr() const { return sParam
; }
217 RtfFieldSwitch::RtfFieldSwitch( const String
& rParam
)
218 : sParam( rParam
), nCurPos( 0 )
220 sParam
.EraseTrailingChars().EraseLeadingChars();
223 sal_Unicode
RtfFieldSwitch::GetSwitch( String
& rParam
)
225 // beginnt ein Schalter?
226 sal_Unicode c
, cKey
= 0;
227 if( '\\' == (c
= sParam
.GetChar( nCurPos
)) )
229 if( '\\' == ( c
= sParam
.GetChar( ++nCurPos
)) )
230 c
= sParam
.GetChar( ++nCurPos
);
234 while( ++nCurPos
< sParam
.Len() &&
235 ' ' == ( c
= sParam
.GetChar( nCurPos
)) )
239 // dann alles in Hochkommatas oder bis zum naechsten // als
242 if( '"' != c
&& '\'' != c
)
243 c
= '\\', nOffset
= 0;
247 sParam
.Erase( 0, nCurPos
+ nOffset
);
248 rParam
= sParam
.GetToken( 0, c
);
249 sParam
.Erase( 0, rParam
.Len() + nOffset
).EraseLeadingChars();
251 rParam
.EraseTrailingChars();
257 struct RTF_EquationData
259 String sFontName
, sUp
, sDown
, sText
;
260 sal_Int32 nJustificationCode
, nFontSize
, nUp
, nDown
, nStyleNo
;
262 inline RTF_EquationData()
263 : nJustificationCode(0), nFontSize(0), nUp(0), nDown(0),
268 xub_StrLen
lcl_FindEndBracket( const String
& rStr
)
270 xub_StrLen nEnd
= rStr
.Len(), nRet
= STRING_NOTFOUND
, nPos
= 0;
273 for( ; nPos
< nEnd
; ++nPos
)
274 if( ')' == (cCh
= rStr
.GetChar( nPos
)) && !--nOpenCnt
)
279 else if( '(' == cCh
)
285 void lcl_ScanEquationField( const String
& rStr
, RTF_EquationData
& rData
,
286 sal_Unicode nSttKey
)
289 RtfFieldSwitch
aRFS( rStr
);
290 while( !aRFS
.IsAtEnd() )
293 sal_Unicode cKey
= aRFS
.GetSwitch( sParam
);
294 if( 1 == nSubSupFlag
)
296 else if( 1 < nSubSupFlag
)
299 BOOL bCheckBracket
= FALSE
;
305 case 'u': rData
.sUp
+= sParam
; break;
306 case 'd': rData
.sDown
+= sParam
; break;
307 default: rData
.sText
+= sParam
; break;
314 if( sParam
.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
315 rData
.nJustificationCode
= sParam
.Copy( 2 ).ToInt32();
316 else if( sParam
.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
317 rData
.nFontSize
= sParam
.Copy( 3 ).ToInt32();
318 else if( sParam
.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
319 rData
.sFontName
= sParam
.Copy( 5 );
320 else if( sParam
.EqualsIgnoreCaseAscii( "cs", 0, 2 ) )
321 rData
.nStyleNo
= sParam
.Copy( 2 ).ToInt32();
329 if( sParam
.Len() && 'p' == sParam
.GetChar( 0 ) &&
332 rData
.nUp
= sParam
.Copy( 1 ).ToInt32();
333 bCheckBracket
= TRUE
;
338 if( sParam
.Len() && 'o' == sParam
.GetChar( 0 ) &&
341 rData
.nDown
= sParam
.Copy( 1 ).ToInt32();
342 bCheckBracket
= TRUE
;
347 bCheckBracket
= TRUE
;
352 if( bCheckBracket
&& sParam
.Len() )
354 xub_StrLen nEnd
, nStt
= sParam
.Search( '(' ),
356 if( STRING_NOTFOUND
!= nStt
)
358 sParam
.Erase( 0, nStt
+ 1 ) += aRFS
.GetStr();
359 if( STRING_NOTFOUND
!=
360 (nEnd
= ::lcl_FindEndBracket( sParam
)) )
362 // end in the added string?
363 if( (nLen
- nStt
- 1 ) < nEnd
)
364 aRFS
.Erase( nEnd
+ 1 - (nLen
- nStt
- 1));
367 // not all handled here, so set new into the RFS
368 aRFS
.Insert( sParam
.Copy( nEnd
+ 1,
369 nLen
- nStt
- nEnd
- 2 ));
371 if( aRFS
.GetStr().Len() &&
372 ( ',' == (cCh
= aRFS
.GetStr().GetChar(0)) ||
377 ::lcl_ScanEquationField( sParam
.Copy( 0, nEnd
),
385 int SwRTFParser::MakeFieldInst( String
& rFieldStr
)
387 // sicher den Original-String fuer die FeldNamen (User/Datenbank)
388 String
aSaveStr( rFieldStr
);
389 SwFieldType
* pFldType
;
390 int nRet
= _WhichFld(rFieldStr
, aSaveStr
);
392 //Strip Mergeformat from fields
394 while (STRING_NOTFOUND
!= ( nPos
= aSaveStr
.SearchAscii("\\*", nPos
)))
396 xub_StrLen nStartDel
= nPos
;
398 while (aSaveStr
.GetChar(nPos
) == ' ')
400 if (aSaveStr
.EqualsIgnoreCaseAscii("MERGEFORMAT", nPos
, 11))
402 xub_StrLen nNoDel
= (nPos
+ 11 ) - nStartDel
;
403 aSaveStr
.Erase(nStartDel
, nNoDel
);
404 nPos
-= (nStartDel
- nPos
);
411 case RTFFLD_INCLUDETEXT
:
415 //JP 11.03.96: vertraegt sich nicht so ganz mit Internet!
416 // if( STRING_NOTFOUND != ( nPos = aSaveStr.Search( '.' )))
417 // aSaveStr.Erase( nPos+4 );
419 aSaveStr
.EraseLeadingAndTrailingChars();
422 sal_Unicode c
= aSaveStr
.GetChar( 0 );
423 if( '"' == c
|| '\'' == c
)
425 aSaveStr
.Erase( 0, 1 );
426 aSaveStr
= aSaveStr
.GetToken( 0, c
);
429 rFieldStr
= URIHelper::SmartRel2Abs(
430 INetURLObject(GetBaseURL()), aSaveStr
,
431 URIHelper::GetMaybeFileHdl() );
433 // SkipGroup(); // ueberlese den Rest
437 case RTFFLD_NUMPAGES
:
439 SwDocStatField
aFld( (SwDocStatFieldType
*)pDoc
->GetSysFldType( RES_DOCSTATFLD
),
440 DS_PAGE
, SVX_NUM_ARABIC
);
441 if( STRING_NOTFOUND
!= ( nPos
= aSaveStr
.SearchAscii( "\\*" )) )
444 while( aSaveStr
.GetChar(nPos
) == ' ' ) nPos
++;
445 aSaveStr
.Erase( 0, nPos
);
447 // steht jetzt geanu auf dem Format-Namen
448 aFld
.ChangeFormat( CheckNumberFmtStr( aSaveStr
));
450 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aFld
), 0 );
457 pFldType
= pDoc
->GetSysFldType( RES_PAGENUMBERFLD
);
458 SwPageNumberField
aPF( (SwPageNumberFieldType
*)pFldType
,
459 PG_RANDOM
, SVX_NUM_ARABIC
);
460 if( STRING_NOTFOUND
!= ( nPos
= aSaveStr
.SearchAscii( "\\*" )) )
463 while( aSaveStr
.GetChar(nPos
) == ' ' ) nPos
++;
464 aSaveStr
.Erase( 0, nPos
);
466 // steht jetzt geanu auf dem Format-Namen
467 aPF
.ChangeFormat( CheckNumberFmtStr( aSaveStr
));
469 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aPF
), 0 );
470 SkipGroup(); // ueberlese den Rest
476 if( STRING_NOTFOUND
== ( nPos
= aSaveStr
.SearchAscii( "\\@" )) )
478 // es fehlt die Format - Angabe: defaulten auf Datum
479 pFldType
= pDoc
->GetSysFldType( RES_DATETIMEFLD
);
480 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( SwDateTimeField(
481 static_cast<SwDateTimeFieldType
*>(pFldType
), DATEFLD
)), 0);
485 // versuche aus dem Formatstring zu erkennen, ob es ein
486 // Datum oder Zeit oder Datum & Zeit Field ist
487 // nur das Format interressiert
488 aSaveStr
.Erase( 0, aSaveStr
.Search( '\"' )+1 );
489 // alles hinter dem Format interressiert auch nicht mehr.
490 aSaveStr
.Erase( aSaveStr
.Search( '\"' ) );
491 aSaveStr
.SearchAndReplaceAscii( "AM", aEmptyStr
);
492 aSaveStr
.SearchAndReplaceAscii( "PM", aEmptyStr
);
494 // #117892# M.M. Put the word date and time formatter stuff in a common area
495 // and get the rtf filter to use it
497 short nNumFmtType
= NUMBERFORMAT_UNDEFINED
;
498 ULONG nFmtIdx
= NUMBERFORMAT_UNDEFINED
;
501 RES_CHRATR eLang
= maPageDefaults
.mbRTLdoc
? RES_CHRATR_CTL_LANGUAGE
: RES_CHRATR_LANGUAGE
;
502 const SvxLanguageItem
*pLang
= (SvxLanguageItem
*)&pDoc
->GetAttrPool().GetDefaultItem( static_cast< USHORT
>(eLang
) );
503 rLang
= pLang
? pLang
->GetValue() : LANGUAGE_ENGLISH_US
;
505 SvNumberFormatter
* pFormatter
= pDoc
->GetNumberFormatter();
510 nFmtIdx
= sw::ms::MSDateTimeFormatToSwFormat(aSaveStr
, pFormatter
, rLang
, bHijri
);
512 nNumFmtType
= pFormatter
->GetType(nFmtIdx
);
515 pFldType
= pDoc
->GetSysFldType( RES_DATETIMEFLD
);
517 if(nNumFmtType
& NUMBERFORMAT_DATE
)
518 pFld
= new SwDateTimeField( (SwDateTimeFieldType
*)pFldType
, DATEFLD
, nFmtIdx
);
519 else if(nNumFmtType
== NUMBERFORMAT_TIME
)
520 pFld
= new SwDateTimeField( (SwDateTimeFieldType
*)pFldType
, TIMEFLD
, nFmtIdx
);
524 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( *pFld
), 0);
528 SkipGroup(); // ueberlese den Rest
534 // Datenbank-FileName: nur der Filename interressiert
535 // Zur Zeit werden nur SDF-Files verarbeitet, also suche nach
538 // im SWG geben die DATA Felder den Namen der Datenbank
539 // an. Dieser kann als Field oder als DBInfo interpretiert
541 // \\data -> Datenbank-Name als Field
542 // DATA -> Datenbank-Info
543 BOOL bField
= rFieldStr
.GetChar( 0 ) != 'D';
545 // nur der Name interressiert
546 if( STRING_NOTFOUND
!= (nPos
= aSaveStr
.Search( '.' )) )
547 aSaveStr
.Erase( nPos
);
549 aData
.sDataSource
= aSaveStr
;
552 pFldType
= pDoc
->GetSysFldType( RES_DBNAMEFLD
);
553 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( SwDBNameField(
554 static_cast<SwDBNameFieldType
*>(pFldType
), SwDBData())), 0);
557 pDoc
->ChgDBData( aData
); // MS: Keine DBInfo verwenden
558 SkipGroup(); // ueberlese den Rest
561 case RTFFLD_MERGEFLD
:
563 // ein Datenbank - Feld: nur der Name interressiert
564 // bis zum Ende vom String ist das der Feldname
565 SwDBFieldType
aTmp( pDoc
, aSaveStr
, SwDBData() ); //
566 SwDBField
aDBFld( (SwDBFieldType
*)pDoc
->InsertFldType( aTmp
));
568 aDBFld
.ChangeFormat( UF_STRING
);
569 pDoc
->InsertPoolItem(*pPam
, SwFmtFld( aDBFld
), 0);
570 SkipGroup(); // ueberlese den Rest
576 // loesche fuehrende Blanks
581 SfxItemSet
& rSet
= GetAttrSet();
583 BOOL bCharIns
= FALSE
;
584 RtfFieldSwitch
aRFS( aSaveStr
);
585 while( !aRFS
.IsAtEnd() )
588 sal_Unicode cKey
= aRFS
.GetSwitch( sParam
);
595 sal_Unicode nChar
= (sal_Unicode
)sParam
.ToInt32();
598 pDoc
->InsertString( *pPam
, nChar
);
607 SvxRTFFontTbl
& rTbl
= GetFontTbl();
608 for( Font
* pFont
= rTbl
.First(); pFont
;
609 pFont
= rTbl
.Next() )
610 if( pFont
->GetName() == sParam
)
612 rSet
.Put( SvxFontItem(
615 pFont
->GetStyleName(),
629 const USHORT nVal
= (USHORT
)(sParam
.ToInt32() * 20);
630 rSet
.Put( SvxFontHeightItem( nVal
,
631 100, RES_CHRATR_FONTSIZE
));
637 if( !IsNewGroup() ) AttrGroupEnd();
638 SetNewGroup( FALSE
);
640 SkipGroup(); // ueberlese den Rest
644 case RTFFLD_HYPERLINK
:
648 // return String ist URL, # Mark, \1 Frame
649 String sMark
, sFrame
;
650 RtfFieldSwitch
aRFS( aSaveStr
);
651 while( !aRFS
.IsAtEnd() )
654 sal_Unicode cKey
= aRFS
.GetSwitch( sParam
);
659 if( !rFieldStr
.Len() )
660 rFieldStr
= URIHelper::SmartRel2Abs(
661 INetURLObject(GetBaseURL()), sParam
,
662 URIHelper::GetMaybeFileHdl() );
665 case 'l': case 'L': sMark
= sParam
; break;
666 case 't': case 'T': sFrame
= sParam
; break;
671 ( rFieldStr
+= INET_MARK_TOKEN
) += sMark
;
673 ( rFieldStr
+= '\1' ) += sFrame
;
681 RTF_EquationData aData
;
682 ::lcl_ScanEquationField( aSaveStr
, aData
, 0 );
684 // is it a ruby attr?
685 if( aData
.sText
.Len() && aData
.sFontName
.Len() &&
686 aData
.nFontSize
&& aData
.sUp
.Len() && !aData
.sDown
.Len() )
688 //Translate and apply
689 switch( aData
.nJustificationCode
)
691 case 0: aData
.nJustificationCode
= 1; break;
692 case 1: aData
.nJustificationCode
= 3; break;
693 case 2: aData
.nJustificationCode
= 4; break;
694 case 4: aData
.nJustificationCode
= 2; break;
696 default: aData
.nJustificationCode
= 0; break;
699 SwFmtRuby
aRuby( aData
.sUp
);
700 SwCharFmt
* pCharFmt
= -1 != aData
.nStyleNo
701 ? aCharFmtTbl
.Get( aData
.nStyleNo
)
706 //Make a guess at which of asian of western we should be setting
708 if (pBreakIt
->GetBreakIter().is())
709 nScript
= pBreakIt
->GetBreakIter()->getScriptType( aData
.sUp
, 0);
711 nScript
= i18n::ScriptType::ASIAN
;
713 USHORT nFntHWhich
= GetWhichOfScript( RES_CHRATR_FONTSIZE
, nScript
),
714 nFntWhich
= GetWhichOfScript( RES_CHRATR_FONT
, nScript
);
716 //Check to see if we already have a ruby charstyle that this fits
717 for(USHORT i
=0; i
< aRubyCharFmts
.Count(); ++i
)
719 SwCharFmt
*pFmt
= (SwCharFmt
*)aRubyCharFmts
[i
];
720 const SvxFontHeightItem
&rF
= (const SvxFontHeightItem
&)
721 pFmt
->GetFmtAttr( nFntHWhich
);
722 if( rF
.GetHeight() == USHORT(aData
.nFontSize
* 10 ))
724 const SvxFontItem
&rFI
= (const SvxFontItem
&)
725 pFmt
->GetFmtAttr( nFntWhich
);
726 if( rFI
.GetFamilyName().Equals( aData
.sFontName
))
734 //Create a new char style if necessary
738 //Take this as the base name
739 SwStyleNameMapper::FillUIName( RES_POOLCHR_RUBYTEXT
, sNm
);
740 sNm
+= String::CreateFromInt32( aRubyCharFmts
.Count() + 1 );
741 pCharFmt
= pDoc
->MakeCharFmt( sNm
,
742 ( SwCharFmt
*)pDoc
->GetDfltCharFmt() );
744 SvxFontHeightItem
aHeightItem( aData
.nFontSize
* 10, 100, RES_CHRATR_FONTSIZE
);
745 aHeightItem
.SetWhich( nFntHWhich
);
747 SvxFontItem
aFontItem( FAMILY_DONTKNOW
, aData
.sFontName
,
748 aEmptyStr
, PITCH_DONTKNOW
, RTL_TEXTENCODING_DONTKNOW
, nFntWhich
);
750 pCharFmt
->SetFmtAttr( aHeightItem
);
751 pCharFmt
->SetFmtAttr( aFontItem
);
753 aRubyCharFmts
.Insert( p
, aRubyCharFmts
.Count() );
757 //Set the charstyle and justification
758 aRuby
.SetCharFmtName( pCharFmt
->GetName() );
759 aRuby
.SetCharFmtId( pCharFmt
->GetPoolFmtId() );
760 aRuby
.SetAdjustment( (USHORT
)aData
.nJustificationCode
);
762 // im FieldStr steht der anzuzeigenden Text, im
763 pDoc
->InsertString( *pPam
, aData
.sText
);
765 pPam
->GetMark()->nContent
-= aData
.sText
.Len();
766 pDoc
->InsertPoolItem( *pPam
, aRuby
,
767 nsSetAttrMode::SETATTR_DONTEXPAND
);
770 // or a combined character field?
771 else if( aData
.sUp
.Len() && aData
.sDown
.Len() &&
772 !aData
.sText
.Len() && !aData
.sFontName
.Len() &&
775 String
sFld( aData
.sUp
);
777 SwCombinedCharField
aFld((SwCombinedCharFieldType
*)pDoc
->
778 GetSysFldType( RES_COMBINED_CHARS
), sFld
);
779 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aFld
), 0);
782 SkipGroup(); // ueberlese den Rest
789 RtfFieldSwitch
aRFS( aSaveStr
);
790 while( !aRFS
.IsAtEnd() )
793 sal_Unicode cKey
= aRFS
.GetSwitch( sParam
);
796 // In the case of pageref the only parameter we are
797 // interested in, is the name of the bookmark
799 if( !sOrigBkmName
.Len() ) // get name of bookmark
800 sOrigBkmName
= sParam
;
805 (SwGetRefFieldType
*)pDoc
->GetSysFldType( RES_GETREFFLD
),
806 sOrigBkmName
,REF_BOOKMARK
,0,REF_PAGE
);
810 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aFld
), 0 );
813 bNestedField
= false;
820 bool bChapterNr
= false;
821 bool bAboveBelow
= false;
823 RtfFieldSwitch
aRFS( aSaveStr
);
824 while( !aRFS
.IsAtEnd() )
827 sal_Unicode cKey
= aRFS
.GetSwitch( sParam
);
831 if( !sOrigBkmName
.Len() ) // get name of bookmark
832 sOrigBkmName
= sParam
;
838 bChapterNr
= true; // activate flag 'Chapter Number'
846 if (!bAboveBelow
|| bChapterNr
)
851 (SwGetRefFieldType
*)pDoc
->GetSysFldType( RES_GETREFFLD
),
852 sOrigBkmName
,REF_BOOKMARK
,0,REF_CHAPTER
);
853 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aFld
), 0 );
858 (SwGetRefFieldType
*)pDoc
->GetSysFldType( RES_GETREFFLD
),
859 sOrigBkmName
,REF_BOOKMARK
,0,REF_CONTENT
);
860 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aFld
), 0 );
866 SwGetRefField
aFld( (SwGetRefFieldType
*)
867 pDoc
->GetSysFldType( RES_GETREFFLD
), sOrigBkmName
, REF_BOOKMARK
, 0,
869 pDoc
->InsertPoolItem(*pPam
, SwFmtFld(aFld
), 0);
880 // keines von den bekannten Feldern, also eine neues UserField
881 aSaveStr
.EraseLeadingChars().EraseTrailingChars();
882 SwUserFieldType
aTmp( pDoc
, aSaveStr
);
883 SwUserField
aUFld( (SwUserFieldType
*)pDoc
->InsertFldType( aTmp
));
884 aUFld
.ChangeFormat( UF_STRING
);
885 pDoc
->InsertPoolItem( *pPam
, SwFmtFld( aUFld
), 0);
886 nRet
= RTFFLD_UNKNOWN
;
894 void SwRTFParser::ReadXEField()
896 bReadSwFly
= false; //#it may be that any uses of this need to be removed and replaced
897 int nNumOpenBrakets
= 1;
902 while (nNumOpenBrakets
&& IsParserWorking())
904 switch (nToken
= GetNextToken())
912 String
sXE(sFieldStr
);
916 // we have to make sure the hidden text flag is not on
917 // otherwise the index will not see this index mark
918 SfxItemSet
& rSet
= GetAttrSet();
919 const SfxPoolItem
* pItem
;
920 if( SFX_ITEM_SET
== rSet
.GetItemState( RES_CHRATR_HIDDEN
, sal_True
, &pItem
) )
922 SvxCharHiddenItem
aCharHidden(*(SvxCharHiddenItem
*)pItem
);
923 aCharHidden
.SetValue(FALSE
);
924 rSet
.Put(aCharHidden
);
927 sw::ms::ImportXE(*pDoc
, *pPam
, sXE
);
935 if( RTF_IGNOREFLAG
!= GetNextToken() )
937 // Unknown und alle bekannten nicht ausgewerteten Gruppen
938 // sofort ueberspringen
939 else if( RTF_UNKNOWNCONTROL
!= GetNextToken() )
943 // gleich herausfiltern
945 if( '}' != GetNextToken() )
946 eState
= SVPAR_ERROR
;
955 sFieldStr
+= (sal_Unicode
)nTokenValue
;
961 case RTF_LINE
: cCh
= '\n'; goto INSINGLECHAR
;
962 case RTF_TAB
: cCh
= '\t'; goto INSINGLECHAR
;
963 case RTF_SUBENTRYINDEX
: cCh
= ':'; goto INSINGLECHAR
;
964 case RTF_EMDASH
: cCh
= 151; goto INSINGLECHAR
;
965 case RTF_ENDASH
: cCh
= 150; goto INSINGLECHAR
;
966 case RTF_BULLET
: cCh
= 149; goto INSINGLECHAR
;
967 case RTF_LQUOTE
: cCh
= 145; goto INSINGLECHAR
;
968 case RTF_RQUOTE
: cCh
= 146; goto INSINGLECHAR
;
969 case RTF_LDBLQUOTE
: cCh
= 147; goto INSINGLECHAR
;
970 case RTF_RDBLQUOTE
: cCh
= 148; goto INSINGLECHAR
;
972 sFieldStr
+= ByteString::ConvertToUnicode( cCh
,
973 RTL_TEXTENCODING_MS_1252
);
976 // kein Break, aToken wird als Text gesetzt
990 sFieldStr
.Append('\x0a');
993 SvxRTFParser::NextToken( nToken
);
998 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1002 void SwRTFParser::ReadField()
1004 bReadSwFly
= false; //#it may be that any uses of this need to be removed and replaced
1006 int nNumOpenBrakets
= 1; // die erste wurde schon vorher erkannt !!
1007 int bFldInst
= FALSE
, bFldRslt
= FALSE
;
1008 String sFieldStr
, sFieldNm
;
1012 while (nNumOpenBrakets
&& IsParserWorking())
1014 switch (nToken
= GetNextToken())
1019 if( 1 != nNumOpenBrakets
|| !bFldInst
)
1024 // FieldInst vollstaendig eingelesen, was ist es denn?
1025 nRet
= MakeFieldInst( sFieldStr
);
1028 case RTFFLD_INCLUDETEXT
:
1031 // erstmal Index/Inhaltsverzeichniss ueberspringen
1032 // und als normalen Text einfuegen. Spaeter mal auch dem
1033 // SwPaM darum aufspannen.
1037 case RTFFLD_HYPERLINK
:
1038 sFieldNm
= sFieldStr
;
1043 else if (RTFFLD_UNKNOWN
== nRet
)
1045 // FieldResult wurde eingelesen
1046 if (SwTxtNode
* pTxtNd
= pPam
->GetPoint()->nNode
.GetNode().GetTxtNode())
1048 SwTxtAttr
* const pFldAttr
=
1049 pTxtNd
->GetTxtAttrForCharAt(
1050 pPam
->GetPoint()->nContent
.GetIndex()-1 );
1054 const SwField
*pFld
= pFldAttr
->GetFld().GetFld();
1055 SwFieldType
*pTyp
= pFld
? pFld
->GetTyp() : 0;
1056 ASSERT(pTyp
->Which() == RES_USERFLD
, "expected a user field");
1057 if (pTyp
->Which() == RES_USERFLD
)
1059 SwUserFieldType
*pUsrTyp
= (SwUserFieldType
*)pTyp
;
1060 pUsrTyp
->SetContent(sFieldStr
);
1065 else if( sFieldNm
.Len() )
1071 InsPicture( sFieldNm
);
1074 case RTFFLD_HYPERLINK
:
1075 if( sFieldStr
.Len() )
1077 if(sNestedFieldStr
.Len())
1078 sFieldStr
.Insert(sNestedFieldStr
);
1080 sNestedFieldStr
.Erase();
1081 // im FieldStr steht der anzuzeigenden Text, im
1082 pDoc
->InsertString( *pPam
, sFieldStr
);
1084 String
sTarget( sFieldNm
.GetToken( 1, '\1' ));
1086 sFieldNm
.Erase( sFieldNm
.Len() - sTarget
.Len() -1 );
1088 // oder ueber den Stack setzen??
1090 pPam
->GetMark()->nContent
-= sFieldStr
.Len();
1091 pDoc
->InsertPoolItem( *pPam
,
1092 SwFmtINetFmt( sFieldNm
, sTarget
),
1093 nsSetAttrMode::SETATTR_DONTEXPAND
);
1100 else if(bNestedField
)
1102 if(nRet
== RTFFLD_PAGEREF
)
1104 // #17371 Nasty hack to get a pageref within a hyperlink working
1105 sNestedFieldStr
= sFieldStr
;
1114 if( RTF_IGNOREFLAG
!= GetNextToken() )
1116 // Unknown und alle bekannten nicht ausgewerteten Gruppen
1117 // sofort ueberspringen
1118 else if( RTF_UNKNOWNCONTROL
!= GetNextToken() )
1122 // gleich herausfiltern
1124 if( '}' != GetNextToken() )
1125 eState
= SVPAR_ERROR
;
1136 bNestedField
= true;
1151 sFieldStr
+= (sal_Unicode
)nTokenValue
;
1153 sFieldStr
+= aToken
;
1157 case RTF_LINE
: cCh
= '\n'; goto INSINGLECHAR
;
1158 case RTF_TAB
: cCh
= '\t'; goto INSINGLECHAR
;
1159 case RTF_SUBENTRYINDEX
: cCh
= ':'; goto INSINGLECHAR
;
1160 case RTF_EMDASH
: cCh
= 151; goto INSINGLECHAR
;
1161 case RTF_ENDASH
: cCh
= 150; goto INSINGLECHAR
;
1162 case RTF_BULLET
: cCh
= 149; goto INSINGLECHAR
;
1163 case RTF_LQUOTE
: cCh
= 145; goto INSINGLECHAR
;
1164 case RTF_RQUOTE
: cCh
= 146; goto INSINGLECHAR
;
1165 case RTF_LDBLQUOTE
: cCh
= 147; goto INSINGLECHAR
;
1166 case RTF_RDBLQUOTE
: cCh
= 148; goto INSINGLECHAR
;
1168 sFieldStr
+= ByteString::ConvertToUnicode( cCh
,
1169 RTL_TEXTENCODING_MS_1252
);
1172 // kein Break, aToken wird als Text gesetzt
1174 sFieldStr
+= aToken
;
1177 case RTF_PICT
: // Pic-Daten einlesen!
1178 if( RTFFLD_IMPORT
== nRet
)
1181 SvxRTFPictureType aPicType
;
1182 if( ReadBmpData( aGrf
, aPicType
) )
1184 InsPicture( sFieldNm
, &aGrf
, &aPicType
);
1201 // we write every time "EQ "
1202 if( bFldInst
&& 0 == sFieldStr
.SearchAscii( "EQ " ))
1204 // insert behind the EQ the "\*cs<NO> " string. This is utilize
1205 // in the MakeFieldInst
1207 (sTmp
.AssignAscii( "\\* cs" )
1208 += String::CreateFromInt32( nTokenValue
)) += ' ';
1209 sFieldStr
.Insert( sTmp
, 3 );
1216 sFieldStr
.Append('\x0a');
1219 SvxRTFParser::NextToken( nToken
);
1225 if (RTFFLD_IMPORT
== nRet
&& sFieldNm
.Len())
1226 InsPicture( sFieldNm
);
1228 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1231 /* vi:set tabstop=4 shiftwidth=4 expandtab: */