Update ooo320-m1
[ooovba.git] / sc / source / filter / rtf / rtfparse.cxx
blob5e7fd2372d3856e65d831ddf4c84f6ab91de626c
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: rtfparse.cxx,v $
10 * $Revision: 1.10 $
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"
50 #include "global.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 ) :
63 ScEEParser( pEditP ),
64 pDefaultList( new ScRTFDefaultList ),
65 pColTwips( new ScRTFColTwips ),
66 pActDefault( NULL ),
67 pDefMerge( NULL ),
68 nStartAdjust( (ULONG)~0 ),
69 nLastWidth(0),
70 bNewDef( FALSE )
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()
82 delete pInsDefault;
83 delete pColTwips;
84 for ( ScRTFCellDefault* pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
85 delete pD;
86 delete pDefaultList;
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();
98 if ( pE
99 // komplett leer
100 && (( pE->aSel.nStartPara == pE->aSel.nEndPara
101 && pE->aSel.nStartPos == pE->aSel.nEndPos)
102 // leerer Paragraph
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
107 pList->Remove();
108 delete pE;
111 ColAdjust();
112 pEdit->SetImportHdl( aOldLink );
113 return nErr;
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 )
129 nRowMax = nRowCnt;
133 BOOL ScRTFParser::SeekTwips( USHORT nTwips, SCCOL* pCol )
135 USHORT nPos;
136 BOOL bFound = pColTwips->Seek_Entry( nTwips, &nPos );
137 *pCol = static_cast<SCCOL>(nPos);
138 if ( bFound )
139 return TRUE;
140 USHORT nCount = pColTwips->Count();
141 if ( !nCount )
142 return FALSE;
143 SCCOL nCol = *pCol;
144 // nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
145 if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) )
146 return TRUE;
147 // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
148 else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) )
150 (*pCol)--;
151 return TRUE;
153 return FALSE;
157 void ScRTFParser::ColAdjust()
159 if ( nStartAdjust != (ULONG)~0 )
161 SCCOL nCol = 0;
162 ScEEParseEntry* pE;
163 pE = pList->Seek( nStartAdjust );
164 while ( pE )
166 if ( pE->nCol == 0 )
167 nCol = 0;
168 pE->nCol = nCol;
169 if ( pE->nColOverlap > 1 )
170 nCol = nCol + pE->nColOverlap; // merged cells mit \clmrg
171 else
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 )
179 nColMax = nCol;
180 pE = pList->Next();
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:
193 ProcToken( pInfo );
194 break;
195 case RTFIMP_UNKNOWNATTR:
196 ProcToken( pInfo );
197 break;
198 case RTFIMP_START:
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;
207 break;
208 case RTFIMP_END:
209 if ( pInfo->aSelection.nEndPos )
210 { // falls noch Text: letzten Absatz erzeugen
211 pActDefault = NULL;
212 pInfo->nToken = RTF_PAR;
213 // EditEngine hat keinen leeren Paragraph mehr angehaengt
214 // den EntryEnd strippen koennte
215 pInfo->aSelection.nEndPara++;
216 ProcToken( pInfo );
218 break;
219 case RTFIMP_SETATTR:
220 break;
221 case RTFIMP_INSERTTEXT:
222 break;
223 case RTFIMP_INSERTPARA:
224 break;
225 default:
226 DBG_ERRORFILE("unknown ImportInfo.eState");
228 return 0;
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*/ )
236 if ( bNewDef )
238 ScRTFCellDefault* pD;
239 bNewDef = FALSE;
240 // rechts nicht buendig? => neue Tabelle
241 if ( nLastWidth
242 && ((pD = pDefaultList->Last()) != 0) && pD->nTwips != nLastWidth )
244 SCCOL n1, n2;
245 if ( !( SeekTwips( nLastWidth, &n1 )
246 && SeekTwips( pD->nTwips, &n2 ) && n1 == n2) )
247 ColAdjust();
249 // TwipCols aufbauen, erst nach nLastWidth Vergleich!
250 for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
252 SCCOL n;
253 if ( !SeekTwips( pD->nTwips, &n ) )
254 pColTwips->Insert( pD->nTwips );
257 pDefMerge = NULL;
258 pActDefault = pDefaultList->First();
259 DBG_ASSERT( pActDefault, "NewCellRow: pActDefault==0" );
266 [\par]
267 \trowd \cellx \cellx ...
268 \intbl \cell \cell ...
269 \row
270 [\par]
271 [\trowd \cellx \cellx ...]
272 \intbl \cell \cell ...
273 \row
274 [\par]
276 M$-Word:
277 ~~~~~~~~
278 [\par]
279 \trowd \cellx \cellx ...
280 \intbl \cell \cell ...
281 \intbl \row
282 [\par]
283 [\trowd \cellx \cellx ...]
284 \intbl \cell \cell ...
285 \intbl \row
286 [\par]
290 void ScRTFParser::ProcToken( ImportInfo* pInfo )
292 ScRTFCellDefault* pD;
293 ScEEParseEntry* pE;
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;
300 nColCnt = 0;
301 for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
302 delete pD;
303 pDefaultList->Clear();
304 pDefMerge = NULL;
305 nLastToken = pInfo->nToken;
307 break;
308 case RTF_CLMGF: // The first cell of cells to be merged
310 pDefMerge = pInsDefault;
311 nLastToken = pInfo->nToken;
313 break;
314 case RTF_CLMRG: // A cell to be merged with the preceding cell
316 if ( !pDefMerge )
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;
324 break;
325 case RTF_CELLX: // closes cell default
327 bNewDef = TRUE;
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 )
334 nColMax = nColCnt;
335 nLastToken = pInfo->nToken;
337 break;
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 )
344 NewCellRow( pInfo );
345 nLastToken = pInfo->nToken;
348 break;
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
355 if ( !pActDefault )
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
371 else
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;
382 break;
383 case RTF_ROW: // means the end of a row
385 NextRow();
386 nLastToken = pInfo->nToken;
388 break;
389 case RTF_PAR: // Paragraph
391 if ( !pActDefault )
392 { // text not in table
393 ColAdjust(); // close the processing table
394 pActEntry->nCol = 0;
395 pActEntry->nRow = nRowCnt;
396 EntryEnd( pActEntry, pInfo->aSelection );
397 pList->Insert( pActEntry, LIST_APPEND );
398 NewActEntry( pActEntry ); // new pActEntry
399 NextRow();
401 nLastToken = pInfo->nToken;
403 break;
404 default:
405 { // do not set nLastToken
406 switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
408 case RTF_SHADINGDEF:
409 ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(
410 pInfo->nToken, pInsDefault->aItemSet, TRUE );
411 break;
412 case RTF_BRDRDEF:
413 ((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr(
414 pInfo->nToken, pInsDefault->aItemSet, TRUE );
415 break;