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