Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "scitems.hxx"
30 : : #include <editeng/eeitem.hxx>
31 : :
32 : :
33 : : #include <editeng/editeng.hxx>
34 : : #include <editeng/fhgtitem.hxx>
35 : : #include <editeng/svxrtf.hxx>
36 : : #include <vcl/outdev.hxx>
37 : : #include <svtools/rtftoken.h>
38 : :
39 : : #define SC_RTFPARSE_CXX
40 : : #include "rtfparse.hxx"
41 : : #include "global.hxx"
42 : : #include "document.hxx"
43 : : #include "docpool.hxx"
44 : :
45 : : #define SC_RTFTWIPTOL 10 // 10 Twips Toleranz bei Spaltenbestimmung
46 : :
47 : :
48 : :
49 : :
50 : 0 : ScRTFParser::ScRTFParser( EditEngine* pEditP ) :
51 : : ScEEParser( pEditP ),
52 : : mnCurPos(0),
53 [ # # ]: 0 : pColTwips( new ScRTFColTwips ),
54 : : pActDefault( NULL ),
55 : : pDefMerge( NULL ),
56 : : nStartAdjust( (sal_uLong)~0 ),
57 : : nLastWidth(0),
58 [ # # ][ # # ]: 0 : bNewDef( false )
59 : : {
60 : : // RTF default FontSize 12Pt
61 [ # # ]: 0 : long nMM = OutputDevice::LogicToLogic( 12, MAP_POINT, MAP_100TH_MM );
62 [ # # ][ # # ]: 0 : pPool->SetPoolDefaultItem( SvxFontHeightItem( nMM, 100, EE_CHAR_FONTHEIGHT ) );
[ # # ]
63 : : // freifliegender pInsDefault
64 [ # # ][ # # ]: 0 : pInsDefault = new ScRTFCellDefault( pPool );
65 : 0 : }
66 : :
67 : :
68 [ # # ]: 0 : ScRTFParser::~ScRTFParser()
69 : : {
70 [ # # ][ # # ]: 0 : delete pInsDefault;
71 [ # # ]: 0 : delete pColTwips;
72 [ # # ]: 0 : maDefaultList.clear();
73 [ # # ]: 0 : }
74 : :
75 : :
76 : 0 : sal_uLong ScRTFParser::Read( SvStream& rStream, const String& rBaseURL )
77 : : {
78 [ # # ]: 0 : Link aOldLink = pEdit->GetImportHdl();
79 [ # # ][ # # ]: 0 : pEdit->SetImportHdl( LINK( this, ScRTFParser, RTFImportHdl ) );
80 [ # # ]: 0 : sal_uLong nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_RTF );
81 [ # # ]: 0 : if ( nLastToken == RTF_PAR )
82 : : {
83 [ # # ]: 0 : if ( !maList.empty() )
84 : : {
85 [ # # ]: 0 : ScEEParseEntry* pE = maList.back();
86 [ # # ][ # # ]: 0 : if ( // komplett leer
[ # # ][ # # ]
[ # # ][ # # ]
87 : : ( ( pE->aSel.nStartPara == pE->aSel.nEndPara
88 : : && pE->aSel.nStartPos == pE->aSel.nEndPos
89 : : )
90 : : || // leerer Paragraph
91 : : ( pE->aSel.nStartPara + 1 == pE->aSel.nEndPara
92 [ # # ]: 0 : && pE->aSel.nStartPos == pEdit->GetTextLen( pE->aSel.nStartPara )
93 : : && pE->aSel.nEndPos == 0
94 : : )
95 : : )
96 : : )
97 : : { // den letzten leeren Absatz nicht uebernehmen
98 [ # # ]: 0 : maList.pop_back();
99 : : }
100 : : }
101 : : }
102 [ # # ]: 0 : ColAdjust();
103 [ # # ]: 0 : pEdit->SetImportHdl( aOldLink );
104 : 0 : return nErr;
105 : : }
106 : :
107 : :
108 : 0 : void ScRTFParser::EntryEnd( ScEEParseEntry* pE, const ESelection& aSel )
109 : : {
110 : : // Paragraph -2 stript den angehaengten leeren Paragraph
111 : 0 : pE->aSel.nEndPara = aSel.nEndPara - 2;
112 : : // obwohl das nEndPos heisst, ist das letzte Position + 1
113 : 0 : pE->aSel.nEndPos = pEdit->GetTextLen( aSel.nEndPara - 1 );
114 : 0 : }
115 : :
116 : :
117 : 0 : inline void ScRTFParser::NextRow()
118 : : {
119 [ # # ]: 0 : if ( nRowMax < ++nRowCnt )
120 : 0 : nRowMax = nRowCnt;
121 : 0 : }
122 : :
123 : :
124 : 0 : sal_Bool ScRTFParser::SeekTwips( sal_uInt16 nTwips, SCCOL* pCol )
125 : : {
126 [ # # ]: 0 : ScRTFColTwips::const_iterator it = pColTwips->find( nTwips );
127 [ # # ]: 0 : sal_Bool bFound = it != pColTwips->end();
128 [ # # ]: 0 : sal_uInt16 nPos = it - pColTwips->end();
129 : 0 : *pCol = static_cast<SCCOL>(nPos);
130 [ # # ]: 0 : if ( bFound )
131 : 0 : return sal_True;
132 : 0 : sal_uInt16 nCount = pColTwips->size();
133 [ # # ]: 0 : if ( !nCount )
134 : 0 : return false;
135 : 0 : SCCOL nCol = *pCol;
136 : : // nCol ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
137 [ # # ][ # # ]: 0 : if ( nCol < static_cast<SCCOL>(nCount) && (((*pColTwips)[nCol] - SC_RTFTWIPTOL) <= nTwips) )
[ # # ][ # # ]
138 : 0 : return sal_True;
139 : : // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
140 [ # # ][ # # ]: 0 : else if ( nCol != 0 && (((*pColTwips)[nCol-1] + SC_RTFTWIPTOL) >= nTwips) )
[ # # ][ # # ]
141 : : {
142 : 0 : (*pCol)--;
143 : 0 : return sal_True;
144 : : }
145 : 0 : return false;
146 : : }
147 : :
148 : :
149 : 0 : void ScRTFParser::ColAdjust()
150 : : {
151 [ # # ]: 0 : if ( nStartAdjust != (sal_uLong)~0 )
152 : : {
153 : 0 : SCCOL nCol = 0;
154 : : ScEEParseEntry* pE;
155 [ # # ]: 0 : for ( size_t i = nStartAdjust, nListSize = maList.size(); i < nListSize; ++ i )
156 : : {
157 : 0 : pE = maList[ i ];
158 [ # # ]: 0 : if ( pE->nCol == 0 )
159 : 0 : nCol = 0;
160 : 0 : pE->nCol = nCol;
161 [ # # ]: 0 : if ( pE->nColOverlap > 1 )
162 : 0 : nCol = nCol + pE->nColOverlap; // merged cells mit \clmrg
163 : : else
164 : : {
165 [ # # ]: 0 : SeekTwips( pE->nTwips, &nCol );
166 [ # # ]: 0 : if ( ++nCol <= pE->nCol )
167 : 0 : nCol = pE->nCol + 1; // verschobene Zell-X
168 : 0 : pE->nColOverlap = nCol - pE->nCol; // merged cells ohne \clmrg
169 : : }
170 [ # # ]: 0 : if ( nCol > nColMax )
171 : 0 : nColMax = nCol;
172 : : }
173 : 0 : nStartAdjust = (sal_uLong)~0;
174 : 0 : pColTwips->clear();
175 : : }
176 : 0 : }
177 : :
178 : :
179 : 0 : IMPL_LINK( ScRTFParser, RTFImportHdl, ImportInfo*, pInfo )
180 : : {
181 [ # # # # : 0 : switch ( pInfo->eState )
# # # # ]
182 : : {
183 : : case RTFIMP_NEXTTOKEN:
184 : 0 : ProcToken( pInfo );
185 : 0 : break;
186 : : case RTFIMP_UNKNOWNATTR:
187 : 0 : ProcToken( pInfo );
188 : 0 : break;
189 : : case RTFIMP_START:
190 : : {
191 : 0 : SvxRTFParser* pParser = (SvxRTFParser*) pInfo->pParser;
192 : 0 : pParser->SetAttrPool( pPool );
193 : 0 : RTFPardAttrMapIds& rMap = pParser->GetPardMap();
194 : 0 : rMap.nBrush = ATTR_BACKGROUND;
195 : 0 : rMap.nBox = ATTR_BORDER;
196 : 0 : rMap.nShadow = ATTR_SHADOW;
197 : : }
198 : 0 : break;
199 : : case RTFIMP_END:
200 [ # # ]: 0 : if ( pInfo->aSelection.nEndPos )
201 : : { // falls noch Text: letzten Absatz erzeugen
202 : 0 : pActDefault = NULL;
203 : 0 : pInfo->nToken = RTF_PAR;
204 : : // EditEngine hat keinen leeren Paragraph mehr angehaengt
205 : : // den EntryEnd strippen koennte
206 : 0 : pInfo->aSelection.nEndPara++;
207 : 0 : ProcToken( pInfo );
208 : : }
209 : 0 : break;
210 : : case RTFIMP_SETATTR:
211 : 0 : break;
212 : : case RTFIMP_INSERTTEXT:
213 : 0 : break;
214 : : case RTFIMP_INSERTPARA:
215 : 0 : break;
216 : : default:
217 : : OSL_FAIL("unknown ImportInfo.eState");
218 : : }
219 : 0 : return 0;
220 : : }
221 : :
222 : :
223 : : // bei RTF_INTBL bzw. am Anfang von erstem RTF_CELL nach RTF_CELLX wenn es
224 : : // kein RTF_INTBL gab, bad behavior
225 : 0 : void ScRTFParser::NewCellRow( ImportInfo* /*pInfo*/ )
226 : : {
227 [ # # ]: 0 : if ( bNewDef )
228 : : {
229 : 0 : bNewDef = false;
230 : : // rechts nicht buendig? => neue Tabelle
231 [ # # ][ # # ]: 0 : if ( nLastWidth && !maDefaultList.empty() )
[ # # ]
232 : : {
233 : 0 : const ScRTFCellDefault& rD = maDefaultList.back();
234 [ # # ]: 0 : if (rD.nTwips != nLastWidth)
235 : : {
236 : : SCCOL n1, n2;
237 [ # # ][ # # ]: 0 : if ( !( SeekTwips( nLastWidth, &n1 )
238 [ # # ]: 0 : && SeekTwips( rD.nTwips, &n2 )
239 : : && n1 == n2
240 [ # # ][ # # ]: 0 : )
[ # # ]
241 : : )
242 : : {
243 [ # # ]: 0 : ColAdjust();
244 : : }
245 : : }
246 : : }
247 : : // TwipCols aufbauen, erst nach nLastWidth Vergleich!
248 [ # # ]: 0 : for ( size_t i = 0, n = maDefaultList.size(); i < n; ++i )
249 : : {
250 [ # # ]: 0 : const ScRTFCellDefault& rD = maDefaultList[i];
251 : : SCCOL nCol;
252 [ # # ][ # # ]: 0 : if ( !SeekTwips(rD.nTwips, &nCol) )
253 [ # # ]: 0 : pColTwips->insert( rD.nTwips );
254 : : }
255 : : }
256 : 0 : pDefMerge = NULL;
257 [ # # ]: 0 : pActDefault = maDefaultList.empty() ? NULL : &maDefaultList[0];
258 : 0 : mnCurPos = 0;
259 : : OSL_ENSURE( pActDefault, "NewCellRow: pActDefault==0" );
260 : 0 : }
261 : :
262 : :
263 : : /*
264 : : SW:
265 : : ~~~
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]
275 : :
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]
287 : :
288 : : */
289 : :
290 : 0 : void ScRTFParser::ProcToken( ImportInfo* pInfo )
291 : : {
292 : : ScEEParseEntry* pE;
293 [ # # # # : 0 : switch ( pInfo->nToken )
# # # #
# ]
294 : : {
295 : : case RTF_TROWD: // denotes table row defauls, before RTF_CELLX
296 : : {
297 [ # # ]: 0 : if (!maDefaultList.empty())
298 : 0 : nLastWidth = maDefaultList.back().nTwips;
299 : :
300 : 0 : nColCnt = 0;
301 : 0 : maDefaultList.clear();
302 : 0 : pDefMerge = NULL;
303 : 0 : nLastToken = pInfo->nToken;
304 : 0 : mnCurPos = 0;
305 : : }
306 : 0 : break;
307 : : case RTF_CLMGF: // The first cell of cells to be merged
308 : : {
309 : 0 : pDefMerge = pInsDefault;
310 : 0 : nLastToken = pInfo->nToken;
311 : : }
312 : 0 : break;
313 : : case RTF_CLMRG: // A cell to be merged with the preceding cell
314 : : {
315 [ # # ][ # # ]: 0 : if (!pDefMerge && !maDefaultList.empty())
[ # # ]
316 : : {
317 : 0 : pDefMerge = &maDefaultList.back();
318 : 0 : mnCurPos = maDefaultList.size() - 1;
319 : : }
320 : : OSL_ENSURE( pDefMerge, "RTF_CLMRG: pDefMerge==0" );
321 [ # # ]: 0 : if ( pDefMerge ) // sonst rottes RTF
322 : 0 : pDefMerge->nColOverlap++; // mehrere nacheinander moeglich
323 : 0 : pInsDefault->nColOverlap = 0; // Flag: ignoriere diese
324 : 0 : nLastToken = pInfo->nToken;
325 : : }
326 : 0 : break;
327 : : case RTF_CELLX: // closes cell default
328 : : {
329 : 0 : bNewDef = sal_True;
330 : 0 : pInsDefault->nCol = nColCnt;
331 : 0 : pInsDefault->nTwips = pInfo->nTokenValue; // rechter Zellenrand
332 : 0 : maDefaultList.push_back( pInsDefault );
333 : : // neuer freifliegender pInsDefault
334 [ # # ]: 0 : pInsDefault = new ScRTFCellDefault( pPool );
335 [ # # ]: 0 : if ( ++nColCnt > nColMax )
336 : 0 : nColMax = nColCnt;
337 : 0 : nLastToken = pInfo->nToken;
338 : : }
339 : 0 : break;
340 : : case RTF_INTBL: // before the first RTF_CELL
341 : : {
342 : : // einmal ueber NextToken und einmal ueber UnknownAttrToken
343 : : // oder z.B. \intbl ... \cell \pard \intbl ... \cell
344 [ # # ][ # # ]: 0 : if ( nLastToken != RTF_INTBL && nLastToken != RTF_CELL && nLastToken != RTF_PAR )
[ # # ]
345 : : {
346 : 0 : NewCellRow( pInfo );
347 : 0 : nLastToken = pInfo->nToken;
348 : : }
349 : : }
350 : 0 : break;
351 : : case RTF_CELL: // denotes the end of a cell.
352 : : {
353 : : OSL_ENSURE( pActDefault, "RTF_CELL: pActDefault==0" );
354 [ # # ][ # # ]: 0 : if ( bNewDef || !pActDefault )
355 : 0 : NewCellRow( pInfo ); // davor war kein \intbl, bad behavior
356 : : // rottes RTF? retten was zu retten ist
357 [ # # ]: 0 : if ( !pActDefault )
358 : 0 : pActDefault = pInsDefault;
359 [ # # ]: 0 : if ( pActDefault->nColOverlap > 0 )
360 : : { // nicht merged mit vorheriger
361 : 0 : pActEntry->nCol = pActDefault->nCol;
362 : 0 : pActEntry->nColOverlap = pActDefault->nColOverlap;
363 : 0 : pActEntry->nTwips = pActDefault->nTwips;
364 : 0 : pActEntry->nRow = nRowCnt;
365 : 0 : pActEntry->aItemSet.Set( pActDefault->aItemSet );
366 : 0 : EntryEnd( pActEntry, pInfo->aSelection );
367 : :
368 [ # # ]: 0 : if ( nStartAdjust == (sal_uLong)~0 )
369 : 0 : nStartAdjust = maList.size();
370 : 0 : maList.push_back( pActEntry );
371 : 0 : NewActEntry( pActEntry ); // neuer freifliegender pActEntry
372 : : }
373 : : else
374 : : { // aktuelle Twips der MergeCell zuweisen
375 [ # # ]: 0 : if ( !maList.empty() )
376 : : {
377 : 0 : pE = maList.back();
378 : 0 : pE->nTwips = pActDefault->nTwips;
379 : : }
380 : : // Selection des freifliegenden pActEntry anpassen
381 : : // Paragraph -1 wg. Textaufbruch in EditEngine waehrend Parse
382 : 0 : pActEntry->aSel.nStartPara = pInfo->aSelection.nEndPara - 1;
383 : : }
384 : :
385 : 0 : pActDefault = NULL;
386 [ # # ][ # # ]: 0 : if (!maDefaultList.empty() && (mnCurPos+1) < maDefaultList.size())
[ # # ]
387 : 0 : pActDefault = &maDefaultList[++mnCurPos];
388 : :
389 : 0 : nLastToken = pInfo->nToken;
390 : : }
391 : 0 : break;
392 : : case RTF_ROW: // means the end of a row
393 : : {
394 : 0 : NextRow();
395 : 0 : nLastToken = pInfo->nToken;
396 : : }
397 : 0 : break;
398 : : case RTF_PAR: // Paragraph
399 : : {
400 [ # # ]: 0 : if ( !pActDefault )
401 : : { // text not in table
402 : 0 : ColAdjust(); // close the processing table
403 : 0 : pActEntry->nCol = 0;
404 : 0 : pActEntry->nRow = nRowCnt;
405 : 0 : EntryEnd( pActEntry, pInfo->aSelection );
406 : 0 : maList.push_back( pActEntry );
407 : 0 : NewActEntry( pActEntry ); // new pActEntry
408 : 0 : NextRow();
409 : : }
410 : 0 : nLastToken = pInfo->nToken;
411 : : }
412 : 0 : break;
413 : : default:
414 : : { // do not set nLastToken
415 [ # # # ]: 0 : switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
416 : : {
417 : : case RTF_SHADINGDEF:
418 : : ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(
419 : 0 : pInfo->nToken, pInsDefault->aItemSet, sal_True );
420 : 0 : break;
421 : : case RTF_BRDRDEF:
422 : : ((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr(
423 : 0 : pInfo->nToken, pInsDefault->aItemSet, sal_True );
424 : 0 : break;
425 : : }
426 : : }
427 : : }
428 : 0 : }
429 : :
430 : :
431 : :
432 : :
433 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|