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