1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rtfparse.cxx,v $
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_sc.hxx"
36 //------------------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <svx/eeitem.hxx>
42 #include <svx/editeng.hxx>
43 #include <svx/fhgtitem.hxx>
44 #include <svx/svxrtf.hxx>
45 #include <vcl/outdev.hxx>
46 #include <svtools/rtftoken.h>
48 #define SC_RTFPARSE_CXX
49 #include "rtfparse.hxx"
51 #include "document.hxx"
52 #include "docpool.hxx"
54 #define SC_RTFTWIPTOL 10 // 10 Twips Toleranz bei Spaltenbestimmung
58 SV_IMPL_VARARR_SORT( ScRTFColTwips
, ULONG
);
62 ScRTFParser::ScRTFParser( EditEngine
* pEditP
) :
64 pDefaultList( new ScRTFDefaultList
),
65 pColTwips( new ScRTFColTwips
),
68 nStartAdjust( (ULONG
)~0 ),
72 // RTF default FontSize 12Pt
73 long nMM
= OutputDevice::LogicToLogic( 12, MAP_POINT
, MAP_100TH_MM
);
74 pPool
->SetPoolDefaultItem( SvxFontHeightItem( nMM
, 100, EE_CHAR_FONTHEIGHT
) );
75 // freifliegender pInsDefault
76 pInsDefault
= new ScRTFCellDefault( pPool
);
80 ScRTFParser::~ScRTFParser()
84 for ( ScRTFCellDefault
* pD
= pDefaultList
->First(); pD
; pD
= pDefaultList
->Next() )
90 ULONG
ScRTFParser::Read( SvStream
& rStream
, const String
& rBaseURL
)
92 Link aOldLink
= pEdit
->GetImportHdl();
93 pEdit
->SetImportHdl( LINK( this, ScRTFParser
, RTFImportHdl
) );
94 ULONG nErr
= pEdit
->Read( rStream
, rBaseURL
, EE_FORMAT_RTF
);
95 if ( nLastToken
== RTF_PAR
)
97 ScEEParseEntry
* pE
= pList
->Last();
100 && (( pE
->aSel
.nStartPara
== pE
->aSel
.nEndPara
101 && pE
->aSel
.nStartPos
== pE
->aSel
.nEndPos
)
103 || ( pE
->aSel
.nStartPara
+ 1 == pE
->aSel
.nEndPara
104 && pE
->aSel
.nStartPos
== pEdit
->GetTextLen( pE
->aSel
.nStartPara
)
105 && pE
->aSel
.nEndPos
== 0 )) )
106 { // den letzten leeren Absatz nicht uebernehmen
112 pEdit
->SetImportHdl( aOldLink
);
117 void ScRTFParser::EntryEnd( ScEEParseEntry
* pE
, const ESelection
& aSel
)
119 // Paragraph -2 stript den angehaengten leeren Paragraph
120 pE
->aSel
.nEndPara
= aSel
.nEndPara
- 2;
121 // obwohl das nEndPos heisst, ist das letzte Position + 1
122 pE
->aSel
.nEndPos
= pEdit
->GetTextLen( aSel
.nEndPara
- 1 );
126 inline void ScRTFParser::NextRow()
128 if ( nRowMax
< ++nRowCnt
)
133 BOOL
ScRTFParser::SeekTwips( USHORT nTwips
, SCCOL
* pCol
)
136 BOOL bFound
= pColTwips
->Seek_Entry( nTwips
, &nPos
);
137 *pCol
= static_cast<SCCOL
>(nPos
);
140 USHORT nCount
= pColTwips
->Count();
144 // nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
145 if ( nCol
< static_cast<SCCOL
>(nCount
) && (((*pColTwips
)[nCol
] - SC_RTFTWIPTOL
) <= nTwips
) )
147 // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
148 else if ( nCol
!= 0 && (((*pColTwips
)[nCol
-1] + SC_RTFTWIPTOL
) >= nTwips
) )
157 void ScRTFParser::ColAdjust()
159 if ( nStartAdjust
!= (ULONG
)~0 )
163 pE
= pList
->Seek( nStartAdjust
);
169 if ( pE
->nColOverlap
> 1 )
170 nCol
= nCol
+ pE
->nColOverlap
; // merged cells mit \clmrg
173 SeekTwips( pE
->nTwips
, &nCol
);
174 if ( ++nCol
<= pE
->nCol
)
175 nCol
= pE
->nCol
+ 1; // verschobene Zell-X
176 pE
->nColOverlap
= nCol
- pE
->nCol
; // merged cells ohne \clmrg
178 if ( nCol
> nColMax
)
182 nStartAdjust
= (ULONG
)~0;
183 pColTwips
->Remove( (USHORT
)0, pColTwips
->Count() );
188 IMPL_LINK( ScRTFParser
, RTFImportHdl
, ImportInfo
*, pInfo
)
190 switch ( pInfo
->eState
)
192 case RTFIMP_NEXTTOKEN
:
195 case RTFIMP_UNKNOWNATTR
:
200 SvxRTFParser
* pParser
= (SvxRTFParser
*) pInfo
->pParser
;
201 pParser
->SetAttrPool( pPool
);
202 RTFPardAttrMapIds
& rMap
= pParser
->GetPardMap();
203 rMap
.nBrush
= ATTR_BACKGROUND
;
204 rMap
.nBox
= ATTR_BORDER
;
205 rMap
.nShadow
= ATTR_SHADOW
;
209 if ( pInfo
->aSelection
.nEndPos
)
210 { // falls noch Text: letzten Absatz erzeugen
212 pInfo
->nToken
= RTF_PAR
;
213 // EditEngine hat keinen leeren Paragraph mehr angehaengt
214 // den EntryEnd strippen koennte
215 pInfo
->aSelection
.nEndPara
++;
221 case RTFIMP_INSERTTEXT
:
223 case RTFIMP_INSERTPARA
:
226 DBG_ERRORFILE("unknown ImportInfo.eState");
232 // bei RTF_INTBL bzw. am Anfang von erstem RTF_CELL nach RTF_CELLX wenn es
233 // kein RTF_INTBL gab, bad behavior
234 void ScRTFParser::NewCellRow( ImportInfo
* /*pInfo*/ )
238 ScRTFCellDefault
* pD
;
240 // rechts nicht buendig? => neue Tabelle
242 && ((pD
= pDefaultList
->Last()) != 0) && pD
->nTwips
!= nLastWidth
)
245 if ( !( SeekTwips( nLastWidth
, &n1
)
246 && SeekTwips( pD
->nTwips
, &n2
) && n1
== n2
) )
249 // TwipCols aufbauen, erst nach nLastWidth Vergleich!
250 for ( pD
= pDefaultList
->First(); pD
; pD
= pDefaultList
->Next() )
253 if ( !SeekTwips( pD
->nTwips
, &n
) )
254 pColTwips
->Insert( pD
->nTwips
);
258 pActDefault
= pDefaultList
->First();
259 DBG_ASSERT( pActDefault
, "NewCellRow: pActDefault==0" );
267 \trowd \cellx \cellx ...
268 \intbl \cell \cell ...
271 [\trowd \cellx \cellx ...]
272 \intbl \cell \cell ...
279 \trowd \cellx \cellx ...
280 \intbl \cell \cell ...
283 [\trowd \cellx \cellx ...]
284 \intbl \cell \cell ...
290 void ScRTFParser::ProcToken( ImportInfo
* pInfo
)
292 ScRTFCellDefault
* pD
;
294 switch ( pInfo
->nToken
)
296 case RTF_TROWD
: // denotes table row defauls, before RTF_CELLX
298 if ( (pD
= pDefaultList
->Last()) != 0 )
299 nLastWidth
= pD
->nTwips
;
301 for ( pD
= pDefaultList
->First(); pD
; pD
= pDefaultList
->Next() )
303 pDefaultList
->Clear();
305 nLastToken
= pInfo
->nToken
;
308 case RTF_CLMGF
: // The first cell of cells to be merged
310 pDefMerge
= pInsDefault
;
311 nLastToken
= pInfo
->nToken
;
314 case RTF_CLMRG
: // A cell to be merged with the preceding cell
317 pDefMerge
= pDefaultList
->Last();
318 DBG_ASSERT( pDefMerge
, "RTF_CLMRG: pDefMerge==0" );
319 if ( pDefMerge
) // sonst rottes RTF
320 pDefMerge
->nColOverlap
++; // mehrere nacheinander moeglich
321 pInsDefault
->nColOverlap
= 0; // Flag: ignoriere diese
322 nLastToken
= pInfo
->nToken
;
325 case RTF_CELLX
: // closes cell default
328 pInsDefault
->nCol
= nColCnt
;
329 pInsDefault
->nTwips
= pInfo
->nTokenValue
; // rechter Zellenrand
330 pDefaultList
->Insert( pInsDefault
, LIST_APPEND
);
331 // neuer freifliegender pInsDefault
332 pInsDefault
= new ScRTFCellDefault( pPool
);
333 if ( ++nColCnt
> nColMax
)
335 nLastToken
= pInfo
->nToken
;
338 case RTF_INTBL
: // before the first RTF_CELL
340 // einmal ueber NextToken und einmal ueber UnknownAttrToken
341 // oder z.B. \intbl ... \cell \pard \intbl ... \cell
342 if ( nLastToken
!= RTF_INTBL
&& nLastToken
!= RTF_CELL
&& nLastToken
!= RTF_PAR
)
345 nLastToken
= pInfo
->nToken
;
349 case RTF_CELL
: // denotes the end of a cell.
351 DBG_ASSERT( pActDefault
, "RTF_CELL: pActDefault==0" );
352 if ( bNewDef
|| !pActDefault
)
353 NewCellRow( pInfo
); // davor war kein \intbl, bad behavior
354 // rottes RTF? retten was zu retten ist
356 pActDefault
= pInsDefault
;
357 if ( pActDefault
->nColOverlap
> 0 )
358 { // nicht merged mit vorheriger
359 pActEntry
->nCol
= pActDefault
->nCol
;
360 pActEntry
->nColOverlap
= pActDefault
->nColOverlap
;
361 pActEntry
->nTwips
= pActDefault
->nTwips
;
362 pActEntry
->nRow
= nRowCnt
;
363 pActEntry
->aItemSet
.Set( pActDefault
->aItemSet
);
364 EntryEnd( pActEntry
, pInfo
->aSelection
);
366 if ( nStartAdjust
== (ULONG
)~0 )
367 nStartAdjust
= pList
->Count();
368 pList
->Insert( pActEntry
, LIST_APPEND
);
369 NewActEntry( pActEntry
); // neuer freifliegender pActEntry
372 { // aktuelle Twips der MergeCell zuweisen
373 if ( (pE
= pList
->Last()) != 0 )
374 pE
->nTwips
= pActDefault
->nTwips
;
375 // Selection des freifliegenden pActEntry anpassen
376 // Paragraph -1 wg. Textaufbruch in EditEngine waehrend Parse
377 pActEntry
->aSel
.nStartPara
= pInfo
->aSelection
.nEndPara
- 1;
379 pActDefault
= pDefaultList
->Next();
380 nLastToken
= pInfo
->nToken
;
383 case RTF_ROW
: // means the end of a row
386 nLastToken
= pInfo
->nToken
;
389 case RTF_PAR
: // Paragraph
392 { // text not in table
393 ColAdjust(); // close the processing table
395 pActEntry
->nRow
= nRowCnt
;
396 EntryEnd( pActEntry
, pInfo
->aSelection
);
397 pList
->Insert( pActEntry
, LIST_APPEND
);
398 NewActEntry( pActEntry
); // new pActEntry
401 nLastToken
= pInfo
->nToken
;
405 { // do not set nLastToken
406 switch ( pInfo
->nToken
& ~(0xff | RTF_TABLEDEF
) )
409 ((SvxRTFParser
*)pInfo
->pParser
)->ReadBackgroundAttr(
410 pInfo
->nToken
, pInsDefault
->aItemSet
, TRUE
);
413 ((SvxRTFParser
*)pInfo
->pParser
)->ReadBorderAttr(
414 pInfo
->nToken
, pInsDefault
->aItemSet
, TRUE
);