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 :
21 : #include <boost/shared_ptr.hpp>
22 : #include <comphelper/string.hxx>
23 :
24 : #include "scitems.hxx"
25 : #include <editeng/eeitem.hxx>
26 :
27 : #include <svtools/htmlcfg.hxx>
28 : #include <svx/algitem.hxx>
29 : #include <editeng/colritem.hxx>
30 : #include <editeng/brushitem.hxx>
31 : #include <editeng/editeng.hxx>
32 : #include <editeng/fhgtitem.hxx>
33 : #include <editeng/fontitem.hxx>
34 : #include <editeng/postitem.hxx>
35 : #include <editeng/udlnitem.hxx>
36 : #include <editeng/wghtitem.hxx>
37 : #include <editeng/boxitem.hxx>
38 : #include <editeng/justifyitem.hxx>
39 : #include <sfx2/objsh.hxx>
40 : #include <svl/eitem.hxx>
41 : #include <svl/intitem.hxx>
42 : #include <vcl/graphicfilter.hxx>
43 : #include <svtools/parhtml.hxx>
44 : #include <svtools/htmlkywd.hxx>
45 : #include <svtools/htmltokn.h>
46 : #include <sfx2/docfile.hxx>
47 :
48 : #include <vcl/svapp.hxx>
49 : #include <tools/urlobj.hxx>
50 : #include <tools/tenccvt.hxx>
51 :
52 : #include <rtl/tencinfo.h>
53 :
54 : #include "htmlpars.hxx"
55 : #include "global.hxx"
56 : #include "document.hxx"
57 : #include "rangelst.hxx"
58 :
59 : #include <config_orcus.h>
60 :
61 : #if ENABLE_ORCUS
62 : #include <orcus/css_parser.hpp>
63 : #endif
64 :
65 : #include <com/sun/star/document/XDocumentProperties.hpp>
66 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
67 : #include <boost/scoped_array.hpp>
68 :
69 : using ::editeng::SvxBorderLine;
70 : using namespace ::com::sun::star;
71 :
72 1 : ScHTMLStyles::ScHTMLStyles() : maEmpty() {}
73 :
74 0 : void ScHTMLStyles::add(const char* pElemName, size_t nElemName, const char* pClassName, size_t nClassName,
75 : const OUString& aProp, const OUString& aValue)
76 : {
77 0 : if (pElemName)
78 : {
79 0 : OUString aElem(pElemName, nElemName, RTL_TEXTENCODING_UTF8);
80 0 : aElem = aElem.toAsciiLowerCase();
81 0 : if (pClassName)
82 : {
83 : // Both element and class names given.
84 0 : ElemsType::iterator itrElem = maElemProps.find(aElem);
85 0 : if (itrElem == maElemProps.end())
86 : {
87 : // new element
88 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
89 0 : std::auto_ptr<NamePropsType> p(new NamePropsType);
90 : SAL_WNODEPRECATED_DECLARATIONS_POP
91 0 : std::pair<ElemsType::iterator, bool> r = maElemProps.insert(aElem, p);
92 0 : if (!r.second)
93 : // insertion failed.
94 0 : return;
95 0 : itrElem = r.first;
96 : }
97 :
98 0 : NamePropsType* pClsProps = itrElem->second;
99 0 : OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
100 0 : aClass = aClass.toAsciiLowerCase();
101 0 : insertProp(*pClsProps, aClass, aProp, aValue);
102 : }
103 : else
104 : {
105 : // Element name only. Add it to the element global.
106 0 : insertProp(maElemGlobalProps, aElem, aProp, aValue);
107 0 : }
108 : }
109 : else
110 : {
111 0 : if (pClassName)
112 : {
113 : // Class name only. Add it to the global.
114 0 : OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
115 0 : aClass = aClass.toAsciiLowerCase();
116 0 : insertProp(maGlobalProps, aClass, aProp, aValue);
117 : }
118 : }
119 : }
120 :
121 0 : const OUString& ScHTMLStyles::getPropertyValue(
122 : const OUString& rElem, const OUString& rClass, const OUString& rPropName) const
123 : {
124 : // First, look into the element-class storage.
125 : {
126 0 : ElemsType::const_iterator itr = maElemProps.find(rElem);
127 0 : if (itr != maElemProps.end())
128 : {
129 0 : const NamePropsType* pClasses = itr->second;
130 0 : NamePropsType::const_iterator itr2 = pClasses->find(rClass);
131 0 : if (itr2 != pClasses->end())
132 : {
133 0 : const PropsType* pProps = itr2->second;
134 0 : PropsType::const_iterator itr3 = pProps->find(rPropName);
135 0 : if (itr3 != pProps->end())
136 0 : return itr3->second;
137 : }
138 : }
139 : }
140 : // Next, look into the class global storage.
141 : {
142 0 : NamePropsType::const_iterator itr = maGlobalProps.find(rClass);
143 0 : if (itr != maGlobalProps.end())
144 : {
145 0 : const PropsType* pProps = itr->second;
146 0 : PropsType::const_iterator itr2 = pProps->find(rPropName);
147 0 : if (itr2 != pProps->end())
148 0 : return itr2->second;
149 : }
150 : }
151 : // As the last resort, look into the element global storage.
152 : {
153 0 : NamePropsType::const_iterator itr = maElemGlobalProps.find(rClass);
154 0 : if (itr != maElemGlobalProps.end())
155 : {
156 0 : const PropsType* pProps = itr->second;
157 0 : PropsType::const_iterator itr2 = pProps->find(rPropName);
158 0 : if (itr2 != pProps->end())
159 0 : return itr2->second;
160 : }
161 : }
162 :
163 0 : return maEmpty; // nothing found.
164 : }
165 :
166 0 : void ScHTMLStyles::insertProp(
167 : NamePropsType& rStore, const OUString& aName,
168 : const OUString& aProp, const OUString& aValue)
169 : {
170 0 : NamePropsType::iterator itr = rStore.find(aName);
171 0 : if (itr == rStore.end())
172 : {
173 : // new element
174 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
175 0 : std::auto_ptr<PropsType> p(new PropsType);
176 : SAL_WNODEPRECATED_DECLARATIONS_POP
177 0 : std::pair<NamePropsType::iterator, bool> r = rStore.insert(aName, p);
178 0 : if (!r.second)
179 : // insertion failed.
180 0 : return;
181 :
182 0 : itr = r.first;
183 : }
184 :
185 0 : PropsType* pProps = itr->second;
186 0 : pProps->insert(PropsType::value_type(aProp, aValue));
187 : }
188 :
189 :
190 : // BASE class for HTML parser classes
191 :
192 :
193 1 : ScHTMLParser::ScHTMLParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
194 : ScEEParser( pEditEngine ),
195 1 : mpDoc( pDoc )
196 : {
197 1 : SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get();
198 8 : for( sal_uInt16 nIndex = 0; nIndex < SC_HTML_FONTSIZES; ++nIndex )
199 7 : maFontHeights[ nIndex ] = rHtmlOptions.GetFontSize( nIndex ) * 20;
200 1 : }
201 :
202 1 : ScHTMLParser::~ScHTMLParser()
203 : {
204 1 : }
205 :
206 0 : ScHTMLStyles& ScHTMLParser::GetStyles()
207 : {
208 0 : return maStyles;
209 : }
210 :
211 0 : ScDocument& ScHTMLParser::GetDoc()
212 : {
213 0 : return *mpDoc;
214 : }
215 :
216 0 : ScHTMLLayoutParser::ScHTMLLayoutParser(
217 : EditEngine* pEditP, const OUString& rBaseURL, const Size& aPageSizeP,
218 : ScDocument* pDocP ) :
219 : ScHTMLParser( pEditP, pDocP ),
220 : aPageSize( aPageSizeP ),
221 : aBaseURL( rBaseURL ),
222 0 : xLockedList( new ScRangeList ),
223 : pTables( NULL ),
224 0 : pColOffset( new ScHTMLColOffset ),
225 0 : pLocalColOffset( new ScHTMLColOffset ),
226 : nFirstTableCell(0),
227 : nTableLevel(0),
228 : nTable(0),
229 : nMaxTable(0),
230 : nColCntStart(0),
231 : nMaxCol(0),
232 : nTableWidth(0),
233 : nColOffset(0),
234 : nColOffsetStart(0),
235 : nOffsetTolerance( SC_HTML_OFFSET_TOLERANCE_SMALL ),
236 : bTabInTabCell( false ),
237 : bFirstRow( true ),
238 : bInCell( false ),
239 0 : bInTitle( false )
240 : {
241 0 : MakeColNoRef( pLocalColOffset, 0, 0, 0, 0 );
242 0 : MakeColNoRef( pColOffset, 0, 0, 0, 0 );
243 0 : }
244 :
245 :
246 0 : ScHTMLLayoutParser::~ScHTMLLayoutParser()
247 : {
248 0 : while ( !aTableStack.empty() )
249 : {
250 0 : ScHTMLTableStackEntry* pS = aTableStack.top();
251 0 : aTableStack.pop();
252 :
253 0 : bool found = false;
254 0 : for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
255 : {
256 0 : if ( pS->pCellEntry == maList[ i ] )
257 : {
258 0 : found = true;
259 0 : break;
260 : }
261 : }
262 0 : if ( !found )
263 0 : delete pS->pCellEntry;
264 0 : if ( pS->pLocalColOffset != pLocalColOffset )
265 0 : delete pS->pLocalColOffset;
266 0 : delete pS;
267 : }
268 0 : delete pLocalColOffset;
269 0 : delete pColOffset;
270 0 : if ( pTables )
271 : {
272 0 : for( OuterMap::const_iterator it = pTables->begin(); it != pTables->end(); ++it)
273 0 : delete it->second;
274 0 : delete pTables;
275 : }
276 0 : }
277 :
278 :
279 0 : sal_uLong ScHTMLLayoutParser::Read( SvStream& rStream, const OUString& rBaseURL )
280 : {
281 0 : Link aOldLink = pEdit->GetImportHdl();
282 0 : pEdit->SetImportHdl( LINK( this, ScHTMLLayoutParser, HTMLImportHdl ) );
283 :
284 0 : SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
285 0 : bool bLoading = pObjSh && pObjSh->IsLoading();
286 :
287 0 : SvKeyValueIteratorRef xValues;
288 0 : SvKeyValueIterator* pAttributes = NULL;
289 0 : if ( bLoading )
290 0 : pAttributes = pObjSh->GetHeaderAttributes();
291 : else
292 : {
293 : // When not loading, set up fake http headers to force the SfxHTMLParser to use UTF8
294 : // (used when pasting from clipboard)
295 0 : const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
296 0 : if( pCharSet )
297 : {
298 0 : OUString aContentType = "text/html; charset=";
299 0 : aContentType += OUString::createFromAscii( pCharSet );
300 :
301 0 : xValues = new SvKeyValueIterator;
302 0 : xValues->Append( SvKeyValue( OUString( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
303 0 : pAttributes = xValues;
304 : }
305 : }
306 :
307 0 : sal_uLong nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_HTML, pAttributes );
308 :
309 0 : pEdit->SetImportHdl( aOldLink );
310 : // Create column width
311 0 : Adjust();
312 0 : OutputDevice* pDefaultDev = Application::GetDefaultDevice();
313 0 : sal_uInt16 nCount = pColOffset->size();
314 0 : sal_uLong nOff = (*pColOffset)[0];
315 0 : Size aSize;
316 0 : for ( sal_uInt16 j = 1; j < nCount; j++ )
317 : {
318 0 : aSize.Width() = (*pColOffset)[j] - nOff;
319 0 : aSize = pDefaultDev->PixelToLogic( aSize, MapMode( MAP_TWIP ) );
320 0 : maColWidths[ j-1 ] = aSize.Width();
321 0 : nOff = (*pColOffset)[j];
322 : }
323 0 : return nErr;
324 : }
325 :
326 :
327 0 : const ScHTMLTable* ScHTMLLayoutParser::GetGlobalTable() const
328 : {
329 0 : return 0;
330 : }
331 :
332 :
333 0 : void ScHTMLLayoutParser::NewActEntry( ScEEParseEntry* pE )
334 : {
335 0 : ScEEParser::NewActEntry( pE );
336 0 : if ( pE )
337 : {
338 0 : if ( !pE->aSel.HasRange() )
339 : { // Completely empty, following text ends up in the same paragraph!
340 0 : pActEntry->aSel.nStartPara = pE->aSel.nEndPara;
341 0 : pActEntry->aSel.nStartPos = pE->aSel.nEndPos;
342 : }
343 : }
344 0 : pActEntry->aSel.nEndPara = pActEntry->aSel.nStartPara;
345 0 : pActEntry->aSel.nEndPos = pActEntry->aSel.nStartPos;
346 0 : }
347 :
348 :
349 0 : void ScHTMLLayoutParser::EntryEnd( ScEEParseEntry* pE, const ESelection& rSel )
350 : {
351 0 : if ( rSel.nEndPara >= pE->aSel.nStartPara )
352 : {
353 0 : pE->aSel.nEndPara = rSel.nEndPara;
354 0 : pE->aSel.nEndPos = rSel.nEndPos;
355 : }
356 0 : else if ( rSel.nStartPara == pE->aSel.nStartPara - 1 && !pE->aSel.HasRange() )
357 : { // Did not attach a paragraph, but empty, do nothing
358 : }
359 : else
360 : {
361 : OSL_FAIL( "EntryEnd: EditEngine ESelection End < Start" );
362 : }
363 0 : }
364 :
365 :
366 0 : void ScHTMLLayoutParser::NextRow( ImportInfo* pInfo )
367 : {
368 0 : if ( bInCell )
369 0 : CloseEntry( pInfo );
370 0 : if ( nRowMax < ++nRowCnt )
371 0 : nRowMax = nRowCnt;
372 0 : nColCnt = nColCntStart;
373 0 : nColOffset = nColOffsetStart;
374 0 : bFirstRow = false;
375 0 : }
376 :
377 :
378 0 : bool ScHTMLLayoutParser::SeekOffset( ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
379 : SCCOL* pCol, sal_uInt16 nOffsetTol )
380 : {
381 : OSL_ENSURE( pOffset, "ScHTMLLayoutParser::SeekOffset - illegal call" );
382 0 : ScHTMLColOffset::const_iterator it = pOffset->find( nOffset );
383 0 : bool bFound = it != pOffset->end();
384 0 : sal_uInt16 nPos = it - pOffset->begin();
385 0 : *pCol = static_cast<SCCOL>(nPos);
386 0 : if ( bFound )
387 0 : return true;
388 0 : sal_uInt16 nCount = pOffset->size();
389 0 : if ( !nCount )
390 0 : return false;
391 : // nPos is the position of insertion, that's where the next higher one is (or isn't)
392 0 : if ( nPos < nCount && (((*pOffset)[nPos] - nOffsetTol) <= nOffset) )
393 0 : return true;
394 : // Not smaller than everything else? Then compare with the next lower one
395 0 : else if ( nPos && (((*pOffset)[nPos-1] + nOffsetTol) >= nOffset) )
396 : {
397 0 : (*pCol)--;
398 0 : return true;
399 : }
400 0 : return false;
401 : }
402 :
403 :
404 0 : void ScHTMLLayoutParser::MakeCol( ScHTMLColOffset* pOffset, sal_uInt16& nOffset,
405 : sal_uInt16& nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
406 : {
407 : OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeCol - illegal call" );
408 : SCCOL nPos;
409 0 : if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
410 0 : nOffset = (sal_uInt16)(*pOffset)[nPos];
411 : else
412 0 : pOffset->insert( nOffset );
413 0 : if ( nWidth )
414 : {
415 0 : if ( SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
416 0 : nWidth = (sal_uInt16)(*pOffset)[nPos] - nOffset;
417 : else
418 0 : pOffset->insert( nOffset + nWidth );
419 : }
420 0 : }
421 :
422 :
423 0 : void ScHTMLLayoutParser::MakeColNoRef( ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
424 : sal_uInt16 nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
425 : {
426 : OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeColNoRef - illegal call" );
427 : SCCOL nPos;
428 0 : if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
429 0 : nOffset = (sal_uInt16)(*pOffset)[nPos];
430 : else
431 0 : pOffset->insert( nOffset );
432 0 : if ( nWidth )
433 : {
434 0 : if ( !SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
435 0 : pOffset->insert( nOffset + nWidth );
436 : }
437 0 : }
438 :
439 :
440 0 : void ScHTMLLayoutParser::ModifyOffset( ScHTMLColOffset* pOffset, sal_uInt16& nOldOffset,
441 : sal_uInt16& nNewOffset, sal_uInt16 nOffsetTol )
442 : {
443 : OSL_ENSURE( pOffset, "ScHTMLLayoutParser::ModifyOffset - illegal call" );
444 : SCCOL nPos;
445 0 : if ( !SeekOffset( pOffset, nOldOffset, &nPos, nOffsetTol ) )
446 : {
447 0 : if ( SeekOffset( pOffset, nNewOffset, &nPos, nOffsetTol ) )
448 0 : nNewOffset = (sal_uInt16)(*pOffset)[nPos];
449 : else
450 0 : pOffset->insert( nNewOffset );
451 0 : return ;
452 : }
453 0 : nOldOffset = (sal_uInt16)(*pOffset)[nPos];
454 : SCCOL nPos2;
455 0 : if ( SeekOffset( pOffset, nNewOffset, &nPos2, nOffsetTol ) )
456 : {
457 0 : nNewOffset = (sal_uInt16)(*pOffset)[nPos2];
458 0 : return ;
459 : }
460 0 : long nDiff = nNewOffset - nOldOffset;
461 0 : if ( nDiff < 0 )
462 : {
463 0 : do
464 : {
465 0 : const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
466 : } while ( nPos-- );
467 : }
468 : else
469 : {
470 0 : do
471 : {
472 0 : const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
473 0 : } while ( ++nPos < (sal_uInt16)pOffset->size() );
474 : }
475 : }
476 :
477 :
478 0 : void ScHTMLLayoutParser::SkipLocked( ScEEParseEntry* pE, bool bJoin )
479 : {
480 0 : if ( ValidCol(pE->nCol) )
481 : { // Or else this would create a wrong value at ScAddress (chance for an infinite loop)!
482 0 : bool bBadCol = false;
483 : bool bAgain;
484 : ScRange aRange( pE->nCol, pE->nRow, 0,
485 0 : pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 );
486 0 : do
487 : {
488 0 : bAgain = false;
489 0 : for ( size_t i = 0, nRanges = xLockedList->size(); i < nRanges; ++i )
490 : {
491 0 : ScRange* pR = (*xLockedList)[i];
492 0 : if ( pR->Intersects( aRange ) )
493 : {
494 0 : pE->nCol = pR->aEnd.Col() + 1;
495 0 : SCCOL nTmp = pE->nCol + pE->nColOverlap - 1;
496 0 : if ( pE->nCol > MAXCOL || nTmp > MAXCOL )
497 0 : bBadCol = true;
498 : else
499 : {
500 0 : bAgain = true;
501 0 : aRange.aStart.SetCol( pE->nCol );
502 0 : aRange.aEnd.SetCol( nTmp );
503 : }
504 0 : break;
505 : }
506 : }
507 : } while ( bAgain );
508 0 : if ( bJoin && !bBadCol )
509 0 : xLockedList->Join( aRange );
510 : }
511 0 : }
512 :
513 :
514 0 : void ScHTMLLayoutParser::Adjust()
515 : {
516 0 : xLockedList->RemoveAll();
517 :
518 0 : ScHTMLAdjustStack aStack;
519 0 : ScHTMLAdjustStackEntry* pS = NULL;
520 0 : sal_uInt16 nTab = 0;
521 0 : SCCOL nLastCol = SCCOL_MAX;
522 0 : SCROW nNextRow = 0;
523 0 : SCROW nCurRow = 0;
524 0 : sal_uInt16 nPageWidth = (sal_uInt16) aPageSize.Width();
525 0 : InnerMap* pTab = NULL;
526 0 : for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
527 : {
528 0 : ScEEParseEntry* pE = maList[ i ];
529 0 : if ( pE->nTab < nTab )
530 : { // Table finished
531 0 : if ( !aStack.empty() )
532 : {
533 0 : pS = aStack.top();
534 0 : aStack.pop();
535 :
536 0 : nLastCol = pS->nLastCol;
537 0 : nNextRow = pS->nNextRow;
538 0 : nCurRow = pS->nCurRow;
539 : }
540 0 : delete pS;
541 0 : pS = NULL;
542 0 : nTab = pE->nTab;
543 0 : if (pTables)
544 : {
545 0 : OuterMap::const_iterator it = pTables->find( nTab );
546 0 : if ( it != pTables->end() )
547 0 : pTab = it->second;
548 : }
549 :
550 : }
551 0 : SCROW nRow = pE->nRow;
552 0 : if ( pE->nCol <= nLastCol )
553 : { // Next row
554 0 : if ( pE->nRow < nNextRow )
555 0 : pE->nRow = nCurRow = nNextRow;
556 : else
557 0 : nCurRow = nNextRow = pE->nRow;
558 0 : SCROW nR = 0;
559 0 : if ( pTab )
560 : {
561 0 : InnerMap::const_iterator it = pTab->find( nCurRow );
562 0 : if ( it != pTab->end() )
563 0 : nR = it->second;
564 : }
565 0 : if ( nR )
566 0 : nNextRow += nR;
567 : else
568 0 : nNextRow++;
569 : }
570 : else
571 0 : pE->nRow = nCurRow;
572 0 : nLastCol = pE->nCol; // Read column
573 0 : if ( pE->nTab > nTab )
574 : { // New table
575 : aStack.push( new ScHTMLAdjustStackEntry(
576 0 : nLastCol, nNextRow, nCurRow ) );
577 0 : nTab = pE->nTab;
578 0 : if ( pTables )
579 : {
580 0 : OuterMap::const_iterator it = pTables->find( nTab );
581 0 : if ( it != pTables->end() )
582 0 : pTab = it->second;
583 : }
584 : // New line spacing
585 0 : SCROW nR = 0;
586 0 : if ( pTab )
587 : {
588 0 : InnerMap::const_iterator it = pTab->find( nCurRow );
589 0 : if ( it != pTab->end() )
590 0 : nR = it->second;
591 : }
592 0 : if ( nR )
593 0 : nNextRow = nCurRow + nR;
594 : else
595 0 : nNextRow = nCurRow + 1;
596 : }
597 0 : if ( nTab == 0 )
598 0 : pE->nWidth = nPageWidth;
599 : else
600 : { // Real table, no paragraphs on the field
601 0 : if ( pTab )
602 : {
603 0 : SCROW nRowSpan = pE->nRowOverlap;
604 0 : for ( SCROW j=0; j < nRowSpan; j++ )
605 : { // RowSpan resulting from merged rows
606 0 : SCROW nRows = 0;
607 0 : InnerMap::const_iterator it = pTab->find( nRow+j );
608 0 : if ( it != pTab->end() )
609 0 : nRows = it->second;
610 0 : if ( nRows > 1 )
611 : {
612 0 : pE->nRowOverlap += nRows - 1;
613 0 : if ( j == 0 )
614 : { // Merged rows move the next row
615 0 : SCROW nTmp = nCurRow + nRows;
616 0 : if ( nNextRow < nTmp )
617 0 : nNextRow = nTmp;
618 : }
619 : }
620 : }
621 : }
622 : }
623 : // Real column
624 0 : SeekOffset( pColOffset, pE->nOffset, &pE->nCol, nOffsetTolerance );
625 0 : SCCOL nColBeforeSkip = pE->nCol;
626 0 : SkipLocked( pE, false );
627 0 : if ( pE->nCol != nColBeforeSkip )
628 : {
629 0 : SCCOL nCount = (SCCOL)pColOffset->size();
630 0 : if ( nCount <= pE->nCol )
631 : {
632 0 : pE->nOffset = (sal_uInt16) (*pColOffset)[nCount-1];
633 0 : MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
634 : }
635 : else
636 : {
637 0 : pE->nOffset = (sal_uInt16) (*pColOffset)[pE->nCol];
638 : }
639 : }
640 : SCCOL nPos;
641 0 : if ( pE->nWidth && SeekOffset( pColOffset, pE->nOffset + pE->nWidth, &nPos, nOffsetTolerance ) )
642 0 : pE->nColOverlap = (nPos > pE->nCol ? nPos - pE->nCol : 1);
643 : else
644 : {
645 : //FIXME: This may not be correct, but works anyway ...
646 0 : pE->nColOverlap = 1;
647 : }
648 : xLockedList->Join( ScRange( pE->nCol, pE->nRow, 0,
649 0 : pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 ) );
650 : // Take over MaxDimensions
651 0 : SCCOL nColTmp = pE->nCol + pE->nColOverlap;
652 0 : if ( nColMax < nColTmp )
653 0 : nColMax = nColTmp;
654 0 : SCROW nRowTmp = pE->nRow + pE->nRowOverlap;
655 0 : if ( nRowMax < nRowTmp )
656 0 : nRowMax = nRowTmp;
657 : }
658 0 : while ( !aStack.empty() )
659 : {
660 0 : delete aStack.top();
661 0 : aStack.pop();
662 0 : }
663 0 : }
664 :
665 :
666 0 : sal_uInt16 ScHTMLLayoutParser::GetWidth( ScEEParseEntry* pE )
667 : {
668 0 : if ( pE->nWidth )
669 0 : return pE->nWidth;
670 0 : sal_Int32 nTmp = ::std::min( static_cast<sal_Int32>( pE->nCol -
671 0 : nColCntStart + pE->nColOverlap),
672 0 : static_cast<sal_Int32>( pLocalColOffset->size() - 1));
673 0 : SCCOL nPos = (nTmp < 0 ? 0 : static_cast<SCCOL>(nTmp));
674 0 : sal_uInt16 nOff2 = (sal_uInt16) (*pLocalColOffset)[nPos];
675 0 : if ( pE->nOffset < nOff2 )
676 0 : return nOff2 - pE->nOffset;
677 0 : return 0;
678 : }
679 :
680 :
681 0 : void ScHTMLLayoutParser::SetWidths()
682 : {
683 : ScEEParseEntry* pE;
684 : SCCOL nCol;
685 0 : if ( !nTableWidth )
686 0 : nTableWidth = (sal_uInt16) aPageSize.Width();
687 0 : SCCOL nColsPerRow = nMaxCol - nColCntStart;
688 0 : if ( nColsPerRow <= 0 )
689 0 : nColsPerRow = 1;
690 0 : if ( pLocalColOffset->size() <= 2 )
691 : { // Only PageSize, there was no width setting
692 0 : sal_uInt16 nWidth = nTableWidth / static_cast<sal_uInt16>(nColsPerRow);
693 0 : sal_uInt16 nOff = nColOffsetStart;
694 0 : pLocalColOffset->clear();
695 0 : for ( nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth )
696 : {
697 0 : MakeColNoRef( pLocalColOffset, nOff, 0, 0, 0 );
698 : }
699 0 : nTableWidth = (sal_uInt16)(pLocalColOffset->back() - pLocalColOffset->front());
700 0 : for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
701 : {
702 0 : pE = maList[ i ];
703 0 : if ( pE->nTab == nTable )
704 : {
705 0 : pE->nOffset = (sal_uInt16) (*pLocalColOffset)[pE->nCol - nColCntStart];
706 0 : pE->nWidth = 0; // to be recalculated later
707 : }
708 : }
709 : }
710 : else
711 : { // Some without width
712 : // Why actually no pE?
713 0 : if ( nFirstTableCell < maList.size() )
714 : {
715 0 : boost::scoped_array<sal_uInt16> pOffsets(new sal_uInt16[ nColsPerRow+1 ]);
716 0 : memset( pOffsets.get(), 0, (nColsPerRow+1) * sizeof(sal_uInt16) );
717 0 : boost::scoped_array<sal_uInt16> pWidths(new sal_uInt16[ nColsPerRow ]);
718 0 : memset( pWidths.get(), 0, nColsPerRow * sizeof(sal_uInt16) );
719 0 : pOffsets[0] = nColOffsetStart;
720 0 : for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
721 : {
722 0 : pE = maList[ i ];
723 0 : if ( pE->nTab == nTable && pE->nWidth )
724 : {
725 0 : nCol = pE->nCol - nColCntStart;
726 0 : if ( nCol < nColsPerRow )
727 : {
728 0 : if ( pE->nColOverlap == 1 )
729 : {
730 0 : if ( pWidths[nCol] < pE->nWidth )
731 0 : pWidths[nCol] = pE->nWidth;
732 : }
733 : else
734 : { // try to find a single undefined width
735 0 : sal_uInt16 nTotal = 0;
736 0 : bool bFound = false;
737 0 : SCCOL nHere = 0;
738 0 : SCCOL nStop = std::min( static_cast<SCCOL>(nCol + pE->nColOverlap), nColsPerRow );
739 0 : for ( ; nCol < nStop; nCol++ )
740 : {
741 0 : if ( pWidths[nCol] )
742 0 : nTotal = nTotal + pWidths[nCol];
743 : else
744 : {
745 0 : if ( bFound )
746 : {
747 0 : bFound = false;
748 0 : break; // for
749 : }
750 0 : bFound = true;
751 0 : nHere = nCol;
752 : }
753 : }
754 0 : if ( bFound && pE->nWidth > nTotal )
755 0 : pWidths[nHere] = pE->nWidth - nTotal;
756 : }
757 : }
758 : }
759 : }
760 0 : sal_uInt16 nWidths = 0;
761 0 : sal_uInt16 nUnknown = 0;
762 0 : for ( nCol = 0; nCol < nColsPerRow; nCol++ )
763 : {
764 0 : if ( pWidths[nCol] )
765 0 : nWidths = nWidths + pWidths[nCol];
766 : else
767 0 : nUnknown++;
768 : }
769 0 : if ( nUnknown )
770 : {
771 0 : sal_uInt16 nW = ((nWidths < nTableWidth) ?
772 0 : ((nTableWidth - nWidths) / nUnknown) :
773 0 : (nTableWidth / nUnknown));
774 0 : for ( nCol = 0; nCol < nColsPerRow; nCol++ )
775 : {
776 0 : if ( !pWidths[nCol] )
777 0 : pWidths[nCol] = nW;
778 : }
779 : }
780 0 : for ( nCol = 1; nCol <= nColsPerRow; nCol++ )
781 : {
782 0 : pOffsets[nCol] = pOffsets[nCol-1] + pWidths[nCol-1];
783 : }
784 0 : pLocalColOffset->clear();
785 0 : for ( nCol = 0; nCol <= nColsPerRow; nCol++ )
786 : {
787 0 : MakeColNoRef( pLocalColOffset, pOffsets[nCol], 0, 0, 0 );
788 : }
789 0 : nTableWidth = pOffsets[nColsPerRow] - pOffsets[0];
790 :
791 0 : for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
792 : {
793 0 : pE = maList[ i ];
794 0 : if ( pE->nTab == nTable )
795 : {
796 0 : nCol = pE->nCol - nColCntStart;
797 : OSL_ENSURE( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
798 0 : if ( nCol < nColsPerRow )
799 : {
800 0 : pE->nOffset = pOffsets[nCol];
801 0 : nCol = nCol + pE->nColOverlap;
802 0 : if ( nCol > nColsPerRow )
803 0 : nCol = nColsPerRow;
804 0 : pE->nWidth = pOffsets[nCol] - pE->nOffset;
805 : }
806 : }
807 0 : }
808 : }
809 : }
810 0 : if ( !pLocalColOffset->empty() )
811 : {
812 0 : sal_uInt16 nMax = (sal_uInt16) pLocalColOffset->back();
813 0 : if ( aPageSize.Width() < nMax )
814 0 : aPageSize.Width() = nMax;
815 : }
816 0 : for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
817 : {
818 0 : pE = maList[ i ];
819 0 : if ( pE->nTab == nTable )
820 : {
821 0 : if ( !pE->nWidth )
822 : {
823 0 : pE->nWidth = GetWidth( pE );
824 : OSL_ENSURE( pE->nWidth, "SetWidths: pE->nWidth == 0" );
825 : }
826 0 : MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
827 : }
828 : }
829 0 : }
830 :
831 :
832 0 : void ScHTMLLayoutParser::Colonize( ScEEParseEntry* pE )
833 : {
834 0 : if ( pE->nCol == SCCOL_MAX )
835 0 : pE->nCol = nColCnt;
836 0 : if ( pE->nRow == SCROW_MAX )
837 0 : pE->nRow = nRowCnt;
838 0 : SCCOL nCol = pE->nCol;
839 0 : SkipLocked( pE ); // Change of columns to the right
840 :
841 0 : if ( nCol < pE->nCol )
842 : { // Replaced
843 0 : nCol = pE->nCol - nColCntStart;
844 0 : SCCOL nCount = static_cast<SCCOL>(pLocalColOffset->size());
845 0 : if ( nCol < nCount )
846 0 : nColOffset = (sal_uInt16) (*pLocalColOffset)[nCol];
847 : else
848 0 : nColOffset = (sal_uInt16) (*pLocalColOffset)[nCount - 1];
849 : }
850 0 : pE->nOffset = nColOffset;
851 0 : sal_uInt16 nWidth = GetWidth( pE );
852 0 : MakeCol( pLocalColOffset, pE->nOffset, nWidth, nOffsetTolerance, nOffsetTolerance );
853 0 : if ( pE->nWidth )
854 0 : pE->nWidth = nWidth;
855 0 : nColOffset = pE->nOffset + nWidth;
856 0 : if ( nTableWidth < nColOffset - nColOffsetStart )
857 0 : nTableWidth = nColOffset - nColOffsetStart;
858 0 : }
859 :
860 :
861 0 : void ScHTMLLayoutParser::CloseEntry( ImportInfo* pInfo )
862 : {
863 0 : bInCell = false;
864 0 : if ( bTabInTabCell )
865 : { // From the stack in TableOff
866 0 : bTabInTabCell = false;
867 0 : bool found = false;
868 0 : for ( size_t i = 0, nListSize = maList.size(); i < nListSize; ++i )
869 : {
870 0 : if ( pActEntry == maList[ i ] )
871 : {
872 0 : found = true;
873 0 : break;
874 : }
875 : }
876 0 : if ( !found )
877 0 : delete pActEntry;
878 0 : NewActEntry( maList.back() ); // New free flying pActEntry
879 0 : return ;
880 : }
881 0 : if ( pActEntry->nTab == 0 )
882 0 : pActEntry->nWidth = (sal_uInt16) aPageSize.Width();
883 0 : Colonize( pActEntry );
884 0 : nColCnt = pActEntry->nCol + pActEntry->nColOverlap;
885 0 : if ( nMaxCol < nColCnt )
886 0 : nMaxCol = nColCnt; // TableStack MaxCol
887 0 : if ( nColMax < nColCnt )
888 0 : nColMax = nColCnt; // Global MaxCol for ScEEParser GetDimensions!
889 0 : EntryEnd( pActEntry, pInfo->aSelection );
890 0 : ESelection& rSel = pActEntry->aSel;
891 0 : while ( rSel.nStartPara < rSel.nEndPara
892 0 : && pEdit->GetTextLen( rSel.nStartPara ) == 0 )
893 : { // Strip preceding empty paragraphs
894 0 : rSel.nStartPara++;
895 : }
896 0 : while ( rSel.nEndPos == 0 && rSel.nEndPara > rSel.nStartPara )
897 : { // Strip successive empty paragraphs
898 0 : rSel.nEndPara--;
899 0 : rSel.nEndPos = pEdit->GetTextLen( rSel.nEndPara );
900 : }
901 0 : if ( rSel.nStartPara > rSel.nEndPara )
902 : { // Gives GPF in CreateTextObject
903 : OSL_FAIL( "CloseEntry: EditEngine ESelection Start > End" );
904 0 : rSel.nEndPara = rSel.nStartPara;
905 : }
906 0 : if ( rSel.HasRange() )
907 0 : pActEntry->aItemSet.Put( SfxBoolItem( ATTR_LINEBREAK, true ) );
908 0 : maList.push_back( pActEntry );
909 0 : NewActEntry( pActEntry ); // New free flying pActEntry
910 : }
911 :
912 :
913 0 : IMPL_LINK( ScHTMLLayoutParser, HTMLImportHdl, ImportInfo*, pInfo )
914 : {
915 0 : switch ( pInfo->eState )
916 : {
917 : case HTMLIMP_NEXTTOKEN:
918 0 : ProcToken( pInfo );
919 0 : break;
920 : case HTMLIMP_UNKNOWNATTR:
921 0 : ProcToken( pInfo );
922 0 : break;
923 : case HTMLIMP_START:
924 0 : break;
925 : case HTMLIMP_END:
926 0 : if ( pInfo->aSelection.nEndPos )
927 : {
928 : // If text remains: create paragraph, without calling CloseEntry().
929 0 : if( bInCell ) // ...but only in opened table cells.
930 : {
931 0 : bInCell = false;
932 0 : NextRow( pInfo );
933 0 : bInCell = true;
934 : }
935 0 : CloseEntry( pInfo );
936 : }
937 0 : while ( nTableLevel > 0 )
938 0 : TableOff( pInfo ); // close tables, if </TABLE> missing
939 0 : break;
940 : case HTMLIMP_SETATTR:
941 0 : break;
942 : case HTMLIMP_INSERTTEXT:
943 0 : break;
944 : case HTMLIMP_INSERTPARA:
945 0 : if ( nTableLevel < 1 )
946 : {
947 0 : CloseEntry( pInfo );
948 0 : NextRow( pInfo );
949 : }
950 0 : break;
951 : case HTMLIMP_INSERTFIELD:
952 0 : break;
953 : default:
954 : OSL_FAIL("HTMLImportHdl: unknown ImportInfo.eState");
955 : }
956 0 : return 0;
957 : }
958 :
959 :
960 : // Greatest common divisor (Euclid)
961 : // Special case: 0 and something gives 1
962 0 : static SCROW lcl_GGT( SCROW a, SCROW b )
963 : {
964 0 : if ( !a || !b )
965 0 : return 1;
966 0 : do
967 : {
968 0 : if ( a > b )
969 0 : a -= SCROW(a / b) * b;
970 : else
971 0 : b -= SCROW(b / a) * a;
972 0 : } while ( a && b );
973 0 : return ((a != 0) ? a : b);
974 : }
975 :
976 :
977 : // Lowest common multiple: a * b / GCD(a,b)
978 0 : static SCROW lcl_KGV( SCROW a, SCROW b )
979 : {
980 0 : if ( a > b ) // Make overflow even less likely
981 0 : return (a / lcl_GGT(a,b)) * b;
982 : else
983 0 : return (b / lcl_GGT(a,b)) * a;
984 : }
985 :
986 :
987 0 : void ScHTMLLayoutParser::TableDataOn( ImportInfo* pInfo )
988 : {
989 0 : if ( bInCell )
990 0 : CloseEntry( pInfo );
991 0 : if ( !nTableLevel )
992 : {
993 : OSL_FAIL( "dumbo doc! <TH> or <TD> without previous <TABLE>" );
994 0 : TableOn( pInfo );
995 : }
996 0 : bInCell = true;
997 0 : bool bHorJustifyCenterTH = (pInfo->nToken == HTML_TABLEHEADER_ON);
998 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
999 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1000 : {
1001 0 : const HTMLOption& rOption = rOptions[i];
1002 0 : switch( rOption.GetToken() )
1003 : {
1004 : case HTML_O_COLSPAN:
1005 : {
1006 0 : pActEntry->nColOverlap = ( SCCOL ) rOption.GetString().toInt32();
1007 : }
1008 0 : break;
1009 : case HTML_O_ROWSPAN:
1010 : {
1011 0 : pActEntry->nRowOverlap = ( SCROW ) rOption.GetString().toInt32();
1012 : }
1013 0 : break;
1014 : case HTML_O_ALIGN:
1015 : {
1016 0 : bHorJustifyCenterTH = false;
1017 : SvxCellHorJustify eVal;
1018 0 : const OUString& rOptVal = rOption.GetString();
1019 0 : if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
1020 0 : eVal = SVX_HOR_JUSTIFY_RIGHT;
1021 0 : else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
1022 0 : eVal = SVX_HOR_JUSTIFY_CENTER;
1023 0 : else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
1024 0 : eVal = SVX_HOR_JUSTIFY_LEFT;
1025 : else
1026 0 : eVal = SVX_HOR_JUSTIFY_STANDARD;
1027 0 : if ( eVal != SVX_HOR_JUSTIFY_STANDARD )
1028 0 : pActEntry->aItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY) );
1029 : }
1030 0 : break;
1031 : case HTML_O_VALIGN:
1032 : {
1033 : SvxCellVerJustify eVal;
1034 0 : const OUString& rOptVal = rOption.GetString();
1035 0 : if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
1036 0 : eVal = SVX_VER_JUSTIFY_TOP;
1037 0 : else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
1038 0 : eVal = SVX_VER_JUSTIFY_CENTER;
1039 0 : else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
1040 0 : eVal = SVX_VER_JUSTIFY_BOTTOM;
1041 : else
1042 0 : eVal = SVX_VER_JUSTIFY_STANDARD;
1043 0 : pActEntry->aItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY) );
1044 : }
1045 0 : break;
1046 : case HTML_O_WIDTH:
1047 : {
1048 0 : pActEntry->nWidth = GetWidthPixel( rOption );
1049 : }
1050 0 : break;
1051 : case HTML_O_BGCOLOR:
1052 : {
1053 0 : Color aColor;
1054 0 : rOption.GetColor( aColor );
1055 : pActEntry->aItemSet.Put(
1056 0 : SvxBrushItem( aColor, ATTR_BACKGROUND ) );
1057 : }
1058 0 : break;
1059 : case HTML_O_SDVAL:
1060 : {
1061 0 : pActEntry->pValStr = new OUString( rOption.GetString() );
1062 : }
1063 0 : break;
1064 : case HTML_O_SDNUM:
1065 : {
1066 0 : pActEntry->pNumStr = new OUString( rOption.GetString() );
1067 : }
1068 0 : break;
1069 : }
1070 : }
1071 0 : pActEntry->nCol = nColCnt;
1072 0 : pActEntry->nRow = nRowCnt;
1073 0 : pActEntry->nTab = nTable;
1074 :
1075 0 : if ( bHorJustifyCenterTH )
1076 : pActEntry->aItemSet.Put(
1077 0 : SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY) );
1078 0 : }
1079 :
1080 :
1081 0 : void ScHTMLLayoutParser::TableRowOn( ImportInfo* pInfo )
1082 : {
1083 0 : if ( nColCnt > nColCntStart )
1084 0 : NextRow( pInfo ); // The optional TableRowOff wasn't there
1085 0 : nColOffset = nColOffsetStart;
1086 0 : }
1087 :
1088 :
1089 0 : void ScHTMLLayoutParser::TableRowOff( ImportInfo* pInfo )
1090 : {
1091 0 : NextRow( pInfo );
1092 0 : }
1093 :
1094 :
1095 0 : void ScHTMLLayoutParser::TableDataOff( ImportInfo* pInfo )
1096 : {
1097 0 : if ( bInCell )
1098 0 : CloseEntry( pInfo ); // Only if it really was one
1099 0 : }
1100 :
1101 :
1102 0 : void ScHTMLLayoutParser::TableOn( ImportInfo* pInfo )
1103 : {
1104 0 : OUString aTabName;
1105 :
1106 0 : if ( ++nTableLevel > 1 )
1107 : { // Table in Table
1108 0 : sal_uInt16 nTmpColOffset = nColOffset; // Will be changed in Colonize()
1109 0 : Colonize( pActEntry );
1110 : aTableStack.push( new ScHTMLTableStackEntry(
1111 : pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
1112 : nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
1113 : nTableWidth, nColOffset, nColOffsetStart,
1114 0 : bFirstRow ) );
1115 0 : sal_uInt16 nLastWidth = nTableWidth;
1116 0 : nTableWidth = GetWidth( pActEntry );
1117 0 : if ( nTableWidth == nLastWidth && nMaxCol - nColCntStart > 1 )
1118 : { // There must be more than one, so this one cannot be enough
1119 0 : nTableWidth = nLastWidth / static_cast<sal_uInt16>((nMaxCol - nColCntStart));
1120 : }
1121 0 : nLastWidth = nTableWidth;
1122 0 : if ( pInfo->nToken == HTML_TABLE_ON )
1123 : { // It can still be TD or TH, if we didn't have a TABLE earlier
1124 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1125 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1126 : {
1127 0 : const HTMLOption& rOption = rOptions[i];
1128 0 : switch( rOption.GetToken() )
1129 : {
1130 : case HTML_O_WIDTH:
1131 : { // Percent: of document width or outer cell
1132 0 : nTableWidth = GetWidthPixel( rOption );
1133 : }
1134 0 : break;
1135 : case HTML_O_BORDER:
1136 : // Border is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
1137 0 : break;
1138 : case HTML_O_ID:
1139 0 : aTabName = rOption.GetString();
1140 0 : break;
1141 : }
1142 : }
1143 : }
1144 0 : bInCell = false;
1145 0 : if ( bTabInTabCell && !(nTableWidth < nLastWidth) )
1146 : { // Multiple tables in one cell, underneath each other
1147 0 : bTabInTabCell = false;
1148 0 : NextRow( pInfo );
1149 : }
1150 : else
1151 : { // It start's in this cell or next to each other
1152 0 : bTabInTabCell = false;
1153 0 : nColCntStart = nColCnt;
1154 0 : nColOffset = nTmpColOffset;
1155 0 : nColOffsetStart = nColOffset;
1156 : }
1157 :
1158 0 : ScEEParseEntry* pE = NULL;
1159 0 : if (maList.size())
1160 0 : pE = maList.back();
1161 0 : NewActEntry( pE ); // New free flying pActEntry
1162 0 : xLockedList = new ScRangeList;
1163 : }
1164 : else
1165 : { // Simple table at the document level
1166 0 : EntryEnd( pActEntry, pInfo->aSelection );
1167 0 : if ( pActEntry->aSel.HasRange() )
1168 : { // Flying text left
1169 0 : CloseEntry( pInfo );
1170 0 : NextRow( pInfo );
1171 : }
1172 : aTableStack.push( new ScHTMLTableStackEntry(
1173 : pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
1174 : nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
1175 : nTableWidth, nColOffset, nColOffsetStart,
1176 0 : bFirstRow ) );
1177 : // As soon as we have multiple tables we need to be tolerant with the offsets.
1178 0 : if (nMaxTable > 0)
1179 0 : nOffsetTolerance = SC_HTML_OFFSET_TOLERANCE_LARGE;
1180 0 : nTableWidth = 0;
1181 0 : if ( pInfo->nToken == HTML_TABLE_ON )
1182 : {
1183 : // It can still be TD or TH, if we didn't have a TABLE earlier
1184 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1185 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1186 : {
1187 0 : const HTMLOption& rOption = rOptions[i];
1188 0 : switch( rOption.GetToken() )
1189 : {
1190 : case HTML_O_WIDTH:
1191 : { // Percent: of document width or outer cell
1192 0 : nTableWidth = GetWidthPixel( rOption );
1193 : }
1194 0 : break;
1195 : case HTML_O_BORDER:
1196 : //BorderOn is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
1197 0 : break;
1198 : case HTML_O_ID:
1199 0 : aTabName = rOption.GetString();
1200 0 : break;
1201 : }
1202 : }
1203 : }
1204 : }
1205 0 : nTable = ++nMaxTable;
1206 0 : bFirstRow = true;
1207 0 : nFirstTableCell = maList.size();
1208 :
1209 0 : pLocalColOffset = new ScHTMLColOffset;
1210 0 : MakeColNoRef( pLocalColOffset, nColOffsetStart, 0, 0, 0 );
1211 0 : }
1212 :
1213 :
1214 0 : void ScHTMLLayoutParser::TableOff( ImportInfo* pInfo )
1215 : {
1216 0 : if ( bInCell )
1217 0 : CloseEntry( pInfo );
1218 0 : if ( nColCnt > nColCntStart )
1219 0 : TableRowOff( pInfo ); // The optional TableRowOff wasn't
1220 0 : if ( !nTableLevel )
1221 : {
1222 : OSL_FAIL( "dumbo doc! </TABLE> without opening <TABLE>" );
1223 0 : return ;
1224 : }
1225 0 : if ( --nTableLevel > 0 )
1226 : { // Table in Table done
1227 0 : if ( !aTableStack.empty() )
1228 : {
1229 0 : ScHTMLTableStackEntry* pS = aTableStack.top();
1230 0 : aTableStack.pop();
1231 :
1232 0 : ScEEParseEntry* pE = pS->pCellEntry;
1233 0 : SCROW nRows = nRowCnt - pS->nRowCnt;
1234 0 : if ( nRows > 1 )
1235 : { // Insert size of table at this position
1236 0 : SCROW nRow = pS->nRowCnt;
1237 0 : sal_uInt16 nTab = pS->nTable;
1238 0 : if ( !pTables )
1239 0 : pTables = new OuterMap;
1240 : // Height of outer table
1241 0 : OuterMap::const_iterator it = pTables->find( nTab );
1242 : InnerMap* pTab1;
1243 0 : if ( it == pTables->end() )
1244 : {
1245 0 : pTab1 = new InnerMap;
1246 0 : (*pTables)[ nTab ] = pTab1;
1247 : }
1248 : else
1249 0 : pTab1 = it->second;
1250 0 : SCROW nRowSpan = pE->nRowOverlap;
1251 : SCROW nRowKGV;
1252 : SCROW nRowsPerRow1; // Outer table
1253 : SCROW nRowsPerRow2; // Inner table
1254 0 : if ( nRowSpan > 1 )
1255 : { // LCM to which we can map the inner and outer rows
1256 0 : nRowKGV = lcl_KGV( nRowSpan, nRows );
1257 0 : nRowsPerRow1 = nRowKGV / nRowSpan;
1258 0 : nRowsPerRow2 = nRowKGV / nRows;
1259 : }
1260 : else
1261 : {
1262 0 : nRowKGV = nRowsPerRow1 = nRows;
1263 0 : nRowsPerRow2 = 1;
1264 : }
1265 0 : InnerMap* pTab2 = NULL;
1266 0 : if ( nRowsPerRow2 > 1 )
1267 : { // Height of the inner table
1268 0 : pTab2 = new InnerMap;
1269 0 : (*pTables)[ nTable ] = pTab2;
1270 : }
1271 : // Abuse void* Data entry of the Table class for height mapping
1272 0 : if ( nRowKGV > 1 )
1273 : {
1274 0 : if ( nRowsPerRow1 > 1 )
1275 : { // Outer
1276 0 : for ( SCROW j=0; j < nRowSpan; j++ )
1277 : {
1278 0 : sal_uLong nRowKey = nRow + j;
1279 0 : SCROW nR = (*pTab1)[ nRowKey ];
1280 0 : if ( !nR )
1281 0 : (*pTab1)[ nRowKey ] = nRowsPerRow1;
1282 0 : else if ( nRowsPerRow1 > nR )
1283 0 : (*pTab1)[ nRowKey ] = nRowsPerRow1;
1284 : //TODO: How can we improve on this?
1285 0 : else if ( nRowsPerRow1 < nR && nRowSpan == 1
1286 0 : && nTable == nMaxTable )
1287 : { // Still some space left, merge in a better way (if possible)
1288 0 : SCROW nAdd = nRowsPerRow1 - (nR % nRowsPerRow1);
1289 0 : nR += nAdd;
1290 0 : if ( (nR % nRows) == 0 )
1291 : { // Only if representable
1292 0 : SCROW nR2 = (*pTab1)[ nRowKey+1 ];
1293 0 : if ( nR2 > nAdd )
1294 : { // Only if we really have enough space
1295 0 : (*pTab1)[ nRowKey ] = nR;
1296 0 : (*pTab1)[ nRowKey+1 ] = nR2 - nAdd;
1297 0 : nRowsPerRow2 = nR / nRows;
1298 : }
1299 : }
1300 : }
1301 : }
1302 : }
1303 0 : if ( nRowsPerRow2 > 1 )
1304 : { // Inner
1305 0 : if ( !pTab2 )
1306 : { // nRowsPerRow2 could be've been incremented
1307 0 : pTab2 = new InnerMap;
1308 0 : (*pTables)[ nTable ] = pTab2;
1309 : }
1310 0 : for ( SCROW j=0; j < nRows; j++ )
1311 : {
1312 0 : sal_uLong nRowKey = nRow + j;
1313 0 : (*pTab2)[ nRowKey ] = nRowsPerRow2;
1314 : }
1315 : }
1316 : }
1317 : }
1318 :
1319 0 : SetWidths();
1320 :
1321 0 : if ( !pE->nWidth )
1322 0 : pE->nWidth = nTableWidth;
1323 0 : else if ( pE->nWidth < nTableWidth )
1324 : {
1325 0 : sal_uInt16 nOldOffset = pE->nOffset + pE->nWidth;
1326 0 : sal_uInt16 nNewOffset = pE->nOffset + nTableWidth;
1327 0 : ModifyOffset( pS->pLocalColOffset, nOldOffset, nNewOffset, nOffsetTolerance );
1328 0 : sal_uInt16 nTmp = nNewOffset - pE->nOffset - pE->nWidth;
1329 0 : pE->nWidth = nNewOffset - pE->nOffset;
1330 0 : pS->nTableWidth = pS->nTableWidth + nTmp;
1331 0 : if ( pS->nColOffset >= nOldOffset )
1332 0 : pS->nColOffset = pS->nColOffset + nTmp;
1333 : }
1334 :
1335 0 : nColCnt = pE->nCol + pE->nColOverlap;
1336 0 : nRowCnt = pS->nRowCnt;
1337 0 : nColCntStart = pS->nColCntStart;
1338 0 : nMaxCol = pS->nMaxCol;
1339 0 : nTable = pS->nTable;
1340 0 : nTableWidth = pS->nTableWidth;
1341 0 : nFirstTableCell = pS->nFirstTableCell;
1342 0 : nColOffset = pS->nColOffset;
1343 0 : nColOffsetStart = pS->nColOffsetStart;
1344 0 : bFirstRow = pS->bFirstRow;
1345 0 : xLockedList = pS->xLockedList;
1346 0 : delete pLocalColOffset;
1347 0 : pLocalColOffset = pS->pLocalColOffset;
1348 0 : delete pActEntry;
1349 : // pActEntry is kept around if a table is started in the same row
1350 : // (anything's possible in HTML); will be deleted by CloseEntry
1351 0 : pActEntry = pE;
1352 0 : delete pS;
1353 : }
1354 0 : bTabInTabCell = true;
1355 0 : bInCell = true;
1356 : }
1357 : else
1358 : { // Simple table finished
1359 0 : SetWidths();
1360 0 : nMaxCol = 0;
1361 0 : nTable = 0;
1362 0 : if ( !aTableStack.empty() )
1363 : {
1364 0 : ScHTMLTableStackEntry* pS = aTableStack.top();
1365 0 : aTableStack.pop();
1366 0 : delete pLocalColOffset;
1367 0 : pLocalColOffset = pS->pLocalColOffset;
1368 0 : delete pS;
1369 : }
1370 : }
1371 : }
1372 :
1373 :
1374 0 : void ScHTMLLayoutParser::Image( ImportInfo* pInfo )
1375 : {
1376 0 : ScHTMLImage* pImage = new ScHTMLImage;
1377 0 : pActEntry->maImageList.push_back( pImage );
1378 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1379 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1380 : {
1381 0 : const HTMLOption& rOption = rOptions[i];
1382 0 : switch( rOption.GetToken() )
1383 : {
1384 : case HTML_O_SRC:
1385 : {
1386 0 : pImage->aURL = INetURLObject::GetAbsURL( aBaseURL, rOption.GetString() );
1387 : }
1388 0 : break;
1389 : case HTML_O_ALT:
1390 : {
1391 0 : if ( !pActEntry->bHasGraphic )
1392 : { // ALT text only if not any image loaded
1393 0 : if (!pActEntry->aAltText.isEmpty())
1394 0 : pActEntry->aAltText += "; ";
1395 :
1396 0 : pActEntry->aAltText += rOption.GetString();
1397 : }
1398 : }
1399 0 : break;
1400 : case HTML_O_WIDTH:
1401 : {
1402 0 : pImage->aSize.Width() = (long)rOption.GetNumber();
1403 : }
1404 0 : break;
1405 : case HTML_O_HEIGHT:
1406 : {
1407 0 : pImage->aSize.Height() = (long)rOption.GetNumber();
1408 : }
1409 0 : break;
1410 : case HTML_O_HSPACE:
1411 : {
1412 0 : pImage->aSpace.X() = (long)rOption.GetNumber();
1413 : }
1414 0 : break;
1415 : case HTML_O_VSPACE:
1416 : {
1417 0 : pImage->aSpace.Y() = (long)rOption.GetNumber();
1418 : }
1419 0 : break;
1420 : }
1421 : }
1422 0 : if (pImage->aURL.isEmpty())
1423 : {
1424 : OSL_FAIL( "Image: graphic without URL ?!?" );
1425 0 : return ;
1426 : }
1427 :
1428 : sal_uInt16 nFormat;
1429 0 : Graphic* pGraphic = new Graphic;
1430 0 : GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
1431 0 : if ( GRFILTER_OK != GraphicFilter::LoadGraphic( pImage->aURL, pImage->aFilterName,
1432 0 : *pGraphic, &rFilter, &nFormat ) )
1433 : {
1434 0 : delete pGraphic;
1435 0 : return ; // Bad luck
1436 : }
1437 0 : if ( !pActEntry->bHasGraphic )
1438 : { // discard any ALT text in this cell if we have any image
1439 0 : pActEntry->bHasGraphic = true;
1440 0 : pActEntry->aAltText = OUString();
1441 : }
1442 0 : pImage->aFilterName = rFilter.GetImportFormatName( nFormat );
1443 0 : pImage->pGraphic = pGraphic;
1444 0 : if ( !(pImage->aSize.Width() && pImage->aSize.Height()) )
1445 : {
1446 0 : OutputDevice* pDefaultDev = Application::GetDefaultDevice();
1447 : pImage->aSize = pDefaultDev->LogicToPixel( pGraphic->GetPrefSize(),
1448 0 : pGraphic->GetPrefMapMode() );
1449 : }
1450 0 : if ( pActEntry->maImageList.size() > 0 )
1451 : {
1452 0 : long nWidth = 0;
1453 0 : for ( sal_uInt32 i=0; i < pActEntry->maImageList.size(); ++i )
1454 : {
1455 0 : ScHTMLImage* pI = &pActEntry->maImageList[ i ];
1456 0 : if ( pI->nDir & nHorizontal )
1457 0 : nWidth += pI->aSize.Width() + 2 * pI->aSpace.X();
1458 : else
1459 0 : nWidth = 0;
1460 : }
1461 0 : if ( pActEntry->nWidth
1462 0 : && (nWidth + pImage->aSize.Width() + 2 * pImage->aSpace.X()
1463 0 : >= pActEntry->nWidth) )
1464 0 : pActEntry->maImageList.back().nDir = nVertical;
1465 : }
1466 : }
1467 :
1468 :
1469 0 : void ScHTMLLayoutParser::ColOn( ImportInfo* pInfo )
1470 : {
1471 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1472 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1473 : {
1474 0 : const HTMLOption& rOption = rOptions[i];
1475 0 : switch( rOption.GetToken() )
1476 : {
1477 : case HTML_O_WIDTH:
1478 : {
1479 0 : sal_uInt16 nVal = GetWidthPixel( rOption );
1480 0 : MakeCol( pLocalColOffset, nColOffset, nVal, 0, 0 );
1481 0 : nColOffset = nColOffset + nVal;
1482 : }
1483 0 : break;
1484 : }
1485 : }
1486 0 : }
1487 :
1488 :
1489 0 : sal_uInt16 ScHTMLLayoutParser::GetWidthPixel( const HTMLOption& rOption )
1490 : {
1491 0 : const OUString& rOptVal = rOption.GetString();
1492 0 : if ( rOptVal.indexOf('%') != -1 )
1493 : { // Percent
1494 0 : sal_uInt16 nW = (nTableWidth ? nTableWidth : (sal_uInt16) aPageSize.Width());
1495 0 : return (sal_uInt16)((rOption.GetNumber() * nW) / 100);
1496 : }
1497 : else
1498 : {
1499 0 : if ( rOptVal.indexOf('*') != -1 )
1500 : { // Relative to what?
1501 : // TODO: Collect all relative values in ColArray and then MakeCol
1502 0 : return 0;
1503 : }
1504 : else
1505 0 : return (sal_uInt16)rOption.GetNumber(); // Pixel
1506 : }
1507 : }
1508 :
1509 :
1510 0 : void ScHTMLLayoutParser::AnchorOn( ImportInfo* pInfo )
1511 : {
1512 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1513 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1514 : {
1515 0 : const HTMLOption& rOption = rOptions[i];
1516 0 : switch( rOption.GetToken() )
1517 : {
1518 : case HTML_O_NAME:
1519 : {
1520 0 : pActEntry->pName = new OUString(rOption.GetString());
1521 : }
1522 0 : break;
1523 : }
1524 : }
1525 0 : }
1526 :
1527 :
1528 0 : bool ScHTMLLayoutParser::IsAtBeginningOfText( ImportInfo* pInfo )
1529 : {
1530 0 : ESelection& rSel = pActEntry->aSel;
1531 0 : return rSel.nStartPara == rSel.nEndPara &&
1532 0 : rSel.nStartPara <= pInfo->aSelection.nEndPara &&
1533 0 : pEdit->GetTextLen( rSel.nStartPara ) == 0;
1534 : }
1535 :
1536 :
1537 0 : void ScHTMLLayoutParser::FontOn( ImportInfo* pInfo )
1538 : {
1539 0 : if ( IsAtBeginningOfText( pInfo ) )
1540 : { // Only at the start of the text; applies to whole line
1541 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1542 0 : for (size_t i = 0, n = rOptions.size(); i < n; ++i)
1543 : {
1544 0 : const HTMLOption& rOption = rOptions[i];
1545 0 : switch( rOption.GetToken() )
1546 : {
1547 : case HTML_O_FACE :
1548 : {
1549 0 : const OUString& rFace = rOption.GetString();
1550 0 : OUString aFontName;
1551 0 : sal_Int32 nPos = 0;
1552 0 : while( nPos != -1 )
1553 : {
1554 : // Font list, VCL uses the semicolon as separator
1555 : // HTML uses the comma
1556 0 : OUString aFName = rFace.getToken( 0, ',', nPos );
1557 0 : aFName = comphelper::string::strip(aFName, ' ');
1558 0 : if( !aFontName.isEmpty() )
1559 0 : aFontName += ";";
1560 0 : aFontName += aFName;
1561 0 : }
1562 0 : if ( !aFontName.isEmpty() )
1563 : pActEntry->aItemSet.Put( SvxFontItem( FAMILY_DONTKNOW,
1564 0 : aFontName, EMPTY_OUSTRING, PITCH_DONTKNOW,
1565 0 : RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
1566 : }
1567 0 : break;
1568 : case HTML_O_SIZE :
1569 : {
1570 0 : sal_uInt16 nSize = (sal_uInt16) rOption.GetNumber();
1571 0 : if ( nSize == 0 )
1572 0 : nSize = 1;
1573 0 : else if ( nSize > SC_HTML_FONTSIZES )
1574 0 : nSize = SC_HTML_FONTSIZES;
1575 : pActEntry->aItemSet.Put( SvxFontHeightItem(
1576 0 : maFontHeights[nSize-1], 100, ATTR_FONT_HEIGHT ) );
1577 : }
1578 0 : break;
1579 : case HTML_O_COLOR :
1580 : {
1581 0 : Color aColor;
1582 0 : rOption.GetColor( aColor );
1583 0 : pActEntry->aItemSet.Put( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
1584 : }
1585 0 : break;
1586 : }
1587 : }
1588 : }
1589 0 : }
1590 :
1591 :
1592 0 : void ScHTMLLayoutParser::ProcToken( ImportInfo* pInfo )
1593 : {
1594 0 : bool bSetLastToken = true;
1595 0 : switch ( pInfo->nToken )
1596 : {
1597 : case HTML_META:
1598 : {
1599 0 : HTMLParser* pParser = static_cast<HTMLParser*>(pInfo->pParser);
1600 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1601 0 : mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
1602 : pParser->ParseMetaOptions(
1603 0 : xDPS->getDocumentProperties(),
1604 0 : mpDoc->GetDocumentShell()->GetHeaderAttributes() );
1605 : }
1606 0 : break;
1607 : case HTML_TITLE_ON:
1608 : {
1609 0 : bInTitle = true;
1610 0 : aString = OUString();
1611 : }
1612 0 : break;
1613 : case HTML_TITLE_OFF:
1614 : {
1615 0 : if ( bInTitle && !aString.isEmpty() )
1616 : {
1617 : // Remove blanks from line brakes
1618 0 : aString = aString.trim();
1619 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1620 : mpDoc->GetDocumentShell()->GetModel(),
1621 0 : uno::UNO_QUERY_THROW);
1622 0 : xDPS->getDocumentProperties()->setTitle(aString);
1623 : }
1624 0 : bInTitle = false;
1625 : }
1626 0 : break;
1627 : case HTML_TABLE_ON:
1628 : {
1629 0 : TableOn( pInfo );
1630 : }
1631 0 : break;
1632 : case HTML_COL_ON:
1633 : {
1634 0 : ColOn( pInfo );
1635 : }
1636 0 : break;
1637 : case HTML_TABLEHEADER_ON: // Opens row
1638 : {
1639 0 : if ( bInCell )
1640 0 : CloseEntry( pInfo );
1641 : // Do not set bInCell to true, TableDataOn does that
1642 : pActEntry->aItemSet.Put(
1643 0 : SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT) );
1644 : } // fall thru
1645 : case HTML_TABLEDATA_ON: // Opens cell
1646 : {
1647 0 : TableDataOn( pInfo );
1648 : }
1649 0 : break;
1650 : case HTML_TABLEHEADER_OFF:
1651 : case HTML_TABLEDATA_OFF: // Closes cell
1652 : {
1653 0 : TableDataOff( pInfo );
1654 : }
1655 0 : break;
1656 : case HTML_TABLEROW_ON: // Before first cell in row
1657 : {
1658 0 : TableRowOn( pInfo );
1659 : }
1660 0 : break;
1661 : case HTML_TABLEROW_OFF: // After last cell in row
1662 : {
1663 0 : TableRowOff( pInfo );
1664 : }
1665 0 : break;
1666 : case HTML_TABLE_OFF:
1667 : {
1668 0 : TableOff( pInfo );
1669 : }
1670 0 : break;
1671 : case HTML_IMAGE:
1672 : {
1673 0 : Image( pInfo );
1674 : }
1675 0 : break;
1676 : case HTML_PARABREAK_OFF:
1677 : { // We continue vertically after an image
1678 0 : if ( pActEntry->maImageList.size() > 0 )
1679 0 : pActEntry->maImageList.back().nDir = nVertical;
1680 : }
1681 0 : break;
1682 : case HTML_ANCHOR_ON:
1683 : {
1684 0 : AnchorOn( pInfo );
1685 : }
1686 0 : break;
1687 : case HTML_FONT_ON :
1688 : {
1689 0 : FontOn( pInfo );
1690 : }
1691 0 : break;
1692 : case HTML_BIGPRINT_ON :
1693 : {
1694 : // TODO: Remember current font size and increase by 1
1695 0 : if ( IsAtBeginningOfText( pInfo ) )
1696 : pActEntry->aItemSet.Put( SvxFontHeightItem(
1697 0 : maFontHeights[3], 100, ATTR_FONT_HEIGHT ) );
1698 : }
1699 0 : break;
1700 : case HTML_SMALLPRINT_ON :
1701 : {
1702 : // TODO: Remember current font size and decrease by 1
1703 0 : if ( IsAtBeginningOfText( pInfo ) )
1704 : pActEntry->aItemSet.Put( SvxFontHeightItem(
1705 0 : maFontHeights[0], 100, ATTR_FONT_HEIGHT ) );
1706 : }
1707 0 : break;
1708 : case HTML_BOLD_ON :
1709 : case HTML_STRONG_ON :
1710 : {
1711 0 : if ( IsAtBeginningOfText( pInfo ) )
1712 : pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
1713 0 : ATTR_FONT_WEIGHT ) );
1714 : }
1715 0 : break;
1716 : case HTML_ITALIC_ON :
1717 : case HTML_EMPHASIS_ON :
1718 : case HTML_ADDRESS_ON :
1719 : case HTML_BLOCKQUOTE_ON :
1720 : case HTML_BLOCKQUOTE30_ON :
1721 : case HTML_CITIATION_ON :
1722 : case HTML_VARIABLE_ON :
1723 : {
1724 0 : if ( IsAtBeginningOfText( pInfo ) )
1725 : pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
1726 0 : ATTR_FONT_POSTURE ) );
1727 : }
1728 0 : break;
1729 : case HTML_DEFINSTANCE_ON :
1730 : {
1731 0 : if ( IsAtBeginningOfText( pInfo ) )
1732 : {
1733 : pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
1734 0 : ATTR_FONT_WEIGHT ) );
1735 : pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
1736 0 : ATTR_FONT_POSTURE ) );
1737 : }
1738 : }
1739 0 : break;
1740 : case HTML_UNDERLINE_ON :
1741 : {
1742 0 : if ( IsAtBeginningOfText( pInfo ) )
1743 : pActEntry->aItemSet.Put( SvxUnderlineItem( UNDERLINE_SINGLE,
1744 0 : ATTR_FONT_UNDERLINE ) );
1745 : }
1746 0 : break;
1747 : case HTML_TEXTTOKEN:
1748 : {
1749 0 : if ( bInTitle )
1750 0 : aString += pInfo->aText;
1751 : }
1752 0 : break;
1753 : default:
1754 : { // Don't set nLastToken!
1755 0 : bSetLastToken = false;
1756 : }
1757 : }
1758 0 : if ( bSetLastToken )
1759 0 : nLastToken = pInfo->nToken;
1760 0 : }
1761 :
1762 :
1763 : // HTML DATA QUERY PARSER
1764 :
1765 :
1766 : template< typename Type >
1767 0 : inline Type getLimitedValue( const Type& rValue, const Type& rMin, const Type& rMax )
1768 0 : { return ::std::max( ::std::min( rValue, rMax ), rMin ); }
1769 :
1770 28 : ScHTMLEntry::ScHTMLEntry( const SfxItemSet& rItemSet, ScHTMLTableId nTableId ) :
1771 : ScEEParseEntry( rItemSet ),
1772 28 : mbImportAlways( false )
1773 : {
1774 28 : nTab = nTableId;
1775 28 : bEntirePara = false;
1776 28 : }
1777 :
1778 40 : bool ScHTMLEntry::HasContents() const
1779 : {
1780 40 : return mbImportAlways || aSel.HasRange() || !aAltText.isEmpty() || IsTable();
1781 : }
1782 :
1783 7 : void ScHTMLEntry::AdjustStart( const ImportInfo& rInfo )
1784 : {
1785 : // set start position
1786 7 : aSel.nStartPara = rInfo.aSelection.nStartPara;
1787 7 : aSel.nStartPos = rInfo.aSelection.nStartPos;
1788 : // adjust end position
1789 7 : if( (aSel.nEndPara < aSel.nStartPara) || ((aSel.nEndPara == aSel.nStartPara) && (aSel.nEndPos < aSel.nStartPos)) )
1790 : {
1791 0 : aSel.nEndPara = aSel.nStartPara;
1792 0 : aSel.nEndPos = aSel.nStartPos;
1793 : }
1794 7 : }
1795 :
1796 32 : void ScHTMLEntry::AdjustEnd( const ImportInfo& rInfo )
1797 : {
1798 : OSL_ENSURE( (aSel.nEndPara < rInfo.aSelection.nEndPara) ||
1799 : ((aSel.nEndPara == rInfo.aSelection.nEndPara) && (aSel.nEndPos <= rInfo.aSelection.nEndPos)),
1800 : "ScHTMLQueryParser::AdjustEntryEnd - invalid end position" );
1801 : // set end position
1802 32 : aSel.nEndPara = rInfo.aSelection.nEndPara;
1803 32 : aSel.nEndPos = rInfo.aSelection.nEndPos;
1804 32 : }
1805 :
1806 26 : void ScHTMLEntry::Strip( const EditEngine& rEditEngine )
1807 : {
1808 : // strip leading empty paragraphs
1809 58 : while( (aSel.nStartPara < aSel.nEndPara) && (rEditEngine.GetTextLen( aSel.nStartPara ) <= aSel.nStartPos) )
1810 : {
1811 6 : ++aSel.nStartPara;
1812 6 : aSel.nStartPos = 0;
1813 : }
1814 : // strip trailing empty paragraphs
1815 52 : while( (aSel.nStartPara < aSel.nEndPara) && (aSel.nEndPos == 0) )
1816 : {
1817 0 : --aSel.nEndPara;
1818 0 : aSel.nEndPos = rEditEngine.GetTextLen( aSel.nEndPara );
1819 : }
1820 26 : }
1821 :
1822 : /** A map of ScHTMLTable objects.
1823 :
1824 : Organizes the tables with a unique table key. Stores nested tables inside
1825 : the parent table and forms in this way a tree structure of tables. An
1826 : instance of this class ownes the contained table objects and deletes them
1827 : on destruction.
1828 : */
1829 : class ScHTMLTableMap
1830 : {
1831 : private:
1832 : typedef ::boost::shared_ptr< ScHTMLTable > ScHTMLTablePtr;
1833 : typedef ::std::map< ScHTMLTableId, ScHTMLTablePtr > ScHTMLTableStdMap;
1834 :
1835 : public:
1836 : typedef ScHTMLTableStdMap::iterator iterator;
1837 : typedef ScHTMLTableStdMap::const_iterator const_iterator;
1838 :
1839 : private:
1840 : ScHTMLTable& mrParentTable; /// Reference to parent table.
1841 : ScHTMLTableStdMap maTables; /// Container for all table objects.
1842 : mutable ScHTMLTable* mpCurrTable; /// Current table, used for fast search.
1843 :
1844 : public:
1845 : explicit ScHTMLTableMap( ScHTMLTable& rParentTable );
1846 : virtual ~ScHTMLTableMap();
1847 :
1848 : inline iterator begin() { return maTables.begin(); }
1849 4 : inline const_iterator begin() const { return maTables.begin(); }
1850 : inline iterator end() { return maTables.end(); }
1851 4 : inline const_iterator end() const { return maTables.end(); }
1852 : inline bool empty() const { return maTables.empty(); }
1853 :
1854 : /** Returns the specified table.
1855 : @param nTableId Unique identifier of the table.
1856 : @param bDeep true = searches deep in all nested table; false = only in this container. */
1857 : ScHTMLTable* FindTable( ScHTMLTableId nTableId, bool bDeep = true ) const;
1858 :
1859 : /** Inserts a new table into the container. This container owns the created table.
1860 : @param bPreFormText true = New table is based on preformatted text (<pre> tag). */
1861 : ScHTMLTable* CreateTable( const ImportInfo& rInfo, bool bPreFormText );
1862 :
1863 : private:
1864 : /** Sets a working table with its index for search optimization. */
1865 5 : inline void SetCurrTable( ScHTMLTable* pTable ) const
1866 5 : { if( pTable ) mpCurrTable = pTable; }
1867 : };
1868 :
1869 1 : ScHTMLTableMap::ScHTMLTableMap( ScHTMLTable& rParentTable ) :
1870 : mrParentTable(rParentTable),
1871 1 : mpCurrTable(NULL)
1872 : {
1873 1 : }
1874 :
1875 2 : ScHTMLTableMap::~ScHTMLTableMap()
1876 : {
1877 2 : }
1878 :
1879 4 : ScHTMLTable* ScHTMLTableMap::FindTable( ScHTMLTableId nTableId, bool bDeep ) const
1880 : {
1881 4 : ScHTMLTable* pResult = 0;
1882 4 : if( mpCurrTable && (nTableId == mpCurrTable->GetTableId()) )
1883 3 : pResult = mpCurrTable; // cached table
1884 : else
1885 : {
1886 1 : const_iterator aFind = maTables.find( nTableId );
1887 1 : if( aFind != maTables.end() )
1888 0 : pResult = aFind->second.get(); // table from this container
1889 : }
1890 :
1891 : // not found -> search deep in nested tables
1892 4 : if( !pResult && bDeep )
1893 2 : for( const_iterator aIter = begin(), aEnd = end(); !pResult && (aIter != aEnd); ++aIter )
1894 1 : pResult = aIter->second->FindNestedTable( nTableId );
1895 :
1896 4 : SetCurrTable( pResult );
1897 4 : return pResult;
1898 : }
1899 :
1900 1 : ScHTMLTable* ScHTMLTableMap::CreateTable( const ImportInfo& rInfo, bool bPreFormText )
1901 : {
1902 1 : ScHTMLTable* pTable = new ScHTMLTable( mrParentTable, rInfo, bPreFormText );
1903 1 : maTables[ pTable->GetTableId() ].reset( pTable );
1904 1 : SetCurrTable( pTable );
1905 1 : return pTable;
1906 : }
1907 :
1908 : /** Simplified forward iterator for convenience.
1909 :
1910 : Before the iterator can be dereferenced, it must be tested with the is()
1911 : method. The iterator may be invalid directly after construction (e.g. empty
1912 : container).
1913 : */
1914 : class ScHTMLTableIterator
1915 : {
1916 : public:
1917 : /** Constructs the iterator for the passed table map.
1918 : @param pTableMap Pointer to the table map (is allowed to be NULL). */
1919 : explicit ScHTMLTableIterator( const ScHTMLTableMap* pTableMap );
1920 :
1921 9 : inline bool is() const { return mpTableMap && maIter != maEnd; }
1922 3 : inline ScHTMLTable* operator->() { return maIter->second.get(); }
1923 : inline ScHTMLTable& operator*() { return *maIter->second; }
1924 3 : inline ScHTMLTableIterator& operator++() { ++maIter; return *this; }
1925 :
1926 : private:
1927 : ScHTMLTableMap::const_iterator maIter;
1928 : ScHTMLTableMap::const_iterator maEnd;
1929 : const ScHTMLTableMap* mpTableMap;
1930 : };
1931 :
1932 6 : ScHTMLTableIterator::ScHTMLTableIterator( const ScHTMLTableMap* pTableMap ) :
1933 6 : mpTableMap(pTableMap)
1934 : {
1935 6 : if( pTableMap )
1936 : {
1937 3 : maIter = pTableMap->begin();
1938 3 : maEnd = pTableMap->end();
1939 : }
1940 6 : }
1941 :
1942 2 : ScHTMLTableAutoId::ScHTMLTableAutoId( ScHTMLTableId& rnUnusedId ) :
1943 : mnTableId( rnUnusedId ),
1944 2 : mrnUnusedId( rnUnusedId )
1945 : {
1946 2 : ++mrnUnusedId;
1947 2 : }
1948 :
1949 1 : ScHTMLTable::ScHTMLTable( ScHTMLTable& rParentTable, const ImportInfo& rInfo, bool bPreFormText ) :
1950 : mpParentTable( &rParentTable ),
1951 : maTableId( rParentTable.maTableId.mrnUnusedId ),
1952 1 : maTableItemSet( rParentTable.GetCurrItemSet() ),
1953 : mrEditEngine( rParentTable.mrEditEngine ),
1954 : mrEEParseList( rParentTable.mrEEParseList ),
1955 : mpCurrEntryList( 0 ),
1956 : maSize( 1, 1 ),
1957 : mpParser(rParentTable.mpParser),
1958 : mbBorderOn( false ),
1959 : mbPreFormText( bPreFormText ),
1960 : mbRowOn( false ),
1961 : mbDataOn( false ),
1962 2 : mbPushEmptyLine( false )
1963 : {
1964 1 : if( mbPreFormText )
1965 : {
1966 0 : ImplRowOn();
1967 0 : ImplDataOn( ScHTMLSize( 1, 1 ) );
1968 : }
1969 : else
1970 : {
1971 1 : ProcessFormatOptions( maTableItemSet, rInfo );
1972 1 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
1973 1 : HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
1974 1 : for (; itr != itrEnd; ++itr)
1975 : {
1976 0 : switch( itr->GetToken() )
1977 : {
1978 : case HTML_O_BORDER:
1979 0 : mbBorderOn = itr->GetString().isEmpty() || (itr->GetNumber() != 0);
1980 0 : break;
1981 : case HTML_O_ID:
1982 0 : maTableName = itr->GetString();
1983 0 : break;
1984 : }
1985 : }
1986 : }
1987 :
1988 1 : CreateNewEntry( rInfo );
1989 1 : }
1990 :
1991 1 : ScHTMLTable::ScHTMLTable(
1992 : SfxItemPool& rPool,
1993 : EditEngine& rEditEngine,
1994 : ::std::vector< ScEEParseEntry* >& rEEParseList,
1995 : ScHTMLTableId& rnUnusedId, ScHTMLParser* pParser
1996 : ) :
1997 : mpParentTable( 0 ),
1998 : maTableId( rnUnusedId ),
1999 : maTableItemSet( rPool ),
2000 : mrEditEngine( rEditEngine ),
2001 : mrEEParseList( rEEParseList ),
2002 : mpCurrEntryList( 0 ),
2003 : maSize( 1, 1 ),
2004 : mpParser(pParser),
2005 : mbBorderOn( false ),
2006 : mbPreFormText( false ),
2007 : mbRowOn( false ),
2008 : mbDataOn( false ),
2009 1 : mbPushEmptyLine( false )
2010 : {
2011 : // open the first "cell" of the document
2012 1 : ImplRowOn();
2013 1 : ImplDataOn( ScHTMLSize( 1, 1 ) );
2014 1 : mxCurrEntry = CreateEntry();
2015 1 : }
2016 :
2017 3 : ScHTMLTable::~ScHTMLTable()
2018 : {
2019 3 : }
2020 :
2021 28 : const SfxItemSet& ScHTMLTable::GetCurrItemSet() const
2022 : {
2023 : // first try cell item set, then row item set, then table item set
2024 28 : return mxDataItemSet.get() ? *mxDataItemSet : (mxRowItemSet.get() ? *mxRowItemSet : maTableItemSet);
2025 : }
2026 :
2027 21 : ScHTMLSize ScHTMLTable::GetSpan( const ScHTMLPos& rCellPos ) const
2028 : {
2029 21 : ScHTMLSize aSpan( 1, 1 );
2030 21 : const ScRange* pRange = NULL;
2031 84 : if( ( (pRange = maVMergedCells.Find( rCellPos.MakeAddr() ) ) != 0)
2032 84 : || ( (pRange = maHMergedCells.Find( rCellPos.MakeAddr() ) ) != 0)
2033 : )
2034 0 : aSpan.Set( pRange->aEnd.Col() - pRange->aStart.Col() + 1, pRange->aEnd.Row() - pRange->aStart.Row() + 1 );
2035 21 : return aSpan;
2036 : }
2037 :
2038 3 : ScHTMLTable* ScHTMLTable::FindNestedTable( ScHTMLTableId nTableId ) const
2039 : {
2040 3 : return mxNestedTables.get() ? mxNestedTables->FindTable( nTableId, true ) : 0;
2041 : }
2042 :
2043 0 : void ScHTMLTable::PutItem( const SfxPoolItem& rItem )
2044 : {
2045 : OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PutItem - no current entry" );
2046 0 : if( mxCurrEntry.get() && mxCurrEntry->IsEmpty() )
2047 0 : mxCurrEntry->GetItemSet().Put( rItem );
2048 0 : }
2049 :
2050 13 : void ScHTMLTable::PutText( const ImportInfo& rInfo )
2051 : {
2052 : OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PutText - no current entry" );
2053 13 : if( mxCurrEntry.get() )
2054 : {
2055 13 : if( !mxCurrEntry->HasContents() && IsSpaceCharInfo( rInfo ) )
2056 7 : mxCurrEntry->AdjustStart( rInfo );
2057 : else
2058 6 : mxCurrEntry->AdjustEnd( rInfo );
2059 : }
2060 13 : }
2061 :
2062 6 : void ScHTMLTable::InsertPara( const ImportInfo& rInfo )
2063 : {
2064 6 : if( mxCurrEntry.get() && mbDataOn && !IsEmptyCell() )
2065 0 : mxCurrEntry->SetImportAlways();
2066 6 : PushEntry( rInfo );
2067 6 : CreateNewEntry( rInfo );
2068 6 : InsertLeadingEmptyLine();
2069 6 : }
2070 :
2071 0 : void ScHTMLTable::BreakOn()
2072 : {
2073 : // empty line, if <br> is at start of cell
2074 0 : mbPushEmptyLine = !mbPreFormText && mbDataOn && IsEmptyCell();
2075 0 : }
2076 :
2077 0 : void ScHTMLTable::HeadingOn()
2078 : {
2079 : // call directly, InsertPara() has not been called before
2080 0 : InsertLeadingEmptyLine();
2081 0 : }
2082 :
2083 6 : void ScHTMLTable::InsertLeadingEmptyLine()
2084 : {
2085 : // empty line, if <p>, </p>, <h?>, or </h*> are not at start of cell
2086 6 : mbPushEmptyLine = !mbPreFormText && mbDataOn && !IsEmptyCell();
2087 6 : }
2088 :
2089 0 : void ScHTMLTable::AnchorOn()
2090 : {
2091 : OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::AnchorOn - no current entry" );
2092 : // don't skip entries with single hyperlinks
2093 0 : if( mxCurrEntry.get() )
2094 0 : mxCurrEntry->SetImportAlways();
2095 0 : }
2096 :
2097 1 : ScHTMLTable* ScHTMLTable::TableOn( const ImportInfo& rInfo )
2098 : {
2099 1 : PushEntry( rInfo );
2100 1 : return InsertNestedTable( rInfo, false );
2101 : }
2102 :
2103 1 : ScHTMLTable* ScHTMLTable::TableOff( const ImportInfo& rInfo )
2104 : {
2105 1 : return mbPreFormText ? this : CloseTable( rInfo );
2106 : }
2107 :
2108 0 : ScHTMLTable* ScHTMLTable::PreOn( const ImportInfo& rInfo )
2109 : {
2110 0 : PushEntry( rInfo );
2111 0 : return InsertNestedTable( rInfo, true );
2112 : }
2113 :
2114 0 : ScHTMLTable* ScHTMLTable::PreOff( const ImportInfo& rInfo )
2115 : {
2116 0 : return mbPreFormText ? CloseTable( rInfo ) : this;
2117 : }
2118 :
2119 2 : void ScHTMLTable::RowOn( const ImportInfo& rInfo )
2120 : {
2121 2 : PushEntry( rInfo, true );
2122 2 : if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
2123 : {
2124 2 : ImplRowOn();
2125 2 : ProcessFormatOptions( *mxRowItemSet, rInfo );
2126 : }
2127 2 : CreateNewEntry( rInfo );
2128 2 : }
2129 :
2130 2 : void ScHTMLTable::RowOff( const ImportInfo& rInfo )
2131 : {
2132 2 : PushEntry( rInfo, true );
2133 2 : if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
2134 2 : ImplRowOff();
2135 2 : CreateNewEntry( rInfo );
2136 2 : }
2137 :
2138 : namespace {
2139 :
2140 : /**
2141 : * Decode a numbert format string stored in Excel-generated HTML's CSS
2142 : * region.
2143 : */
2144 0 : OUString decodeNumberFormat(const OUString& rFmt)
2145 : {
2146 0 : OUStringBuffer aBuf;
2147 0 : const sal_Unicode* p = rFmt.getStr();
2148 0 : sal_Int32 n = rFmt.getLength();
2149 0 : for (sal_Int32 i = 0; i < n; ++i, ++p)
2150 : {
2151 0 : if (*p == '\\')
2152 : {
2153 : // Skip '\'.
2154 0 : ++i;
2155 0 : ++p;
2156 :
2157 : // Parse all subsequent digits until first non-digit is found.
2158 0 : sal_Int32 nDigitCount = 0;
2159 0 : const sal_Unicode* p1 = p;
2160 0 : for (; i < n; ++i, ++p, ++nDigitCount)
2161 : {
2162 0 : if (*p < '0' || '9' < *p)
2163 : {
2164 0 : --i;
2165 0 : --p;
2166 0 : break;
2167 : }
2168 :
2169 : }
2170 0 : if (nDigitCount)
2171 : {
2172 : // Hex-encoded character found. Decode it back into its
2173 : // original character. An example of number format with
2174 : // hex-encoded chars: "\0022$\0022\#\,\#\#0\.00"
2175 0 : sal_uInt32 nVal = OUString(p1, nDigitCount).toUInt32(16);
2176 0 : aBuf.append(static_cast<sal_Unicode>(nVal));
2177 : }
2178 : }
2179 : else
2180 0 : aBuf.append(*p);
2181 : }
2182 0 : return aBuf.makeStringAndClear();
2183 : }
2184 :
2185 : }
2186 :
2187 6 : void ScHTMLTable::DataOn( const ImportInfo& rInfo )
2188 : {
2189 6 : PushEntry( rInfo, true );
2190 6 : if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
2191 : {
2192 : // read needed options from the <td> tag
2193 6 : ScHTMLSize aSpanSize( 1, 1 );
2194 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2195 12 : ::std::auto_ptr<OUString> pValStr, pNumStr;
2196 : SAL_WNODEPRECATED_DECLARATIONS_POP
2197 6 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
2198 6 : HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
2199 6 : sal_uInt32 nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
2200 6 : for (; itr != itrEnd; ++itr)
2201 : {
2202 0 : switch (itr->GetToken())
2203 : {
2204 : case HTML_O_COLSPAN:
2205 0 : aSpanSize.mnCols = static_cast<SCCOL>( getLimitedValue<sal_Int32>( itr->GetString().toInt32(), 1, 256 ) );
2206 0 : break;
2207 : case HTML_O_ROWSPAN:
2208 0 : aSpanSize.mnRows = static_cast<SCROW>( getLimitedValue<sal_Int32>( itr->GetString().toInt32(), 1, 256 ) );
2209 0 : break;
2210 : case HTML_O_SDVAL:
2211 0 : pValStr.reset(new OUString(itr->GetString()));
2212 0 : break;
2213 : case HTML_O_SDNUM:
2214 0 : pNumStr.reset(new OUString(itr->GetString()));
2215 0 : break;
2216 : case HTML_O_CLASS:
2217 : {
2218 : // Pick up the number format associated with this class (if
2219 : // any).
2220 0 : OUString aElem("td");
2221 0 : OUString aClass = itr->GetString();
2222 0 : OUString aProp("mso-number-format");
2223 0 : const ScHTMLStyles& rStyles = mpParser->GetStyles();
2224 0 : const OUString& rVal = rStyles.getPropertyValue(aElem, aClass, aProp);
2225 0 : if (!rVal.isEmpty())
2226 : {
2227 0 : OUString aNumFmt = decodeNumberFormat(rVal);
2228 :
2229 0 : nNumberFormat = GetFormatTable()->GetEntryKey(aNumFmt);
2230 0 : if (nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
2231 : {
2232 0 : sal_Int32 nErrPos = 0;
2233 : short nDummy;
2234 0 : bool bValidFmt = GetFormatTable()->PutEntry(aNumFmt, nErrPos, nDummy, nNumberFormat);
2235 0 : if (!bValidFmt)
2236 0 : nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
2237 0 : }
2238 0 : }
2239 : }
2240 0 : break;
2241 : }
2242 : }
2243 :
2244 6 : ImplDataOn( aSpanSize );
2245 :
2246 6 : if (nNumberFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
2247 0 : mxDataItemSet->Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat) );
2248 :
2249 6 : ProcessFormatOptions( *mxDataItemSet, rInfo );
2250 6 : CreateNewEntry( rInfo );
2251 6 : mxCurrEntry->pValStr = pValStr.release();
2252 12 : mxCurrEntry->pNumStr = pNumStr.release();
2253 : }
2254 : else
2255 0 : CreateNewEntry( rInfo );
2256 6 : }
2257 :
2258 6 : void ScHTMLTable::DataOff( const ImportInfo& rInfo )
2259 : {
2260 6 : PushEntry( rInfo, true );
2261 6 : if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
2262 6 : ImplDataOff();
2263 6 : CreateNewEntry( rInfo );
2264 6 : }
2265 :
2266 1 : void ScHTMLTable::BodyOn( const ImportInfo& rInfo )
2267 : {
2268 1 : bool bPushed = PushEntry( rInfo );
2269 1 : if( !mpParentTable )
2270 : {
2271 : // do not start new row, if nothing (no title) precedes the body.
2272 1 : if( bPushed || !mbRowOn )
2273 0 : ImplRowOn();
2274 1 : if( bPushed || !mbDataOn )
2275 0 : ImplDataOn( ScHTMLSize( 1, 1 ) );
2276 1 : ProcessFormatOptions( *mxDataItemSet, rInfo );
2277 : }
2278 1 : CreateNewEntry( rInfo );
2279 1 : }
2280 :
2281 1 : void ScHTMLTable::BodyOff( const ImportInfo& rInfo )
2282 : {
2283 1 : PushEntry( rInfo );
2284 1 : if( !mpParentTable )
2285 : {
2286 1 : ImplDataOff();
2287 1 : ImplRowOff();
2288 : }
2289 1 : CreateNewEntry( rInfo );
2290 1 : }
2291 :
2292 1 : ScHTMLTable* ScHTMLTable::CloseTable( const ImportInfo& rInfo )
2293 : {
2294 1 : if( mpParentTable ) // not allowed to close global table
2295 : {
2296 1 : PushEntry( rInfo, mbDataOn );
2297 1 : ImplDataOff();
2298 1 : ImplRowOff();
2299 1 : mpParentTable->PushTableEntry( GetTableId() );
2300 1 : mpParentTable->CreateNewEntry( rInfo );
2301 1 : if( mbPreFormText ) // enclose preformatted table with empty lines in parent table
2302 0 : mpParentTable->InsertLeadingEmptyLine();
2303 1 : return mpParentTable;
2304 : }
2305 0 : return this;
2306 : }
2307 :
2308 0 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
2309 : {
2310 0 : const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2311 0 : size_t nIndex = static_cast< size_t >( nCellPos );
2312 0 : if( nIndex >= rSizes.size() ) return 0;
2313 0 : return (nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]);
2314 : }
2315 :
2316 28 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellBegin, SCCOLROW nCellEnd ) const
2317 : {
2318 28 : const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2319 28 : size_t nBeginIdx = static_cast< size_t >( ::std::max< SCCOLROW >( nCellBegin, 0 ) );
2320 28 : size_t nEndIdx = static_cast< size_t >( ::std::min< SCCOLROW >( nCellEnd, static_cast< SCCOLROW >( rSizes.size() ) ) );
2321 28 : if (nBeginIdx >= nEndIdx ) return 0;
2322 21 : return rSizes[ nEndIdx - 1 ] - ((nBeginIdx == 0) ? 0 : rSizes[ nBeginIdx - 1 ]);
2323 : }
2324 :
2325 9 : SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient ) const
2326 : {
2327 9 : const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2328 9 : return rSizes.empty() ? 0 : rSizes.back();
2329 : }
2330 :
2331 7 : ScHTMLSize ScHTMLTable::GetDocSize( const ScHTMLPos& rCellPos ) const
2332 : {
2333 7 : ScHTMLSize aCellSpan = GetSpan( rCellPos );
2334 : return ScHTMLSize(
2335 7 : static_cast< SCCOL >( GetDocSize( tdCol, rCellPos.mnCol, rCellPos.mnCol + aCellSpan.mnCols ) ),
2336 14 : static_cast< SCROW >( GetDocSize( tdRow, rCellPos.mnRow, rCellPos.mnRow + aCellSpan.mnRows ) ) );
2337 : }
2338 :
2339 14 : SCCOLROW ScHTMLTable::GetDocPos( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
2340 : {
2341 14 : return maDocBasePos.Get( eOrient ) + GetDocSize( eOrient, 0, nCellPos );
2342 : }
2343 :
2344 7 : ScHTMLPos ScHTMLTable::GetDocPos( const ScHTMLPos& rCellPos ) const
2345 : {
2346 : return ScHTMLPos(
2347 7 : static_cast< SCCOL >( GetDocPos( tdCol, rCellPos.mnCol ) ),
2348 14 : static_cast< SCROW >( GetDocPos( tdRow, rCellPos.mnRow ) ) );
2349 : }
2350 :
2351 1 : void ScHTMLTable::GetDocRange( ScRange& rRange ) const
2352 : {
2353 1 : rRange.aStart = rRange.aEnd = maDocBasePos.MakeAddr();
2354 1 : rRange.aEnd.Move( static_cast< SCsCOL >( GetDocSize( tdCol ) ) - 1, static_cast< SCsROW >( GetDocSize( tdRow ) ) - 1, 0 );
2355 1 : }
2356 :
2357 2 : void ScHTMLTable::ApplyCellBorders( ScDocument* pDoc, const ScAddress& rFirstPos ) const
2358 : {
2359 : OSL_ENSURE( pDoc, "ScHTMLTable::ApplyCellBorders - no document" );
2360 2 : if( pDoc && mbBorderOn )
2361 : {
2362 0 : const SCCOL nLastCol = maSize.mnCols - 1;
2363 0 : const SCROW nLastRow = maSize.mnRows - 1;
2364 0 : const long nOuterLine = DEF_LINE_WIDTH_2;
2365 0 : const long nInnerLine = DEF_LINE_WIDTH_0;
2366 0 : SvxBorderLine aOuterLine(0, nOuterLine, table::BorderLineStyle::SOLID);
2367 0 : SvxBorderLine aInnerLine(0, nInnerLine, table::BorderLineStyle::SOLID);
2368 0 : SvxBoxItem aBorderItem( ATTR_BORDER );
2369 :
2370 0 : for( SCCOL nCol = 0; nCol <= nLastCol; ++nCol )
2371 : {
2372 0 : SvxBorderLine* pLeftLine = (nCol == 0) ? &aOuterLine : &aInnerLine;
2373 0 : SvxBorderLine* pRightLine = (nCol == nLastCol) ? &aOuterLine : &aInnerLine;
2374 0 : SCCOL nCellCol1 = static_cast< SCCOL >( GetDocPos( tdCol, nCol ) ) + rFirstPos.Col();
2375 0 : SCCOL nCellCol2 = nCellCol1 + static_cast< SCCOL >( GetDocSize( tdCol, nCol ) ) - 1;
2376 0 : for( SCROW nRow = 0; nRow <= nLastRow; ++nRow )
2377 : {
2378 0 : SvxBorderLine* pTopLine = (nRow == 0) ? &aOuterLine : &aInnerLine;
2379 0 : SvxBorderLine* pBottomLine = (nRow == nLastRow) ? &aOuterLine : &aInnerLine;
2380 0 : SCROW nCellRow1 = GetDocPos( tdRow, nRow ) + rFirstPos.Row();
2381 0 : SCROW nCellRow2 = nCellRow1 + GetDocSize( tdRow, nRow ) - 1;
2382 0 : for( SCCOL nCellCol = nCellCol1; nCellCol <= nCellCol2; ++nCellCol )
2383 : {
2384 0 : aBorderItem.SetLine( (nCellCol == nCellCol1) ? pLeftLine : 0, BOX_LINE_LEFT );
2385 0 : aBorderItem.SetLine( (nCellCol == nCellCol2) ? pRightLine : 0, BOX_LINE_RIGHT );
2386 0 : for( SCROW nCellRow = nCellRow1; nCellRow <= nCellRow2; ++nCellRow )
2387 : {
2388 0 : aBorderItem.SetLine( (nCellRow == nCellRow1) ? pTopLine : 0, BOX_LINE_TOP );
2389 0 : aBorderItem.SetLine( (nCellRow == nCellRow2) ? pBottomLine : 0, BOX_LINE_BOTTOM );
2390 0 : pDoc->ApplyAttr( nCellCol, nCellRow, rFirstPos.Tab(), aBorderItem );
2391 : }
2392 : }
2393 : }
2394 0 : }
2395 : }
2396 :
2397 3 : for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2398 1 : aIter->ApplyCellBorders( pDoc, rFirstPos );
2399 2 : }
2400 :
2401 0 : SvNumberFormatter* ScHTMLTable::GetFormatTable()
2402 : {
2403 0 : return mpParser->GetDoc().GetFormatTable();
2404 : }
2405 :
2406 28 : bool ScHTMLTable::IsEmptyCell() const
2407 : {
2408 28 : return mpCurrEntryList && mpCurrEntryList->empty();
2409 : }
2410 :
2411 13 : bool ScHTMLTable::IsSpaceCharInfo( const ImportInfo& rInfo )
2412 : {
2413 13 : return (rInfo.nToken == HTML_TEXTTOKEN) && (rInfo.aText.getLength() == 1) && (rInfo.aText[ 0 ] == ' ');
2414 : }
2415 :
2416 27 : ScHTMLTable::ScHTMLEntryPtr ScHTMLTable::CreateEntry() const
2417 : {
2418 27 : return ScHTMLEntryPtr( new ScHTMLEntry( GetCurrItemSet() ) );
2419 : }
2420 :
2421 26 : void ScHTMLTable::CreateNewEntry( const ImportInfo& rInfo )
2422 : {
2423 : OSL_ENSURE( !mxCurrEntry.get(), "ScHTMLTable::CreateNewEntry - old entry still present" );
2424 26 : mxCurrEntry = CreateEntry();
2425 26 : mxCurrEntry->aSel = rInfo.aSelection;
2426 26 : }
2427 :
2428 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2429 7 : void ScHTMLTable::ImplPushEntryToList( ScHTMLEntryList& rEntryList, ScHTMLEntryPtr& rxEntry )
2430 : {
2431 : // HTML entry list does not own the entries
2432 7 : rEntryList.push_back( rxEntry.get() );
2433 : // mrEEParseList (reference to member of ScEEParser) owns the entries
2434 7 : mrEEParseList.push_back( rxEntry.release() );
2435 7 : }
2436 : SAL_WNODEPRECATED_DECLARATIONS_POP
2437 :
2438 : SAL_WNODEPRECATED_DECLARATIONS_PUSH
2439 27 : bool ScHTMLTable::PushEntry( ScHTMLEntryPtr& rxEntry )
2440 : {
2441 27 : bool bPushed = false;
2442 27 : if( rxEntry.get() && rxEntry->HasContents() )
2443 : {
2444 7 : if( mpCurrEntryList )
2445 : {
2446 7 : if( mbPushEmptyLine )
2447 : {
2448 0 : ScHTMLEntryPtr xEmptyEntry = CreateEntry();
2449 0 : ImplPushEntryToList( *mpCurrEntryList, xEmptyEntry );
2450 0 : mbPushEmptyLine = false;
2451 : }
2452 7 : ImplPushEntryToList( *mpCurrEntryList, rxEntry );
2453 7 : bPushed = true;
2454 : }
2455 0 : else if( mpParentTable )
2456 : {
2457 0 : bPushed = mpParentTable->PushEntry( rxEntry );
2458 : }
2459 : else
2460 : {
2461 : OSL_FAIL( "ScHTMLTable::PushEntry - cannot push entry, no parent found" );
2462 : }
2463 : }
2464 27 : return bPushed;
2465 : }
2466 : SAL_WNODEPRECATED_DECLARATIONS_POP
2467 :
2468 26 : bool ScHTMLTable::PushEntry( const ImportInfo& rInfo, bool bLastInCell )
2469 : {
2470 : OSL_ENSURE( mxCurrEntry.get(), "ScHTMLTable::PushEntry - no current entry" );
2471 26 : bool bPushed = false;
2472 26 : if( mxCurrEntry.get() )
2473 : {
2474 26 : mxCurrEntry->AdjustEnd( rInfo );
2475 26 : mxCurrEntry->Strip( mrEditEngine );
2476 :
2477 : // import entry always, if it is the last in cell, and cell is still empty
2478 26 : if( bLastInCell && IsEmptyCell() )
2479 : {
2480 0 : mxCurrEntry->SetImportAlways();
2481 : // don't insert empty lines before single empty entries
2482 0 : if( mxCurrEntry->IsEmpty() )
2483 0 : mbPushEmptyLine = false;
2484 : }
2485 :
2486 26 : bPushed = PushEntry( mxCurrEntry );
2487 26 : mxCurrEntry.reset();
2488 : }
2489 26 : return bPushed;
2490 : }
2491 :
2492 1 : bool ScHTMLTable::PushTableEntry( ScHTMLTableId nTableId )
2493 : {
2494 : OSL_ENSURE( nTableId != SC_HTML_GLOBAL_TABLE, "ScHTMLTable::PushTableEntry - cannot push global table" );
2495 1 : bool bPushed = false;
2496 1 : if( nTableId != SC_HTML_GLOBAL_TABLE )
2497 : {
2498 1 : ScHTMLEntryPtr xEntry( new ScHTMLEntry( maTableItemSet, nTableId ) );
2499 1 : bPushed = PushEntry( xEntry );
2500 : }
2501 1 : return bPushed;
2502 : }
2503 :
2504 14 : ScHTMLTable* ScHTMLTable::GetExistingTable( ScHTMLTableId nTableId ) const
2505 : {
2506 2 : ScHTMLTable* pTable = ((nTableId != SC_HTML_GLOBAL_TABLE) && mxNestedTables.get()) ?
2507 16 : mxNestedTables->FindTable( nTableId, false ) : 0;
2508 : OSL_ENSURE( pTable || (nTableId == SC_HTML_GLOBAL_TABLE), "ScHTMLTable::GetExistingTable - table not found" );
2509 14 : return pTable;
2510 : }
2511 :
2512 1 : ScHTMLTable* ScHTMLTable::InsertNestedTable( const ImportInfo& rInfo, bool bPreFormText )
2513 : {
2514 1 : if( !mxNestedTables.get() )
2515 1 : mxNestedTables.reset( new ScHTMLTableMap( *this ) );
2516 1 : if( bPreFormText ) // enclose new preformatted table with empty lines
2517 0 : InsertLeadingEmptyLine();
2518 1 : return mxNestedTables->CreateTable( rInfo, bPreFormText );
2519 : }
2520 :
2521 7 : void ScHTMLTable::InsertNewCell( const ScHTMLSize& rSpanSize )
2522 : {
2523 : ScRange* pRange;
2524 :
2525 : /* Find an unused cell by skipping all merged ranges that cover the
2526 : current cell position stored in maCurrCell. */
2527 14 : while( ((pRange = maVMergedCells.Find( maCurrCell.MakeAddr() )) != 0) || ((pRange = maHMergedCells.Find( maCurrCell.MakeAddr() )) != 0) )
2528 0 : maCurrCell.mnCol = pRange->aEnd.Col() + 1;
2529 7 : mpCurrEntryList = &maEntryMap[ maCurrCell ];
2530 :
2531 : /* If the new cell is merged horizontally, try to find collisions with
2532 : other vertically merged ranges. In this case, shrink existing
2533 : vertically merged ranges (do not shrink the new cell). */
2534 7 : SCCOL nColEnd = maCurrCell.mnCol + rSpanSize.mnCols;
2535 14 : for( ScAddress aAddr( maCurrCell.MakeAddr() ); aAddr.Col() < nColEnd; aAddr.IncCol() )
2536 7 : if( (pRange = maVMergedCells.Find( aAddr )) != 0 )
2537 0 : pRange->aEnd.SetRow( maCurrCell.mnRow - 1 );
2538 :
2539 : // insert the new range into the cell lists
2540 7 : ScRange aNewRange( maCurrCell.MakeAddr() );
2541 7 : aNewRange.aEnd.Move( rSpanSize.mnCols - 1, rSpanSize.mnRows - 1, 0 );
2542 7 : if( rSpanSize.mnRows > 1 )
2543 : {
2544 0 : maVMergedCells.Append( aNewRange );
2545 : /* Do not insert vertically merged ranges into maUsedCells yet,
2546 : because they may be shrunken (see above). The final vertically
2547 : merged ranges are inserted in FillEmptyCells(). */
2548 : }
2549 : else
2550 : {
2551 7 : if( rSpanSize.mnCols > 1 )
2552 0 : maHMergedCells.Append( aNewRange );
2553 : /* Insert horizontally merged ranges and single cells into
2554 : maUsedCells, they will not be changed anymore. */
2555 7 : maUsedCells.Join( aNewRange );
2556 : }
2557 :
2558 : // adjust table size
2559 7 : maSize.mnCols = ::std::max< SCCOL >( maSize.mnCols, aNewRange.aEnd.Col() + 1 );
2560 7 : maSize.mnRows = ::std::max< SCROW >( maSize.mnRows, aNewRange.aEnd.Row() + 1 );
2561 7 : }
2562 :
2563 3 : void ScHTMLTable::ImplRowOn()
2564 : {
2565 3 : if( mbRowOn )
2566 0 : ImplRowOff();
2567 3 : mxRowItemSet.reset( new SfxItemSet( maTableItemSet ) );
2568 3 : maCurrCell.mnCol = 0;
2569 3 : mbRowOn = true;
2570 3 : mbDataOn = false;
2571 3 : }
2572 :
2573 4 : void ScHTMLTable::ImplRowOff()
2574 : {
2575 4 : if( mbDataOn )
2576 0 : ImplDataOff();
2577 4 : if( mbRowOn )
2578 : {
2579 3 : mxRowItemSet.reset();
2580 3 : ++maCurrCell.mnRow;
2581 3 : mbRowOn = mbDataOn = false;
2582 : }
2583 4 : }
2584 :
2585 7 : void ScHTMLTable::ImplDataOn( const ScHTMLSize& rSpanSize )
2586 : {
2587 7 : if( mbDataOn )
2588 0 : ImplDataOff();
2589 7 : if( !mbRowOn )
2590 0 : ImplRowOn();
2591 7 : mxDataItemSet.reset( new SfxItemSet( *mxRowItemSet ) );
2592 7 : InsertNewCell( rSpanSize );
2593 7 : mbDataOn = true;
2594 7 : mbPushEmptyLine = false;
2595 7 : }
2596 :
2597 8 : void ScHTMLTable::ImplDataOff()
2598 : {
2599 8 : if( mbDataOn )
2600 : {
2601 7 : mxDataItemSet.reset();
2602 7 : ++maCurrCell.mnCol;
2603 7 : mpCurrEntryList = 0;
2604 7 : mbDataOn = false;
2605 : }
2606 8 : }
2607 :
2608 10 : void ScHTMLTable::ProcessFormatOptions( SfxItemSet& rItemSet, const ImportInfo& rInfo )
2609 : {
2610 : // special handling for table header cells
2611 10 : if( rInfo.nToken == HTML_TABLEHEADER_ON )
2612 : {
2613 0 : rItemSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
2614 0 : rItemSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
2615 : }
2616 :
2617 10 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
2618 10 : HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
2619 10 : for (; itr != itrEnd; ++itr)
2620 : {
2621 0 : switch( itr->GetToken() )
2622 : {
2623 : case HTML_O_ALIGN:
2624 : {
2625 0 : SvxCellHorJustify eVal = SVX_HOR_JUSTIFY_STANDARD;
2626 0 : const OUString& rOptVal = itr->GetString();
2627 0 : if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
2628 0 : eVal = SVX_HOR_JUSTIFY_RIGHT;
2629 0 : else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
2630 0 : eVal = SVX_HOR_JUSTIFY_CENTER;
2631 0 : else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
2632 0 : eVal = SVX_HOR_JUSTIFY_LEFT;
2633 0 : if( eVal != SVX_HOR_JUSTIFY_STANDARD )
2634 0 : rItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY ) );
2635 : }
2636 0 : break;
2637 :
2638 : case HTML_O_VALIGN:
2639 : {
2640 0 : SvxCellVerJustify eVal = SVX_VER_JUSTIFY_STANDARD;
2641 0 : const OUString& rOptVal = itr->GetString();
2642 0 : if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
2643 0 : eVal = SVX_VER_JUSTIFY_TOP;
2644 0 : else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
2645 0 : eVal = SVX_VER_JUSTIFY_CENTER;
2646 0 : else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
2647 0 : eVal = SVX_VER_JUSTIFY_BOTTOM;
2648 0 : if( eVal != SVX_VER_JUSTIFY_STANDARD )
2649 0 : rItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY ) );
2650 : }
2651 0 : break;
2652 :
2653 : case HTML_O_BGCOLOR:
2654 : {
2655 0 : Color aColor;
2656 0 : itr->GetColor( aColor );
2657 0 : rItemSet.Put( SvxBrushItem( aColor, ATTR_BACKGROUND ) );
2658 : }
2659 0 : break;
2660 : }
2661 : }
2662 10 : }
2663 :
2664 14 : void ScHTMLTable::SetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nSize )
2665 : {
2666 : OSL_ENSURE( nCellPos >= 0, "ScHTMLTable::SetDocSize - unexpected negative position" );
2667 14 : ScSizeVec& rSizes = maCumSizes[ eOrient ];
2668 14 : size_t nIndex = static_cast< size_t >( nCellPos );
2669 : // expand with height/width == 1
2670 35 : while( nIndex >= rSizes.size() )
2671 7 : rSizes.push_back( rSizes.empty() ? 1 : (rSizes.back() + 1) );
2672 : // update size of passed position and all following
2673 : // #i109987# only grow, don't shrink - use the largest needed size
2674 14 : SCsCOLROW nDiff = nSize - ((nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]));
2675 14 : if( nDiff > 0 )
2676 4 : for( ScSizeVec::iterator aIt = rSizes.begin() + nIndex, aEnd = rSizes.end(); aIt != aEnd; ++aIt )
2677 2 : *aIt += nDiff;
2678 14 : }
2679 :
2680 14 : void ScHTMLTable::CalcNeededDocSize(
2681 : ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nCellSpan, SCCOLROW nRealDocSize )
2682 : {
2683 14 : SCCOLROW nDiffSize = 0;
2684 : // in merged columns/rows: reduce needed size by size of leading columns
2685 28 : while( nCellSpan > 1 )
2686 : {
2687 0 : nDiffSize += GetDocSize( eOrient, nCellPos );
2688 0 : --nCellSpan;
2689 0 : ++nCellPos;
2690 : }
2691 : // set remaining needed size to last column/row
2692 14 : nRealDocSize -= ::std::min< SCCOLROW >( nRealDocSize - 1, nDiffSize );
2693 14 : SetDocSize( eOrient, nCellPos, nRealDocSize );
2694 14 : }
2695 :
2696 2 : void ScHTMLTable::FillEmptyCells()
2697 : {
2698 3 : for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2699 1 : aIter->FillEmptyCells();
2700 :
2701 : // insert the final vertically merged ranges into maUsedCells
2702 2 : for ( size_t i = 0, nRanges = maVMergedCells.size(); i < nRanges; ++i )
2703 : {
2704 0 : ScRange* pRange = maVMergedCells[ i ];
2705 0 : maUsedCells.Join( *pRange );
2706 : }
2707 :
2708 5 : for( ScAddress aAddr; aAddr.Row() < maSize.mnRows; aAddr.IncRow() )
2709 : {
2710 10 : for( aAddr.SetCol( 0 ); aAddr.Col() < maSize.mnCols; aAddr.IncCol() )
2711 : {
2712 7 : if( !maUsedCells.Find( aAddr ) )
2713 : {
2714 : // create a range for the lock list (used to calc. cell span)
2715 0 : ScRange aRange( aAddr );
2716 0 : do
2717 : {
2718 0 : aRange.aEnd.IncCol();
2719 : }
2720 0 : while( (aRange.aEnd.Col() < maSize.mnCols) && !maUsedCells.Find( aRange.aEnd ) );
2721 0 : aRange.aEnd.IncCol( -1 );
2722 0 : maUsedCells.Join( aRange );
2723 :
2724 : // insert a dummy entry
2725 0 : ScHTMLEntryPtr xEntry = CreateEntry();
2726 0 : ImplPushEntryToList( maEntryMap[ ScHTMLPos( aAddr ) ], xEntry );
2727 : }
2728 : }
2729 : }
2730 2 : }
2731 :
2732 2 : void ScHTMLTable::RecalcDocSize()
2733 : {
2734 : // recalc table sizes recursively from inner to outer
2735 3 : for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2736 1 : aIter->RecalcDocSize();
2737 :
2738 : /* Two passes: first calculates the sizes of single columns/rows, then
2739 : the sizes of spanned columns/rows. This allows to fill nested tables
2740 : into merged cells optimally. */
2741 : static const sal_uInt16 PASS_SINGLE = 0;
2742 : static const sal_uInt16 PASS_SPANNED = 1;
2743 6 : for( sal_uInt16 nPass = PASS_SINGLE; nPass <= PASS_SPANNED; ++nPass )
2744 : {
2745 : // iterate through every table cell
2746 4 : ScHTMLEntryMap::const_iterator aMapIterEnd = maEntryMap.end();
2747 18 : for( ScHTMLEntryMap::const_iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
2748 : {
2749 14 : const ScHTMLPos& rCellPos = aMapIter->first;
2750 14 : ScHTMLSize aCellSpan = GetSpan( rCellPos );
2751 :
2752 14 : const ScHTMLEntryList& rEntryList = aMapIter->second;
2753 14 : ScHTMLEntryList::const_iterator aListIter;
2754 14 : ScHTMLEntryList::const_iterator aListIterEnd = rEntryList.end();
2755 :
2756 : // process the dimension of the current cell in this pass?
2757 : // (pass is single and span is 1) or (pass is not single and span is not 1)
2758 14 : bool bProcessColWidth = ((nPass == PASS_SINGLE) == (aCellSpan.mnCols == 1));
2759 14 : bool bProcessRowHeight = ((nPass == PASS_SINGLE) == (aCellSpan.mnRows == 1));
2760 14 : if( bProcessColWidth || bProcessRowHeight )
2761 : {
2762 7 : ScHTMLSize aDocSize( 1, 0 ); // resulting size of the cell in document
2763 :
2764 : // expand the cell size for each cell parse entry
2765 14 : for( aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
2766 : {
2767 7 : ScHTMLTable* pTable = GetExistingTable( (*aListIter)->GetTableId() );
2768 : // find entry with maximum width
2769 7 : if( bProcessColWidth && pTable )
2770 1 : aDocSize.mnCols = ::std::max( aDocSize.mnCols, static_cast< SCCOL >( pTable->GetDocSize( tdCol ) ) );
2771 : // add up height of each entry
2772 7 : if( bProcessRowHeight )
2773 7 : aDocSize.mnRows += pTable ? pTable->GetDocSize( tdRow ) : 1;
2774 : }
2775 7 : if( !aDocSize.mnRows )
2776 0 : aDocSize.mnRows = 1;
2777 :
2778 7 : if( bProcessColWidth )
2779 7 : CalcNeededDocSize( tdCol, rCellPos.mnCol, aCellSpan.mnCols, aDocSize.mnCols );
2780 7 : if( bProcessRowHeight )
2781 7 : CalcNeededDocSize( tdRow, rCellPos.mnRow, aCellSpan.mnRows, aDocSize.mnRows );
2782 : }
2783 : }
2784 : }
2785 2 : }
2786 :
2787 2 : void ScHTMLTable::RecalcDocPos( const ScHTMLPos& rBasePos )
2788 : {
2789 2 : maDocBasePos = rBasePos;
2790 : // after the previous assignment it is allowed to call GetDocPos() methods
2791 :
2792 : // iterate through every table cell
2793 2 : ScHTMLEntryMap::iterator aMapIterEnd = maEntryMap.end();
2794 9 : for( ScHTMLEntryMap::iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
2795 : {
2796 : // fixed doc position of the entire cell (first entry)
2797 7 : const ScHTMLPos aCellDocPos( GetDocPos( aMapIter->first ) );
2798 : // fixed doc size of the entire cell
2799 7 : const ScHTMLSize aCellDocSize( GetDocSize( aMapIter->first ) );
2800 :
2801 : // running doc position for single entries
2802 7 : ScHTMLPos aEntryDocPos( aCellDocPos );
2803 :
2804 7 : ScHTMLEntryList& rEntryList = aMapIter->second;
2805 7 : ScHTMLEntry* pEntry = 0;
2806 7 : ScHTMLEntryList::iterator aListIterEnd = rEntryList.end();
2807 14 : for( ScHTMLEntryList::iterator aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
2808 : {
2809 7 : pEntry = *aListIter;
2810 7 : if( ScHTMLTable* pTable = GetExistingTable( pEntry->GetTableId() ) )
2811 : {
2812 1 : pTable->RecalcDocPos( aEntryDocPos ); // recalc nested table
2813 1 : pEntry->nCol = SCCOL_MAX;
2814 1 : pEntry->nRow = SCROW_MAX;
2815 1 : SCROW nTableRows = static_cast< SCROW >( pTable->GetDocSize( tdRow ) );
2816 :
2817 : // use this entry to pad empty space right of table
2818 1 : if( mpParentTable ) // ... but not in global table
2819 : {
2820 0 : SCCOL nStartCol = aEntryDocPos.mnCol + static_cast< SCCOL >( pTable->GetDocSize( tdCol ) );
2821 0 : SCCOL nNextCol = aEntryDocPos.mnCol + aCellDocSize.mnCols;
2822 0 : if( nStartCol < nNextCol )
2823 : {
2824 0 : pEntry->nCol = nStartCol;
2825 0 : pEntry->nRow = aEntryDocPos.mnRow;
2826 0 : pEntry->nColOverlap = nNextCol - nStartCol;
2827 0 : pEntry->nRowOverlap = nTableRows;
2828 : }
2829 : }
2830 1 : aEntryDocPos.mnRow += nTableRows;
2831 : }
2832 : else
2833 : {
2834 6 : pEntry->nCol = aEntryDocPos.mnCol;
2835 6 : pEntry->nRow = aEntryDocPos.mnRow;
2836 6 : if( mpParentTable ) // do not merge in global table
2837 6 : pEntry->nColOverlap = aCellDocSize.mnCols;
2838 6 : ++aEntryDocPos.mnRow;
2839 : }
2840 : }
2841 :
2842 : // pEntry points now to last entry.
2843 7 : if( pEntry )
2844 : {
2845 7 : if( (pEntry == rEntryList.front()) && (pEntry->GetTableId() == SC_HTML_NO_TABLE) )
2846 : {
2847 : // pEntry is the only entry in this cell - merge rows of cell with single non-table entry.
2848 6 : pEntry->nRowOverlap = aCellDocSize.mnRows;
2849 : }
2850 : else
2851 : {
2852 : // fill up incomplete entry lists
2853 1 : SCROW nFirstUnusedRow = aCellDocPos.mnRow + aCellDocSize.mnRows;
2854 2 : while( aEntryDocPos.mnRow < nFirstUnusedRow )
2855 : {
2856 0 : ScHTMLEntryPtr xDummyEntry( new ScHTMLEntry( pEntry->GetItemSet() ) );
2857 0 : xDummyEntry->nCol = aEntryDocPos.mnCol;
2858 0 : xDummyEntry->nRow = aEntryDocPos.mnRow;
2859 0 : xDummyEntry->nColOverlap = aCellDocSize.mnCols;
2860 0 : ImplPushEntryToList( rEntryList, xDummyEntry );
2861 0 : ++aEntryDocPos.mnRow;
2862 0 : }
2863 : }
2864 : }
2865 : }
2866 2 : }
2867 :
2868 1 : ScHTMLGlobalTable::ScHTMLGlobalTable(
2869 : SfxItemPool& rPool,
2870 : EditEngine& rEditEngine,
2871 : ::std::vector< ScEEParseEntry* >& rEEParseList,
2872 : ScHTMLTableId& rnUnusedId,
2873 : ScHTMLParser* pParser
2874 : ) :
2875 1 : ScHTMLTable( rPool, rEditEngine, rEEParseList, rnUnusedId, pParser )
2876 : {
2877 1 : }
2878 :
2879 2 : ScHTMLGlobalTable::~ScHTMLGlobalTable()
2880 : {
2881 2 : }
2882 :
2883 1 : void ScHTMLGlobalTable::Recalc()
2884 : {
2885 : // Fills up empty cells with a dummy entry. */
2886 1 : FillEmptyCells();
2887 : // recalc table sizes of all nested tables and this table
2888 1 : RecalcDocSize();
2889 : // recalc document positions of all entries in this table and in nested tables
2890 1 : RecalcDocPos( GetDocPos() );
2891 1 : }
2892 :
2893 1 : ScHTMLQueryParser::ScHTMLQueryParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
2894 : ScHTMLParser( pEditEngine, pDoc ),
2895 : mnUnusedId( SC_HTML_GLOBAL_TABLE ),
2896 1 : mbTitleOn( false )
2897 : {
2898 : mxGlobTable.reset(
2899 1 : new ScHTMLGlobalTable(*pPool, *pEdit, maList, mnUnusedId, this));
2900 1 : mpCurrTable = mxGlobTable.get();
2901 1 : }
2902 :
2903 2 : ScHTMLQueryParser::~ScHTMLQueryParser()
2904 : {
2905 2 : }
2906 :
2907 1 : sal_uLong ScHTMLQueryParser::Read( SvStream& rStrm, const OUString& rBaseURL )
2908 : {
2909 1 : SvKeyValueIteratorRef xValues;
2910 1 : SvKeyValueIterator* pAttributes = 0;
2911 :
2912 1 : SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
2913 1 : if( pObjSh && pObjSh->IsLoading() )
2914 : {
2915 1 : pAttributes = pObjSh->GetHeaderAttributes();
2916 : }
2917 : else
2918 : {
2919 : /* When not loading, set up fake HTTP headers to force the SfxHTMLParser
2920 : to use UTF8 (used when pasting from clipboard) */
2921 0 : const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
2922 0 : if( pCharSet )
2923 : {
2924 0 : OUString aContentType = "text/html; charset=";
2925 0 : aContentType += OUString::createFromAscii( pCharSet );
2926 :
2927 0 : xValues = new SvKeyValueIterator;
2928 0 : xValues->Append( SvKeyValue( OUString( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
2929 0 : pAttributes = xValues;
2930 : }
2931 : }
2932 :
2933 1 : Link aOldLink = pEdit->GetImportHdl();
2934 1 : pEdit->SetImportHdl( LINK( this, ScHTMLQueryParser, HTMLImportHdl ) );
2935 1 : sal_uLong nErr = pEdit->Read( rStrm, rBaseURL, EE_FORMAT_HTML, pAttributes );
2936 1 : pEdit->SetImportHdl( aOldLink );
2937 :
2938 1 : mxGlobTable->Recalc();
2939 1 : nColMax = static_cast< SCCOL >( mxGlobTable->GetDocSize( tdCol ) - 1 );
2940 1 : nRowMax = static_cast< SCROW >( mxGlobTable->GetDocSize( tdRow ) - 1 );
2941 :
2942 1 : return nErr;
2943 : }
2944 :
2945 1 : const ScHTMLTable* ScHTMLQueryParser::GetGlobalTable() const
2946 : {
2947 1 : return mxGlobTable.get();
2948 : }
2949 :
2950 34 : void ScHTMLQueryParser::ProcessToken( const ImportInfo& rInfo )
2951 : {
2952 34 : switch( rInfo.nToken )
2953 : {
2954 : // --- meta data ---
2955 0 : case HTML_META: MetaOn( rInfo ); break; // <meta>
2956 :
2957 : // --- title handling ---
2958 0 : case HTML_TITLE_ON: TitleOn( rInfo ); break; // <title>
2959 0 : case HTML_TITLE_OFF: TitleOff( rInfo ); break; // </title>
2960 :
2961 0 : case HTML_STYLE_ON: break;
2962 0 : case HTML_STYLE_OFF: ParseStyle(rInfo.aText); break;
2963 :
2964 : // --- body handling ---
2965 1 : case HTML_BODY_ON: mpCurrTable->BodyOn( rInfo ); break; // <body>
2966 1 : case HTML_BODY_OFF: mpCurrTable->BodyOff( rInfo ); break; // </body>
2967 :
2968 : // --- insert text ---
2969 13 : case HTML_TEXTTOKEN: InsertText( rInfo ); break; // any text
2970 0 : case HTML_LINEBREAK: mpCurrTable->BreakOn(); break; // <br>
2971 : case HTML_HEAD1_ON: // <h1>
2972 : case HTML_HEAD2_ON: // <h2>
2973 : case HTML_HEAD3_ON: // <h3>
2974 : case HTML_HEAD4_ON: // <h4>
2975 : case HTML_HEAD5_ON: // <h5>
2976 : case HTML_HEAD6_ON: // <h6>
2977 0 : case HTML_PARABREAK_ON: mpCurrTable->HeadingOn(); break; // <p>
2978 :
2979 : // --- misc. contents ---
2980 0 : case HTML_ANCHOR_ON: mpCurrTable->AnchorOn(); break; // <a>
2981 :
2982 : // --- table handling ---
2983 1 : case HTML_TABLE_ON: TableOn( rInfo ); break; // <table>
2984 1 : case HTML_TABLE_OFF: TableOff( rInfo ); break; // </table>
2985 2 : case HTML_TABLEROW_ON: mpCurrTable->RowOn( rInfo ); break; // <tr>
2986 2 : case HTML_TABLEROW_OFF: mpCurrTable->RowOff( rInfo ); break; // </tr>
2987 : case HTML_TABLEHEADER_ON: // <th>
2988 6 : case HTML_TABLEDATA_ON: mpCurrTable->DataOn( rInfo ); break; // <td>
2989 : case HTML_TABLEHEADER_OFF: // </th>
2990 6 : case HTML_TABLEDATA_OFF: mpCurrTable->DataOff( rInfo ); break; // </td>
2991 0 : case HTML_PREFORMTXT_ON: PreOn( rInfo ); break; // <pre>
2992 0 : case HTML_PREFORMTXT_OFF: PreOff( rInfo ); break; // </pre>
2993 :
2994 : // --- formatting ---
2995 0 : case HTML_FONT_ON: FontOn( rInfo ); break; // <font>
2996 :
2997 : case HTML_BIGPRINT_ON: // <big>
2998 : //! TODO: store current font size, use following size
2999 0 : mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 3 ], 100, ATTR_FONT_HEIGHT ) );
3000 0 : break;
3001 : case HTML_SMALLPRINT_ON: // <small>
3002 : //! TODO: store current font size, use preceding size
3003 0 : mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 0 ], 100, ATTR_FONT_HEIGHT ) );
3004 0 : break;
3005 :
3006 : case HTML_BOLD_ON: // <b>
3007 : case HTML_STRONG_ON: // <strong>
3008 0 : mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
3009 0 : break;
3010 :
3011 : case HTML_ITALIC_ON: // <i>
3012 : case HTML_EMPHASIS_ON: // <em>
3013 : case HTML_ADDRESS_ON: // <address>
3014 : case HTML_BLOCKQUOTE_ON: // <blockquote>
3015 : case HTML_BLOCKQUOTE30_ON: // <bq>
3016 : case HTML_CITIATION_ON: // <cite>
3017 : case HTML_VARIABLE_ON: // <var>
3018 0 : mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
3019 0 : break;
3020 :
3021 : case HTML_DEFINSTANCE_ON: // <dfn>
3022 0 : mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
3023 0 : mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
3024 0 : break;
3025 :
3026 : case HTML_UNDERLINE_ON: // <u>
3027 0 : mpCurrTable->PutItem( SvxUnderlineItem( UNDERLINE_SINGLE, ATTR_FONT_UNDERLINE ) );
3028 0 : break;
3029 : }
3030 34 : }
3031 :
3032 13 : void ScHTMLQueryParser::InsertText( const ImportInfo& rInfo )
3033 : {
3034 13 : mpCurrTable->PutText( rInfo );
3035 13 : if( mbTitleOn )
3036 0 : maTitle.append(rInfo.aText);
3037 13 : }
3038 :
3039 0 : void ScHTMLQueryParser::FontOn( const ImportInfo& rInfo )
3040 : {
3041 0 : const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
3042 0 : HTMLOptions::const_iterator itr = rOptions.begin(), itrEnd = rOptions.end();
3043 0 : for (; itr != itrEnd; ++itr)
3044 : {
3045 0 : switch( itr->GetToken() )
3046 : {
3047 : case HTML_O_FACE :
3048 : {
3049 0 : const OUString& rFace = itr->GetString();
3050 0 : OUString aFontName;
3051 0 : sal_Int32 nPos = 0;
3052 0 : while( nPos != -1 )
3053 : {
3054 : // font list separator: VCL = ';' HTML = ','
3055 0 : OUString aFName = comphelper::string::strip(rFace.getToken(0, ',', nPos), ' ');
3056 0 : aFontName = ScGlobal::addToken(aFontName, aFName, ';');
3057 0 : }
3058 0 : if ( !aFontName.isEmpty() )
3059 : mpCurrTable->PutItem( SvxFontItem( FAMILY_DONTKNOW,
3060 0 : aFontName, EMPTY_OUSTRING, PITCH_DONTKNOW,
3061 0 : RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
3062 : }
3063 0 : break;
3064 : case HTML_O_SIZE :
3065 : {
3066 0 : sal_uInt32 nSize = getLimitedValue< sal_uInt32 >( itr->GetNumber(), 1, SC_HTML_FONTSIZES );
3067 0 : mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ nSize - 1 ], 100, ATTR_FONT_HEIGHT ) );
3068 : }
3069 0 : break;
3070 : case HTML_O_COLOR :
3071 : {
3072 0 : Color aColor;
3073 0 : itr->GetColor( aColor );
3074 0 : mpCurrTable->PutItem( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
3075 : }
3076 0 : break;
3077 : }
3078 : }
3079 0 : }
3080 :
3081 0 : void ScHTMLQueryParser::MetaOn( const ImportInfo& rInfo )
3082 : {
3083 0 : if( mpDoc->GetDocumentShell() )
3084 : {
3085 0 : HTMLParser* pParser = static_cast< HTMLParser* >( rInfo.pParser );
3086 :
3087 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
3088 0 : mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
3089 : pParser->ParseMetaOptions(
3090 0 : xDPS->getDocumentProperties(),
3091 0 : mpDoc->GetDocumentShell()->GetHeaderAttributes() );
3092 : }
3093 0 : }
3094 :
3095 0 : void ScHTMLQueryParser::TitleOn( const ImportInfo& /*rInfo*/ )
3096 : {
3097 0 : mbTitleOn = true;
3098 0 : maTitle.makeStringAndClear();
3099 0 : }
3100 :
3101 0 : void ScHTMLQueryParser::TitleOff( const ImportInfo& rInfo )
3102 : {
3103 0 : if( mbTitleOn )
3104 : {
3105 0 : OUString aTitle = maTitle.makeStringAndClear().trim();
3106 0 : if (!aTitle.isEmpty() && mpDoc->GetDocumentShell())
3107 : {
3108 : uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
3109 0 : mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
3110 :
3111 0 : xDPS->getDocumentProperties()->setTitle(aTitle);
3112 : }
3113 0 : InsertText( rInfo );
3114 0 : mbTitleOn = false;
3115 : }
3116 0 : }
3117 :
3118 1 : void ScHTMLQueryParser::TableOn( const ImportInfo& rInfo )
3119 : {
3120 1 : mpCurrTable = mpCurrTable->TableOn( rInfo );
3121 1 : }
3122 :
3123 1 : void ScHTMLQueryParser::TableOff( const ImportInfo& rInfo )
3124 : {
3125 1 : mpCurrTable = mpCurrTable->TableOff( rInfo );
3126 1 : }
3127 :
3128 0 : void ScHTMLQueryParser::PreOn( const ImportInfo& rInfo )
3129 : {
3130 0 : mpCurrTable = mpCurrTable->PreOn( rInfo );
3131 0 : }
3132 :
3133 0 : void ScHTMLQueryParser::PreOff( const ImportInfo& rInfo )
3134 : {
3135 0 : mpCurrTable = mpCurrTable->PreOff( rInfo );
3136 0 : }
3137 :
3138 0 : void ScHTMLQueryParser::CloseTable( const ImportInfo& rInfo )
3139 : {
3140 0 : mpCurrTable = mpCurrTable->CloseTable( rInfo );
3141 0 : }
3142 :
3143 : #if ENABLE_ORCUS
3144 :
3145 : namespace {
3146 :
3147 : /**
3148 : * Handler class for the CSS parser.
3149 : */
3150 0 : class CSSHandler
3151 : {
3152 : struct MemStr
3153 : {
3154 : const char* mp;
3155 : size_t mn;
3156 :
3157 0 : MemStr() : mp(NULL), mn(0) {}
3158 0 : MemStr(const char* p, size_t n) : mp(p), mn(n) {}
3159 0 : MemStr(const MemStr& r) : mp(r.mp), mn(r.mn) {}
3160 0 : MemStr& operator=(const MemStr& r)
3161 : {
3162 0 : mp = r.mp;
3163 0 : mn = r.mn;
3164 0 : return *this;
3165 : }
3166 : };
3167 :
3168 : typedef std::pair<MemStr, MemStr> SelectorName; // element : class
3169 : typedef std::vector<SelectorName> SelectorNames;
3170 : SelectorNames maSelectorNames; /// current selector names.
3171 : MemStr maPropName; /// current property name.
3172 : MemStr maPropValue; /// current property value.
3173 :
3174 : ScHTMLStyles& mrStyles;
3175 : public:
3176 0 : CSSHandler(ScHTMLStyles& rStyles) : mrStyles(rStyles) {}
3177 :
3178 0 : void at_rule_name(const char* /*p*/, size_t /*n*/)
3179 : {
3180 : // TODO: For now, we ignore at-rule properties.
3181 0 : }
3182 :
3183 0 : void selector_name(const char* p_elem, size_t n_elem, const char* p_class, size_t n_class)
3184 : {
3185 0 : MemStr aElem(p_elem, n_elem), aClass(p_class, n_class);
3186 0 : SelectorName aName(aElem, aClass);
3187 0 : maSelectorNames.push_back(aName);
3188 0 : }
3189 :
3190 0 : void property_name(const char* p, size_t n)
3191 : {
3192 0 : maPropName = MemStr(p, n);
3193 0 : }
3194 :
3195 0 : void value(const char* p, size_t n)
3196 : {
3197 0 : maPropValue = MemStr(p, n);
3198 0 : }
3199 :
3200 0 : void begin_parse() {}
3201 :
3202 0 : void end_parse() {}
3203 :
3204 0 : void begin_block() {}
3205 :
3206 0 : void end_block()
3207 : {
3208 0 : maSelectorNames.clear();
3209 0 : }
3210 :
3211 0 : void begin_property() {}
3212 :
3213 0 : void end_property()
3214 : {
3215 0 : SelectorNames::const_iterator itr = maSelectorNames.begin(), itrEnd = maSelectorNames.end();
3216 0 : for (; itr != itrEnd; ++itr)
3217 : {
3218 : // Add this property to the collection for each selector.
3219 0 : const SelectorName& rSelName = *itr;
3220 0 : const MemStr& rElem = rSelName.first;
3221 0 : const MemStr& rClass = rSelName.second;
3222 0 : OUString aName(maPropName.mp, maPropName.mn, RTL_TEXTENCODING_UTF8);
3223 0 : OUString aValue(maPropValue.mp, maPropValue.mn, RTL_TEXTENCODING_UTF8);
3224 0 : mrStyles.add(rElem.mp, rElem.mn, rClass.mp, rClass.mn, aName, aValue);
3225 0 : }
3226 0 : maPropName = MemStr();
3227 0 : maPropValue = MemStr();
3228 0 : }
3229 : };
3230 :
3231 : }
3232 :
3233 0 : void ScHTMLQueryParser::ParseStyle(const OUString& rStrm)
3234 : {
3235 0 : OString aStr = OUStringToOString(rStrm, RTL_TEXTENCODING_UTF8);
3236 0 : CSSHandler aHdl(GetStyles());
3237 0 : orcus::css_parser<CSSHandler> aParser(aStr.getStr(), aStr.getLength(), aHdl);
3238 : try
3239 : {
3240 0 : aParser.parse();
3241 : }
3242 0 : catch (const orcus::css_parse_error&)
3243 : {
3244 : // TODO: Parsing of CSS failed. Do nothing for now.
3245 0 : }
3246 0 : }
3247 :
3248 : #else
3249 :
3250 : void ScHTMLQueryParser::ParseStyle(const OUString&) {}
3251 :
3252 : #endif
3253 :
3254 110 : IMPL_LINK( ScHTMLQueryParser, HTMLImportHdl, const ImportInfo*, pInfo )
3255 : {
3256 55 : switch( pInfo->eState )
3257 : {
3258 : case HTMLIMP_START:
3259 1 : break;
3260 :
3261 : case HTMLIMP_NEXTTOKEN:
3262 : case HTMLIMP_UNKNOWNATTR:
3263 34 : ProcessToken( *pInfo );
3264 34 : break;
3265 :
3266 : case HTMLIMP_INSERTPARA:
3267 6 : mpCurrTable->InsertPara( *pInfo );
3268 6 : break;
3269 :
3270 : case HTMLIMP_SETATTR:
3271 : case HTMLIMP_INSERTTEXT:
3272 : case HTMLIMP_INSERTFIELD:
3273 13 : break;
3274 :
3275 : case HTMLIMP_END:
3276 2 : while( mpCurrTable->GetTableId() != SC_HTML_GLOBAL_TABLE )
3277 0 : CloseTable( *pInfo );
3278 1 : break;
3279 :
3280 : default:
3281 : OSL_FAIL( "ScHTMLQueryParser::HTMLImportHdl - unknown ImportInfo::eState" );
3282 : }
3283 55 : return 0;
3284 : }
3285 :
3286 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|