merge the formfield patch from ooo-build
[ooovba.git] / sw / source / filter / rtf / rtffld.cxx
blobd891d53fd26c89f501f5d0f68ba686cf75c1b7df
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rtffld.cxx,v $
10 * $Revision: 1.33 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
35 #include <ctype.h>
36 #include <hintids.hxx>
38 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
39 #include <com/sun/star/i18n/ScriptType.hdl>
40 #endif
41 #ifndef _GRAPH_HXX //autogen
42 #include <vcl/graph.hxx>
43 #endif
44 #include <svtools/urihelper.hxx>
45 #include <svtools/rtftoken.h>
46 #include <svtools/zforlist.hxx>
47 #include <svx/fontitem.hxx>
48 #include <svx/fhgtitem.hxx>
49 #include <svx/langitem.hxx>
50 #include <svx/brkitem.hxx>
51 #include <fmtfld.hxx>
52 #include <fmtinfmt.hxx>
53 #include <swtypes.hxx>
54 #include <doc.hxx>
55 #include <pam.hxx>
56 #include <ndtxt.hxx>
57 #include <shellio.hxx>
58 #include <fldbas.hxx>
59 #include <swparrtf.hxx>
60 #include <txatbase.hxx>
61 #include <dbfld.hxx>
62 #include <usrfld.hxx>
63 #include <docufld.hxx>
64 #include <flddat.hxx>
65 #include <charfmt.hxx>
66 #ifndef _fmtruby_HXX
67 #include <fmtruby.hxx>
68 #endif
69 #include <breakit.hxx>
70 #include <reffld.hxx>
71 #include <SwStyleNameMapper.hxx>
72 #include <svx/charhiddenitem.hxx>
75 // bestimme, ob es sich um ein IMPORT/TOC - Feld handelt.
76 // return: 0 - weder noch,
77 // 1 - TOC
78 // 2 - IMPORT
79 // 3 - INDEX
80 enum RTF_FLD_TYPES {
81 RTFFLD_UNKNOWN = 0,
82 RTFFLD_TOC,
83 RTFFLD_IMPORT,
84 RTFFLD_INDEX,
85 RTFFLD_SYMBOL,
86 RTFFLD_PAGE,
87 RTFFLD_NUMPAGES,
88 RTFFLD_DATE,
89 RTFFLD_TIME,
90 RTFFLD_DATA,
91 RTFFLD_MERGEFLD,
92 RTFFLD_HYPERLINK,
93 RTFFLD_REF,
94 RTFFLD_PAGEREF,
95 RTFFLD_EQ,
96 RTFFLD_INCLUDETEXT
99 static RTF_FLD_TYPES _WhichFld( String& rName, String& rNext )
101 // Strings sind PascalStrings; Laenge steht an 1. Stellen, dadurch wird
102 // sich der Aufruf von strlen erspart!!!
103 sal_Char __READONLY_DATA sTOC[]= "\x03""toc";
104 sal_Char __READONLY_DATA sIMPORT[]= "\x06""import";
105 sal_Char __READONLY_DATA sINDEX[]= "\x05""index";
106 sal_Char __READONLY_DATA sSYMBOL[]= "\x06""symbol";
107 sal_Char __READONLY_DATA sPAGE[]= "\x04""page";
108 sal_Char __READONLY_DATA sNUMPAGES[]= "\x08""numpages";
109 sal_Char __READONLY_DATA sDATE[]= "\x04""date";
110 sal_Char __READONLY_DATA sTIME[]= "\x04""time";
111 sal_Char __READONLY_DATA sDATA[]= "\x04""data";
112 sal_Char __READONLY_DATA sMERGEFLD[]= "\x0A""mergefield";
113 sal_Char __READONLY_DATA sIMPORT2[]= "\x0E""includepicture";
114 sal_Char __READONLY_DATA sHYPERLINK[]= "\x09""hyperlink";
115 sal_Char __READONLY_DATA sREF[]= "\x03""ref";
116 sal_Char __READONLY_DATA sPAGEREF[]= "\x07""pageref";
117 sal_Char __READONLY_DATA sEQ[]= "\x02""eq";
118 sal_Char __READONLY_DATA sINCLUDETEXT[]="\x0B""includetext";
120 struct _Dummy_RTF_FLD_TYPES
122 RTF_FLD_TYPES eFldType;
123 const sal_Char* pFldNm;
125 __READONLY_DATA _Dummy_RTF_FLD_TYPES aFldNmArr[RTFFLD_INCLUDETEXT + 1] = {
126 {RTFFLD_TOC, sTOC},
127 {RTFFLD_IMPORT, sIMPORT},
128 {RTFFLD_INDEX, sINDEX},
129 {RTFFLD_SYMBOL, sSYMBOL},
130 {RTFFLD_PAGE, sPAGE},
131 {RTFFLD_NUMPAGES, sNUMPAGES},
132 {RTFFLD_DATE, sDATE},
133 {RTFFLD_TIME, sTIME},
134 {RTFFLD_DATA, sDATA},
135 {RTFFLD_MERGEFLD, sMERGEFLD},
136 {RTFFLD_IMPORT, sIMPORT2},
137 {RTFFLD_HYPERLINK, sHYPERLINK},
138 {RTFFLD_REF, sREF},
139 {RTFFLD_PAGEREF, sPAGEREF},
140 {RTFFLD_EQ, sEQ},
141 {RTFFLD_INCLUDETEXT, sINCLUDETEXT}
145 if( !rName.Len() )
146 return RTFFLD_UNKNOWN;
148 String sNm( rName );
149 sNm = sNm.EraseLeadingChars().GetToken(0, ' ');
150 ASSERT( sNm.Len(), "Feldname hat keine Laenge!" );
151 if( !sNm.Len() )
152 return RTFFLD_UNKNOWN;
154 xub_StrLen nTokenStt = rName.Search( sNm );
155 sNm.ToLowerAscii();
157 for (size_t n = 0; n < sizeof(aFldNmArr) / sizeof(aFldNmArr[0]); ++n)
159 const sal_Char* pCmp = aFldNmArr[n].pFldNm;
160 int nLen = *pCmp++;
161 xub_StrLen nFndPos = sNm.SearchAscii( pCmp );
162 if( STRING_NOTFOUND != nFndPos &&
163 ( !nFndPos || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos-1) )) ) &&
164 ( nFndPos+nLen == sNm.Len() || !isalpha(sNm.GetChar( static_cast< xub_StrLen >(nFndPos+nLen) ) ) ) )
166 // rName = sNm.Copy( nFndPos, nLen );
167 rName = rName.Copy( nFndPos, static_cast< xub_StrLen >(nLen) );
168 nFndPos += nTokenStt + static_cast< xub_StrLen >(nLen);
169 while( rNext.GetChar( nFndPos ) == ' ' ) ++nFndPos;
170 rNext.Erase( 0, nFndPos );
171 rNext.EraseTrailingChars();
172 return aFldNmArr[n].eFldType;
175 return RTFFLD_UNKNOWN; // nichts gefunden.
178 static USHORT CheckNumberFmtStr( const String& rNStr )
180 const static sal_Char* aNumberTypeTab[] =
182 "\x0A""ALPHABETIC", /* CHARS_UPPER_LETTER*/
183 "\x0A""alphabetic", /* CHARS_LOWER_LETTER*/
184 "\x05""ROMAN", /* ROMAN_UPPER */
185 "\x05""roman", /* ROMAN_LOWER */
186 "\x06""ARABIC", /* ARABIC */
187 "\x04""NONE", /* NUMBER_NONE */
188 "\x04""CHAR", /* CHAR_SPECIAL */
189 "\x04""PAGE" /* PAGEDESC */
192 ASSERT(sizeof(aNumberTypeTab) / sizeof(sal_Char *)
193 >= SVX_NUM_PAGEDESC - SVX_NUM_CHARS_UPPER_LETTER, "impossible");
195 for (USHORT n = SVX_NUM_CHARS_UPPER_LETTER; n <= SVX_NUM_PAGEDESC; ++n)
197 const sal_Char* pCmp = aNumberTypeTab[n - SVX_NUM_CHARS_UPPER_LETTER];
198 int nLen = *pCmp++;
199 if( rNStr.EqualsAscii( pCmp, 0, static_cast< xub_StrLen >(nLen) ))
200 return static_cast< USHORT >(2 <= n ? n : (n + SVX_NUM_CHARS_UPPER_LETTER_N));
202 return SVX_NUM_PAGEDESC; // default-Wert
205 class RtfFieldSwitch
207 String sParam;
208 xub_StrLen nCurPos;
209 public:
210 RtfFieldSwitch( const String& rParam );
211 sal_Unicode GetSwitch( String& rParam );
213 BOOL IsAtEnd() const { return nCurPos >= sParam.Len(); }
214 xub_StrLen GetCurPos() const { return nCurPos; }
215 void Erase( xub_StrLen nEndPos ) { sParam.Erase( 0, nEndPos ); }
216 void Insert( const String& rIns ) { sParam.Insert( rIns, 0 ); }
217 const String& GetStr() const { return sParam; }
220 RtfFieldSwitch::RtfFieldSwitch( const String& rParam )
221 : sParam( rParam ), nCurPos( 0 )
223 sParam.EraseTrailingChars().EraseLeadingChars();
226 sal_Unicode RtfFieldSwitch::GetSwitch( String& rParam )
228 // beginnt ein Schalter?
229 sal_Unicode c, cKey = 0;
230 if( '\\' == (c = sParam.GetChar( nCurPos )) )
232 if( '\\' == ( c = sParam.GetChar( ++nCurPos )) )
233 c = sParam.GetChar( ++nCurPos );
235 cKey = c;
237 while( ++nCurPos < sParam.Len() &&
238 ' ' == ( c = sParam.GetChar( nCurPos )) )
242 // dann alles in Hochkommatas oder bis zum naechsten // als
243 // Param returnen
244 USHORT nOffset;
245 if( '"' != c && '\'' != c )
246 c = '\\', nOffset = 0;
247 else
248 nOffset = 1;
250 sParam.Erase( 0, nCurPos + nOffset );
251 rParam = sParam.GetToken( 0, c );
252 sParam.Erase( 0, rParam.Len() + nOffset ).EraseLeadingChars();
253 if( '\\' == c )
254 rParam.EraseTrailingChars();
255 nCurPos = 0;
257 return cKey;
260 struct RTF_EquationData
262 String sFontName, sUp, sDown, sText;
263 sal_Int32 nJustificationCode, nFontSize, nUp, nDown, nStyleNo;
265 inline RTF_EquationData()
266 : nJustificationCode(0), nFontSize(0), nUp(0), nDown(0),
267 nStyleNo( -1 )
271 xub_StrLen lcl_FindEndBracket( const String& rStr )
273 xub_StrLen nEnd = rStr.Len(), nRet = STRING_NOTFOUND, nPos = 0;
274 int nOpenCnt = 1;
275 sal_Unicode cCh;
276 for( ; nPos < nEnd; ++nPos )
277 if( ')' == (cCh = rStr.GetChar( nPos )) && !--nOpenCnt )
279 nRet = nPos;
280 break;
282 else if( '(' == cCh )
283 ++nOpenCnt;
285 return nRet;
288 void lcl_ScanEquationField( const String& rStr, RTF_EquationData& rData,
289 sal_Unicode nSttKey )
291 int nSubSupFlag(0);
292 RtfFieldSwitch aRFS( rStr );
293 while( !aRFS.IsAtEnd() )
295 String sParam;
296 sal_Unicode cKey = aRFS.GetSwitch( sParam );
297 if( 1 == nSubSupFlag )
298 ++nSubSupFlag;
299 else if( 1 < nSubSupFlag )
300 nSubSupFlag = 0;
302 BOOL bCheckBracket = FALSE;
303 switch( cKey )
305 case 0:
306 switch( nSttKey )
308 case 'u': rData.sUp += sParam; break;
309 case 'd': rData.sDown += sParam; break;
310 default: rData.sText += sParam; break;
312 break;
314 case '*':
315 if( sParam.Len() )
317 if( sParam.EqualsIgnoreCaseAscii( "jc", 0, 2 ) )
318 rData.nJustificationCode = sParam.Copy( 2 ).ToInt32();
319 else if( sParam.EqualsIgnoreCaseAscii( "hps", 0, 3 ) )
320 rData.nFontSize= sParam.Copy( 3 ).ToInt32();
321 else if( sParam.EqualsIgnoreCaseAscii( "Font:", 0, 5 ) )
322 rData.sFontName = sParam.Copy( 5 );
323 else if( sParam.EqualsIgnoreCaseAscii( "cs", 0, 2 ) )
324 rData.nStyleNo = sParam.Copy( 2 ).ToInt32();
326 break;
327 case 's' :
328 ++nSubSupFlag;
329 break;
331 case 'u':
332 if( sParam.Len() && 'p' == sParam.GetChar( 0 ) &&
333 2 == nSubSupFlag )
335 rData.nUp = sParam.Copy( 1 ).ToInt32();
336 bCheckBracket = TRUE;
338 break;
340 case 'd':
341 if( sParam.Len() && 'o' == sParam.GetChar( 0 ) &&
342 2 == nSubSupFlag )
344 rData.nDown = sParam.Copy( 1 ).ToInt32();
345 bCheckBracket = TRUE;
347 break;
349 default:
350 bCheckBracket = TRUE;
351 cKey = 0;
352 break;
355 if( bCheckBracket && sParam.Len() )
357 xub_StrLen nEnd, nStt = sParam.Search( '(' ),
358 nLen = sParam.Len();
359 if( STRING_NOTFOUND != nStt )
361 sParam.Erase( 0, nStt + 1 ) += aRFS.GetStr();
362 if( STRING_NOTFOUND !=
363 (nEnd = ::lcl_FindEndBracket( sParam )) )
365 // end in the added string?
366 if( (nLen - nStt - 1 ) < nEnd )
367 aRFS.Erase( nEnd + 1 - (nLen - nStt - 1));
368 else
370 // not all handled here, so set new into the RFS
371 aRFS.Insert( sParam.Copy( nEnd + 1,
372 nLen - nStt - nEnd - 2 ));
373 sal_Unicode cCh;
374 if( aRFS.GetStr().Len() &&
375 ( ',' == (cCh = aRFS.GetStr().GetChar(0)) ||
376 ';' == cCh ))
377 aRFS.Erase( 1 );
380 ::lcl_ScanEquationField( sParam.Copy( 0, nEnd ),
381 rData, cKey );
388 int SwRTFParser::MakeFieldInst( String& rFieldStr )
390 // sicher den Original-String fuer die FeldNamen (User/Datenbank)
391 String aSaveStr( rFieldStr );
392 SwFieldType * pFldType;
393 int nRet = _WhichFld(rFieldStr, aSaveStr);
395 //Strip Mergeformat from fields
396 xub_StrLen nPos=0;
397 while (STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii("\\*", nPos)))
399 xub_StrLen nStartDel = nPos;
400 nPos += 2;
401 while (aSaveStr.GetChar(nPos) == ' ')
402 ++nPos;
403 if (aSaveStr.EqualsIgnoreCaseAscii("MERGEFORMAT", nPos, 11))
405 xub_StrLen nNoDel = (nPos + 11 ) - nStartDel;
406 aSaveStr.Erase(nStartDel, nNoDel);
407 nPos -= (nStartDel - nPos);
411 nPos = 0;
412 switch (nRet)
414 case RTFFLD_INCLUDETEXT:
415 break;
416 case RTFFLD_IMPORT:
418 //JP 11.03.96: vertraegt sich nicht so ganz mit Internet!
419 // if( STRING_NOTFOUND != ( nPos = aSaveStr.Search( '.' )))
420 // aSaveStr.Erase( nPos+4 );
422 aSaveStr.EraseLeadingAndTrailingChars();
423 if( aSaveStr.Len() )
425 sal_Unicode c = aSaveStr.GetChar( 0 );
426 if( '"' == c || '\'' == c )
428 aSaveStr.Erase( 0, 1 );
429 aSaveStr = aSaveStr.GetToken( 0, c );
432 rFieldStr = URIHelper::SmartRel2Abs(
433 INetURLObject(GetBaseURL()), aSaveStr,
434 URIHelper::GetMaybeFileHdl() );
436 // SkipGroup(); // ueberlese den Rest
438 break;
440 case RTFFLD_NUMPAGES:
442 SwDocStatField aFld( (SwDocStatFieldType*)pDoc->GetSysFldType( RES_DOCSTATFLD ),
443 DS_PAGE, SVX_NUM_ARABIC );
444 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
446 nPos += 2;
447 while( aSaveStr.GetChar(nPos) == ' ' ) nPos++;
448 aSaveStr.Erase( 0, nPos );
450 // steht jetzt geanu auf dem Format-Namen
451 aFld.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
453 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
454 SkipGroup();
456 break;
458 case RTFFLD_PAGE:
460 pFldType = pDoc->GetSysFldType( RES_PAGENUMBERFLD );
461 SwPageNumberField aPF( (SwPageNumberFieldType*)pFldType,
462 PG_RANDOM, SVX_NUM_ARABIC);
463 if( STRING_NOTFOUND != ( nPos = aSaveStr.SearchAscii( "\\*" )) )
465 nPos += 2;
466 while( aSaveStr.GetChar(nPos) == ' ' ) nPos++;
467 aSaveStr.Erase( 0, nPos );
469 // steht jetzt geanu auf dem Format-Namen
470 aPF.ChangeFormat( CheckNumberFmtStr( aSaveStr ));
472 pDoc->InsertPoolItem( *pPam, SwFmtFld( aPF ), 0 );
473 SkipGroup(); // ueberlese den Rest
475 break;
476 case RTFFLD_DATE:
477 case RTFFLD_TIME:
479 if( STRING_NOTFOUND == ( nPos = aSaveStr.SearchAscii( "\\@" )) )
481 // es fehlt die Format - Angabe: defaulten auf Datum
482 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
483 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDateTimeField(
484 static_cast<SwDateTimeFieldType*>(pFldType), DATEFLD)), 0);
486 else
488 // versuche aus dem Formatstring zu erkennen, ob es ein
489 // Datum oder Zeit oder Datum & Zeit Field ist
490 // nur das Format interressiert
491 aSaveStr.Erase( 0, aSaveStr.Search( '\"' )+1 );
492 // alles hinter dem Format interressiert auch nicht mehr.
493 aSaveStr.Erase( aSaveStr.Search( '\"' ) );
494 aSaveStr.SearchAndReplaceAscii( "AM", aEmptyStr );
495 aSaveStr.SearchAndReplaceAscii( "PM", aEmptyStr );
497 // #117892# M.M. Put the word date and time formatter stuff in a common area
498 // and get the rtf filter to use it
499 SwField *pFld = 0;
500 short nNumFmtType = NUMBERFORMAT_UNDEFINED;
501 ULONG nFmtIdx = NUMBERFORMAT_UNDEFINED;
503 USHORT rLang(0);
504 RES_CHRATR eLang = maPageDefaults.mbRTLdoc ? RES_CHRATR_CTL_LANGUAGE : RES_CHRATR_LANGUAGE;
505 const SvxLanguageItem *pLang = (SvxLanguageItem*)&pDoc->GetAttrPool().GetDefaultItem( static_cast< USHORT >(eLang) );
506 rLang = pLang ? pLang->GetValue() : LANGUAGE_ENGLISH_US;
508 SvNumberFormatter* pFormatter = pDoc->GetNumberFormatter();
509 bool bHijri = false;
511 if( pFormatter )
513 nFmtIdx = sw::ms::MSDateTimeFormatToSwFormat(aSaveStr, pFormatter, rLang, bHijri);
514 if (nFmtIdx)
515 nNumFmtType = pFormatter->GetType(nFmtIdx);
518 pFldType = pDoc->GetSysFldType( RES_DATETIMEFLD );
520 if(nNumFmtType & NUMBERFORMAT_DATE)
521 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, DATEFLD, nFmtIdx );
522 else if(nNumFmtType == NUMBERFORMAT_TIME)
523 pFld = new SwDateTimeField( (SwDateTimeFieldType*)pFldType, TIMEFLD, nFmtIdx );
525 if( pFld )
527 pDoc->InsertPoolItem( *pPam, SwFmtFld( *pFld ), 0);
528 delete pFld;
531 SkipGroup(); // ueberlese den Rest
533 break;
535 case RTFFLD_DATA:
537 // Datenbank-FileName: nur der Filename interressiert
538 // Zur Zeit werden nur SDF-Files verarbeitet, also suche nach
539 // der Extension
541 // im SWG geben die DATA Felder den Namen der Datenbank
542 // an. Dieser kann als Field oder als DBInfo interpretiert
543 // werden:
544 // \\data -> Datenbank-Name als Field
545 // DATA -> Datenbank-Info
546 BOOL bField = rFieldStr.GetChar( 0 ) != 'D';
548 // nur der Name interressiert
549 if( STRING_NOTFOUND != (nPos = aSaveStr.Search( '.' )) )
550 aSaveStr.Erase( nPos );
551 SwDBData aData;
552 aData.sDataSource = aSaveStr;
553 if( bField )
555 pFldType = pDoc->GetSysFldType( RES_DBNAMEFLD );
556 pDoc->InsertPoolItem( *pPam, SwFmtFld( SwDBNameField(
557 static_cast<SwDBNameFieldType*>(pFldType), SwDBData())), 0);
559 else
560 pDoc->ChgDBData( aData ); // MS: Keine DBInfo verwenden
561 SkipGroup(); // ueberlese den Rest
563 break;
564 case RTFFLD_MERGEFLD:
566 // ein Datenbank - Feld: nur der Name interressiert
567 // bis zum Ende vom String ist das der Feldname
568 SwDBFieldType aTmp( pDoc, aSaveStr, SwDBData() ); //
569 SwDBField aDBFld( (SwDBFieldType*)pDoc->InsertFldType( aTmp ));
571 aDBFld.ChangeFormat( UF_STRING );
572 pDoc->InsertPoolItem(*pPam, SwFmtFld( aDBFld ), 0);
573 SkipGroup(); // ueberlese den Rest
575 break;
577 case RTFFLD_SYMBOL:
579 // loesche fuehrende Blanks
580 if( IsNewGroup() )
581 GetAttrSet();
582 SetNewGroup( TRUE );
584 SfxItemSet& rSet = GetAttrSet();
586 BOOL bCharIns = FALSE;
587 RtfFieldSwitch aRFS( aSaveStr );
588 while( !aRFS.IsAtEnd() )
590 String sParam;
591 sal_Unicode cKey = aRFS.GetSwitch( sParam );
592 if( sParam.Len() )
593 switch( cKey )
595 case 0:
596 if( !bCharIns )
598 sal_Unicode nChar = (sal_Unicode)sParam.ToInt32();
599 if( nChar )
601 pDoc->InsertString( *pPam, nChar );
602 bCharIns = TRUE;
605 break;
607 case 'f': case 'F':
608 // Font setzen
610 SvxRTFFontTbl& rTbl = GetFontTbl();
611 for( Font* pFont = rTbl.First(); pFont;
612 pFont = rTbl.Next() )
613 if( pFont->GetName() == sParam )
615 rSet.Put( SvxFontItem(
616 pFont->GetFamily(),
617 sParam,
618 pFont->GetStyleName(),
619 pFont->GetPitch(),
620 pFont->GetCharSet(),
621 RES_CHRATR_FONT ));
622 break;
625 break;
626 case 'h': case 'H':
627 //??
628 break;
629 case 's': case 'S':
630 // Fontsize setzen
632 const USHORT nVal = (USHORT)(sParam.ToInt32() * 20);
633 rSet.Put( SvxFontHeightItem( nVal,
634 100, RES_CHRATR_FONTSIZE ));
636 break;
640 if( !IsNewGroup() ) AttrGroupEnd();
641 SetNewGroup( FALSE );
643 SkipGroup(); // ueberlese den Rest
645 break;
647 case RTFFLD_HYPERLINK:
648 rFieldStr.Erase();
649 if( aSaveStr.Len() )
651 // return String ist URL, # Mark, \1 Frame
652 String sMark, sFrame;
653 RtfFieldSwitch aRFS( aSaveStr );
654 while( !aRFS.IsAtEnd() )
656 String sParam;
657 sal_Unicode cKey = aRFS.GetSwitch( sParam );
658 if( sParam.Len() )
659 switch( cKey )
661 case 0:
662 if( !rFieldStr.Len() )
663 rFieldStr = URIHelper::SmartRel2Abs(
664 INetURLObject(GetBaseURL()), sParam,
665 URIHelper::GetMaybeFileHdl() );
666 break;
668 case 'l': case 'L': sMark = sParam; break;
669 case 't': case 'T': sFrame = sParam; break;
673 if( sMark.Len() )
674 ( rFieldStr += INET_MARK_TOKEN ) += sMark;
675 if( sFrame.Len() )
676 ( rFieldStr += '\1' ) += sFrame;
678 break;
680 case RTFFLD_EQ:
681 rFieldStr.Erase();
682 if( aSaveStr.Len() )
684 RTF_EquationData aData;
685 ::lcl_ScanEquationField( aSaveStr, aData, 0 );
687 // is it a ruby attr?
688 if( aData.sText.Len() && aData.sFontName.Len() &&
689 aData.nFontSize && aData.sUp.Len() && !aData.sDown.Len() )
691 //Translate and apply
692 switch( aData.nJustificationCode )
694 case 0: aData.nJustificationCode = 1; break;
695 case 1: aData.nJustificationCode = 3; break;
696 case 2: aData.nJustificationCode = 4; break;
697 case 4: aData.nJustificationCode = 2; break;
698 // case 3:
699 default: aData.nJustificationCode = 0; break;
702 SwFmtRuby aRuby( aData.sUp );
703 SwCharFmt * pCharFmt = -1 != aData.nStyleNo
704 ? aCharFmtTbl.Get( aData.nStyleNo )
705 : 0;
707 if( !pCharFmt )
709 //Make a guess at which of asian of western we should be setting
710 USHORT nScript;
711 if (pBreakIt->GetBreakIter().is())
712 nScript = pBreakIt->GetBreakIter()->getScriptType( aData.sUp, 0);
713 else
714 nScript = i18n::ScriptType::ASIAN;
716 USHORT nFntHWhich = GetWhichOfScript( RES_CHRATR_FONTSIZE, nScript ),
717 nFntWhich = GetWhichOfScript( RES_CHRATR_FONT, nScript );
719 //Check to see if we already have a ruby charstyle that this fits
720 for(USHORT i=0; i < aRubyCharFmts.Count(); ++i )
722 SwCharFmt *pFmt = (SwCharFmt *)aRubyCharFmts[i];
723 const SvxFontHeightItem &rF = (const SvxFontHeightItem &)
724 pFmt->GetFmtAttr( nFntHWhich );
725 if( rF.GetHeight() == USHORT(aData.nFontSize * 10 ))
727 const SvxFontItem &rFI = (const SvxFontItem &)
728 pFmt->GetFmtAttr( nFntWhich );
729 if( rFI.GetFamilyName().Equals( aData.sFontName ))
731 pCharFmt = pFmt;
732 break;
737 //Create a new char style if necessary
738 if( !pCharFmt )
740 String sNm;
741 //Take this as the base name
742 SwStyleNameMapper::FillUIName( RES_POOLCHR_RUBYTEXT, sNm );
743 sNm += String::CreateFromInt32( aRubyCharFmts.Count() + 1 );
744 pCharFmt = pDoc->MakeCharFmt( sNm,
745 ( SwCharFmt*)pDoc->GetDfltCharFmt() );
747 SvxFontHeightItem aHeightItem( aData.nFontSize * 10, 100, RES_CHRATR_FONTSIZE );
748 aHeightItem.SetWhich( nFntHWhich );
750 SvxFontItem aFontItem( FAMILY_DONTKNOW, aData.sFontName,
751 aEmptyStr, PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, nFntWhich );
753 pCharFmt->SetFmtAttr( aHeightItem );
754 pCharFmt->SetFmtAttr( aFontItem );
755 void* p = pCharFmt;
756 aRubyCharFmts.Insert( p, aRubyCharFmts.Count() );
760 //Set the charstyle and justification
761 aRuby.SetCharFmtName( pCharFmt->GetName() );
762 aRuby.SetCharFmtId( pCharFmt->GetPoolFmtId() );
763 aRuby.SetAdjustment( (USHORT)aData.nJustificationCode );
765 // im FieldStr steht der anzuzeigenden Text, im
766 pDoc->InsertString( *pPam, aData.sText );
767 pPam->SetMark();
768 pPam->GetMark()->nContent -= aData.sText.Len();
769 pDoc->InsertPoolItem( *pPam, aRuby,
770 nsSetAttrMode::SETATTR_DONTEXPAND );
771 pPam->DeleteMark();
773 // or a combined character field?
774 else if( aData.sUp.Len() && aData.sDown.Len() &&
775 !aData.sText.Len() && !aData.sFontName.Len() &&
776 !aData.nFontSize )
778 String sFld( aData.sUp );
779 sFld += aData.sDown;
780 SwCombinedCharField aFld((SwCombinedCharFieldType*)pDoc->
781 GetSysFldType( RES_COMBINED_CHARS ), sFld );
782 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0);
785 SkipGroup(); // ueberlese den Rest
787 break;
789 case RTFFLD_PAGEREF:
791 String sOrigBkmName;
792 RtfFieldSwitch aRFS( aSaveStr );
793 while( !aRFS.IsAtEnd() )
795 String sParam;
796 sal_Unicode cKey = aRFS.GetSwitch( sParam );
797 switch( cKey )
799 // In the case of pageref the only parameter we are
800 // interested in, is the name of the bookmark
801 case 0:
802 if( !sOrigBkmName.Len() ) // get name of bookmark
803 sOrigBkmName = sParam;
804 break;
807 SwGetRefField aFld(
808 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
809 sOrigBkmName,REF_BOOKMARK,0,REF_PAGE);
811 if(!bNestedField)
813 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
815 else
816 bNestedField = false;
818 break;
820 case RTFFLD_REF:
822 String sOrigBkmName;
823 bool bChapterNr = false;
824 bool bAboveBelow = false;
826 RtfFieldSwitch aRFS( aSaveStr );
827 while( !aRFS.IsAtEnd() )
829 String sParam;
830 sal_Unicode cKey = aRFS.GetSwitch( sParam );
831 switch( cKey )
833 case 0:
834 if( !sOrigBkmName.Len() ) // get name of bookmark
835 sOrigBkmName = sParam;
836 break;
838 case 'n':
839 case 'r':
840 case 'w':
841 bChapterNr = true; // activate flag 'Chapter Number'
842 break;
844 case 'p':
845 bAboveBelow = true;
846 break;
849 if (!bAboveBelow || bChapterNr)
851 if (bChapterNr)
853 SwGetRefField aFld(
854 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
855 sOrigBkmName,REF_BOOKMARK,0,REF_CHAPTER);
856 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
858 else
860 SwGetRefField aFld(
861 (SwGetRefFieldType*)pDoc->GetSysFldType( RES_GETREFFLD ),
862 sOrigBkmName,REF_BOOKMARK,0,REF_CONTENT);
863 pDoc->InsertPoolItem( *pPam, SwFmtFld( aFld ), 0 );
867 if( bAboveBelow )
869 SwGetRefField aFld( (SwGetRefFieldType*)
870 pDoc->GetSysFldType( RES_GETREFFLD ), sOrigBkmName, REF_BOOKMARK, 0,
871 REF_UPDOWN );
872 pDoc->InsertPoolItem(*pPam, SwFmtFld(aFld), 0);
875 break;
877 case RTFFLD_TOC:
878 case RTFFLD_INDEX:
879 break;
881 default:
883 // keines von den bekannten Feldern, also eine neues UserField
884 aSaveStr.EraseLeadingChars().EraseTrailingChars();
885 SwUserFieldType aTmp( pDoc, aSaveStr );
886 SwUserField aUFld( (SwUserFieldType*)pDoc->InsertFldType( aTmp ));
887 aUFld.ChangeFormat( UF_STRING );
888 pDoc->InsertPoolItem( *pPam, SwFmtFld( aUFld ), 0);
889 nRet = RTFFLD_UNKNOWN;
891 break;
893 return nRet;
897 void SwRTFParser::ReadXEField()
899 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
900 int nNumOpenBrakets = 1;
901 String sFieldStr;
902 BYTE cCh;
904 int nToken;
905 while (nNumOpenBrakets && IsParserWorking())
907 switch (nToken = GetNextToken())
909 case '}':
911 --nNumOpenBrakets;
913 if( sFieldStr.Len())
915 String sXE(sFieldStr);
916 sXE.Insert('\"', 0);
917 sXE.Append('\"');
919 // we have to make sure the hidden text flag is not on
920 // otherwise the index will not see this index mark
921 SfxItemSet& rSet = GetAttrSet();
922 const SfxPoolItem* pItem;
923 if( SFX_ITEM_SET == rSet.GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
925 SvxCharHiddenItem aCharHidden(*(SvxCharHiddenItem*)pItem);
926 aCharHidden.SetValue(FALSE);
927 rSet.Put(aCharHidden);
930 sw::ms::ImportXE(*pDoc, *pPam, sXE);
932 sFieldStr.Erase();
935 break;
937 case '{':
938 if( RTF_IGNOREFLAG != GetNextToken() )
939 SkipToken( -1 );
940 // Unknown und alle bekannten nicht ausgewerteten Gruppen
941 // sofort ueberspringen
942 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
943 SkipToken( -2 );
944 else
946 // gleich herausfiltern
947 ReadUnknownData();
948 if( '}' != GetNextToken() )
949 eState = SVPAR_ERROR;
950 break;
952 ++nNumOpenBrakets;
953 break;
955 case RTF_U:
957 if( nTokenValue )
958 sFieldStr += (sal_Unicode)nTokenValue;
959 else
960 sFieldStr += aToken;
962 break;
964 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
965 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
966 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
967 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
968 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
969 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
970 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
971 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
972 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
973 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
974 INSINGLECHAR:
975 sFieldStr += ByteString::ConvertToUnicode( cCh,
976 RTL_TEXTENCODING_MS_1252 );
977 break;
979 // kein Break, aToken wird als Text gesetzt
980 case RTF_TEXTTOKEN:
981 sFieldStr += aToken;
982 break;
984 case RTF_BKMK_KEY:
985 case RTF_TC:
986 case RTF_NEXTFILE:
987 case RTF_TEMPLATE:
988 case RTF_SHPRSLT:
989 SkipGroup();
990 break;
992 case RTF_PAR:
993 sFieldStr.Append('\x0a');
994 break;
995 default:
996 SvxRTFParser::NextToken( nToken );
997 break;
1001 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1005 void SwRTFParser::ReadField()
1007 bReadSwFly = false; //#it may be that any uses of this need to be removed and replaced
1008 int nRet = 0;
1009 int nNumOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
1010 int bFldInst = FALSE, bFldRslt = FALSE;
1011 String sFieldStr, sFieldNm;
1012 BYTE cCh;
1014 int nToken;
1015 while (nNumOpenBrakets && IsParserWorking())
1017 switch (nToken = GetNextToken())
1019 case '}':
1021 --nNumOpenBrakets;
1022 if( 1 != nNumOpenBrakets || !bFldInst )
1023 break;
1025 if( !bFldRslt )
1027 // FieldInst vollstaendig eingelesen, was ist es denn?
1028 nRet = MakeFieldInst( sFieldStr );
1029 switch ( nRet )
1031 case RTFFLD_INCLUDETEXT:
1032 case RTFFLD_TOC:
1033 case RTFFLD_INDEX:
1034 // erstmal Index/Inhaltsverzeichniss ueberspringen
1035 // und als normalen Text einfuegen. Spaeter mal auch dem
1036 // SwPaM darum aufspannen.
1037 return ;
1039 case RTFFLD_IMPORT:
1040 case RTFFLD_HYPERLINK:
1041 sFieldNm = sFieldStr;
1042 break;
1044 sFieldStr.Erase();
1046 else if (RTFFLD_UNKNOWN == nRet)
1048 // FieldResult wurde eingelesen
1049 if (SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode())
1051 SwTxtAttr* const pFldAttr =
1052 pTxtNd->GetTxtAttrForCharAt(
1053 pPam->GetPoint()->nContent.GetIndex()-1 );
1055 if (pFldAttr)
1057 const SwField *pFld = pFldAttr->GetFld().GetFld();
1058 SwFieldType *pTyp = pFld ? pFld->GetTyp() : 0;
1059 ASSERT(pTyp->Which() == RES_USERFLD, "expected a user field");
1060 if (pTyp->Which() == RES_USERFLD)
1062 SwUserFieldType *pUsrTyp = (SwUserFieldType*)pTyp;
1063 pUsrTyp->SetContent(sFieldStr);
1068 else if( sFieldNm.Len() )
1070 switch ( nRet )
1072 case RTFFLD_IMPORT:
1073 // Grafik einfuegen
1074 InsPicture( sFieldNm );
1075 nRet = INT_MAX;
1076 break;
1077 case RTFFLD_HYPERLINK:
1078 if( sFieldStr.Len() )
1080 if(sNestedFieldStr.Len())
1081 sFieldStr.Insert(sNestedFieldStr);
1083 sNestedFieldStr.Erase();
1084 // im FieldStr steht der anzuzeigenden Text, im
1085 pDoc->InsertString( *pPam, sFieldStr );
1087 String sTarget( sFieldNm.GetToken( 1, '\1' ));
1088 if( sTarget.Len() )
1089 sFieldNm.Erase( sFieldNm.Len() - sTarget.Len() -1 );
1091 // oder ueber den Stack setzen??
1092 pPam->SetMark();
1093 pPam->GetMark()->nContent -= sFieldStr.Len();
1094 pDoc->InsertPoolItem( *pPam,
1095 SwFmtINetFmt( sFieldNm, sTarget ),
1096 nsSetAttrMode::SETATTR_DONTEXPAND );
1097 pPam->DeleteMark();
1100 break;
1103 else if(bNestedField)
1105 if(nRet == RTFFLD_PAGEREF)
1107 // #17371 Nasty hack to get a pageref within a hyperlink working
1108 sNestedFieldStr = sFieldStr;
1114 break;
1116 case '{':
1117 if( RTF_IGNOREFLAG != GetNextToken() )
1118 SkipToken( -1 );
1119 // Unknown und alle bekannten nicht ausgewerteten Gruppen
1120 // sofort ueberspringen
1121 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
1122 SkipToken( -2 );
1123 else
1125 // gleich herausfiltern
1126 ReadUnknownData();
1127 if( '}' != GetNextToken() )
1128 eState = SVPAR_ERROR;
1129 break;
1131 ++nNumOpenBrakets;
1132 break;
1134 case RTF_DATAFIELD:
1135 SkipGroup();
1136 break;
1138 case RTF_FIELD:
1139 bNestedField = true;
1140 ReadField();
1141 break;
1143 case RTF_FLDINST:
1144 bFldInst = TRUE;
1145 break;
1147 case RTF_FLDRSLT:
1148 bFldRslt = TRUE;
1149 break;
1151 case RTF_U:
1153 if( nTokenValue )
1154 sFieldStr += (sal_Unicode)nTokenValue;
1155 else
1156 sFieldStr += aToken;
1158 break;
1160 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
1161 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
1162 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
1163 case RTF_EMDASH: cCh = 151; goto INSINGLECHAR;
1164 case RTF_ENDASH: cCh = 150; goto INSINGLECHAR;
1165 case RTF_BULLET: cCh = 149; goto INSINGLECHAR;
1166 case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR;
1167 case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR;
1168 case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR;
1169 case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR;
1170 INSINGLECHAR:
1171 sFieldStr += ByteString::ConvertToUnicode( cCh,
1172 RTL_TEXTENCODING_MS_1252 );
1173 break;
1175 // kein Break, aToken wird als Text gesetzt
1176 case RTF_TEXTTOKEN:
1177 sFieldStr += aToken;
1178 break;
1180 case RTF_PICT: // Pic-Daten einlesen!
1181 if( RTFFLD_IMPORT == nRet )
1183 Graphic aGrf;
1184 SvxRTFPictureType aPicType;
1185 if( ReadBmpData( aGrf, aPicType ) )
1187 InsPicture( sFieldNm, &aGrf, &aPicType );
1188 nRet = INT_MAX;
1190 SkipGroup();
1192 break;
1194 case RTF_BKMK_KEY:
1195 case RTF_XE:
1196 case RTF_TC:
1197 case RTF_NEXTFILE:
1198 case RTF_TEMPLATE:
1199 case RTF_SHPRSLT:
1200 SkipGroup();
1201 break;
1203 case RTF_CS:
1204 // we write every time "EQ "
1205 if( bFldInst && 0 == sFieldStr.SearchAscii( "EQ " ))
1207 // insert behind the EQ the "\*cs<NO> " string. This is utilize
1208 // in the MakeFieldInst
1209 String sTmp;
1210 (sTmp.AssignAscii( "\\* cs" )
1211 += String::CreateFromInt32( nTokenValue )) += ' ';
1212 sFieldStr.Insert( sTmp, 3 );
1214 break;
1215 case RTF_FFNAME:
1216 case RTF_FORMFIELD:
1217 break;
1218 case RTF_PAR:
1219 sFieldStr.Append('\x0a');
1220 break;
1221 default:
1222 SvxRTFParser::NextToken( nToken );
1223 break;
1227 // Grafik einfuegen
1228 if (RTFFLD_IMPORT == nRet && sFieldNm.Len())
1229 InsPicture( sFieldNm );
1231 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1234 /* vi:set tabstop=4 shiftwidth=4 expandtab: */