summaryrefslogtreecommitdiff
path: root/sw/source/filter/html/htmltab.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/html/htmltab.cxx')
-rw-r--r--sw/source/filter/html/htmltab.cxx6187
1 files changed, 6187 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx
new file mode 100644
index 000000000000..4b1f09167f6d
--- /dev/null
+++ b/sw/source/filter/html/htmltab.cxx
@@ -0,0 +1,6187 @@
+/*************************************************************************
+ *
+ * $RCSfile: htmltab.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 17:14:56 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+//#define TEST_RESIZE
+
+#ifdef PRECOMPILED
+#include "filt_pch.hxx"
+#endif
+
+#pragma hdrstop
+
+#include "hintids.hxx"
+
+#ifndef _SV_SVAPP_HXX //autogen
+#include <vcl/svapp.hxx>
+#endif
+#ifndef _WRKWIN_HXX //autogen
+#include <vcl/wrkwin.hxx>
+#endif
+#ifndef _SVX_BOXITEM_HXX //autogen
+#define ITEMID_BOXINFO SID_ATTR_BORDER_INNER
+#include <svx/boxitem.hxx>
+#endif
+#ifndef _SVX_BRSHITEM_HXX //autogen
+#include <svx/brshitem.hxx>
+#endif
+#ifndef _SVX_ADJITEM_HXX //autogen
+#include <svx/adjitem.hxx>
+#endif
+#ifndef _SVX_FHGTITEM_HXX //autogen
+#include <svx/fhgtitem.hxx>
+#endif
+#ifndef _SVX_ULSPITEM_HXX //autogen
+#include <svx/ulspitem.hxx>
+#endif
+#ifndef _SVX_LRSPITEM_HXX //autogen
+#include <svx/lrspitem.hxx>
+#endif
+#ifndef _SVX_BRKITEM_HXX //autogen
+#include <svx/brkitem.hxx>
+#endif
+#ifndef _SVX_SPLTITEM_HXX //autogen
+#include <svx/spltitem.hxx>
+#endif
+#ifndef _HTMLTOKN_H
+#include <svtools/htmltokn.h>
+#endif
+#ifndef _HTMLKYWD_HXX
+#include <svtools/htmlkywd.hxx>
+#endif
+
+
+#ifndef _FMTORNT_HXX //autogen
+#include <fmtornt.hxx>
+#endif
+#ifndef _FRMFMT_HXX //autogen
+#include <frmfmt.hxx>
+#endif
+#ifndef _FMTFSIZE_HXX //autogen
+#include <fmtfsize.hxx>
+#endif
+#ifndef _FMTSRND_HXX //autogen
+#include <fmtsrnd.hxx>
+#endif
+#ifndef _FMTPDSC_HXX //autogen
+#include <fmtpdsc.hxx>
+#endif
+#ifndef _FMTCNTNT_HXX //autogen
+#include <fmtcntnt.hxx>
+#endif
+#ifndef _FMTANCHR_HXX //autogen
+#include <fmtanchr.hxx>
+#endif
+#ifndef _FMTTSPLT_HXX //autogen
+#include <fmtlsplt.hxx>
+#endif
+#ifndef _FRMATR_HXX
+#include "frmatr.hxx"
+#endif
+#include "pam.hxx"
+#include "doc.hxx"
+#include "ndtxt.hxx"
+#include "shellio.hxx"
+#include "poolfmt.hxx"
+#include "swtable.hxx"
+#include "cellatr.hxx"
+#ifdef TEST_RESIZE
+#include "viewsh.hxx"
+#endif
+#include "htmltbl.hxx"
+#include "swtblfmt.hxx"
+#include "htmlnum.hxx"
+#include "swhtml.hxx"
+#include "swcss1.hxx"
+
+#define NETSCAPE_DFLT_BORDER 1
+#define NETSCAPE_DFLT_CELLPADDING 1
+#define NETSCAPE_DFLT_CELLSPACING 2
+
+//#define FIX56334
+
+static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] =
+{
+ { sHTML_VA_top, VERT_NONE },
+ { sHTML_VA_middle, VERT_CENTER },
+ { sHTML_VA_bottom, VERT_BOTTOM },
+ { 0, 0 }
+};
+
+
+/* */
+
+// Die Optionen eines Table-Tags
+
+struct HTMLTableOptions
+{
+ sal_uInt16 nCols;
+ sal_uInt16 nWidth;
+ sal_uInt16 nHeight;
+ sal_uInt16 nCellPadding;
+ sal_uInt16 nCellSpacing;
+ sal_uInt16 nBorder;
+ sal_uInt16 nHSpace;
+ sal_uInt16 nVSpace;
+
+ SvxAdjust eAdjust;
+ SwVertOrient eVertOri;
+ HTMLTableFrame eFrame;
+ HTMLTableRules eRules;
+
+ sal_Bool bPrcWidth : 1;
+ sal_Bool bTableAdjust : 1;
+ sal_Bool bBGColor : 1;
+
+ Color aBorderColor;
+ Color aBGColor;
+
+ String aBGImage, aStyle, aId, aClass;
+
+ HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust );
+};
+
+/* */
+
+class _HTMLTableContext
+{
+ SwHTMLNumRuleInfo aNumRuleInfo; // Vor der Tabelle gueltige Numerierung
+
+ SwTableNode *pTblNd; // der Tabellen-Node
+ SwFrmFmt *pFrmFmt; // der Fly ::com::sun::star::frame::Frame, in dem die Tabelle steht
+ SwPosition *pPos; // die Position hinter der Tabelle
+
+ sal_uInt16 nContextStAttrMin;
+ sal_uInt16 nContextStMin;
+
+ sal_Bool bRestartPRE : 1;
+ sal_Bool bRestartXMP : 1;
+ sal_Bool bRestartListing : 1;
+
+public:
+
+ _HTMLAttrTable aAttrTab; // und die Attribute
+
+ _HTMLTableContext( SwPosition *pPs, sal_uInt16 nCntxtStMin,
+ sal_uInt16 nCntxtStAttrMin ) :
+ pTblNd( 0 ), pFrmFmt( 0 ), pPos( pPs ),
+ nContextStMin( nCntxtStMin ), nContextStAttrMin( nCntxtStAttrMin ),
+ bRestartPRE( sal_False ), bRestartXMP( sal_False ), bRestartListing( sal_False )
+ {
+ memset( &aAttrTab, 0, sizeof( _HTMLAttrTable ));
+ }
+
+ ~_HTMLTableContext();
+
+ void SetNumInfo( const SwHTMLNumRuleInfo& rInf ) { aNumRuleInfo.Set(rInf); }
+ const SwHTMLNumRuleInfo& GetNumInfo() const { return aNumRuleInfo; };
+
+ void SavePREListingXMP( SwHTMLParser& rParser );
+ void RestorePREListingXMP( SwHTMLParser& rParser );
+
+ SwPosition *GetPos() const { return pPos; }
+
+ void SetTableNode( SwTableNode *pNd ) { pTblNd = pNd; }
+ SwTableNode *GetTableNode() const { return pTblNd; }
+
+ void SetFrmFmt( SwFrmFmt *pFmt ) { pFrmFmt = pFmt; }
+ SwFrmFmt *GetFrmFmt() const { return pFrmFmt; }
+
+ sal_uInt16 GetContextStMin() const { return nContextStMin; }
+ sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMin; }
+};
+
+/* */
+
+// der Inhalt einer Zelle ist eine verkettete Liste mit SwStartNodes und
+// HTMLTables.
+
+class HTMLTableCnts
+{
+ HTMLTableCnts *pNext; // der naechste Inhalt
+
+ // von den beiden naechsten Pointern darf nur einer gesetzt sein!
+ const SwStartNode *pStartNode; // ein Abastz
+ HTMLTable *pTable; // eine Tabelle
+
+ SwHTMLTableLayoutCnts* pLayoutInfo;
+
+ sal_Bool bNoBreak;
+
+ void InitCtor();
+
+public:
+
+ HTMLTableCnts( const SwStartNode* pStNd );
+ HTMLTableCnts( HTMLTable* pTab );
+
+ ~HTMLTableCnts(); // nur in ~HTMLTableCell erlaubt
+
+ // Ermitteln des SwStartNode bzw. der HTMLTable
+ const SwStartNode *GetStartNode() const { return pStartNode; }
+ const HTMLTable *GetTable() const { return pTable; }
+ HTMLTable *GetTable() { return pTable; }
+
+ // hinzufuegen eines neuen Knotens am Listenende
+ void Add( HTMLTableCnts* pNewCnts );
+
+ // Ermitteln des naechsten Knotens
+ const HTMLTableCnts *Next() const { return pNext; }
+ HTMLTableCnts *Next() { return pNext; }
+
+ inline void SetTableBox( SwTableBox *pBox );
+
+ void SetNoBreak() { bNoBreak = sal_True; }
+
+ SwHTMLTableLayoutCnts *CreateLayoutInfo();
+};
+
+/* */
+
+// Eine Zelle der HTML-Tabelle
+
+class HTMLTableCell
+{
+ // !!!ACHTUNG!!!!! Fuer jeden neuen Pointer muss die SetProtected-
+ // Methode (und natuerlich der Destruktor) bearbeitet werden.
+ HTMLTableCnts *pContents; // der Inhalt der Zelle
+ SvxBrushItem *pBGBrush; // Hintergrund der Zelle
+ // !!!ACHTUNG!!!!!
+
+ sal_uInt32 nNumFmt;
+ sal_uInt16 nRowSpan; // ROWSPAN der Zelle
+ sal_uInt16 nColSpan; // COLSPAN der Zelle
+ sal_uInt16 nWidth; // WIDTH der Zelle
+ double nValue;
+ SwVertOrient eVertOri; // vertikale Ausrichtung der Zelle
+ sal_Bool bProtected : 1; // Zelle darf nicht belegt werden
+ sal_Bool bRelWidth : 1; // nWidth ist %-Angabe
+ sal_Bool bHasNumFmt : 1;
+ sal_Bool bHasValue : 1;
+ sal_Bool bNoWrap : 1;
+
+public:
+
+ HTMLTableCell(); // neue Zellen sind immer leer
+
+ ~HTMLTableCell(); // nur in ~HTMLTableRow erlaubt
+
+ // Belegen einer nicht-leeren Zelle
+ void Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
+ SwVertOrient eVertOri, SvxBrushItem *pBGBrush,
+ sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
+ sal_Bool bHasValue, double nValue, sal_Bool bNoWrap );
+
+ // Schuetzen einer leeren 1x1-Zelle
+ void SetProtected();
+
+ // Setzen/Ermitteln des Inhalts einer Zelle
+ void SetContents( HTMLTableCnts *pCnts ) { pContents = pCnts; }
+ const HTMLTableCnts *GetContents() const { return pContents; }
+ HTMLTableCnts *GetContents() { return pContents; }
+
+ // ROWSPAN/COLSPAN der Zelle Setzen/Ermitteln
+ void SetRowSpan( sal_uInt16 nRSpan ) { nRowSpan = nRSpan; }
+ sal_uInt16 GetRowSpan() const { return nRowSpan; }
+
+ void SetColSpan( sal_uInt16 nCSpan ) { nColSpan = nCSpan; }
+ sal_uInt16 GetColSpan() const { return nColSpan; }
+
+ inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth );
+
+ const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
+
+ inline sal_Bool GetNumFmt( sal_uInt32& rNumFmt ) const;
+ inline sal_Bool GetValue( double& rValue ) const;
+
+ SwVertOrient GetVertOri() const { return eVertOri; }
+
+ // Ist die Zelle belegt oder geschuetzt?
+ sal_Bool IsUsed() const { return pContents!=0 || bProtected; }
+
+ SwHTMLTableLayoutCell *CreateLayoutInfo();
+};
+
+/* */
+
+// Eine Zeile der HTML-Tabelle
+
+typedef HTMLTableCell* HTMLTableCellPtr;
+SV_DECL_PTRARR_DEL(HTMLTableCells,HTMLTableCellPtr,5,5)
+
+class HTMLTableRow
+{
+ HTMLTableCells *pCells; // die Zellen der Zeile
+
+ sal_Bool bIsEndOfGroup : 1;
+ sal_Bool bSplitable : 1;
+
+ sal_uInt16 nHeight; // Optionen von <TR>/<TD>
+ sal_uInt16 nEmptyRows; // wieviele Leere Zeilen folgen
+
+ SvxAdjust eAdjust;
+ SwVertOrient eVertOri;
+ SvxBrushItem *pBGBrush; // Hintergrund der Zelle aus STYLE
+
+public:
+
+ sal_Bool bBottomBorder; // kommt hinter der Zeile eine Linie?
+
+ HTMLTableRow( sal_uInt16 nCells=0 ); // die Zellen der Zeile sind leer
+
+ ~HTMLTableRow();
+
+ inline void SetHeight( sal_uInt16 nHeight );
+ sal_uInt16 GetHeight() const { return nHeight; }
+
+ // Ermitteln einer Zelle
+ inline HTMLTableCell *GetCell( sal_uInt16 nCell ) const;
+ inline const HTMLTableCells *GetCells() const { return pCells; }
+
+
+ inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
+ inline SvxAdjust GetAdjust() const { return eAdjust; }
+
+ inline void SetVertOri( SwVertOrient eV) { eVertOri = eV; }
+ inline SwVertOrient GetVertOri() const { return eVertOri; }
+
+ void SetBGBrush( SvxBrushItem *pBrush ) { pBGBrush = pBrush; }
+ const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
+
+ inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
+ inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
+
+ void IncEmptyRows() { nEmptyRows++; }
+ sal_uInt16 GetEmptyRows() const { return nEmptyRows; }
+
+ // Expandieren einer Zeile durch hinzufuegen leerer Zellen
+ void Expand( sal_uInt16 nCells, sal_Bool bOneCell=sal_False );
+
+ // Verkuerzen einer Zeile durch loesen von leeren Zellen
+ void Shrink( sal_uInt16 nCells );
+
+ void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
+ sal_Bool IsSplitable() const { return bSplitable; }
+};
+
+/* */
+
+// Eine Spalte der HTML-Tabelle
+
+class HTMLTableColumn
+{
+ sal_Bool bIsEndOfGroup;
+
+ sal_uInt16 nWidth; // Optionen von <COL>
+ sal_Bool bRelWidth;
+
+ SvxAdjust eAdjust;
+ SwVertOrient eVertOri;
+
+ SwFrmFmt *aFrmFmts[6];
+
+ inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine,
+ SwVertOrient eVertOri ) const;
+
+public:
+
+ sal_Bool bLeftBorder; // kommt vor der Spalte eine Linie
+
+ HTMLTableColumn();
+
+ inline void SetWidth( sal_uInt16 nWidth, sal_Bool bRelWidth);
+
+ inline void SetAdjust( SvxAdjust eAdj ) { eAdjust = eAdj; }
+ inline SvxAdjust GetAdjust() const { return eAdjust; }
+
+ inline void SetVertOri( SwVertOrient eV) { eVertOri = eV; }
+ inline SwVertOrient GetVertOri() const { return eVertOri; }
+
+ inline void SetEndOfGroup() { bIsEndOfGroup = sal_True; }
+ inline sal_Bool IsEndOfGroup() const { return bIsEndOfGroup; }
+
+ inline void SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
+ SwVertOrient eVertOri );
+ inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine,
+ SwVertOrient eVertOri ) const;
+
+ SwHTMLTableLayoutColumn *CreateLayoutInfo();
+};
+
+/* */
+
+// eine HTML-Tabelle
+
+typedef HTMLTableRow* HTMLTableRowPtr;
+SV_DECL_PTRARR_DEL(HTMLTableRows,HTMLTableRowPtr,5,5)
+
+typedef HTMLTableColumn* HTMLTableColumnPtr;
+SV_DECL_PTRARR_DEL(HTMLTableColumns,HTMLTableColumnPtr,5,5)
+
+SV_DECL_PTRARR(SdrObjects,SdrObject *,1,1)
+
+class HTMLTable
+{
+ String aId;
+ String aStyle;
+ String aClass;
+
+ SdrObjects *pResizeDrawObjs;// SDR-Objekte
+ SvUShorts *pDrawObjPrcWidths; // Spalte des Zeichen-Objekts und dessen
+ // relative Breite
+
+ HTMLTableRows *pRows; // die Zeilen der Tabelle
+ HTMLTableColumns *pColumns; // die Spalten der Tabelle
+
+ sal_uInt16 nRows; // Anzahl Zeilen
+ sal_uInt16 nCols; // Anzahl Spalten
+ sal_uInt16 nFilledCols; // Anzahl tatsaechlich gefuellter Spalten
+
+ sal_uInt16 nCurRow; // aktuelle Zeile
+ sal_uInt16 nCurCol; // aktuelle Spalte
+
+ sal_uInt16 nLeftMargin; // Abstand zum linken Rand (aus Absatz)
+ sal_uInt16 nRightMargin; // Abstand zum rechten Rand (aus Absatz)
+
+ sal_uInt16 nCellPadding; // Abstand Umrandung zum Text
+ sal_uInt16 nCellSpacing; // Abstand zwischen zwei Zellen
+ sal_uInt16 nHSpace;
+ sal_uInt16 nVSpace;
+
+ sal_uInt16 nBoxes; // Wievele Boxen enthaelt die Tabelle
+
+ const SwStartNode *pPrevStNd; // der Table-Node oder der Start-Node
+ // der vorhergehenden Section
+ const SwTable *pSwTable; // die SW-Tabelle (nur auf dem Top-Level)
+ SwTableBox *pBox1; // die TableBox, die beim Erstellen
+ // der Top-Level-Tabelle angelegt wird
+
+ SwTableBoxFmt *pBoxFmt; // das ::com::sun::star::frame::Frame-Format einer SwTableBox
+ SwTableLineFmt *pLineFmt; // das ::com::sun::star::frame::Frame-Format einer SwTableLine
+ SwTableLineFmt *pLineFrmFmtNoHeight;
+ SvxBrushItem *pBGBrush; // Hintergrund der Tabelle
+ SvxBrushItem *pInhBGBrush; // "geerbter" Hintergrund der Tabelle
+ const SwStartNode *pCaptionStartNode; // Start-Node der Tabellen-Ueberschrift
+
+ SvxBorderLine aTopBorderLine; // die Linie fuer die Umrandung
+ SvxBorderLine aBottomBorderLine;// die Linie fuer die Umrandung
+ SvxBorderLine aLeftBorderLine; // die Linie fuer die Umrandung
+ SvxBorderLine aRightBorderLine; // die Linie fuer die Umrandung
+ SvxBorderLine aBorderLine; // die Linie fuer die Umrandung
+ SvxBorderLine aInhLeftBorderLine; // die Linie fuer die Umrandung
+ SvxBorderLine aInhRightBorderLine; // die Linie fuer die Umrandung
+ sal_Bool bTopBorder; // besitzt die Tabelle oben eine Linie
+ sal_Bool bRightBorder; // besitzt die Tabelle rechts eine Linie
+ sal_Bool bTopAlwd; // duerfen die Raender gesetzt werden?
+ sal_Bool bRightAlwd;
+ sal_Bool bFillerTopBorder; // bekommt eine linke/rechter Filler-
+ sal_Bool bFillerBottomBorder; // Zelle eine obere/untere Umrandung?
+ sal_Bool bInhLeftBorder;
+ sal_Bool bInhRightBorder;
+ sal_Bool bBordersSet; // die Umrandung wurde bereits gesetzt
+ sal_Bool bForceFrame;
+ sal_Bool bTableAdjustOfTag; // stammt nTableAdjust aus <TABLE>?
+ sal_Bool bHeadlineRepeat; // Ueberschrift wiederholen
+ sal_Bool bIsParentHead;
+ sal_Bool bHasParentSection;
+ sal_Bool bMakeTopSubTable;
+ sal_Bool bHasToFly;
+ sal_Bool bFixedCols;
+ sal_Bool bColSpec; // Gab es COL(GROUP)-Elemente?
+ sal_Bool bPrcWidth; // Breite ist eine %-Angabe
+
+ SwHTMLParser *pParser; // der aktuelle Parser
+ HTMLTable *pTopTable; // die Tabelle auf dem Top-Level
+ HTMLTableCnts *pParentContents;
+
+ _HTMLTableContext *pContext; // der Kontext der Tabelle
+
+ SwHTMLTableLayout *pLayoutInfo;
+
+
+ // die folgenden Parameter stammen aus der dem <TABLE>-Tag
+ sal_uInt16 nWidth; // die Breite der Tabelle
+ sal_uInt16 nHeight; // absolute Hoehe der Tabelle
+ SvxAdjust eTableAdjust; // ::com::sun::star::drawing::Alignment der Tabelle
+ SwVertOrient eVertOri; // Default vertikale Ausr. der Zellen
+ sal_uInt16 nBorder; // Breite der auesseren Umrandung
+ HTMLTableFrame eFrame; // Rahmen um die Tabelle
+ HTMLTableRules eRules; // Ramhen in der Tabelle
+ sal_Bool bTopCaption; // Ueberschrift ueber der Tabelle
+
+ void InitCtor( const HTMLTableOptions *pOptions );
+
+ // Korigieren des Row-Spans fuer alle Zellen oberhalb der
+ // angegeben Zelle und der Zelle selbst, fuer die den anegebenen
+ // Inhalt besitzen. Die angegeben Zelle bekommt den Row-Span 1
+ void FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, const HTMLTableCnts *pCnts );
+
+ // Schuetzen der angegeben Zelle und den darunterliegenden
+ void ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan );
+
+ // Suchen des SwStartNodes der logisch vorhergehenden Box
+ // bei nRow==nCell==USHRT_MAX wird der allerletzte Start-Node
+ // der Tabelle zurueckgegeben
+ const SwStartNode* GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCell ) const;
+
+ sal_uInt16 GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
+ sal_Bool bSwBorders=sal_True ) const;
+ sal_uInt16 GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
+ sal_Bool bSwBorders=sal_True ) const;
+
+ // Anpassen des ::com::sun::star::frame::Frame-Formates einer Box
+ void FixFrameFmt( SwTableBox *pBox, sal_uInt16 nRow, sal_uInt16 nCol,
+ sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_Bool bFirstPara=sal_True, sal_Bool bLastPara=sal_True ) const;
+ void FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const;
+
+ // den Inhalt (Lines/Boxen) eine Tabelle erstellen
+ void _MakeTable( SwTableBox *pUpper=0 );
+
+ // Anlegen einer neuen SwTableBox, die einen SwStartNode enthaelt
+ SwTableBox *NewTableBox( const SwStartNode *pStNd,
+ SwTableLine *pUpper ) const;
+
+ // Erstellen einer SwTableLine aus den Zellen des Rechtecks
+ // (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive
+ SwTableLine *MakeTableLine( SwTableBox *pUpper,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
+
+ // Erstellen einer SwTableBox aus den Zellen des Rechtecks
+ // (nTopRow/nLeftCol) inklusive bis (nBottomRow/nRightRow) exklusive
+ SwTableBox *MakeTableBox( SwTableLine *pUpper,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBottomRow, sal_uInt16 nRightCol );
+
+ // Erstellen einer SwTableBox aus dem Inhalt einer Zelle
+ SwTableBox *MakeTableBox( SwTableLine *pUpper,
+ HTMLTableCnts *pCnts,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBootomRow, sal_uInt16 nRightCol );
+
+ // der Autolayout-Algorithmus
+
+ // Setzen der Umrandung anhand der Vorgaben der Parent-Tabelle
+ void InheritBorders( const HTMLTable *pParent,
+ sal_uInt16 nRow, sal_uInt16 nCol,
+ sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_Bool bFirstPara, sal_Bool bLastPara );
+
+ // Linke und rechte Umrandung der umgebenen Tabelle erben
+ void InheritVertBorders( const HTMLTable *pParent,
+ sal_uInt16 nCol, sal_uInt16 nColSpan );
+
+
+ // Setzen der Umrandung anhand der Benutzervorgaben
+ void SetBorders();
+
+ // wurde die Umrandung der Tabelle schon gesetzt
+ sal_Bool BordersSet() const { return bBordersSet; }
+
+ const SvxBrushItem *GetBGBrush() const { return pBGBrush; }
+ const SvxBrushItem *GetInhBGBrush() const { return pInhBGBrush; }
+
+ sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
+ sal_Bool bWithDistance=sal_False ) const;
+
+public:
+
+ sal_Bool bFirstCell; // wurde schon eine Zelle angelegt?
+
+ HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
+ sal_Bool bParHead, sal_Bool bHasParentSec,
+ sal_Bool bTopTbl, sal_Bool bHasToFly,
+ const HTMLTableOptions *pOptions );
+
+ ~HTMLTable();
+
+ // Ermitteln einer Zelle
+ inline HTMLTableCell *GetCell( sal_uInt16 nRow, sal_uInt16 nCell ) const;
+
+ // Ueberschrift setzen/ermitteln
+ inline void SetCaption( const SwStartNode *pStNd, sal_Bool bTop );
+ const SwStartNode *GetCaptionStartNode() const { return pCaptionStartNode; }
+ sal_Bool IsTopCaption() const { return bTopCaption; }
+
+ SvxAdjust GetTableAdjust( sal_Bool bAny ) const
+ {
+ return (bTableAdjustOfTag || bAny) ? eTableAdjust : SVX_ADJUST_END;
+ }
+ SwVertOrient GetVertOri() const { return eVertOri; }
+
+ sal_uInt16 GetHSpace() const { return nHSpace; }
+ sal_uInt16 GetVSpace() const { return nVSpace; }
+
+ sal_Bool HasPrcWidth() const { return bPrcWidth; }
+ sal_uInt8 GetPrcWidth() const { return bPrcWidth ? (sal_uInt8)nWidth : 0; }
+
+ sal_uInt16 GetMinWidth() const
+ {
+ sal_uInt32 nMin = pLayoutInfo->GetMin();
+ return nMin < USHRT_MAX ? (sal_uInt16)nMin : USHRT_MAX;
+ }
+
+ // von Zeilen oder Spalten geerbtes ::com::sun::star::drawing::Alignment holen
+ SvxAdjust GetInheritedAdjust() const;
+ SwVertOrient GetInheritedVertOri() const;
+
+ // Einfuegen einer Zelle an der aktuellen Position
+ void InsertCell( HTMLTableCnts *pCnts, sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight,
+ SwVertOrient eVertOri, SvxBrushItem *pBGBrush,
+ sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
+ sal_Bool bHasValue, double nValue, sal_Bool bNoWrap );
+
+ // Start/Ende einer neuen Zeile bekanntgeben
+ void OpenRow( SvxAdjust eAdjust, SwVertOrient eVertOri,
+ SvxBrushItem *pBGBrush );
+ void CloseRow( sal_Bool bEmpty );
+
+ // Ende einer neuen Section bekanntgeben
+ inline void CloseSection( sal_Bool bHead );
+
+ // Ende einer Spalten-Gruppe bekanntgeben
+ inline void CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
+ SvxAdjust eAdjust, SwVertOrient eVertOri );
+
+ // Einfuegen einer Spalte
+ void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
+ SvxAdjust eAdjust, SwVertOrient eVertOri );
+
+ // Beenden einer Tab-Definition (MUSS fuer ALLE Tabs aufgerufen werden)
+ void CloseTable();
+
+ // SwTable konstruieren (inkl. der Child-Tabellen)
+ void MakeTable( SwTableBox *pUpper, sal_uInt16 nAbsAvail,
+ sal_uInt16 nRelAvail=0, sal_uInt16 nAbsLeftSpace=0,
+ sal_uInt16 nAbsRightSpace=0, sal_uInt16 nInhAbsSpace=0 );
+
+ inline sal_Bool IsNewDoc() const { return pParser->IsNewDoc(); }
+
+ void SetHasParentSection( sal_Bool bSet ) { bHasParentSection = bSet; }
+ sal_Bool HasParentSection() const { return bHasParentSection; }
+
+ void SetParentContents( HTMLTableCnts *pCnts ) { pParentContents = pCnts; }
+ HTMLTableCnts *GetParentContents() const { return pParentContents; }
+
+ void MakeParentContents();
+
+ sal_Bool GetIsParentHeader() const { return bIsParentHead; }
+
+ sal_Bool IsMakeTopSubTable() const { return bMakeTopSubTable; }
+ void SetHasToFly() { bHasToFly=sal_True; }
+ sal_Bool HasToFly() const { return bHasToFly; }
+
+ void SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
+ sal_uInt16 nLeft, sal_uInt16 nRight,
+ const SwTable *pSwTab=0, sal_Bool bFrcFrame=sal_False );
+
+ _HTMLTableContext *GetContext() const { return pContext; }
+
+ SwHTMLTableLayout *CreateLayoutInfo();
+
+ sal_Bool HasColTags() const { return bColSpec; }
+
+ sal_uInt16 IncGrfsThatResize() { return pSwTable ? ((SwTable *)pSwTable)->IncGrfsThatResize() : 0; }
+
+ void RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth );
+
+ const SwTable *GetSwTable() const { return pSwTable; }
+
+ void SetBGBrush( const SvxBrushItem& rBrush ) { delete pBGBrush; pBGBrush = new SvxBrushItem( rBrush ); }
+
+ const String& GetId() const { return aId; }
+ const String& GetClass() const { return aClass; }
+ const String& GetStyle() const { return aStyle; }
+
+ void IncBoxCount() { nBoxes++; }
+ sal_Bool IsOverflowing() const { return nBoxes > 64000; }
+};
+
+SV_IMPL_PTRARR(HTMLTableCells,HTMLTableCellPtr)
+SV_IMPL_PTRARR(HTMLTableRows,HTMLTableRowPtr)
+SV_IMPL_PTRARR(HTMLTableColumns,HTMLTableColumnPtr)
+
+/* */
+
+
+void HTMLTableCnts::InitCtor()
+{
+ pNext = 0;
+ pLayoutInfo = 0;
+
+ bNoBreak = sal_False;
+}
+
+HTMLTableCnts::HTMLTableCnts( const SwStartNode* pStNd ):
+ pStartNode(pStNd), pTable(0)
+{
+ InitCtor();
+}
+
+HTMLTableCnts::HTMLTableCnts( HTMLTable* pTab ):
+ pStartNode(0), pTable(pTab)
+{
+ InitCtor();
+}
+
+HTMLTableCnts::~HTMLTableCnts()
+{
+ delete pTable; // die Tabellen brauchen wir nicht mehr
+ delete pNext;
+}
+
+void HTMLTableCnts::Add( HTMLTableCnts* pNewCnts )
+{
+ HTMLTableCnts *pCnts = this;
+
+ while( pCnts->pNext )
+ pCnts = pCnts->pNext;
+
+ pCnts->pNext = pNewCnts;
+}
+
+inline void HTMLTableCnts::SetTableBox( SwTableBox *pBox )
+{
+ ASSERT( pLayoutInfo, "Da sit noch keine Layout-Info" );
+ if( pLayoutInfo )
+ pLayoutInfo->SetTableBox( pBox );
+}
+
+SwHTMLTableLayoutCnts *HTMLTableCnts::CreateLayoutInfo()
+{
+ if( !pLayoutInfo )
+ {
+ SwHTMLTableLayoutCnts *pNextInfo = pNext ? pNext->CreateLayoutInfo() : 0;
+ SwHTMLTableLayout *pTableInfo = pTable ? pTable->CreateLayoutInfo() : 0;
+
+ pLayoutInfo = new SwHTMLTableLayoutCnts( pStartNode, pTableInfo,
+ bNoBreak, pNextInfo );
+ }
+
+ return pLayoutInfo;
+}
+
+/* */
+
+HTMLTableCell::HTMLTableCell():
+ pContents(0),
+ pBGBrush(0),
+ nRowSpan(1), nColSpan(1), nWidth( 0 ),
+ eVertOri( VERT_NONE ),
+ bProtected(sal_False), bRelWidth( sal_False ),
+ bHasNumFmt(sal_False), nNumFmt(0),
+ bHasValue(sal_False), nValue(0)
+{}
+
+HTMLTableCell::~HTMLTableCell()
+{
+ // der Inhalt ist in mehrere Zellen eingetragen, darf aber nur einmal
+ // geloescht werden
+ if( 1==nRowSpan && 1==nColSpan )
+ {
+ delete pContents;
+ delete pBGBrush;
+ }
+}
+
+void HTMLTableCell::Set( HTMLTableCnts *pCnts, sal_uInt16 nRSpan, sal_uInt16 nCSpan,
+ SwVertOrient eVert, SvxBrushItem *pBrush,
+ sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal,
+ sal_Bool bNWrap )
+{
+ pContents = pCnts;
+ nRowSpan = nRSpan;
+ nColSpan = nCSpan;
+ bProtected = sal_False;
+ eVertOri = eVert;
+ pBGBrush = pBrush;
+
+ bHasNumFmt = bHasNF;
+ bHasValue = bHasV;
+ nNumFmt = nNF;
+ nValue = nVal;
+
+ bNoWrap = bNWrap;
+}
+
+inline void HTMLTableCell::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
+{
+ nWidth = nWdth;
+ bRelWidth = bRelWdth;
+}
+
+void HTMLTableCell::SetProtected()
+{
+ // Die Inhalte dieser Zelle mussen nich irgenwo anders verankert
+ // sein, weil sie nicht geloescht werden!!!
+
+ // Inhalt loeschen
+ pContents = 0;
+
+ // Hintergrundfarbe kopieren.
+ if( pBGBrush )
+ pBGBrush = new SvxBrushItem( *pBGBrush );
+
+ nRowSpan = 1;
+ nColSpan = 1;
+ bProtected = sal_True;
+}
+
+inline sal_Bool HTMLTableCell::GetNumFmt( sal_uInt32& rNumFmt ) const
+{
+ rNumFmt = nNumFmt;
+ return bHasNumFmt;
+}
+
+inline sal_Bool HTMLTableCell::GetValue( double& rValue ) const
+{
+ rValue = nValue;
+ return bHasValue;
+}
+
+SwHTMLTableLayoutCell *HTMLTableCell::CreateLayoutInfo()
+{
+ SwHTMLTableLayoutCnts *pCntInfo = pContents ? pContents->CreateLayoutInfo() : 0;
+
+ return new SwHTMLTableLayoutCell( pCntInfo, nRowSpan, nColSpan, nWidth,
+ bRelWidth, bNoWrap );
+}
+
+/* */
+
+HTMLTableRow::HTMLTableRow( sal_uInt16 nCells ):
+ pCells(new HTMLTableCells), bIsEndOfGroup(sal_False),
+ eAdjust(SVX_ADJUST_END), eVertOri(VERT_TOP), pBGBrush(0),
+ bBottomBorder(sal_False), nHeight(0), nEmptyRows(0), bSplitable( sal_False )
+{
+ for( sal_uInt16 i=0; i<nCells; i++ )
+ {
+ pCells->Insert( new HTMLTableCell, pCells->Count() );
+ }
+
+ ASSERT( nCells==pCells->Count(),
+ "Zellenzahl in neuer HTML-Tabellenzeile stimmt nicht" );
+}
+
+HTMLTableRow::~HTMLTableRow()
+{
+ delete pCells;
+ delete pBGBrush;
+}
+
+inline void HTMLTableRow::SetHeight( sal_uInt16 nHght )
+{
+ if( nHght > nHeight )
+ nHeight = nHght;
+}
+
+inline HTMLTableCell *HTMLTableRow::GetCell( sal_uInt16 nCell ) const
+{
+ ASSERT( nCell<pCells->Count(),
+ "ungueltiger Zellen-Index in HTML-Tabellenzeile" );
+ return (*pCells)[nCell];
+}
+
+void HTMLTableRow::Expand( sal_uInt16 nCells, sal_Bool bOneCell )
+{
+ // die Zeile wird mit einer einzigen Zelle aufgefuellt, wenn
+ // bOneCell gesetzt ist. Das geht, nur fuer Zeilen, in die keine
+ // Zellen mehr eingefuegt werden!
+
+ sal_uInt16 nColSpan = nCells-pCells->Count();
+ for( sal_uInt16 i=pCells->Count(); i<nCells; i++ )
+ {
+ HTMLTableCell *pCell = new HTMLTableCell;
+ if( bOneCell )
+ pCell->SetColSpan( nColSpan );
+
+ pCells->Insert( pCell, pCells->Count() );
+ nColSpan--;
+ }
+
+ ASSERT( nCells==pCells->Count(),
+ "Zellenzahl in expandierter HTML-Tabellenzeile stimmt nicht" );
+}
+
+void HTMLTableRow::Shrink( sal_uInt16 nCells )
+{
+ ASSERT( nCells < pCells->Count(), "Anzahl Zellen falsch" );
+
+#ifdef DEBUG
+ sal_uInt16 nEnd = pCells->Count();
+ for( sal_uInt16 i=nCells; i<nEnd; i++ )
+ {
+ HTMLTableCell *pCell = (*pCells)[i];
+ ASSERT( pCell->GetRowSpan() == 1,
+ "RowSpan von zu loesender Zelle ist falsch" );
+ ASSERT( pCell->GetColSpan() == nEnd - i,
+ "ColSpan von zu loesender Zelle ist falsch" );
+ ASSERT( !pCell->GetContents(), "Zu loeschende Zelle hat Inhalt" );
+ }
+#endif
+
+ pCells->DeleteAndDestroy( nCells, pCells->Count()-nCells );
+}
+
+/* */
+
+HTMLTableColumn::HTMLTableColumn():
+ bIsEndOfGroup(sal_False),
+ nWidth(0), bRelWidth(sal_False),
+ eAdjust(SVX_ADJUST_END), eVertOri(VERT_TOP),
+ bLeftBorder(sal_False)
+{
+ for( sal_uInt16 i=0; i<6; i++ )
+ aFrmFmts[i] = 0;
+}
+
+inline void HTMLTableColumn::SetWidth( sal_uInt16 nWdth, sal_Bool bRelWdth )
+{
+ if( bRelWidth==bRelWdth )
+ {
+ if( nWdth > nWidth )
+ nWidth = nWdth;
+ }
+ else
+ nWidth = nWdth;
+ bRelWidth = bRelWdth;
+}
+
+inline SwHTMLTableLayoutColumn *HTMLTableColumn::CreateLayoutInfo()
+{
+ return new SwHTMLTableLayoutColumn( nWidth, bRelWidth, bLeftBorder );
+}
+
+inline sal_uInt16 HTMLTableColumn::GetFrmFmtIdx( sal_Bool bBorderLine,
+ SwVertOrient eVertOri ) const
+{
+ ASSERT( VERT_TOP != eVertOri, "Top ist nicht erlaubt" );
+ sal_uInt16 n = bBorderLine ? 3 : 0;
+ switch( eVertOri )
+ {
+ case VERT_CENTER: n+=1; break;
+ case VERT_BOTTOM: n+=2; break;
+ }
+ return n;
+}
+
+inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine,
+ SwVertOrient eVertOri )
+{
+ aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOri)] = pFmt;
+}
+
+inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine,
+ SwVertOrient eVertOri ) const
+{
+ return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOri)];
+}
+
+/* */
+
+
+void HTMLTable::InitCtor( const HTMLTableOptions *pOptions )
+{
+ pResizeDrawObjs = 0;
+ pDrawObjPrcWidths = 0;
+
+ pRows = new HTMLTableRows;
+ pColumns = new HTMLTableColumns;
+ nRows = 0;
+ nCurRow = 0; nCurCol = 0;
+
+ pBox1 = 0;
+ pBoxFmt = 0; pLineFmt = 0;
+ pLineFrmFmtNoHeight = 0;
+ pInhBGBrush = 0;
+
+ pPrevStNd = 0;
+ pSwTable = 0;
+
+ bTopBorder = sal_False; bRightBorder = sal_False;
+ bTopAlwd = sal_True; bRightAlwd = sal_True;
+ bFillerTopBorder = sal_False; bFillerBottomBorder = sal_False;
+ bInhLeftBorder = sal_False; bInhRightBorder = sal_False;
+ bBordersSet = sal_False;
+ bForceFrame = sal_False;
+ bHeadlineRepeat = sal_False;
+
+ nLeftMargin = 0;
+ nRightMargin = 0;
+
+ const Color& rBorderColor = pOptions->aBorderColor;
+
+ long nBorderOpt = (long)pOptions->nBorder;
+ long nPWidth = nBorderOpt==USHRT_MAX ? NETSCAPE_DFLT_BORDER
+ : nBorderOpt;
+ long nPHeight = nBorderOpt==USHRT_MAX ? 0 : nBorderOpt;
+ SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
+
+ // nBorder gibt die Breite der Umrandung an, wie sie in die
+ // Breitenberechnung in Netscape einfliesst. Wenn pOption->nBorder
+ // == USHRT_MAX, wurde keine BORDER-Option angegeben. Trotzdem fliesst
+ // eine 1 Pixel breite Umrandung in die Breitenberechnung mit ein.
+ nBorder = (sal_uInt16)nPWidth;
+ if( nBorderOpt==USHRT_MAX )
+ nPWidth = 0;
+
+ // HACK: ein Pixel-breite Linien sollen zur Haarlinie werden, wenn
+ // wir mit doppelter Umrandung arbeiten
+ if( pOptions->nCellSpacing!=0 && nBorderOpt==1 )
+ {
+ nPWidth = 1;
+ nPHeight = 1;
+ }
+
+ SvxCSS1Parser::SetBorderWidth( aTopBorderLine, (sal_uInt16)nPHeight,
+ pOptions->nCellSpacing!=0, sal_True );
+ aTopBorderLine.SetColor( rBorderColor );
+ aBottomBorderLine = aTopBorderLine;
+
+ if( nPWidth == nPHeight )
+ {
+ aLeftBorderLine = aTopBorderLine;
+ }
+ else
+ {
+ SvxCSS1Parser::SetBorderWidth( aLeftBorderLine, (sal_uInt16)nPWidth,
+ pOptions->nCellSpacing!=0, sal_True );
+ aLeftBorderLine.SetColor( rBorderColor );
+ }
+ aRightBorderLine = aLeftBorderLine;
+
+ if( pOptions->nCellSpacing != 0 )
+ {
+ aBorderLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
+ aBorderLine.SetInWidth( DEF_DOUBLE_LINE7_IN );
+ aBorderLine.SetDistance( DEF_DOUBLE_LINE7_DIST );
+ }
+ else
+ {
+ aBorderLine.SetOutWidth( DEF_LINE_WIDTH_1 );
+ }
+ aBorderLine.SetColor( rBorderColor );
+
+ if( nCellPadding )
+ {
+ if( nCellPadding==USHRT_MAX )
+ nCellPadding = MIN_BORDER_DIST; // default
+ else
+ {
+ nCellPadding = pParser->ToTwips( nCellPadding );
+ if( nCellPadding<MIN_BORDER_DIST )
+ nCellPadding = MIN_BORDER_DIST;
+ }
+ }
+ if( nCellSpacing )
+ {
+ if( nCellSpacing==USHRT_MAX )
+ nCellSpacing = NETSCAPE_DFLT_CELLSPACING;
+ nCellSpacing = pParser->ToTwips( nCellSpacing );
+ }
+
+ nPWidth = pOptions->nHSpace;
+ nPHeight = pOptions->nVSpace;
+ SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
+ nHSpace = (sal_uInt16)nPWidth;
+ nVSpace = (sal_uInt16)nPHeight;
+
+ bColSpec = sal_False;
+
+ pBGBrush = pParser->CreateBrushItem(
+ pOptions->bBGColor ? &(pOptions->aBGColor) : 0,
+ pOptions->aBGImage, aEmptyStr, aEmptyStr, aEmptyStr );
+
+ pContext = 0;
+ pParentContents = 0;
+
+ aId = pOptions->aId;
+ aClass = pOptions->aClass;
+ aStyle = pOptions->aStyle;
+}
+
+HTMLTable::HTMLTable( SwHTMLParser* pPars, HTMLTable *pTopTab,
+ sal_Bool bParHead,
+ sal_Bool bHasParentSec, sal_Bool bTopTbl, sal_Bool bHasToFlw,
+ const HTMLTableOptions *pOptions ) :
+ nCols( pOptions->nCols ),
+ nFilledCols( 0 ),
+ nWidth( pOptions->nWidth ), bPrcWidth( pOptions->bPrcWidth ),
+ nHeight( pTopTab ? 0 : pOptions->nHeight ),
+ nBoxes( 1 ),
+ eTableAdjust( pOptions->eAdjust ),
+ bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ),
+ eVertOri( pOptions->eVertOri ),
+ eFrame( pOptions->eFrame ), eRules( pOptions->eRules ),
+ nCellPadding( pOptions->nCellPadding ),
+ nCellSpacing( pOptions->nCellSpacing ),
+ pParser( pPars ), pTopTable( pTopTab ? pTopTab : this ),
+ pCaptionStartNode( 0 ),
+ bFirstCell( !pTopTab ),
+ bIsParentHead( bParHead ),
+ bHasParentSection( bHasParentSec ), bMakeTopSubTable( bTopTbl ),
+ bHasToFly( bHasToFlw ),
+ bFixedCols( pOptions->nCols>0 ), bTopCaption( sal_False ),
+ pLayoutInfo( 0 )
+{
+ InitCtor( pOptions );
+
+ for( sal_uInt16 i=0; i<nCols; i++ )
+ pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
+}
+
+
+HTMLTable::~HTMLTable()
+{
+ delete pResizeDrawObjs;
+ delete pDrawObjPrcWidths;
+
+ delete pRows;
+ delete pColumns;
+ delete pBGBrush;
+ delete pInhBGBrush;
+
+ delete pContext;
+
+ // pLayoutInfo wurde entweder bereits geloescht oder muss aber es
+ // in den Besitz der SwTable uebergegangen.
+}
+
+SwHTMLTableLayout *HTMLTable::CreateLayoutInfo()
+{
+ sal_uInt16 nW = bPrcWidth ? nWidth : pParser->ToTwips( nWidth );
+
+ sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
+ sal_uInt16 nLeftBorderWidth =
+ ((*pColumns)[0])->bLeftBorder ? GetBorderWidth( aLeftBorderLine, sal_True ) : 0;
+ sal_uInt16 nRightBorderWidth =
+ bRightBorder ? GetBorderWidth( aRightBorderLine, sal_True ) : 0;
+ sal_uInt16 nInhLeftBorderWidth = 0;
+ sal_uInt16 nInhRightBorderWidth = 0;
+
+ pLayoutInfo = new SwHTMLTableLayout(
+ pSwTable,
+ nRows, nCols, bFixedCols, bColSpec,
+ nW, bPrcWidth, nBorder, nCellPadding,
+ nCellSpacing, eTableAdjust,
+ nLeftMargin, nRightMargin,
+ nBorderWidth, nLeftBorderWidth, nRightBorderWidth,
+ nInhLeftBorderWidth, nInhRightBorderWidth );
+
+ sal_Bool bExportable = sal_True;
+ sal_uInt16 i;
+ for( i=0; i<nRows; i++ )
+ {
+ HTMLTableRow *pRow = (*pRows)[i];
+ for( sal_uInt16 j=0; j<nCols; j++ )
+ {
+ SwHTMLTableLayoutCell *pLayoutCell =
+ pRow->GetCell(j)->CreateLayoutInfo();
+
+ pLayoutInfo->SetCell( pLayoutCell, i, j );
+
+ if( bExportable )
+ {
+ SwHTMLTableLayoutCnts *pLayoutCnts =
+ pLayoutCell->GetContents();
+ bExportable = !pLayoutCnts ||
+ ( pLayoutCnts->GetStartNode() &&
+ !pLayoutCnts->GetNext() );
+ }
+ }
+ }
+
+ pLayoutInfo->SetExportable( bExportable );
+
+ for( i=0; i<nCols; i++ )
+ pLayoutInfo->SetColumn( ((*pColumns)[i])->CreateLayoutInfo(), i );
+
+ return pLayoutInfo;
+}
+
+inline void HTMLTable::SetCaption( const SwStartNode *pStNd, sal_Bool bTop )
+{
+ pCaptionStartNode = pStNd;
+ bTopCaption = bTop;
+}
+
+void HTMLTable::FixRowSpan( sal_uInt16 nRow, sal_uInt16 nCol,
+ const HTMLTableCnts *pCnts )
+{
+ sal_uInt16 nRowSpan=1;
+ HTMLTableCell *pCell;
+ while( ( pCell=GetCell(nRow,nCol), pCell->GetContents()==pCnts ) )
+ {
+ pCell->SetRowSpan( nRowSpan );
+ if( pLayoutInfo )
+ pLayoutInfo->GetCell(nRow,nCol)->SetRowSpan( nRowSpan );
+
+ if( !nRow ) break;
+ nRowSpan++; nRow--;
+ }
+}
+
+void HTMLTable::ProtectRowSpan( sal_uInt16 nRow, sal_uInt16 nCol, sal_uInt16 nRowSpan )
+{
+ for( sal_uInt16 i=0; i<nRowSpan; i++ )
+ {
+ GetCell(nRow+i,nCol)->SetProtected();
+ if( pLayoutInfo )
+ pLayoutInfo->GetCell(nRow+i,nCol)->SetProtected();
+ }
+}
+
+
+// Suchen des SwStartNodes der letzten belegten Vorgaengerbox
+const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 nCol ) const
+{
+ const HTMLTableCnts *pPrevCnts = 0;
+
+ if( 0==nRow )
+ {
+ // immer die Vorgaenger-Zelle
+ if( nCol>0 )
+ pPrevCnts = GetCell( 0, nCol-1 )->GetContents();
+ else
+ return pPrevStNd;
+ }
+ else if( USHRT_MAX==nRow && USHRT_MAX==nCol )
+ // der Contents der letzten Zelle
+ pPrevCnts = GetCell( nRows-1, nCols-1 )->GetContents();
+ else
+ {
+ sal_uInt16 i;
+ HTMLTableRow *pPrevRow = (*pRows)[nRow-1];
+
+ // evtl. eine Zelle in der aktuellen Zeile
+ i = nCol;
+ while( i )
+ {
+ i--;
+ if( 1 == pPrevRow->GetCell(i)->GetRowSpan() )
+ {
+ pPrevCnts = GetCell(nRow,i)->GetContents();
+ break;
+ }
+ }
+
+ // sonst die letzte gefuellte Zelle der Zeile davor suchen
+ if( !pPrevCnts )
+ {
+ i = nCols;
+ while( !pPrevCnts && i )
+ {
+ i--;
+ pPrevCnts = pPrevRow->GetCell(i)->GetContents();
+ }
+ }
+ }
+ ASSERT( pPrevCnts, "keine gefuellte Vorgaenger-Zelle gefunden" );
+ if( !pPrevCnts )
+ {
+ pPrevCnts = GetCell(0,0)->GetContents();
+ if( !pPrevCnts )
+ return pPrevStNd;
+ }
+
+ while( pPrevCnts->Next() )
+ pPrevCnts = pPrevCnts->Next();
+
+ return ( pPrevCnts->GetStartNode() ? pPrevCnts->GetStartNode()
+ : pPrevCnts->GetTable()->GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX ) );
+}
+
+
+static sal_Bool IsBoxEmpty( const SwTableBox *pBox )
+{
+ const SwStartNode *pSttNd = pBox->GetSttNd();
+ if( pSttNd &&
+ pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() )
+ {
+ const SwCntntNode *pCNd =
+ pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetCntntNode();
+ if( pCNd && !pCNd->Len() )
+ return sal_True;
+ }
+
+ return sal_False;
+}
+
+sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
+ sal_Bool bSwBorders ) const
+{
+ sal_uInt16 nSpace = nCellPadding;
+
+ if( nRow == 0 )
+ {
+ nSpace += nBorder + nCellSpacing;
+ if( bSwBorders )
+ {
+ sal_uInt16 nTopBorderWidth =
+ GetBorderWidth( aTopBorderLine, sal_True );
+ if( nSpace < nTopBorderWidth )
+ nSpace = nTopBorderWidth;
+ }
+ }
+ else if( bSwBorders && ((*pRows)[nRow+nRowSpan-1])->bBottomBorder &&
+ nSpace < MIN_BORDER_DIST )
+ {
+ ASSERT( !nCellPadding, "GetTopCellSpace: CELLPADDING!=0" );
+ // Wenn die Gegenueberliegende Seite umrandet ist muessen
+ // wir zumindest den minimalen Abstand zum Inhalt
+ // beruecksichtigen. (Koennte man zusaetzlich auch an
+ // nCellPadding festmachen.)
+ nSpace = MIN_BORDER_DIST;
+ }
+
+ return nSpace;
+}
+
+sal_uInt16 HTMLTable::GetBottomCellSpace( sal_uInt16 nRow, sal_uInt16 nRowSpan,
+ sal_Bool bSwBorders ) const
+{
+ sal_uInt16 nSpace = nCellSpacing + nCellPadding;
+
+ if( nRow+nRowSpan == nRows )
+ {
+ nSpace += nBorder;
+
+ if( bSwBorders )
+ {
+ sal_uInt16 nBottomBorderWidth =
+ GetBorderWidth( aBottomBorderLine, sal_True );
+ if( nSpace < nBottomBorderWidth )
+ nSpace = nBottomBorderWidth;
+ }
+ }
+ else if( bSwBorders )
+ {
+ if( ((*pRows)[nRow+nRowSpan+1])->bBottomBorder )
+ {
+ sal_uInt16 nBorderWidth = GetBorderWidth( aBorderLine, sal_True );
+ if( nSpace < nBorderWidth )
+ nSpace = nBorderWidth;
+ }
+ else if( nRow==0 && bTopBorder && nSpace < MIN_BORDER_DIST )
+ {
+ ASSERT( GetBorderWidth( aTopBorderLine, sal_True ) > 0,
+ "GetBottomCellSpace: |aTopLine| == 0" );
+ ASSERT( !nCellPadding, "GetBottomCellSpace: CELLPADDING!=0" );
+ // Wenn die Gegenueberliegende Seite umrandet ist muessen
+ // wir zumindest den minimalen Abstand zum Inhalt
+ // beruecksichtigen. (Koennte man zusaetzlich auch an
+ // nCellPadding festmachen.)
+ nSpace = MIN_BORDER_DIST;
+ }
+ }
+
+ return nSpace;
+}
+
+void HTMLTable::FixFrameFmt( SwTableBox *pBox,
+ sal_uInt16 nRow, sal_uInt16 nCol,
+ sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_Bool bFirstPara, sal_Bool bLastPara ) const
+{
+ SwFrmFmt *pFrmFmt = 0; // ::com::sun::star::frame::Frame-Format
+ SwVertOrient eVOri = VERT_NONE;
+ const SvxBrushItem *pBGBrush = 0; // Hintergrund
+ sal_Bool bTopLine = sal_False, bBottomLine = sal_False, bLastBottomLine = sal_False;
+ sal_Bool bReUsable = sal_False; // Format nochmals verwendbar?
+ sal_uInt16 nEmptyRows = 0;
+ sal_Bool bHasNumFmt = sal_False;
+ sal_Bool bHasValue = sal_False;
+ sal_uInt32 nNumFmt;
+ double nValue;
+
+ HTMLTableColumn *pColumn = (*pColumns)[nCol];
+
+ if( pBox->GetSttNd() )
+ {
+ // die Hintergrundfarbe/-grafik bestimmen
+ const HTMLTableCell *pCell = GetCell( nRow, nCol );
+ pBGBrush = pCell->GetBGBrush();
+ if( !pBGBrush )
+ {
+ // Wenn die Zelle ueber mehrere Zeilen geht muss ein evtl.
+ // an der Zeile gesetzter Hintergrund an die Zelle uebernommen
+ // werden.
+#ifndef FIX56334
+ // Wenn es sich um eine Tabelle in der Tabelle handelt und
+ // die Zelle ueber die gesamte Heoehe der Tabelle geht muss
+ // ebenfalls der Hintergrund der Zeile uebernommen werden, weil
+ // die Line von der GC (zu Recht) wegoptimiert wird.
+ if( nRowSpan > 1 || (this != pTopTable && nRowSpan==nRows) )
+#else
+ if( nRowSpan > 1 )
+#endif
+ {
+ pBGBrush = ((*pRows)[nRow])->GetBGBrush();
+ if( !pBGBrush && this != pTopTable )
+ {
+ pBGBrush = GetBGBrush();
+ if( !pBGBrush )
+ pBGBrush = GetInhBGBrush();
+ }
+ }
+ }
+
+ bTopLine = 0==nRow && bTopBorder && bFirstPara;
+ if( ((*pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
+ {
+ nEmptyRows = ((*pRows)[nRow+nRowSpan-1])->GetEmptyRows();
+ if( nRow+nRowSpan == nRows )
+ bLastBottomLine = sal_True;
+ else
+ bBottomLine = sal_True;
+ }
+
+ eVOri = pCell->GetVertOri();
+ bHasNumFmt = pCell->GetNumFmt( nNumFmt );
+ if( bHasNumFmt )
+ bHasValue = pCell->GetValue( nValue );
+
+ if( nColSpan==1 && !bTopLine && !bLastBottomLine && !nEmptyRows &&
+ !pBGBrush && !bHasNumFmt )
+ {
+ pFrmFmt = pColumn->GetFrmFmt( bBottomLine, eVOri );
+ bReUsable = !pFrmFmt;
+ }
+ }
+
+ if( !pFrmFmt )
+ {
+ pFrmFmt = pBox->ClaimFrmFmt();
+
+ // die Breite der Box berechnen
+ SwTwips nFrmWidth = (SwTwips)pLayoutInfo->GetColumn(nCol)
+ ->GetRelColWidth();
+ for( sal_uInt16 i=1; i<nColSpan; i++ )
+ nFrmWidth += (SwTwips)pLayoutInfo->GetColumn(nCol+i)
+ ->GetRelColWidth();
+
+ // die Umrandung nur an Edit-Boxen setzen (bei der oberen und unteren
+ // Umrandung muss beruecks. werden, ob es sich um den ersten oder
+ // letzen Absatz der Zelle handelt)
+ if( pBox->GetSttNd() )
+ {
+ sal_Bool bSet = (nCellPadding > 0);
+
+ SvxBoxItem aBoxItem;
+ long nInnerFrmWidth = nFrmWidth;
+
+ if( bTopLine )
+ {
+ aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
+ bSet = sal_True;
+ }
+ if( bLastBottomLine )
+ {
+ aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
+ bSet = sal_True;
+ }
+ else if( bBottomLine )
+ {
+ if( nEmptyRows && !aBorderLine.GetInWidth() )
+ {
+ // Leere Zeilen koennen zur Zeit nur dann ueber
+ // dicke Linien simuliert werden, wenn die Linie
+ // einfach ist.
+ SvxBorderLine aThickBorderLine( aBorderLine );
+
+ sal_uInt16 nBorderWidth = aBorderLine.GetOutWidth();
+ nBorderWidth *= (nEmptyRows + 1);
+ SvxCSS1Parser::SetBorderWidth( aThickBorderLine,
+ nBorderWidth, sal_False );
+ aBoxItem.SetLine( &aThickBorderLine, BOX_LINE_BOTTOM );
+ }
+ else
+ {
+ aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
+ }
+ bSet = sal_True;
+ }
+ if( ((*pColumns)[nCol])->bLeftBorder )
+ {
+ const SvxBorderLine& rBorderLine =
+ 0==nCol ? aLeftBorderLine : aBorderLine;
+ aBoxItem.SetLine( &rBorderLine, BOX_LINE_LEFT );
+ nInnerFrmWidth -= GetBorderWidth( rBorderLine );
+ bSet = sal_True;
+ }
+ if( nCol+nColSpan == nCols && bRightBorder )
+ {
+ aBoxItem.SetLine( &aRightBorderLine, BOX_LINE_RIGHT );
+ nInnerFrmWidth -= GetBorderWidth( aRightBorderLine );
+ bSet = sal_True;
+ }
+
+ if( bSet )
+ {
+ // fix #30588#: BorderDist nicht mehr Bestandteil
+ // einer Zelle mit fixer Breite
+ sal_uInt16 nBDist =
+ (2*nCellPadding <= nInnerFrmWidth) ? nCellPadding
+ : (nInnerFrmWidth / 2);
+ // wir setzen das Item nur, wenn es eine Umrandung gibt
+ // oder eine ::com::sun::star::sheet::Border-Distanz vorgegeben ist. Fehlt letztere,
+ // dann gibt es eine Umrandung, und wir muessen die Distanz
+ // setzen
+ aBoxItem.SetDistance( nBDist ? nBDist : MIN_BORDER_DIST );
+ pFrmFmt->SetAttr( aBoxItem );
+ }
+ else
+ pFrmFmt->ResetAttr( RES_BOX );
+
+ if( pBGBrush )
+ {
+ pFrmFmt->SetAttr( *pBGBrush );
+ }
+ else
+ pFrmFmt->ResetAttr( RES_BACKGROUND );
+
+ // fix #41003#: Format nur setzten, wenn es auch einen Value
+ // gibt oder die Box leer ist.
+ if( bHasNumFmt && (bHasValue || IsBoxEmpty(pBox)) )
+ {
+ sal_Bool bLock = pFrmFmt->GetDoc()->GetNumberFormatter()
+ ->IsTextFormat( nNumFmt );
+ SfxItemSet aItemSet( *pFrmFmt->GetAttrSet().GetPool(),
+ RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
+ SvxAdjust eAdjust = SVX_ADJUST_END;
+ SwCntntNode *pCNd = 0;
+ if( !bLock )
+ {
+ const SwStartNode *pSttNd = pBox->GetSttNd();
+ pCNd = pSttNd->GetNodes()[pSttNd->GetIndex()+1]
+ ->GetCntntNode();
+ const SfxPoolItem *pItem;
+ if( pCNd && pCNd->GetpSwAttrSet() &&
+ SFX_ITEM_SET==pCNd->GetpSwAttrSet()->GetItemState(
+ RES_PARATR_ADJUST, sal_False, &pItem ) )
+ {
+ eAdjust = ((const SvxAdjustItem *)pItem)
+ ->GetAdjust();
+ }
+ }
+ aItemSet.Put( SwTblBoxNumFormat(nNumFmt) );
+ if( bHasValue )
+ aItemSet.Put( SwTblBoxValue(nValue) );
+
+ if( bLock )
+ pFrmFmt->LockModify();
+ pFrmFmt->SetAttr( aItemSet );
+ if( bLock )
+ pFrmFmt->UnlockModify();
+ else if( pCNd && SVX_ADJUST_END != eAdjust )
+ {
+ SvxAdjustItem aAdjItem( eAdjust );
+ pCNd->SetAttr( aAdjItem );
+ }
+ }
+ else
+ pFrmFmt->ResetAttr( RES_BOXATR_FORMAT );
+
+ ASSERT( eVOri != VERT_TOP, "VERT_TOP ist nicht erlaubt!" );
+ if( VERT_NONE != eVOri )
+ {
+ pFrmFmt->SetAttr( SwFmtVertOrient( 0, eVOri ) );
+ }
+ else
+ pFrmFmt->ResetAttr( RES_VERT_ORIENT );
+
+ if( bReUsable )
+ pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri );
+ }
+ else
+ {
+ pFrmFmt->ResetAttr( RES_BOX );
+ pFrmFmt->ResetAttr( RES_BACKGROUND );
+ pFrmFmt->ResetAttr( RES_VERT_ORIENT );
+ pFrmFmt->ResetAttr( RES_BOXATR_FORMAT );
+ }
+ }
+ else
+ {
+ ASSERT( pBox->GetSttNd() ||
+ SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
+ RES_VERT_ORIENT, sal_False ),
+ "Box ohne Inhalt hat vertikale Ausrichtung" );
+ pBox->ChgFrmFmt( (SwTableBoxFmt*)pFrmFmt );
+ }
+
+}
+
+void HTMLTable::FixFillerFrameFmt( SwTableBox *pBox, sal_Bool bRight ) const
+{
+ SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
+
+ if( bFillerTopBorder || bFillerBottomBorder ||
+ (!bRight && bInhLeftBorder) || (bRight && bInhRightBorder) )
+ {
+ SvxBoxItem aBoxItem;
+ if( bFillerTopBorder )
+ aBoxItem.SetLine( &aTopBorderLine, BOX_LINE_TOP );
+ if( bFillerBottomBorder )
+ aBoxItem.SetLine( &aBottomBorderLine, BOX_LINE_BOTTOM );
+ if( !bRight && bInhLeftBorder )
+ aBoxItem.SetLine( &aInhLeftBorderLine, BOX_LINE_LEFT );
+ if( bRight && bInhRightBorder )
+ aBoxItem.SetLine( &aInhRightBorderLine, BOX_LINE_RIGHT );
+ aBoxItem.SetDistance( MIN_BORDER_DIST );
+ pFrmFmt->SetAttr( aBoxItem );
+ }
+ else
+ {
+ pFrmFmt->ResetAttr( RES_BOX );
+ }
+
+ if( GetInhBGBrush() )
+ pFrmFmt->SetAttr( *GetInhBGBrush() );
+ else
+ pFrmFmt->ResetAttr( RES_BACKGROUND );
+
+ pFrmFmt->ResetAttr( RES_VERT_ORIENT );
+ pFrmFmt->ResetAttr( RES_BOXATR_FORMAT );
+}
+
+SwTableBox *HTMLTable::NewTableBox( const SwStartNode *pStNd,
+ SwTableLine *pUpper ) const
+{
+ SwTableBox *pBox;
+
+ if( pTopTable->pBox1 &&
+ pTopTable->pBox1->GetSttNd() == pStNd )
+ {
+ // wenn der StartNode dem StartNode der initial angelegten Box
+ // entspricht nehmen wir diese Box
+ pBox = pTopTable->pBox1;
+ pBox->SetUpper( pUpper );
+ pTopTable->pBox1 = 0;
+ }
+ else
+ pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
+
+ return pBox;
+}
+
+
+static void ResetLineFrmFmtAttrs( SwFrmFmt *pFrmFmt )
+{
+ pFrmFmt->ResetAttr( RES_FRM_SIZE );
+ pFrmFmt->ResetAttr( RES_BACKGROUND );
+ ASSERT( SFX_ITEM_SET!=pFrmFmt->GetAttrSet().GetItemState(
+ RES_VERT_ORIENT, sal_False ),
+ "Zeile hat vertikale Ausrichtung" );
+}
+
+// !!! kann noch vereinfacht werden
+SwTableLine *HTMLTable::MakeTableLine( SwTableBox *pUpper,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
+{
+ SwTableLine *pLine;
+ if( this==pTopTable && !pUpper && 0==nTopRow )
+ pLine = (pSwTable->GetTabLines())[0];
+ else
+ pLine = new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
+ : pLineFmt,
+ 0, pUpper );
+
+ HTMLTableRow *pTopRow = (*pRows)[nTopRow];
+ sal_uInt16 nHeight = pTopRow->GetHeight();
+ const SvxBrushItem *pBGBrush = 0;
+#ifndef FIX56334
+ if( this == pTopTable || nTopRow>0 || nBottomRow<nRows )
+ {
+ // An der Line eine Frabe zu setzen macht keinen Sinn, wenn sie
+ // die auesserste und gleichzeitig einzige Zeile einer Tabelle in
+ // der Tabelle ist.
+#endif
+ pBGBrush = pTopRow->GetBGBrush();
+
+ if( !pBGBrush && this != pTopTable )
+ {
+ // Ein an einer Tabellen in der Tabelle gesetzter Hintergrund
+ // wird an den Rows gesetzt. Das gilt auch fuer den Hintergrund
+ // der Zelle, in dem die Tabelle vorkommt.
+ pBGBrush = GetBGBrush();
+ if( !pBGBrush )
+ pBGBrush = GetInhBGBrush();
+ }
+#ifndef FIX56334
+ }
+#endif
+ if( nTopRow==nBottomRow-1 && (nHeight || pBGBrush) )
+ {
+ SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt();
+ ResetLineFrmFmtAttrs( pFrmFmt );
+
+ if( nHeight )
+ {
+ // Tabellenhoehe einstellen. Da es sich um eine
+ // Mindesthoehe handelt, kann sie genauso wie in
+ // Netscape berechnet werden, also ohne Beruecksichtigung
+ // der tatsaechlichen Umrandungsbreite.
+ nHeight += GetTopCellSpace( nTopRow, 1, sal_False ) +
+ GetBottomCellSpace( nTopRow, 1, sal_False );
+
+ pFrmFmt->SetAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) );
+ }
+
+ if( pBGBrush )
+ {
+ pFrmFmt->SetAttr( *pBGBrush );
+ }
+
+ }
+ else if( !pLineFrmFmtNoHeight )
+ {
+ // sonst muessen wir die Hoehe aus dem Attribut entfernen
+ // und koennen uns das Format merken
+ pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
+
+ ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
+ }
+
+
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+
+ sal_uInt16 nStartCol = nLeftCol;
+ while( nStartCol<nRightCol )
+ {
+ for( sal_uInt16 nRow=nTopRow; nRow<nBottomRow; nRow++ )
+ (*pRows)[nRow]->SetSplitable( sal_True );
+
+ sal_uInt16 nCol = nStartCol;
+ sal_uInt16 nSplitCol = nRightCol;
+ sal_Bool bSplitted = sal_False;
+ while( !bSplitted )
+ {
+ ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
+
+ // Kann hinter der aktuellen HTML-Tabellen-Spalte gesplittet
+ // werden? Wenn ja, koennte der enstehende Bereich auch noch
+ // in Zeilen zerlegt werden, wenn man die naechste Spalte
+ // hinzunimmt?
+ sal_Bool bSplit = sal_True;
+ sal_Bool bHoriSplitMayContinue = sal_False;
+ sal_Bool bHoriSplitPossible = sal_False;
+ for( sal_uInt16 nRow=nTopRow; nRow<nBottomRow; nRow++ )
+ {
+ HTMLTableCell *pCell = GetCell(nRow,nCol);
+ // Gibt es in allen vorhergehenden Spalten und der gerade
+ // btrachteten Zeile eine gemeinsame Zeile?
+ sal_Bool bHoriSplit = (*pRows)[nRow]->IsSplitable() &&
+ nRow+1 < nBottomRow &&
+ 1 == pCell->GetRowSpan();
+ (*pRows)[nRow]->SetSplitable( bHoriSplit );
+
+ bSplit &= ( 1 == pCell->GetColSpan() );
+ if( bSplit )
+ {
+ bHoriSplitPossible |= bHoriSplit;
+
+ // Gilt das eventuell auch noch, wenn man die naechste
+ // Spalte hinzunimmt?
+ bHoriSplit &= (nCol+1 < nRightCol &&
+ 1 == GetCell(nRow,nCol+1)->GetRowSpan());
+ bHoriSplitMayContinue |= bHoriSplit;
+ }
+ }
+
+#ifndef PRODUCT
+ if( nCol == nRightCol-1 )
+ {
+ ASSERT( bSplit, "Split-Flag falsch" );
+ ASSERT( !bHoriSplitMayContinue,
+ "HoriSplitMayContinue-Flag falsch" );
+ HTMLTableCell *pCell = GetCell( nTopRow, nStartCol );
+ ASSERT( pCell->GetRowSpan() != (nBottomRow-nTopRow) ||
+ !bHoriSplitPossible, "HoriSplitPossible-Flag falsch" );
+ }
+#endif
+ ASSERT( !bHoriSplitMayContinue || bHoriSplitPossible,
+ "bHoriSplitMayContinue, aber nicht bHoriSplitPossible" );
+
+ if( bSplit )
+ {
+ SwTableBox* pBox = 0;
+ HTMLTableCell *pCell = GetCell( nTopRow, nStartCol );
+ if( pCell->GetRowSpan() == (nBottomRow-nTopRow) &&
+ pCell->GetColSpan() == (nCol+1-nStartCol) )
+ {
+ // Die HTML-Tabellen-Zellen bilden genau eine Box.
+ // Dann muss hinter der Box gesplittet werden
+ nSplitCol = nCol + 1;
+
+ // eventuell ist die Zelle noch leer
+ if( !pCell->GetContents() )
+ {
+ ASSERT( 1==pCell->GetRowSpan(),
+ "leere Box ist nicht 1 Zeile hoch" );
+ const SwStartNode* pPrevStNd =
+ GetPrevBoxStartNode( nTopRow, nStartCol );
+ HTMLTableCnts *pCnts = new HTMLTableCnts(
+ pParser->InsertTableSection(pPrevStNd) );
+ SwHTMLTableLayoutCnts *pCntsLayoutInfo =
+ pCnts->CreateLayoutInfo();
+
+ pCell->SetContents( pCnts );
+ pLayoutInfo->GetCell( nTopRow, nStartCol )
+ ->SetContents( pCntsLayoutInfo );
+
+ // ggf. COLSPAN beachten
+ for( sal_uInt16 j=nStartCol+1; j<nSplitCol; j++ )
+ {
+ GetCell(nTopRow,j)->SetContents( pCnts );
+ pLayoutInfo->GetCell( nTopRow, j )
+ ->SetContents( pCntsLayoutInfo );
+ }
+ }
+ pBox = MakeTableBox( pLine, pCell->GetContents(),
+ nTopRow, nStartCol,
+ nBottomRow, nSplitCol );
+ bSplitted = sal_True;
+ }
+ else if( bHoriSplitPossible && bHoriSplitMayContinue )
+ {
+ // Bis hierher lies sich die Box noch in Zeilen zerlegen
+ // und evetutell gillt das auch noch, wenn man die
+ // naechste hinzunimmt. Dann suchen wir weiter, merken
+ // uns aber die Position als moegliche Split-Position.
+ nSplitCol = nCol + 1;
+ }
+ else
+ {
+ // Wenn sich die Box bis hier her noch in Zeilen
+ // zerlegen lies, durch hinzunahmen noch einer
+ // Spalte aber nicht mehr, dann wird genau hinter
+ // dieser Splate gesplittet. (#55447#: Das gilt
+ // insbesondere auch fuer die letzte Spalte).
+ // Hinter der aktuellen Spalte wurd ausserdem gesplittet,
+ // wenn bisher noch gar keine andere Split-Position
+ // gefunden wurde.
+ // In allen anderen Faellen wird die bisher gemerkte
+ // Split-Position benutzt.
+ if( bHoriSplitPossible || nSplitCol > nCol+1 )
+ {
+ ASSERT( !bHoriSplitMayContinue,
+ "bHoriSplitMayContinue==sal_True" );
+ ASSERT( bHoriSplitPossible || nSplitCol == nRightCol,
+ "bHoriSplitPossible-Flag sollte gesetzt sein" );
+
+ nSplitCol = nCol + 1;
+ }
+
+ // Wenn die enstehende Box nicht mehr in Zeilen zerlegt
+ // werden kann, wenn man die naechste Spalte hinzunimmt
+ // muss man ebenfalls Splitten.
+ pBox = MakeTableBox( pLine, nTopRow, nStartCol,
+ nBottomRow, nSplitCol );
+ bSplitted = sal_True;
+ }
+ if( pBox )
+ rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
+ }
+ nCol++;
+ }
+ nStartCol = nSplitCol;
+ }
+
+ return pLine;
+}
+
+// Fuellen einer SwTableBox
+// !!! kann noch vereinfacht werden
+SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
+{
+ SwTableBox *pBox = new SwTableBox( pBoxFmt, 0, pUpper );
+ FixFrameFmt( pBox, nTopRow, nLeftCol,
+ nTopRow-nBottomRow, nRightCol-nLeftCol );
+
+ SwTableLines& rLines = pBox->GetTabLines();
+ sal_Bool bSplitted = sal_False;
+
+ while( !bSplitted )
+ {
+ sal_uInt16 nStartRow = nTopRow;
+ for( sal_uInt16 i=nTopRow; i<nBottomRow; i++ )
+ {
+ // kann hinter der aktuellen HTML-Tabellen-Zeile gesplittet werden?
+ sal_Bool bSplit = sal_True;
+ HTMLTableRow *pRow = (*pRows)[i];
+ for( sal_uInt16 j=nLeftCol; j<nRightCol; j++ )
+ {
+ bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
+ if( !bSplit )
+ break;
+ }
+ if( bSplit && (nStartRow>nTopRow || i+1<nBottomRow) )
+ {
+ // kein Spezialfall fuer die erste Zeile neotig, da wir hier
+ // in einer Box und nicht in der Tabelle sind
+ SwTableLine *pLine = MakeTableLine( pBox, nStartRow, nLeftCol, i+1, nRightCol );
+
+ rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
+
+ nStartRow = i+1;
+ bSplitted = sal_True;
+ }
+ }
+ if( !bSplitted )
+ {
+ // jetzt muessen wir die Zelle mit Gewalt Teilen
+
+ nStartRow = nTopRow;
+ while( nStartRow < nBottomRow )
+ {
+ sal_uInt16 nMaxRowSpan=0;
+ HTMLTableRow *pStartRow = (*pRows)[nStartRow];
+ HTMLTableCell *pCell;
+ for( i=nLeftCol; i<nRightCol; i++ )
+ if( ( pCell=pStartRow->GetCell(i),
+ pCell->GetRowSpan() > nMaxRowSpan ) )
+ nMaxRowSpan = pCell->GetRowSpan();
+
+ nStartRow += nMaxRowSpan;
+ if( nStartRow<nBottomRow )
+ {
+ HTMLTableRow *pPrevRow = (*pRows)[nStartRow-1];
+ for( i=nLeftCol; i<nRightCol; i++ )
+ {
+ if( pPrevRow->GetCell(i)->GetRowSpan() > 1 )
+ {
+ // Die Inhalte sind in der Zeile darueber (also
+ // der durch FixRowSpan bearbeiteten) verankert
+ // und koennen/mussen deshalb in den mit
+ // ProtectRowSpan bearbeitetebn Zeilen
+ // geloescht oder kopiert werden
+ HTMLTableCell *pCell = GetCell( nStartRow, i );
+ FixRowSpan( nStartRow-1, i, pCell->GetContents() );
+ ProtectRowSpan( nStartRow, i,
+ pCell->GetRowSpan() );
+ }
+ }
+ }
+ }
+ // und jetzt nochmal von vorne ...
+ }
+ }
+
+ return pBox;
+}
+
+
+SwTableBox *HTMLTable::MakeTableBox( SwTableLine *pUpper,
+ HTMLTableCnts *pCnts,
+ sal_uInt16 nTopRow, sal_uInt16 nLeftCol,
+ sal_uInt16 nBottomRow, sal_uInt16 nRightCol )
+{
+ SwTableBox *pBox;
+ sal_uInt16 nColSpan = nRightCol - nLeftCol;
+ sal_uInt16 nRowSpan = nBottomRow - nTopRow;
+
+ if( !pCnts->Next() )
+ {
+ // nur eine Inhalts-Section
+ if( pCnts->GetStartNode() )
+ {
+ // und die ist keine Tabelle
+ pBox = NewTableBox( pCnts->GetStartNode(), pUpper );
+ pCnts->SetTableBox( pBox );
+ }
+ else
+ {
+ pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
+ nRightCol-nLeftCol );
+ // und die ist eine Tabelle: dann bauen wir eine neue
+ // Box und fuegen die Zeilen der Tabelle in die Zeilen
+ // der Box ein
+ pBox = new SwTableBox( pBoxFmt, 0, pUpper );
+ sal_uInt16 nAbs, nRel;
+ pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
+ sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol, nColSpan );
+ sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol, nColSpan );
+ sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
+ pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace, nRSpace,
+ nInhSpace );
+ }
+ }
+ else
+ {
+ // mehrere Inhalts Sections: dann brauchen wir eine Box mit Zeilen
+ pBox = new SwTableBox( pBoxFmt, 0, pUpper );
+ SwTableLines& rLines = pBox->GetTabLines();
+ sal_Bool bFirstPara = sal_True;
+
+ while( pCnts )
+ {
+ if( pCnts->GetStartNode() )
+ {
+ // normale Absaetze werden zu einer Box in einer Zeile
+ SwTableLine *pLine =
+ new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
+ : pLineFmt, 0, pBox );
+ if( !pLineFrmFmtNoHeight )
+ {
+ // Wenn es noch kein Line-Format ohne Hoehe gibt, koennen
+ // wir uns dieses her als soleches merken
+ pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
+
+ ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
+ }
+
+ SwTableBox* pCntBox = NewTableBox( pCnts->GetStartNode(),
+ pLine );
+ pCnts->SetTableBox( pCntBox );
+ FixFrameFmt( pCntBox, nTopRow, nLeftCol, nRowSpan, nColSpan,
+ bFirstPara, 0==pCnts->Next() );
+ pLine->GetTabBoxes().C40_INSERT( SwTableBox, pCntBox,
+ pLine->GetTabBoxes().Count() );
+
+ rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
+ }
+ else
+ {
+ pCnts->GetTable()->InheritVertBorders( this, nLeftCol,
+ nRightCol-nLeftCol );
+ // Tabellen werden direkt eingetragen
+ sal_uInt16 nAbs, nRel;
+ pLayoutInfo->GetAvail( nLeftCol, nColSpan, nAbs, nRel );
+ sal_uInt16 nLSpace = pLayoutInfo->GetLeftCellSpace( nLeftCol,
+ nColSpan );
+ sal_uInt16 nRSpace = pLayoutInfo->GetRightCellSpace( nLeftCol,
+ nColSpan );
+ sal_uInt16 nInhSpace = pLayoutInfo->GetInhCellSpace( nLeftCol, nColSpan );
+ pCnts->GetTable()->MakeTable( pBox, nAbs, nRel, nLSpace,
+ nRSpace, nInhSpace );
+ }
+
+ pCnts = pCnts->Next();
+ bFirstPara = sal_False;
+ }
+ }
+
+ FixFrameFmt( pBox, nTopRow, nLeftCol, nRowSpan, nColSpan );
+
+ return pBox;
+}
+
+void HTMLTable::InheritBorders( const HTMLTable *pParent,
+ sal_uInt16 nRow, sal_uInt16 nCol,
+ sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_Bool bFirstPara, sal_Bool bLastPara )
+{
+ ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
+ "Wurde CloseTable nicht aufgerufen?" );
+
+ // Die Child-Tabelle muss einen Rahmen bekommen, wenn die umgebende
+ // Zelle einen Rand an der betreffenden Seite besitzt.
+ // Der obere bzw. untere Rand wird nur gesetzt, wenn die Tabelle
+ // ale erster bzw. letzter Absatz in der Zelle vorkommt. Ansonsten
+ // Fuer den linken/rechten Rand kann noch nicht entschieden werden,
+ // ob eine Umrandung der Tabelle noetig/moeglich ist, weil das davon
+ // abhaengt, ob "Filler"-Zellen eingefuegt werden. Hier werden deshalb
+ // erstmal nur Informationen gesammelt
+ //
+ if( 0==nRow && pParent->bTopBorder && bFirstPara )
+ {
+ bTopBorder = sal_True;
+ bFillerTopBorder = sal_True; // auch Filler bekommt eine Umrandung
+ aTopBorderLine = pParent->aTopBorderLine;
+ }
+ if( ((*pParent->pRows)[nRow+nRowSpan-1])->bBottomBorder && bLastPara )
+ {
+ ((*pRows)[nRows-1])->bBottomBorder = sal_True;
+ bFillerBottomBorder = sal_True; // auch Filler bekommt eine Umrandung
+ aBottomBorderLine =
+ nRow+nRowSpan==pParent->nRows ? pParent->aBottomBorderLine
+ : pParent->aBorderLine;
+ }
+
+
+ // Die Child Tabelle darf keinen oberen oder linken Rahmen bekommen,
+ // wenn der bereits durch die umgebende Tabelle gesetzt ist.
+ // Sie darf jedoch immer einen oberen Rand bekommen, wenn die Tabelle
+ // nicht der erste Absatz in der Zelle ist.
+ bTopAlwd = ( !bFirstPara || (pParent->bTopAlwd &&
+ (0==nRow || !((*pParent->pRows)[nRow-1])->bBottomBorder)) );
+
+ // die Child-Tabelle muss die Farbe der Zelle erben, in der sie
+ // vorkommt, wenn sie keine eigene besitzt
+ const SvxBrushItem *pInhBG = pParent->GetCell(nRow,nCol)->GetBGBrush();
+ if( !pInhBG && pParent != pTopTable &&
+ pParent->GetCell(nRow,nCol)->GetRowSpan() == pParent->nRows )
+ {
+ // die ganze umgebende Tabelle ist eine Tabelle in der Tabelle
+ // und besteht nur aus einer Line, die bei der GC (zu Recht)
+ // wegoptimiert wird. Deshalb muss der Hintergrund der Line in
+ // diese Tabelle uebernommen werden.
+ pInhBG = ((*pParent->pRows)[nRow])->GetBGBrush();
+ if( !pInhBG )
+ pInhBG = pParent->GetBGBrush();
+ if( !pInhBG )
+ pInhBG = pParent->GetInhBGBrush();
+ }
+ if( pInhBG )
+ pInhBGBrush = new SvxBrushItem( *pInhBG );
+}
+
+void HTMLTable::InheritVertBorders( const HTMLTable *pParent,
+ sal_uInt16 nCol, sal_uInt16 nColSpan )
+{
+ sal_uInt16 nInhLeftBorderWidth = 0;
+ sal_uInt16 nInhRightBorderWidth = 0;
+
+ if( nCol+nColSpan==pParent->nCols && pParent->bRightBorder )
+ {
+ bInhRightBorder = sal_True; // erstmal nur merken
+ aInhRightBorderLine = pParent->aRightBorderLine;
+ nInhRightBorderWidth =
+ GetBorderWidth( aInhRightBorderLine, sal_True ) + MIN_BORDER_DIST;
+ }
+
+ if( ((*pParent->pColumns)[nCol])->bLeftBorder )
+ {
+ bInhLeftBorder = sal_True; // erstmal nur merken
+ aInhLeftBorderLine = 0==nCol ? pParent->aLeftBorderLine
+ : pParent->aBorderLine;
+ nInhLeftBorderWidth =
+ GetBorderWidth( aInhLeftBorderLine, sal_True ) + MIN_BORDER_DIST;
+ }
+
+ if( !bInhLeftBorder && (bFillerTopBorder || bFillerBottomBorder) )
+ nInhLeftBorderWidth = 2 * MIN_BORDER_DIST;
+ if( !bInhRightBorder && (bFillerTopBorder || bFillerBottomBorder) )
+ nInhRightBorderWidth = 2 * MIN_BORDER_DIST;
+ pLayoutInfo->SetInhBorderWidths( nInhLeftBorderWidth,
+ nInhRightBorderWidth );
+
+ bRightAlwd = ( pParent->bRightAlwd &&
+ (nCol+nColSpan==pParent->nCols ||
+ !((*pParent->pColumns)[nCol+nColSpan])->bLeftBorder) );
+}
+
+void HTMLTable::SetBorders()
+{
+ sal_uInt16 i;
+ for( i=1; i<nCols; i++ )
+ if( HTML_TR_ALL==eRules || HTML_TR_COLS==eRules ||
+ ((HTML_TR_ROWS==eRules || HTML_TR_GROUPS==eRules) &&
+ ((*pColumns)[i-1])->IsEndOfGroup()) )
+ ((*pColumns)[i])->bLeftBorder = sal_True;
+
+ for( i=0; i<nRows-1; i++ )
+ if( HTML_TR_ALL==eRules || HTML_TR_ROWS==eRules ||
+ ((HTML_TR_COLS==eRules || HTML_TR_GROUPS==eRules) &&
+ ((*pRows)[i])->IsEndOfGroup()) )
+ ((*pRows)[i])->bBottomBorder = sal_True;
+
+ if( bTopAlwd && (HTML_TF_ABOVE==eFrame || HTML_TF_HSIDES==eFrame ||
+ HTML_TF_BOX==eFrame) )
+ bTopBorder = sal_True;
+ if( HTML_TF_BELOW==eFrame || HTML_TF_HSIDES==eFrame ||
+ HTML_TF_BOX==eFrame )
+ ((*pRows)[nRows-1])->bBottomBorder = sal_True;
+ if( /*bRightAlwd &&*/ (HTML_TF_RHS==eFrame || HTML_TF_VSIDES==eFrame ||
+ HTML_TF_BOX==eFrame) )
+ bRightBorder = sal_True;
+ if( HTML_TF_LHS==eFrame || HTML_TF_VSIDES==eFrame || HTML_TF_BOX==eFrame )
+ ((*pColumns)[0])->bLeftBorder = sal_True;
+
+ for( i=0; i<nRows; i++ )
+ {
+ HTMLTableRow *pRow = (*pRows)[i];
+ for( sal_uInt16 j=0; j<nCols; j++ )
+ {
+ HTMLTableCell *pCell = pRow->GetCell(j);
+ if( pCell->GetContents() )
+ {
+ HTMLTableCnts *pCnts = pCell->GetContents();
+ sal_Bool bFirstPara = sal_True;
+ while( pCnts )
+ {
+ HTMLTable *pTable = pCnts->GetTable();
+ if( pTable && !pTable->BordersSet() )
+ {
+ pTable->InheritBorders( this, i, j,
+ pCell->GetRowSpan(),
+ pCell->GetColSpan(),
+ bFirstPara,
+ 0==pCnts->Next() );
+ pTable->SetBorders();
+ }
+ bFirstPara = sal_False;
+ pCnts = pCnts->Next();
+ }
+ }
+ }
+ }
+
+ bBordersSet = sal_True;
+}
+
+sal_uInt16 HTMLTable::GetBorderWidth( const SvxBorderLine& rBLine,
+ sal_Bool bWithDistance ) const
+{
+ sal_uInt16 nWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() +
+ rBLine.GetDistance();
+ if( bWithDistance )
+ {
+ if( nCellPadding )
+ nWidth += nCellPadding;
+ else if( nWidth )
+ nWidth += MIN_BORDER_DIST;
+ }
+
+ return nWidth;
+}
+
+inline HTMLTableCell *HTMLTable::GetCell( sal_uInt16 nRow,
+ sal_uInt16 nCell ) const
+{
+ ASSERT( nRow<pRows->Count(),
+ "ungueltiger Zeilen-Index in HTML-Tabelle" );
+ return ((*pRows)[nRow])->GetCell( nCell );
+}
+
+
+
+SvxAdjust HTMLTable::GetInheritedAdjust() const
+{
+ SvxAdjust eAdjust = (nCurCol<nCols ? ((*pColumns)[nCurCol])->GetAdjust()
+ : SVX_ADJUST_END );
+ if( SVX_ADJUST_END==eAdjust )
+ eAdjust = ((*pRows)[nCurRow])->GetAdjust();
+
+ return eAdjust;
+}
+
+SwVertOrient HTMLTable::GetInheritedVertOri() const
+{
+ // VERT_TOP ist der default!
+ SwVertOrient eVOri = ((*pRows)[nCurRow])->GetVertOri();
+ if( VERT_TOP==eVOri && nCurCol<nCols )
+ eVOri = ((*pColumns)[nCurCol])->GetVertOri();
+ if( VERT_TOP==eVOri )
+ eVOri = eVertOri;
+
+ ASSERT( eVertOri != VERT_TOP, "VERT_TOP ist nicht erlaubt!" );
+ return eVOri;
+}
+
+void HTMLTable::InsertCell( HTMLTableCnts *pCnts,
+ sal_uInt16 nRowSpan, sal_uInt16 nColSpan,
+ sal_uInt16 nWidth, sal_Bool bRelWidth, sal_uInt16 nHeight,
+ SwVertOrient eVertOri, SvxBrushItem *pBGBrush,
+ sal_Bool bHasNumFmt, sal_uInt32 nNumFmt,
+ sal_Bool bHasValue, double nValue, sal_Bool bNoWrap )
+{
+ if( !nRowSpan || (sal_uInt32)nCurRow + nRowSpan > USHRT_MAX )
+ nRowSpan = 1;
+
+ if( !nColSpan || (sal_uInt32)nCurCol + nColSpan > USHRT_MAX )
+ nColSpan = 1;
+
+ sal_uInt16 nColsReq = nCurCol + nColSpan; // benoetigte Spalten
+ sal_uInt16 nRowsReq = nCurRow + nRowSpan; // benoetigte Zeilen
+ sal_uInt16 i, j;
+
+ // falls wir mehr Spalten benoetigen als wir zur Zeit haben,
+ // muessen wir in allen Zeilen noch Zellen hinzufuegen
+ if( nCols < nColsReq )
+ {
+ for( i=nCols; i<nColsReq; i++ )
+ pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
+ for( i=0; i<nRows; i++ )
+ ((*pRows)[i])->Expand( nColsReq, i<nCurRow );
+ nCols = nColsReq;
+ ASSERT( pColumns->Count()==nCols,
+ "Anzahl der Spalten nach Expandieren stimmt nicht" );
+ }
+ if( nColsReq > nFilledCols )
+ nFilledCols = nColsReq;
+
+ // falls wir mehr Zeilen benoetigen als wir zur Zeit haben,
+ // muessen wir noch neue Zeilen hinzufuegen
+ if( nRows < nRowsReq )
+ {
+ for( i=nRows; i<nRowsReq; i++ )
+ pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
+ nRows = nRowsReq;
+ ASSERT( nRows==pRows->Count(), "Zeilenzahl in Insert stimmt nicht" );
+ }
+
+ // Testen, ob eine Ueberschneidung vorliegt und diese
+ // gegebenfalls beseitigen
+ sal_uInt16 nSpanedCols = 0;
+ if( nCurRow>0 )
+ {
+ HTMLTableRow *pCurRow = (*pRows)[nCurRow];
+ for( i=nCurCol; i<nColsReq; i++ )
+ {
+ HTMLTableCell *pCell = pCurRow->GetCell(i);
+ if( pCell->GetContents() )
+ {
+ // Der Inhalt reicht von einer weiter oben stehenden Zelle
+ // hier herein. Inhalt und Farbe der Zelle sind deshalb in
+ // jedem Fall noch dort verankert und koennen deshalb
+ // ueberschrieben werden bzw. von ProtectRowSpan geloescht
+ // (Inhalt) oder kopiert (Farbe) werden.
+ nSpanedCols = i + pCell->GetColSpan();
+ FixRowSpan( nCurRow-1, i, pCell->GetContents() );
+ if( pCell->GetRowSpan() > nRowSpan )
+ ProtectRowSpan( nRowsReq, i,
+ pCell->GetRowSpan()-nRowSpan );
+ }
+ }
+ for( i=nColsReq; i<nSpanedCols; i++ )
+ {
+ // Auch diese Inhalte sind in jedem Fall nich in der Zeile
+ // darueber verankert.
+ HTMLTableCell *pCell = pCurRow->GetCell(i);
+ FixRowSpan( nCurRow-1, i, pCell->GetContents() );
+ ProtectRowSpan( nCurRow, i, pCell->GetRowSpan() );
+ }
+ }
+
+ // die Zellen fuellen
+ for( i=nColSpan; i>0; i-- )
+ for( j=nRowSpan; j>0; j-- )
+ GetCell( nRowsReq-j, nColsReq-i )
+ ->Set( pCnts, j, i, eVertOri, pBGBrush,
+ bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap );
+
+ Size aTwipSz( bRelWidth ? 0 : nWidth, nHeight );
+ if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
+ {
+ aTwipSz = Application::GetDefaultDevice()
+ ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
+ }
+
+ // die Breite nur in die erste Zelle setzen!
+ if( nWidth )
+ {
+ sal_uInt16 nTmp = bRelWidth ? nWidth : (sal_uInt16)aTwipSz.Width();
+ GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth );
+ }
+
+ // Ausserdem noch die Hoehe merken
+ if( nHeight && 1==nRowSpan )
+ {
+ if( nHeight < MINLAY )
+ nHeight = MINLAY;
+ ((*pRows)[nCurRow])->SetHeight( (sal_uInt16)aTwipSz.Height() );
+ }
+
+ // den Spaltenzaehler hinter die neuen Zellen setzen
+ nCurCol = nColsReq;
+ if( nSpanedCols > nCurCol )
+ nCurCol = nSpanedCols;
+
+ // und die naechste freie Zelle suchen
+ while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
+ nCurCol++;
+}
+
+inline void HTMLTable::CloseSection( sal_Bool bHead )
+{
+ // die vorhergende Section beenden, falls es schon eine Zeile gibt
+ ASSERT( nCurRow<=nRows, "ungeultige aktuelle Zeile" );
+ if( nCurRow>0 && nCurRow<=nRows )
+ ((*pRows)[nCurRow-1])->SetEndOfGroup();
+ if( bHead /*&& nCurRow==1*/ )
+ bHeadlineRepeat = sal_True;
+}
+
+void HTMLTable::OpenRow( SvxAdjust eAdjust, SwVertOrient eVertOri,
+ SvxBrushItem *pBGBrush )
+{
+ sal_uInt16 nRowsReq = nCurRow+1; // Anzahl benoetigter Zeilen;
+
+ // die naechste Zeile anlegen, falls sie nicht schon da ist
+ if( nRows<nRowsReq )
+ {
+ for( sal_uInt16 i=nRows; i<nRowsReq; i++ )
+ pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
+ nRows = nRowsReq;
+ ASSERT( nRows==pRows->Count(),
+ "Zeilenzahl in OpenRow stimmt nicht" );
+ }
+
+ HTMLTableRow *pCurRow = ((*pRows)[nCurRow]);
+ pCurRow->SetAdjust( eAdjust );
+ pCurRow->SetVertOri( eVertOri );
+ if( pBGBrush )
+ ((*pRows)[nCurRow])->SetBGBrush( pBGBrush );
+
+ // den Spaltenzaehler wieder an den Anfang setzen
+ nCurCol=0;
+
+ // und die naechste freie Zelle suchen
+ while( nCurCol<nCols && GetCell(nCurRow,nCurCol)->IsUsed() )
+ nCurCol++;
+}
+
+void HTMLTable::CloseRow( sal_Bool bEmpty )
+{
+ ASSERT( nCurRow<nRows, "aktulle Zeile hinter dem Tabellenende" );
+
+ // leere Zellen bekommen einfach einen etwas dickeren unteren Rand!
+ if( bEmpty )
+ {
+ if( nCurRow > 0 )
+ ((*pRows)[nCurRow-1])->IncEmptyRows();
+ return;
+ }
+
+ HTMLTableRow *pRow = (*pRows)[nCurRow];
+
+ // den COLSPAN aller leeren Zellen am Zeilenende so anpassen, dass
+ // eine Zelle daraus wird. Das kann man hier machen (und auf keinen
+ // Fall frueher), weill jetzt keine Zellen mehr in die Zeile eingefuegt
+ // werden.
+ sal_uInt16 i=nCols;
+ while( i )
+ {
+ HTMLTableCell *pCell = pRow->GetCell(--i);
+ if( !pCell->GetContents() )
+ {
+ sal_uInt16 nColSpan = nCols-i;
+ if( nColSpan > 1 )
+ pCell->SetColSpan( nColSpan );
+ }
+ else
+ break;
+ }
+
+
+ nCurRow++;
+}
+
+inline void HTMLTable::CloseColGroup( sal_uInt16 nSpan, sal_uInt16 nWidth,
+ sal_Bool bRelWidth, SvxAdjust eAdjust,
+ SwVertOrient eVertOri )
+{
+ if( nSpan )
+ InsertCol( nSpan, nWidth, bRelWidth, eAdjust, eVertOri );
+
+ ASSERT( nCurCol<=nCols, "ungueltige Spalte" );
+ if( nCurCol>0 && nCurCol<=nCols )
+ ((*pColumns)[nCurCol-1])->SetEndOfGroup();
+}
+
+void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth,
+ SvxAdjust eAdjust, SwVertOrient eVertOri )
+{
+ sal_uInt16 i;
+
+ if( !nSpan )
+ nSpan = 1;
+
+ sal_uInt16 nColsReq = nCurCol + nSpan; // benoetigte Spalten
+
+ if( nCols < nColsReq )
+ {
+ for( i=nCols; i<nColsReq; i++ )
+ pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
+ nCols = nColsReq;
+ }
+
+ Size aTwipSz( bRelWidth ? 0 : nWidth, 0 );
+ if( aTwipSz.Width() && Application::GetDefaultDevice() )
+ {
+ aTwipSz = Application::GetDefaultDevice()
+ ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) );
+ }
+
+ for( i=nCurCol; i<nColsReq; i++ )
+ {
+ HTMLTableColumn *pCol = (*pColumns)[i];
+ sal_uInt16 nTmp = bRelWidth ? nWidth : (sal_uInt16)aTwipSz.Width();
+ pCol->SetWidth( nTmp, bRelWidth );
+ pCol->SetAdjust( eAdjust );
+ pCol->SetVertOri( eVertOri );
+ }
+
+ bColSpec = sal_True;
+
+ nCurCol = nColsReq;
+}
+
+
+void HTMLTable::CloseTable()
+{
+ sal_uInt16 i;
+
+ // Die Anzahl der Tabellenzeilen richtet sich nur nach den
+ // <TR>-Elementen (d.h. nach nCurRow). Durch ROWSPAN aufgespannte
+ // Zeilen hinter Zeile nCurRow muessen wir deshalb loeschen
+ // und vor allem aber den ROWSPAN in den darueberliegenden Zeilen
+ // anpassen.
+ if( nRows>nCurRow )
+ {
+ HTMLTableRow *pPrevRow = (*pRows)[nCurRow-1];
+ HTMLTableCell *pCell;
+ for( i=0; i<nCols; i++ )
+ if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1 ) )
+ {
+ FixRowSpan( nCurRow-1, i, pCell->GetContents() );
+ ProtectRowSpan( nCurRow, i, (*pRows)[nCurRow]->GetCell(i)->GetRowSpan() );
+ }
+ for( i=nRows-1; i>=nCurRow; i-- )
+ pRows->DeleteAndDestroy(i);
+ nRows = nCurRow;
+ }
+
+ // falls die Tabelle keine Spalte hat, muessen wir eine hinzufuegen
+ if( 0==nCols )
+ {
+ pColumns->Insert( new HTMLTableColumn, pColumns->Count() );
+ for( i=0; i<nRows; i++ )
+ ((*pRows)[i])->Expand(1);
+ nCols = 1;
+ nFilledCols = 1;
+ }
+
+ // falls die Tabelle keine Zeile hat, muessen wir eine hinzufuegen
+ if( 0==nRows )
+ {
+ pRows->Insert( new HTMLTableRow(nCols), pRows->Count() );
+ nRows = 1;
+ nCurRow = 1;
+ }
+
+ if( nFilledCols < nCols )
+ {
+ pColumns->DeleteAndDestroy( nFilledCols, nCols-nFilledCols );
+ for( i=0; i<nRows; i++ )
+ ((*pRows)[i])->Shrink( nFilledCols );
+ nCols = nFilledCols;
+ }
+}
+
+void HTMLTable::_MakeTable( SwTableBox *pBox )
+{
+ SwTableLines& rLines = (pBox ? pBox->GetTabLines()
+ : ((SwTable *)pSwTable)->GetTabLines() );
+
+ // jetzt geht's richtig los ...
+ sal_uInt16 nStartRow = 0;
+
+ for( sal_uInt16 i=0; i<nRows; i++ )
+ {
+ // kann hinter der aktuellen HTML-Tabellen-Zeile gesplittet werden?
+ sal_Bool bSplit = sal_True;
+ HTMLTableRow *pRow = (*pRows)[i];
+ for( sal_uInt16 j=0; j<nCols; j++ )
+ {
+ bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
+ if( !bSplit )
+ break;
+ }
+
+ if( bSplit )
+ {
+ SwTableLine *pLine = MakeTableLine( pBox, nStartRow, 0, i+1, nCols );
+ if( pBox || nStartRow>0 )
+ {
+ rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
+ }
+ nStartRow = i+1;
+ }
+ }
+}
+
+/* Wie werden Tabellen ausgerichtet?
+
+erste Zeile: ohne Absatz-Einzuege
+zweite Zeile: mit Absatz-Einzuegen
+
+ALIGN= LEFT RIGHT CENTER -
+-------------------------------------------------------------------------
+xxx bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
+xxx nn = 100 HORI_FULL HORI_FULL HORI_FULL HORI_FULL %
+xxx HORI_NONE HORI_NONE HORI_NONE % HORI_NONE %
+xxx nn < 100 Rahmen F Rahmen F HORI_CENTER % HORI_LEFT %
+xxx Rahmen F Rahmen F HORI_CENTER % HORI_NONE %
+
+bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung:
+nn = 100 HORI_LEFT HORI_RIGHT HORI_CENTER % HORI_LEFT %
+ HORI_LEFT_AND HORI_RIGHT HORI_CENTER % HORI_LEFT_AND %
+nn < 100 Rahmen F Rahmen F HORI_CENTER % HORI_LEFT %
+ Rahmen F Rahmen F HORI_CENTER % HORI_NONE %
+
+sonst die berechnete Breite w
+w = avail* HORI_LEFT HORI_RIGHT HORI_CENTER HORI_LEFT
+ HORI_LEDT_AND HORI_RIGHT HORI_CENTER HORI_LEFT_AND
+w < avail Rahmen L Rahmen L HORI_CENTER HORI_LEFT
+ Rahmen L Rahmen L HORI_CENTER HORI_NONE
+
+xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer
+xxx HORI_FULL genommen
+
+*/
+
+void HTMLTable::MakeTable( SwTableBox *pBox, sal_uInt16 nAbsAvail,
+ sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace,
+ sal_uInt16 nAbsRightSpace, sal_uInt16 nInhAbsSpace )
+{
+ ASSERT( nRows>0 && nCols>0 && nCurRow==nRows,
+ "Wurde CloseTable nicht aufgerufen?" );
+
+ ASSERT( (pLayoutInfo==0) == (this==pTopTable),
+ "Top-Tabelle hat keine Layout-Info oder umgekehrt" );
+
+ if( this==pTopTable )
+ {
+ // Umrandung der Tabelle und aller in ihr enthaltenen berechnen
+ SetBorders();
+
+ // Schritt 1: Die benoetigten Layout-Strukturen werden angelegt
+ // (inklusive Tabellen in Tabellen).
+ CreateLayoutInfo();
+
+ // Schritt 2: Die minimalen und maximalen Spaltenbreiten werden
+ // berechnet (inklusive Tabellen in Tabellen). Da wir noch keine
+ // Boxen haben, arabeiten wir noch auf den Start-Nodes.
+ pLayoutInfo->AutoLayoutPass1();
+ }
+
+ // Schritt 3: Die tatsaechlichen Spaltenbreiten dieser Tabelle werden
+ // berechnet (nicht von Tabellen in Tabellen). Dies muss jetzt schon
+ // sein, damit wir entscheiden koennen ob Filler-Zellen benoetigt werden
+ // oder nicht (deshalb war auch Pass1 schon noetig).
+ pLayoutInfo->AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace,
+ nAbsRightSpace, nInhAbsSpace );
+
+ if( this!=pTopTable )
+ {
+ // die linke und rechte Umrandung der Tabelle kann jetzt entgueltig
+ // festgelegt werden
+ if( pLayoutInfo->GetRelRightFill() == 0 )
+ {
+ if( !bRightBorder )
+ {
+ // linke Umrandung von auesserer Tabelle uebernehmen
+ if( bInhRightBorder )
+ {
+ bRightBorder = sal_True;
+ aRightBorderLine = aInhRightBorderLine;
+ }
+ }
+ else
+ {
+ // Umrandung nur setzen, wenn es erlaubt ist
+ bRightBorder = bRightAlwd;
+ }
+ }
+
+ if( pLayoutInfo->GetRelLeftFill() == 0 &&
+ !((*pColumns)[0])->bLeftBorder &&
+ bInhLeftBorder )
+ {
+ // ggf. rechte Umrandung von auesserer Tabelle uebernehmen
+ ((*pColumns)[0])->bLeftBorder = sal_True;
+ aLeftBorderLine = aInhLeftBorderLine;
+ }
+ }
+
+ // Fuer die Top-Table muss die Ausrichtung gesetzt werden
+ if( this==pTopTable )
+ {
+ SwHoriOrient eHoriOri;
+ if( bForceFrame )
+ {
+ // Die Tabelle soll in einen Rahmen und ist auch schmaler
+ // als der verfuegbare Platz und nicht 100% breit.
+ // Dann kommt sie in einen Rahmen
+ eHoriOri = bPrcWidth ? HORI_FULL : HORI_LEFT;
+ }
+ else switch( eTableAdjust )
+ {
+ // Die Tabelle passt entweder auf die Seite, soll aber in keinen
+ // Rahmen oder sie ist Breiter als die Seite und soll deshalb
+ // in keinen Rahmen
+
+ case SVX_ADJUST_RIGHT:
+ // in rechtsbuendigen Tabellen kann nicht auf den rechten
+ // Rand Ruecksicht genommen werden
+ eHoriOri = HORI_RIGHT;
+ break;
+ case SVX_ADJUST_CENTER:
+ // zentrierte Tabellen nehmen keine Ruecksicht auf Raender!
+ eHoriOri = HORI_CENTER;
+ break;
+ case SVX_ADJUST_LEFT:
+ default:
+ // linksbuendige Tabellen nehmen nur auf den linken Rand
+ // Ruecksicht
+ eHoriOri = nLeftMargin ? HORI_LEFT_AND_WIDTH : HORI_LEFT;
+ break;
+ }
+
+ // das Tabellenform holen und anpassen
+ SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
+ pFrmFmt->SetAttr( SwFmtHoriOrient(0,eHoriOri) );
+ if( HORI_LEFT_AND_WIDTH==eHoriOri )
+ {
+ ASSERT( nLeftMargin || nRightMargin,
+ "Da gibt's wohl noch Reste von relativen Breiten" );
+
+ // The right margin will be ignored anyway.
+ SvxLRSpaceItem aLRItem( pSwTable->GetFrmFmt()->GetLRSpace() );
+ aLRItem.SetLeft( nLeftMargin );
+ aLRItem.SetRight( nRightMargin );
+ pFrmFmt->SetAttr( aLRItem );
+ }
+
+ if( bPrcWidth && HORI_FULL!=eHoriOri )
+ {
+ pFrmFmt->LockModify();
+ SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
+ aFrmSize.SetWidthPercent( (sal_uInt8)nWidth );
+ pFrmFmt->SetAttr( aFrmSize );
+ pFrmFmt->UnlockModify();
+ }
+ }
+
+ // die Default Line- und Box-Formate holen
+ if( this==pTopTable )
+ {
+ // die erste Box merken und aus der ersten Zeile ausketten
+ SwTableLine *pLine1 = (pSwTable->GetTabLines())[0];
+ pBox1 = (pLine1->GetTabBoxes())[0];
+ pLine1->GetTabBoxes().Remove(0);
+
+ pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
+ pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
+ }
+ else
+ {
+ pLineFmt = (SwTableLineFmt*)pTopTable->pLineFmt;
+ pBoxFmt = (SwTableBoxFmt*)pTopTable->pBoxFmt;
+ }
+
+ // ggf. muessen fuer Tabellen in Tabellen "Filler"-Zellen eingefuegt
+ // werden
+ if( this != pTopTable &&
+ ( pLayoutInfo->GetRelLeftFill() > 0 ||
+ pLayoutInfo->GetRelRightFill() > 0 ) )
+ {
+ ASSERT( pBox, "kein TableBox fuer Tabelle in Tabelle" );
+
+ SwTableLines& rLines = pBox->GetTabLines();
+
+ // dazu brauchen wir erstmal ein eine neue Table-Line in der Box
+ SwTableLine *pLine =
+ new SwTableLine( pLineFrmFmtNoHeight ? pLineFrmFmtNoHeight
+ : pLineFmt, 0, pBox );
+ rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
+
+ // Sicherstellen, dass wie ein Format ohne Hoehe erwischt haben
+ if( !pLineFrmFmtNoHeight )
+ {
+ // sonst muessen wir die Hoehe aus dem Attribut entfernen
+ // und koennen uns das Format merken
+ pLineFrmFmtNoHeight = (SwTableLineFmt*)pLine->ClaimFrmFmt();
+
+ ResetLineFrmFmtAttrs( pLineFrmFmtNoHeight );
+ }
+
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ SwTableBox *pNewBox;
+
+ // ggf. links eine Zelle einfuegen
+ if( pLayoutInfo->GetRelLeftFill() > 0 )
+ {
+ // pPrevStNd ist der Vorgaenger-Start-Node der Tabelle. Den
+ // "Filler"-Node fuegen wir einfach dahinter ein ...
+ pPrevStNd = pParser->InsertTableSection( pPrevStNd );
+
+ pNewBox = NewTableBox( pPrevStNd, pLine );
+ rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
+ FixFillerFrameFmt( pNewBox, sal_False );
+ pLayoutInfo->SetLeftFillerBox( pNewBox );
+ }
+
+ // jetzt die Tabelle bearbeiten
+ pNewBox = new SwTableBox( pBoxFmt, 0, pLine );
+ rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
+
+ SwFrmFmt *pFrmFmt = pNewBox->ClaimFrmFmt();
+ pFrmFmt->ResetAttr( RES_BOX );
+ pFrmFmt->ResetAttr( RES_BACKGROUND );
+ pFrmFmt->ResetAttr( RES_VERT_ORIENT );
+ pFrmFmt->ResetAttr( RES_BOXATR_FORMAT );
+
+
+ _MakeTable( pNewBox );
+
+ // und noch ggf. rechts eine Zelle einfuegen
+ if( pLayoutInfo->GetRelRightFill() > 0 )
+ {
+ const SwStartNode *pStNd =
+ GetPrevBoxStartNode( USHRT_MAX, USHRT_MAX );
+ pStNd = pParser->InsertTableSection( pStNd );
+
+ pNewBox = NewTableBox( pStNd, pLine );
+ rBoxes.C40_INSERT( SwTableBox, pNewBox, rBoxes.Count() );
+
+ FixFillerFrameFmt( pNewBox, sal_True );
+ pLayoutInfo->SetRightFillerBox( pNewBox );
+ }
+ }
+ else
+ {
+ _MakeTable( pBox );
+ }
+
+ // zum Schluss fuehren wir noch eine Garbage-Collection fuer die
+ // Top-Level-Tabelle durch
+ if( this==pTopTable )
+ {
+ if( 1==nRows && nHeight && 1==pSwTable->GetTabLines().Count() )
+ {
+ // Hoehe einer einzeiligen Tabelle als Mindesthoehe der
+ // Zeile setzen. (War mal fixe Hoehe, aber das gibt manchmal
+ // Probleme (fix #34972#) und ist auch nicht Netscape 4.0
+ // konform
+ nHeight = pParser->ToTwips( nHeight );
+ if( nHeight < MINLAY )
+ nHeight = MINLAY;
+
+ (pSwTable->GetTabLines())[0]->ClaimFrmFmt();
+ (pSwTable->GetTabLines())[0]->GetFrmFmt()
+ ->SetAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) );
+ }
+
+ if( GetBGBrush() )
+ pSwTable->GetFrmFmt()->SetAttr( *GetBGBrush() );
+
+ ((SwTable *)pSwTable)->SetHeadlineRepeat( bHeadlineRepeat );
+ ((SwTable *)pSwTable)->GCLines();
+
+ sal_Bool bIsInFlyFrame = pContext && pContext->GetFrmFmt();
+ if( bIsInFlyFrame && !nWidth )
+ {
+ SvxAdjust eTblAdjust = GetTableAdjust(sal_False);
+ if( eTblAdjust != SVX_ADJUST_LEFT &&
+ eTblAdjust != SVX_ADJUST_RIGHT )
+ {
+ // Wenn eine Tabelle ohne Breitenangabe nicht links oder
+ // rechts umflossen werden soll, dann stacken wir sie
+ // in einem Rahmen mit 100%-Breite, damit ihre Groesse
+ // angepasst wird. Der Rahmen darf nicht angepasst werden.
+ ASSERT( HasToFly(), "Warum ist die Tabelle in einem Rahmen?" );
+ sal_uInt32 nMin = pLayoutInfo->GetMin();
+ if( nMin > USHRT_MAX )
+ nMin = USHRT_MAX;
+ SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMin, MINLAY );
+ aFlyFrmSize.SetWidthPercent( 100 );
+ pContext->GetFrmFmt()->SetAttr( aFlyFrmSize );
+ bIsInFlyFrame = sal_False;
+ }
+ else
+ {
+ // Links und rechts ausgerichtete Tabellen ohne Breite
+ // duerfen leider nicht in der Breite angepasst werden, denn
+ // sie wuerden nur schrumpfen aber nie wachsen.
+ pLayoutInfo->SetMustNotRecalc( sal_True );
+ if( pContext->GetFrmFmt()->GetAnchor().GetCntntAnchor()
+ ->nNode.GetNode().FindTableNode() )
+ {
+ sal_uInt32 nMax = pLayoutInfo->GetMax();
+ if( nMax > USHRT_MAX )
+ nMax = USHRT_MAX;
+ SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, (SwTwips)nMax, MINLAY );
+ pContext->GetFrmFmt()->SetAttr( aFlyFrmSize );
+ bIsInFlyFrame = sal_False;
+ }
+ else
+ {
+ pLayoutInfo->SetMustNotResize( sal_True );
+ }
+ }
+ }
+ pLayoutInfo->SetMayBeInFlyFrame( bIsInFlyFrame );
+
+ // Nur Tabellen mit relativer Breite oder ohne Breite muessen
+ // angepasst werden.
+ pLayoutInfo->SetMustResize( bPrcWidth || !nWidth );
+
+ pLayoutInfo->SetWidths();
+
+ ((SwTable *)pSwTable)->SetHTMLTableLayout( pLayoutInfo );
+
+ if( pResizeDrawObjs )
+ {
+ sal_uInt16 nCount = pResizeDrawObjs->Count();
+ for( sal_uInt16 i=0; i<nCount; i++ )
+ {
+ SdrObject *pObj = (*pResizeDrawObjs)[i];
+ sal_uInt16 nRow = (*pDrawObjPrcWidths)[3*i];
+ sal_uInt16 nCol = (*pDrawObjPrcWidths)[3*i+1];
+ sal_uInt8 nPrcWidth = (sal_uInt8)(*pDrawObjPrcWidths)[3*i+2];
+
+ SwHTMLTableLayoutCell *pLayoutCell =
+ pLayoutInfo->GetCell( nRow, nCol );
+ sal_uInt16 nColSpan = pLayoutCell->GetColSpan();
+
+ sal_uInt16 nWidth, nDummy;
+ pLayoutInfo->GetAvail( nCol, nColSpan, nWidth, nDummy );
+ nWidth -= pLayoutInfo->GetLeftCellSpace( nCol, nColSpan );
+ nWidth -= pLayoutInfo->GetRightCellSpace( nCol, nColSpan );
+ nWidth = ((long)nWidth * nPrcWidth) / 100;
+
+ pParser->ResizeDrawObject( pObj, nWidth );
+ }
+ }
+ }
+}
+
+void HTMLTable::SetTable( const SwStartNode *pStNd, _HTMLTableContext *pCntxt,
+ sal_uInt16 nLeft, sal_uInt16 nRight,
+ const SwTable *pSwTab, sal_Bool bFrcFrame )
+{
+ pPrevStNd = pStNd;
+ pSwTable = pSwTab;
+ pContext = pCntxt;
+
+ nLeftMargin = nLeft;
+ nRightMargin = nRight;
+
+ bForceFrame = bFrcFrame;
+}
+
+void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth )
+{
+ if( !pResizeDrawObjs )
+ pResizeDrawObjs = new SdrObjects;
+ pResizeDrawObjs->C40_INSERT( SdrObject, pObj, pResizeDrawObjs->Count() );
+
+ if( !pDrawObjPrcWidths )
+ pDrawObjPrcWidths = new SvUShorts;
+ pDrawObjPrcWidths->Insert( nCurRow, pDrawObjPrcWidths->Count() );
+ pDrawObjPrcWidths->Insert( nCurCol, pDrawObjPrcWidths->Count() );
+ pDrawObjPrcWidths->Insert( (sal_uInt16)nPrcWidth, pDrawObjPrcWidths->Count() );
+}
+
+void HTMLTable::MakeParentContents()
+{
+ if( !GetContext() && !HasParentSection() )
+ {
+ SetParentContents(
+ pParser->InsertTableContents( GetIsParentHeader() ) );
+
+ SetHasParentSection( sal_True );
+ }
+}
+
+_HTMLTableContext::~_HTMLTableContext()
+{
+ delete pPos;
+}
+
+void _HTMLTableContext::SavePREListingXMP( SwHTMLParser& rParser )
+{
+ bRestartPRE = rParser.IsReadPRE();
+ bRestartXMP = rParser.IsReadXMP();
+ bRestartListing = rParser.IsReadListing();
+ rParser.FinishPREListingXMP();
+}
+
+void _HTMLTableContext::RestorePREListingXMP( SwHTMLParser& rParser )
+{
+ rParser.FinishPREListingXMP();
+
+ if( bRestartPRE )
+ rParser.StartPRE();
+
+ if( bRestartXMP )
+ rParser.StartXMP();
+
+ if( bRestartListing )
+ rParser.StartListing();
+}
+
+/* */
+
+const SwStartNode *SwHTMLParser::InsertTableSection
+ ( const SwStartNode *pPrevStNd )
+{
+ ASSERT( pPrevStNd, "Start-Node ist NULL" );
+
+ pCSS1Parser->SetTDTagStyles();
+ SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TABLE );
+
+ const SwStartNode *pStNd;
+ if( pTable && pTable->bFirstCell )
+ {
+ SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ pNd->GetTxtNode()->ChgFmtColl( pColl );
+ pStNd = pNd->FindTableBoxStartNode();
+ pTable->bFirstCell = sal_False;
+ }
+ else
+ {
+ const SwNode* pNd;
+ if( pPrevStNd->IsTableNode() )
+ pNd = pPrevStNd;
+ else
+ pNd = pPrevStNd->EndOfSectionNode();
+ SwNodeIndex nIdx( *pNd, 1 );
+ pStNd = pDoc->GetNodes().MakeTextSection( nIdx, SwTableBoxStartNode,
+ pColl );
+ pTable->IncBoxCount();
+ }
+
+ pDoc->GetNodes()[pStNd->GetIndex()+1]
+ ->GetCntntNode()->SetAttr( SvxFontHeightItem(40) );
+
+ return pStNd;
+}
+
+const SwStartNode *SwHTMLParser::InsertTableSection( sal_uInt16 nPoolId )
+{
+ switch( nPoolId )
+ {
+ case RES_POOLCOLL_TABLE_HDLN:
+ pCSS1Parser->SetTHTagStyles();
+ break;
+ case RES_POOLCOLL_TABLE:
+ pCSS1Parser->SetTDTagStyles();
+ break;
+ }
+
+ SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( nPoolId );
+
+ SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ const SwStartNode *pStNd;
+ if( pTable && pTable->bFirstCell )
+ {
+ pNd->GetTxtNode()->ChgFmtColl( pColl );
+ pTable->bFirstCell = sal_False;
+ pStNd = pNd->FindTableBoxStartNode();
+ }
+ else
+ {
+ SwTableNode *pTblNd = pNd->FindTableNode();
+ SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
+ pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
+ pColl );
+
+ pPam->GetPoint()->nNode = pStNd->GetIndex() + 1;
+ SwTxtNode *pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
+ pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
+ pTable->IncBoxCount();
+ }
+
+ return pStNd;
+}
+
+const SwStartNode *SwHTMLParser::InsertEmptyTableSection()
+{
+ ASSERT( !pTable || !pTable->bFirstCell,
+ "erste Zelle der Tabelle nicht genutzt" );
+
+ const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ const SwTableNode *pTblNd = pNd->FindTableNode();
+ pTable->IncBoxCount();
+
+ return pDoc->GetNodes().MakeEmptySection(
+ SwNodeIndex( *pTblNd->EndOfSectionNode() ), SwTableBoxStartNode );
+}
+
+SwStartNode *SwHTMLParser::InsertTempTableCaptionSection()
+{
+ SwTxtFmtColl *pColl = pCSS1Parser->GetTxtCollFromPool( RES_POOLCOLL_TEXT );
+ SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
+ rIdx = pDoc->GetNodes().GetEndOfExtras();
+ SwStartNode *pStNd = pDoc->GetNodes().MakeTextSection( rIdx,
+ SwNormalStartNode, pColl );
+
+ rIdx = pStNd->GetIndex() + 1;
+ pPam->GetPoint()->nContent.Assign( rIdx.GetNode().GetTxtNode(), 0 );
+
+ return pStNd;
+}
+
+
+xub_StrLen SwHTMLParser::StripTrailingLF()
+{
+ xub_StrLen nStripped = 0;
+
+ xub_StrLen nLen = pPam->GetPoint()->nContent.GetIndex();
+ if( nLen )
+ {
+ SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
+ // vorsicht, wenn Kommentare nicht uebrlesen werden!!!
+ if( pTxtNd )
+ {
+ xub_StrLen nPos = nLen;
+ xub_StrLen nLFCount = 0;
+ while( nPos && '\x0a' == (pTxtNd->GetTxt()).GetChar(--nPos) )
+ nLFCount++;
+
+ if( nLFCount )
+ {
+// MIB 6.6.97: Warum sollte man bei leeren Absaetzen nur ein LF loeschen?
+// Das stimmt doch irgendwi nicht ...
+// if( nLFCount == nLen )
+// {
+// // nur Lfs, dann nur ein LF loeschen
+// nLFCount = 1;
+// }
+// else if( nLFCount > 2 )
+ if( nLFCount > 2 )
+ {
+ // Bei Netscape entspricht ein Absatz-Ende zwei LFs
+ // (mit einem kommt man in die naechste Zeile, das
+ // zweite erzeugt eine Leerzeile) Diesen Abstand
+ // erreichen wie aber schon mit dem unteren
+ // Absatz-Abstand. Wenn nach den <BR> ein neuer
+ // Absatz aufgemacht wird, wird das Maximum des Abstands,
+ // der sich aus den BR und dem P ergibt genommen.
+ // Deshalb muessen wir 2 bzw. alle bei weniger
+ // als zweien loeschen
+ nLFCount = 2;
+ }
+
+ nPos = nLen - nLFCount;
+ SwIndex nIdx( pTxtNd, nPos );
+ pTxtNd->Erase( nIdx, nLFCount );
+ nStripped = nLFCount;
+ }
+ }
+ }
+
+ return nStripped;
+}
+
+SvxBrushItem* SwHTMLParser::CreateBrushItem( const Color *pColor,
+ const String& rImageURL,
+ const String& rStyle,
+ const String& rId,
+ const String& rClass )
+{
+ SvxBrushItem *pBrushItem = 0;
+
+ if( rStyle.Len() || rId.Len() || rClass.Len() )
+ {
+ SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_BACKGROUND,
+ RES_BACKGROUND );
+ SvxCSS1PropertyInfo aPropInfo;
+
+ if( rClass.Len() )
+ {
+ SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( rClass );
+ if( pClass )
+ aItemSet.Put( pClass->GetItemSet() );
+ }
+
+ if( rId.Len() )
+ {
+ SvxCSS1MapEntry *pId = pCSS1Parser->GetId( rId );
+ if( pId )
+ aItemSet.Put( pId->GetItemSet() );
+ }
+
+ pCSS1Parser->ParseStyleOption( rStyle, aItemSet, aPropInfo );
+ const SfxPoolItem *pItem = 0;
+ if( SFX_ITEM_SET == aItemSet.GetItemState( RES_BACKGROUND, sal_False,
+ &pItem ) )
+ {
+ pBrushItem = new SvxBrushItem( *((const SvxBrushItem *)pItem) );
+ }
+ }
+
+ if( !pBrushItem && (pColor || rImageURL.Len()) )
+ {
+ pBrushItem = new SvxBrushItem();
+
+ if( pColor )
+ pBrushItem->SetColor(*pColor);
+
+ if( rImageURL.Len() )
+ {
+ pBrushItem->SetGraphicLink( INetURLObject::RelToAbs(rImageURL) );
+ pBrushItem->SetGraphicPos( GPOS_TILED );
+ }
+ }
+
+ return pBrushItem;
+}
+
+/* */
+
+class _SectionSaveStruct : public SwPendingStackData
+{
+ sal_uInt16 nBaseFontStMinSave, nFontStMinSave, nFontStHeadStartSave;
+ sal_uInt16 nDefListDeepSave, nContextStMinSave, nContextStAttrMinSave;
+
+public:
+
+ HTMLTable *pTable;
+
+ _SectionSaveStruct( SwHTMLParser& rParser );
+ virtual ~_SectionSaveStruct();
+
+ sal_uInt16 GetContextStAttrMin() const { return nContextStAttrMinSave; }
+
+ void Restore( SwHTMLParser& rParser );
+};
+
+_SectionSaveStruct::_SectionSaveStruct( SwHTMLParser& rParser ) :
+ nBaseFontStMinSave(0), nFontStMinSave(0), nFontStHeadStartSave(0),
+ nDefListDeepSave(0), nContextStMinSave(0), nContextStAttrMinSave(0),
+ pTable( 0 )
+{
+ // Font-Stacks einfrieren
+ nBaseFontStMinSave = rParser.nBaseFontStMin;
+ rParser.nBaseFontStMin = rParser.aBaseFontStack.Count();
+
+ nFontStMinSave = rParser.nFontStMin;
+ nFontStHeadStartSave = rParser.nFontStHeadStart;
+ rParser.nFontStMin = rParser.aFontStack.Count();
+
+ // Kontext-Stack einfrieren
+ nContextStMinSave = rParser.nContextStMin;
+ nContextStAttrMinSave = rParser.nContextStAttrMin;
+ rParser.nContextStMin = rParser.aContexts.Count();
+ rParser.nContextStAttrMin = rParser.nContextStMin;
+
+ // und noch ein par Zaehler retten
+ nDefListDeepSave = rParser.nDefListDeep;
+ rParser.nDefListDeep = 0;
+}
+
+_SectionSaveStruct::~_SectionSaveStruct()
+{}
+
+void _SectionSaveStruct::Restore( SwHTMLParser& rParser )
+{
+ // Font-Stacks wieder auftauen
+ sal_uInt16 nMin = rParser.nBaseFontStMin;
+ if( rParser.aBaseFontStack.Count() > nMin )
+ rParser.aBaseFontStack.Remove( nMin,
+ rParser.aBaseFontStack.Count() - nMin );
+ rParser.nBaseFontStMin = nBaseFontStMinSave;
+
+
+ nMin = rParser.nFontStMin;
+ if( rParser.aFontStack.Count() > nMin )
+ rParser.aFontStack.Remove( nMin,
+ rParser.aFontStack.Count() - nMin );
+ rParser.nFontStMin = nFontStMinSave;
+ rParser.nFontStHeadStart = nFontStHeadStartSave;
+
+ // Der Kontext-Stack muss schon aufgeraeumt sein!
+ ASSERT( rParser.aContexts.Count() == rParser.nContextStMin &&
+ rParser.aContexts.Count() == rParser.nContextStAttrMin,
+ "Der Kontext-Stack wurde nicht aufgeraeumt" );
+ rParser.nContextStMin = nContextStMinSave;
+ rParser.nContextStAttrMin = nContextStAttrMinSave;
+
+ // und noch ein par Zaehler rekonstruieren
+ rParser.nDefListDeep = nDefListDeepSave;
+
+ // und ein par Flags zuruecksetzen
+ rParser.bNoParSpace = sal_False;
+ rParser.nOpenParaToken = 0;
+
+ if( rParser.aParaAttrs.Count() )
+ rParser.aParaAttrs.Remove( 0, rParser.aParaAttrs.Count() );
+}
+
+/* */
+
+class _CellSaveStruct : public _SectionSaveStruct
+{
+ String aStyle, aId, aClass;
+ String aBGImage;
+ Color aBGColor;
+
+ HTMLTableCnts* pCnts; // Liste aller Inhalte
+ HTMLTableCnts* pCurrCnts; // der aktuelle Inhalt oder 0
+ SwNodeIndex *pNoBreakEndParaIdx;// Absatz-Index eines </NOBR>
+
+ double nValue;
+
+ sal_uInt32 nNumFmt;
+
+ sal_uInt16 nRowSpan, nColSpan, nWidth, nHeight;
+ xub_StrLen nNoBreakEndCntntPos; // Zeichen-Index eines </NOBR>
+
+ SvxAdjust eAdjust;
+ SwVertOrient eVertOri;
+
+ sal_Bool bHead : 1;
+ sal_Bool bPrcWidth : 1;
+ sal_Bool bHasNumFmt : 1;
+ sal_Bool bHasValue : 1;
+ sal_Bool bBGColor : 1;
+ sal_Bool bNoWrap : 1; // NOWRAP-Option
+ sal_Bool bNoBreak : 1; // NOBREAK-Tag
+
+public:
+
+ _CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable, sal_Bool bHd,
+ sal_Bool bReadOpt );
+
+ virtual ~_CellSaveStruct();
+
+ void AddContents( HTMLTableCnts *pNewCnts );
+ HTMLTableCnts *GetFirstContents() { return pCnts; }
+
+ void ClearIsInSection() { pCurrCnts = 0; }
+ sal_Bool IsInSection() const { return pCurrCnts!=0; }
+ HTMLTableCnts *GetCurrContents() const { return pCurrCnts; }
+
+ void InsertCell( SwHTMLParser& rParser, HTMLTable *pCurTable );
+
+ sal_Bool IsHeaderCell() const { return bHead; }
+
+ void StartNoBreak( const SwPosition& rPos );
+ void EndNoBreak( const SwPosition& rPos );
+ void CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc );
+};
+
+
+_CellSaveStruct::_CellSaveStruct( SwHTMLParser& rParser, HTMLTable *pCurTable,
+ sal_Bool bHd, sal_Bool bReadOpt ) :
+ _SectionSaveStruct( rParser ),
+ pCnts( 0 ), pCurrCnts( 0 ), pNoBreakEndParaIdx( 0 ),
+ nValue( 0.0 ),
+ nNumFmt( 0 ),
+ nRowSpan( 1 ), nColSpan( 1 ), nWidth( 0 ), nHeight( 0 ),
+ nNoBreakEndCntntPos( 0 ),
+ eAdjust( pCurTable->GetInheritedAdjust() ),
+ bHead( bHd ),
+ eVertOri( pCurTable->GetInheritedVertOri() ),
+ bPrcWidth( sal_False ), bBGColor( sal_False ),
+ bHasNumFmt( sal_False ), bHasValue( sal_False ),
+ bNoWrap( sal_False ), bNoBreak( sal_False )
+{
+ String aNumFmt, aValue;
+
+ if( bReadOpt )
+ {
+ const HTMLOptions *pOptions = rParser.GetOptions();
+ for( sal_uInt16 i = pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*pOptions)[--i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_ID:
+ aId = pOption->GetString();
+ break;
+ case HTML_O_COLSPAN:
+ nColSpan = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_ROWSPAN:
+ nRowSpan = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_ALIGN:
+ eAdjust = (SvxAdjust)pOption->GetEnum(
+ aHTMLPAlignTable, eAdjust );
+ break;
+ case HTML_O_VALIGN:
+ eVertOri = (SwVertOrient)pOption->GetEnum(
+ aHTMLTblVAlignTable, eVertOri );
+ break;
+ case HTML_O_WIDTH:
+ nWidth = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
+ bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
+ if( bPrcWidth && nWidth>100 )
+ nWidth = 100;
+ break;
+ case HTML_O_HEIGHT:
+ nHeight = (sal_uInt16)pOption->GetNumber(); // nur fuer Netscape
+ if( pOption->GetString().Search('%') != STRING_NOTFOUND)
+ nHeight = 0; // keine %-Angaben beruecksichtigen
+ break;
+ case HTML_O_BGCOLOR:
+ // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
+ // ignorieren, bei allen anderen Tags *wirklich* nicht.
+ if( pOption->GetString().Len() )
+ {
+ pOption->GetColor( aBGColor );
+ bBGColor = sal_True;
+ }
+ break;
+ case HTML_O_BACKGROUND:
+ aBGImage = pOption->GetString();
+ break;
+ case HTML_O_STYLE:
+ aStyle = pOption->GetString();
+ break;
+ case HTML_O_CLASS:
+ aClass = pOption->GetString();
+ break;
+ case HTML_O_SDNUM:
+ aNumFmt = pOption->GetString();
+ bHasNumFmt = sal_True;
+ break;
+ case HTML_O_SDVAL:
+ bHasValue = sal_True;
+ aValue = pOption->GetString();
+ break;
+ case HTML_O_NOWRAP:
+ bNoWrap = sal_True;
+ break;
+ }
+ }
+
+ if( aId.Len() )
+ rParser.InsertBookmark( aId );
+ }
+
+ if( bHasNumFmt )
+ {
+ LanguageType eLang;
+ nValue = rParser.GetTableDataOptionsValNum(
+ nNumFmt, eLang, aValue, aNumFmt,
+ *rParser.pDoc->GetNumberFormatter() );
+ }
+
+ // einen neuen Kontext anlegen, aber das ::com::sun::star::drawing::Alignment-Attribut
+ // nicht dort verankern, weil es noch ger keine Section gibt, in der
+ // es gibt.
+ sal_uInt16 nToken, nColl;
+ if( bHead )
+ {
+ nToken = HTML_TABLEHEADER_ON;
+ nColl = RES_POOLCOLL_TABLE_HDLN;
+ }
+ else
+ {
+ nToken = HTML_TABLEDATA_ON;
+ nColl = RES_POOLCOLL_TABLE;
+ }
+ _HTMLAttrContext *pCntxt = new _HTMLAttrContext( nToken, nColl, aEmptyStr, sal_True );
+ if( SVX_ADJUST_END != eAdjust )
+ rParser.InsertAttr( &rParser.aAttrTab.pAdjust, SvxAdjustItem(eAdjust),
+ pCntxt );
+
+ if( rParser.HasStyleOptions( aStyle, aId, aClass ) )
+ {
+ SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(),
+ rParser.pCSS1Parser->GetWhichMap() );
+ SvxCSS1PropertyInfo aPropInfo;
+
+ if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet,
+ aPropInfo ) )
+ rParser.InsertAttrs( aItemSet, aPropInfo, pCntxt );
+ }
+
+ rParser.SplitPREListingXMP( pCntxt );
+
+ rParser.PushContext( pCntxt );
+}
+
+_CellSaveStruct::~_CellSaveStruct()
+{
+ delete pNoBreakEndParaIdx;
+}
+
+void _CellSaveStruct::AddContents( HTMLTableCnts *pNewCnts )
+{
+ if( pCnts )
+ pCnts->Add( pNewCnts );
+ else
+ pCnts = pNewCnts;
+
+ pCurrCnts = pNewCnts;
+}
+
+void _CellSaveStruct::InsertCell( SwHTMLParser& rParser,
+ HTMLTable *pCurTable )
+{
+#ifndef PRODUCT
+ // Die Attribute muessen schon beim Auefrauemen des Kontext-Stacks
+ // entfernt worden sein, sonst ist etwas schiefgelaufen. Das
+ // Checken wir mal eben ...
+ // MIB 8.1.98: Wenn ausserhalb einer Zelle Attribute geoeffnet
+ // wurden stehen diese noch in der Attribut-Tabelle und werden erst
+ // ganz zum Schluss durch die CleanContext-Aufrufe in BuildTable
+ // geloescht. Damit es in diesem Fall keine Asserts gibt findet dann
+ // keine Ueberpruefung statt. Erkennen tut man diesen Fall an
+ // nContextStAttrMin: Der gemerkte Wert nContextStAttrMinSave ist der
+ // Wert, den nContextStAttrMin beim Start der Tabelle hatte. Und
+ // der aktuelle Wert von nContextStAttrMin entspricht der Anzahl der
+ // Kontexte, die beim Start der Zelle vorgefunden wurden. Sind beide
+ // Werte unterschiedlich, wurden ausserhalb der Zelle Kontexte
+ // angelegt und wir ueberpruefen nichts.
+
+ if( rParser.nContextStAttrMin == GetContextStAttrMin() )
+ {
+ _HTMLAttr** pTbl = (_HTMLAttr**)&rParser.aAttrTab;
+
+ for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
+ nCnt--; ++pTbl )
+ {
+ ASSERT( !*pTbl, "Die Attribut-Tabelle ist nicht leer" );
+ }
+ }
+#endif
+
+ // jetzt muessen wir noch die Zelle an der aktuellen Position einfuegen
+ SvxBrushItem *pBrushItem =
+ rParser.CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage,
+ aStyle, aId, aClass );
+ pCurTable->InsertCell( pCnts, nRowSpan, nColSpan, nWidth,
+ bPrcWidth, nHeight, eVertOri, pBrushItem,
+ bHasNumFmt, nNumFmt, bHasValue, nValue,
+ bNoWrap );
+ Restore( rParser );
+}
+
+void _CellSaveStruct::StartNoBreak( const SwPosition& rPos )
+{
+ if( !pCnts ||
+ (!rPos.nContent.GetIndex() && pCurrCnts==pCnts &&
+ pCnts->GetStartNode() &&
+ pCnts->GetStartNode()->GetIndex() + 1 ==
+ rPos.nNode.GetIndex()) )
+ {
+ bNoBreak = sal_True;
+ }
+}
+
+void _CellSaveStruct::EndNoBreak( const SwPosition& rPos )
+{
+ if( bNoBreak )
+ {
+ delete pNoBreakEndParaIdx;
+ pNoBreakEndParaIdx = new SwNodeIndex( rPos.nNode );
+ nNoBreakEndCntntPos = rPos.nContent.GetIndex();
+ bNoBreak = sal_False;
+ }
+}
+
+void _CellSaveStruct::CheckNoBreak( const SwPosition& rPos, SwDoc *pDoc )
+{
+ if( pCnts && pCurrCnts==pCnts )
+ {
+ if( bNoBreak )
+ {
+ // <NOBR> wurde nicht beendet
+ pCnts->SetNoBreak();
+ }
+ else if( pNoBreakEndParaIdx &&
+ pNoBreakEndParaIdx->GetIndex() == rPos.nNode.GetIndex() )
+ {
+ if( nNoBreakEndCntntPos == rPos.nContent.GetIndex() )
+ {
+ // <NOBR> wurde unmittelbar vor dem Zellen-Ende beendet
+ pCnts->SetNoBreak();
+ }
+ else if( nNoBreakEndCntntPos + 1 == rPos.nContent.GetIndex() )
+ {
+ const SwTxtNode *pTxtNd =
+ pDoc->GetNodes()[rPos.nNode]->GetTxtNode();
+ if( pTxtNd )
+ {
+ register sal_Unicode cLast =
+ pTxtNd->GetTxt().GetChar(nNoBreakEndCntntPos);
+ if( ' '==cLast || '\x0a'==cLast )
+ {
+ // Zwischem dem </NOBR> und dem Zellen-Ende gibt es nur
+ // ein Blank oder einen Zeilenumbruch.
+ pCnts->SetNoBreak();
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+HTMLTableCnts *SwHTMLParser::InsertTableContents(
+ sal_Bool bHead )
+{
+ // eine neue Section anlegen, der PaM steht dann darin
+ const SwStartNode *pStNd =
+ InsertTableSection( bHead ? RES_POOLCOLL_TABLE_HDLN
+ : RES_POOLCOLL_TABLE );
+
+ if( GetNumInfo().GetNumRule() )
+ {
+ // 1. Absatz auf nicht numeriert setzen
+ SetNodeNum( GetNumInfo().GetLevel() | NO_NUMLEVEL );
+ }
+
+ // Attributierungs-Anfang neu setzen
+ const SwNodeIndex& rSttPara = pPam->GetPoint()->nNode;
+ xub_StrLen nSttCnt = pPam->GetPoint()->nContent.GetIndex();
+
+ _HTMLAttr** pTbl = (_HTMLAttr**)&aAttrTab;
+ for( sal_uInt16 nCnt = sizeof( _HTMLAttrTable ) / sizeof( _HTMLAttr* );
+ nCnt--; ++pTbl )
+ {
+
+ _HTMLAttr *pAttr = *pTbl;
+ while( pAttr )
+ {
+ ASSERT( !pAttr->GetPrev(), "Attribut hat Previous-Liste" );
+ pAttr->nSttPara = rSttPara;
+ pAttr->nEndPara = rSttPara;
+ pAttr->nSttCntnt = nSttCnt;
+ pAttr->nEndCntnt = nSttCnt;
+
+ pAttr = pAttr->GetNext();
+ }
+ }
+
+ return new HTMLTableCnts( pStNd );
+}
+
+sal_uInt16 SwHTMLParser::IncGrfsThatResizeTable()
+{
+ return pTable ? pTable->IncGrfsThatResize() : 0;
+}
+
+void SwHTMLParser::RegisterDrawObjectToTable( HTMLTable *pCurTable,
+ SdrObject *pObj, sal_uInt8 nPrcWidth )
+{
+ pCurTable->RegisterDrawObject( pObj, nPrcWidth );
+}
+
+void SwHTMLParser::BuildTableCell( HTMLTable *pCurTable, sal_Bool bReadOptions,
+ sal_Bool bHead )
+{
+ if( !IsParserWorking() && !pPendStack )
+ return;
+
+ _CellSaveStruct* pSaveStruct;
+
+ int nToken = 0;
+ sal_Bool bPending = sal_False;
+ if( pPendStack )
+ {
+ pSaveStruct = (_CellSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ bPending = SVPAR_ERROR == eState && pPendStack != 0;
+
+ SaveState( nToken );
+ }
+ else
+ {
+ // <TH> bzw. <TD> wurde bereits gelesen
+ if( pTable->IsOverflowing() )
+ {
+ SaveState( 0 );
+ return;
+ }
+
+ if( !pCurTable->GetContext() )
+ {
+// MIB: 5.9.2000: Do we need this any longer?
+// bIsWriterDoc = sal_True;
+ sal_Bool bTopTable = pTable==pCurTable;
+
+ // die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche
+ // Tabelle muss erst noch angelegt werden
+
+ String aStyle, aId, aClass;
+ static sal_uInt16 aWhichIds[] =
+ {
+ RES_PARATR_SPLIT, RES_PARATR_SPLIT,
+ RES_PAGEDESC, RES_PAGEDESC,
+ RES_BREAK, RES_BREAK,
+ RES_BACKGROUND, RES_BACKGROUND,
+ RES_KEEP, RES_KEEP,
+ RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT,
+ 0
+ };
+
+ SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds );
+ SvxCSS1PropertyInfo aPropInfo;
+
+ sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(),
+ pCurTable->GetId(),
+ pCurTable->GetClass(),
+ aItemSet, aPropInfo );
+ const SfxPoolItem *pItem = 0;
+ if( bStyleParsed )
+ {
+ if( SFX_ITEM_SET == aItemSet.GetItemState(
+ RES_BACKGROUND, sal_False, &pItem ) )
+ {
+ pCurTable->SetBGBrush( *(const SvxBrushItem *)pItem );
+ aItemSet.ClearItem( RES_BACKGROUND );
+ }
+ if( SFX_ITEM_SET == aItemSet.GetItemState(
+ RES_PARATR_SPLIT, sal_False, &pItem ) )
+ {
+ aItemSet.Put(
+ SwFmtLayoutSplit( ((const SvxFmtSplitItem *)pItem)
+ ->GetValue() ) );
+ aItemSet.ClearItem( RES_PARATR_SPLIT );
+ }
+ }
+
+ // Den linken/rechten Absatzeinzug ermitteln
+ sal_uInt16 nLeftSpace = 0;
+ sal_uInt16 nRightSpace = 0;
+ short nIndent;
+ GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent );
+
+ // die aktuelle Position an die wir irgendwann zurueckkehren
+ SwPosition *pSavePos = 0;
+ sal_Bool bForceFrame = sal_False;
+ sal_Bool bAppended = sal_False;
+ sal_Bool bParentLFStripped = sal_False;
+ if( bTopTable )
+ {
+ // Sind wir in einer Tabelle in der Tabelle?
+ const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ const SwTableNode *pTblNd = pNd->FindTableNode();
+
+ SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False);
+
+ // Wenn das Table-Tag in einem Rahmen stand, den es nicht
+ // mehr gibt, muessen wir die Tabelle in einen Rahmen
+ // stecken.
+ if( pCurTable->IsMakeTopSubTable() && pTblNd!=0 )
+ pCurTable->SetHasToFly();
+
+ // Wenn die Tabelle links oder rechts ausgerivchtet ist,
+ // oder in einen Rahmen soll, dann kommt sie auch in einen
+ // solchen.
+ bForceFrame = eTblAdjust == SVX_ADJUST_LEFT ||
+ eTblAdjust == SVX_ADJUST_RIGHT ||
+ pCurTable->HasToFly();
+
+ // Da Tabelle in Tabelle nicht geht, muss die Tabelle
+ // entweder in einen Rahmen, oder sie steht in einem
+ // Rahmen sie steht in keiner anderen Tabelle.
+ ASSERT( bForceFrame || !pTblNd,
+ "Tabelle in der Tabelle geht nur mit oder in Rahmen" );
+
+ // Entweder kommt die Tabelle in keinen Rahmen und befindet
+ // sich in keinem Rahmen (wird also durch Zellen simuliert),
+ // oder es gibt bereits Inhalt an der entsprechenden Stelle.
+ ASSERT( !bForceFrame || pCurTable->HasParentSection(),
+ "Tabelle im Rahmen hat keine Umgebung!" );
+// SCHOEN WAER'S, aber wie bekommen den Inhalt nicht zurueck
+// in die umgebende Zelle
+// if( bForceFrame && !pCurTable->HasParentSection() )
+// {
+// pCurTable->SetParentContents(
+// InsertTableContents( sal_False, SVX_ADJUST_END ) );
+// pCurTable->SetHasParentSection( sal_True );
+// }
+
+ sal_Bool bAppend = sal_False;
+ if( bForceFrame )
+ {
+ // Wenn die Tabelle in einen Rahmen kommt, muss
+ // nur ein neuer Absatz aufgemacht werden, wenn
+ // der Absatz Rahmen ohne Umlauf enthaelt.
+ bAppend = HasCurrentParaFlys(sal_True);
+ }
+ else
+ {
+ // Sonst muss ein neuer Absatz aufgemacht werden,
+ // wenn der Absatz nicht leer ist, oder Rahmen
+ // oder ::com::sun::star::text::Bookmarks enthaelt.
+ bAppend =
+ pPam->GetPoint()->nContent.GetIndex() ||
+ HasCurrentParaFlys() ||
+ HasCurrentParaBookmarks();
+ }
+ if( bAppend )
+ {
+ if( !pPam->GetPoint()->nContent.GetIndex() )
+ {
+ pDoc->SetTxtFmtColl( *pPam,
+ pCSS1Parser->GetTxtCollFromPool(RES_POOLCOLL_STANDARD) );
+ _HTMLAttr* pTmp =
+ new _HTMLAttr( *pPam->GetPoint(),
+ SvxFontHeightItem( 40 ) );
+ aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() );
+ pTmp = new _HTMLAttr( *pPam->GetPoint(),
+ SvxULSpaceItem( 0, 0 ) );
+ aSetAttrTab.Insert( pTmp, 0 ); // ja, 0, weil schon
+ // vom Tabellenende vorher
+ // was gesetzt sein kann.
+ }
+ AppendTxtNode( AM_NOSPACE );
+ bAppended = sal_True;
+ }
+ else if( aParaAttrs.Count() )
+ {
+ if( !bForceFrame )
+ {
+ // Der Absatz wird gleich hinter die Tabelle
+ // verschoben. Deshalb entfernen wir alle harten
+ // Attribute des Absatzes
+
+ for( sal_uInt16 i=0; i<aParaAttrs.Count(); i++ )
+ aParaAttrs[i]->Invalidate();
+ }
+
+ aParaAttrs.Remove( 0, aParaAttrs.Count() );
+ }
+
+ pSavePos = new SwPosition( *pPam->GetPoint() );
+ }
+ else if( pCurTable->HasParentSection() )
+ {
+ bParentLFStripped = StripTrailingLF() > 0;
+
+ // Absaetze bzw. ueberschriften beeenden
+ nOpenParaToken = 0;
+ nFontStHeadStart = nFontStMin;
+
+ // die harten Attribute an diesem Absatz werden nie mehr ungueltig
+ if( aParaAttrs.Count() )
+ aParaAttrs.Remove( 0, aParaAttrs.Count() );
+
+#ifndef NUM_RELSPACE
+ if( GetNumInfo().GetNumRule() )
+ UpdateNumRuleInTable();
+#endif
+ }
+
+ // einen Tabellen Kontext anlegen
+ _HTMLTableContext *pTCntxt =
+ new _HTMLTableContext( pSavePos, nContextStMin,
+ nContextStAttrMin );
+
+ // alle noch offenen Attribute beenden und hinter der Tabelle
+ // neu aufspannen
+ _HTMLAttrs *pPostIts = 0;
+ if( !bForceFrame && (bTopTable || pCurTable->HasParentSection()) )
+ {
+ SplitAttrTab( pTCntxt->aAttrTab, bTopTable );
+ // Wenn wir einen schon vorhandenen Absatz verwenden, duerfen
+ // in den keine PostIts eingefuegt werden, weil der Absatz
+ // ja hinter die Tabelle wandert. Sie werden deshalb in den
+ // ersten Absatz der Tabelle verschoben.
+ // Bei Tabellen in Tabellen duerfen ebenfalls keine PostIts
+ // in einen noch leeren Absatz eingefuegt werden, weil
+ // der sonat nicht geloescht wird.
+ if( (bTopTable && !bAppended) ||
+ (!bTopTable && !bParentLFStripped &&
+ !pPam->GetPoint()->nContent.GetIndex()) )
+ pPostIts = new _HTMLAttrs;
+ SetAttr( bTopTable, bTopTable, pPostIts );
+ }
+ else
+ {
+ SaveAttrTab( pTCntxt->aAttrTab );
+ if( bTopTable && !bAppended )
+ {
+ pPostIts = new _HTMLAttrs;
+ SetAttr( sal_True, sal_True, pPostIts );
+ }
+ }
+ bNoParSpace = sal_False;
+
+ // Aktuelle Numerierung retten und auschalten.
+ pTCntxt->SetNumInfo( GetNumInfo() );
+ GetNumInfo().Clear();
+ pTCntxt->SavePREListingXMP( *this );
+
+ if( bTopTable )
+ {
+ if( bForceFrame )
+ {
+ // Die Tabelle soll in einen Rahmen geschaufelt werden.
+
+ SfxItemSet aFrmSet( pDoc->GetAttrPool(),
+ RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
+ if( !pCurTable->IsNewDoc() )
+ Reader::ResetFrmFmtAttrs( aFrmSet );
+
+ SwSurround eSurround = SURROUND_NONE;
+ SwHoriOrient eHori;
+
+ switch( pCurTable->GetTableAdjust(sal_True) )
+ {
+ case SVX_ADJUST_RIGHT:
+ eHori = HORI_RIGHT;
+ eSurround = SURROUND_LEFT;
+ break;
+ case SVX_ADJUST_CENTER:
+ eHori = HORI_CENTER;
+ break;
+ case SVX_ADJUST_LEFT:
+ eSurround = SURROUND_RIGHT;
+ default:
+ eHori = HORI_LEFT;
+ break;
+ }
+ SetAnchorAndAdjustment( VERT_NONE, eHori, aFrmSet,
+ sal_True );
+ aFrmSet.Put( SwFmtSurround(eSurround) );
+
+ SwFmtFrmSize aFrmSize( ATT_VAR_SIZE, 20*MM50, MINLAY );
+ aFrmSize.SetWidthPercent( 100 );
+ aFrmSet.Put( aFrmSize );
+
+ sal_uInt16 nSpace = pCurTable->GetHSpace();
+ if( nSpace )
+ aFrmSet.Put( SvxLRSpaceItem(nSpace,nSpace) );
+ nSpace = pCurTable->GetVSpace();
+ if( nSpace )
+ aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace) );
+
+ RndStdIds eAnchorId = ((const SwFmtAnchor&)aFrmSet.
+ Get( RES_ANCHOR )).
+ GetAnchorId();
+ SwFrmFmt *pFrmFmt = pDoc->MakeFlySection(
+ eAnchorId, pPam->GetPoint(), &aFrmSet );
+
+ pTCntxt->SetFrmFmt( pFrmFmt );
+ const SwFmtCntnt& rFlyCntnt = pFrmFmt->GetCntnt();
+ pPam->GetPoint()->nNode = *rFlyCntnt.GetCntntIdx();
+ SwCntntNode *pCNd =
+ pDoc->GetNodes().GoNext( &(pPam->GetPoint()->nNode) );
+ pPam->GetPoint()->nContent.Assign( pCNd, 0 );
+
+ // automatisch verankerte Rahmen muessen noch um
+ // eine Position nach vorne verschoben werden.
+ //if( FLY_AUTO_CNTNT==eAnchorId )
+ // aMoveFlyFrms.C40_INSERT( SwFrmFmt, pFrmFmt,
+ // aMoveFlyFrms.Count() );
+ }
+
+ // eine SwTable mit einer Box anlegen und den PaM in den
+ // Inhalt der Box-Section bewegen (der Ausrichtungs-Parameter
+ // ist erstmal nur ein Dummy und wird spaeter noch richtig
+ // gesetzt)
+ ASSERT( !pPam->GetPoint()->nContent.GetIndex(),
+ "Der Absatz hinter der Tabelle ist nicht leer!" );
+ const SwTable* pSwTable = pDoc->InsertTable( *pPam->GetPoint(),
+ 1, 1, HORI_LEFT );
+
+ if( bForceFrame )
+ {
+ SwNodeIndex aDstIdx( pPam->GetPoint()->nNode );
+ pPam->Move( fnMoveBackward );
+ pDoc->GetNodes().Delete( aDstIdx );
+ }
+ else
+ {
+ if( bStyleParsed )
+ {
+ pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo );
+ pSwTable->GetFrmFmt()->SetAttr( aItemSet );
+ }
+ pPam->Move( fnMoveBackward );
+ }
+
+ const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ if( !bAppended && !bForceFrame )
+ {
+ SwTxtNode* pOldTxtNd =
+ pDoc->GetNodes()[pSavePos->nNode]->GetTxtNode();
+ ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" );
+ SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
+
+ const SfxPoolItem* pItem;
+ if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
+ .GetItemState( RES_PAGEDESC, sal_False, &pItem ) &&
+ ((SwFmtPageDesc *)pItem)->GetPageDesc() )
+ {
+ pFrmFmt->SetAttr( *pItem );
+ pOldTxtNd->ResetAttr( RES_PAGEDESC );
+ }
+ if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet()
+ .GetItemState( RES_BREAK, sal_True, &pItem ) )
+ {
+ switch( ((SvxFmtBreakItem *)pItem)->GetBreak() )
+ {
+ case SVX_BREAK_PAGE_BEFORE:
+ case SVX_BREAK_PAGE_AFTER:
+ case SVX_BREAK_PAGE_BOTH:
+ pFrmFmt->SetAttr( *pItem );
+ pOldTxtNd->ResetAttr( RES_BREAK );
+ }
+ }
+ }
+
+ if( !bAppended && pPostIts )
+ {
+ // noch vorhandene PostIts in den ersten Absatz
+ // der Tabelle setzen
+ InsertAttrs( *pPostIts );
+ delete pPostIts;
+ pPostIts = 0;
+ }
+
+ pTCntxt->SetTableNode( (SwTableNode *)pNd->FindTableNode() );
+
+ pCurTable->SetTable( pTCntxt->GetTableNode(), pTCntxt,
+ nLeftSpace, nRightSpace,
+ pSwTable, bForceFrame );
+
+ ASSERT( !pPostIts, "ubenutzte PostIts" );
+ }
+ else
+ {
+ // noch offene Bereiche muessen noch entfernt werden
+ if( EndSections( bParentLFStripped ) )
+ bParentLFStripped = sal_False;
+
+ if( pCurTable->HasParentSection() )
+ {
+ // dannach entfernen wir ein ggf. zu viel vorhandenen
+ // leeren Absatz, aber nur, wenn er schon vor dem
+ // entfernen von LFs leer war
+ if( !bParentLFStripped )
+ StripTrailingPara();
+
+ if( pPostIts )
+ {
+ // noch vorhandene PostIts an das Ende des jetzt
+ // aktuellen Absatzes schieben
+ InsertAttrs( *pPostIts );
+ delete pPostIts;
+ pPostIts = 0;
+ }
+ }
+
+ const SwNode *pNd = pDoc->GetNodes()[pPam->GetPoint()->nNode];
+ const SwStartNode *pStNd = (pTable->bFirstCell ? pNd->FindTableNode()
+ : pNd->FindTableBoxStartNode() );
+
+ pCurTable->SetTable( pStNd, pTCntxt, nLeftSpace, nRightSpace );
+ }
+
+ // Den Kontext-Stack einfrieren, denn es koennen auch mal
+ // irgendwo ausserhalb von Zellen Attribute gesetzt werden.
+ // Darf nicht frueher passieren, weil eventuell noch im
+ // Stack gesucht wird!!!
+ nContextStMin = aContexts.Count();
+ nContextStAttrMin = nContextStMin;
+ }
+
+ pSaveStruct = new _CellSaveStruct( *this, pCurTable, bHead,
+ bReadOptions );
+
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ if( !nToken )
+ nToken = GetNextToken(); // Token nach <TABLE>
+
+ sal_Bool bDone = sal_False;
+ while( (IsParserWorking() && !bDone) || bPending )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ ASSERT( pPendStack || !bCallNextToken || pSaveStruct->IsInSection(),
+ "Wo ist die Section gebieben?" );
+ if( !pPendStack && bCallNextToken && pSaveStruct->IsInSection() )
+ {
+ // NextToken direkt aufrufen (z.B. um den Inhalt von
+ // Floating-Frames oder Applets zu ignorieren)
+ NextToken( nToken );
+ }
+ else switch( nToken )
+ {
+ case HTML_TABLEHEADER_ON:
+ case HTML_TABLEDATA_ON:
+ case HTML_TABLEROW_ON:
+ case HTML_TABLEROW_OFF:
+ case HTML_THEAD_ON:
+ case HTML_THEAD_OFF:
+ case HTML_TFOOT_ON:
+ case HTML_TFOOT_OFF:
+ case HTML_TBODY_ON:
+ case HTML_TBODY_OFF:
+ case HTML_TABLE_OFF:
+ SkipToken(-1);
+ case HTML_TABLEHEADER_OFF:
+ case HTML_TABLEDATA_OFF:
+ bDone = sal_True;
+ break;
+ case HTML_TABLE_ON:
+ {
+ sal_Bool bTopTable = sal_False;
+ sal_Bool bHasToFly = sal_False;
+ SvxAdjust eTabAdjust = SVX_ADJUST_END;
+ if( !pPendStack )
+ {
+ // nur wenn eine neue Tabelle aufgemacht wird, aber
+ // nicht wenn nach einem Pending in der Tabelle
+ // weitergelesen wird!
+ pSaveStruct->pTable = pTable;
+
+ // HACK: Eine Section fuer eine Tabelle anlegen, die
+ // in einen Rahmen kommt.
+ if( !pSaveStruct->IsInSection() )
+ {
+ // Diese Schleife muss vorwartes sein, weil die
+ // erste Option immer gewinnt.
+ sal_Bool bNeedsSection = sal_False;
+ const HTMLOptions *pOptions = GetOptions();
+ for( sal_uInt16 i=0; i<pOptions->Count(); i++ )
+ {
+ const HTMLOption *pOption = (*pOptions)[i];
+ if( HTML_O_ALIGN==pOption->GetToken() )
+ {
+ SvxAdjust eAdjust =
+ (SvxAdjust)pOption->GetEnum(
+ aHTMLPAlignTable, SVX_ADJUST_END );
+ bNeedsSection = SVX_ADJUST_LEFT == eAdjust ||
+ SVX_ADJUST_RIGHT == eAdjust;
+ break;
+ }
+ }
+ if( bNeedsSection )
+ {
+ pSaveStruct->AddContents(
+ InsertTableContents(bHead ) );
+ }
+ }
+ else
+ {
+ // Wenn wir mitlerweile in einem Rahmen stehen
+ // koennen wir erneut eine echte Tabelle aufmachen.
+ // Wir erkennen das daran, dass wir keinen
+ // Tabellen-Node mehr finden.
+ bTopTable = pDoc->GetNodes()[pPam->GetPoint()->nNode]
+ ->FindTableNode() == 0;
+
+ // Wenn im aktuellen Absatz Flys verankert sind,
+ // muss die neue Tabelle in einen Rahmen.
+ bHasToFly = HasCurrentParaFlys(sal_False,sal_True);
+ }
+
+ // in der Zelle kann sich ein Bereich befinden!
+ eTabAdjust = aAttrTab.pAdjust
+ ? ((const SvxAdjustItem&)aAttrTab.pAdjust->GetItem()).
+ GetAdjust()
+ : SVX_ADJUST_END;
+ }
+
+ HTMLTable *pSubTable = BuildTable( eTabAdjust,
+ bHead,
+ pSaveStruct->IsInSection(),
+ bTopTable, bHasToFly );
+ if( SVPAR_PENDING != GetStatus() )
+ {
+ // nur wenn die Tabelle wirklich zu Ende ist!
+ if( pSubTable )
+ {
+ ASSERT( pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_LEFT &&
+ pSubTable->GetTableAdjust(sal_False)!= SVX_ADJUST_RIGHT,
+ "links oder rechts ausgerichtete Tabellen gehoehren in Rahmen" );
+
+
+ HTMLTableCnts *pParentContents =
+ pSubTable->GetParentContents();
+ if( pParentContents )
+ {
+ ASSERT( !pSaveStruct->IsInSection(),
+ "Wo ist die Section geblieben" );
+
+ // Wenn jetzt keine Tabelle kommt haben wir eine
+ // Section
+ pSaveStruct->AddContents( pParentContents );
+ }
+
+ const SwStartNode *pCapStNd =
+ pSubTable->GetCaptionStartNode();
+
+ if( pSubTable->GetContext() )
+ {
+ ASSERT( !pSubTable->GetContext()->GetFrmFmt(),
+ "Tabelle steht im Rahmen" );
+
+ if( pCapStNd && pSubTable->IsTopCaption() )
+ {
+ pSaveStruct->AddContents(
+ new HTMLTableCnts(pCapStNd) );
+ }
+
+ pSaveStruct->AddContents(
+ new HTMLTableCnts(pSubTable) );
+
+ if( pCapStNd && !pSubTable->IsTopCaption() )
+ {
+ pSaveStruct->AddContents(
+ new HTMLTableCnts(pCapStNd) );
+ }
+
+ // Jetzt haben wir keine Section mehr
+ pSaveStruct->ClearIsInSection();
+ }
+ else if( pCapStNd )
+ {
+ // Da wir diese Sction nicht mehr loeschen
+ // koennen (sie koeente zur erster Box
+ // gehoeren), fuegen wir sie ein.
+ pSaveStruct->AddContents(
+ new HTMLTableCnts(pCapStNd) );
+
+ // Jetzt haben wir keine Section mehr
+ pSaveStruct->ClearIsInSection();
+ }
+ }
+
+ pTable = pSaveStruct->pTable;
+ }
+ }
+ break;
+
+ case HTML_NOBR_ON:
+ // HACK fuer MS: Steht das <NOBR> zu beginn der Zelle?
+ pSaveStruct->StartNoBreak( *pPam->GetPoint() );
+ break;
+
+ case HTML_NOBR_OFF:
+ pSaveStruct->EndNoBreak( *pPam->GetPoint() );
+ break;
+
+ case HTML_COMMENT:
+ // Mit Kommentar-Feldern werden Spaces nicht mehr geloescht
+ // ausserdem wollen wir fuer einen Kommentar keine neue Zelle
+ // anlegen !!!
+ NextToken( nToken );
+ break;
+
+ case HTML_MARQUEE_ON:
+ if( !pSaveStruct->IsInSection() )
+ {
+ // eine neue Section anlegen, der PaM steht dann darin
+ pSaveStruct->AddContents(
+ InsertTableContents( bHead ) );
+ }
+ bCallNextToken = sal_True;
+ NewMarquee( pCurTable );
+ break;
+
+ case HTML_TEXTTOKEN:
+ // keine Section fuer einen leeren String anlegen
+ if( !pSaveStruct->IsInSection() && 1==aToken.Len() &&
+ ' '==aToken.GetChar(0) )
+ break;
+ default:
+ if( !pSaveStruct->IsInSection() )
+ {
+ // eine neue Section anlegen, der PaM steht dann darin
+ pSaveStruct->AddContents(
+ InsertTableContents( bHead ) );
+ }
+
+ if( IsParserWorking() || bPending )
+ NextToken( nToken );
+ break;
+ }
+
+ ASSERT( !bPending || !pPendStack,
+ "SwHTMLParser::BuildTableCell: Es gibt wieder einen Pend-Stack" );
+ bPending = sal_False;
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING == GetStatus() )
+ {
+ pPendStack = new SwPendingStack( bHead ? HTML_TABLEHEADER_ON
+ : HTML_TABLEDATA_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+
+ return;
+ }
+
+ // Falls der Inhalt der Zelle leer war, muessen wir noch einen
+ // leeren Inhalt anlegen. Ausserdem legen wir einen leeren Inhalt
+ // an, wenn die Zelle mit einer Tabelle aufgehoert hat und keine
+ // COL-Tags hatte (sonst wurde sie wahrscheinlich von uns exportiert,
+ // und dann wollen wir natuerlich keinen zusaetzlichen Absatz haben).
+ if( !pSaveStruct->GetFirstContents() ||
+ (!pSaveStruct->IsInSection() && !pCurTable->HasColTags()) )
+ {
+ ASSERT( pSaveStruct->GetFirstContents() ||
+ !pSaveStruct->IsInSection(),
+ "Section oder nicht, das ist hier die Frage" );
+ const SwStartNode *pStNd =
+ InsertTableSection( pSaveStruct->IsHeaderCell()
+ ? RES_POOLCOLL_TABLE_HDLN
+ : RES_POOLCOLL_TABLE );
+ pDoc->GetNodes()[pStNd->GetIndex()+1]
+ ->GetCntntNode()->SetAttr( SvxFontHeightItem(40) );
+ pSaveStruct->AddContents( new HTMLTableCnts(pStNd) );
+ pSaveStruct->ClearIsInSection();
+ }
+
+ sal_Bool bLFStripped = sal_False;
+ if( pSaveStruct->IsInSection() )
+ {
+ pSaveStruct->CheckNoBreak( *pPam->GetPoint(), pDoc );
+
+ // Alle noch offenen Kontexte beenden. Wir nehmen hier
+ // AttrMin, weil nContxtStMin evtl. veraendert wurde.
+ // Da es durch EndContext wieder restauriert wird, geht das.
+ while( aContexts.Count() > nContextStAttrMin+1 )
+ {
+ _HTMLAttrContext *pCntxt = PopContext();
+ EndContext( pCntxt );
+ delete pCntxt;
+ }
+
+ // LFs am Absatz-Ende entfernen
+ if( StripTrailingLF()==0 && !pPam->GetPoint()->nContent.GetIndex() )
+ StripTrailingPara();
+
+#ifndef NUM_RELSPACE
+ if( GetNumInfo().GetNumRule() )
+ UpdateNumRuleInTable();
+#endif
+
+ // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
+ // wir die beenden
+ _HTMLAttrContext *pCntxt = PopContext();
+ EndContext( pCntxt );
+ delete pCntxt;
+ }
+ else
+ {
+ // Alle noch offenen Kontexte beenden
+ while( aContexts.Count() > nContextStAttrMin )
+ {
+ _HTMLAttrContext *pCntxt = PopContext();
+ ClearContext( pCntxt );
+ delete pCntxt;
+ }
+ }
+
+ // auch eine Numerierung muss beendet werden
+ GetNumInfo().Clear();
+
+ SetAttr( sal_False );
+
+ pSaveStruct->InsertCell( *this, pCurTable );
+
+ // wir stehen jetzt (wahrschenlich) vor <TH>, <TD>, <TR> oder </TABLE>
+ delete pSaveStruct;
+}
+
+
+class _RowSaveStruct : public SwPendingStackData
+{
+public:
+ SvxAdjust eAdjust;
+ SwVertOrient eVertOri;
+ sal_Bool bHasCells;
+
+ _RowSaveStruct() :
+ bHasCells( sal_False ), eAdjust( SVX_ADJUST_END ), eVertOri( VERT_TOP )
+ {}
+};
+
+
+void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions,
+ SvxAdjust eGrpAdjust,
+ SwVertOrient eGrpVertOri )
+{
+ // <TR> wurde bereist gelesen
+
+ if( !IsParserWorking() && !pPendStack )
+ return;
+
+ int nToken = 0;
+ _RowSaveStruct* pSaveStruct;
+
+ sal_Bool bPending = sal_False;
+ if( pPendStack )
+ {
+ pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ bPending = SVPAR_ERROR == eState && pPendStack != 0;
+
+ SaveState( nToken );
+ }
+ else
+ {
+ SvxAdjust eAdjust = eGrpAdjust;
+ SwVertOrient eVertOri = eGrpVertOri;
+ Color aBGColor;
+ String aBGImage, aStyle, aId, aClass;
+ sal_Bool bBGColor = sal_False;
+ pSaveStruct = new _RowSaveStruct;
+
+ if( bReadOptions )
+ {
+ const HTMLOptions *pOptions = GetOptions();
+ for( sal_uInt16 i = pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*pOptions)[--i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_ID:
+ aId = pOption->GetString();
+ break;
+ case HTML_O_ALIGN:
+ eAdjust = (SvxAdjust)pOption->GetEnum(
+ aHTMLPAlignTable, eAdjust );
+ break;
+ case HTML_O_VALIGN:
+ eVertOri = (SwVertOrient)pOption->GetEnum(
+ aHTMLTblVAlignTable, eVertOri );
+ break;
+ case HTML_O_BGCOLOR:
+ // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netsc.
+ // ignorieren, bei allen anderen Tags *wirklich* nicht.
+ if( pOption->GetString().Len() )
+ {
+ pOption->GetColor( aBGColor );
+ bBGColor = sal_True;
+ }
+ break;
+ case HTML_O_BACKGROUND:
+ aBGImage = pOption->GetString();
+ break;
+ case HTML_O_STYLE:
+ aStyle = pOption->GetString();
+ break;
+ case HTML_O_CLASS:
+ aClass= pOption->GetString();
+ break;
+ }
+ }
+ }
+
+ if( aId.Len() )
+ InsertBookmark( aId );
+
+ SvxBrushItem *pBrushItem =
+ CreateBrushItem( bBGColor ? &aBGColor : 0, aBGImage, aStyle,
+ aId, aClass );
+ pCurTable->OpenRow( eAdjust, eVertOri, pBrushItem );
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ if( !nToken )
+ nToken = GetNextToken(); // naechstes Token
+
+ sal_Bool bDone = sal_False;
+ while( (IsParserWorking() && !bDone) || bPending )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ ASSERT( pPendStack || !bCallNextToken ||
+ pCurTable->GetContext() || pCurTable->HasParentSection(),
+ "Wo ist die Section gebieben?" );
+ if( !pPendStack && bCallNextToken &&
+ (pCurTable->GetContext() || pCurTable->HasParentSection()) )
+ {
+ // NextToken direkt aufrufen (z.B. um den Inhalt von
+ // Floating-Frames oder Applets zu ignorieren)
+ NextToken( nToken );
+ }
+ else switch( nToken )
+ {
+ case HTML_TABLE_ON:
+ if( !pCurTable->GetContext() )
+ {
+ SkipToken( -1 );
+ bDone = sal_True;
+ }
+// else
+// {
+// NextToken( nToken );
+// }
+ break;
+ case HTML_TABLEROW_ON:
+ case HTML_THEAD_ON:
+ case HTML_THEAD_OFF:
+ case HTML_TBODY_ON:
+ case HTML_TBODY_OFF:
+ case HTML_TFOOT_ON:
+ case HTML_TFOOT_OFF:
+ case HTML_TABLE_OFF:
+ SkipToken( -1 );
+ case HTML_TABLEROW_OFF:
+ bDone = sal_True;
+ break;
+ case HTML_TABLEHEADER_ON:
+ case HTML_TABLEDATA_ON:
+ BuildTableCell( pCurTable, sal_True, HTML_TABLEHEADER_ON==nToken );
+ if( SVPAR_PENDING != GetStatus() )
+ {
+ pSaveStruct->bHasCells = sal_True;
+ bDone = pTable->IsOverflowing();
+ }
+ break;
+ case HTML_CAPTION_ON:
+ BuildTableCaption( pCurTable );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_CAPTION_OFF:
+ case HTML_TABLEHEADER_OFF:
+ case HTML_TABLEDATA_OFF:
+ case HTML_COLGROUP_ON:
+ case HTML_COLGROUP_OFF:
+ case HTML_COL_ON:
+ case HTML_COL_OFF:
+ // wo keine Zelle anfing kann auch keine aufhoehren, oder?
+ // und die ganzen anderen Tokens haben hier auch nicht zu
+ // suchen und machen nur die Tabelle kaputt
+ break;
+ case HTML_MULTICOL_ON:
+ // spaltige Rahmen koennen wir hier leider nicht einguegen
+ break;
+ case HTML_FORM_ON:
+ NewForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_FORM_OFF:
+ EndForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_COMMENT:
+ NextToken( nToken );
+ break;
+ case HTML_MAP_ON:
+ // eine Image-Map fuegt nichts ein, deshalb koennen wir sie
+ // problemlos auch ohne Zelle parsen
+ NextToken( nToken );
+ break;
+ case HTML_TEXTTOKEN:
+ if( (pCurTable->GetContext() ||
+ !pCurTable->HasParentSection()) &&
+ 1==aToken.Len() && ' '==aToken.GetChar(0) )
+ break;
+ default:
+ pCurTable->MakeParentContents();
+ NextToken( nToken );
+ break;
+ }
+
+ ASSERT( !bPending || !pPendStack,
+ "SwHTMLParser::BuildTableRow: Es gibt wieder einen Pend-Stack" );
+ bPending = sal_False;
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING == GetStatus() )
+ {
+ pPendStack = new SwPendingStack( HTML_TABLEROW_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+ }
+ else
+ {
+ pCurTable->CloseRow( !pSaveStruct->bHasCells );
+ delete pSaveStruct;
+ }
+
+ // wir stehen jetzt (wahrscheinlich) vor <TR> oder </TABLE>
+}
+
+void SwHTMLParser::BuildTableSection( HTMLTable *pCurTable,
+ sal_Bool bReadOptions,
+ sal_Bool bHead )
+{
+ // <THEAD>, <TBODY> bzw. <TFOOT> wurde bereits gelesen
+ if( !IsParserWorking() && !pPendStack )
+ return;
+
+ int nToken = 0;
+ sal_Bool bPending = sal_False;
+ _RowSaveStruct* pSaveStruct;
+
+ if( pPendStack )
+ {
+ pSaveStruct = (_RowSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ bPending = SVPAR_ERROR == eState && pPendStack != 0;
+
+ SaveState( nToken );
+ }
+ else
+ {
+ pSaveStruct = new _RowSaveStruct;
+
+ if( bReadOptions )
+ {
+ const HTMLOptions *pOptions = GetOptions();
+ for( sal_uInt16 i = pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*pOptions)[--i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_ID:
+ InsertBookmark( pOption->GetString() );
+ break;
+ case HTML_O_ALIGN:
+ pSaveStruct->eAdjust =
+ (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable,
+ pSaveStruct->eAdjust );
+ break;
+ case HTML_O_VALIGN:
+ pSaveStruct->eVertOri =
+ (SwVertOrient)pOption->GetEnum( aHTMLTblVAlignTable,
+ pSaveStruct->eVertOri );
+ break;
+ }
+ }
+ }
+
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ if( !nToken )
+ nToken = GetNextToken(); // naechstes Token
+
+ sal_Bool bDone = sal_False;
+ while( (IsParserWorking() && !bDone) || bPending )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ ASSERT( pPendStack || !bCallNextToken ||
+ pCurTable->GetContext() || pCurTable->HasParentSection(),
+ "Wo ist die Section gebieben?" );
+ if( !pPendStack && bCallNextToken &&
+ (pCurTable->GetContext() || pCurTable->HasParentSection()) )
+ {
+ // NextToken direkt aufrufen (z.B. um den Inhalt von
+ // Floating-Frames oder Applets zu ignorieren)
+ NextToken( nToken );
+ }
+ else switch( nToken )
+ {
+ case HTML_TABLE_ON:
+ if( !pCurTable->GetContext() )
+ {
+ SkipToken( -1 );
+ bDone = sal_True;
+ }
+// else
+// {
+// NextToken( nToken );
+// }
+ break;
+ case HTML_THEAD_ON:
+ case HTML_TFOOT_ON:
+ case HTML_TBODY_ON:
+ case HTML_TABLE_OFF:
+ SkipToken( -1 );
+ case HTML_THEAD_OFF:
+ case HTML_TBODY_OFF:
+ case HTML_TFOOT_OFF:
+ bDone = sal_True;
+ break;
+ case HTML_CAPTION_ON:
+ BuildTableCaption( pCurTable );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_CAPTION_OFF:
+ break;
+ case HTML_TABLEHEADER_ON:
+ case HTML_TABLEDATA_ON:
+ SkipToken( -1 );
+ BuildTableRow( pCurTable, sal_False, pSaveStruct->eAdjust,
+ pSaveStruct->eVertOri );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_TABLEROW_ON:
+ BuildTableRow( pCurTable, sal_True, pSaveStruct->eAdjust,
+ pSaveStruct->eVertOri );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_MULTICOL_ON:
+ // spaltige Rahmen koennen wir hier leider nicht einguegen
+ break;
+ case HTML_FORM_ON:
+ NewForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_FORM_OFF:
+ EndForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_TEXTTOKEN:
+ // Blank-Strings sind Folge von CR+LF und kein Text
+ if( (pCurTable->GetContext() ||
+ !pCurTable->HasParentSection()) &&
+ 1==aToken.Len() && ' '==aToken.GetChar(0) )
+ break;
+ default:
+ pCurTable->MakeParentContents();
+ NextToken( nToken );
+ }
+
+ ASSERT( !bPending || !pPendStack,
+ "SwHTMLParser::BuildTableSection: Es gibt wieder einen Pend-Stack" );
+ bPending = sal_False;
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING == GetStatus() )
+ {
+ pPendStack = new SwPendingStack( bHead ? HTML_THEAD_ON
+ : HTML_TBODY_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+ }
+ else
+ {
+ pCurTable->CloseSection( bHead );
+ delete pSaveStruct;
+ }
+
+ // wir stehen jetzt (wahrscheinlich) vor <TBODY>,... oder </TABLE>
+}
+
+struct _TblColGrpSaveStruct : public SwPendingStackData
+{
+ sal_uInt16 nColGrpSpan;
+ sal_uInt16 nColGrpWidth;
+ sal_Bool bRelColGrpWidth;
+ SvxAdjust eColGrpAdjust;
+ SwVertOrient eColGrpVertOri;
+
+ inline _TblColGrpSaveStruct();
+
+
+ inline void CloseColGroup( HTMLTable *pTable );
+};
+
+inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() :
+ nColGrpSpan( 1 ), nColGrpWidth( 0 ),
+ bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ),
+ eColGrpVertOri( VERT_TOP )
+{}
+
+
+inline void _TblColGrpSaveStruct::CloseColGroup( HTMLTable *pTable )
+{
+ pTable->CloseColGroup( nColGrpSpan, nColGrpWidth,
+ bRelColGrpWidth, eColGrpAdjust, eColGrpVertOri );
+}
+
+void SwHTMLParser::BuildTableColGroup( HTMLTable *pCurTable,
+ sal_Bool bReadOptions )
+{
+ // <COLGROUP> wurde bereits gelesen, wenn bReadOptions
+
+ if( !IsParserWorking() && !pPendStack )
+ return;
+
+ int nToken = 0;
+ sal_Bool bPending = sal_False;
+ _TblColGrpSaveStruct* pSaveStruct;
+
+ if( pPendStack )
+ {
+ pSaveStruct = (_TblColGrpSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ bPending = SVPAR_ERROR == eState && pPendStack != 0;
+
+ SaveState( nToken );
+ }
+ else
+ {
+
+ pSaveStruct = new _TblColGrpSaveStruct;
+ if( bReadOptions )
+ {
+ const HTMLOptions *pColGrpOptions = GetOptions();
+ for( sal_uInt16 i = pColGrpOptions->Count(); i; )
+ {
+ const HTMLOption *pColGrpOption = (*pColGrpOptions)[--i];
+ switch( pColGrpOption->GetToken() )
+ {
+ case HTML_O_ID:
+ InsertBookmark( pColGrpOption->GetString() );
+ break;
+ case HTML_O_SPAN:
+ pSaveStruct->nColGrpSpan = (sal_uInt16)pColGrpOption->GetNumber();
+ break;
+ case HTML_O_WIDTH:
+ pSaveStruct->nColGrpWidth = (sal_uInt16)pColGrpOption->GetNumber();
+ pSaveStruct->bRelColGrpWidth =
+ (pColGrpOption->GetString().Search('*') != STRING_NOTFOUND);
+ break;
+ case HTML_O_ALIGN:
+ pSaveStruct->eColGrpAdjust =
+ (SvxAdjust)pColGrpOption->GetEnum( aHTMLPAlignTable,
+ pSaveStruct->eColGrpAdjust );
+ break;
+ case HTML_O_VALIGN:
+ pSaveStruct->eColGrpVertOri =
+ (SwVertOrient)pColGrpOption->GetEnum( aHTMLTblVAlignTable,
+ pSaveStruct->eColGrpVertOri );
+ break;
+ }
+ }
+ }
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ if( !nToken )
+ nToken = GetNextToken(); // naechstes Token
+
+ sal_Bool bDone = sal_False;
+ while( (IsParserWorking() && !bDone) || bPending )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ ASSERT( pPendStack || !bCallNextToken ||
+ pCurTable->GetContext() || pCurTable->HasParentSection(),
+ "Wo ist die Section gebieben?" );
+ if( !pPendStack && bCallNextToken &&
+ (pCurTable->GetContext() || pCurTable->HasParentSection()) )
+ {
+ // NextToken direkt aufrufen (z.B. um den Inhalt von
+ // Floating-Frames oder Applets zu ignorieren)
+ NextToken( nToken );
+ }
+ else switch( nToken )
+ {
+ case HTML_TABLE_ON:
+ if( !pCurTable->GetContext() )
+ {
+ SkipToken( -1 );
+ bDone = sal_True;
+ }
+// else
+// {
+// NextToken( nToken );
+// }
+ break;
+ case HTML_COLGROUP_ON:
+ case HTML_THEAD_ON:
+ case HTML_TFOOT_ON:
+ case HTML_TBODY_ON:
+ case HTML_TABLEROW_ON:
+ case HTML_TABLE_OFF:
+ SkipToken( -1 );
+ case HTML_COLGROUP_OFF:
+ bDone = sal_True;
+ break;
+ case HTML_COL_ON:
+ {
+ sal_uInt16 nColSpan = 1;
+ sal_uInt16 nColWidth = pSaveStruct->nColGrpWidth;
+ sal_Bool bRelColWidth = pSaveStruct->bRelColGrpWidth;
+ SvxAdjust eColAdjust = pSaveStruct->eColGrpAdjust;
+ SwVertOrient eColVertOri = pSaveStruct->eColGrpVertOri;
+
+ const HTMLOptions *pColOptions = GetOptions();
+ for( sal_uInt16 i = pColOptions->Count(); i; )
+ {
+ const HTMLOption *pColOption = (*pColOptions)[--i];
+ switch( pColOption->GetToken() )
+ {
+ case HTML_O_ID:
+ InsertBookmark( pColOption->GetString() );
+ break;
+ case HTML_O_SPAN:
+ nColSpan = (sal_uInt16)pColOption->GetNumber();
+ break;
+ case HTML_O_WIDTH:
+ nColWidth = (sal_uInt16)pColOption->GetNumber();
+ bRelColWidth =
+ (pColOption->GetString().Search('*') != STRING_NOTFOUND);
+ break;
+ case HTML_O_ALIGN:
+ eColAdjust =
+ (SvxAdjust)pColOption->GetEnum( aHTMLPAlignTable,
+ eColAdjust );
+ break;
+ case HTML_O_VALIGN:
+ eColVertOri =
+ (SwVertOrient)pColOption->GetEnum( aHTMLTblVAlignTable,
+ eColVertOri );
+ break;
+ }
+ }
+ pCurTable->InsertCol( nColSpan, nColWidth, bRelColWidth,
+ eColAdjust, eColVertOri );
+
+ // die Angaben in <COLGRP> sollen ignoriert werden, wenn
+ // <COL>-Elemente existieren
+ pSaveStruct->nColGrpSpan = 0;
+ }
+ break;
+ case HTML_COL_OFF:
+ break; // Ignorieren
+ case HTML_MULTICOL_ON:
+ // spaltige Rahmen koennen wir hier leider nicht einguegen
+ break;
+ case HTML_TEXTTOKEN:
+ if( (pCurTable->GetContext() ||
+ !pCurTable->HasParentSection()) &&
+ 1==aToken.Len() && ' '==aToken.GetChar(0) )
+ break;
+ default:
+ pCurTable->MakeParentContents();
+ NextToken( nToken );
+ }
+
+ ASSERT( !bPending || !pPendStack,
+ "SwHTMLParser::BuildTableColGrp: Es gibt wieder einen Pend-Stack" );
+ bPending = sal_False;
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING == GetStatus() )
+ {
+ pPendStack = new SwPendingStack( HTML_COL_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+ }
+ else
+ {
+ pSaveStruct->CloseColGroup( pCurTable );
+ delete pSaveStruct;
+ }
+}
+
+class _CaptionSaveStruct : public _SectionSaveStruct
+{
+ SwPosition aSavePos;
+ SwHTMLNumRuleInfo aNumRuleInfo; // gueltige Numerierung
+
+public:
+
+ _HTMLAttrTable aAttrTab; // und die Attribute
+
+ _CaptionSaveStruct( SwHTMLParser& rParser, const SwPosition& rPos ) :
+ _SectionSaveStruct( rParser ), aSavePos( rPos )
+ {
+ rParser.SaveAttrTab( aAttrTab );
+
+ // Die aktuelle Numerierung wurde gerettet und muss nur
+ // noch beendet werden.
+#ifndef NUM_RELSPACE
+ if( rParser.GetNumInfo().GetNumRule() )
+ rParser.UpdateNumRuleInTable();
+#endif
+ aNumRuleInfo.Set( rParser.GetNumInfo() );
+ rParser.GetNumInfo().Clear();
+ }
+
+ const SwPosition& GetPos() const { return aSavePos; }
+
+ void RestoreAll( SwHTMLParser& rParser )
+ {
+ // Die alten Stack wiederherstellen
+ Restore( rParser );
+
+ // Die alte Attribut-Tabelle wiederherstellen
+ rParser.RestoreAttrTab( aAttrTab );
+
+ // Die alte Numerierung wieder aufspannen
+ rParser.GetNumInfo().Set( aNumRuleInfo );
+ }
+
+ virtual ~_CaptionSaveStruct();
+};
+
+_CaptionSaveStruct::~_CaptionSaveStruct()
+{}
+
+void SwHTMLParser::BuildTableCaption( HTMLTable *pCurTable )
+{
+ // <CAPTION> wurde bereits gelesen
+
+ if( !IsParserWorking() && !pPendStack )
+ return;
+
+ int nToken = 0;
+ _CaptionSaveStruct* pSaveStruct;
+
+ if( pPendStack )
+ {
+ pSaveStruct = (_CaptionSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ ASSERT( !pPendStack, "Wo kommt hier ein Pending-Stack her?" );
+
+ SaveState( nToken );
+ }
+ else
+ {
+ if( pTable->IsOverflowing() )
+ {
+ SaveState( 0 );
+ return;
+ }
+
+ sal_Bool bTop = sal_True;
+ const HTMLOptions *pOptions = GetOptions();
+ for ( sal_uInt16 i = pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*pOptions)[--i];
+ if( HTML_O_ALIGN == pOption->GetToken() )
+ {
+ if( pOption->GetString().EqualsIgnoreCaseAscii(sHTML_VA_bottom))
+ bTop = sal_False;
+ }
+ }
+
+ // Alte PaM-Position retten.
+ pSaveStruct = new _CaptionSaveStruct( *this, *pPam->GetPoint() );
+
+ // Eine Text-Section im Icons-Bereich als Container fuer die
+ // Ueberschrift anlegen und PaM dort reinstellen.
+ const SwStartNode *pStNd;
+ if( pTable == pCurTable )
+ pStNd = InsertTempTableCaptionSection();
+ else
+ pStNd = InsertTableSection( RES_POOLCOLL_TEXT );
+
+ _HTMLAttrContext *pCntxt = new _HTMLAttrContext( HTML_CAPTION_ON );
+
+ // Tabellen-Ueberschriften sind immer zentriert.
+ NewAttr( &aAttrTab.pAdjust, SvxAdjustItem(SVX_ADJUST_CENTER) );
+
+ _HTMLAttrs &rAttrs = pCntxt->GetAttrs();
+ rAttrs.Insert( aAttrTab.pAdjust, rAttrs.Count() );
+
+ PushContext( pCntxt );
+
+ // StartNode der Section an der Tabelle merken.
+ pCurTable->SetCaption( pStNd, bTop );
+
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ if( !nToken )
+ nToken = GetNextToken(); // naechstes Token
+
+ // </CAPTION> wird laut DTD benoetigt
+ sal_Bool bDone = sal_False;
+ while( IsParserWorking() && !bDone )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ switch( nToken )
+ {
+ case HTML_TABLE_ON:
+ if( !pPendStack )
+ {
+ pSaveStruct->pTable = pTable;
+ sal_Bool bHasToFly = pSaveStruct->pTable!=pCurTable;
+ BuildTable( pCurTable->GetTableAdjust( sal_True ),
+ sal_False, sal_True, sal_True, bHasToFly );
+ }
+ else
+ {
+ BuildTable( SVX_ADJUST_END );
+ }
+ if( SVPAR_PENDING != GetStatus() )
+ {
+ pTable = pSaveStruct->pTable;
+ }
+ break;
+ case HTML_TABLE_OFF:
+ case HTML_COLGROUP_ON:
+ case HTML_THEAD_ON:
+ case HTML_TFOOT_ON:
+ case HTML_TBODY_ON:
+ case HTML_TABLEROW_ON:
+ SkipToken( -1 );
+ bDone = sal_True;
+ break;
+
+ case HTML_CAPTION_OFF:
+ bDone = sal_True;
+ break;
+ default:
+ int nNxtToken = nToken;
+ if( pPendStack )
+ {
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+
+ ASSERT( !pTmp, "weiter kann es nicht gehen!" );
+ nNxtToken = 0; // neu lesen
+ }
+
+ if( IsParserWorking() )
+ NextToken( nToken );
+ break;
+ }
+
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING==GetStatus() )
+ {
+ pPendStack = new SwPendingStack( HTML_CAPTION_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+ return;
+ }
+
+ // Alle noch offenen Kontexte beenden
+ while( aContexts.Count() > nContextStAttrMin+1 )
+ {
+ _HTMLAttrContext *pCntxt = PopContext();
+ EndContext( pCntxt );
+ delete pCntxt;
+ }
+
+ // LF am Absatz-Ende entfernen
+ sal_Bool bLFStripped = StripTrailingLF() > 0;
+
+ if( pTable==pCurTable )
+ {
+ // Beim spaeteren verschieben der Beschriftung vor oder hinter
+ // die Tabelle wird der letzte Absatz nicht mitverschoben.
+ // Deshalb muss sich am Ende der Section immer ein leerer
+ // Absatz befinden.
+ if( pPam->GetPoint()->nContent.GetIndex() || bLFStripped )
+ AppendTxtNode( AM_NOSPACE );
+ }
+ else
+ {
+ // LFs am Absatz-Ende entfernen
+ if( !pPam->GetPoint()->nContent.GetIndex() && !bLFStripped )
+ StripTrailingPara();
+ }
+
+ // falls fuer die Zelle eine Ausrichtung gesetzt wurde, muessen
+ // wir die beenden
+ _HTMLAttrContext *pCntxt = PopContext();
+ EndContext( pCntxt );
+ delete pCntxt;
+
+ SetAttr( sal_False );
+
+ // Stacks und Attribut-Tabelle wiederherstellen
+ pSaveStruct->RestoreAll( *this );
+
+ // PaM wiederherstellen.
+ *pPam->GetPoint() = pSaveStruct->GetPos();
+
+ delete pSaveStruct;
+}
+
+class _TblSaveStruct : public SwPendingStackData
+{
+public:
+ HTMLTable *pCurTable;
+
+ _TblSaveStruct( HTMLTable *pCurTbl ) :
+ pCurTable( pCurTbl )
+ {}
+
+ virtual ~_TblSaveStruct();
+
+ // Aufbau der Tabelle anstossen und die Tabelle ggf. in einen
+ // Rahmen packen. Wenn sal_True zurueckgegeben wird muss noch ein
+ // Absatz eingefuegt werden!
+ void MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc );
+};
+
+_TblSaveStruct::~_TblSaveStruct()
+{}
+
+
+void _TblSaveStruct::MakeTable( sal_uInt16 nWidth, SwPosition& rPos, SwDoc *pDoc )
+{
+ pCurTable->MakeTable( 0, nWidth );
+
+ _HTMLTableContext *pTCntxt = pCurTable->GetContext();
+ ASSERT( pTCntxt, "Wo ist der Tabellen-Kontext" );
+
+ SwTableNode *pTblNd = pTCntxt->GetTableNode();
+ ASSERT( pTblNd, "Wo ist der Tabellen-Node" );
+
+ if( pDoc->GetRootFrm() && pTblNd )
+ {
+ // Existiert schon ein Layout, dann muss an dieser Tabelle die
+ // BoxFrames neu erzeugt werden.
+
+ if( pTCntxt->GetFrmFmt() )
+ {
+ pTCntxt->GetFrmFmt()->DelFrms();
+ pTblNd->DelFrms();
+ pTCntxt->GetFrmFmt()->MakeFrms();
+ }
+ else
+ {
+ pTblNd->DelFrms();
+ SwNodeIndex aIdx( *pTblNd->EndOfSectionNode(), 1 );
+ ASSERT( aIdx.GetIndex() <= pTCntxt->GetPos()->nNode.GetIndex(),
+ "unerwarteter Node fuer das Tabellen-Layout" );
+ pTblNd->MakeFrms( &aIdx );
+ }
+ }
+
+ rPos = *pTCntxt->GetPos();
+}
+
+
+HTMLTableOptions::HTMLTableOptions( const HTMLOptions *pOptions,
+ SvxAdjust eParentAdjust ) :
+ nCols( 0 ),
+ nWidth( 0 ), nHeight( 0 ),
+ nCellPadding( USHRT_MAX ), nCellSpacing( USHRT_MAX ),
+ nBorder( USHRT_MAX ),
+ nHSpace( 0 ), nVSpace( 0 ),
+ eAdjust( eParentAdjust ), eVertOri( VERT_CENTER ),
+ eFrame( HTML_TF_VOID ), eRules( HTML_TR_NONE ),
+ bPrcWidth( sal_False ),
+ bTableAdjust( sal_False ),
+ bBGColor( sal_False ),
+ aBorderColor( COL_GRAY )
+{
+ sal_Bool bBorderColor = sal_False;
+ sal_Bool bHasFrame = sal_False, bHasRules = sal_False;
+
+ for( sal_uInt16 i = pOptions->Count(); i; )
+ {
+ const HTMLOption *pOption = (*pOptions)[--i];
+ switch( pOption->GetToken() )
+ {
+ case HTML_O_ID:
+ aId = pOption->GetString();
+ break;
+ case HTML_O_COLS:
+ nCols = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_WIDTH:
+ nWidth = (sal_uInt16)pOption->GetNumber();
+ bPrcWidth = (pOption->GetString().Search('%') != STRING_NOTFOUND);
+ if( bPrcWidth && nWidth>100 )
+ nWidth = 100;
+ break;
+ case HTML_O_HEIGHT:
+ nHeight = (sal_uInt16)pOption->GetNumber();
+ if( pOption->GetString().Search('%') != STRING_NOTFOUND )
+ nHeight = 0; // keine %-Anagben benutzen!!!
+ break;
+ case HTML_O_CELLPADDING:
+ nCellPadding = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_CELLSPACING:
+ nCellSpacing = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_ALIGN:
+ {
+ sal_uInt16 nAdjust = eAdjust;
+ if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) )
+ {
+ eAdjust = (SvxAdjust)nAdjust;
+ bTableAdjust = sal_True;
+ }
+ }
+ break;
+ case HTML_O_VALIGN:
+ eVertOri = (SwVertOrient)pOption->GetEnum( aHTMLTblVAlignTable,
+ eVertOri );
+ break;
+ case HTML_O_BORDER:
+ // BORDER und BORDER=BORDER wie BORDER=1 behandeln
+ if( pOption->GetString().Len() &&
+ !pOption->GetString().EqualsIgnoreCaseAscii(sHTML_O_border) )
+ nBorder = (sal_uInt16)pOption->GetNumber();
+ else
+ nBorder = 1;
+
+ if( !bHasFrame )
+ eFrame = ( nBorder ? HTML_TF_BOX : HTML_TF_VOID );
+ if( !bHasRules )
+ eRules = ( nBorder ? HTML_TR_ALL : HTML_TR_NONE );
+ break;
+ case HTML_O_FRAME:
+ eFrame = pOption->GetTableFrame();
+ bHasFrame = sal_True;
+ break;
+ case HTML_O_RULES:
+ eRules = pOption->GetTableRules();
+ bHasRules = sal_True;
+ break;
+ case HTML_O_BGCOLOR:
+ // Leere BGCOLOR bei <TABLE>, <TR> und <TD>/<TH> wie Netscape
+ // ignorieren, bei allen anderen Tags *wirklich* nicht.
+ if( pOption->GetString().Len() )
+ {
+ pOption->GetColor( aBGColor );
+ bBGColor = sal_True;
+ }
+ break;
+ case HTML_O_BACKGROUND:
+ aBGImage = pOption->GetString();
+ break;
+ case HTML_O_BORDERCOLOR:
+ pOption->GetColor( aBorderColor );
+ bBorderColor = sal_True;
+ break;
+ case HTML_O_BORDERCOLORDARK:
+ if( !bBorderColor )
+ pOption->GetColor( aBorderColor );
+ break;
+ case HTML_O_STYLE:
+ aStyle = pOption->GetString();
+ break;
+ case HTML_O_CLASS:
+ aClass = pOption->GetString();
+ break;
+ case HTML_O_HSPACE:
+ nHSpace = (sal_uInt16)pOption->GetNumber();
+ break;
+ case HTML_O_VSPACE:
+ nVSpace = (sal_uInt16)pOption->GetNumber();
+ break;
+ }
+ }
+
+ if( nCols && !nWidth )
+ {
+ nWidth = 100;
+ bPrcWidth = sal_True;
+ }
+
+ // Wenn BORDER=0 oder kein BORDER gegeben ist, daan darf es auch
+ // keine Umrandung geben
+ if( 0==nBorder || USHRT_MAX==nBorder )
+ {
+ eFrame = HTML_TF_VOID;
+ eRules = HTML_TR_NONE;
+ }
+}
+
+
+HTMLTable *SwHTMLParser::BuildTable( SvxAdjust eParentAdjust,
+ sal_Bool bIsParentHead,
+ sal_Bool bHasParentSection,
+ sal_Bool bMakeTopSubTable,
+ sal_Bool bHasToFly )
+{
+ if( !IsParserWorking() && !pPendStack )
+ return 0;
+
+ int nToken = 0;
+ sal_Bool bPending = sal_False;
+ _TblSaveStruct* pSaveStruct;
+
+ if( pPendStack )
+ {
+ pSaveStruct = (_TblSaveStruct*)pPendStack->pData;
+
+ SwPendingStack* pTmp = pPendStack->pNext;
+ delete pPendStack;
+ pPendStack = pTmp;
+ nToken = pPendStack ? pPendStack->nToken : GetSaveToken();
+ bPending = SVPAR_ERROR == eState && pPendStack != 0;
+
+ SaveState( nToken );
+ }
+ else
+ {
+ HTMLTableOptions *pTblOptions =
+ new HTMLTableOptions( GetOptions(), eParentAdjust );
+
+ if( pTblOptions->aId.Len() )
+ InsertBookmark( pTblOptions->aId );
+
+ // Wenn die Tabelle in einem Rahmen steht oder link oder rechts
+ // ausgerichtet ist, wird in jedem Fall eine "echte" Tabelle daraus.
+ if( bMakeTopSubTable || bHasToFly ||
+ (pTblOptions->bTableAdjust &&
+ (SVX_ADJUST_LEFT==pTblOptions->eAdjust ||
+ SVX_ADJUST_RIGHT==pTblOptions->eAdjust)) )
+ {
+ pTable = 0;
+ }
+
+ HTMLTable *pCurTable = new HTMLTable( this, pTable,
+ bIsParentHead,
+ bHasParentSection,
+ bMakeTopSubTable,
+ bHasToFly,
+ pTblOptions );
+ if( !pTable )
+ pTable = pCurTable;
+
+ pSaveStruct = new _TblSaveStruct( pCurTable );
+
+ delete pTblOptions;
+
+ // ist beim ersten GetNextToken schon pending, muss bei
+ // wiederaufsetzen auf jedenfall neu gelesen werden!
+ SaveState( 0 );
+ }
+
+ HTMLTable *pCurTable = pSaveStruct->pCurTable;
+
+ // </TABLE> wird laut DTD benoetigt
+ if( !nToken )
+ nToken = GetNextToken(); // naechstes Token
+
+ sal_Bool bDone = sal_False;
+ while( (IsParserWorking() && !bDone) || bPending )
+ {
+ SaveState( nToken );
+
+ nToken = FilterToken( nToken );
+
+ ASSERT( pPendStack || !bCallNextToken ||
+ pCurTable->GetContext() || pCurTable->HasParentSection(),
+ "Wo ist die Section gebieben?" );
+ if( !pPendStack && bCallNextToken &&
+ (pCurTable->GetContext() || pCurTable->HasParentSection()) )
+ {
+ // NextToken direkt aufrufen (z.B. um den Inhalt von
+ // Floating-Frames oder Applets zu ignorieren)
+ NextToken( nToken );
+ }
+ else switch( nToken )
+ {
+ case HTML_TABLE_ON:
+ if( !pCurTable->GetContext() )
+ {
+ // Wenn noch keine Tabelle eingefuegt wurde,
+ // die naechste Tabelle lesen
+ SkipToken( -1 );
+ bDone = sal_True;
+ }
+// else
+// {
+// NextToken( nToken );
+// }
+ break;
+ case HTML_TABLE_OFF:
+ bDone = sal_True;
+ break;
+ case HTML_CAPTION_ON:
+ BuildTableCaption( pCurTable );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_COL_ON:
+ SkipToken( -1 );
+ BuildTableColGroup( pCurTable, sal_False );
+ break;
+ case HTML_COLGROUP_ON:
+ BuildTableColGroup( pCurTable, sal_True );
+ break;
+ case HTML_TABLEROW_ON:
+ case HTML_TABLEHEADER_ON:
+ case HTML_TABLEDATA_ON:
+ SkipToken( -1 );
+ BuildTableSection( pCurTable, sal_False, sal_False );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_THEAD_ON:
+ case HTML_TFOOT_ON:
+ case HTML_TBODY_ON:
+ BuildTableSection( pCurTable, sal_True, HTML_THEAD_ON==nToken );
+ bDone = pTable->IsOverflowing();
+ break;
+ case HTML_MULTICOL_ON:
+ // spaltige Rahmen koennen wir hier leider nicht einguegen
+ break;
+ case HTML_FORM_ON:
+ NewForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_FORM_OFF:
+ EndForm( sal_False ); // keinen neuen Absatz aufmachen!
+ break;
+ case HTML_TEXTTOKEN:
+ // Blank-Strings sind u. U. eine Folge von CR+LF und kein Text
+ if( (pCurTable->GetContext() ||
+ !pCurTable->HasParentSection()) &&
+ 1==aToken.Len() && ' '==aToken.GetChar(0) )
+ break;
+ default:
+ pCurTable->MakeParentContents();
+ NextToken( nToken );
+ break;
+ }
+
+ ASSERT( !bPending || !pPendStack,
+ "SwHTMLParser::BuildTable: Es gibt wieder einen Pend-Stack" );
+ bPending = sal_False;
+ if( IsParserWorking() )
+ SaveState( 0 );
+
+ if( !bDone )
+ nToken = GetNextToken();
+ }
+
+ if( SVPAR_PENDING == GetStatus() )
+ {
+ pPendStack = new SwPendingStack( HTML_TABLE_ON, pPendStack );
+ pPendStack->pData = pSaveStruct;
+ return 0;
+ }
+
+ _HTMLTableContext *pTCntxt = pCurTable->GetContext();
+ if( pTCntxt )
+ {
+ // Die Tabelle wurde auch angelegt
+
+ // Tabellen-Struktur anpassen
+ pCurTable->CloseTable();
+
+ // ausserhalb von Zellen begonnene Kontexte beenden
+ // muss vor(!) dem Umsetzten der Attribut Tabelle existieren,
+ // weil die aktuelle danach nicht mehr existiert
+ while( aContexts.Count() > nContextStAttrMin )
+ {
+ _HTMLAttrContext *pCntxt = PopContext();
+ ClearContext( pCntxt );
+ delete pCntxt;
+ }
+
+ nContextStMin = pTCntxt->GetContextStMin();
+ nContextStAttrMin = pTCntxt->GetContextStAttrMin();
+
+ if( pTable==pCurTable )
+ {
+ // Tabellen-Beschriftung setzen
+ const SwStartNode *pCapStNd = pTable->GetCaptionStartNode();
+ if( pCapStNd )
+ {
+ // Der letzte Absatz der Section wird nie mitkopiert. Deshalb
+ // muss die Section mindestens zwei Absaetze enthalten.
+
+ if( pCapStNd->EndOfSectionIndex() - pCapStNd->GetIndex() > 2 )
+ {
+ // Start-Node und letzten Absatz nicht mitkopieren.
+ SwNodeRange aSrcRg( *pCapStNd, 1,
+ *pCapStNd->EndOfSectionNode(), -1 );
+
+ sal_Bool bTop = pTable->IsTopCaption();
+ SwStartNode *pTblStNd = pTCntxt->GetTableNode();
+
+ ASSERT( pTblStNd, "Wo ist der Tabellen-Node" );
+ ASSERT( pTblStNd==pPam->GetNode()->FindTableNode(),
+ "Stehen wir in der falschen Tabelle?" );
+
+ SwNode* pNd;
+ if( bTop )
+ pNd = pTblStNd;
+ else
+ pNd = pTblStNd->EndOfSectionNode();
+ SwNodeIndex aDstIdx( *pNd, bTop ? 0 : 1 );
+
+ pDoc->Move( aSrcRg, aDstIdx );
+
+ // Wenn die Caption vor der Tabelle eingefuegt wurde muss
+ // eine an der Tabelle gestzte Seitenvorlage noch in den
+ // ersten Absatz der Ueberschrift verschoben werden.
+ // Ausserdem muessen alle gemerkten Indizes, die auf den
+ // Tabellen-Node zeigen noch verschoben werden.
+ if( bTop )
+ {
+ MovePageDescAttrs( pTblStNd, aSrcRg.aStart.GetIndex(),
+ sal_False );
+ }
+ }
+
+ // Die Section wird jetzt nicht mehr gebraucht.
+ pPam->SetMark();
+ pPam->DeleteMark();
+ pDoc->DeleteSection( (SwStartNode *)pCapStNd );
+ pTable->SetCaption( 0, sal_False );
+ }
+
+ // SwTable aufbereiten
+ sal_uInt16 nBrowseWidth = (sal_uInt16)GetCurrentBrowseWidth();
+ pSaveStruct->MakeTable( nBrowseWidth, *pPam->GetPoint(), pDoc );
+
+#ifdef TEST_RESIZE
+ const SwTable *pSwTable = pTable->GetSwTable();
+ SwHTMLTableLayout *pLayoutInfo =
+ pSwTable ? ((SwTable *)pSwTable)->GetHTMLTableLayout() : 0;
+ if( pLayoutInfo )
+ {
+ ViewShell *pVSh = CheckActionViewShell();
+ if( pVSh )
+ {
+ CallEndAction( sal_False, sal_False );
+ CallStartAction( pVSh, sal_False );
+
+ sal_uInt16 nNewBrwoseWidth =
+ (sal_uInt16)GetCurrentBrowseWidth();
+ if( nBrowseWidth != nNewBrowseWidth )
+ pLayoutInfo->Resize( nNewBrowseWidth );
+ }
+ }
+#endif
+ }
+
+ GetNumInfo().Set( pTCntxt->GetNumInfo() );
+ pTCntxt->RestorePREListingXMP( *this );
+ RestoreAttrTab( pTCntxt->aAttrTab );
+
+ if( pTable==pCurTable )
+ {
+ // oberen Absatz-Abstand einstellen
+ bUpperSpace = sal_True;
+ SetTxtCollAttrs();
+
+ nParaCnt -= Min(nParaCnt, pTCntxt->GetTableNode()->GetTable().GetTabSortBoxes().Count());
+
+ // ggfs. eine Tabelle anspringen
+ if( JUMPTO_TABLE == eJumpTo && pTable->GetSwTable() &&
+ pTable->GetSwTable()->GetFrmFmt()->GetName() == sJmpMark )
+ {
+ bChkJumpMark = sal_True;
+ eJumpTo = JUMPTO_NONE;
+ }
+
+ // fix #37886#: Wenn Import abgebrochen wurde kein erneutes Show
+ // aufrufen, weil die ViewShell schon geloescht wurde!
+ // fix #41669#: Genuegt nicht. Auch im ACCEPTING_STATE darf
+ // kein Show aufgerufen werden, weil sonst waehrend des
+ // Reschedules der Parser zerstoert wird, wenn noch ein
+ // DataAvailable-Link kommt. Deshalb: Nur im WORKING-State.
+ if( !nParaCnt && SVPAR_WORKING == GetStatus() )
+ Show();
+ }
+ }
+ else if( pTable==pCurTable )
+ {
+ // Es wurde gar keine Tabelle gelesen.
+
+ // Dann muss eine evtl gelesene Beschriftung noch geloescht werden.
+ const SwStartNode *pCapStNd = pCurTable->GetCaptionStartNode();
+ if( pCapStNd )
+ {
+ pPam->SetMark();
+ pPam->DeleteMark();
+ pDoc->DeleteSection( (SwStartNode *)pCapStNd );
+ pCurTable->SetCaption( 0, sal_False );
+ }
+ }
+
+ if( pTable == pCurTable )
+ {
+ delete pSaveStruct->pCurTable;
+ pSaveStruct->pCurTable = 0;
+ pTable = 0;
+ }
+
+ HTMLTable* pRetTbl = pSaveStruct->pCurTable;
+ delete pSaveStruct;
+
+ return pRetTbl;
+}
+
+
+
+/*************************************************************************
+
+ Source Code Control System - Header
+
+ $Header: /zpool/svn/migration/cvs_rep_09_09_08/code/sw/source/filter/html/htmltab.cxx,v 1.1.1.1 2000-09-18 17:14:56 hr Exp $
+
+ Source Code Control System - Update
+
+ $Log: not supported by cvs2svn $
+ Revision 1.295 2000/09/18 16:04:46 willem.vandorp
+ OpenOffice header added.
+
+ Revision 1.294 2000/09/05 14:01:28 mib
+ #78294#: removed support for frameset documents
+
+ Revision 1.293 2000/06/26 09:52:30 jp
+ must change: GetAppWindow->GetDefaultDevice
+
+ Revision 1.292 2000/04/28 14:29:12 mib
+ unicode
+
+ Revision 1.291 2000/04/10 12:20:57 mib
+ unicode
+
+ Revision 1.290 2000/03/21 15:06:18 os
+ UNOIII
+
+ Revision 1.289 2000/03/03 15:21:01 os
+ StarView remainders removed
+
+ Revision 1.288 2000/02/11 14:37:28 hr
+ #70473# changes for unicode ( patched by automated patchtool )
+
+ Revision 1.287 2000/02/07 08:24:58 mib
+ #72727#: HORI_LEFT_AND_WIDTH
+
+ Revision 1.286 1999/11/19 16:40:20 os
+ modules renamed
+
+ Revision 1.285 1999/09/17 12:14:09 mib
+ support of multiple and non system text encodings
+
+ Revision 1.284 1999/07/29 06:21:52 MIB
+ fix LHS means left border and RHS right border, not vice versa
+
+
+ Rev 1.283 29 Jul 1999 08:21:52 MIB
+ fix LHS means left border and RHS right border, not vice versa
+
+ Rev 1.282 10 Jun 1999 10:34:26 JP
+ have to change: no AppWin from SfxApp
+
+ Rev 1.281 09 Jun 1999 19:37:00 JP
+ have to change: no cast from GetpApp to SfxApp/OffApp, SfxShell only subclass of SfxApp
+
+ Rev 1.280 20 Apr 1999 10:07:50 MIB
+ bCallNextToken auch in Rows etc. auswerten
+
+ Rev 1.279 15 Apr 1999 13:48:20 MIB
+ #41833#: Styles fuer A-Tag
+
+ Rev 1.278 12 Apr 1999 09:23:28 MIB
+ Korrekt horizontal splitten (auch #64460#)
+
+ Rev 1.277 09 Apr 1999 10:30:36 MIB
+ #64522#: Styles fuer TD/TH auswerten
+
+ Rev 1.276 08 Apr 1999 11:13:10 MIB
+ #56334#: Optimierung fuer Hintergrundfarben wieder ausgebaut
+
+ Rev 1.275 06 Apr 1999 12:07:14 MIB
+ #64308#: ALIGN=? an Tabelle
+
+ Rev 1.274 01 Apr 1999 10:20:08 MIB
+ bug fix: Leere BGColor nicht auswerten
+
+ Rev 1.273 01 Apr 1999 08:57:02 MIB
+ #56334#: Keine Spezialbehandlung der Hintergruende fuer die GC mehr noetig
+
+ Rev 1.272 30 Mar 1999 11:58:36 MIB
+ #62977#: Nicht mehr Spalten einfuegen als Zellen je Zeile vorhanden
+
+ Rev 1.271 30 Mar 1999 11:44:26 MIB
+ #62977#: Nicht mehr Spalten einfuegen als Zellen je Zeile vorhanden (nur>529)
+
+ Rev 1.270 26 Mar 1999 11:39:46 MIB
+ #63049#: Sofortige Numerierungs-Aktualisierung in Tabellen ist jetzt unnoetig
+
+ Rev 1.269 17 Mar 1999 16:47:10 MIB
+ #63049#: Numerierungen mit relativen Abstaenden
+
+ Rev 1.268 10 Mar 1999 15:44:10 MIB
+ #62682#: Beim Setzen der Control-Groesse wenn noetig auf die ViewShell warten
+
+ Rev 1.267 25 Feb 1999 16:00:42 MIB
+ #61949#: globale Shell entsorgt
+
+ Rev 1.266 27 Jan 1999 09:43:56 OS
+ #56371# TF_ONE51
+
+ Rev 1.265 11 Jan 1999 11:17:08 MIB
+ Attribut-Tabellen-Ueberpruefung in NonPro wegen Asserts nicht immer
+
+ Rev 1.264 05 Jan 1999 14:48:00 MIB
+ #60429#: Zeilenhoehe korrekt berechnen
+
+ Rev 1.263 11 Nov 1998 17:42:10 MIB
+ #59059#: Beim Abbrechen Pendung-Stack noch aufraeumen
+
+ Rev 1.262 09 Nov 1998 11:35:18 MIB
+ #59159#: Pending-Stack von fremden Token nicht loeschen
+
+ Rev 1.261 03 Nov 1998 15:37:10 MIB
+ #58840#: bHoriSplittAll-Assert war falsch
+
+ Rev 1.260 25 Sep 1998 08:36:04 MIB
+ #45631#: Tabellen nach 64000 Zellen beenden
+
+ Rev 1.259 14 Sep 1998 11:41:12 MIB
+ #51238#: Beim Setzen des Zeilen-Hintergrundes ROWSPAN>1 beachten
+
+ Rev 1.258 31 Aug 1998 11:19:44 MIB
+ ##: Beim vertikalen Zerlegen auch letzte Spalte auf moegliche vert. Zerlegeung pruefen
+
+ Rev 1.257 27 Aug 1998 09:45:52 MIB
+ #54170#: Line-Format-Attribute zuruecksetzen, bevor Hoehe oder Hintergrund gesetzt wird
+
+ Rev 1.256 26 Aug 1998 09:30:36 MIB
+ #55144#: Umlauf bei Tabellen in Rahmen richtig setzen und beachten
+
+ Rev 1.255 21 Jul 1998 16:55:46 JP
+ Bug #53456#: nie per Add eine Box im Format anmelden, sondern per Box::ChgFrmFmt
+
+ Rev 1.254 05 Jun 1998 13:56:54 JP
+ Bug #42487#: Sprung zum Mark schon waehrend des Ladens ausfuehren
+
+ Rev 1.253 12 May 1998 15:50:24 JP
+ rund um Flys/DrawObjs im Doc/FESh umgestellt/optimiert
+
+ Rev 1.252 15 Apr 1998 14:56:46 MIB
+ Zwei-seitige Printing-Extensions
+
+ Rev 1.251 27 Mar 1998 18:02:42 MIB
+ HSPACE/VSPACE
+
+ Rev 1.250 24 Mar 1998 14:31:24 MIB
+ obsolete ParseStyleOptions-Methode entfernt
+
+ Rev 1.249 11 Mar 1998 18:28:54 MIB
+ fix #47846#: auto-gebundenen Rahmen korrekt verankern
+
+ Rev 1.248 02 Mar 1998 18:43:16 MIB
+ fix #45489#: Umrandung ueber mehrere Ebenenen vererben
+
+ Rev 1.247 27 Feb 1998 16:42:38 MIB
+ fix #46450#: Horizontale une vertikale Ausrichtung von Zellen mit NumFmt
+
+ Rev 1.246 27 Feb 1998 14:05:10 MIB
+ Auto-gebundene Rahmen
+
+ Rev 1.245 25 Feb 1998 12:17:36 MIB
+ I like ME and its 0xffs
+
+ Rev 1.244 25 Feb 1998 10:49:54 MIB
+ fix: Tabellen-Ueberschriften in Sub-Tabellen gleich in eine eigene Box packen
+
+ Rev 1.243 24 Feb 1998 17:45:50 MIB
+ Attribute von Tabellen-Zellen ueber AttrTab setzen
+
+ Rev 1.242 20 Feb 1998 18:52:04 MIB
+ fix #45328#: Bessere Behandlung von Styles an Tabellen-Zellen
+
+ Rev 1.241 20 Feb 1998 12:25:12 MIB
+ fix #45631#: Weniger ::com::sun::star::frame::Frame-Formate anlegen
+
+ Rev 1.240 19 Feb 1998 15:14:52 MIB
+ fix #47394#: Tabellen-Zellen wurden unnoetig geteilt
+
+ Rev 1.239 18 Feb 1998 10:57:30 MIB
+ fix #45153#: Bei fixer Tabellenhoehe Tabelle in Tabelle beachten
+
+ Rev 1.238 13 Feb 1998 18:48:42 HR
+ C40_INSERT
+
+ Rev 1.237 29 Jan 1998 21:34:18 JP
+ GetEndOfIcons ersetzt durch GetEndOfExtras, das auf GetEndOfRedlines mappt
+
+ Rev 1.236 19 Jan 1998 16:27:14 MIB
+ Numerierungs-Umbau
+
+ Rev 1.235 26 Nov 1997 19:09:42 MA
+ includes
+
+ Rev 1.234 17 Nov 1997 10:16:40 JP
+ Umstellung Numerierung
+
+ Rev 1.233 09 Oct 1997 14:34:14 JP
+ Umstellung NodeIndex/-Array/BigPtrArray
+
+ Rev 1.232 19 Sep 1997 08:40:34 MIB
+ fix #41185#: Laufschrift an Tabellenzellen-Breite anpassen
+
+ Rev 1.231 16 Sep 1997 14:55:28 MIB
+ ITEMID_BOXINFOITEM (voreubergendend) definieren
+
+ Rev 1.230 16 Sep 1997 13:05:08 MIB
+ Abs.-Pos. Rahmen am Tabellen-Ende beenden
+
+ Rev 1.229 16 Sep 1997 11:19:12 MIB
+ Kopf-/Fusszeilen ohne Moven von Nodes, autom. Beenden von Bereichen/Rahmen
+
+ Rev 1.228 12 Sep 1997 11:54:02 MIB
+ fix #41253#: Script in PRE (keine Schleifen)
+
+ Rev 1.227 09 Sep 1997 14:10:48 MIB
+ Ueberall Browse-View-Breite statt Seitenbreite verwenden
+
+ Rev 1.226 08 Sep 1997 10:38:54 MIB
+ Keine Schleifen fuer PRE mehr (auch fix #41253#) (nicht freigeschaltet)
+
+ Rev 1.225 04 Sep 1997 15:45:30 MIB
+ fix: <NOBR> auch beachten, wenn danach ein <BR> folgt
+
+ Rev 1.224 04 Sep 1997 09:37:40 MIB
+ fix #42771#: Tabellen in Rahmen beachten
+
+ Rev 1.223 29 Aug 1997 16:49:44 OS
+ DLL-Umstellung
+
+ Rev 1.222 15 Aug 1997 12:47:38 OS
+ charatr/frmatr/txtatr aufgeteilt
+
+ Rev 1.221 12 Aug 1997 13:42:50 OS
+ Header-Umstellung
+
+ Rev 1.220 11 Aug 1997 14:04:42 OM
+ Headerfile-Umstellung
+
+ Rev 1.219 07 Aug 1997 15:08:18 OM
+ Headerfile-Umstellung
+
+ Rev 1.218 04 Aug 1997 13:54:24 MIB
+ aboslute psoitioning (fuer fast alle Zeichen-Attribute/-Vorlagen)
+
+ Rev 1.217 31 Jul 1997 10:44:32 MIB
+ DIV-Stack weg
+
+ Rev 1.216 25 Jul 1997 11:08:30 MIB
+ fix #42109#: Kommentare bei Tabellen in Tabellen beachten
+
+ Rev 1.215 21 Jul 1997 10:55:22 MIB
+ fix #41869#: Keile zusaetlichen Splaten bei selbst exportierten Tabellen
+
+ Rev 1.214 16 Jul 1997 18:33:04 MIB
+ fix #41669#: Kein Show im Accepted-State, weil Parser sonst zerst. werden kann
+
+ Rev 1.213 15 Jul 1997 13:11:54 MIB
+ fix: Tabellen-Ueberschriften immer zentrieren
+
+ Rev 1.212 11 Jul 1997 11:51:30 MIB
+ fix: Bei RULES=COLS auch Zeilen-Gruppen umranden
+
+ Rev 1.211 10 Jul 1997 10:30:30 MIB
+ fix #41516#: Keine Umrandung bei FRAME ohne BORDER
+
+ Rev 1.210 09 Jul 1997 08:45:16 MIB
+ 'Ueberschrift wiederholen' uanhaengig von </THEAD>-Position abktivieren
+
+ Rev 1.209 08 Jul 1997 14:16:42 MIB
+ Meta-Tags als PostIts und die immer im ersten Body-Absatz verankern
+
+ Rev 1.208 03 Jul 1997 09:37:00 MIB
+ HTML-Tabellen: Bei letzter Grafik ohne Groesse sofort anpassen
+
+ Rev 1.207 01 Jul 1997 12:39:14 MIB
+ fix: Beim Vergeben von Filler-Boxen tatsaechliche Umrandung betrachten
+
+ Rev 1.206 28 Jun 1997 11:32:00 MIB
+ fix: Bei Umrandung und CELLPADDING=0 minimalen Abstand zum Inhalte beachten
+
+ Rev 1.205 27 Jun 1997 15:57:40 MIB
+ fix: Pending-Stack bei bCallNextToken beachten
+
+ Rev 1.204 26 Jun 1997 11:54:52 MIB
+ fix #41003#: Nimber-Format nur bei Value oder leerer Zelle setzen
+
+ Rev 1.203 26 Jun 1997 10:56:32 MIB
+ fix #40941#: Tabellen In Tabellen in Rahmen, wenn sie ausweichen muessen
+
+ Rev 1.202 24 Jun 1997 08:59:54 MIB
+ fix: Beim Splitten von Zelle auch Tabellen-Layout anpassen
+
+ Rev 1.201 20 Jun 1997 13:36:08 MIB
+ Auch Grafiken in Tabellen asynchron laden
+
+ Rev 1.200 19 Jun 1997 11:57:04 MIB
+ Tabellen weichen jetzt Rahmen aus
+
+ Rev 1.199 16 Jun 1997 08:27:56 MIB
+ CLASS/ID auch fier Tabellen
+
+ Rev 1.198 12 Jun 1997 15:55:36 MIB
+ 358-Tabellen korrekt importieren
+
+ Rev 1.197 12 Jun 1997 09:13:42 MIB
+ fix: PostIts auch vor Tabellen in Rahmen in die Tabelle verschieben
+
+ Rev 1.196 09 Jun 1997 18:14:08 MIB
+ fix: leere Zellen und Zellen, die nur Grafiken enthalten, bekommen einen 2pt-Font
+
+ Rev 1.195 09 Jun 1997 12:56:46 MIB
+ fix: Kein GPF beim berechnen der Exportierbarkeit des Layouts mehr
+
+ Rev 1.194 09 Jun 1997 09:07:22 MIB
+ fix: Auch aus leeren Absatzen 2 LF entfernen
+
+ Rev 1.193 05 Jun 1997 17:42:38 MIB
+ fix: <NOBR> auch mit Space dahinter, Anpassungen an Export-Moeglichkeit
+
+ Rev 1.192 02 Jun 1997 12:01:18 MIB
+ fix: Bei vorhandener Umrandung deren Breite doch beruecksichtigen
+
+ Rev 1.191 30 May 1997 18:02:42 MIB
+ NOWRAP/NOBR, Einhalten der Mindestbreite bei rel. Tabellen
+
+ Rev 1.190 28 May 1997 19:14:26 MIB
+ fix: Layout-Info nicht im Destr. loeschen, TEST_RESIZE entfernt
+
+ Rev 1.189 28 May 1997 16:11:52 MIB
+ fix: Numerierung ueber Tabellen-Ueberschrift retten
+
+ Rev 1.188 28 May 1997 15:35:34 MIB
+ fix: -Angabe aus dem Format fuer Rahmen zu nehmen war keine gute Idee
+
+ Rev 1.187 27 May 1997 11:47:08 MIB
+ Netscape-konformere Beruecksichtigung von BORDER/CELLPADDING/CELLSPACING
+
+ Rev 1.186 15 May 1997 15:42:36 MIB
+ HTML-Tabellen-Layout an SwTable merken
+
+ Rev 1.185 06 May 1997 12:07:54 MA
+ swtablehxx aufgeteilt
+
+ Rev 1.184 30 Apr 1997 18:10:02 MIB
+ Ermitteln der verfuegbaren Breite ueber Layout
+
+ Rev 1.183 30 Apr 1997 14:54:46 MIB
+ Tabellen-Layout ausgelagert
+
+ Rev 1.182 23 Apr 1997 14:57:04 MIB
+ memory leak beseitig (wie 1.171.1.0)
+
+ Rev 1.181 21 Apr 1997 18:08:18 MIB
+ fix #38931#: 1. Absaetze hinter Tab in Tab nicht numerieren, Zelle hinter T in T
+
+ Rev 1.180 16 Apr 1997 18:23:12 MIB
+ fix #37769#: Tabellenbreite sinnvoll begrenzen und USHRT_MAX-Ueberlauf vermeiden
+
+ Rev 1.179 16 Apr 1997 15:19:26 MIB
+ fix #36787#: Ersatzdarstellung von Frames, Applets etc. auch in Tabellen ignorieren
+
+ Rev 1.178 14 Apr 1997 16:44:48 MIB
+ fixes #36418#, #36819#: Tabellen mit relativen/nicht relativen Spalten gleichz.
+
+ Rev 1.177 11 Apr 1997 17:58:52 MIB
+ fix #36820#: Bei Tabellen in Rahmen Absatz-Abstand beachten
+
+ Rev 1.176 10 Apr 1997 16:40:00 MIB
+ fix #37987#: Andere Berechnung der Spalten-Mindestbreite
+
+ Rev 1.175 09 Apr 1997 16:50:50 MIB
+ fix #38575#: Nicht immer einen Absatz vor Tabellen in Rahmen aufmachen
+
+ Rev 1.174 08 Apr 1997 11:07:02 MIB
+ fix #37219#: In Tabellen-Beschriftung alles erlauben
+
+ Rev 1.173 04 Apr 1997 11:04:22 AMA
+ Chg: Ein weiterer Parameter fuer GetMinMaxSize: das absolute Minimum
+
+ Rev 1.172 01 Apr 1997 10:47:08 MIB
+ fix #38284#: keine gelegentlich vertikale Ausrichtung an Zellen ohne Inhalt mehr
+
+ Rev 1.171 18 Mar 1997 19:06:44 MIB
+ fix #37886#: Kein Show beim Abbrechen mehr aufrufen, weil ViewShell tot sein koennte
+
+ Rev 1.170 18 Mar 1997 09:42:50 MIB
+ fix #37795#: Tabellen in Tabellen-Ueberschriften abfangen
+
+ Rev 1.169 05 Mar 1997 14:48:36 MIB
+ Absatz-Abstaende verbessert
+
+ Rev 1.168 22 Feb 1997 20:30:32 MIB
+ Tabellen-Layout an Netscape 4.0 Preview 2 anpassen
+
+ Rev 1.167 21 Feb 1997 15:28:26 MIB
+ fix #36692#: Fuer ::com::sun::star::form::Forms in Tabellen ausserhalb von Zellen keine neuen Absaetze
+
+ Rev 1.166 20 Feb 1997 17:04:46 MIB
+ bug fix: SaveState auch fuer Col-Groups
+
+
+*************************************************************************/
+