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