merged tag ooo/OOO330_m14
[LibreOffice.git] / sc / source / filter / rtf / rtfparse.cxx
blobb3373bbf45960c3b76ecdb01aef0bc9eb449d2cd
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_sc.hxx"
33 //------------------------------------------------------------------------
35 #include "scitems.hxx"
36 #include <editeng/eeitem.hxx>
39 #include <editeng/editeng.hxx>
40 #include <editeng/fhgtitem.hxx>
41 #include <editeng/svxrtf.hxx>
42 #include <vcl/outdev.hxx>
43 #include <svtools/rtftoken.h>
45 #define SC_RTFPARSE_CXX
46 #include "rtfparse.hxx"
47 #include "global.hxx"
48 #include "document.hxx"
49 #include "docpool.hxx"
51 #define SC_RTFTWIPTOL 10 // 10 Twips Toleranz bei Spaltenbestimmung
55 SV_IMPL_VARARR_SORT( ScRTFColTwips, ULONG );
59 ScRTFParser::ScRTFParser( EditEngine* pEditP ) :
60 ScEEParser( pEditP ),
61 pDefaultList( new ScRTFDefaultList ),
62 pColTwips( new ScRTFColTwips ),
63 pActDefault( NULL ),
64 pDefMerge( NULL ),
65 nStartAdjust( (ULONG)~0 ),
66 nLastWidth(0),
67 bNewDef( FALSE )
69 // RTF default FontSize 12Pt
70 long nMM = OutputDevice::LogicToLogic( 12, MAP_POINT, MAP_100TH_MM );
71 pPool->SetPoolDefaultItem( SvxFontHeightItem( nMM, 100, EE_CHAR_FONTHEIGHT ) );
72 // freifliegender pInsDefault
73 pInsDefault = new ScRTFCellDefault( pPool );
77 ScRTFParser::~ScRTFParser()
79 delete pInsDefault;
80 delete pColTwips;
81 for ( ScRTFCellDefault* pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
82 delete pD;
83 delete pDefaultList;
87 ULONG ScRTFParser::Read( SvStream& rStream, const String& rBaseURL )
89 Link aOldLink = pEdit->GetImportHdl();
90 pEdit->SetImportHdl( LINK( this, ScRTFParser, RTFImportHdl ) );
91 ULONG nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_RTF );
92 if ( nLastToken == RTF_PAR )
94 ScEEParseEntry* pE = pList->Last();
95 if ( pE
96 // komplett leer
97 && (( pE->aSel.nStartPara == pE->aSel.nEndPara
98 && pE->aSel.nStartPos == pE->aSel.nEndPos)
99 // leerer Paragraph
100 || ( pE->aSel.nStartPara + 1 == pE->aSel.nEndPara
101 && pE->aSel.nStartPos == pEdit->GetTextLen( pE->aSel.nStartPara )
102 && pE->aSel.nEndPos == 0 )) )
103 { // den letzten leeren Absatz nicht uebernehmen
104 pList->Remove();
105 delete pE;
108 ColAdjust();
109 pEdit->SetImportHdl( aOldLink );
110 return nErr;
114 void ScRTFParser::EntryEnd( ScEEParseEntry* pE, const ESelection& aSel )
116 // Paragraph -2 stript den angehaengten leeren Paragraph
117 pE->aSel.nEndPara = aSel.nEndPara - 2;
118 // obwohl das nEndPos heisst, ist das letzte Position + 1
119 pE->aSel.nEndPos = pEdit->GetTextLen( aSel.nEndPara - 1 );
123 inline void ScRTFParser::NextRow()
125 if ( nRowMax < ++nRowCnt )
126 nRowMax = nRowCnt;
130 BOOL ScRTFParser::SeekTwips( USHORT nTwips, SCCOL* pCol )
132 USHORT nPos;
133 BOOL bFound = pColTwips->Seek_Entry( nTwips, &nPos );
134 *pCol = static_cast<SCCOL>(nPos);
135 if ( bFound )
136 return TRUE;
137 USHORT nCount = pColTwips->Count();
138 if ( !nCount )
139 return FALSE;
140 SCCOL nCol = *pCol;
141 // nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
142 if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) )
143 return TRUE;
144 // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
145 else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) )
147 (*pCol)--;
148 return TRUE;
150 return FALSE;
154 void ScRTFParser::ColAdjust()
156 if ( nStartAdjust != (ULONG)~0 )
158 SCCOL nCol = 0;
159 ScEEParseEntry* pE;
160 pE = pList->Seek( nStartAdjust );
161 while ( pE )
163 if ( pE->nCol == 0 )
164 nCol = 0;
165 pE->nCol = nCol;
166 if ( pE->nColOverlap > 1 )
167 nCol = nCol + pE->nColOverlap; // merged cells mit \clmrg
168 else
170 SeekTwips( pE->nTwips, &nCol );
171 if ( ++nCol <= pE->nCol )
172 nCol = pE->nCol + 1; // verschobene Zell-X
173 pE->nColOverlap = nCol - pE->nCol; // merged cells ohne \clmrg
175 if ( nCol > nColMax )
176 nColMax = nCol;
177 pE = pList->Next();
179 nStartAdjust = (ULONG)~0;
180 pColTwips->Remove( (USHORT)0, pColTwips->Count() );
185 IMPL_LINK( ScRTFParser, RTFImportHdl, ImportInfo*, pInfo )
187 switch ( pInfo->eState )
189 case RTFIMP_NEXTTOKEN:
190 ProcToken( pInfo );
191 break;
192 case RTFIMP_UNKNOWNATTR:
193 ProcToken( pInfo );
194 break;
195 case RTFIMP_START:
197 SvxRTFParser* pParser = (SvxRTFParser*) pInfo->pParser;
198 pParser->SetAttrPool( pPool );
199 RTFPardAttrMapIds& rMap = pParser->GetPardMap();
200 rMap.nBrush = ATTR_BACKGROUND;
201 rMap.nBox = ATTR_BORDER;
202 rMap.nShadow = ATTR_SHADOW;
204 break;
205 case RTFIMP_END:
206 if ( pInfo->aSelection.nEndPos )
207 { // falls noch Text: letzten Absatz erzeugen
208 pActDefault = NULL;
209 pInfo->nToken = RTF_PAR;
210 // EditEngine hat keinen leeren Paragraph mehr angehaengt
211 // den EntryEnd strippen koennte
212 pInfo->aSelection.nEndPara++;
213 ProcToken( pInfo );
215 break;
216 case RTFIMP_SETATTR:
217 break;
218 case RTFIMP_INSERTTEXT:
219 break;
220 case RTFIMP_INSERTPARA:
221 break;
222 default:
223 DBG_ERRORFILE("unknown ImportInfo.eState");
225 return 0;
229 // bei RTF_INTBL bzw. am Anfang von erstem RTF_CELL nach RTF_CELLX wenn es
230 // kein RTF_INTBL gab, bad behavior
231 void ScRTFParser::NewCellRow( ImportInfo* /*pInfo*/ )
233 if ( bNewDef )
235 ScRTFCellDefault* pD;
236 bNewDef = FALSE;
237 // rechts nicht buendig? => neue Tabelle
238 if ( nLastWidth
239 && ((pD = pDefaultList->Last()) != 0) && pD->nTwips != nLastWidth )
241 SCCOL n1, n2;
242 if ( !( SeekTwips( nLastWidth, &n1 )
243 && SeekTwips( pD->nTwips, &n2 ) && n1 == n2) )
244 ColAdjust();
246 // TwipCols aufbauen, erst nach nLastWidth Vergleich!
247 for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
249 SCCOL n;
250 if ( !SeekTwips( pD->nTwips, &n ) )
251 pColTwips->Insert( pD->nTwips );
254 pDefMerge = NULL;
255 pActDefault = pDefaultList->First();
256 DBG_ASSERT( pActDefault, "NewCellRow: pActDefault==0" );
263 [\par]
264 \trowd \cellx \cellx ...
265 \intbl \cell \cell ...
266 \row
267 [\par]
268 [\trowd \cellx \cellx ...]
269 \intbl \cell \cell ...
270 \row
271 [\par]
273 M$-Word:
274 ~~~~~~~~
275 [\par]
276 \trowd \cellx \cellx ...
277 \intbl \cell \cell ...
278 \intbl \row
279 [\par]
280 [\trowd \cellx \cellx ...]
281 \intbl \cell \cell ...
282 \intbl \row
283 [\par]
287 void ScRTFParser::ProcToken( ImportInfo* pInfo )
289 ScRTFCellDefault* pD;
290 ScEEParseEntry* pE;
291 switch ( pInfo->nToken )
293 case RTF_TROWD: // denotes table row defauls, before RTF_CELLX
295 if ( (pD = pDefaultList->Last()) != 0 )
296 nLastWidth = pD->nTwips;
297 nColCnt = 0;
298 for ( pD = pDefaultList->First(); pD; pD = pDefaultList->Next() )
299 delete pD;
300 pDefaultList->Clear();
301 pDefMerge = NULL;
302 nLastToken = pInfo->nToken;
304 break;
305 case RTF_CLMGF: // The first cell of cells to be merged
307 pDefMerge = pInsDefault;
308 nLastToken = pInfo->nToken;
310 break;
311 case RTF_CLMRG: // A cell to be merged with the preceding cell
313 if ( !pDefMerge )
314 pDefMerge = pDefaultList->Last();
315 DBG_ASSERT( pDefMerge, "RTF_CLMRG: pDefMerge==0" );
316 if ( pDefMerge ) // sonst rottes RTF
317 pDefMerge->nColOverlap++; // mehrere nacheinander moeglich
318 pInsDefault->nColOverlap = 0; // Flag: ignoriere diese
319 nLastToken = pInfo->nToken;
321 break;
322 case RTF_CELLX: // closes cell default
324 bNewDef = TRUE;
325 pInsDefault->nCol = nColCnt;
326 pInsDefault->nTwips = pInfo->nTokenValue; // rechter Zellenrand
327 pDefaultList->Insert( pInsDefault, LIST_APPEND );
328 // neuer freifliegender pInsDefault
329 pInsDefault = new ScRTFCellDefault( pPool );
330 if ( ++nColCnt > nColMax )
331 nColMax = nColCnt;
332 nLastToken = pInfo->nToken;
334 break;
335 case RTF_INTBL: // before the first RTF_CELL
337 // einmal ueber NextToken und einmal ueber UnknownAttrToken
338 // oder z.B. \intbl ... \cell \pard \intbl ... \cell
339 if ( nLastToken != RTF_INTBL && nLastToken != RTF_CELL && nLastToken != RTF_PAR )
341 NewCellRow( pInfo );
342 nLastToken = pInfo->nToken;
345 break;
346 case RTF_CELL: // denotes the end of a cell.
348 DBG_ASSERT( pActDefault, "RTF_CELL: pActDefault==0" );
349 if ( bNewDef || !pActDefault )
350 NewCellRow( pInfo ); // davor war kein \intbl, bad behavior
351 // rottes RTF? retten was zu retten ist
352 if ( !pActDefault )
353 pActDefault = pInsDefault;
354 if ( pActDefault->nColOverlap > 0 )
355 { // nicht merged mit vorheriger
356 pActEntry->nCol = pActDefault->nCol;
357 pActEntry->nColOverlap = pActDefault->nColOverlap;
358 pActEntry->nTwips = pActDefault->nTwips;
359 pActEntry->nRow = nRowCnt;
360 pActEntry->aItemSet.Set( pActDefault->aItemSet );
361 EntryEnd( pActEntry, pInfo->aSelection );
363 if ( nStartAdjust == (ULONG)~0 )
364 nStartAdjust = pList->Count();
365 pList->Insert( pActEntry, LIST_APPEND );
366 NewActEntry( pActEntry ); // neuer freifliegender pActEntry
368 else
369 { // aktuelle Twips der MergeCell zuweisen
370 if ( (pE = pList->Last()) != 0 )
371 pE->nTwips = pActDefault->nTwips;
372 // Selection des freifliegenden pActEntry anpassen
373 // Paragraph -1 wg. Textaufbruch in EditEngine waehrend Parse
374 pActEntry->aSel.nStartPara = pInfo->aSelection.nEndPara - 1;
376 pActDefault = pDefaultList->Next();
377 nLastToken = pInfo->nToken;
379 break;
380 case RTF_ROW: // means the end of a row
382 NextRow();
383 nLastToken = pInfo->nToken;
385 break;
386 case RTF_PAR: // Paragraph
388 if ( !pActDefault )
389 { // text not in table
390 ColAdjust(); // close the processing table
391 pActEntry->nCol = 0;
392 pActEntry->nRow = nRowCnt;
393 EntryEnd( pActEntry, pInfo->aSelection );
394 pList->Insert( pActEntry, LIST_APPEND );
395 NewActEntry( pActEntry ); // new pActEntry
396 NextRow();
398 nLastToken = pInfo->nToken;
400 break;
401 default:
402 { // do not set nLastToken
403 switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
405 case RTF_SHADINGDEF:
406 ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(
407 pInfo->nToken, pInsDefault->aItemSet, TRUE );
408 break;
409 case RTF_BRDRDEF:
410 ((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr(
411 pInfo->nToken, pInsDefault->aItemSet, TRUE );
412 break;