| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| //#define TEST_RESIZE |
| |
| |
| #include "hintids.hxx" |
| #include <vcl/svapp.hxx> |
| #ifndef _WRKWIN_HXX //autogen |
| #include <vcl/wrkwin.hxx> |
| #endif |
| #include <editeng/boxitem.hxx> |
| #include <editeng/brshitem.hxx> |
| #include <editeng/adjitem.hxx> |
| #include <editeng/fhgtitem.hxx> |
| #include <editeng/ulspitem.hxx> |
| #include <editeng/lrspitem.hxx> |
| #include <editeng/brkitem.hxx> |
| #include <editeng/spltitem.hxx> |
| #include <svtools/htmltokn.h> |
| #include <svtools/htmlkywd.hxx> |
| #include <svl/urihelper.hxx> |
| |
| |
| #include <fmtornt.hxx> |
| #include <frmfmt.hxx> |
| #include <fmtfsize.hxx> |
| #include <fmtsrnd.hxx> |
| #include <fmtpdsc.hxx> |
| #include <fmtcntnt.hxx> |
| #include <fmtanchr.hxx> |
| #include <fmtlsplt.hxx> |
| #include "frmatr.hxx" |
| #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" |
| #include <numrule.hxx> |
| |
| #define NETSCAPE_DFLT_BORDER 1 |
| #define NETSCAPE_DFLT_CELLPADDING 1 |
| #define NETSCAPE_DFLT_CELLSPACING 2 |
| |
| //#define FIX56334 |
| |
| using namespace ::com::sun::star; |
| |
| |
| static HTMLOptionEnum __FAR_DATA aHTMLTblVAlignTable[] = |
| { |
| { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::NONE }, |
| { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER }, |
| { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::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; |
| sal_Int16 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, aDir; |
| |
| HTMLTableOptions( const HTMLOptions *pOptions, SvxAdjust eParentAdjust ); |
| }; |
| |
| /* */ |
| |
| class _HTMLTableContext |
| { |
| SwHTMLNumRuleInfo aNumRuleInfo; // Vor der Tabelle gueltige Numerierung |
| |
| SwTableNode *pTblNd; // der Tabellen-Node |
| SwFrmFmt *pFrmFmt; // der Fly 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 ), |
| nContextStAttrMin( nCntxtStAttrMin ), |
| nContextStMin( nCntxtStMin ), |
| 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; |
| sal_Int16 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; |
| sal_Bool mbCovered : 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, |
| sal_Int16 eVertOri, SvxBrushItem *pBGBrush, |
| sal_Bool bHasNumFmt, sal_uInt32 nNumFmt, |
| sal_Bool bHasValue, double nValue, sal_Bool bNoWrap, sal_Bool bCovered ); |
| |
| // 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; |
| |
| sal_Int16 GetVertOri() const { return eVertOri; } |
| |
| // Ist die Zelle belegt oder geschuetzt? |
| sal_Bool IsUsed() const { return pContents!=0 || bProtected; } |
| |
| SwHTMLTableLayoutCell *CreateLayoutInfo(); |
| |
| sal_Bool IsCovered() const { return mbCovered; } |
| }; |
| |
| /* */ |
| |
| // 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; |
| sal_Int16 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( sal_Int16 eV) { eVertOri = eV; } |
| inline sal_Int16 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; |
| sal_Int16 eVertOri; |
| |
| SwFrmFmt *aFrmFmts[6]; |
| |
| inline sal_uInt16 GetFrmFmtIdx( sal_Bool bBorderLine, |
| sal_Int16 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( sal_Int16 eV) { eVertOri = eV; } |
| inline sal_Int16 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, |
| sal_Int16 eVertOri ); |
| inline SwFrmFmt *GetFrmFmt( sal_Bool bBorderLine, |
| sal_Int16 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; |
| String aDir; |
| |
| 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 frame::Frame-Format einer SwTableBox |
| SwTableLineFmt *pLineFmt; // das 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_uInt32 nHeadlineRepeat; // repeating rows |
| 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; // drawing::Alignment der Tabelle |
| sal_Int16 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 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 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; |
| } |
| sal_Int16 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 drawing::Alignment holen |
| SvxAdjust GetInheritedAdjust() const; |
| sal_Int16 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, |
| sal_Int16 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, sal_Int16 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, sal_Int16 eVertOri ); |
| |
| // Einfuegen einer Spalte |
| void InsertCol( sal_uInt16 nSpan, sal_uInt16 nWidth, sal_Bool bRelWidth, |
| SvxAdjust eAdjust, sal_Int16 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; } |
| const String& GetDirection() const { return aDir; } |
| |
| 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), |
| nNumFmt(0), |
| nRowSpan(1), |
| nColSpan(1), |
| nWidth( 0 ), |
| nValue(0), |
| eVertOri( text::VertOrientation::NONE ), |
| bProtected(sal_False), |
| bRelWidth( sal_False ), |
| bHasNumFmt(sal_False), |
| bHasValue(sal_False), |
| mbCovered(sal_False) |
| {} |
| |
| 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, |
| sal_Int16 eVert, SvxBrushItem *pBrush, |
| sal_Bool bHasNF, sal_uInt32 nNF, sal_Bool bHasV, double nVal, |
| sal_Bool bNWrap, sal_Bool bCovered ) |
| { |
| pContents = pCnts; |
| nRowSpan = nRSpan; |
| nColSpan = nCSpan; |
| bProtected = sal_False; |
| eVertOri = eVert; |
| pBGBrush = pBrush; |
| |
| bHasNumFmt = bHasNF; |
| bHasValue = bHasV; |
| nNumFmt = nNF; |
| nValue = nVal; |
| |
| bNoWrap = bNWrap; |
| mbCovered = bCovered; |
| } |
| |
| 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), |
| bSplitable( sal_False ), |
| nHeight(0), |
| nEmptyRows(0), |
| eAdjust(SVX_ADJUST_END), |
| eVertOri(text::VertOrientation::TOP), |
| pBGBrush(0), |
| bBottomBorder(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 DBG_UTIL |
| sal_uInt16 nEnd = pCells->Count(); |
| #endif |
| // The colspan of empty cells at the end has to be fixed to the new |
| // number of cells. |
| sal_uInt16 i=nCells; |
| while( i ) |
| { |
| HTMLTableCell *pCell = (*pCells)[--i]; |
| if( !pCell->GetContents() ) |
| { |
| ASSERT( pCell->GetColSpan() == nEnd - i, |
| "invalid col span for empty cell at row end" ); |
| pCell->SetColSpan( nCells-i); |
| } |
| else |
| break; |
| } |
| #ifdef DBG_UTIL |
| for( 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(text::VertOrientation::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, |
| sal_Int16 eVertOrient ) const |
| { |
| ASSERT( text::VertOrientation::TOP != eVertOrient, "Top ist nicht erlaubt" ); |
| sal_uInt16 n = bBorderLine ? 3 : 0; |
| switch( eVertOrient ) |
| { |
| case text::VertOrientation::CENTER: n+=1; break; |
| case text::VertOrientation::BOTTOM: n+=2; break; |
| default: |
| ; |
| } |
| return n; |
| } |
| |
| inline void HTMLTableColumn::SetFrmFmt( SwFrmFmt *pFmt, sal_Bool bBorderLine, |
| sal_Int16 eVertOrient ) |
| { |
| aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)] = pFmt; |
| } |
| |
| inline SwFrmFmt *HTMLTableColumn::GetFrmFmt( sal_Bool bBorderLine, |
| sal_Int16 eVertOrient ) const |
| { |
| return aFrmFmts[GetFrmFmtIdx(bBorderLine,eVertOrient)]; |
| } |
| |
| /* */ |
| |
| |
| 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; |
| nHeadlineRepeat = 0; |
| |
| 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; |
| aDir = pOptions->aDir; |
| } |
| |
| 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 ), |
| nCellPadding( pOptions->nCellPadding ), |
| nCellSpacing( pOptions->nCellSpacing ), |
| nBoxes( 1 ), |
| pCaptionStartNode( 0 ), |
| bTableAdjustOfTag( pTopTab ? sal_False : pOptions->bTableAdjust ), |
| bIsParentHead( bParHead ), |
| bHasParentSection( bHasParentSec ), |
| bMakeTopSubTable( bTopTbl ), |
| bHasToFly( bHasToFlw ), |
| bFixedCols( pOptions->nCols>0 ), |
| bPrcWidth( pOptions->bPrcWidth ), |
| pParser( pPars ), |
| pTopTable( pTopTab ? pTopTab : this ), |
| pLayoutInfo( 0 ), |
| nWidth( pOptions->nWidth ), |
| nHeight( pTopTab ? 0 : pOptions->nHeight ), |
| eTableAdjust( pOptions->eAdjust ), |
| eVertOri( pOptions->eVertOri ), |
| eFrame( pOptions->eFrame ), |
| eRules( pOptions->eRules ), |
| bTopCaption( sal_False ), |
| bFirstCell( !pTopTab ) |
| { |
| 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 = 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; // frame::Frame-Format |
| sal_Int16 eVOri = text::VertOrientation::NONE; |
| const SvxBrushItem *pBGBrushItem = 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 = 0; |
| double nValue = 0.0; |
| |
| HTMLTableColumn *pColumn = (*pColumns)[nCol]; |
| |
| if( pBox->GetSttNd() ) |
| { |
| // die Hintergrundfarbe/-grafik bestimmen |
| const HTMLTableCell *pCell = GetCell( nRow, nCol ); |
| pBGBrushItem = pCell->GetBGBrush(); |
| if( !pBGBrushItem ) |
| { |
| // 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 |
| { |
| pBGBrushItem = ((*pRows)[nRow])->GetBGBrush(); |
| if( !pBGBrushItem && this != pTopTable ) |
| { |
| pBGBrushItem = GetBGBrush(); |
| if( !pBGBrushItem ) |
| pBGBrushItem = 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 && |
| !pBGBrushItem && !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( RES_BOX ); |
| 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 = static_cast< sal_uInt16 >( |
| (2*nCellPadding <= nInnerFrmWidth) ? nCellPadding |
| : (nInnerFrmWidth / 2) ); |
| // wir setzen das Item nur, wenn es eine Umrandung gibt |
| // oder eine 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->SetFmtAttr( aBoxItem ); |
| } |
| else |
| pFrmFmt->ResetFmtAttr( RES_BOX ); |
| |
| if( pBGBrushItem ) |
| { |
| pFrmFmt->SetFmtAttr( *pBGBrushItem ); |
| } |
| else |
| pFrmFmt->ResetFmtAttr( 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->HasSwAttrSet() && |
| 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->SetFmtAttr( aItemSet ); |
| if( bLock ) |
| pFrmFmt->UnlockModify(); |
| else if( pCNd && SVX_ADJUST_END != eAdjust ) |
| { |
| SvxAdjustItem aAdjItem( eAdjust, RES_PARATR_ADJUST ); |
| pCNd->SetAttr( aAdjItem ); |
| } |
| } |
| else |
| pFrmFmt->ResetFmtAttr( RES_BOXATR_FORMAT ); |
| |
| ASSERT( eVOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" ); |
| if( text::VertOrientation::NONE != eVOri ) |
| { |
| pFrmFmt->SetFmtAttr( SwFmtVertOrient( 0, eVOri ) ); |
| } |
| else |
| pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); |
| |
| if( bReUsable ) |
| pColumn->SetFrmFmt( pFrmFmt, bBottomLine, eVOri ); |
| } |
| else |
| { |
| pFrmFmt->ResetFmtAttr( RES_BOX ); |
| pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); |
| pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); |
| pFrmFmt->ResetFmtAttr( 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( RES_BOX ); |
| 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->SetFmtAttr( aBoxItem ); |
| } |
| else |
| { |
| pFrmFmt->ResetFmtAttr( RES_BOX ); |
| } |
| |
| if( GetInhBGBrush() ) |
| pFrmFmt->SetFmtAttr( *GetInhBGBrush() ); |
| else |
| pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); |
| |
| pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); |
| pFrmFmt->ResetFmtAttr( 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->ResetFmtAttr( RES_FRM_SIZE ); |
| pFrmFmt->ResetFmtAttr( 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 nRowHeight = pTopRow->GetHeight(); |
| const SvxBrushItem *pBGBrushItem = 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 |
| pBGBrushItem = pTopRow->GetBGBrush(); |
| |
| if( !pBGBrushItem && 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. |
| pBGBrushItem = GetBGBrush(); |
| if( !pBGBrushItem ) |
| pBGBrushItem = GetInhBGBrush(); |
| } |
| #ifndef FIX56334 |
| } |
| #endif |
| if( nTopRow==nBottomRow-1 && (nRowHeight || pBGBrushItem) ) |
| { |
| SwTableLineFmt *pFrmFmt = (SwTableLineFmt*)pLine->ClaimFrmFmt(); |
| ResetLineFrmFmtAttrs( pFrmFmt ); |
| |
| if( nRowHeight ) |
| { |
| // Tabellenhoehe einstellen. Da es sich um eine |
| // Mindesthoehe handelt, kann sie genauso wie in |
| // Netscape berechnet werden, also ohne Beruecksichtigung |
| // der tatsaechlichen Umrandungsbreite. |
| nRowHeight += GetTopCellSpace( nTopRow, 1, sal_False ) + |
| GetBottomCellSpace( nTopRow, 1, sal_False ); |
| |
| pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nRowHeight ) ); |
| } |
| |
| if( pBGBrushItem ) |
| { |
| pFrmFmt->SetFmtAttr( *pBGBrushItem ); |
| } |
| |
| } |
| 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 ) |
| { |
| sal_uInt16 nCol = nStartCol; |
| sal_uInt16 nSplitCol = nRightCol; |
| sal_Bool bSplitted = sal_False; |
| while( !bSplitted ) |
| { |
| ASSERT( nCol < nRightCol, "Zu weit gelaufen" ); |
| |
| HTMLTableCell *pCell = GetCell(nTopRow,nCol); |
| const sal_Bool bSplit = 1 == pCell->GetColSpan(); |
| |
| #ifdef DBG_UTIL |
| if( nCol == nRightCol-1 ) |
| { |
| ASSERT( bSplit, "Split-Flag falsch" ); |
| } |
| #endif |
| if( bSplit ) |
| { |
| SwTableBox* pBox = 0; |
| HTMLTableCell *pCell2 = GetCell( nTopRow, nStartCol ); |
| if( pCell2->GetColSpan() == (nCol+1-nStartCol) ) |
| { |
| // Die HTML-Tabellen-Zellen bilden genau eine Box. |
| // Dann muss hinter der Box gesplittet werden |
| nSplitCol = nCol + 1; |
| |
| long nBoxRowSpan = pCell2->GetRowSpan(); |
| if ( !pCell2->GetContents() || pCell2->IsCovered() ) |
| { |
| if ( pCell2->IsCovered() ) |
| nBoxRowSpan = -1 * nBoxRowSpan; |
| |
| const SwStartNode* pPrevStartNd = |
| GetPrevBoxStartNode( nTopRow, nStartCol ); |
| HTMLTableCnts *pCnts = new HTMLTableCnts( |
| pParser->InsertTableSection(pPrevStartNd) ); |
| SwHTMLTableLayoutCnts *pCntsLayoutInfo = |
| pCnts->CreateLayoutInfo(); |
| |
| pCell2->SetContents( pCnts ); |
| SwHTMLTableLayoutCell *pCurrCell = pLayoutInfo->GetCell( nTopRow, nStartCol ); |
| pCurrCell->SetContents( pCntsLayoutInfo ); |
| if( nBoxRowSpan < 0 ) |
| pCurrCell->SetRowSpan( 0 ); |
| |
| // 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, pCell2->GetContents(), |
| nTopRow, nStartCol, |
| nBottomRow, nSplitCol ); |
| |
| if ( 1 != nBoxRowSpan ) |
| pBox->setRowSpan( nBoxRowSpan ); |
| |
| bSplitted = sal_True; |
| } |
| |
| ASSERT( pBox, "Colspan trouble" ) |
| |
| if( pBox ) |
| rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() ); |
| } |
| nCol++; |
| } |
| nStartCol = nSplitCol; |
| } |
| |
| return pLine; |
| } |
| |
| 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 nBorderWidth = rBLine.GetOutWidth() + rBLine.GetInWidth() + |
| rBLine.GetDistance(); |
| if( bWithDistance ) |
| { |
| if( nCellPadding ) |
| nBorderWidth = nBorderWidth + nCellPadding; |
| else if( nBorderWidth ) |
| nBorderWidth = nBorderWidth + MIN_BORDER_DIST; |
| } |
| |
| return nBorderWidth; |
| } |
| |
| 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; |
| } |
| |
| sal_Int16 HTMLTable::GetInheritedVertOri() const |
| { |
| // text::VertOrientation::TOP ist der default! |
| sal_Int16 eVOri = ((*pRows)[nCurRow])->GetVertOri(); |
| if( text::VertOrientation::TOP==eVOri && nCurCol<nCols ) |
| eVOri = ((*pColumns)[nCurCol])->GetVertOri(); |
| if( text::VertOrientation::TOP==eVOri ) |
| eVOri = eVertOri; |
| |
| ASSERT( eVertOri != text::VertOrientation::TOP, "text::VertOrientation::TOP ist nicht erlaubt!" ); |
| return eVOri; |
| } |
| |
| void HTMLTable::InsertCell( HTMLTableCnts *pCnts, |
| sal_uInt16 nRowSpan, sal_uInt16 nColSpan, |
| sal_uInt16 nCellWidth, sal_Bool bRelWidth, sal_uInt16 nCellHeight, |
| sal_Int16 eVertOrient, SvxBrushItem *pBGBrushItem, |
| 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() ); |
| } |
| } |
| |
| // Fill the cells |
| for( i=nColSpan; i>0; i-- ) |
| { |
| for( j=nRowSpan; j>0; j-- ) |
| { |
| const bool bCovered = i != nColSpan || j != nRowSpan; |
| GetCell( nRowsReq-j, nColsReq-i ) |
| ->Set( pCnts, j, i, eVertOrient, pBGBrushItem, |
| bHasNumFmt, nNumFmt, bHasValue, nValue, bNoWrap, bCovered ); |
| } |
| } |
| |
| Size aTwipSz( bRelWidth ? 0 : nCellWidth, nCellHeight ); |
| if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() ) |
| { |
| aTwipSz = Application::GetDefaultDevice() |
| ->PixelToLogic( aTwipSz, MapMode( MAP_TWIP ) ); |
| } |
| |
| // die Breite nur in die erste Zelle setzen! |
| if( nCellWidth ) |
| { |
| sal_uInt16 nTmp = bRelWidth ? nCellWidth : (sal_uInt16)aTwipSz.Width(); |
| GetCell( nCurRow, nCurCol )->SetWidth( nTmp, bRelWidth ); |
| } |
| |
| // Ausserdem noch die Hoehe merken |
| if( nCellHeight && 1==nRowSpan ) |
| { |
| if( nCellHeight < MINLAY ) |
| nCellHeight = 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; |
| nHeadlineRepeat = nCurRow; |
| } |
| |
| void HTMLTable::OpenRow( SvxAdjust eAdjust, sal_Int16 eVertOrient, |
| SvxBrushItem *pBGBrushItem ) |
| { |
| 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( eVertOrient ); |
| if( pBGBrushItem ) |
| ((*pRows)[nCurRow])->SetBGBrush( pBGBrushItem ); |
| |
| // 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, |
| sal_Int16 eVertOrient ) |
| { |
| if( nSpan ) |
| InsertCol( nSpan, _nWidth, bRelWidth, eAdjust, eVertOrient ); |
| |
| ASSERT( nCurCol<=nCols, "ungueltige Spalte" ); |
| if( nCurCol>0 && nCurCol<=nCols ) |
| ((*pColumns)[nCurCol-1])->SetEndOfGroup(); |
| } |
| |
| void HTMLTable::InsertCol( sal_uInt16 nSpan, sal_uInt16 nColWidth, sal_Bool bRelWidth, |
| SvxAdjust eAdjust, sal_Int16 eVertOrient ) |
| { |
| // --> OD, MIB 2004-11-08 #i35143# - no columns, if rows already exist. |
| if ( nRows > 0 ) |
| return; |
| // <-- |
| |
| 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 : nColWidth, 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 ? nColWidth : (sal_uInt16)aTwipSz.Width(); |
| pCol->SetWidth( nTmp, bRelWidth ); |
| pCol->SetAdjust( eAdjust ); |
| pCol->SetVertOri( eVertOrient ); |
| } |
| |
| 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 ... |
| |
| for( sal_uInt16 i=0; i<nRows; i++ ) |
| { |
| SwTableLine *pLine = MakeTableLine( pBox, i, 0, i+1, nCols ); |
| if( pBox || i > 0 ) |
| rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() ); |
| } |
| } |
| |
| /* 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 text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL text::HoriOrientation::FULL % |
| xxx text::HoriOrientation::NONE text::HoriOrientation::NONE text::HoriOrientation::NONE % text::HoriOrientation::NONE % |
| xxx nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % |
| xxx Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE % |
| |
| bei Tabellen mit WIDTH=nn% ist die Prozent-Angabe von Bedeutung: |
| nn = 100 text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % |
| text::HoriOrientation::LEFT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER % text::HoriOrientation::LEFT_AND % |
| nn < 100 Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::LEFT % |
| Rahmen F Rahmen F text::HoriOrientation::CENTER % text::HoriOrientation::NONE % |
| |
| sonst die berechnete Breite w |
| w = avail* text::HoriOrientation::LEFT text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT |
| HORI_LEDT_AND text::HoriOrientation::RIGHT text::HoriOrientation::CENTER text::HoriOrientation::LEFT_AND |
| w < avail Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::LEFT |
| Rahmen L Rahmen L text::HoriOrientation::CENTER text::HoriOrientation::NONE |
| |
| xxx *) wenn fuer die Tabelle keine Groesse angegeben wurde, wird immer |
| xxx text::HoriOrientation::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 ) |
| { |
| sal_Int16 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 ? text::HoriOrientation::FULL : text::HoriOrientation::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 = text::HoriOrientation::RIGHT; |
| break; |
| case SVX_ADJUST_CENTER: |
| // zentrierte Tabellen nehmen keine Ruecksicht auf Raender! |
| eHoriOri = text::HoriOrientation::CENTER; |
| break; |
| case SVX_ADJUST_LEFT: |
| default: |
| // linksbuendige Tabellen nehmen nur auf den linken Rand |
| // Ruecksicht |
| eHoriOri = nLeftMargin ? text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::LEFT; |
| break; |
| } |
| |
| // das Tabellenform holen und anpassen |
| SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); |
| pFrmFmt->SetFmtAttr( SwFmtHoriOrient(0,eHoriOri) ); |
| if( text::HoriOrientation::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->SetFmtAttr( aLRItem ); |
| } |
| |
| if( bPrcWidth && text::HoriOrientation::FULL!=eHoriOri ) |
| { |
| pFrmFmt->LockModify(); |
| SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() ); |
| aFrmSize.SetWidthPercent( (sal_uInt8)nWidth ); |
| pFrmFmt->SetFmtAttr( 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->ResetFmtAttr( RES_BOX ); |
| pFrmFmt->ResetFmtAttr( RES_BACKGROUND ); |
| pFrmFmt->ResetFmtAttr( RES_VERT_ORIENT ); |
| pFrmFmt->ResetFmtAttr( 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() |
| ->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nHeight ) ); |
| } |
| |
| if( GetBGBrush() ) |
| pSwTable->GetFrmFmt()->SetFmtAttr( *GetBGBrush() ); |
| |
| ((SwTable *)pSwTable)->SetRowsToRepeat( static_cast< sal_uInt16 >(nHeadlineRepeat) ); |
| ((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()->SetFmtAttr( 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()->SetFmtAttr( 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 nWidth2, nDummy; |
| pLayoutInfo->GetAvail( nCol, nColSpan, nWidth2, nDummy ); |
| nWidth2 = nWidth2 - pLayoutInfo->GetLeftCellSpace( nCol, nColSpan ); |
| nWidth2 = nWidth2 - pLayoutInfo->GetRightCellSpace( nCol, nColSpan ); |
| nWidth2 = static_cast< sal_uInt16 >(((long)nWidth * nPrcWidth) / 100); |
| |
| pParser->ResizeDrawObject( pObj, nWidth2 ); |
| } |
| } |
| } |
| } |
| |
| 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 *const pNd = & pPam->GetPoint()->nNode.GetNode(); |
| 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(); |
| } |
| |
| SwCntntNode *pCNd = pDoc->GetNodes()[pStNd->GetIndex()+1] ->GetCntntNode(); |
| SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| |
| 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 *const pNd = & pPam->GetPoint()->nNode.GetNode(); |
| const SwStartNode *pStNd; |
| if( pTable && pTable->bFirstCell ) |
| { |
| pNd->GetTxtNode()->ChgFmtColl( pColl ); |
| pTable->bFirstCell = sal_False; |
| pStNd = pNd->FindTableBoxStartNode(); |
| } |
| else |
| { |
| SwTableNode *pTblNd = pNd->FindTableNode(); |
| if( pTblNd->GetTable().GetHTMLTableLayout() ) |
| { // if there is already a HTMTableLayout, this table is already finished |
| // and we have to look for the right table in the environment |
| SwTableNode *pOutTbl = pTblNd; |
| do { |
| pTblNd = pOutTbl; |
| pOutTbl = pOutTbl->StartOfSectionNode()->FindTableNode(); |
| } while( pOutTbl && pTblNd->GetTable().GetHTMLTableLayout() ); |
| } |
| 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; |
| } |
| |
| 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->EraseText( 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() ) |
| { |
| String aClass( rClass ); |
| SwCSS1Parser::GetScriptFromClass( aClass ); |
| SvxCSS1MapEntry *pClass = pCSS1Parser->GetClass( aClass ); |
| 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(RES_BACKGROUND); |
| |
| if( pColor ) |
| pBrushItem->SetColor(*pColor); |
| |
| if( rImageURL.Len() ) |
| { |
| pBrushItem->SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject(sBaseURL), rImageURL, Link(), false) ); |
| 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, aLang, aDir; |
| 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; |
| sal_Int16 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() ), |
| eVertOri( pCurTable->GetInheritedVertOri() ), |
| bHead( bHd ), |
| bPrcWidth( sal_False ), |
| bHasNumFmt( sal_False ), |
| bHasValue( sal_False ), |
| bBGColor( 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, static_cast< sal_uInt16 >(eAdjust) ); |
| break; |
| case HTML_O_VALIGN: |
| eVertOri = 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_LANG: |
| aLang = pOption->GetString(); |
| break; |
| case HTML_O_DIR: |
| aDir = 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 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, RES_PARATR_ADJUST), |
| pCntxt ); |
| |
| if( rParser.HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) ) |
| { |
| SfxItemSet aItemSet( rParser.pDoc->GetAttrPool(), |
| rParser.pCSS1Parser->GetWhichMap() ); |
| SvxCSS1PropertyInfo aPropInfo; |
| |
| if( rParser.ParseStyleOptions( aStyle, aId, aClass, aItemSet, |
| aPropInfo, &aLang, &aDir ) ) |
| 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 ) |
| { |
| #ifdef DBG_UTIL |
| // 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() ) |
| { |
| SwTxtNode const*const pTxtNd(rPos.nNode.GetNode().GetTxtNode()); |
| if( pTxtNd ) |
| { |
| 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( static_cast< sal_uInt16 >(bHead ? RES_POOLCOLL_TABLE_HDLN |
| : RES_POOLCOLL_TABLE) ); |
| |
| if( GetNumInfo().GetNumRule() ) |
| { |
| // 1. Absatz auf nicht numeriert setzen |
| sal_uInt8 nLvl = GetNumInfo().GetLevel(); |
| // --> OD 2008-04-02 #refactorlists# |
| // SetNoNum(&nLvl, sal_True); |
| // SetNodeNum( nLvl); |
| SetNodeNum( nLvl, false ); |
| } |
| |
| // 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() ) |
| { |
| sal_Bool bTopTable = pTable==pCurTable; |
| |
| // die Tabelle besitzt noch keinen Inhalt, d.h. die eigentliche |
| // Tabelle muss erst noch angelegt werden |
| |
| 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, |
| RES_FRAMEDIR, RES_FRAMEDIR, |
| 0 |
| }; |
| |
| SfxItemSet aItemSet( pDoc->GetAttrPool(), aWhichIds ); |
| SvxCSS1PropertyInfo aPropInfo; |
| |
| sal_Bool bStyleParsed = ParseStyleOptions( pCurTable->GetStyle(), |
| pCurTable->GetId(), |
| pCurTable->GetClass(), |
| aItemSet, aPropInfo, |
| 0, &pCurTable->GetDirection() ); |
| 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 ) |
| { |
| SvxAdjust eTblAdjust = pTable->GetTableAdjust(sal_False); |
| |
| // 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(); |
| |
| // 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 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) ); |
| SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); |
| |
| _HTMLAttr* pTmp = |
| new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); |
| aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); |
| |
| aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); |
| pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); |
| aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); |
| |
| aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); |
| pTmp = new _HTMLAttr( *pPam->GetPoint(), aFontHeight ); |
| aSetAttrTab.Insert( pTmp, aSetAttrTab.Count() ); |
| |
| pTmp = new _HTMLAttr( *pPam->GetPoint(), |
| SvxULSpaceItem( 0, 0, RES_UL_SPACE ) ); |
| 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() ); |
| } |
| |
| // 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; |
| sal_Int16 eHori; |
| |
| switch( pCurTable->GetTableAdjust(sal_True) ) |
| { |
| case SVX_ADJUST_RIGHT: |
| eHori = text::HoriOrientation::RIGHT; |
| eSurround = SURROUND_LEFT; |
| break; |
| case SVX_ADJUST_CENTER: |
| eHori = text::HoriOrientation::CENTER; |
| break; |
| case SVX_ADJUST_LEFT: |
| eSurround = SURROUND_RIGHT; |
| default: |
| eHori = text::HoriOrientation::LEFT; |
| break; |
| } |
| SetAnchorAndAdjustment( text::VertOrientation::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, 0, 0, RES_LR_SPACE) ); |
| nSpace = pCurTable->GetVSpace(); |
| if( nSpace ) |
| aFrmSet.Put( SvxULSpaceItem(nSpace,nSpace, RES_UL_SPACE) ); |
| |
| 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( |
| SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ), |
| *pPam->GetPoint(), 1, 1, text::HoriOrientation::LEFT ); |
| |
| if( bForceFrame ) |
| { |
| SwNodeIndex aDstIdx( pPam->GetPoint()->nNode ); |
| pPam->Move( fnMoveBackward ); |
| pDoc->GetNodes().Delete( aDstIdx ); |
| } |
| else |
| { |
| if( bStyleParsed ) |
| { |
| pCSS1Parser->SetFmtBreak( aItemSet, aPropInfo ); |
| pSwTable->GetFrmFmt()->SetFmtAttr( aItemSet ); |
| } |
| pPam->Move( fnMoveBackward ); |
| } |
| |
| SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode(); |
| if( !bAppended && !bForceFrame ) |
| { |
| SwTxtNode *const pOldTxtNd = |
| pSavePos->nNode.GetNode().GetTxtNode(); |
| ASSERT( pOldTxtNd, "Wieso stehen wir in keinem Txt-Node?" ); |
| SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); |
| |
| const SfxPoolItem* pItem2; |
| if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet() |
| .GetItemState( RES_PAGEDESC, sal_False, &pItem2 ) && |
| ((SwFmtPageDesc *)pItem2)->GetPageDesc() ) |
| { |
| pFrmFmt->SetFmtAttr( *pItem2 ); |
| pOldTxtNd->ResetAttr( RES_PAGEDESC ); |
| } |
| if( SFX_ITEM_SET == pOldTxtNd->GetSwAttrSet() |
| .GetItemState( RES_BREAK, sal_True, &pItem2 ) ) |
| { |
| switch( ((SvxFmtBreakItem *)pItem2)->GetBreak() ) |
| { |
| case SVX_BREAK_PAGE_BEFORE: |
| case SVX_BREAK_PAGE_AFTER: |
| case SVX_BREAK_PAGE_BOTH: |
| pFrmFmt->SetFmtAttr( *pItem2 ); |
| pOldTxtNd->ResetAttr( RES_BREAK ); |
| default: |
| ; |
| } |
| } |
| } |
| |
| 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; |
| } |
| } |
| |
| SwNode const*const pNd = & pPam->GetPoint()->nNode.GetNode(); |
| 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 *pHTMLOptions = GetOptions(); |
| for( sal_uInt16 i=0; i<pHTMLOptions->Count(); i++ ) |
| { |
| const HTMLOption *pOption = (*pHTMLOptions)[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 = (0 == |
| pPam->GetPoint()->nNode.GetNode().FindTableNode()); |
| |
| // 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( static_cast< sal_uInt16 >(pSaveStruct->IsHeaderCell() |
| ? RES_POOLCOLL_TABLE_HDLN |
| : RES_POOLCOLL_TABLE )); |
| const SwEndNode *pEndNd = pStNd->EndOfSectionNode(); |
| SwCntntNode *pCNd = pDoc->GetNodes()[pEndNd->GetIndex()-1] ->GetCntntNode(); |
| SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| aFontHeight.SetWhich( RES_CHRATR_CJK_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| aFontHeight.SetWhich( RES_CHRATR_CTL_FONTSIZE ); |
| pCNd->SetAttr( aFontHeight ); |
| |
| pSaveStruct->AddContents( new HTMLTableCnts(pStNd) ); |
| pSaveStruct->ClearIsInSection(); |
| } |
| |
| 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(); |
| |
| // 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; |
| sal_Int16 eVertOri; |
| sal_Bool bHasCells; |
| |
| _RowSaveStruct() : |
| eAdjust( SVX_ADJUST_END ), eVertOri( text::VertOrientation::TOP ), bHasCells( sal_False ) |
| {} |
| }; |
| |
| |
| void SwHTMLParser::BuildTableRow( HTMLTable *pCurTable, sal_Bool bReadOptions, |
| SvxAdjust eGrpAdjust, |
| sal_Int16 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; |
| sal_Int16 eVertOri = eGrpVertOri; |
| Color aBGColor; |
| String aBGImage, aStyle, aId, aClass; |
| sal_Bool bBGColor = sal_False; |
| pSaveStruct = new _RowSaveStruct; |
| |
| if( bReadOptions ) |
| { |
| const HTMLOptions *pHTMLOptions = GetOptions(); |
| for( sal_uInt16 i = pHTMLOptions->Count(); i; ) |
| { |
| const HTMLOption *pOption = (*pHTMLOptions)[--i]; |
| switch( pOption->GetToken() ) |
| { |
| case HTML_O_ID: |
| aId = pOption->GetString(); |
| break; |
| case HTML_O_ALIGN: |
| eAdjust = (SvxAdjust)pOption->GetEnum( |
| aHTMLPAlignTable, static_cast< sal_uInt16 >(eAdjust) ); |
| break; |
| case HTML_O_VALIGN: |
| eVertOri = 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 *pHTMLOptions = GetOptions(); |
| for( sal_uInt16 i = pHTMLOptions->Count(); i; ) |
| { |
| const HTMLOption *pOption = (*pHTMLOptions)[--i]; |
| switch( pOption->GetToken() ) |
| { |
| case HTML_O_ID: |
| InsertBookmark( pOption->GetString() ); |
| break; |
| case HTML_O_ALIGN: |
| pSaveStruct->eAdjust = |
| (SvxAdjust)pOption->GetEnum( aHTMLPAlignTable, |
| static_cast< sal_uInt16 >(pSaveStruct->eAdjust) ); |
| break; |
| case HTML_O_VALIGN: |
| pSaveStruct->eVertOri = |
| 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; |
| sal_Int16 eColGrpVertOri; |
| |
| inline _TblColGrpSaveStruct(); |
| |
| |
| inline void CloseColGroup( HTMLTable *pTable ); |
| }; |
| |
| inline _TblColGrpSaveStruct::_TblColGrpSaveStruct() : |
| nColGrpSpan( 1 ), nColGrpWidth( 0 ), |
| bRelColGrpWidth( sal_False ), eColGrpAdjust( SVX_ADJUST_END ), |
| eColGrpVertOri( text::VertOrientation::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, |
| static_cast< sal_uInt16 >(pSaveStruct->eColGrpAdjust) ); |
| break; |
| case HTML_O_VALIGN: |
| pSaveStruct->eColGrpVertOri = |
| 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; |
| sal_Int16 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, |
| static_cast< sal_uInt16 >(eColAdjust) ); |
| break; |
| case HTML_O_VALIGN: |
| eColVertOri = |
| 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. |
| 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 *pHTMLOptions = GetOptions(); |
| for ( sal_uInt16 i = pHTMLOptions->Count(); i; ) |
| { |
| const HTMLOption *pOption = (*pHTMLOptions)[--i]; |
| if( HTML_O_ALIGN == pOption->GetToken() ) |
| { |
| if( pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_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, RES_PARATR_ADJUST) ); |
| |
| _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->GetCurrentViewShell() && pTblNd ) //swmod 071108//swmod 071225 |
| { |
| // 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( text::VertOrientation::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 = static_cast< sal_uInt16 >(eAdjust); |
| if( pOption->GetEnum( nAdjust, aHTMLPAlignTable ) ) |
| { |
| eAdjust = (SvxAdjust)nAdjust; |
| bTableAdjust = sal_True; |
| } |
| } |
| break; |
| case HTML_O_VALIGN: |
| eVertOri = pOption->GetEnum( aHTMLTblVAlignTable, eVertOri ); |
| break; |
| case HTML_O_BORDER: |
| // BORDER und BORDER=BORDER wie BORDER=1 behandeln |
| if( pOption->GetString().Len() && |
| !pOption->GetString().EqualsIgnoreCaseAscii(OOO_STRING_SVTOOLS_HTML_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_DIR: |
| aDir = 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 |
| { |
| pTable = 0; |
| HTMLTableOptions *pTblOptions = |
| new HTMLTableOptions( GetOptions(), eParentAdjust ); |
| |
| if( pTblOptions->aId.Len() ) |
| InsertBookmark( pTblOptions->aId ); |
| |
| 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->MoveNodeRange( aSrcRg, aDstIdx, |
| IDocumentContentOperations::DOC_MOVEDEFAULT ); |
| |
| // 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 = 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; |
| } |
| |
| |