summaryrefslogtreecommitdiff
path: root/sw/source/core/doc/htmltbl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/doc/htmltbl.cxx')
-rw-r--r--sw/source/core/doc/htmltbl.cxx1926
1 files changed, 1926 insertions, 0 deletions
diff --git a/sw/source/core/doc/htmltbl.cxx b/sw/source/core/doc/htmltbl.cxx
new file mode 100644
index 000000000000..e3effed7250c
--- /dev/null
+++ b/sw/source/core/doc/htmltbl.cxx
@@ -0,0 +1,1926 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: htmltbl.cxx,v $
+ * $Revision: 1.17 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+#include "hintids.hxx"
+
+//#define TEST_DELAYED_RESIZE
+
+#ifdef TEST_DELAYED_RESIZE
+#include <vcl/sound.hxx>
+#endif
+#ifndef _WRKWIN_HXX //autogen
+#include <vcl/wrkwin.hxx>
+#endif
+#ifndef _APP_HXX //autogen
+#include <vcl/svapp.hxx>
+#endif
+#include <sot/storage.hxx>
+#include <fmtornt.hxx>
+#include <fmtfsize.hxx>
+#include <frmfmt.hxx>
+#include <docary.hxx>
+#include "ndtxt.hxx"
+#include "doc.hxx"
+#include "swtable.hxx"
+#include "rootfrm.hxx"
+#include "docsh.hxx"
+#include "flyfrm.hxx"
+#include "poolfmt.hxx"
+#include "viewsh.hxx"
+#include "tabfrm.hxx"
+
+#include "htmltbl.hxx"
+#include "ndindex.hxx"
+
+using namespace ::com::sun::star;
+
+
+#define COLFUZZY 20
+#define MAX_TABWIDTH (USHRT_MAX - 2001)
+
+
+/* */
+
+class SwHTMLTableLayoutConstraints
+{
+ USHORT nRow; // Start-Zeile
+ USHORT nCol; // Start-Spalte
+ USHORT nColSpan; // COLSPAN der Zelle
+
+ SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung
+
+ ULONG nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1
+
+public:
+
+ SwHTMLTableLayoutConstraints( ULONG nMin, ULONG nMax, USHORT nRow,
+ USHORT nCol, USHORT nColSp );
+ ~SwHTMLTableLayoutConstraints();
+
+ ULONG GetMinNoAlign() const { return nMinNoAlign; }
+ ULONG GetMaxNoAlign() const { return nMaxNoAlign; }
+
+ SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
+ SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
+
+ USHORT GetRow() const { return nRow; }
+
+ USHORT GetColSpan() const { return nColSpan; }
+ USHORT GetColumn() const { return nCol; }
+};
+
+/* */
+
+SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
+ SwHTMLTableLayout* pTab,
+ BOOL bNoBrTag,
+ SwHTMLTableLayoutCnts* pNxt ) :
+ pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
+ nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
+{}
+
+SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
+{
+ delete pNext;
+ delete pTable;
+}
+
+const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
+{
+ return pBox ? pBox->GetSttNd() : pStartNode;
+}
+
+
+/* */
+
+SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
+ USHORT nRSpan, USHORT nCSpan,
+ USHORT nWidth, BOOL bPrcWidth,
+ BOOL bNWrapOpt ) :
+ pContents( pCnts ),
+ nRowSpan( nRSpan ), nColSpan( nCSpan ),
+ nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
+ bNoWrapOption( bNWrapOpt )
+{}
+
+SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
+{
+ if( nRowSpan==1 && nColSpan==1 )
+ {
+ delete pContents;
+ }
+}
+
+/* */
+
+SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( USHORT nWidth,
+ BOOL bRelWidth,
+ BOOL bLBorder ) :
+ nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
+ nMin(0), nMax(0),
+ nAbsColWidth(0), nRelColWidth(0),
+ nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
+ bLeftBorder( bLBorder )
+{}
+
+
+/* */
+
+SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
+ ULONG nMin, ULONG nMax, USHORT nRw, USHORT nColumn, USHORT nColSp ):
+ nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
+ pNext( 0 ),
+ nMinNoAlign( nMin ), nMaxNoAlign( nMax )
+{}
+
+SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
+{
+ delete pNext;
+}
+
+SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
+ SwHTMLTableLayoutConstraints *pNxt )
+{
+ SwHTMLTableLayoutConstraints *pPrev = 0;
+ SwHTMLTableLayoutConstraints *pConstr = this;
+ while( pConstr )
+ {
+ if( pConstr->GetRow() > pNxt->GetRow() ||
+ pConstr->GetColumn() > pNxt->GetColumn() )
+ break;
+ pPrev = pConstr;
+ pConstr = pConstr->GetNext();
+ }
+
+ if( pPrev )
+ {
+ pNxt->pNext = pPrev->GetNext();
+ pPrev->pNext = pNxt;
+ pConstr = this;
+ }
+ else
+ {
+ pNxt->pNext = this;
+ pConstr = pNxt;
+ }
+
+ return pConstr;
+}
+
+/* */
+
+typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
+typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
+
+SwHTMLTableLayout::SwHTMLTableLayout(
+ const SwTable * pSwTbl,
+ USHORT nRws, USHORT nCls, BOOL bColsOpt, BOOL bColTgs,
+ USHORT nWdth, BOOL bPrcWdth, USHORT nBorderOpt,
+ USHORT nCellPad, USHORT nCellSp, SvxAdjust eAdjust,
+ USHORT nLMargin, USHORT nRMargin,
+ USHORT nBWidth, USHORT nLeftBWidth,
+ USHORT nRightBWidth,
+ USHORT nInhLeftBWidth, USHORT nInhRightBWidth ) :
+ aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
+ aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
+ pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
+ nMin( 0 ), nMax( 0 ),
+ nRows( nRws ), nCols( nCls ),
+ nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
+ nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
+ nRelLeftFill( 0 ), nRelRightFill( 0 ),
+ nRelTabWidth( 0 ), nWidthOption( nWdth ),
+ nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
+ nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
+ nInhLeftBorderWidth( nInhLeftBWidth ),
+ nInhRightBorderWidth( nInhRightBWidth ),
+ nBorderWidth( nBWidth ),
+ nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
+ nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
+ bColsOption( bColsOpt ), bColTags( bColTgs ),
+ bPrcWidthOption( bPrcWdth ), bUseRelWidth( FALSE ),
+ bMustResize( TRUE ), bExportable( TRUE ), bBordersChanged( FALSE ),
+ bMustNotResize( FALSE ), bMustNotRecalc( FALSE )
+{
+ aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
+ DelayedResize_Impl ) );
+}
+
+SwHTMLTableLayout::~SwHTMLTableLayout()
+{
+ USHORT i;
+
+ for( i = 0; i < nCols; i++ )
+ delete aColumns[i];
+ delete[] aColumns;
+
+ USHORT nCount = nRows*nCols;
+ for( i=0; i<nCount; i++ )
+ delete aCells[i];
+ delete[] aCells;
+}
+
+// Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet:
+// Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING
+// Innere Umrandung: CELLSPACING + CELLPADDING
+// Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn
+// bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird.
+// MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden,
+// und zwar auch dann, wenn wenn nur die gegenueberliegende Seite
+// eine Umrandung hat.
+USHORT SwHTMLTableLayout::GetLeftCellSpace( USHORT nCol, USHORT nColSpan,
+ BOOL bSwBorders ) const
+{
+ USHORT nSpace = nCellSpacing + nCellPadding;
+
+ if( nCol == 0 )
+ {
+ nSpace = nSpace + nBorder;
+
+ if( bSwBorders && nSpace < nLeftBorderWidth )
+ nSpace = nLeftBorderWidth;
+ }
+ else if( bSwBorders )
+ {
+ if( GetColumn(nCol)->HasLeftBorder() )
+ {
+ if( nSpace < nBorderWidth )
+ nSpace = nBorderWidth;
+ }
+ else if( nCol+nColSpan == nCols && nRightBorderWidth &&
+ nSpace < MIN_BORDER_DIST )
+ {
+ ASSERT( !nCellPadding, "GetLeftCellSpace: 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;
+}
+
+USHORT SwHTMLTableLayout::GetRightCellSpace( USHORT nCol, USHORT nColSpan,
+ BOOL bSwBorders ) const
+{
+ USHORT nSpace = nCellPadding;
+
+ if( nCol+nColSpan == nCols )
+ {
+ nSpace += nBorder + nCellSpacing;
+ if( bSwBorders && nSpace < nRightBorderWidth )
+ nSpace = nRightBorderWidth;
+ }
+ else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
+ nSpace < MIN_BORDER_DIST )
+ {
+ ASSERT( !nCellPadding, "GetRightCellSpace: 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 SwHTMLTableLayout::AddBorderWidth( ULONG &rMin, ULONG &rMax,
+ ULONG &rAbsMin,
+ USHORT nCol, USHORT nColSpan,
+ BOOL bSwBorders ) const
+{
+ ULONG nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
+ GetRightCellSpace( nCol, nColSpan, bSwBorders );
+
+ rMin += nAdd;
+ rMax += nAdd;
+ rAbsMin += nAdd;
+}
+
+void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, USHORT nCol,
+ USHORT nColSpan ) const
+{
+ SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
+
+ // die Breite der Box berechnen
+ SwTwips nFrmWidth = 0;
+ while( nColSpan-- )
+ nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
+
+ // und neu setzen
+
+ pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
+}
+
+void SwHTMLTableLayout::GetAvail( USHORT nCol, USHORT nColSpan,
+ USHORT& rAbsAvail, USHORT& rRelAvail ) const
+{
+ rAbsAvail = 0;
+ rRelAvail = 0;
+ for( USHORT i=nCol; i<nCol+nColSpan;i++ )
+ {
+ const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
+ rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
+ rRelAvail = rRelAvail + pColumn->GetRelColWidth();
+ }
+}
+
+USHORT SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
+{
+ ViewShell *pVSh = 0;
+ rDoc.GetEditShell( &pVSh );
+ if( pVSh )
+ {
+ return (USHORT)pVSh->GetBrowseWidth();
+ }
+
+ return 0;
+}
+
+USHORT SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
+{
+ // Wenn ein Layout da ist, koennen wir die Breite dort herholen.
+ const SwRootFrm *pRootFrm = rDoc.GetRootFrm();
+ if( pRootFrm )
+ {
+ const SwFrm *pPageFrm = pRootFrm->GetLower();
+ if( pPageFrm )
+ return (USHORT)pPageFrm->Prt().Width();
+ }
+
+ // Sonst versuchen wir es ueber die ViewShell
+ USHORT nWidth = GetBrowseWidthByVisArea( rDoc );
+ if( !nWidth )
+ {
+ // Und wenn das auch nicht geht, gibt es noch die ActualSize an der
+ // DocShell.
+ if( rDoc.GetDocShell() && GetpApp() && GetpApp()->GetDefaultDevice() )
+ {
+ // this case shouldn't happen because the filter always waits until
+ // a view has been created
+/*
+ nWidth = (USHORT)Application::GetDefaultDevice()
+ ->PixelToLogic( rDoc.GetDocShell()->GetActualSize(),
+ MapMode( MAP_TWIP ) ).Width();
+*/
+ ASSERT( nWidth, "No browse width available" );
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ // und wenn das auch nicht klappt, gibt es zur Zeit keine Breite
+ ASSERT( nWidth, "No browse width available" );
+ }
+#endif
+ }
+ return nWidth;
+}
+
+USHORT SwHTMLTableLayout::GetBrowseWidthByTabFrm(
+ const SwTabFrm& rTabFrm ) const
+{
+ SwTwips nWidth = 0;
+
+ const SwFrm *pUpper = rTabFrm.GetUpper();
+ if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
+ ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
+ {
+ // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist
+ // die Breite Ankers und nicht die Breite Rahmens von Bedeutung.
+ // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet.
+ const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
+ if( pAnchor->IsTxtFrm() )
+ nWidth = pAnchor->Frm().Width();
+ else
+ nWidth = pAnchor->Prt().Width();
+ }
+ else
+ {
+ nWidth = pUpper->Prt().Width();
+ }
+
+ SwTwips nUpperDummy = 0;
+ long nRightOffset = 0,
+ nLeftOffset = 0;
+ rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
+ nWidth -= (nLeftOffset + nRightOffset);
+
+ return nWidth < USHRT_MAX ? static_cast<USHORT>(nWidth) : USHRT_MAX;
+}
+
+USHORT SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
+{
+ USHORT nBrowseWidth = 0;
+ SwClientIter aIter( *(SwModify*)pSwTable->GetFrmFmt() );
+ SwClient* pCli = aIter.First( TYPE( SwTabFrm ));
+ if( pCli )
+ {
+ nBrowseWidth = GetBrowseWidthByTabFrm( *(SwTabFrm*)pCli );
+ }
+ else
+ {
+ nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
+ }
+
+ return nBrowseWidth;
+}
+
+const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
+{
+ const SwStartNode *pBoxSttNd;
+
+ const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
+ while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
+ {
+ ASSERT( pBox->GetTabLines().Count() > 0,
+ "Box ohne Start-Node und Lines" );
+ ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0,
+ "Line ohne Boxen" );
+ pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
+ }
+
+ return pBoxSttNd;
+}
+
+SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
+{
+ const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
+ ASSERT( pTblNd, "Kein Table-Node?" );
+ return pTblNd->GetFlyFmt();
+}
+
+static void lcl_GetMinMaxSize( ULONG& rMinNoAlignCnts, ULONG& rMaxNoAlignCnts,
+ ULONG& rAbsMinNoAlignCnts,
+#ifdef FIX41370
+ BOOL& rHR,
+#endif
+ SwTxtNode *pTxtNd, ULONG nIdx, BOOL bNoBreak )
+{
+ pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
+ rAbsMinNoAlignCnts );
+ ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
+ "GetMinMaxSize: absmin > min" );
+ ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts,
+ "GetMinMaxSize: max > min" );
+
+ //Bei einen <PRE>-Absatz entspricht die maximale Breite der
+ // minimalen breite
+ const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
+ while( pColl && !pColl->IsDefault() &&
+ (USER_FMT & pColl->GetPoolFmtId()) )
+ {
+ pColl = (const SwFmtColl *)pColl->DerivedFrom();
+ }
+
+ // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht
+ // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken.
+ if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
+ {
+ rMinNoAlignCnts = rMaxNoAlignCnts;
+ rAbsMinNoAlignCnts = rMaxNoAlignCnts;
+ }
+#ifdef FIX41370
+ else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() )
+ {
+ rHR |= !pTxtNd->HasSwAttrSet() ||
+ SFX_ITEM_SET != pTxtNd->GetpSwAttrSet()
+ ->GetItemState( RES_LR_SPACE, FALSE );
+ }
+#endif
+}
+
+void SwHTMLTableLayout::AutoLayoutPass1()
+{
+ nPass1Done++;
+
+ ClearPass1Info();
+
+ BOOL bFixRelWidths = FALSE;
+ USHORT i;
+
+ SwHTMLTableLayoutConstraints *pConstraints = 0;
+
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ pColumn->ClearPass1Info( !HasColTags() );
+ USHORT nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir
+ // berechnete Breite bezieht
+ USHORT nColSkip = USHRT_MAX; // Wie viele Spalten muessen
+ // uebersprungen werden
+
+ for( USHORT j=0; j<nRows; j++ )
+ {
+ SwHTMLTableLayoutCell *pCell = GetCell(j,i);
+ SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
+
+ // fix #31488#: Zum Ermitteln der naechsten zu berechnenden
+ // Spalte muessen alle Zeilen herangezogen werden
+ USHORT nColSpan = pCell->GetColSpan();
+ if( nColSpan < nColSkip )
+ nColSkip = nColSpan;
+
+ if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
+ {
+ // die Zelle ist leer oder ihr Inhalt wurde nich nicht
+ // bearbeitet
+ if( nColSpan < nMinColSpan )
+ nMinColSpan = nColSpan;
+
+ ULONG nMinNoAlignCell = 0;
+ ULONG nMaxNoAlignCell = 0;
+ ULONG nAbsMinNoAlignCell = 0;
+ ULONG nMaxTableCell = 0;
+ ULONG nAbsMinTableCell = 0;
+#ifdef FIX41370
+ BOOL bHR = FALSE;
+#endif
+
+ while( pCnts )
+ {
+ const SwStartNode *pSttNd = pCnts->GetStartNode();
+ if( pSttNd )
+ {
+ const SwDoc *pDoc = pSttNd->GetDoc();
+ ULONG nIdx = pSttNd->GetIndex();
+ while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
+ {
+ SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
+ if( pTxtNd )
+ {
+ ULONG nMinNoAlignCnts = 0;
+ ULONG nMaxNoAlignCnts = 0;
+ ULONG nAbsMinNoAlignCnts = 0;
+
+ lcl_GetMinMaxSize( nMinNoAlignCnts,
+ nMaxNoAlignCnts,
+ nAbsMinNoAlignCnts,
+#ifdef FIX41370
+ bHR,
+#endif
+ pTxtNd, nIdx,
+ pCnts->HasNoBreakTag() );
+
+ if( nMinNoAlignCnts > nMinNoAlignCell )
+ nMinNoAlignCell = nMinNoAlignCnts;
+ if( nMaxNoAlignCnts > nMaxNoAlignCell )
+ nMaxNoAlignCell = nMaxNoAlignCnts;
+ if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
+ nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
+ }
+ else
+ {
+ SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
+ if( pTabNd )
+ {
+ SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
+ if( pChild )
+ {
+ pChild->AutoLayoutPass1();
+ ULONG nMaxTableCnts = pChild->nMax;
+ ULONG nAbsMinTableCnts = pChild->nMin;
+
+ // Eine feste Tabellen-Breite wird als Minimum
+ // und Maximum gleichzeitig uebernommen
+ if( !pChild->bPrcWidthOption && pChild->nWidthOption )
+ {
+ ULONG nTabWidth = pChild->nWidthOption;
+ if( nTabWidth >= nAbsMinTableCnts )
+ {
+ nMaxTableCnts = nTabWidth;
+ nAbsMinTableCnts = nTabWidth;
+ }
+ else
+ {
+ nMaxTableCnts = nAbsMinTableCnts;
+ }
+ }
+
+ if( nMaxTableCnts > nMaxTableCell )
+ nMaxTableCell = nMaxTableCnts;
+ if( nAbsMinTableCnts > nAbsMinTableCell )
+ nAbsMinTableCell = nAbsMinTableCnts;
+ }
+ nIdx = pTabNd->EndOfSectionNode()->GetIndex();
+ }
+ }
+ nIdx++;
+ }
+ }
+ else
+ {
+ ASSERT( !this, "Sub tables in HTML import?" )
+ SwHTMLTableLayout *pChild = pCnts->GetTable();
+ pChild->AutoLayoutPass1();
+ ULONG nMaxTableCnts = pChild->nMax;
+ ULONG nAbsMinTableCnts = pChild->nMin;
+
+ // Eine feste Tabellen-Breite wird als Minimum
+ // und Maximum gleichzeitig uebernommen
+ if( !pChild->bPrcWidthOption && pChild->nWidthOption )
+ {
+ ULONG nTabWidth = pChild->nWidthOption;
+ if( nTabWidth >= nAbsMinTableCnts )
+ {
+ nMaxTableCnts = nTabWidth;
+ nAbsMinTableCnts = nTabWidth;
+ }
+ else
+ {
+ nMaxTableCnts = nAbsMinTableCnts;
+ }
+ }
+
+ if( nMaxTableCnts > nMaxTableCell )
+ nMaxTableCell = nMaxTableCnts;
+ if( nAbsMinTableCnts > nAbsMinTableCell )
+ nAbsMinTableCell = nAbsMinTableCnts;
+ }
+ pCnts->SetPass1Done( nPass1Done );
+ pCnts = pCnts->GetNext();
+ }
+
+// War frueher hinter AddBorderWidth
+ // Wenn die Breite einer Tabelle in der Zelle breiter ist als
+ // das, was wir fuer sonstigen Inhalt berechnet haben, mussen
+ // wir die Breite der Tabelle nutzen
+ if( nMaxTableCell > nMaxNoAlignCell )
+ nMaxNoAlignCell = nMaxTableCell;
+ if( nAbsMinTableCell > nAbsMinNoAlignCell )
+ {
+ nAbsMinNoAlignCell = nAbsMinTableCell;
+ if( nMinNoAlignCell < nAbsMinNoAlignCell )
+ nMinNoAlignCell = nAbsMinNoAlignCell;
+ if( nMaxNoAlignCell < nMinNoAlignCell )
+ nMaxNoAlignCell = nMinNoAlignCell;
+ }
+// War frueher hinter AddBorderWidth
+
+ BOOL bRelWidth = pCell->IsPrcWidthOption();
+ USHORT nWidth = pCell->GetWidthOption();
+
+ // Eine NOWRAP-Option bezieht sich auf Text und auf
+ // Tabellen, wird aber bei fester Zellenbreite
+ // nicht uebernommen. Stattdessen wirkt die angegebene
+ // Zellenbreite wie eine Mindestbreite.
+ if( pCell->HasNoWrapOption() )
+ {
+ if( nWidth==0 || bRelWidth )
+ {
+ nMinNoAlignCell = nMaxNoAlignCell;
+ nAbsMinNoAlignCell = nMaxNoAlignCell;
+ }
+ else
+ {
+ if( nWidth>nMinNoAlignCell )
+ nMinNoAlignCell = nWidth;
+ if( nWidth>nAbsMinNoAlignCell )
+ nAbsMinNoAlignCell = nWidth;
+ }
+ }
+#ifdef FIX41370
+ else if( bHR && nWidth>0 && !bRelWidth )
+ {
+ // Ein kleiner Hack, um einen Bug in Netscape 4.0
+ // nachzubilden (siehe #41370#). Wenn eine Zelle eine
+ // fixe Breite besitzt und gleichzeitig ein HR, wird
+ // sie nie schmaler als die angegebene Breite.
+ // (Genaugenomen scheint die Zelle nie schmaler zu werden
+ // als die HR-Linie, denn wenn man fuer die Linie eine
+ // Breite angibt, die breiter ist als die der Zelle, dann
+ // wird die Zelle so breit wie die Linie. Das bekommen wir
+ // natuerlich nicht hin.)
+ if( nWidth>nMinNoAlignCell )
+ nMinNoAlignCell = nWidth;
+ if( nWidth>nAbsMinNoAlignCell )
+ nAbsMinNoAlignCell = nWidth;
+ }
+#endif
+
+ // Mindestbreite fuer Inhalt einhalten
+ if( nMinNoAlignCell < MINLAY )
+ nMinNoAlignCell = MINLAY;
+ if( nMaxNoAlignCell < MINLAY )
+ nMaxNoAlignCell = MINLAY;
+ if( nAbsMinNoAlignCell < MINLAY )
+ nAbsMinNoAlignCell = MINLAY;
+
+ // Umrandung und Abstand zum Inhalt beachten.
+ AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
+ nAbsMinNoAlignCell, i, nColSpan );
+
+ if( 1==nColSpan )
+ {
+ // die Werte direkt uebernehmen
+ pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
+ nMaxNoAlignCell,
+ nAbsMinNoAlignCell );
+
+ // bei den WIDTH angaben gewinnt die breiteste
+ if( !HasColTags() )
+ pColumn->MergeCellWidthOption( nWidth, bRelWidth );
+ }
+ else
+ {
+ // die Angaben erst am Ende, und zwar zeilenweise von
+ // links nach rechts bearbeiten
+
+ // Wann welche Werte wie uebernommen werden ist weiter
+ // unten erklaert.
+ if( !HasColTags() && nWidth && !bRelWidth )
+ {
+ ULONG nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
+ AddBorderWidth( nAbsWidth, nDummy, nDummy2,
+ i, nColSpan, FALSE );
+
+ if( nAbsWidth >= nMinNoAlignCell )
+ {
+ nMaxNoAlignCell = nAbsWidth;
+ if( HasColsOption() )
+ nMinNoAlignCell = nAbsWidth;
+ }
+ else if( nAbsWidth >= nAbsMinNoAlignCell )
+ {
+ nMaxNoAlignCell = nAbsWidth;
+ nMinNoAlignCell = nAbsWidth;
+ }
+ else
+ {
+ nMaxNoAlignCell = nAbsMinNoAlignCell;
+ nMinNoAlignCell = nAbsMinNoAlignCell;
+ }
+ }
+ else if( HasColsOption() || HasColTags() )
+ nMinNoAlignCell = nAbsMinNoAlignCell;
+
+ SwHTMLTableLayoutConstraints *pConstr =
+ new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
+ nMaxNoAlignCell, j, i, nColSpan );
+ if( pConstraints )
+ pConstraints = pConstraints->InsertNext( pConstr );
+ else
+ pConstraints = pConstr;
+ }
+ }
+ }
+
+ ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
+ "Layout Pass 1: Da werden Spalten vergessen!" );
+ ASSERT( nMinColSpan!=USHRT_MAX,
+ "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" );
+
+ if( 1==nMinColSpan )
+ {
+ // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle
+ // Werte in pColumn
+
+ // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen:
+ //
+ // WIDTH: kein COLS COLS
+ //
+ // keine min = min min = absmin
+ // max = max max = max
+ //
+ // >= min min = min min = width
+ // max = width max = width
+ //
+ // >= absmin min = wdith(*) min = width
+ // max = width max = width
+ //
+ // < absmin min = absmin min = absmin
+ // max = absmin max = absmin
+ //
+ // (*) Netscape benutzt hier die Mindestbreite ohne einen
+ // Umbruch vor der letzten Grafik. Haben wir (noch?) nicht,
+ // also belassen wir es bei width.^
+
+ if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
+ {
+ // absolute Breiten als Minimal- und Maximalbreite
+ // uebernehmen.
+ ULONG nAbsWidth = pColumn->GetWidthOption();
+ ULONG nDummy = 0, nDummy2 = 0;
+ AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, FALSE );
+
+ if( nAbsWidth >= pColumn->GetMinNoAlign() )
+ {
+ pColumn->SetMinMax( HasColsOption() ? nAbsWidth
+ : pColumn->GetMinNoAlign(),
+ nAbsWidth );
+ }
+ else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
+ {
+ pColumn->SetMinMax( nAbsWidth, nAbsWidth );
+ }
+ else
+ {
+ pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
+ pColumn->GetAbsMinNoAlign() );
+ }
+ }
+ else
+ {
+ pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
+ : pColumn->GetMinNoAlign(),
+ pColumn->GetMaxNoAlign() );
+ }
+ }
+ else if( USHRT_MAX!=nMinColSpan )
+ {
+ // kann irgendwas !=0 sein, weil es durch die Constraints
+ // angepasst wird.
+ pColumn->SetMinMax( MINLAY, MINLAY );
+
+ // die naechsten Spalten muessen nicht bearbeitet werden
+ i += (nColSkip-1);
+ }
+
+ nMin += pColumn->GetMin();
+ nMax += pColumn->GetMax();
+ bFixRelWidths |= pColumn->IsRelWidthOption();
+ }
+
+ // jetzt noch die Constrains verarbeiten
+ SwHTMLTableLayoutConstraints *pConstr = pConstraints;
+ while( pConstr )
+ {
+ // Erstmal muss die Breite analog zu den den Spaltenbreiten
+ // aufbereitet werden
+ USHORT nCol = pConstr->GetColumn();
+ USHORT nColSpan = pConstr->GetColSpan();
+ ULONG nConstrMin = pConstr->GetMinNoAlign();
+ ULONG nConstrMax = pConstr->GetMaxNoAlign();
+
+ // jetzt holen wir uns die bisherige Breite der ueberspannten
+ // Spalten
+ ULONG nColsMin = 0;
+ ULONG nColsMax = 0;
+ for( USHORT j=nCol; j<nCol+nColSpan; j++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
+ nColsMin += pColumn->GetMin();
+ nColsMax += pColumn->GetMax();
+ }
+
+ if( nColsMin<nConstrMin )
+ {
+ // den Minimalwert anteilig auf die Spalten verteilen
+ ULONG nMinD = nConstrMin-nColsMin;
+
+ if( nConstrMin > nColsMax )
+ {
+ // Anteilig anhand der Mindestbreiten
+ USHORT nEndCol = nCol+nColSpan;
+ ULONG nDiff = nMinD;
+ for( USHORT ic=nCol; ic<nEndCol; ic++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
+
+ ULONG nColMin = pColumn->GetMin();
+ ULONG nColMax = pColumn->GetMax();
+
+ nMin -= nColMin;
+ ULONG nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
+ : nDiff;
+ nColMin += nAdd;
+ nMin += nColMin;
+ ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" );
+ nDiff -= nAdd;
+
+ if( nColMax < nColMin )
+ {
+ nMax -= nColMax;
+ nColsMax -= nColMax;
+ nColMax = nColMin;
+ nMax += nColMax;
+ nColsMax += nColMax;
+ }
+
+ pColumn->SetMinMax( nColMin, nColMax );
+ }
+ }
+ else
+ {
+ // Anteilig anhand der Differenz zwischen Max und Min
+ for( USHORT ic=nCol; ic<nCol+nColSpan; ic++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
+
+ ULONG nDiff = pColumn->GetMax()-pColumn->GetMin();
+ if( nMinD < nDiff )
+ nDiff = nMinD;
+
+ pColumn->AddToMin( nDiff );
+
+ ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
+ "Wieso ist die SPalte auf einmal zu schmal?" )
+
+ nMin += nDiff;
+ nMinD -= nDiff;
+ }
+ }
+ }
+
+ if( !HasColTags() && nColsMax<nConstrMax )
+ {
+ ULONG nMaxD = nConstrMax-nColsMax;
+
+ for( USHORT ic=nCol; ic<nCol+nColSpan; ic++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
+
+ nMax -= pColumn->GetMax();
+
+ pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
+
+ nMax += pColumn->GetMax();
+ }
+ }
+
+ pConstr = pConstr->GetNext();
+ }
+
+
+ if( bFixRelWidths )
+ {
+ if( HasColTags() )
+ {
+ // Zum Anpassen der relativen Breiten werden im 1. Schritt die
+ // Minmalbreiten aller anzupassenden Zellen jeweils mit der
+ // relativen Breite einer Spalte multipliziert. Dadurch stimmen
+ // dann die Breitenverhaeltnisse der Spalten untereinander.
+ // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch
+ // breiter gworden ist als die Minmalbreite.
+ // Im 2. Schritt werden dann die berechneten Breiten durch diesen
+ // Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle
+ // erhalten und dient als Ausgangsbasis fuer die andern Breiten.
+ // Es werden auch hier nur die Maximalbreiten beeinflusst!
+
+ ULONG nAbsMin = 0; // absolte Min-Breite alter Spalten mit
+ // relativer Breite
+ ULONG nRel = 0; // Summe der relativen Breiten aller Spalten
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
+ {
+ nAbsMin += pColumn->GetMin();
+ nRel += pColumn->GetWidthOption();
+ }
+ }
+
+ ULONG nQuot = ULONG_MAX;
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() )
+ {
+ nMax -= pColumn->GetMax();
+ if( pColumn->GetWidthOption() && pColumn->GetMin() )
+ {
+ pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
+ ULONG nColQuot = pColumn->GetMax() / pColumn->GetMin();
+ if( nColQuot<nQuot )
+ nQuot = nColQuot;
+ }
+ }
+ }
+ ASSERT( 0==nRel || nQuot!=ULONG_MAX,
+ "Wo sind die relativen Spalten geblieben?" );
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() )
+ {
+ if( pColumn->GetWidthOption() )
+ pColumn->SetMax( pColumn->GetMax() / nQuot );
+ else
+ pColumn->SetMax( pColumn->GetMin() );
+ ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
+ "Maximale Spaltenbreite kleiner als Minimale" );
+ nMax += pColumn->GetMax();
+ }
+ }
+ }
+ else
+ {
+ USHORT nRel = 0; // Summe der relativen Breiten aller Spalten
+ USHORT nRelCols = 0; // Anzahl Spalten mit relativer Angabe
+ ULONG nRelMax = 0; // Anteil am Maximum dieser Spalten
+ for( i=0; i<nCols; i++ )
+ {
+ ASSERT( nRel<=100, "relative Breite aller Spalten>100%" );
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
+ {
+ // Sicherstellen, dass die relativen breiten nicht
+ // ueber 100% landen
+ USHORT nColWidth = pColumn->GetWidthOption();
+ if( nRel+nColWidth > 100 )
+ {
+ nColWidth = 100 - nRel;
+ pColumn->SetWidthOption( nColWidth, TRUE, FALSE );
+ }
+ nRelMax += pColumn->GetMax();
+ nRel = nRel + nColWidth;
+ nRelCols++;
+ }
+ else if( !pColumn->GetMin() )
+ {
+ // Die Spalte ist leer (wurde also auschliesslich
+ // durch COLSPAN erzeugt) und darf deshalb auch
+ // keine %-Breite zugewiesen bekommen.
+ nRelCols++;
+ }
+ }
+
+ // Eventuell noch vorhandene Prozente werden auf die Spalten ohne
+ // eine Breiten-Angabe verteilt. Wie in Netscape werden die
+ // verbleibenden Prozente enstprechend der Verhaeltnisse
+ // der Maximalbreiten der in Frage kommenden Spalten
+ // untereinander verteilt.
+ // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten
+ // mit fester Breite. Ist das richtig???
+ if( nRel < 100 && nRelCols < nCols )
+ {
+ USHORT nRelLeft = 100 - nRel;
+ ULONG nFixMax = nMax - nRelMax;
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( !pColumn->IsRelWidthOption() &&
+ !pColumn->GetWidthOption() &&
+ pColumn->GetMin() )
+ {
+ // den Rest bekommt die naechste Spalte
+ USHORT nColWidth =
+ (USHORT)((pColumn->GetMax() * nRelLeft) / nFixMax);
+ pColumn->SetWidthOption( nColWidth, TRUE, FALSE );
+ }
+ }
+ }
+
+ // nun die Maximalbreiten entsprechend anpassen
+ ULONG nQuotMax = ULONG_MAX;
+ ULONG nOldMax = nMax;
+ nMax = 0;
+ for( i=0; i<nCols; i++ )
+ {
+ // Spalten mit %-Angaben werden enstprechend angepasst.
+ // Spalten, die
+ // - keine %-Angabe besitzen und in einer Tabelle mit COLS
+ // oder WIDTH vorkommen, oder
+ // - als Breite 0% angegeben haben erhalten die Minimalbreite
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
+ {
+ ULONG nNewMax;
+ ULONG nColQuotMax;
+ if( !nWidthOption )
+ {
+ nNewMax = nOldMax * pColumn->GetWidthOption();
+ nColQuotMax = nNewMax / pColumn->GetMax();
+ }
+ else
+ {
+ nNewMax = nMin * pColumn->GetWidthOption();
+ nColQuotMax = nNewMax / pColumn->GetMin();
+ }
+ pColumn->SetMax( nNewMax );
+ if( nColQuotMax < nQuotMax )
+ nQuotMax = nColQuotMax;
+ }
+ else if( HasColsOption() || nWidthOption ||
+ (pColumn->IsRelWidthOption() &&
+ !pColumn->GetWidthOption()) )
+ pColumn->SetMax( pColumn->GetMin() );
+ }
+ // und durch den Quotienten teilen
+ ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" );
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
+ {
+ if( pColumn->GetWidthOption() )
+ {
+ pColumn->SetMax( pColumn->GetMax() / nQuotMax );
+ ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
+ "Minimalbreite ein Spalte Groesser Maximum" );
+ if( pColumn->GetMax() < pColumn->GetMin() )
+ pColumn->SetMax( pColumn->GetMin() );
+ }
+ }
+ nMax += pColumn->GetMax();
+ }
+ }
+ }
+
+ delete pConstraints;
+}
+
+// nAbsAvail ist der verfuegbare Platz in TWIPS.
+// nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0
+// nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle
+// fur die Umrandung und den Abstand zum Inhalt reserviert ist.
+void SwHTMLTableLayout::AutoLayoutPass2( USHORT nAbsAvail, USHORT nRelAvail,
+ USHORT nAbsLeftSpace,
+ USHORT nAbsRightSpace,
+ USHORT nParentInhAbsSpace )
+{
+ // Erstmal fuehren wie jede Menge Plausibilaets-Test durch
+
+ // Eine abolute zur Verfuegung stehende Breite muss immer uebergeben
+ // werden.
+ ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" );
+
+ // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer
+ // Tabellen in Tabellen uebergeben
+ ASSERT( IsTopTable() == (nRelAvail==0),
+ "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" );
+
+ // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein
+ // als das die Maximalbreite.
+ ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" );
+
+ // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken.
+ // (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung
+ // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.)
+ nLastResizeAbsAvail = nAbsAvail;
+
+ // Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender,
+ // vorhandene Filler-Zellen und Abstande angepasst
+
+ // Abstand zum Inhalt und Unrandung
+ USHORT nAbsLeftFill = 0, nAbsRightFill = 0;
+ if( !IsTopTable() &&
+ GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
+ {
+ nAbsLeftFill = nAbsLeftSpace;
+ nAbsRightFill = nAbsRightSpace;
+ }
+
+ // Linker und rechter Abstand
+ if( nLeftMargin || nRightMargin )
+ {
+ if( IsTopTable() )
+ {
+ // fuer die Top-Table beruecksichtigen wir die Raender immer,
+ // den die Minimalbreite der Tabelle wird hier nie unterschritten
+ nAbsAvail -= (nLeftMargin + nRightMargin);
+ }
+ else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
+ {
+ // sonst beruecksichtigen wir die Raender nur, wenn auch Platz
+ // fuer sie da ist (nMin ist hier bereits berechnet!)
+ nAbsLeftFill = nAbsLeftFill + nLeftMargin;
+ nAbsRightFill = nAbsRightFill + nRightMargin;
+ }
+ }
+
+ // Filler-Zellen
+ if( !IsTopTable() )
+ {
+ if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
+ nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
+ if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
+ nAbsRightFill = MINLAY+nInhRightBorderWidth;
+ }
+
+ // Anpassen des verfuegbaren Platzes.
+ nRelLeftFill = 0;
+ nRelRightFill = 0;
+ if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
+ {
+ ULONG nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
+
+ nRelLeftFill = (USHORT)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
+ nRelRightFill = (USHORT)((nAbsRightFillL * nRelAvail) / nAbsAvail);
+
+ nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
+ if( nRelAvail )
+ nRelAvail -= (nRelLeftFill + nRelRightFill);
+ }
+
+
+ // Schritt 2: Die absolute Tabellenbreite wird berechnet.
+ USHORT nAbsTabWidth = 0;
+ bUseRelWidth = FALSE;
+ if( nWidthOption )
+ {
+ if( bPrcWidthOption )
+ {
+ ASSERT( nWidthOption<=100, "Prozentangabe zu gross" );
+ if( nWidthOption > 100 )
+ nWidthOption = 100;
+
+ // Die absolute Breite entspricht den angegeben Prozent der
+ // zur Verfuegung stehenden Breite.
+ // Top-Tabellen bekommen nur eine relative Breite, wenn der
+ // verfuegbare Platz *echt groesser* ist als die Minimalbreite.
+ // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel
+ // von einer relativen Breite zu einer absoluten Breite durch
+ // Resize sonst zu einer Endlosschleife fuehrt.
+ // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird,
+ // wenn der Rahmen eine nicht-relative Breite besitzt, koennen
+ // wir da solche Spielchen nicht spielen
+ // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen
+ // jetzt doch. Dort war eine Grafik in einer 1%-breiten
+ // Tabelle und hat da natuerlich nicht hineingepasst.
+ nAbsTabWidth = (USHORT)( ((ULONG)nAbsAvail * nWidthOption) / 100 );
+ if( IsTopTable() &&
+ ( /*MayBeInFlyFrame() ||*/ (ULONG)nAbsTabWidth > nMin ) )
+ {
+ nRelAvail = USHRT_MAX;
+ bUseRelWidth = TRUE;
+ }
+ }
+ else
+ {
+ nAbsTabWidth = nWidthOption;
+ if( nAbsTabWidth > MAX_TABWIDTH )
+ nAbsTabWidth = MAX_TABWIDTH;
+
+ // Tabellen in Tabellen duerfen niemals breiter werden als der
+ // verfuegbare Platz.
+ if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
+ nAbsTabWidth = nAbsAvail;
+ }
+ }
+
+ ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail,
+ "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" );
+ ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail,
+ "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" );
+
+ // Catch fuer die beiden Asserts von oben (man weiss ja nie!)
+ if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
+ nAbsTabWidth = nAbsAvail;
+
+
+ // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der
+ // absoluten und relativen Tabellenbreiten.
+ if( (!IsTopTable() && nMin > (ULONG)nAbsAvail) ||
+ nMin > MAX_TABWIDTH )
+ {
+ // Wenn
+ // - das Minumum einer inneren Tabelle groesser ist als der
+ // verfuegbare Platz, oder
+ // - das Minumum einer Top-Table groesser ist als USHRT_MAX
+ // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX
+ // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten
+ // untereinander erhalten.
+
+ nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
+ nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
+
+ // First of all, we check wether we can fit the layout constrains,
+ // that are: Every cell's width excluding the borders must be at least
+ // MINLAY:
+
+ ULONG nRealMin = 0;
+ for( USHORT i=0; i<nCols; i++ )
+ {
+ ULONG nRealColMin = MINLAY, nDummy1, nDummy2;
+ AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
+ nRealMin += nRealColMin;
+ }
+ if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
+ {
+ // "Nichts geht mehr". We cannot get the minimum column widths
+ // the layout wants to have.
+
+ USHORT nAbs = 0, nRel = 0;
+ SwHTMLTableLayoutColumn *pColumn;
+ for( USHORT i=0; i<nCols-1; i++ )
+ {
+ pColumn = GetColumn( i );
+ ULONG nColMin = pColumn->GetMin();
+ if( nColMin <= USHRT_MAX )
+ {
+ pColumn->SetAbsColWidth(
+ (USHORT)((nColMin * nAbsTabWidth) / nMin) );
+ pColumn->SetRelColWidth(
+ (USHORT)((nColMin * nRelTabWidth) / nMin) );
+ }
+ else
+ {
+ double nColMinD = nColMin;
+ pColumn->SetAbsColWidth(
+ (USHORT)((nColMinD * nAbsTabWidth) / nMin) );
+ pColumn->SetRelColWidth(
+ (USHORT)((nColMinD * nRelTabWidth) / nMin) );
+ }
+
+ nAbs = nAbs + (USHORT)pColumn->GetAbsColWidth();
+ nRel = nRel + (USHORT)pColumn->GetRelColWidth();
+ }
+ pColumn = GetColumn( nCols-1 );
+ pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
+ pColumn->SetRelColWidth( nRelTabWidth - nRel );
+ }
+ else
+ {
+ ULONG nDistAbs = nAbsTabWidth - nRealMin;
+ ULONG nDistRel = nRelTabWidth - nRealMin;
+ ULONG nDistMin = nMin - nRealMin;
+ USHORT nAbs = 0, nRel = 0;
+ SwHTMLTableLayoutColumn *pColumn;
+ for( USHORT i=0; i<nCols-1; i++ )
+ {
+ pColumn = GetColumn( i );
+ ULONG nColMin = pColumn->GetMin();
+ ULONG nRealColMin = MINLAY, nDummy1, nDummy2;
+ AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
+
+ if( nColMin <= USHRT_MAX )
+ {
+ pColumn->SetAbsColWidth(
+ (USHORT)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
+ pColumn->SetRelColWidth(
+ (USHORT)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
+ }
+ else
+ {
+ double nColMinD = nColMin;
+ pColumn->SetAbsColWidth(
+ (USHORT)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
+ pColumn->SetRelColWidth(
+ (USHORT)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
+ }
+
+ nAbs = nAbs + (USHORT)pColumn->GetAbsColWidth();
+ nRel = nRel + (USHORT)pColumn->GetRelColWidth();
+ }
+ pColumn = GetColumn( nCols-1 );
+ pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
+ pColumn->SetRelColWidth( nRelTabWidth - nRel );
+ }
+ }
+ else if( nMax <= (ULONG)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
+ {
+ // Wenn
+ // - die Tabelle eine fixe Breite besitzt und das Maximum der
+ // Tabelle kleiner ist, oder
+ // - das Maximum kleiner ist als der verfuegbare Platz
+ // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur
+ // unter Beruecksichtigung des Maxumums an die fixe Breite
+ // angepasst werden.
+
+ // Keine fixe Breite, dann das Maximum nehmen.
+ if( !nAbsTabWidth )
+ nAbsTabWidth = (USHORT)nMax;
+
+ // Eine Top-Table darf auch beriter werden als der verfuegbare Platz.
+ if( nAbsTabWidth > nAbsAvail )
+ {
+ ASSERT( IsTopTable(),
+ "Tabelle in Tabelle soll breiter werden als umgebende Zelle" );
+ nAbsAvail = nAbsTabWidth;
+ }
+
+ // Nur den Anteil der relativen Breite verwenden, der auch fuer
+ // die absolute Breite verwendet wuerde.
+ ULONG nAbsTabWidthL = nAbsTabWidth;
+ nRelTabWidth =
+ ( nRelAvail ? (USHORT)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
+ : nAbsTabWidth );
+
+ // Gibt es Spalten mit und Spalten ohne %-Angabe?
+ ULONG nFixMax = nMax;
+ for( USHORT i=0; i<nCols; i++ )
+ {
+ const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
+ nFixMax -= pColumn->GetMax();
+ }
+
+ if( nFixMax > 0 && nFixMax < nMax )
+ {
+ // ja, dann den zu verteilenden Platz nur auf die Spalten
+ // mit %-Angabe verteilen.
+
+ // In diesem (und nur in diesem) Fall gibt es Spalten,
+ // die ihre Maximalbreite genau einhalten, also weder
+ // schmaler noch breiter werden. Beim zurueckrechnen der
+ // absoluten Breite aus der relativen Breite kann es
+ // zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen
+ // werden zuerst die fixen Breiten entsprechend korrigiert
+ // eingestellt und erst danach die relativen.
+
+ USHORT nAbs = 0, nRel = 0;
+ USHORT nFixedCols = 0;
+ USHORT i;
+
+ for( i = 0; i < nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
+ {
+ // Die Spalte behaelt ihre Breite bei.
+ nFixedCols++;
+ ULONG nColMax = pColumn->GetMax();
+ pColumn->SetAbsColWidth( (USHORT)nColMax );
+
+ ULONG nRelColWidth =
+ (nColMax * nRelTabWidth) / nAbsTabWidth;
+ ULONG nChkWidth =
+ (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
+ if( nChkWidth < nColMax )
+ nRelColWidth++;
+ else if( nChkWidth > nColMax )
+ nRelColWidth--;
+ pColumn->SetRelColWidth( (USHORT)nRelColWidth );
+
+ nAbs = nAbs + (USHORT)nColMax;
+ nRel = nRel + (USHORT)nRelColWidth;
+ }
+ }
+
+ // Zu verteilende Anteile des Maximums und der relativen und
+ // absoluten Breiten. nFixMax entspricht an dieser Stelle
+ // nAbs, so dass man gleich nFixMax haette nehmen koennen.
+ // Der Code ist so aber verstaendlicher.
+ ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" )
+ ULONG nDistMax = nMax - nFixMax;
+ USHORT nDistAbsTabWidth = nAbsTabWidth - nAbs;
+ USHORT nDistRelTabWidth = nRelTabWidth - nRel;
+
+ for( i=0; i<nCols; i++ )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
+ if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
+ {
+ // Die Spalte wird anteilig breiter.
+ nFixedCols++;
+ if( nFixedCols == nCols )
+ {
+ pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
+ pColumn->SetRelColWidth( nRelTabWidth-nRel );
+ }
+ else
+ {
+ ULONG nColMax = pColumn->GetMax();
+ pColumn->SetAbsColWidth(
+ (USHORT)((nColMax * nDistAbsTabWidth) / nDistMax) );
+ pColumn->SetRelColWidth(
+ (USHORT)((nColMax * nDistRelTabWidth) / nDistMax) );
+ }
+ nAbs = nAbs + pColumn->GetAbsColWidth();
+ nRel = nRel + pColumn->GetRelColWidth();
+ }
+ }
+ ASSERT( nCols==nFixedCols, "Spalte vergessen!" );
+ }
+ else
+ {
+ // nein, dann den zu verteilenden Platz auf alle Spalten
+ // gleichmaessig vertilen.
+ for( USHORT i=0; i<nCols; i++ )
+ {
+ ULONG nColMax = GetColumn( i )->GetMax();
+ GetColumn( i )->SetAbsColWidth(
+ (USHORT)((nColMax * nAbsTabWidth) / nMax) );
+ GetColumn( i )->SetRelColWidth(
+ (USHORT)((nColMax * nRelTabWidth) / nMax) );
+ }
+ }
+ }
+ else
+ {
+ // den ueber die Minimalbreite herausgehenden Platz entsprechend
+ // den einzelnen Spalten anteilig zuschlagen
+ if( !nAbsTabWidth )
+ nAbsTabWidth = nAbsAvail;
+ if( nAbsTabWidth < nMin )
+ nAbsTabWidth = (USHORT)nMin;
+
+ if( nAbsTabWidth > nAbsAvail )
+ {
+ ASSERT( IsTopTable(),
+ "Tabelle in Tabelle soll breiter werden als Platz da ist" );
+ nAbsAvail = nAbsTabWidth;
+ }
+
+ ULONG nAbsTabWidthL = nAbsTabWidth;
+ nRelTabWidth =
+ ( nRelAvail ? (USHORT)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
+ : nAbsTabWidth );
+ double nW = nAbsTabWidth - nMin;
+ double nD = (nMax==nMin ? 1 : nMax-nMin);
+ USHORT nAbs = 0, nRel = 0;
+ for( USHORT i=0; i<nCols-1; i++ )
+ {
+ double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
+ ULONG nAbsColWidth = GetColumn( i )->GetMin() + (ULONG)((nd*nW)/nD);
+ ULONG nRelColWidth = nRelAvail
+ ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
+ : nAbsColWidth;
+
+ GetColumn( i )->SetAbsColWidth( (USHORT)nAbsColWidth );
+ GetColumn( i )->SetRelColWidth( (USHORT)nRelColWidth );
+ nAbs = nAbs + (USHORT)nAbsColWidth;
+ nRel = nRel + (USHORT)nRelColWidth;
+ }
+ GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
+ GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
+
+ }
+
+ // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts
+ // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet.
+ nInhAbsLeftSpace = 0;
+ nInhAbsRightSpace = 0;
+ if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
+ nAbsTabWidth<nAbsAvail) )
+ {
+ // Die Breite von zusaetzlichen Zellen zur Ausrichtung der
+ // inneren Tabelle bestimmen
+ USHORT nAbsDist = (USHORT)(nAbsAvail-nAbsTabWidth);
+ USHORT nRelDist = (USHORT)(nRelAvail-nRelTabWidth);
+ USHORT nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
+
+ // Groesse und Position der zusaetzlichen Zellen bestimmen
+ switch( eTableAdjust )
+ {
+ case SVX_ADJUST_RIGHT:
+ nAbsLeftFill = nAbsLeftFill + nAbsDist;
+ nRelLeftFill = nRelLeftFill + nRelDist;
+ nParentInhAbsLeftSpace = nParentInhAbsSpace;
+ break;
+ case SVX_ADJUST_CENTER:
+ {
+ USHORT nAbsLeftDist = nAbsDist / 2;
+ nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
+ nAbsRightFill += nAbsDist - nAbsLeftDist;
+ USHORT nRelLeftDist = nRelDist / 2;
+ nRelLeftFill = nRelLeftFill + nRelLeftDist;
+ nRelRightFill += nRelDist - nRelLeftDist;
+ nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
+ nParentInhAbsRightSpace = nParentInhAbsSpace -
+ nParentInhAbsLeftSpace;
+ }
+ break;
+ case SVX_ADJUST_LEFT:
+ default:
+ nAbsRightFill = nAbsRightFill + nAbsDist;
+ nRelRightFill = nRelRightFill + nRelDist;
+ nParentInhAbsRightSpace = nParentInhAbsSpace;
+ break;
+ }
+
+ ASSERT( !pLeftFillerBox || nRelLeftFill>0,
+ "Fuer linke Filler-Box ist keine Breite da!" );
+ ASSERT( !pRightFillerBox || nRelRightFill>0,
+ "Fuer rechte Filler-Box ist keine Breite da!" );
+
+ // Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn
+ // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0)
+ // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und
+ // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir
+ // die Tabelle wahrscheinlich selbst exportiert)
+ if( nRelLeftFill && !pLeftFillerBox &&
+ ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
+ (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
+// (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
+ pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
+ pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
+ nRelLeftFill = 0;
+ nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
+ }
+ if( nRelRightFill && !pRightFillerBox &&
+ ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
+ (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
+// (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) )
+ {
+ SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
+ pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
+ pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
+ nRelRightFill = 0;
+ nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
+ }
+ }
+}
+
+static BOOL lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara );
+
+static BOOL lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara )
+{
+ USHORT *pWidth = (USHORT *)pPara;
+
+ if( !rpBox->GetSttNd() )
+ {
+ USHORT nWidth = 0;
+ ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth );
+ rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
+ *pWidth = *pWidth + nWidth;
+ }
+ else
+ {
+ *pWidth = *pWidth + (USHORT)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
+ }
+
+ return TRUE;
+}
+
+static BOOL lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara )
+{
+ USHORT *pWidth = (USHORT *)pPara;
+#ifdef DBG_UTIL
+ USHORT nOldWidth = *pWidth;
+#endif
+ *pWidth = 0;
+ ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth );
+
+#ifdef DBG_UTIL
+ ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
+ "Zeilen einer Box sind unterschiedlich lang" );
+#endif
+
+ return TRUE;
+}
+
+void SwHTMLTableLayout::SetWidths( BOOL bCallPass2, USHORT nAbsAvail,
+ USHORT nRelAvail, USHORT nAbsLeftSpace,
+ USHORT nAbsRightSpace,
+ USHORT nParentInhAbsSpace )
+{
+ // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen
+ // worden sein.
+ nWidthSet++;
+
+ // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus
+ // aufgerufen.
+ if( bCallPass2 )
+ AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
+ nParentInhAbsSpace );
+
+ // Schritt 1: Setzten der neuen Breite an allen Content-Boxen.
+ // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird
+ // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen
+ // in Tabellen wird rekursiv SetWidth aufgerufen.
+ for( USHORT i=0; i<nRows; i++ )
+ {
+ for( USHORT j=0; j<nCols; j++ )
+ {
+ SwHTMLTableLayoutCell *pCell = GetCell( i, j );
+
+ SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
+ while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
+ {
+ SwTableBox *pBox = pCntnts->GetTableBox();
+ if( pBox )
+ {
+ SetBoxWidth( pBox, j, pCell->GetColSpan() );
+ }
+ else
+ {
+ USHORT nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
+ nInhSpace = 0;
+ if( bCallPass2 )
+ {
+ USHORT nColSpan = pCell->GetColSpan();
+ GetAvail( j, nColSpan, nAbs, nRel );
+ nLSpace = GetLeftCellSpace( j, nColSpan );
+ nRSpace = GetRightCellSpace( j, nColSpan );
+ nInhSpace = GetInhCellSpace( j, nColSpan );
+ }
+ pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
+ nLSpace, nRSpace,
+ nInhSpace );
+ }
+
+ pCntnts->SetWidthSet( nWidthSet );
+ pCntnts = pCntnts->GetNext();
+ }
+ }
+ }
+
+ // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate
+ // der Nicht-Content-Boxen angepasst. Da diese aufgrund der
+ // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen
+ // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch
+ // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden
+ // stattdessen die Breiten der Filler-Zellen gesetzt.
+ if( IsTopTable() )
+ {
+ USHORT nCalcTabWidth = 0;
+ ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine,
+ &nCalcTabWidth );
+ ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
+ "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." );
+
+ // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst
+ // die Boxformate erneut angepasst werden. Ausserdem muss eine
+ // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben.
+ SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
+ ((SwTable *)pSwTable)->LockModify();
+ SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
+ aFrmSize.SetWidth( nRelTabWidth );
+ BOOL bRel = bUseRelWidth &&
+ text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
+ aFrmSize.SetWidthPercent( (BYTE)(bRel ? nWidthOption : 0) );
+ pFrmFmt->SetFmtAttr( aFrmSize );
+ ((SwTable *)pSwTable)->UnlockModify();
+
+ // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen
+ // breite angepasst werden.
+ if( MayBeInFlyFrame() )
+ {
+ SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
+ if( pFlyFrmFmt )
+ {
+ SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
+
+ if( bUseRelWidth )
+ {
+ // Bei %-Angaben wird die Breite auf das Minimum gesetzt.
+ aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX
+ : nMin );
+ aFlyFrmSize.SetWidthPercent( (BYTE)nWidthOption );
+ }
+ pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
+ }
+ }
+
+#ifdef DBG_UTIL
+ {
+ // steht im tblrwcl.cxx
+ extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
+
+ // checke doch mal ob die Tabellen korrekte Breiten haben
+ SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
+ const SwTableLines& rLines = pSwTable->GetTabLines();
+ for( USHORT n = 0; n < rLines.Count(); ++n )
+ _CheckBoxWidth( *rLines[ n ], nSize );
+ }
+#endif
+
+ }
+ else
+ {
+ if( pLeftFillerBox )
+ {
+ pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
+ SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
+ }
+ if( pRightFillerBox )
+ {
+ pRightFillerBox->GetFrmFmt()->SetFmtAttr(
+ SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
+ }
+ }
+}
+
+void SwHTMLTableLayout::_Resize( USHORT nAbsAvail, BOOL bRecalc )
+{
+ // Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas
+ // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt
+ // werden.
+ if( bRecalc )
+ AutoLayoutPass1();
+
+ SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetRootFrm();
+ if ( pRoot && pRoot->IsCallbackActionEnabled() )
+ pRoot->StartAllAction();
+
+ // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils
+ // noch der Pass 2 laufen muss.
+ SetWidths( TRUE, nAbsAvail );
+
+ if ( pRoot && pRoot->IsCallbackActionEnabled() )
+ pRoot->EndAllAction( TRUE ); //True per VirDev (Browsen ruhiger)
+}
+
+IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
+{
+#ifdef TEST_DELAYED_RESIZE
+ Sound::Beep( SOUND_WARNING );
+#endif
+ pThis->aResizeTimer.Stop();
+ pThis->_Resize( pThis->nDelayedResizeAbsAvail,
+ pThis->bDelayedResizeRecalc );
+
+ return 0;
+}
+
+
+BOOL SwHTMLTableLayout::Resize( USHORT nAbsAvail, BOOL bRecalc,
+ BOOL bForce, ULONG nDelay )
+{
+ if( 0 == nAbsAvail )
+ return FALSE;
+ ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" );
+
+ // Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem?
+ if( bMustNotResize && !bForce )
+ return FALSE;
+
+ // Darf ein Recalc der Tabelle durchgefuehrt werden?
+ if( bMustNotRecalc && !bForce )
+ bRecalc = FALSE;
+
+ const SwDoc *pDoc = GetDoc();
+
+ // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames
+ // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen
+ // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden,
+ // weil sond die Umschaltung von relativ nach absolut nicht funktioniert.
+ if( pDoc->GetRootFrm() && pDoc->get(IDocumentSettingAccess::BROWSE_MODE) )
+ {
+ USHORT nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
+ if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
+ nAbsAvail = nVisAreaWidth;
+ }
+
+ if( nDelay==0 && aResizeTimer.IsActive() )
+ {
+ // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones
+ // Resize aussteht, dann werden nur die neuen Werte uebernommen.
+
+ bRecalc |= bDelayedResizeRecalc;
+ nDelayedResizeAbsAvail = nAbsAvail;
+ return FALSE;
+ }
+
+ // Optimierung:
+ // Wenn die Minima/Maxima nicht neu berechnet werden sollen und
+ // - die Breite der Tabelle nie neu berechnet werden muss, oder
+ // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder
+ // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist
+ // und die Tabelle bereits die Minimalbreite besitzt, oder
+ // - der verfuegbare Platz groesser ist als die Maximalbreite und
+ // die Tabelle bereits die Maximalbreite besitzt
+ // wird sich an der Tabelle nichts aendern.
+ if( !bRecalc && ( !bMustResize ||
+ (nLastResizeAbsAvail==nAbsAvail) ||
+ (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
+ (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
+ return FALSE;
+
+ if( nDelay==HTMLTABLE_RESIZE_NOW )
+ {
+ if( aResizeTimer.IsActive() )
+ aResizeTimer.Stop();
+ _Resize( nAbsAvail, bRecalc );
+ }
+ else if( nDelay > 0 )
+ {
+ nDelayedResizeAbsAvail = nAbsAvail;
+ bDelayedResizeRecalc = bRecalc;
+ aResizeTimer.SetTimeout( nDelay );
+ aResizeTimer.Start();
+#ifdef TEST_DELAYED_RESIZE
+ Sound::Beep( SOUND_DEFAULT );
+#endif
+ }
+ else
+ {
+ _Resize( nAbsAvail, bRecalc );
+ }
+
+ return TRUE;
+}
+
+void SwHTMLTableLayout::BordersChanged( USHORT nAbsAvail, BOOL bRecalc )
+{
+ bBordersChanged = TRUE;
+
+ Resize( nAbsAvail, bRecalc );
+}
+
+