| /************************************************************** |
| * |
| * 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" |
| #include "hintids.hxx" |
| |
| //#define TEST_DELAYED_RESIZE |
| |
| #ifdef TEST_DELAYED_RESIZE |
| #include <vcl/sound.hxx> |
| #endif |
| #include <vcl/wrkwin.hxx> |
| #include <vcl/svapp.hxx> |
| #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 "viewopt.hxx" |
| #include "htmltbl.hxx" |
| #include "ndindex.hxx" |
| #include "switerator.hxx" |
| |
| using namespace ::com::sun::star; |
| |
| |
| #define COLFUZZY 20 |
| #define MAX_TABWIDTH (USHRT_MAX - 2001) |
| |
| |
| class SwHTMLTableLayoutConstraints |
| { |
| sal_uInt16 nRow; // Start-Zeile |
| sal_uInt16 nCol; // Start-Spalte |
| sal_uInt16 nColSpan; // COLSPAN der Zelle |
| |
| SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung |
| |
| sal_uLong nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1 |
| |
| public: |
| |
| SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow, |
| sal_uInt16 nCol, sal_uInt16 nColSp ); |
| ~SwHTMLTableLayoutConstraints(); |
| |
| sal_uLong GetMinNoAlign() const { return nMinNoAlign; } |
| sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; } |
| |
| SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt ); |
| SwHTMLTableLayoutConstraints* GetNext() const { return pNext; } |
| |
| sal_uInt16 GetRow() const { return nRow; } |
| |
| sal_uInt16 GetColSpan() const { return nColSpan; } |
| sal_uInt16 GetColumn() const { return nCol; } |
| }; |
| |
| /* */ |
| |
| SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd, |
| SwHTMLTableLayout* pTab, |
| sal_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, |
| sal_uInt16 nRSpan, sal_uInt16 nCSpan, |
| sal_uInt16 nWidth, sal_Bool bPrcWidth, |
| sal_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( sal_uInt16 nWidth, |
| sal_Bool bRelWidth, |
| sal_Bool bLBorder ) : |
| nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY), |
| nMin(0), nMax(0), |
| nAbsColWidth(0), nRelColWidth(0), |
| nWidthOption( nWidth ), bRelWidthOption( bRelWidth ), |
| bLeftBorder( bLBorder ) |
| {} |
| |
| |
| /* */ |
| |
| SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints( |
| sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 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, |
| sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs, |
| sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt, |
| sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust, |
| sal_uInt16 nLMargin, sal_uInt16 nRMargin, |
| sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth, |
| sal_uInt16 nRightBWidth, |
| sal_uInt16 nInhLeftBWidth, sal_uInt16 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( sal_False ), |
| bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ), |
| bMustNotResize( sal_False ), bMustNotRecalc( sal_False ) |
| { |
| aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout, |
| DelayedResize_Impl ) ); |
| } |
| |
| SwHTMLTableLayout::~SwHTMLTableLayout() |
| { |
| sal_uInt16 i; |
| |
| for( i = 0; i < nCols; i++ ) |
| delete aColumns[i]; |
| delete[] aColumns; |
| |
| sal_uInt16 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. |
| sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, |
| sal_Bool bSwBorders ) const |
| { |
| sal_uInt16 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; |
| } |
| |
| sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, |
| sal_Bool bSwBorders ) const |
| { |
| sal_uInt16 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( sal_uLong &rMin, sal_uLong &rMax, |
| sal_uLong &rAbsMin, |
| sal_uInt16 nCol, sal_uInt16 nColSpan, |
| sal_Bool bSwBorders ) const |
| { |
| sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) + |
| GetRightCellSpace( nCol, nColSpan, bSwBorders ); |
| |
| rMin += nAdd; |
| rMax += nAdd; |
| rAbsMin += nAdd; |
| } |
| |
| void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol, |
| sal_uInt16 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( sal_uInt16 nCol, sal_uInt16 nColSpan, |
| sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const |
| { |
| rAbsAvail = 0; |
| rRelAvail = 0; |
| for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ ) |
| { |
| const SwHTMLTableLayoutColumn *pColumn = GetColumn(i); |
| rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth(); |
| rRelAvail = rRelAvail + pColumn->GetRelColWidth(); |
| } |
| } |
| |
| sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc ) |
| { |
| ViewShell *pVSh = 0; |
| rDoc.GetEditShell( &pVSh ); |
| if( pVSh ) |
| { |
| return (sal_uInt16)pVSh->GetBrowseWidth(); |
| } |
| |
| return 0; |
| } |
| |
| sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc ) |
| { |
| // Wenn ein Layout da ist, koennen wir die Breite dort herholen. |
| const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); //swmod 080218 |
| if( pRootFrm ) |
| { |
| const SwFrm *pPageFrm = pRootFrm->GetLower(); |
| if( pPageFrm ) |
| return (sal_uInt16)pPageFrm->Prt().Width(); |
| } |
| |
| // --> OD 2010-05-12 #i91658# |
| // Assertion removed which state that no browse width is available. |
| // Investigation reveals that all calls can handle the case that no browse |
| // width is provided. |
| return GetBrowseWidthByVisArea( rDoc ); |
| // <-- |
| } |
| |
| sal_uInt16 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<sal_uInt16>(nWidth) : USHRT_MAX; |
| } |
| |
| sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const |
| { |
| sal_uInt16 nBrowseWidth = 0; |
| SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() ); |
| if( pFrm ) |
| { |
| nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm ); |
| } |
| 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( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts, |
| sal_uLong& rAbsMinNoAlignCnts, |
| #ifdef FIX41370 |
| sal_Bool& rHR, |
| #endif |
| SwTxtNode *pTxtNd, sal_uLong nIdx, sal_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, sal_False ); |
| } |
| #endif |
| } |
| |
| void SwHTMLTableLayout::AutoLayoutPass1() |
| { |
| nPass1Done++; |
| |
| ClearPass1Info(); |
| |
| sal_Bool bFixRelWidths = sal_False; |
| sal_uInt16 i; |
| |
| SwHTMLTableLayoutConstraints *pConstraints = 0; |
| |
| for( i=0; i<nCols; i++ ) |
| { |
| SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); |
| pColumn->ClearPass1Info( !HasColTags() ); |
| sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir |
| // berechnete Breite bezieht |
| sal_uInt16 nColSkip = USHRT_MAX; // Wie viele Spalten muessen |
| // uebersprungen werden |
| |
| for( sal_uInt16 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 |
| sal_uInt16 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; |
| |
| sal_uLong nMinNoAlignCell = 0; |
| sal_uLong nMaxNoAlignCell = 0; |
| sal_uLong nAbsMinNoAlignCell = 0; |
| sal_uLong nMaxTableCell = 0; |
| sal_uLong nAbsMinTableCell = 0; |
| #ifdef FIX41370 |
| sal_Bool bHR = sal_False; |
| #endif |
| |
| while( pCnts ) |
| { |
| const SwStartNode *pSttNd = pCnts->GetStartNode(); |
| if( pSttNd ) |
| { |
| const SwDoc *pDoc = pSttNd->GetDoc(); |
| sal_uLong nIdx = pSttNd->GetIndex(); |
| while( !(pDoc->GetNodes()[nIdx])->IsEndNode() ) |
| { |
| SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode(); |
| if( pTxtNd ) |
| { |
| sal_uLong nMinNoAlignCnts = 0; |
| sal_uLong nMaxNoAlignCnts = 0; |
| sal_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(); |
| sal_uLong nMaxTableCnts = pChild->nMax; |
| sal_uLong nAbsMinTableCnts = pChild->nMin; |
| |
| // Eine feste Tabellen-Breite wird als Minimum |
| // und Maximum gleichzeitig uebernommen |
| if( !pChild->bPrcWidthOption && pChild->nWidthOption ) |
| { |
| sal_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(); |
| sal_uLong nMaxTableCnts = pChild->nMax; |
| sal_uLong nAbsMinTableCnts = pChild->nMin; |
| |
| // Eine feste Tabellen-Breite wird als Minimum |
| // und Maximum gleichzeitig uebernommen |
| if( !pChild->bPrcWidthOption && pChild->nWidthOption ) |
| { |
| sal_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 |
| |
| sal_Bool bRelWidth = pCell->IsPrcWidthOption(); |
| sal_uInt16 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 ) |
| { |
| sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0; |
| AddBorderWidth( nAbsWidth, nDummy, nDummy2, |
| i, nColSpan, sal_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. |
| sal_uLong nAbsWidth = pColumn->GetWidthOption(); |
| sal_uLong nDummy = 0, nDummy2 = 0; |
| AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_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 |
| sal_uInt16 nCol = pConstr->GetColumn(); |
| sal_uInt16 nColSpan = pConstr->GetColSpan(); |
| sal_uLong nConstrMin = pConstr->GetMinNoAlign(); |
| sal_uLong nConstrMax = pConstr->GetMaxNoAlign(); |
| |
| // jetzt holen wir uns die bisherige Breite der ueberspannten |
| // Spalten |
| sal_uLong nColsMin = 0; |
| sal_uLong nColsMax = 0; |
| for( sal_uInt16 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 |
| sal_uLong nMinD = nConstrMin-nColsMin; |
| |
| if( nConstrMin > nColsMax ) |
| { |
| // Anteilig anhand der Mindestbreiten |
| sal_uInt16 nEndCol = nCol+nColSpan; |
| sal_uLong nDiff = nMinD; |
| for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ ) |
| { |
| SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); |
| |
| sal_uLong nColMin = pColumn->GetMin(); |
| sal_uLong nColMax = pColumn->GetMax(); |
| |
| nMin -= nColMin; |
| sal_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( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ ) |
| { |
| SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); |
| |
| sal_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 ) |
| { |
| sal_uLong nMaxD = nConstrMax-nColsMax; |
| |
| for( sal_uInt16 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! |
| |
| sal_uLong nAbsMin = 0; // absolte Min-Breite alter Spalten mit |
| // relativer Breite |
| sal_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(); |
| } |
| } |
| |
| sal_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() ); |
| sal_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 |
| { |
| sal_uInt16 nRel = 0; // Summe der relativen Breiten aller Spalten |
| sal_uInt16 nRelCols = 0; // Anzahl Spalten mit relativer Angabe |
| sal_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 |
| sal_uInt16 nColWidth = pColumn->GetWidthOption(); |
| if( nRel+nColWidth > 100 ) |
| { |
| nColWidth = 100 - nRel; |
| pColumn->SetWidthOption( nColWidth, sal_True, sal_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 ) |
| { |
| sal_uInt16 nRelLeft = 100 - nRel; |
| sal_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 |
| sal_uInt16 nColWidth = |
| (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax); |
| pColumn->SetWidthOption( nColWidth, sal_True, sal_False ); |
| } |
| } |
| } |
| |
| // nun die Maximalbreiten entsprechend anpassen |
| sal_uLong nQuotMax = ULONG_MAX; |
| sal_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() ) |
| { |
| sal_uLong nNewMax; |
| sal_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( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail, |
| sal_uInt16 nAbsLeftSpace, |
| sal_uInt16 nAbsRightSpace, |
| sal_uInt16 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 |
| sal_uInt16 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) ) |
| { |
| sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill; |
| |
| nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail); |
| nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail); |
| |
| nAbsAvail -= (nAbsLeftFill + nAbsRightFill); |
| if( nRelAvail ) |
| nRelAvail -= (nRelLeftFill + nRelRightFill); |
| } |
| |
| |
| // Schritt 2: Die absolute Tabellenbreite wird berechnet. |
| sal_uInt16 nAbsTabWidth = 0; |
| bUseRelWidth = sal_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 = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 ); |
| if( IsTopTable() && |
| ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) ) |
| { |
| nRelAvail = USHRT_MAX; |
| bUseRelWidth = sal_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 > (sal_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: |
| |
| sal_uLong nRealMin = 0; |
| for( sal_uInt16 i=0; i<nCols; i++ ) |
| { |
| sal_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. |
| |
| sal_uInt16 nAbs = 0, nRel = 0; |
| SwHTMLTableLayoutColumn *pColumn; |
| for( sal_uInt16 i=0; i<nCols-1; i++ ) |
| { |
| pColumn = GetColumn( i ); |
| sal_uLong nColMin = pColumn->GetMin(); |
| if( nColMin <= USHRT_MAX ) |
| { |
| pColumn->SetAbsColWidth( |
| (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) ); |
| pColumn->SetRelColWidth( |
| (sal_uInt16)((nColMin * nRelTabWidth) / nMin) ); |
| } |
| else |
| { |
| double nColMinD = nColMin; |
| pColumn->SetAbsColWidth( |
| (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) ); |
| pColumn->SetRelColWidth( |
| (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) ); |
| } |
| |
| nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); |
| nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); |
| } |
| pColumn = GetColumn( nCols-1 ); |
| pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); |
| pColumn->SetRelColWidth( nRelTabWidth - nRel ); |
| } |
| else |
| { |
| sal_uLong nDistAbs = nAbsTabWidth - nRealMin; |
| sal_uLong nDistRel = nRelTabWidth - nRealMin; |
| sal_uLong nDistMin = nMin - nRealMin; |
| sal_uInt16 nAbs = 0, nRel = 0; |
| SwHTMLTableLayoutColumn *pColumn; |
| for( sal_uInt16 i=0; i<nCols-1; i++ ) |
| { |
| pColumn = GetColumn( i ); |
| sal_uLong nColMin = pColumn->GetMin(); |
| sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2; |
| AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 ); |
| |
| if( nColMin <= USHRT_MAX ) |
| { |
| pColumn->SetAbsColWidth( |
| (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); |
| pColumn->SetRelColWidth( |
| (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); |
| } |
| else |
| { |
| double nColMinD = nColMin; |
| pColumn->SetAbsColWidth( |
| (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); |
| pColumn->SetRelColWidth( |
| (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); |
| } |
| |
| nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); |
| nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); |
| } |
| pColumn = GetColumn( nCols-1 ); |
| pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); |
| pColumn->SetRelColWidth( nRelTabWidth - nRel ); |
| } |
| } |
| else if( nMax <= (sal_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 = (sal_uInt16)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. |
| sal_uLong nAbsTabWidthL = nAbsTabWidth; |
| nRelTabWidth = |
| ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) |
| : nAbsTabWidth ); |
| |
| // Gibt es Spalten mit und Spalten ohne %-Angabe? |
| sal_uLong nFixMax = nMax; |
| for( sal_uInt16 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. |
| |
| sal_uInt16 nAbs = 0, nRel = 0; |
| sal_uInt16 nFixedCols = 0; |
| sal_uInt16 i; |
| |
| for( i = 0; i < nCols; i++ ) |
| { |
| SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); |
| if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() ) |
| { |
| // Die Spalte behaelt ihre Breite bei. |
| nFixedCols++; |
| sal_uLong nColMax = pColumn->GetMax(); |
| pColumn->SetAbsColWidth( (sal_uInt16)nColMax ); |
| |
| sal_uLong nRelColWidth = |
| (nColMax * nRelTabWidth) / nAbsTabWidth; |
| sal_uLong nChkWidth = |
| (nRelColWidth * nAbsTabWidth) / nRelTabWidth; |
| if( nChkWidth < nColMax ) |
| nRelColWidth++; |
| else if( nChkWidth > nColMax ) |
| nRelColWidth--; |
| pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth ); |
| |
| nAbs = nAbs + (sal_uInt16)nColMax; |
| nRel = nRel + (sal_uInt16)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?" ) |
| sal_uLong nDistMax = nMax - nFixMax; |
| sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs; |
| sal_uInt16 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 |
| { |
| sal_uLong nColMax = pColumn->GetMax(); |
| pColumn->SetAbsColWidth( |
| (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) ); |
| pColumn->SetRelColWidth( |
| (sal_uInt16)((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( sal_uInt16 i=0; i<nCols; i++ ) |
| { |
| sal_uLong nColMax = GetColumn( i )->GetMax(); |
| GetColumn( i )->SetAbsColWidth( |
| (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) ); |
| GetColumn( i )->SetRelColWidth( |
| (sal_uInt16)((nColMax * nRelTabWidth) / nMax) ); |
| } |
| } |
| } |
| else |
| { |
| // den ueber die Minimalbreite herausgehenden Platz entsprechend |
| // den einzelnen Spalten anteilig zuschlagen |
| if( !nAbsTabWidth ) |
| nAbsTabWidth = nAbsAvail; |
| if( nAbsTabWidth < nMin ) |
| nAbsTabWidth = (sal_uInt16)nMin; |
| |
| if( nAbsTabWidth > nAbsAvail ) |
| { |
| ASSERT( IsTopTable(), |
| "Tabelle in Tabelle soll breiter werden als Platz da ist" ); |
| nAbsAvail = nAbsTabWidth; |
| } |
| |
| sal_uLong nAbsTabWidthL = nAbsTabWidth; |
| nRelTabWidth = |
| ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) |
| : nAbsTabWidth ); |
| double nW = nAbsTabWidth - nMin; |
| double nD = (nMax==nMin ? 1 : nMax-nMin); |
| sal_uInt16 nAbs = 0, nRel = 0; |
| for( sal_uInt16 i=0; i<nCols-1; i++ ) |
| { |
| double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin(); |
| sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD); |
| sal_uLong nRelColWidth = nRelAvail |
| ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth |
| : nAbsColWidth; |
| |
| GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth ); |
| GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth ); |
| nAbs = nAbs + (sal_uInt16)nAbsColWidth; |
| nRel = nRel + (sal_uInt16)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 |
| sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth); |
| sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth); |
| sal_uInt16 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: |
| { |
| sal_uInt16 nAbsLeftDist = nAbsDist / 2; |
| nAbsLeftFill = nAbsLeftFill + nAbsLeftDist; |
| nAbsRightFill += nAbsDist - nAbsLeftDist; |
| sal_uInt16 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 sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ); |
| |
| static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara ) |
| { |
| sal_uInt16 *pWidth = (sal_uInt16 *)pPara; |
| |
| if( !rpBox->GetSttNd() ) |
| { |
| sal_uInt16 nWidth = 0; |
| ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth ); |
| rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); |
| *pWidth = *pWidth + nWidth; |
| } |
| else |
| { |
| *pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width(); |
| } |
| |
| return sal_True; |
| } |
| |
| static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ) |
| { |
| sal_uInt16 *pWidth = (sal_uInt16 *)pPara; |
| #ifdef DBG_UTIL |
| sal_uInt16 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 sal_True; |
| } |
| |
| void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail, |
| sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace, |
| sal_uInt16 nAbsRightSpace, |
| sal_uInt16 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( sal_uInt16 i=0; i<nRows; i++ ) |
| { |
| for( sal_uInt16 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 |
| { |
| sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0, |
| nInhSpace = 0; |
| if( bCallPass2 ) |
| { |
| sal_uInt16 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() ) |
| { |
| sal_uInt16 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 ); |
| sal_Bool bRel = bUseRelWidth && |
| text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient(); |
| aFrmSize.SetWidthPercent( (sal_uInt8)(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( (sal_uInt8)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( sal_uInt16 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( sal_uInt16 nAbsAvail, sal_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()->GetCurrentViewShell()->GetLayout(); |
| if ( pRoot && pRoot->IsCallbackActionEnabled() ) |
| pRoot->StartAllAction(); //swmod 071108//swmod 071225 |
| |
| // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils |
| // noch der Pass 2 laufen muss. |
| SetWidths( sal_True, nAbsAvail ); |
| |
| if ( pRoot && pRoot->IsCallbackActionEnabled() ) |
| pRoot->EndAllAction( sal_True ); //True per VirDev (Browsen ruhiger) //swmod 071108//swmod 071225 |
| } |
| |
| 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; |
| } |
| |
| |
| sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc, |
| sal_Bool bForce, sal_uLong nDelay ) |
| { |
| if( 0 == nAbsAvail ) |
| return sal_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 sal_False; |
| |
| // Darf ein Recalc der Tabelle durchgefuehrt werden? |
| if( bMustNotRecalc && !bForce ) |
| bRecalc = sal_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->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() ) |
| { |
| const sal_uInt16 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 sal_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 sal_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 sal_True; |
| } |
| |
| void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc ) |
| { |
| bBordersChanged = sal_True; |
| |
| Resize( nAbsAvail, bRecalc ); |
| } |
| |
| |