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