summaryrefslogtreecommitdiff
path: root/sc/source/filter/html/htmlpars.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/html/htmlpars.cxx')
-rw-r--r--sc/source/filter/html/htmlpars.cxx3069
1 files changed, 3069 insertions, 0 deletions
diff --git a/sc/source/filter/html/htmlpars.cxx b/sc/source/filter/html/htmlpars.cxx
new file mode 100644
index 000000000000..85e77fc3124b
--- /dev/null
+++ b/sc/source/filter/html/htmlpars.cxx
@@ -0,0 +1,3069 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+#define SC_HTMLPARS_CXX
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+
+#include <svtools/htmlcfg.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brshitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/eitem.hxx>
+#include <svtools/filter.hxx>
+#include <svtools/parhtml.hxx>
+#include <svtools/htmlkywd.hxx>
+#include <svtools/htmltokn.h>
+#include <sfx2/docfile.hxx>
+
+#include <vcl/svapp.hxx>
+#include <tools/urlobj.hxx>
+#include <tools/tenccvt.hxx>
+
+#include "htmlpars.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "rangelst.hxx"
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
+
+using namespace ::com::sun::star;
+
+
+SV_IMPL_VARARR_SORT( ScHTMLColOffset, ULONG );
+
+
+// ============================================================================
+// BASE class for HTML parser classes
+// ============================================================================
+
+ScHTMLParser::ScHTMLParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
+ ScEEParser( pEditEngine ),
+ mpDoc( pDoc )
+{
+ SvxHtmlOptions* pHtmlOptions = SvxHtmlOptions::Get();
+ for( sal_uInt16 nIndex = 0; nIndex < SC_HTML_FONTSIZES; ++nIndex )
+ maFontHeights[ nIndex ] = pHtmlOptions->GetFontSize( nIndex ) * 20;
+}
+
+ScHTMLParser::~ScHTMLParser()
+{
+}
+
+
+// ============================================================================
+
+ScHTMLLayoutParser::ScHTMLLayoutParser( EditEngine* pEditP, const String& rBaseURL, const Size& aPageSizeP, ScDocument* pDocP ) :
+ ScHTMLParser( pEditP, pDocP ),
+ aPageSize( aPageSizeP ),
+ aBaseURL( rBaseURL ),
+ xLockedList( new ScRangeList ),
+ pTables( NULL ),
+ pColOffset( new ScHTMLColOffset ),
+ pLocalColOffset( new ScHTMLColOffset ),
+ nFirstTableCell(0),
+ nTableLevel(0),
+ nTable(0),
+ nMaxTable(0),
+ nColCntStart(0),
+ nMaxCol(0),
+ nTableWidth(0),
+ nColOffset(0),
+ nColOffsetStart(0),
+ nMetaCnt(0),
+ nOffsetTolerance( SC_HTML_OFFSET_TOLERANCE_SMALL ),
+ bTabInTabCell( FALSE ),
+ bFirstRow( TRUE ),
+ bInCell( FALSE ),
+ bInTitle( FALSE )
+{
+ MakeColNoRef( pLocalColOffset, 0, 0, 0, 0 );
+ MakeColNoRef( pColOffset, 0, 0, 0, 0 );
+}
+
+
+ScHTMLLayoutParser::~ScHTMLLayoutParser()
+{
+ ScHTMLTableStackEntry* pS;
+ while ( (pS = aTableStack.Pop()) != 0 )
+ {
+ if ( pList->GetPos( pS->pCellEntry ) == LIST_ENTRY_NOTFOUND )
+ delete pS->pCellEntry;
+ if ( pS->pLocalColOffset != pLocalColOffset )
+ delete pS->pLocalColOffset;
+ delete pS;
+ }
+ if ( pLocalColOffset )
+ delete pLocalColOffset;
+ if ( pColOffset )
+ delete pColOffset;
+ if ( pTables )
+ {
+ for ( Table* pT = (Table*) pTables->First(); pT; pT = (Table*) pTables->Next() )
+ delete pT;
+ delete pTables;
+ }
+}
+
+
+ULONG ScHTMLLayoutParser::Read( SvStream& rStream, const String& rBaseURL )
+{
+ Link aOldLink = pEdit->GetImportHdl();
+ pEdit->SetImportHdl( LINK( this, ScHTMLLayoutParser, HTMLImportHdl ) );
+
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ BOOL bLoading = pObjSh && pObjSh->IsLoading();
+
+ SvKeyValueIteratorRef xValues;
+ SvKeyValueIterator* pAttributes = NULL;
+ if ( bLoading )
+ pAttributes = pObjSh->GetHeaderAttributes();
+ else
+ {
+ // When not loading, set up fake http headers to force the SfxHTMLParser to use UTF8
+ // (used when pasting from clipboard)
+
+ const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
+ if( pCharSet )
+ {
+ String aContentType = String::CreateFromAscii( "text/html; charset=" );
+ aContentType.AppendAscii( pCharSet );
+
+ xValues = new SvKeyValueIterator;
+ xValues->Append( SvKeyValue( String::CreateFromAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
+ pAttributes = xValues;
+ }
+ }
+
+ ULONG nErr = pEdit->Read( rStream, rBaseURL, EE_FORMAT_HTML, pAttributes );
+
+ pEdit->SetImportHdl( aOldLink );
+ // Spaltenbreiten erzeugen
+ Adjust();
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ USHORT nCount = pColOffset->Count();
+ const ULONG* pOff = (const ULONG*) pColOffset->GetData();
+ ULONG nOff = *pOff++;
+ Size aSize;
+ for ( USHORT j = 1; j < nCount; j++, pOff++ )
+ {
+ aSize.Width() = *pOff - nOff;
+ aSize = pDefaultDev->PixelToLogic( aSize, MapMode( MAP_TWIP ) );
+ pColWidths->Insert( j-1, (void*)aSize.Width() );
+ nOff = *pOff;
+ }
+ return nErr;
+}
+
+
+const ScHTMLTable* ScHTMLLayoutParser::GetGlobalTable() const
+{
+ return 0;
+}
+
+
+void ScHTMLLayoutParser::NewActEntry( ScEEParseEntry* pE )
+{
+ ScEEParser::NewActEntry( pE );
+ if ( pE )
+ {
+ if ( !pE->aSel.HasRange() )
+ { // komplett leer, nachfolgender Text landet im gleichen Absatz!
+ pActEntry->aSel.nStartPara = pE->aSel.nEndPara;
+ pActEntry->aSel.nStartPos = pE->aSel.nEndPos;
+ }
+ }
+ pActEntry->aSel.nEndPara = pActEntry->aSel.nStartPara;
+ pActEntry->aSel.nEndPos = pActEntry->aSel.nStartPos;
+}
+
+
+void ScHTMLLayoutParser::EntryEnd( ScEEParseEntry* pE, const ESelection& rSel )
+{
+ if ( rSel.nEndPara >= pE->aSel.nStartPara )
+ {
+ pE->aSel.nEndPara = rSel.nEndPara;
+ pE->aSel.nEndPos = rSel.nEndPos;
+ }
+ else if ( rSel.nStartPara == pE->aSel.nStartPara - 1 && !pE->aSel.HasRange() )
+ { // kein Absatz angehaengt aber leer, nichts tun
+ }
+ else
+ {
+ DBG_ERRORFILE( "EntryEnd: EditEngine ESelection End < Start" );
+ }
+}
+
+
+void ScHTMLLayoutParser::NextRow( ImportInfo* pInfo )
+{
+ if ( bInCell )
+ CloseEntry( pInfo );
+ if ( nRowMax < ++nRowCnt )
+ nRowMax = nRowCnt;
+ nColCnt = nColCntStart;
+ nColOffset = nColOffsetStart;
+ bFirstRow = FALSE;
+}
+
+
+BOOL ScHTMLLayoutParser::SeekOffset( ScHTMLColOffset* pOffset, USHORT nOffset,
+ SCCOL* pCol, USHORT nOffsetTol )
+{
+ DBG_ASSERT( pOffset, "ScHTMLLayoutParser::SeekOffset - illegal call" );
+ USHORT nPos;
+ BOOL bFound = pOffset->Seek_Entry( nOffset, &nPos );
+ *pCol = static_cast<SCCOL>(nPos);
+ if ( bFound )
+ return TRUE;
+ USHORT nCount = pOffset->Count();
+ if ( !nCount )
+ return FALSE;
+ // nPos ist Einfuegeposition, da liegt der Naechsthoehere (oder auch nicht)
+ if ( nPos < nCount && (((*pOffset)[nPos] - nOffsetTol) <= nOffset) )
+ return TRUE;
+ // nicht kleiner als alles andere? dann mit Naechstniedrigerem vergleichen
+ else if ( nPos && (((*pOffset)[nPos-1] + nOffsetTol) >= nOffset) )
+ {
+ (*pCol)--;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+void ScHTMLLayoutParser::MakeCol( ScHTMLColOffset* pOffset, USHORT& nOffset,
+ USHORT& nWidth, USHORT nOffsetTol, USHORT nWidthTol )
+{
+ DBG_ASSERT( pOffset, "ScHTMLLayoutParser::MakeCol - illegal call" );
+ SCCOL nPos;
+ if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
+ nOffset = (USHORT)(*pOffset)[nPos];
+ else
+ pOffset->Insert( nOffset );
+ if ( nWidth )
+ {
+ if ( SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
+ nWidth = (USHORT)(*pOffset)[nPos] - nOffset;
+ else
+ pOffset->Insert( nOffset + nWidth );
+ }
+}
+
+
+void ScHTMLLayoutParser::MakeColNoRef( ScHTMLColOffset* pOffset, USHORT nOffset,
+ USHORT nWidth, USHORT nOffsetTol, USHORT nWidthTol )
+{
+ DBG_ASSERT( pOffset, "ScHTMLLayoutParser::MakeColNoRef - illegal call" );
+ SCCOL nPos;
+ if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
+ nOffset = (USHORT)(*pOffset)[nPos];
+ else
+ pOffset->Insert( nOffset );
+ if ( nWidth )
+ {
+ if ( !SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
+ pOffset->Insert( nOffset + nWidth );
+ }
+}
+
+
+void ScHTMLLayoutParser::ModifyOffset( ScHTMLColOffset* pOffset, USHORT& nOldOffset,
+ USHORT& nNewOffset, USHORT nOffsetTol )
+{
+ DBG_ASSERT( pOffset, "ScHTMLLayoutParser::ModifyOffset - illegal call" );
+ SCCOL nPos;
+ if ( !SeekOffset( pOffset, nOldOffset, &nPos, nOffsetTol ) )
+ {
+ if ( SeekOffset( pOffset, nNewOffset, &nPos, nOffsetTol ) )
+ nNewOffset = (USHORT)(*pOffset)[nPos];
+ else
+ pOffset->Insert( nNewOffset );
+ return ;
+ }
+ nOldOffset = (USHORT)(*pOffset)[nPos];
+ SCCOL nPos2;
+ if ( SeekOffset( pOffset, nNewOffset, &nPos2, nOffsetTol ) )
+ {
+ nNewOffset = (USHORT)(*pOffset)[nPos2];
+ return ;
+ }
+ ULONG* pData = ((ULONG*) pOffset->GetData()) + nPos; //! QAD
+ long nDiff = nNewOffset - nOldOffset;
+ if ( nDiff < 0 )
+ {
+ const ULONG* pStop = pOffset->GetData();
+ do
+ {
+ *pData += nDiff;
+ } while ( pStop < pData-- );
+ }
+ else
+ {
+ const ULONG* pStop = pOffset->GetData() + pOffset->Count();
+ do
+ {
+ *pData += nDiff;
+ } while ( ++pData < pStop );
+ }
+}
+
+
+void ScHTMLLayoutParser::SkipLocked( ScEEParseEntry* pE, BOOL bJoin )
+{
+ if ( ValidCol(pE->nCol) )
+ { // wuerde sonst bei ScAddress falschen Wert erzeugen, evtl. Endlosschleife!
+ BOOL bBadCol = FALSE;
+ BOOL bAgain;
+ ScRange aRange( pE->nCol, pE->nRow, 0,
+ pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 );
+ do
+ {
+ bAgain = FALSE;
+ for ( ScRange* pR = xLockedList->First(); pR; pR = xLockedList->Next() )
+ {
+ if ( pR->Intersects( aRange ) )
+ {
+ pE->nCol = pR->aEnd.Col() + 1;
+ SCCOL nTmp = pE->nCol + pE->nColOverlap - 1;
+ if ( pE->nCol > MAXCOL || nTmp > MAXCOL )
+ bBadCol = TRUE;
+ else
+ {
+ bAgain = TRUE;
+ aRange.aStart.SetCol( pE->nCol );
+ aRange.aEnd.SetCol( nTmp );
+ }
+ break;
+ }
+ }
+ } while ( bAgain );
+ if ( bJoin && !bBadCol )
+ xLockedList->Join( aRange );
+ }
+}
+
+
+void ScHTMLLayoutParser::Adjust()
+{
+ for ( ScRange* pR = xLockedList->First(); pR; pR = xLockedList->Next() )
+ delete pR;
+ xLockedList->Clear();
+ ScHTMLAdjustStack aStack;
+ ScHTMLAdjustStackEntry* pS;
+ USHORT nTab = 0;
+ SCCOL nLastCol = SCCOL_MAX;
+ SCROW nNextRow = 0;
+ SCROW nCurRow = 0;
+ USHORT nPageWidth = (USHORT) aPageSize.Width();
+ Table* pTab = NULL;
+ for ( ScEEParseEntry* pE = pList->First(); pE; pE = pList->Next() )
+ {
+ if ( pE->nTab < nTab )
+ { // Table beendet
+ if ( (pS = aStack.Pop()) != 0 )
+ {
+ nLastCol = pS->nLastCol;
+ nNextRow = pS->nNextRow;
+ nCurRow = pS->nCurRow;
+ }
+ delete pS;
+ nTab = pE->nTab;
+ pTab = (pTables ? (Table*) pTables->Get( nTab ) : NULL);
+
+ }
+ SCROW nRow = pE->nRow;
+ if ( pE->nCol <= nLastCol )
+ { // naechste Zeile
+ if ( pE->nRow < nNextRow )
+ pE->nRow = nCurRow = nNextRow;
+ else
+ nCurRow = nNextRow = pE->nRow;
+ SCROW nR;
+ if ( pTab && ((nR = (SCROW)(ULONG)pTab->Get( nCurRow )) != 0) )
+ nNextRow += nR;
+ else
+ nNextRow++;
+ }
+ else
+ pE->nRow = nCurRow;
+ nLastCol = pE->nCol; // eingelesene Col
+ if ( pE->nTab > nTab )
+ { // neue Table
+ aStack.Push( new ScHTMLAdjustStackEntry(
+ nLastCol, nNextRow, nCurRow ) );
+ nTab = pE->nTab;
+ pTab = (pTables ? (Table*) pTables->Get( nTab ) : NULL);
+ // neuer Zeilenabstand
+ SCROW nR;
+ if ( pTab && ((nR = (SCROW)(ULONG)pTab->Get( nCurRow )) != 0) )
+ nNextRow = nCurRow + nR;
+ else
+ nNextRow = nCurRow + 1;
+ }
+ if ( nTab == 0 )
+ pE->nWidth = nPageWidth;
+ else
+ { // echte Table, keine Absaetze auf der Wiese
+ if ( pTab )
+ {
+ SCROW nRowSpan = pE->nRowOverlap;
+ for ( SCROW j=0; j < nRowSpan; j++ )
+ { // aus merged Zeilen resultierendes RowSpan
+ SCROW nRows = (SCROW)(ULONG)pTab->Get( nRow+j );
+ if ( nRows > 1 )
+ {
+ pE->nRowOverlap += nRows - 1;
+ if ( j == 0 )
+ { // merged Zeilen verschieben die naechste Zeile
+ SCROW nTmp = nCurRow + nRows;
+ if ( nNextRow < nTmp )
+ nNextRow = nTmp;
+ }
+ }
+ }
+ }
+ }
+ // echte Col
+ SeekOffset( pColOffset, pE->nOffset, &pE->nCol, nOffsetTolerance );
+ SCCOL nColBeforeSkip = pE->nCol;
+ SkipLocked( pE, FALSE );
+ if ( pE->nCol != nColBeforeSkip )
+ {
+ SCCOL nCount = (SCCOL)pColOffset->Count();
+ if ( nCount <= pE->nCol )
+ {
+ pE->nOffset = (USHORT) (*pColOffset)[nCount-1];
+ MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
+ }
+ else
+ {
+ pE->nOffset = (USHORT) (*pColOffset)[pE->nCol];
+ }
+ }
+ SCCOL nPos;
+ if ( pE->nWidth && SeekOffset( pColOffset, pE->nOffset + pE->nWidth, &nPos, nOffsetTolerance ) )
+ pE->nColOverlap = (nPos > pE->nCol ? nPos - pE->nCol : 1);
+ else
+ {
+//2do: das muss nicht korrekt sein, ist aber..
+ pE->nColOverlap = 1;
+ }
+ xLockedList->Join( ScRange( pE->nCol, pE->nRow, 0,
+ pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 ) );
+ // MaxDimensions mitfuehren
+ SCCOL nColTmp = pE->nCol + pE->nColOverlap;
+ if ( nColMax < nColTmp )
+ nColMax = nColTmp;
+ SCROW nRowTmp = pE->nRow + pE->nRowOverlap;
+ if ( nRowMax < nRowTmp )
+ nRowMax = nRowTmp;
+ }
+ while ( (pS = aStack.Pop()) != 0 )
+ delete pS;
+}
+
+
+USHORT ScHTMLLayoutParser::GetWidth( ScEEParseEntry* pE )
+{
+ if ( pE->nWidth )
+ return pE->nWidth;
+ sal_Int32 nTmp = ::std::min( static_cast<sal_Int32>( pE->nCol -
+ nColCntStart + pE->nColOverlap),
+ static_cast<sal_Int32>( pLocalColOffset->Count() - 1));
+ SCCOL nPos = (nTmp < 0 ? 0 : static_cast<SCCOL>(nTmp));
+ USHORT nOff2 = (USHORT) (*pLocalColOffset)[nPos];
+ if ( pE->nOffset < nOff2 )
+ return nOff2 - pE->nOffset;
+ return 0;
+}
+
+
+void ScHTMLLayoutParser::SetWidths()
+{
+ ScEEParseEntry* pE;
+ SCCOL nCol;
+ if ( !nTableWidth )
+ nTableWidth = (USHORT) aPageSize.Width();
+ SCCOL nColsPerRow = nMaxCol - nColCntStart;
+ if ( nColsPerRow <= 0 )
+ nColsPerRow = 1;
+ if ( pLocalColOffset->Count() <= 2 )
+ { // nur PageSize, es gab keine Width-Angabe
+ USHORT nWidth = nTableWidth / static_cast<USHORT>(nColsPerRow);
+ USHORT nOff = nColOffsetStart;
+ pLocalColOffset->Remove( (USHORT)0, pLocalColOffset->Count() );
+ for ( nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth )
+ {
+ MakeColNoRef( pLocalColOffset, nOff, 0, 0, 0 );
+ }
+ nTableWidth = (USHORT)((*pLocalColOffset)[pLocalColOffset->Count() -1 ] - (*pLocalColOffset)[0]);
+ pE = pList->Seek( nFirstTableCell );
+ while ( pE )
+ {
+ if ( pE->nTab == nTable )
+ {
+ pE->nOffset = (USHORT) (*pLocalColOffset)[pE->nCol - nColCntStart];
+ pE->nWidth = 0; // to be recalculated later
+ }
+ pE = pList->Next();
+ }
+ }
+ else
+ { // einige mit einige ohne Width
+ pE = pList->Seek( nFirstTableCell );
+ // #36350# wieso eigentlich kein pE ?!?
+ if ( pE )
+ {
+ USHORT* pOffsets = new USHORT[ nColsPerRow+1 ];
+ memset( pOffsets, 0, (nColsPerRow+1) * sizeof(USHORT) );
+ USHORT* pWidths = new USHORT[ nColsPerRow ];
+ memset( pWidths, 0, nColsPerRow * sizeof(USHORT) );
+ pOffsets[0] = nColOffsetStart;
+ while ( pE )
+ {
+ if ( pE->nTab == nTable && pE->nWidth )
+ {
+ nCol = pE->nCol - nColCntStart;
+ if ( nCol < nColsPerRow )
+ {
+ if ( pE->nColOverlap == 1 )
+ {
+ if ( pWidths[nCol] < pE->nWidth )
+ pWidths[nCol] = pE->nWidth;
+ }
+ else
+ { // try to find a single undefined width
+ USHORT nTotal = 0;
+ BOOL bFound = FALSE;
+ SCCOL nHere = 0;
+ SCCOL nStop = Min( static_cast<SCCOL>(nCol + pE->nColOverlap), nColsPerRow );
+ for ( ; nCol < nStop; nCol++ )
+ {
+ if ( pWidths[nCol] )
+ nTotal = nTotal + pWidths[nCol];
+ else
+ {
+ if ( bFound )
+ {
+ bFound = FALSE;
+ break; // for
+ }
+ bFound = TRUE;
+ nHere = nCol;
+ }
+ }
+ if ( bFound && pE->nWidth > nTotal )
+ pWidths[nHere] = pE->nWidth - nTotal;
+ }
+ }
+ }
+ pE = pList->Next();
+ }
+ USHORT nWidths = 0;
+ USHORT nUnknown = 0;
+ for ( nCol = 0; nCol < nColsPerRow; nCol++ )
+ {
+ if ( pWidths[nCol] )
+ nWidths = nWidths + pWidths[nCol];
+ else
+ nUnknown++;
+ }
+ if ( nUnknown )
+ {
+ USHORT nW = ((nWidths < nTableWidth) ?
+ ((nTableWidth - nWidths) / nUnknown) :
+ (nTableWidth / nUnknown));
+ for ( nCol = 0; nCol < nColsPerRow; nCol++ )
+ {
+ if ( !pWidths[nCol] )
+ pWidths[nCol] = nW;
+ }
+ }
+ for ( nCol = 1; nCol <= nColsPerRow; nCol++ )
+ {
+ pOffsets[nCol] = pOffsets[nCol-1] + pWidths[nCol-1];
+ }
+ pLocalColOffset->Remove( (USHORT)0, pLocalColOffset->Count() );
+ for ( nCol = 0; nCol <= nColsPerRow; nCol++ )
+ {
+ MakeColNoRef( pLocalColOffset, pOffsets[nCol], 0, 0, 0 );
+ }
+ nTableWidth = pOffsets[nColsPerRow] - pOffsets[0];
+
+ pE = pList->Seek( nFirstTableCell );
+ while ( pE )
+ {
+ if ( pE->nTab == nTable )
+ {
+ nCol = pE->nCol - nColCntStart;
+ DBG_ASSERT( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
+ if ( nCol < nColsPerRow )
+ {
+ pE->nOffset = pOffsets[nCol];
+ nCol = nCol + pE->nColOverlap;
+ if ( nCol > nColsPerRow )
+ nCol = nColsPerRow;
+ pE->nWidth = pOffsets[nCol] - pE->nOffset;
+ }
+ }
+ pE = pList->Next();
+ }
+
+ delete [] pWidths;
+ delete [] pOffsets;
+ }
+ }
+ if ( pLocalColOffset->Count() )
+ {
+ USHORT nMax = (USHORT) (*pLocalColOffset)[pLocalColOffset->Count() - 1];
+ if ( aPageSize.Width() < nMax )
+ aPageSize.Width() = nMax;
+ }
+ pE = pList->Seek( nFirstTableCell );
+ while ( pE )
+ {
+ if ( pE->nTab == nTable )
+ {
+ if ( !pE->nWidth )
+ {
+ pE->nWidth = GetWidth( pE );
+ DBG_ASSERT( pE->nWidth, "SetWidths: pE->nWidth == 0" );
+ }
+ MakeCol( pColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
+ }
+ pE = pList->Next();
+ }
+}
+
+
+void ScHTMLLayoutParser::Colonize( ScEEParseEntry* pE )
+{
+ if ( pE->nCol == SCCOL_MAX )
+ pE->nCol = nColCnt;
+ if ( pE->nRow == SCROW_MAX )
+ pE->nRow = nRowCnt;
+ SCCOL nCol = pE->nCol;
+ SkipLocked( pE ); // Spaltenverdraengung nach rechts
+
+ if ( nCol < pE->nCol )
+ { // verdraengt
+ nCol = pE->nCol - nColCntStart;
+ SCCOL nCount = static_cast<SCCOL>(pLocalColOffset->Count());
+ if ( nCol < nCount )
+ nColOffset = (USHORT) (*pLocalColOffset)[nCol];
+ else
+ nColOffset = (USHORT) (*pLocalColOffset)[nCount - 1];
+ }
+ pE->nOffset = nColOffset;
+ USHORT nWidth = GetWidth( pE );
+ MakeCol( pLocalColOffset, pE->nOffset, nWidth, nOffsetTolerance, nOffsetTolerance );
+ if ( pE->nWidth )
+ pE->nWidth = nWidth;
+ nColOffset = pE->nOffset + nWidth;
+ if ( nTableWidth < nColOffset - nColOffsetStart )
+ nTableWidth = nColOffset - nColOffsetStart;
+}
+
+
+void ScHTMLLayoutParser::CloseEntry( ImportInfo* pInfo )
+{
+ bInCell = FALSE;
+ if ( bTabInTabCell )
+ { // in TableOff vom Stack geholt
+ bTabInTabCell = FALSE;
+ if ( pList->GetPos( pActEntry ) == LIST_ENTRY_NOTFOUND )
+ delete pActEntry;
+ NewActEntry( pList->Last() ); // neuer freifliegender pActEntry
+ return ;
+ }
+ if ( pActEntry->nTab == 0 )
+ pActEntry->nWidth = (USHORT) aPageSize.Width();
+ Colonize( pActEntry );
+ nColCnt = pActEntry->nCol + pActEntry->nColOverlap;
+ if ( nMaxCol < nColCnt )
+ nMaxCol = nColCnt; // TableStack MaxCol
+ if ( nColMax < nColCnt )
+ nColMax = nColCnt; // globales MaxCol fuer ScEEParser GetDimensions!
+ EntryEnd( pActEntry, pInfo->aSelection );
+ ESelection& rSel = pActEntry->aSel;
+ while ( rSel.nStartPara < rSel.nEndPara
+ && pEdit->GetTextLen( rSel.nStartPara ) == 0 )
+ { // vorgehaengte Leerabsaetze strippen
+ rSel.nStartPara++;
+ }
+ while ( rSel.nEndPos == 0 && rSel.nEndPara > rSel.nStartPara )
+ { // angehaengte Leerabsaetze strippen
+ rSel.nEndPara--;
+ rSel.nEndPos = pEdit->GetTextLen( rSel.nEndPara );
+ }
+ if ( rSel.nStartPara > rSel.nEndPara )
+ { // gibt GPF in CreateTextObject
+ DBG_ERRORFILE( "CloseEntry: EditEngine ESelection Start > End" );
+ rSel.nEndPara = rSel.nStartPara;
+ }
+ if ( rSel.HasRange() )
+ pActEntry->aItemSet.Put( SfxBoolItem( ATTR_LINEBREAK, TRUE ) );
+ pList->Insert( pActEntry, LIST_APPEND );
+ NewActEntry( pActEntry ); // neuer freifliegender pActEntry
+}
+
+
+IMPL_LINK( ScHTMLLayoutParser, HTMLImportHdl, ImportInfo*, pInfo )
+{
+#if defined(erDEBUG) //|| 1
+ static ESelection aDebugSel;
+ static String aDebugStr;
+ static SvFileStream* pDebugStrm = NULL;
+ static ULONG nDebugStrmPos = 0;
+ static ULONG nDebugCount = 0;
+ static ULONG nDebugCountAll = 0;
+ static const sal_Char* sDebugState[15] = {
+ "RTFIMP_START", "RTFIMP_END",
+ "RTFIMP_NEXTTOKEN", "RTFIMP_UNKNOWNATTR",
+ "RTFIMP_SETATTR",
+ "RTFIMP_INSERTTEXT",
+ "RTFIMP_INSERTPARA",
+ "HTMLIMP_START", "HTMLIMP_END",
+ "HTMLIMP_NEXTTOKEN", "HTMLIMP_UNKNOWNATTR",
+ "HTMLIMP_SETATTR",
+ "HTMLIMP_INSERTTEXT",
+ "HTMLIMP_INSERTPARA", "HTMLIMP_INSERTFIELD"
+ };
+
+ nDebugCountAll++;
+ if ( pInfo->eState != HTMLIMP_NEXTTOKEN // not too much
+ || pInfo->nToken == HTML_TABLE_ON
+ || pInfo->nToken == HTML_TABLE_OFF
+ || pInfo->nToken == HTML_TABLEROW_ON
+ || pInfo->nToken == HTML_TABLEROW_OFF
+ || pInfo->nToken == HTML_TABLEHEADER_ON
+ || pInfo->nToken == HTML_TABLEHEADER_OFF
+ || pInfo->nToken == HTML_TABLEDATA_ON
+ || pInfo->nToken == HTML_TABLEDATA_OFF
+ || !aDebugSel.IsEqual( pInfo->aSelection )
+ || pInfo->aText.Len() || aDebugStr != pInfo->aText
+ )
+ {
+ aDebugSel = pInfo->aSelection;
+ aDebugStr = pInfo->aText;
+ nDebugCount++;
+ if ( !pDebugStrm )
+ {
+ pDebugStrm = new SvFileStream( "d:\\erdbghtm.log",
+ STREAM_WRITE | STREAM_TRUNC );
+ }
+ else
+ {
+ pDebugStrm->ReOpen();
+ pDebugStrm->Seek( nDebugStrmPos );
+ }
+ SvFileStream& rS = *pDebugStrm;
+ rS.WriteNumber( nDebugCountAll ); rS << ".: ";
+ rS.WriteNumber( nDebugCount ); rS << ". State: ";
+ rS.WriteNumber( (USHORT) pInfo->eState );
+ rS << ' ' << sDebugState[pInfo->eState] << endl;
+ rS << "SPar,SPos EPar,EPos: ";
+ rS.WriteNumber( aDebugSel.nStartPara ); rS << ',';
+ rS.WriteNumber( aDebugSel.nStartPos ); rS << ' ';
+ rS.WriteNumber( aDebugSel.nEndPara ); rS << ',';
+ rS.WriteNumber( aDebugSel.nEndPos ); rS << endl;
+ if ( aDebugStr.Len() )
+ {
+ rS << "Text: \"" << aDebugStr << '\"' << endl;
+ }
+ else
+ {
+ rS << "Text:" << endl;
+ }
+ rS << "Token: "; rS.WriteNumber( pInfo->nToken );
+ switch ( pInfo->nToken )
+ {
+ case HTML_TABLE_ON:
+ rS << " HTML_TABLE_ON";
+ break;
+ case HTML_TABLE_OFF:
+ rS << " HTML_TABLE_OFF";
+ break;
+ case HTML_TABLEROW_ON:
+ rS << " HTML_TABLEROW_ON";
+ break;
+ case HTML_TABLEROW_OFF:
+ rS << " HTML_TABLEROW_OFF";
+ break;
+ case HTML_TABLEHEADER_ON:
+ rS << " HTML_TABLEHEADER_ON";
+ break;
+ case HTML_TABLEHEADER_OFF:
+ rS << " HTML_TABLEHEADER_OFF";
+ break;
+ case HTML_TABLEDATA_ON:
+ rS << " HTML_TABLEDATA_ON";
+ break;
+ case HTML_TABLEDATA_OFF:
+ rS << " HTML_TABLEDATA_OFF";
+ break;
+ }
+ rS << " Value: "; rS.WriteNumber( pInfo->nTokenValue );
+ rS << endl << endl;
+ nDebugStrmPos = pDebugStrm->Tell();
+ pDebugStrm->Close();
+ }
+#endif
+ switch ( pInfo->eState )
+ {
+ case HTMLIMP_NEXTTOKEN:
+ ProcToken( pInfo );
+ break;
+ case HTMLIMP_UNKNOWNATTR:
+ ProcToken( pInfo );
+ break;
+ case HTMLIMP_START:
+ break;
+ case HTMLIMP_END:
+ if ( pInfo->aSelection.nEndPos )
+ {
+ // If text remains: create paragraph, without calling CloseEntry().
+ if( bInCell ) // #108269# ...but only in opened table cells.
+ {
+ bInCell = FALSE;
+ NextRow( pInfo );
+ bInCell = TRUE;
+ }
+ CloseEntry( pInfo );
+ }
+ while ( nTableLevel > 0 )
+ TableOff( pInfo ); // close tables, if </TABLE> missing
+ break;
+ case HTMLIMP_SETATTR:
+ break;
+ case HTMLIMP_INSERTTEXT:
+ break;
+ case HTMLIMP_INSERTPARA:
+ if ( nTableLevel < 1 )
+ {
+ CloseEntry( pInfo );
+ NextRow( pInfo );
+ }
+ break;
+ case HTMLIMP_INSERTFIELD:
+ break;
+ default:
+ DBG_ERRORFILE("HTMLImportHdl: unknown ImportInfo.eState");
+ }
+ return 0;
+}
+
+
+// Groesster Gemeinsamer Teiler nach Euklid (Kettendivision)
+// Sonderfall: 0 und irgendwas geben 1
+SCROW lcl_GGT( SCROW a, SCROW b )
+{
+ if ( !a || !b )
+ return 1;
+ do
+ {
+ if ( a > b )
+ a -= SCROW(a / b) * b;
+ else
+ b -= SCROW(b / a) * a;
+ } while ( a && b );
+ return ((a != 0) ? a : b);
+}
+
+
+// Kleinstes Gemeinsames Vielfaches: a * b / GGT(a,b)
+SCROW lcl_KGV( SCROW a, SCROW b )
+{
+ if ( a > b ) // Ueberlauf unwahrscheinlicher machen
+ return (a / lcl_GGT(a,b)) * b;
+ else
+ return (b / lcl_GGT(a,b)) * a;
+}
+
+
+void ScHTMLLayoutParser::TableDataOn( ImportInfo* pInfo )
+{
+ if ( bInCell )
+ CloseEntry( pInfo );
+ if ( !nTableLevel )
+ {
+ DBG_ERROR( "Dummbatz-Dok! <TH> oder <TD> ohne vorheriges <TABLE>" );
+ TableOn( pInfo );
+ }
+ bInCell = TRUE;
+ BOOL bHorJustifyCenterTH = (pInfo->nToken == HTML_TABLEHEADER_ON);
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_COLSPAN:
+ {
+ pActEntry->nColOverlap = ( SCCOL ) pOption->GetString().ToInt32();
+ }
+ break;
+ case HTML_O_ROWSPAN:
+ {
+ pActEntry->nRowOverlap = ( SCROW ) pOption->GetString().ToInt32();
+ }
+ break;
+ case HTML_O_ALIGN:
+ {
+ bHorJustifyCenterTH = FALSE;
+ SvxCellHorJustify eVal;
+ const String& rOptVal = pOption->GetString();
+ if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) == COMPARE_EQUAL )
+ eVal = SVX_HOR_JUSTIFY_RIGHT;
+ else if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_center ) == COMPARE_EQUAL )
+ eVal = SVX_HOR_JUSTIFY_CENTER;
+ else if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_left ) == COMPARE_EQUAL )
+ eVal = SVX_HOR_JUSTIFY_LEFT;
+ else
+ eVal = SVX_HOR_JUSTIFY_STANDARD;
+ if ( eVal != SVX_HOR_JUSTIFY_STANDARD )
+ pActEntry->aItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY) );
+ }
+ break;
+ case HTML_O_VALIGN:
+ {
+ SvxCellVerJustify eVal;
+ const String& rOptVal = pOption->GetString();
+ if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_top ) == COMPARE_EQUAL )
+ eVal = SVX_VER_JUSTIFY_TOP;
+ else if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_middle ) == COMPARE_EQUAL )
+ eVal = SVX_VER_JUSTIFY_CENTER;
+ else if ( rOptVal.CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_VA_bottom ) == COMPARE_EQUAL )
+ eVal = SVX_VER_JUSTIFY_BOTTOM;
+ else
+ eVal = SVX_VER_JUSTIFY_STANDARD;
+ pActEntry->aItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY) );
+ }
+ break;
+ case HTML_O_WIDTH:
+ {
+ pActEntry->nWidth = GetWidthPixel( pOption );
+ }
+ break;
+ case HTML_O_BGCOLOR:
+ {
+ Color aColor;
+ pOption->GetColor( aColor );
+ pActEntry->aItemSet.Put(
+ SvxBrushItem( aColor, ATTR_BACKGROUND ) );
+ }
+ break;
+ case HTML_O_SDVAL:
+ {
+ pActEntry->pValStr = new String( pOption->GetString() );
+ }
+ break;
+ case HTML_O_SDNUM:
+ {
+ pActEntry->pNumStr = new String( pOption->GetString() );
+ }
+ break;
+ }
+ }
+ pActEntry->nCol = nColCnt;
+ pActEntry->nRow = nRowCnt;
+ pActEntry->nTab = nTable;
+
+ if ( bHorJustifyCenterTH )
+ pActEntry->aItemSet.Put(
+ SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY) );
+}
+
+
+void ScHTMLLayoutParser::TableRowOn( ImportInfo* pInfo )
+{
+ if ( nColCnt > nColCntStart )
+ NextRow( pInfo ); // das optionale TableRowOff war nicht
+ nColOffset = nColOffsetStart;
+}
+
+
+void ScHTMLLayoutParser::TableRowOff( ImportInfo* pInfo )
+{
+ NextRow( pInfo );
+}
+
+
+void ScHTMLLayoutParser::TableDataOff( ImportInfo* pInfo )
+{
+ if ( bInCell )
+ CloseEntry( pInfo ); // aber nur wenn's auch eine war
+}
+
+
+void ScHTMLLayoutParser::TableOn( ImportInfo* pInfo )
+{
+ String aTabName;
+ bool bBorderOn = false;
+
+ if ( ++nTableLevel > 1 )
+ { // Table in Table
+ USHORT nTmpColOffset = nColOffset; // wird in Colonize noch angepasst
+ Colonize( pActEntry );
+ aTableStack.Push( new ScHTMLTableStackEntry(
+ pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
+ nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
+ nTableWidth, nColOffset, nColOffsetStart,
+ bFirstRow ) );
+ USHORT nLastWidth = nTableWidth;
+ nTableWidth = GetWidth( pActEntry );
+ if ( nTableWidth == nLastWidth && nMaxCol - nColCntStart > 1 )
+ { // es muss mehr als einen geben, also kann dieser nicht alles sein
+ nTableWidth = nLastWidth / static_cast<USHORT>((nMaxCol - nColCntStart));
+ }
+ nLastWidth = nTableWidth;
+ if ( pInfo->nToken == HTML_TABLE_ON )
+ { // es kann auch TD oder TH sein, wenn es vorher kein TABLE gab
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_WIDTH:
+ { // Prozent: von Dokumentbreite bzw. aeusserer Zelle
+ nTableWidth = GetWidthPixel( pOption );
+ }
+ break;
+ case HTML_O_BORDER:
+ bBorderOn = ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
+ break;
+ case HTML_O_ID:
+ aTabName.Assign( pOption->GetString() );
+ break;
+ }
+ }
+ }
+ bInCell = FALSE;
+ if ( bTabInTabCell && !(nTableWidth < nLastWidth) )
+ { // mehrere Tabellen in einer Zelle, untereinander
+ bTabInTabCell = FALSE;
+ NextRow( pInfo );
+ }
+ else
+ { // in dieser Zelle geht's los, oder nebeneinander
+ bTabInTabCell = FALSE;
+ nColCntStart = nColCnt;
+ nColOffset = nTmpColOffset;
+ nColOffsetStart = nColOffset;
+ }
+
+ ScEEParseEntry* pE = pList->Last();
+ NewActEntry( pE ); // neuer freifliegender pActEntry
+ xLockedList = new ScRangeList;
+ }
+ else
+ { // einfache Table auf Dokumentebene
+ EntryEnd( pActEntry, pInfo->aSelection );
+ if ( pActEntry->aSel.HasRange() )
+ { // noch fliegender Text
+ CloseEntry( pInfo );
+ NextRow( pInfo );
+ }
+ aTableStack.Push( new ScHTMLTableStackEntry(
+ pActEntry, xLockedList, pLocalColOffset, nFirstTableCell,
+ nColCnt, nRowCnt, nColCntStart, nMaxCol, nTable,
+ nTableWidth, nColOffset, nColOffsetStart,
+ bFirstRow ) );
+ // As soon as we have multiple tables we need to be tolerant with the offsets.
+ if (nMaxTable > 0)
+ nOffsetTolerance = SC_HTML_OFFSET_TOLERANCE_LARGE;
+ nTableWidth = 0;
+ if ( pInfo->nToken == HTML_TABLE_ON )
+ { // es kann auch TD oder TH sein, wenn es vorher kein TABLE gab
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_WIDTH:
+ { // Prozent: von Dokumentbreite bzw. aeusserer Zelle
+ nTableWidth = GetWidthPixel( pOption );
+ }
+ break;
+ case HTML_O_BORDER:
+ bBorderOn = ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
+ break;
+ case HTML_O_ID:
+ aTabName.Assign( pOption->GetString() );
+ break;
+ }
+ }
+ }
+ }
+ nTable = ++nMaxTable;
+ bFirstRow = TRUE;
+ nFirstTableCell = pList->Count();
+
+ pLocalColOffset = new ScHTMLColOffset;
+ MakeColNoRef( pLocalColOffset, nColOffsetStart, 0, 0, 0 );
+}
+
+
+void ScHTMLLayoutParser::TableOff( ImportInfo* pInfo )
+{
+ if ( bInCell )
+ CloseEntry( pInfo );
+ if ( nColCnt > nColCntStart )
+ TableRowOff( pInfo ); // das optionale TableRowOff war nicht
+ if ( !nTableLevel )
+ {
+ DBG_ERROR( "Dummbatz-Dok! </TABLE> ohne oeffnendes <TABLE>" );
+ return ;
+ }
+ if ( --nTableLevel > 0 )
+ { // Table in Table beendet
+ ScHTMLTableStackEntry* pS = aTableStack.Pop();
+ if ( pS )
+ {
+ ScEEParseEntry* pE = pS->pCellEntry;
+ SCROW nRows = nRowCnt - pS->nRowCnt;
+ if ( nRows > 1 )
+ { // Groesse der Tabelle an dieser Position eintragen
+ SCROW nRow = pS->nRowCnt;
+ USHORT nTab = pS->nTable;
+ if ( !pTables )
+ pTables = new Table;
+ // Hoehen der aeusseren Table
+ Table* pTab1 = (Table*) pTables->Get( nTab );
+ if ( !pTab1 )
+ {
+ pTab1 = new Table;
+ pTables->Insert( nTab, pTab1 );
+ }
+ SCROW nRowSpan = pE->nRowOverlap;
+ SCROW nRowKGV;
+ SCROW nRowsPerRow1; // aeussere Table
+ SCROW nRowsPerRow2; // innere Table
+ if ( nRowSpan > 1 )
+ { // KGV auf das sich aussere und innere Zeilen
+ // abbilden lassen
+ nRowKGV = lcl_KGV( nRowSpan, nRows );
+ nRowsPerRow1 = nRowKGV / nRowSpan;
+ nRowsPerRow2 = nRowKGV / nRows;
+ }
+ else
+ {
+ nRowKGV = nRowsPerRow1 = nRows;
+ nRowsPerRow2 = 1;
+ }
+ Table* pTab2 = NULL;
+ if ( nRowsPerRow2 > 1 )
+ { // Hoehen der inneren Table
+ pTab2 = new Table;
+ pTables->Insert( nTable, pTab2 );
+ }
+ // void* Data-Entry der Table-Class fuer das
+ // Hoehen-Mapping missbrauchen
+ if ( nRowKGV > 1 )
+ {
+ if ( nRowsPerRow1 > 1 )
+ { // aussen
+ for ( SCROW j=0; j < nRowSpan; j++ )
+ {
+ ULONG nRowKey = nRow + j;
+ SCROW nR = (SCROW)(ULONG)pTab1->Get( nRowKey );
+ if ( !nR )
+ pTab1->Insert( nRowKey, (void*) nRowsPerRow1 );
+ else if ( nRowsPerRow1 > nR )
+ pTab1->Replace( nRowKey, (void*) nRowsPerRow1 );
+ //2do: wie geht das noch besser?
+ else if ( nRowsPerRow1 < nR && nRowSpan == 1
+ && nTable == nMaxTable )
+ { // Platz uebrig, evtl. besser mergen
+ SCROW nAdd = nRowsPerRow1 - (nR % nRowsPerRow1);
+ nR += nAdd;
+ if ( (nR % nRows) == 0 )
+ { // nur wenn abbildbar
+ SCROW nR2 = (SCROW)(ULONG)pTab1->Get( nRowKey+1 );
+ if ( nR2 > nAdd )
+ { // nur wenn wirklich Platz
+ pTab1->Replace( nRowKey, (void*) nR );
+ pTab1->Replace( nRowKey+1, (void*) (nR2 - nAdd) );
+ nRowsPerRow2 = nR / nRows;
+ }
+ }
+ }
+ }
+ }
+ if ( nRowsPerRow2 > 1 )
+ { // innen
+ if ( !pTab2 )
+ { // nRowsPerRow2 kann erhoeht worden sein
+ pTab2 = new Table;
+ pTables->Insert( nTable, pTab2 );
+ }
+ for ( SCROW j=0; j < nRows; j++ )
+ {
+ ULONG nRowKey = nRow + j;
+ SCROW nR = (SCROW)(ULONG)pTab2->Get( nRowKey );
+ if ( !nR )
+ pTab2->Insert( nRowKey, (void*) nRowsPerRow2 );
+ else if ( nRowsPerRow2 > nR )
+ pTab2->Replace( nRowKey, (void*) nRowsPerRow2 );
+ }
+ }
+ }
+ }
+
+ SetWidths();
+
+ if ( !pE->nWidth )
+ pE->nWidth = nTableWidth;
+ else if ( pE->nWidth < nTableWidth )
+ {
+ USHORT nOldOffset = pE->nOffset + pE->nWidth;
+ USHORT nNewOffset = pE->nOffset + nTableWidth;
+ ModifyOffset( pS->pLocalColOffset, nOldOffset, nNewOffset, nOffsetTolerance );
+ USHORT nTmp = nNewOffset - pE->nOffset - pE->nWidth;
+ pE->nWidth = nNewOffset - pE->nOffset;
+ pS->nTableWidth = pS->nTableWidth + nTmp;
+ if ( pS->nColOffset >= nOldOffset )
+ pS->nColOffset = pS->nColOffset + nTmp;
+ }
+
+ nColCnt = pE->nCol + pE->nColOverlap;
+ nRowCnt = pS->nRowCnt;
+ nColCntStart = pS->nColCntStart;
+ nMaxCol = pS->nMaxCol;
+ nTable = pS->nTable;
+ nTableWidth = pS->nTableWidth;
+ nFirstTableCell = pS->nFirstTableCell;
+ nColOffset = pS->nColOffset;
+ nColOffsetStart = pS->nColOffsetStart;
+ bFirstRow = pS->bFirstRow;
+ xLockedList = pS->xLockedList;
+ if ( pLocalColOffset )
+ delete pLocalColOffset;
+ pLocalColOffset = pS->pLocalColOffset;
+ delete pActEntry;
+ // pActEntry bleibt erstmal erhalten falls da noch 'ne Table in
+ // der gleichen Zelle aufgemacht werden sollte (in HTML ist ja
+ // alles moeglich..) und wird in CloseEntry deleted
+ pActEntry = pE;
+ delete pS;
+ }
+ bTabInTabCell = TRUE;
+ bInCell = TRUE;
+ }
+ else
+ { // einfache Table beendet
+ SetWidths();
+ ScHTMLTableStackEntry* pS = aTableStack.Pop();
+ nMaxCol = 0;
+ nTable = 0;
+ if ( pS )
+ {
+ if ( pLocalColOffset )
+ delete pLocalColOffset;
+ pLocalColOffset = pS->pLocalColOffset;
+ delete pS;
+ }
+ }
+}
+
+
+void ScHTMLLayoutParser::Image( ImportInfo* pInfo )
+{
+ if ( !pActEntry->pImageList )
+ pActEntry->pImageList = new ScHTMLImageList;
+ ScHTMLImageList* pIL = pActEntry->pImageList;
+ ScHTMLImage* pImage = new ScHTMLImage;
+ pIL->Insert( pImage, LIST_APPEND );
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_SRC:
+ {
+ pImage->aURL = INetURLObject::GetAbsURL( aBaseURL, pOption->GetString() );
+ }
+ break;
+ case HTML_O_ALT:
+ {
+ if ( !pActEntry->bHasGraphic )
+ { // ALT text only if not any image loaded
+ if ( pActEntry->aAltText.Len() )
+ pActEntry->aAltText.AppendAscii( "; " );
+ pActEntry->aAltText += pOption->GetString();
+ }
+ }
+ break;
+ case HTML_O_WIDTH:
+ {
+ pImage->aSize.Width() = (long)pOption->GetNumber();
+ }
+ break;
+ case HTML_O_HEIGHT:
+ {
+ pImage->aSize.Height() = (long)pOption->GetNumber();
+ }
+ break;
+ case HTML_O_HSPACE:
+ {
+ pImage->aSpace.X() = (long)pOption->GetNumber();
+ }
+ break;
+ case HTML_O_VSPACE:
+ {
+ pImage->aSpace.Y() = (long)pOption->GetNumber();
+ }
+ break;
+ }
+ }
+ if ( !pImage->aURL.Len() )
+ {
+ DBG_ERRORFILE( "Image: Grafik ohne URL ?!?" );
+ return ;
+ }
+
+ USHORT nFormat;
+ Graphic* pGraphic = new Graphic;
+ GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter();
+ if ( GRFILTER_OK != GraphicFilter::LoadGraphic( pImage->aURL, pImage->aFilterName,
+ *pGraphic, pFilter, &nFormat ) )
+ {
+ delete pGraphic;
+ return ; // dumm gelaufen
+ }
+ if ( !pActEntry->bHasGraphic )
+ { // discard any ALT text in this cell if we have any image
+ pActEntry->bHasGraphic = TRUE;
+ pActEntry->aAltText.Erase();
+ }
+ pImage->aFilterName = pFilter->GetImportFormatName( nFormat );
+ pImage->pGraphic = pGraphic;
+ if ( !(pImage->aSize.Width() && pImage->aSize.Height()) )
+ {
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ pImage->aSize = pDefaultDev->LogicToPixel( pGraphic->GetPrefSize(),
+ pGraphic->GetPrefMapMode() );
+ }
+ if ( pIL->Count() > 0 )
+ {
+ long nWidth = 0;
+ for ( ScHTMLImage* pI = pIL->First(); pI; pI = pIL->Next() )
+ {
+ if ( pI->nDir & nHorizontal )
+ nWidth += pI->aSize.Width() + 2 * pI->aSpace.X();
+ else
+ nWidth = 0;
+ }
+ if ( pActEntry->nWidth
+ && (nWidth + pImage->aSize.Width() + 2 * pImage->aSpace.X()
+ >= pActEntry->nWidth) )
+ pIL->Last()->nDir = nVertical;
+ }
+}
+
+
+void ScHTMLLayoutParser::ColOn( ImportInfo* pInfo )
+{
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_WIDTH:
+ {
+ USHORT nVal = GetWidthPixel( pOption );
+ MakeCol( pLocalColOffset, nColOffset, nVal, 0, 0 );
+ nColOffset = nColOffset + nVal;
+ }
+ break;
+ }
+ }
+}
+
+
+USHORT ScHTMLLayoutParser::GetWidthPixel( const HTMLOption* pOption )
+{
+ const String& rOptVal = pOption->GetString();
+ if ( rOptVal.Search('%') != STRING_NOTFOUND )
+ { // Prozent
+ USHORT nW = (nTableWidth ? nTableWidth : (USHORT) aPageSize.Width());
+ return (USHORT)((pOption->GetNumber() * nW) / 100);
+ }
+ else
+ {
+ if ( rOptVal.Search('*') != STRING_NOTFOUND )
+ { // relativ zu was?!?
+//2do: ColArray aller relativen Werte sammeln und dann MakeCol
+ return 0;
+ }
+ else
+ return (USHORT)pOption->GetNumber(); // Pixel
+ }
+}
+
+
+void ScHTMLLayoutParser::AnchorOn( ImportInfo* pInfo )
+{
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_NAME:
+ {
+ pActEntry->pName = new String( pOption->GetString() );
+ }
+ break;
+ }
+ }
+}
+
+
+BOOL ScHTMLLayoutParser::IsAtBeginningOfText( ImportInfo* pInfo )
+{
+ ESelection& rSel = pActEntry->aSel;
+ return rSel.nStartPara == rSel.nEndPara &&
+ rSel.nStartPara <= pInfo->aSelection.nEndPara &&
+ pEdit->GetTextLen( rSel.nStartPara ) == 0;
+}
+
+
+void ScHTMLLayoutParser::FontOn( ImportInfo* pInfo )
+{
+ if ( IsAtBeginningOfText( pInfo ) )
+ { // nur am Anfang des Textes, gilt dann fuer gesamte Zelle
+ const HTMLOptions* pOptions = ((HTMLParser*)pInfo->pParser)->GetOptions();
+ USHORT nArrLen = pOptions->Count();
+ for ( USHORT i = 0; i < nArrLen; i++ )
+ {
+ const HTMLOption* pOption = (*pOptions)[i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_FACE :
+ {
+ const String& rFace = pOption->GetString();
+ String aFontName;
+ xub_StrLen nPos = 0;
+ while( nPos != STRING_NOTFOUND )
+ { // Fontliste, VCL: Semikolon als Separator, HTML: Komma
+ String aFName = rFace.GetToken( 0, ',', nPos );
+ aFName.EraseTrailingChars().EraseLeadingChars();
+ if( aFontName.Len() )
+ aFontName += ';';
+ aFontName += aFName;
+ }
+ if ( aFontName.Len() )
+ pActEntry->aItemSet.Put( SvxFontItem( FAMILY_DONTKNOW,
+ aFontName, EMPTY_STRING, PITCH_DONTKNOW,
+ RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
+ }
+ break;
+ case HTML_O_SIZE :
+ {
+ USHORT nSize = (USHORT) pOption->GetNumber();
+ if ( nSize == 0 )
+ nSize = 1;
+ else if ( nSize > SC_HTML_FONTSIZES )
+ nSize = SC_HTML_FONTSIZES;
+ pActEntry->aItemSet.Put( SvxFontHeightItem(
+ maFontHeights[nSize-1], 100, ATTR_FONT_HEIGHT ) );
+ }
+ break;
+ case HTML_O_COLOR :
+ {
+ Color aColor;
+ pOption->GetColor( aColor );
+ pActEntry->aItemSet.Put( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+void ScHTMLLayoutParser::ProcToken( ImportInfo* pInfo )
+{
+ BOOL bSetLastToken = TRUE;
+ switch ( pInfo->nToken )
+ {
+ case HTML_META:
+ {
+ HTMLParser* pParser = (HTMLParser*) pInfo->pParser;
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
+ pParser->ParseMetaOptions(
+ xDPS->getDocumentProperties(),
+ mpDoc->GetDocumentShell()->GetHeaderAttributes() );
+ }
+ break;
+ case HTML_TITLE_ON:
+ {
+ bInTitle = TRUE;
+ aString.Erase();
+ }
+ break;
+ case HTML_TITLE_OFF:
+ {
+ if ( bInTitle && aString.Len() )
+ {
+ // Leerzeichen von Zeilenumbruechen raus
+ aString.EraseLeadingChars();
+ aString.EraseTrailingChars();
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDoc->GetDocumentShell()->GetModel(),
+ uno::UNO_QUERY_THROW);
+ xDPS->getDocumentProperties()->setTitle(aString);
+ }
+ bInTitle = FALSE;
+ }
+ break;
+ case HTML_TABLE_ON:
+ {
+ TableOn( pInfo );
+ }
+ break;
+ case HTML_COL_ON:
+ {
+ ColOn( pInfo );
+ }
+ break;
+ case HTML_TABLEHEADER_ON: // oeffnet Zelle
+ {
+ if ( bInCell )
+ CloseEntry( pInfo );
+ // bInCell nicht TRUE setzen, das macht TableDataOn
+ pActEntry->aItemSet.Put(
+ SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT) );
+ } // fall thru
+ case HTML_TABLEDATA_ON: // oeffnet Zelle
+ {
+ TableDataOn( pInfo );
+ }
+ break;
+ case HTML_TABLEHEADER_OFF:
+ case HTML_TABLEDATA_OFF: // schliesst Zelle
+ {
+ TableDataOff( pInfo );
+ }
+ break;
+ case HTML_TABLEROW_ON: // vor erster Zelle in Row
+ {
+ TableRowOn( pInfo );
+ }
+ break;
+ case HTML_TABLEROW_OFF: // nach letzter Zelle in Row
+ {
+ TableRowOff( pInfo );
+ }
+ break;
+ case HTML_TABLE_OFF:
+ {
+ TableOff( pInfo );
+ }
+ break;
+ case HTML_IMAGE:
+ {
+ Image( pInfo );
+ }
+ break;
+ case HTML_PARABREAK_OFF:
+ { // nach einem Image geht es vertikal weiter
+ if ( pActEntry->pImageList && pActEntry->pImageList->Count() > 0 )
+ pActEntry->pImageList->Last()->nDir = nVertical;
+ }
+ break;
+ case HTML_ANCHOR_ON:
+ {
+ AnchorOn( pInfo );
+ }
+ break;
+ case HTML_FONT_ON :
+ {
+ FontOn( pInfo );
+ }
+ break;
+ case HTML_BIGPRINT_ON :
+ {
+//2do: aktuelle Fontgroesse merken und einen groesser
+ if ( IsAtBeginningOfText( pInfo ) )
+ pActEntry->aItemSet.Put( SvxFontHeightItem(
+ maFontHeights[3], 100, ATTR_FONT_HEIGHT ) );
+ }
+ break;
+ case HTML_SMALLPRINT_ON :
+ {
+//2do: aktuelle Fontgroesse merken und einen kleiner
+ if ( IsAtBeginningOfText( pInfo ) )
+ pActEntry->aItemSet.Put( SvxFontHeightItem(
+ maFontHeights[0], 100, ATTR_FONT_HEIGHT ) );
+ }
+ break;
+ case HTML_BOLD_ON :
+ case HTML_STRONG_ON :
+ {
+ if ( IsAtBeginningOfText( pInfo ) )
+ pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
+ ATTR_FONT_WEIGHT ) );
+ }
+ break;
+ case HTML_ITALIC_ON :
+ case HTML_EMPHASIS_ON :
+ case HTML_ADDRESS_ON :
+ case HTML_BLOCKQUOTE_ON :
+ case HTML_BLOCKQUOTE30_ON :
+ case HTML_CITIATION_ON :
+ case HTML_VARIABLE_ON :
+ {
+ if ( IsAtBeginningOfText( pInfo ) )
+ pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
+ ATTR_FONT_POSTURE ) );
+ }
+ break;
+ case HTML_DEFINSTANCE_ON :
+ {
+ if ( IsAtBeginningOfText( pInfo ) )
+ {
+ pActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
+ ATTR_FONT_WEIGHT ) );
+ pActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
+ ATTR_FONT_POSTURE ) );
+ }
+ }
+ break;
+ case HTML_UNDERLINE_ON :
+ {
+ if ( IsAtBeginningOfText( pInfo ) )
+ pActEntry->aItemSet.Put( SvxUnderlineItem( UNDERLINE_SINGLE,
+ ATTR_FONT_UNDERLINE ) );
+ }
+ break;
+ case HTML_TEXTTOKEN:
+ {
+ if ( bInTitle )
+ aString += pInfo->aText;
+ }
+ break;
+ default:
+ { // nLastToken nicht setzen!
+ bSetLastToken = FALSE;
+ }
+ }
+ if ( bSetLastToken )
+ nLastToken = pInfo->nToken;
+}
+
+
+
+// ============================================================================
+// HTML DATA QUERY PARSER
+// ============================================================================
+
+template< typename Type >
+inline Type getLimitedValue( const Type& rValue, const Type& rMin, const Type& rMax )
+{ return ::std::max( ::std::min( rValue, rMax ), rMin ); }
+
+// ============================================================================
+
+/** Iterates through all HTML tag options of the passed ImportInfo struct. */
+class ScHTMLOptionIterator
+{
+private:
+ const HTMLOptions* mpOptions; /// The options array.
+ const HTMLOption* mpCurrOption; /// Current option.
+ sal_uInt16 mnCount; /// Size of the options array.
+ sal_uInt16 mnIndex; /// Next option to return.
+
+public:
+ explicit ScHTMLOptionIterator( const ImportInfo& rInfo );
+
+ inline bool is() const { return mnIndex < mnCount; }
+ inline const HTMLOption* operator->() const { return mpCurrOption; }
+ inline const HTMLOption& operator*() const { return *mpCurrOption; }
+ ScHTMLOptionIterator& operator++();
+};
+
+// ----------------------------------------------------------------------------
+
+ScHTMLOptionIterator::ScHTMLOptionIterator( const ImportInfo& rInfo ) :
+ mpOptions( 0 ),
+ mpCurrOption( 0 ),
+ mnCount( 0 ),
+ mnIndex( 0 )
+{
+ const HTMLParser* pParser = static_cast< const HTMLParser* >( rInfo.pParser );
+ if( pParser )
+ mpOptions = pParser->GetOptions();
+ if( mpOptions )
+ mnCount = mpOptions->Count();
+ if( mnCount )
+ mpCurrOption = mpOptions->GetObject( 0 );
+}
+
+ScHTMLOptionIterator& ScHTMLOptionIterator::operator++()
+{
+ if( mnIndex < mnCount ) ++mnIndex;
+ mpCurrOption = (mnIndex < mnCount) ? mpOptions->GetObject( mnIndex ) : 0;
+ return *this;
+}
+
+// ============================================================================
+
+ScHTMLEntry::ScHTMLEntry( const SfxItemSet& rItemSet, ScHTMLTableId nTableId ) :
+ ScEEParseEntry( rItemSet ),
+ mbImportAlways( false )
+{
+ nTab = nTableId;
+ bEntirePara = false;
+}
+
+bool ScHTMLEntry::HasContents() const
+{
+ return mbImportAlways || aSel.HasRange() || aAltText.Len() || IsTable();
+}
+
+void ScHTMLEntry::AdjustStart( const ImportInfo& rInfo )
+{
+ // set start position
+ aSel.nStartPara = rInfo.aSelection.nStartPara;
+ aSel.nStartPos = rInfo.aSelection.nStartPos;
+ // adjust end position
+ if( (aSel.nEndPara < aSel.nStartPara) || ((aSel.nEndPara == aSel.nStartPara) && (aSel.nEndPos < aSel.nStartPos)) )
+ {
+ aSel.nEndPara = aSel.nStartPara;
+ aSel.nEndPos = aSel.nStartPos;
+ }
+}
+
+void ScHTMLEntry::AdjustEnd( const ImportInfo& rInfo )
+{
+ DBG_ASSERT( (aSel.nEndPara < rInfo.aSelection.nEndPara) ||
+ ((aSel.nEndPara == rInfo.aSelection.nEndPara) && (aSel.nEndPos <= rInfo.aSelection.nEndPos)),
+ "ScHTMLQueryParser::AdjustEntryEnd - invalid end position" );
+ // set end position
+ aSel.nEndPara = rInfo.aSelection.nEndPara;
+ aSel.nEndPos = rInfo.aSelection.nEndPos;
+}
+
+void ScHTMLEntry::Strip( const EditEngine& rEditEngine )
+{
+ // strip leading empty paragraphs
+ while( (aSel.nStartPara < aSel.nEndPara) && (rEditEngine.GetTextLen( aSel.nStartPara ) <= aSel.nStartPos) )
+ {
+ ++aSel.nStartPara;
+ aSel.nStartPos = 0;
+ }
+ // strip trailing empty paragraphs
+ while( (aSel.nStartPara < aSel.nEndPara) && (aSel.nEndPos == 0) )
+ {
+ --aSel.nEndPara;
+ aSel.nEndPos = rEditEngine.GetTextLen( aSel.nEndPara );
+ }
+}
+
+// ============================================================================
+
+/** A map of ScHTMLTable objects.
+
+ Organizes the tables with a unique table key. Stores nested tables inside
+ the parent table and forms in this way a tree structure of tables. An
+ instance of this class ownes the contained table objects and deletes them
+ on destruction.
+ */
+class ScHTMLTableMap
+{
+private:
+ typedef ::boost::shared_ptr< ScHTMLTable > ScHTMLTablePtr;
+ typedef ::std::map< ScHTMLTableId, ScHTMLTablePtr > ScHTMLTableStdMap;
+
+public:
+ typedef ScHTMLTableStdMap::iterator iterator;
+ typedef ScHTMLTableStdMap::const_iterator const_iterator;
+
+private:
+ ScHTMLTable& mrParentTable; /// Reference to parent table.
+ ScHTMLTableStdMap maTables; /// Container for all table objects.
+ mutable ScHTMLTable* mpCurrTable; /// Current table, used for fast search.
+
+public:
+ explicit ScHTMLTableMap( ScHTMLTable& rParentTable );
+ virtual ~ScHTMLTableMap();
+
+ inline iterator begin() { return maTables.begin(); }
+ inline const_iterator begin() const { return maTables.begin(); }
+ inline iterator end() { return maTables.end(); }
+ inline const_iterator end() const { return maTables.end(); }
+ inline bool empty() const { return maTables.empty(); }
+
+ /** Returns the specified table.
+ @param nTableId Unique identifier of the table.
+ @param bDeep true = searches deep in all nested table; false = only in this container. */
+ ScHTMLTable* FindTable( ScHTMLTableId nTableId, bool bDeep = true ) const;
+
+ /** Inserts a new table into the container. This container owns the created table.
+ @param bPreFormText true = New table is based on preformatted text (<pre> tag). */
+ ScHTMLTable* CreateTable( const ImportInfo& rInfo, bool bPreFormText );
+
+private:
+ /** Sets a working table with its index for search optimization. */
+ inline void SetCurrTable( ScHTMLTable* pTable ) const
+ { if( pTable ) mpCurrTable = pTable; }
+};
+
+// ----------------------------------------------------------------------------
+
+ScHTMLTableMap::ScHTMLTableMap( ScHTMLTable& rParentTable ) :
+ mrParentTable( rParentTable )
+{
+}
+
+ScHTMLTableMap::~ScHTMLTableMap()
+{
+}
+
+ScHTMLTable* ScHTMLTableMap::FindTable( ScHTMLTableId nTableId, bool bDeep ) const
+{
+ ScHTMLTable* pResult = 0;
+ if( mpCurrTable && (nTableId == mpCurrTable->GetTableId()) )
+ pResult = mpCurrTable; // cached table
+ else
+ {
+ const_iterator aFind = maTables.find( nTableId );
+ if( aFind != maTables.end() )
+ pResult = aFind->second.get(); // table from this container
+ }
+
+ // not found -> search deep in nested tables
+ if( !pResult && bDeep )
+ for( const_iterator aIter = begin(), aEnd = end(); !pResult && (aIter != aEnd); ++aIter )
+ pResult = aIter->second->FindNestedTable( nTableId );
+
+ SetCurrTable( pResult );
+ return pResult;
+}
+
+ScHTMLTable* ScHTMLTableMap::CreateTable( const ImportInfo& rInfo, bool bPreFormText )
+{
+ ScHTMLTable* pTable = new ScHTMLTable( mrParentTable, rInfo, bPreFormText );
+ maTables[ pTable->GetTableId() ].reset( pTable );
+ SetCurrTable( pTable );
+ return pTable;
+}
+
+// ----------------------------------------------------------------------------
+
+/** Simplified forward iterator for convenience.
+
+ Before the iterator can be dereferenced, it must be tested with the is()
+ method. The iterator may be invalid directly after construction (e.g. empty
+ container).
+ */
+class ScHTMLTableIterator
+{
+public:
+ /** Constructs the iterator for the passed table map.
+ @param pTableMap Pointer to the table map (is allowed to be NULL). */
+ explicit ScHTMLTableIterator( const ScHTMLTableMap* pTableMap );
+
+ inline bool is() const { return maIter != maEnd; }
+ inline ScHTMLTable* operator->() { return maIter->second.get(); }
+ inline ScHTMLTable& operator*() { return *maIter->second; }
+ inline ScHTMLTableIterator& operator++() { ++maIter; return *this; }
+
+private:
+ ScHTMLTableMap::const_iterator maIter;
+ ScHTMLTableMap::const_iterator maEnd;
+};
+
+ScHTMLTableIterator::ScHTMLTableIterator( const ScHTMLTableMap* pTableMap )
+{
+ if( pTableMap )
+ {
+ maIter = pTableMap->begin();
+ maEnd = pTableMap->end();
+ }
+}
+
+// ============================================================================
+
+ScHTMLTableAutoId::ScHTMLTableAutoId( ScHTMLTableId& rnUnusedId ) :
+ mnTableId( rnUnusedId ),
+ mrnUnusedId( rnUnusedId )
+{
+ ++mrnUnusedId;
+}
+
+// ----------------------------------------------------------------------------
+
+ScHTMLTable::ScHTMLTable( ScHTMLTable& rParentTable, const ImportInfo& rInfo, bool bPreFormText ) :
+ mpParentTable( &rParentTable ),
+ maTableId( rParentTable.maTableId.mrnUnusedId ),
+ maTableItemSet( rParentTable.GetCurrItemSet() ),
+ mrEditEngine( rParentTable.mrEditEngine ),
+ mrEEParseList( rParentTable.mrEEParseList ),
+ mpCurrEntryList( 0 ),
+ maSize( 1, 1 ),
+ mbBorderOn( false ),
+ mbPreFormText( bPreFormText ),
+ mbRowOn( false ),
+ mbDataOn( false ),
+ mbPushEmptyLine( false )
+{
+ if( mbPreFormText )
+ {
+ ImplRowOn();
+ ImplDataOn( ScHTMLSize( 1, 1 ) );
+ }
+ else
+ {
+ ProcessFormatOptions( maTableItemSet, rInfo );
+ for( ScHTMLOptionIterator aIter( rInfo ); aIter.is(); ++aIter )
+ {
+ switch( aIter->GetToken() )
+ {
+ case HTML_O_BORDER:
+ mbBorderOn = ((aIter->GetString().Len() == 0) || (aIter->GetNumber() != 0));
+ break;
+ case HTML_O_ID:
+ maTableName = aIter->GetString();
+ break;
+ }
+ }
+ }
+
+ CreateNewEntry( rInfo );
+}
+
+ScHTMLTable::ScHTMLTable( SfxItemPool& rPool, EditEngine& rEditEngine, ScEEParseList& rEEParseList, ScHTMLTableId& rnUnusedId ) :
+ mpParentTable( 0 ),
+ maTableId( rnUnusedId ),
+ maTableItemSet( rPool ),
+ mrEditEngine( rEditEngine ),
+ mrEEParseList( rEEParseList ),
+ mpCurrEntryList( 0 ),
+ maSize( 1, 1 ),
+ mbBorderOn( false ),
+ mbPreFormText( false ),
+ mbRowOn( false ),
+ mbDataOn( false ),
+ mbPushEmptyLine( false )
+{
+ // open the first "cell" of the document
+ ImplRowOn();
+ ImplDataOn( ScHTMLSize( 1, 1 ) );
+ mxCurrEntry = CreateEntry();
+}
+
+ScHTMLTable::~ScHTMLTable()
+{
+}
+
+const SfxItemSet& ScHTMLTable::GetCurrItemSet() const
+{
+ // first try cell item set, then row item set, then table item set
+ return mxDataItemSet.get() ? *mxDataItemSet : (mxRowItemSet.get() ? *mxRowItemSet : maTableItemSet);
+}
+
+ScHTMLSize ScHTMLTable::GetSpan( const ScHTMLPos& rCellPos ) const
+{
+ ScHTMLSize aSpan( 1, 1 );
+ ScRange* pRange = 0;
+ if( ((pRange = maVMergedCells.Find( rCellPos.MakeAddr() )) != 0) || ((pRange = maHMergedCells.Find( rCellPos.MakeAddr() )) != 0) )
+ aSpan.Set( pRange->aEnd.Col() - pRange->aStart.Col() + 1, pRange->aEnd.Row() - pRange->aStart.Row() + 1 );
+ return aSpan;
+}
+
+ScHTMLTable* ScHTMLTable::FindNestedTable( ScHTMLTableId nTableId ) const
+{
+ return mxNestedTables.get() ? mxNestedTables->FindTable( nTableId, true ) : 0;
+}
+
+void ScHTMLTable::PutItem( const SfxPoolItem& rItem )
+{
+ DBG_ASSERT( mxCurrEntry.get(), "ScHTMLTable::PutItem - no current entry" );
+ if( mxCurrEntry.get() && mxCurrEntry->IsEmpty() )
+ mxCurrEntry->GetItemSet().Put( rItem );
+}
+
+void ScHTMLTable::PutText( const ImportInfo& rInfo )
+{
+ DBG_ASSERT( mxCurrEntry.get(), "ScHTMLTable::PutText - no current entry" );
+ if( mxCurrEntry.get() )
+ {
+ if( !mxCurrEntry->HasContents() && IsSpaceCharInfo( rInfo ) )
+ mxCurrEntry->AdjustStart( rInfo );
+ else
+ mxCurrEntry->AdjustEnd( rInfo );
+ }
+}
+
+void ScHTMLTable::InsertPara( const ImportInfo& rInfo )
+{
+ if( mxCurrEntry.get() && mbDataOn && !IsEmptyCell() )
+ mxCurrEntry->SetImportAlways();
+ PushEntry( rInfo );
+ CreateNewEntry( rInfo );
+ InsertLeadingEmptyLine();
+}
+
+void ScHTMLTable::BreakOn()
+{
+ // empty line, if <br> is at start of cell
+ mbPushEmptyLine = !mbPreFormText && mbDataOn && IsEmptyCell();
+}
+
+void ScHTMLTable::HeadingOn()
+{
+ // call directly, InsertPara() has not been called before
+ InsertLeadingEmptyLine();
+}
+
+void ScHTMLTable::InsertLeadingEmptyLine()
+{
+ // empty line, if <p>, </p>, <h?>, or </h*> are not at start of cell
+ mbPushEmptyLine = !mbPreFormText && mbDataOn && !IsEmptyCell();
+}
+
+void ScHTMLTable::AnchorOn()
+{
+ DBG_ASSERT( mxCurrEntry.get(), "ScHTMLTable::AnchorOn - no current entry" );
+ // don't skip entries with single hyperlinks
+ if( mxCurrEntry.get() )
+ mxCurrEntry->SetImportAlways();
+}
+
+ScHTMLTable* ScHTMLTable::TableOn( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo );
+ return InsertNestedTable( rInfo, false );
+}
+
+ScHTMLTable* ScHTMLTable::TableOff( const ImportInfo& rInfo )
+{
+ return mbPreFormText ? this : CloseTable( rInfo );
+}
+
+ScHTMLTable* ScHTMLTable::PreOn( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo );
+ return InsertNestedTable( rInfo, true );
+}
+
+ScHTMLTable* ScHTMLTable::PreOff( const ImportInfo& rInfo )
+{
+ return mbPreFormText ? CloseTable( rInfo ) : this;
+}
+
+void ScHTMLTable::RowOn( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo, true );
+ if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
+ {
+ ImplRowOn();
+ ProcessFormatOptions( *mxRowItemSet, rInfo );
+ }
+ CreateNewEntry( rInfo );
+}
+
+void ScHTMLTable::RowOff( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo, true );
+ if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
+ ImplRowOff();
+ CreateNewEntry( rInfo );
+}
+
+void ScHTMLTable::DataOn( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo, true );
+ if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
+ {
+ // read needed options from the <td> tag
+ ScHTMLSize aSpanSize( 1, 1 );
+ ::std::auto_ptr< String > pValStr, pNumStr;
+ for( ScHTMLOptionIterator aIter( rInfo ); aIter.is(); ++aIter )
+ {
+ switch( aIter->GetToken() )
+ {
+ case HTML_O_COLSPAN:
+ aSpanSize.mnCols = static_cast< SCCOL >( getLimitedValue< sal_Int32 >( aIter->GetString().ToInt32(), 1, 256 ) );
+ break;
+ case HTML_O_ROWSPAN:
+ aSpanSize.mnRows = static_cast< SCROW >( getLimitedValue< sal_Int32 >( aIter->GetString().ToInt32(), 1, 256 ) );
+ break;
+ case HTML_O_SDVAL:
+ pValStr.reset( new String( aIter->GetString() ) );
+ break;
+ case HTML_O_SDNUM:
+ pNumStr.reset( new String( aIter->GetString() ) );
+ break;
+ }
+ }
+
+ ImplDataOn( aSpanSize );
+ ProcessFormatOptions( *mxDataItemSet, rInfo );
+ CreateNewEntry( rInfo );
+ mxCurrEntry->pValStr = pValStr.release();
+ mxCurrEntry->pNumStr = pNumStr.release();
+ }
+ else
+ CreateNewEntry( rInfo );
+}
+
+void ScHTMLTable::DataOff( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo, true );
+ if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
+ ImplDataOff();
+ CreateNewEntry( rInfo );
+}
+
+void ScHTMLTable::BodyOn( const ImportInfo& rInfo )
+{
+ bool bPushed = PushEntry( rInfo );
+ if( !mpParentTable )
+ {
+ // #108269# do not start new row, if nothing (no title) precedes the body.
+ if( bPushed || !mbRowOn )
+ ImplRowOn();
+ if( bPushed || !mbDataOn )
+ ImplDataOn( ScHTMLSize( 1, 1 ) );
+ ProcessFormatOptions( *mxDataItemSet, rInfo );
+ }
+ CreateNewEntry( rInfo );
+}
+
+void ScHTMLTable::BodyOff( const ImportInfo& rInfo )
+{
+ PushEntry( rInfo );
+ if( !mpParentTable )
+ {
+ ImplDataOff();
+ ImplRowOff();
+ }
+ CreateNewEntry( rInfo );
+}
+
+ScHTMLTable* ScHTMLTable::CloseTable( const ImportInfo& rInfo )
+{
+ if( mpParentTable ) // not allowed to close global table
+ {
+ PushEntry( rInfo, mbDataOn );
+ ImplDataOff();
+ ImplRowOff();
+ mpParentTable->PushTableEntry( GetTableId() );
+ mpParentTable->CreateNewEntry( rInfo );
+ if( mbPreFormText ) // enclose preformatted table with empty lines in parent table
+ mpParentTable->InsertLeadingEmptyLine();
+ return mpParentTable;
+ }
+ return this;
+}
+
+SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
+{
+ const ScSizeVec& rSizes = maCumSizes[ eOrient ];
+ size_t nIndex = static_cast< size_t >( nCellPos );
+ if( nIndex >= rSizes.size() ) return 0;
+ return (nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]);
+}
+
+SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellBegin, SCCOLROW nCellEnd ) const
+{
+ const ScSizeVec& rSizes = maCumSizes[ eOrient ];
+ size_t nBeginIdx = static_cast< size_t >( ::std::max< SCCOLROW >( nCellBegin, 0 ) );
+ size_t nEndIdx = static_cast< size_t >( ::std::min< SCCOLROW >( nCellEnd, static_cast< SCCOLROW >( rSizes.size() ) ) );
+ if (nBeginIdx >= nEndIdx ) return 0;
+ return rSizes[ nEndIdx - 1 ] - ((nBeginIdx == 0) ? 0 : rSizes[ nBeginIdx - 1 ]);
+}
+
+SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient ) const
+{
+ const ScSizeVec& rSizes = maCumSizes[ eOrient ];
+ return rSizes.empty() ? 0 : rSizes.back();
+}
+
+ScHTMLSize ScHTMLTable::GetDocSize( const ScHTMLPos& rCellPos ) const
+{
+ ScHTMLSize aCellSpan = GetSpan( rCellPos );
+ return ScHTMLSize(
+ static_cast< SCCOL >( GetDocSize( tdCol, rCellPos.mnCol, rCellPos.mnCol + aCellSpan.mnCols ) ),
+ static_cast< SCROW >( GetDocSize( tdRow, rCellPos.mnRow, rCellPos.mnRow + aCellSpan.mnRows ) ) );
+}
+
+SCCOLROW ScHTMLTable::GetDocPos( ScHTMLOrient eOrient, SCCOLROW nCellPos ) const
+{
+ return maDocBasePos.Get( eOrient ) + GetDocSize( eOrient, 0, nCellPos );
+}
+
+ScHTMLPos ScHTMLTable::GetDocPos( const ScHTMLPos& rCellPos ) const
+{
+ return ScHTMLPos(
+ static_cast< SCCOL >( GetDocPos( tdCol, rCellPos.mnCol ) ),
+ static_cast< SCROW >( GetDocPos( tdRow, rCellPos.mnRow ) ) );
+}
+
+void ScHTMLTable::GetDocRange( ScRange& rRange ) const
+{
+ rRange.aStart = rRange.aEnd = maDocBasePos.MakeAddr();
+ rRange.aEnd.Move( static_cast< SCsCOL >( GetDocSize( tdCol ) ) - 1, static_cast< SCsROW >( GetDocSize( tdRow ) ) - 1, 0 );
+}
+
+void ScHTMLTable::ApplyCellBorders( ScDocument* pDoc, const ScAddress& rFirstPos ) const
+{
+ DBG_ASSERT( pDoc, "ScHTMLTable::ApplyCellBorders - no document" );
+ if( pDoc && mbBorderOn )
+ {
+ const SCCOL nLastCol = maSize.mnCols - 1;
+ const SCROW nLastRow = maSize.mnRows - 1;
+ const sal_uInt16 nOuterLine = DEF_LINE_WIDTH_2;
+ const sal_uInt16 nInnerLine = DEF_LINE_WIDTH_0;
+ SvxBorderLine aOuterLine, aInnerLine;
+ aOuterLine.SetColor( Color( COL_BLACK ) );
+ aOuterLine.SetOutWidth( nOuterLine );
+ aInnerLine.SetColor( Color( COL_BLACK ) );
+ aInnerLine.SetOutWidth( nInnerLine );
+ SvxBoxItem aBorderItem( ATTR_BORDER );
+
+ for( SCCOL nCol = 0; nCol <= nLastCol; ++nCol )
+ {
+ SvxBorderLine* pLeftLine = (nCol == 0) ? &aOuterLine : &aInnerLine;
+ SvxBorderLine* pRightLine = (nCol == nLastCol) ? &aOuterLine : &aInnerLine;
+ SCCOL nCellCol1 = static_cast< SCCOL >( GetDocPos( tdCol, nCol ) ) + rFirstPos.Col();
+ SCCOL nCellCol2 = nCellCol1 + static_cast< SCCOL >( GetDocSize( tdCol, nCol ) ) - 1;
+ for( SCROW nRow = 0; nRow <= nLastRow; ++nRow )
+ {
+ SvxBorderLine* pTopLine = (nRow == 0) ? &aOuterLine : &aInnerLine;
+ SvxBorderLine* pBottomLine = (nRow == nLastRow) ? &aOuterLine : &aInnerLine;
+ SCROW nCellRow1 = GetDocPos( tdRow, nRow ) + rFirstPos.Row();
+ SCROW nCellRow2 = nCellRow1 + GetDocSize( tdRow, nRow ) - 1;
+ for( SCCOL nCellCol = nCellCol1; nCellCol <= nCellCol2; ++nCellCol )
+ {
+ aBorderItem.SetLine( (nCellCol == nCellCol1) ? pLeftLine : 0, BOX_LINE_LEFT );
+ aBorderItem.SetLine( (nCellCol == nCellCol2) ? pRightLine : 0, BOX_LINE_RIGHT );
+ for( SCROW nCellRow = nCellRow1; nCellRow <= nCellRow2; ++nCellRow )
+ {
+ aBorderItem.SetLine( (nCellRow == nCellRow1) ? pTopLine : 0, BOX_LINE_TOP );
+ aBorderItem.SetLine( (nCellRow == nCellRow2) ? pBottomLine : 0, BOX_LINE_BOTTOM );
+ pDoc->ApplyAttr( nCellCol, nCellRow, rFirstPos.Tab(), aBorderItem );
+ }
+ }
+ }
+ }
+ }
+
+ for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
+ aIter->ApplyCellBorders( pDoc, rFirstPos );
+}
+
+// ----------------------------------------------------------------------------
+
+bool ScHTMLTable::IsEmptyCell() const
+{
+ return mpCurrEntryList && mpCurrEntryList->empty();
+}
+
+bool ScHTMLTable::IsSpaceCharInfo( const ImportInfo& rInfo )
+{
+ return (rInfo.nToken == HTML_TEXTTOKEN) && (rInfo.aText.Len() == 1) && (rInfo.aText.GetChar( 0 ) == ' ');
+}
+
+ScHTMLTable::ScHTMLEntryPtr ScHTMLTable::CreateEntry() const
+{
+ return ScHTMLEntryPtr( new ScHTMLEntry( GetCurrItemSet() ) );
+}
+
+void ScHTMLTable::CreateNewEntry( const ImportInfo& rInfo )
+{
+ DBG_ASSERT( !mxCurrEntry.get(), "ScHTMLTable::CreateNewEntry - old entry still present" );
+ mxCurrEntry = CreateEntry();
+ mxCurrEntry->aSel = rInfo.aSelection;
+}
+
+void ScHTMLTable::ImplPushEntryToList( ScHTMLEntryList& rEntryList, ScHTMLEntryPtr& rxEntry )
+{
+ // HTML entry list does not own the entries
+ rEntryList.push_back( rxEntry.get() );
+ // mrEEParseList (reference to member of ScEEParser) owns the entries
+ mrEEParseList.Insert( rxEntry.release(), LIST_APPEND );
+}
+
+bool ScHTMLTable::PushEntry( ScHTMLEntryPtr& rxEntry )
+{
+ bool bPushed = false;
+ if( rxEntry.get() && rxEntry->HasContents() )
+ {
+ if( mpCurrEntryList )
+ {
+ if( mbPushEmptyLine )
+ {
+ ScHTMLEntryPtr xEmptyEntry = CreateEntry();
+ ImplPushEntryToList( *mpCurrEntryList, xEmptyEntry );
+ mbPushEmptyLine = false;
+ }
+ ImplPushEntryToList( *mpCurrEntryList, rxEntry );
+ bPushed = true;
+ }
+ else if( mpParentTable )
+ {
+ bPushed = mpParentTable->PushEntry( rxEntry );
+ }
+ else
+ {
+ DBG_ERRORFILE( "ScHTMLTable::PushEntry - cannot push entry, no parent found" );
+ }
+ }
+ return bPushed;
+}
+
+bool ScHTMLTable::PushEntry( const ImportInfo& rInfo, bool bLastInCell )
+{
+ DBG_ASSERT( mxCurrEntry.get(), "ScHTMLTable::PushEntry - no current entry" );
+ bool bPushed = false;
+ if( mxCurrEntry.get() )
+ {
+ mxCurrEntry->AdjustEnd( rInfo );
+ mxCurrEntry->Strip( mrEditEngine );
+
+ // import entry always, if it is the last in cell, and cell is still empty
+ if( bLastInCell && IsEmptyCell() )
+ {
+ mxCurrEntry->SetImportAlways();
+ // don't insert empty lines before single empty entries
+ if( mxCurrEntry->IsEmpty() )
+ mbPushEmptyLine = false;
+ }
+
+ bPushed = PushEntry( mxCurrEntry );
+ mxCurrEntry.reset();
+ }
+ return bPushed;
+}
+
+bool ScHTMLTable::PushTableEntry( ScHTMLTableId nTableId )
+{
+ DBG_ASSERT( nTableId != SC_HTML_GLOBAL_TABLE, "ScHTMLTable::PushTableEntry - cannot push global table" );
+ bool bPushed = false;
+ if( nTableId != SC_HTML_GLOBAL_TABLE )
+ {
+ ScHTMLEntryPtr xEntry( new ScHTMLEntry( maTableItemSet, nTableId ) );
+ bPushed = PushEntry( xEntry );
+ }
+ return bPushed;
+}
+
+ScHTMLTable* ScHTMLTable::GetExistingTable( ScHTMLTableId nTableId ) const
+{
+ ScHTMLTable* pTable = ((nTableId != SC_HTML_GLOBAL_TABLE) && mxNestedTables.get()) ?
+ mxNestedTables->FindTable( nTableId, false ) : 0;
+ DBG_ASSERT( pTable || (nTableId == SC_HTML_GLOBAL_TABLE), "ScHTMLTable::GetExistingTable - table not found" );
+ return pTable;
+}
+
+ScHTMLTable* ScHTMLTable::InsertNestedTable( const ImportInfo& rInfo, bool bPreFormText )
+{
+ if( !mxNestedTables.get() )
+ mxNestedTables.reset( new ScHTMLTableMap( *this ) );
+ if( bPreFormText ) // enclose new preformatted table with empty lines
+ InsertLeadingEmptyLine();
+ return mxNestedTables->CreateTable( rInfo, bPreFormText );
+}
+
+void ScHTMLTable::InsertNewCell( const ScHTMLSize& rSpanSize )
+{
+ ScRange* pRange;
+
+ /* Find an unused cell by skipping all merged ranges that cover the
+ current cell position stored in maCurrCell. */
+ while( ((pRange = maVMergedCells.Find( maCurrCell.MakeAddr() )) != 0) || ((pRange = maHMergedCells.Find( maCurrCell.MakeAddr() )) != 0) )
+ maCurrCell.mnCol = pRange->aEnd.Col() + 1;
+ mpCurrEntryList = &maEntryMap[ maCurrCell ];
+
+ /* If the new cell is merged horizontally, try to find collisions with
+ other vertically merged ranges. In this case, shrink existing
+ vertically merged ranges (do not shrink the new cell). */
+ SCCOL nColEnd = maCurrCell.mnCol + rSpanSize.mnCols;
+ for( ScAddress aAddr( maCurrCell.MakeAddr() ); aAddr.Col() < nColEnd; aAddr.IncCol() )
+ if( (pRange = maVMergedCells.Find( aAddr )) != 0 )
+ pRange->aEnd.SetRow( maCurrCell.mnRow - 1 );
+
+ // insert the new range into the cell lists
+ ScRange aNewRange( maCurrCell.MakeAddr() );
+ aNewRange.aEnd.Move( rSpanSize.mnCols - 1, rSpanSize.mnRows - 1, 0 );
+ if( rSpanSize.mnRows > 1 )
+ {
+ maVMergedCells.Append( aNewRange );
+ /* Do not insert vertically merged ranges into maUsedCells yet,
+ because they may be shrunken (see above). The final vertically
+ merged ranges are inserted in FillEmptyCells(). */
+ }
+ else
+ {
+ if( rSpanSize.mnCols > 1 )
+ maHMergedCells.Append( aNewRange );
+ /* Insert horizontally merged ranges and single cells into
+ maUsedCells, they will not be changed anymore. */
+ maUsedCells.Join( aNewRange );
+ }
+
+ // adjust table size
+ maSize.mnCols = ::std::max< SCCOL >( maSize.mnCols, aNewRange.aEnd.Col() + 1 );
+ maSize.mnRows = ::std::max< SCROW >( maSize.mnRows, aNewRange.aEnd.Row() + 1 );
+}
+
+void ScHTMLTable::ImplRowOn()
+{
+ if( mbRowOn )
+ ImplRowOff();
+ mxRowItemSet.reset( new SfxItemSet( maTableItemSet ) );
+ maCurrCell.mnCol = 0;
+ mbRowOn = true;
+ mbDataOn = false;
+}
+
+void ScHTMLTable::ImplRowOff()
+{
+ if( mbDataOn )
+ ImplDataOff();
+ if( mbRowOn )
+ {
+ mxRowItemSet.reset();
+ ++maCurrCell.mnRow;
+ mbRowOn = mbDataOn = false;
+ }
+}
+
+void ScHTMLTable::ImplDataOn( const ScHTMLSize& rSpanSize )
+{
+ if( mbDataOn )
+ ImplDataOff();
+ if( !mbRowOn )
+ ImplRowOn();
+ mxDataItemSet.reset( new SfxItemSet( *mxRowItemSet ) );
+ InsertNewCell( rSpanSize );
+ mbDataOn = true;
+ mbPushEmptyLine = false;
+}
+
+void ScHTMLTable::ImplDataOff()
+{
+ if( mbDataOn )
+ {
+ mxDataItemSet.reset();
+ ++maCurrCell.mnCol;
+ mpCurrEntryList = 0;
+ mbDataOn = false;
+ }
+}
+
+void ScHTMLTable::ProcessFormatOptions( SfxItemSet& rItemSet, const ImportInfo& rInfo )
+{
+ // special handling for table header cells
+ if( rInfo.nToken == HTML_TABLEHEADER_ON )
+ {
+ rItemSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ rItemSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
+ }
+
+ for( ScHTMLOptionIterator aIter( rInfo ); aIter.is(); ++aIter )
+ {
+ switch( aIter->GetToken() )
+ {
+ case HTML_O_ALIGN:
+ {
+ SvxCellHorJustify eVal = SVX_HOR_JUSTIFY_STANDARD;
+ const String& rOptVal = aIter->GetString();
+ if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) )
+ eVal = SVX_HOR_JUSTIFY_RIGHT;
+ else if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_center ) )
+ eVal = SVX_HOR_JUSTIFY_CENTER;
+ else if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_AL_left ) )
+ eVal = SVX_HOR_JUSTIFY_LEFT;
+ if( eVal != SVX_HOR_JUSTIFY_STANDARD )
+ rItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY ) );
+ }
+ break;
+
+ case HTML_O_VALIGN:
+ {
+ SvxCellVerJustify eVal = SVX_VER_JUSTIFY_STANDARD;
+ const String& rOptVal = aIter->GetString();
+ if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_top ) )
+ eVal = SVX_VER_JUSTIFY_TOP;
+ else if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
+ eVal = SVX_VER_JUSTIFY_CENTER;
+ else if( rOptVal.EqualsIgnoreCaseAscii( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
+ eVal = SVX_VER_JUSTIFY_BOTTOM;
+ if( eVal != SVX_VER_JUSTIFY_STANDARD )
+ rItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY ) );
+ }
+ break;
+
+ case HTML_O_BGCOLOR:
+ {
+ Color aColor;
+ aIter->GetColor( aColor );
+ rItemSet.Put( SvxBrushItem( aColor, ATTR_BACKGROUND ) );
+ }
+ break;
+ }
+ }
+}
+
+void ScHTMLTable::SetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nSize )
+{
+ DBG_ASSERT( nCellPos >= 0, "ScHTMLTable::SetDocSize - unexpected negative position" );
+ ScSizeVec& rSizes = maCumSizes[ eOrient ];
+ size_t nIndex = static_cast< size_t >( nCellPos );
+ // expand with height/width == 1
+ while( nIndex >= rSizes.size() )
+ rSizes.push_back( rSizes.empty() ? 1 : (rSizes.back() + 1) );
+ // update size of passed position and all following
+ // #i109987# only grow, don't shrink - use the largest needed size
+ SCsCOLROW nDiff = nSize - ((nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]));
+ if( nDiff > 0 )
+ for( ScSizeVec::iterator aIt = rSizes.begin() + nIndex, aEnd = rSizes.end(); aIt != aEnd; ++aIt )
+ *aIt += nDiff;
+}
+
+void ScHTMLTable::CalcNeededDocSize(
+ ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nCellSpan, SCCOLROW nRealDocSize )
+{
+ SCCOLROW nDiffSize = 0;
+ // in merged columns/rows: reduce needed size by size of leading columns
+ while( nCellSpan > 1 )
+ {
+ nDiffSize += GetDocSize( eOrient, nCellPos );
+ --nCellSpan;
+ ++nCellPos;
+ }
+ // set remaining needed size to last column/row
+ nRealDocSize -= ::std::min< SCCOLROW >( nRealDocSize - 1, nDiffSize );
+ SetDocSize( eOrient, nCellPos, nRealDocSize );
+}
+
+// ----------------------------------------------------------------------------
+
+void ScHTMLTable::FillEmptyCells()
+{
+ for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
+ aIter->FillEmptyCells();
+
+ // insert the final vertically merged ranges into maUsedCells
+ for( const ScRange* pRange = maVMergedCells.First(); pRange; pRange = maVMergedCells.Next() )
+ maUsedCells.Join( *pRange );
+
+ for( ScAddress aAddr; aAddr.Row() < maSize.mnRows; aAddr.IncRow() )
+ {
+ for( aAddr.SetCol( 0 ); aAddr.Col() < maSize.mnCols; aAddr.IncCol() )
+ {
+ if( !maUsedCells.Find( aAddr ) )
+ {
+ // create a range for the lock list (used to calc. cell span)
+ ScRange aRange( aAddr );
+ do
+ {
+ aRange.aEnd.IncCol();
+ }
+ while( (aRange.aEnd.Col() < maSize.mnCols) && !maUsedCells.Find( aRange.aEnd ) );
+ aRange.aEnd.IncCol( -1 );
+ maUsedCells.Join( aRange );
+
+ // insert a dummy entry
+ ScHTMLEntryPtr xEntry = CreateEntry();
+ ImplPushEntryToList( maEntryMap[ ScHTMLPos( aAddr ) ], xEntry );
+ }
+ }
+ }
+}
+
+void ScHTMLTable::RecalcDocSize()
+{
+ // recalc table sizes recursively from inner to outer
+ for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
+ aIter->RecalcDocSize();
+
+ /* Two passes: first calculates the sizes of single columns/rows, then
+ the sizes of spanned columns/rows. This allows to fill nested tables
+ into merged cells optimally. */
+ static const sal_uInt16 PASS_SINGLE = 0;
+ static const sal_uInt16 PASS_SPANNED = 1;
+ for( sal_uInt16 nPass = PASS_SINGLE; nPass <= PASS_SPANNED; ++nPass )
+ {
+ // iterate through every table cell
+ ScHTMLEntryMap::const_iterator aMapIterEnd = maEntryMap.end();
+ for( ScHTMLEntryMap::const_iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
+ {
+ const ScHTMLPos& rCellPos = aMapIter->first;
+ ScHTMLSize aCellSpan = GetSpan( rCellPos );
+
+ const ScHTMLEntryList& rEntryList = aMapIter->second;
+ ScHTMLEntryList::const_iterator aListIter;
+ ScHTMLEntryList::const_iterator aListIterEnd = rEntryList.end();
+
+ // process the dimension of the current cell in this pass?
+ // (pass is single and span is 1) or (pass is not single and span is not 1)
+ bool bProcessColWidth = ((nPass == PASS_SINGLE) == (aCellSpan.mnCols == 1));
+ bool bProcessRowHeight = ((nPass == PASS_SINGLE) == (aCellSpan.mnRows == 1));
+ if( bProcessColWidth || bProcessRowHeight )
+ {
+ ScHTMLSize aDocSize( 1, 0 ); // resulting size of the cell in document
+
+ // expand the cell size for each cell parse entry
+ for( aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
+ {
+ ScHTMLTable* pTable = GetExistingTable( (*aListIter)->GetTableId() );
+ // find entry with maximum width
+ if( bProcessColWidth && pTable )
+ aDocSize.mnCols = ::std::max( aDocSize.mnCols, static_cast< SCCOL >( pTable->GetDocSize( tdCol ) ) );
+ // add up height of each entry
+ if( bProcessRowHeight )
+ aDocSize.mnRows += pTable ? pTable->GetDocSize( tdRow ) : 1;
+ }
+ if( !aDocSize.mnRows )
+ aDocSize.mnRows = 1;
+
+ if( bProcessColWidth )
+ CalcNeededDocSize( tdCol, rCellPos.mnCol, aCellSpan.mnCols, aDocSize.mnCols );
+ if( bProcessRowHeight )
+ CalcNeededDocSize( tdRow, rCellPos.mnRow, aCellSpan.mnRows, aDocSize.mnRows );
+ }
+ }
+ }
+}
+
+void ScHTMLTable::RecalcDocPos( const ScHTMLPos& rBasePos )
+{
+ maDocBasePos = rBasePos;
+ // after the previous assignment it is allowed to call GetDocPos() methods
+
+ // iterate through every table cell
+ ScHTMLEntryMap::iterator aMapIterEnd = maEntryMap.end();
+ for( ScHTMLEntryMap::iterator aMapIter = maEntryMap.begin(); aMapIter != aMapIterEnd; ++aMapIter )
+ {
+ // fixed doc position of the entire cell (first entry)
+ const ScHTMLPos aCellDocPos( GetDocPos( aMapIter->first ) );
+ // fixed doc size of the entire cell
+ const ScHTMLSize aCellDocSize( GetDocSize( aMapIter->first ) );
+
+ // running doc position for single entries
+ ScHTMLPos aEntryDocPos( aCellDocPos );
+
+ ScHTMLEntryList& rEntryList = aMapIter->second;
+ ScHTMLEntry* pEntry = 0;
+ ScHTMLEntryList::iterator aListIterEnd = rEntryList.end();
+ for( ScHTMLEntryList::iterator aListIter = rEntryList.begin(); aListIter != aListIterEnd; ++aListIter )
+ {
+ pEntry = *aListIter;
+ if( ScHTMLTable* pTable = GetExistingTable( pEntry->GetTableId() ) )
+ {
+ pTable->RecalcDocPos( aEntryDocPos ); // recalc nested table
+ pEntry->nCol = SCCOL_MAX;
+ pEntry->nRow = SCROW_MAX;
+ SCROW nTableRows = static_cast< SCROW >( pTable->GetDocSize( tdRow ) );
+
+ // use this entry to pad empty space right of table
+ if( mpParentTable ) // ... but not in global table
+ {
+ SCCOL nStartCol = aEntryDocPos.mnCol + static_cast< SCCOL >( pTable->GetDocSize( tdCol ) );
+ SCCOL nNextCol = aEntryDocPos.mnCol + aCellDocSize.mnCols;
+ if( nStartCol < nNextCol )
+ {
+ pEntry->nCol = nStartCol;
+ pEntry->nRow = aEntryDocPos.mnRow;
+ pEntry->nColOverlap = nNextCol - nStartCol;
+ pEntry->nRowOverlap = nTableRows;
+ }
+ }
+ aEntryDocPos.mnRow += nTableRows;
+ }
+ else
+ {
+ pEntry->nCol = aEntryDocPos.mnCol;
+ pEntry->nRow = aEntryDocPos.mnRow;
+ if( mpParentTable ) // do not merge in global table
+ pEntry->nColOverlap = aCellDocSize.mnCols;
+ ++aEntryDocPos.mnRow;
+ }
+ }
+
+ // pEntry points now to last entry.
+ if( pEntry )
+ {
+ if( (pEntry == rEntryList.front()) && (pEntry->GetTableId() == SC_HTML_NO_TABLE) )
+ {
+ // pEntry is the only entry in this cell - merge rows of cell with single non-table entry.
+ pEntry->nRowOverlap = aCellDocSize.mnRows;
+ }
+ else
+ {
+ // #111667# fill up incomplete entry lists
+ SCROW nFirstUnusedRow = aCellDocPos.mnRow + aCellDocSize.mnRows;
+ while( aEntryDocPos.mnRow < nFirstUnusedRow )
+ {
+ ScHTMLEntryPtr xDummyEntry( new ScHTMLEntry( pEntry->GetItemSet() ) );
+ xDummyEntry->nCol = aEntryDocPos.mnCol;
+ xDummyEntry->nRow = aEntryDocPos.mnRow;
+ xDummyEntry->nColOverlap = aCellDocSize.mnCols;
+ ImplPushEntryToList( rEntryList, xDummyEntry );
+ ++aEntryDocPos.mnRow;
+ }
+ }
+ }
+ }
+}
+
+// ============================================================================
+
+ScHTMLGlobalTable::ScHTMLGlobalTable( SfxItemPool& rPool, EditEngine& rEditEngine, ScEEParseList& rEEParseList, ScHTMLTableId& rnUnusedId ) :
+ ScHTMLTable( rPool, rEditEngine, rEEParseList, rnUnusedId )
+{
+}
+
+ScHTMLGlobalTable::~ScHTMLGlobalTable()
+{
+}
+
+void ScHTMLGlobalTable::Recalc()
+{
+ // Fills up empty cells with a dummy entry. */
+ FillEmptyCells();
+ // recalc table sizes of all nested tables and this table
+ RecalcDocSize();
+ // recalc document positions of all entries in this table and in nested tables
+ RecalcDocPos( GetDocPos() );
+}
+
+// ============================================================================
+
+ScHTMLQueryParser::ScHTMLQueryParser( EditEngine* pEditEngine, ScDocument* pDoc ) :
+ ScHTMLParser( pEditEngine, pDoc ),
+ mnUnusedId( SC_HTML_GLOBAL_TABLE ),
+ mbTitleOn( false )
+{
+ mxGlobTable.reset( new ScHTMLGlobalTable( *pPool, *pEdit, *pList, mnUnusedId ) );
+ mpCurrTable = mxGlobTable.get();
+}
+
+ScHTMLQueryParser::~ScHTMLQueryParser()
+{
+}
+
+ULONG ScHTMLQueryParser::Read( SvStream& rStrm, const String& rBaseURL )
+{
+ SvKeyValueIteratorRef xValues;
+ SvKeyValueIterator* pAttributes = 0;
+
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if( pObjSh && pObjSh->IsLoading() )
+ {
+ pAttributes = pObjSh->GetHeaderAttributes();
+ }
+ else
+ {
+ /* When not loading, set up fake HTTP headers to force the SfxHTMLParser
+ to use UTF8 (used when pasting from clipboard) */
+ const sal_Char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
+ if( pCharSet )
+ {
+ String aContentType = String::CreateFromAscii( "text/html; charset=" );
+ aContentType.AppendAscii( pCharSet );
+
+ xValues = new SvKeyValueIterator;
+ xValues->Append( SvKeyValue( String::CreateFromAscii( OOO_STRING_SVTOOLS_HTML_META_content_type ), aContentType ) );
+ pAttributes = xValues;
+ }
+ }
+
+ Link aOldLink = pEdit->GetImportHdl();
+ pEdit->SetImportHdl( LINK( this, ScHTMLQueryParser, HTMLImportHdl ) );
+ ULONG nErr = pEdit->Read( rStrm, rBaseURL, EE_FORMAT_HTML, pAttributes );
+ pEdit->SetImportHdl( aOldLink );
+
+ mxGlobTable->Recalc();
+ nColMax = static_cast< SCCOL >( mxGlobTable->GetDocSize( tdCol ) - 1 );
+ nRowMax = static_cast< SCROW >( mxGlobTable->GetDocSize( tdRow ) - 1 );
+
+ return nErr;
+}
+
+const ScHTMLTable* ScHTMLQueryParser::GetGlobalTable() const
+{
+ return mxGlobTable.get();
+}
+
+void ScHTMLQueryParser::ProcessToken( const ImportInfo& rInfo )
+{
+ switch( rInfo.nToken )
+ {
+// --- meta data ---
+ case HTML_META: MetaOn( rInfo ); break; // <meta>
+
+// --- title handling ---
+ case HTML_TITLE_ON: TitleOn( rInfo ); break; // <title>
+ case HTML_TITLE_OFF: TitleOff( rInfo ); break; // </title>
+
+// --- body handling ---
+ case HTML_BODY_ON: mpCurrTable->BodyOn( rInfo ); break; // <body>
+ case HTML_BODY_OFF: mpCurrTable->BodyOff( rInfo ); break; // </body>
+
+// --- insert text ---
+ case HTML_TEXTTOKEN: InsertText( rInfo ); break; // any text
+ case HTML_LINEBREAK: mpCurrTable->BreakOn(); break; // <br>
+ case HTML_HEAD1_ON: // <h1>
+ case HTML_HEAD2_ON: // <h2>
+ case HTML_HEAD3_ON: // <h3>
+ case HTML_HEAD4_ON: // <h4>
+ case HTML_HEAD5_ON: // <h5>
+ case HTML_HEAD6_ON: // <h6>
+ case HTML_PARABREAK_ON: mpCurrTable->HeadingOn(); break; // <p>
+
+// --- misc. contents ---
+ case HTML_ANCHOR_ON: mpCurrTable->AnchorOn(); break; // <a>
+
+// --- table handling ---
+ case HTML_TABLE_ON: TableOn( rInfo ); break; // <table>
+ case HTML_TABLE_OFF: TableOff( rInfo ); break; // </table>
+ case HTML_TABLEROW_ON: mpCurrTable->RowOn( rInfo ); break; // <tr>
+ case HTML_TABLEROW_OFF: mpCurrTable->RowOff( rInfo ); break; // </tr>
+ case HTML_TABLEHEADER_ON: // <th>
+ case HTML_TABLEDATA_ON: mpCurrTable->DataOn( rInfo ); break; // <td>
+ case HTML_TABLEHEADER_OFF: // </th>
+ case HTML_TABLEDATA_OFF: mpCurrTable->DataOff( rInfo ); break; // </td>
+ case HTML_PREFORMTXT_ON: PreOn( rInfo ); break; // <pre>
+ case HTML_PREFORMTXT_OFF: PreOff( rInfo ); break; // </pre>
+
+// --- formatting ---
+ case HTML_FONT_ON: FontOn( rInfo ); break; // <font>
+
+ case HTML_BIGPRINT_ON: // <big>
+ //! TODO: store current font size, use following size
+ mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 3 ], 100, ATTR_FONT_HEIGHT ) );
+ break;
+ case HTML_SMALLPRINT_ON: // <small>
+ //! TODO: store current font size, use preceding size
+ mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ 0 ], 100, ATTR_FONT_HEIGHT ) );
+ break;
+
+ case HTML_BOLD_ON: // <b>
+ case HTML_STRONG_ON: // <strong>
+ mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ break;
+
+ case HTML_ITALIC_ON: // <i>
+ case HTML_EMPHASIS_ON: // <em>
+ case HTML_ADDRESS_ON: // <address>
+ case HTML_BLOCKQUOTE_ON: // <blockquote>
+ case HTML_BLOCKQUOTE30_ON: // <bq>
+ case HTML_CITIATION_ON: // <cite>
+ case HTML_VARIABLE_ON: // <var>
+ mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
+ break;
+
+ case HTML_DEFINSTANCE_ON: // <dfn>
+ mpCurrTable->PutItem( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ mpCurrTable->PutItem( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
+ break;
+
+ case HTML_UNDERLINE_ON: // <u>
+ mpCurrTable->PutItem( SvxUnderlineItem( UNDERLINE_SINGLE, ATTR_FONT_UNDERLINE ) );
+ break;
+ }
+}
+
+void ScHTMLQueryParser::InsertText( const ImportInfo& rInfo )
+{
+ mpCurrTable->PutText( rInfo );
+ if( mbTitleOn )
+ maTitle.Append( rInfo.aText );
+}
+
+void ScHTMLQueryParser::FontOn( const ImportInfo& rInfo )
+{
+ for( ScHTMLOptionIterator aIter( rInfo ); aIter.is(); ++aIter )
+ {
+ switch( aIter->GetToken() )
+ {
+ case HTML_O_FACE :
+ {
+ const String& rFace = aIter->GetString();
+ String aFontName;
+ xub_StrLen nPos = 0;
+ while( nPos != STRING_NOTFOUND )
+ {
+ // font list separator: VCL = ';' HTML = ','
+ String aFName = rFace.GetToken( 0, ',', nPos );
+ aFName.EraseLeadingAndTrailingChars();
+ ScGlobal::AddToken( aFontName, aFName, ';' );
+ }
+ if ( aFontName.Len() )
+ mpCurrTable->PutItem( SvxFontItem( FAMILY_DONTKNOW,
+ aFontName, EMPTY_STRING, PITCH_DONTKNOW,
+ RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
+ }
+ break;
+ case HTML_O_SIZE :
+ {
+ sal_uInt32 nSize = getLimitedValue< sal_uInt32 >( aIter->GetNumber(), 1, SC_HTML_FONTSIZES );
+ mpCurrTable->PutItem( SvxFontHeightItem( maFontHeights[ nSize - 1 ], 100, ATTR_FONT_HEIGHT ) );
+ }
+ break;
+ case HTML_O_COLOR :
+ {
+ Color aColor;
+ aIter->GetColor( aColor );
+ mpCurrTable->PutItem( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
+ }
+ break;
+ }
+ }
+}
+
+void ScHTMLQueryParser::MetaOn( const ImportInfo& rInfo )
+{
+ if( mpDoc->GetDocumentShell() )
+ {
+ HTMLParser* pParser = static_cast< HTMLParser* >( rInfo.pParser );
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
+ pParser->ParseMetaOptions(
+ xDPS->getDocumentProperties(),
+ mpDoc->GetDocumentShell()->GetHeaderAttributes() );
+ }
+}
+
+void ScHTMLQueryParser::TitleOn( const ImportInfo& /*rInfo*/ )
+{
+ mbTitleOn = true;
+ maTitle.Erase();
+}
+
+void ScHTMLQueryParser::TitleOff( const ImportInfo& rInfo )
+{
+ if( mbTitleOn )
+ {
+ maTitle.EraseLeadingAndTrailingChars();
+ if( maTitle.Len() && mpDoc->GetDocumentShell() ) {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
+
+ xDPS->getDocumentProperties()->setTitle(maTitle);
+ }
+ InsertText( rInfo );
+ mbTitleOn = false;
+ }
+}
+
+void ScHTMLQueryParser::TableOn( const ImportInfo& rInfo )
+{
+ mpCurrTable = mpCurrTable->TableOn( rInfo );
+}
+
+void ScHTMLQueryParser::TableOff( const ImportInfo& rInfo )
+{
+ mpCurrTable = mpCurrTable->TableOff( rInfo );
+}
+
+void ScHTMLQueryParser::PreOn( const ImportInfo& rInfo )
+{
+ mpCurrTable = mpCurrTable->PreOn( rInfo );
+}
+
+void ScHTMLQueryParser::PreOff( const ImportInfo& rInfo )
+{
+ mpCurrTable = mpCurrTable->PreOff( rInfo );
+}
+
+void ScHTMLQueryParser::CloseTable( const ImportInfo& rInfo )
+{
+ mpCurrTable = mpCurrTable->CloseTable( rInfo );
+}
+
+// ----------------------------------------------------------------------------
+
+IMPL_LINK( ScHTMLQueryParser, HTMLImportHdl, const ImportInfo*, pInfo )
+{
+ switch( pInfo->eState )
+ {
+ case HTMLIMP_START:
+ break;
+
+ case HTMLIMP_NEXTTOKEN:
+ case HTMLIMP_UNKNOWNATTR:
+ ProcessToken( *pInfo );
+ break;
+
+ case HTMLIMP_INSERTPARA:
+ mpCurrTable->InsertPara( *pInfo );
+ break;
+
+ case HTMLIMP_SETATTR:
+ case HTMLIMP_INSERTTEXT:
+ case HTMLIMP_INSERTFIELD:
+ break;
+
+ case HTMLIMP_END:
+ while( mpCurrTable->GetTableId() != SC_HTML_GLOBAL_TABLE )
+ CloseTable( *pInfo );
+ break;
+
+ default:
+ DBG_ERRORFILE( "ScHTMLQueryParser::HTMLImportHdl - unknown ImportInfo::eState" );
+ }
+ return 0;
+}
+
+// ============================================================================
+