merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / htmltbl.cxx
blob836ab141047de40a87bdf86997c30a0c7d55f789
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: htmltbl.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "hintids.hxx"
35 //#define TEST_DELAYED_RESIZE
37 #ifdef TEST_DELAYED_RESIZE
38 #include <vcl/sound.hxx>
39 #endif
40 #ifndef _WRKWIN_HXX //autogen
41 #include <vcl/wrkwin.hxx>
42 #endif
43 #ifndef _APP_HXX //autogen
44 #include <vcl/svapp.hxx>
45 #endif
46 #include <sot/storage.hxx>
47 #include <fmtornt.hxx>
48 #include <fmtfsize.hxx>
49 #include <frmfmt.hxx>
50 #include <docary.hxx>
51 #include "ndtxt.hxx"
52 #include "doc.hxx"
53 #include "swtable.hxx"
54 #include "rootfrm.hxx"
55 #include "docsh.hxx"
56 #include "flyfrm.hxx"
57 #include "poolfmt.hxx"
58 #include "viewsh.hxx"
59 #include "tabfrm.hxx"
61 #include "htmltbl.hxx"
62 #include "ndindex.hxx"
64 using namespace ::com::sun::star;
67 #define COLFUZZY 20
68 #define MAX_TABWIDTH (USHRT_MAX - 2001)
71 /* \f */
73 class SwHTMLTableLayoutConstraints
75 USHORT nRow; // Start-Zeile
76 USHORT nCol; // Start-Spalte
77 USHORT nColSpan; // COLSPAN der Zelle
79 SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung
81 ULONG nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1
83 public:
85 SwHTMLTableLayoutConstraints( ULONG nMin, ULONG nMax, USHORT nRow,
86 USHORT nCol, USHORT nColSp );
87 ~SwHTMLTableLayoutConstraints();
89 ULONG GetMinNoAlign() const { return nMinNoAlign; }
90 ULONG GetMaxNoAlign() const { return nMaxNoAlign; }
92 SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt );
93 SwHTMLTableLayoutConstraints* GetNext() const { return pNext; }
95 USHORT GetRow() const { return nRow; }
97 USHORT GetColSpan() const { return nColSpan; }
98 USHORT GetColumn() const { return nCol; }
101 /* \f */
103 SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd,
104 SwHTMLTableLayout* pTab,
105 BOOL bNoBrTag,
106 SwHTMLTableLayoutCnts* pNxt ) :
107 pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ),
108 nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag )
111 SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts()
113 delete pNext;
114 delete pTable;
117 const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const
119 return pBox ? pBox->GetSttNd() : pStartNode;
123 /* \f */
125 SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts,
126 USHORT nRSpan, USHORT nCSpan,
127 USHORT nWidth, BOOL bPrcWidth,
128 BOOL bNWrapOpt ) :
129 pContents( pCnts ),
130 nRowSpan( nRSpan ), nColSpan( nCSpan ),
131 nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ),
132 bNoWrapOption( bNWrapOpt )
135 SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell()
137 if( nRowSpan==1 && nColSpan==1 )
139 delete pContents;
143 /* \f */
145 SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( USHORT nWidth,
146 BOOL bRelWidth,
147 BOOL bLBorder ) :
148 nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY),
149 nMin(0), nMax(0),
150 nAbsColWidth(0), nRelColWidth(0),
151 nWidthOption( nWidth ), bRelWidthOption( bRelWidth ),
152 bLeftBorder( bLBorder )
156 /* \f */
158 SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints(
159 ULONG nMin, ULONG nMax, USHORT nRw, USHORT nColumn, USHORT nColSp ):
160 nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ),
161 pNext( 0 ),
162 nMinNoAlign( nMin ), nMaxNoAlign( nMax )
165 SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints()
167 delete pNext;
170 SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext(
171 SwHTMLTableLayoutConstraints *pNxt )
173 SwHTMLTableLayoutConstraints *pPrev = 0;
174 SwHTMLTableLayoutConstraints *pConstr = this;
175 while( pConstr )
177 if( pConstr->GetRow() > pNxt->GetRow() ||
178 pConstr->GetColumn() > pNxt->GetColumn() )
179 break;
180 pPrev = pConstr;
181 pConstr = pConstr->GetNext();
184 if( pPrev )
186 pNxt->pNext = pPrev->GetNext();
187 pPrev->pNext = pNxt;
188 pConstr = this;
190 else
192 pNxt->pNext = this;
193 pConstr = pNxt;
196 return pConstr;
199 /* \f */
201 typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr;
202 typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr;
204 SwHTMLTableLayout::SwHTMLTableLayout(
205 const SwTable * pSwTbl,
206 USHORT nRws, USHORT nCls, BOOL bColsOpt, BOOL bColTgs,
207 USHORT nWdth, BOOL bPrcWdth, USHORT nBorderOpt,
208 USHORT nCellPad, USHORT nCellSp, SvxAdjust eAdjust,
209 USHORT nLMargin, USHORT nRMargin,
210 USHORT nBWidth, USHORT nLeftBWidth,
211 USHORT nRightBWidth,
212 USHORT nInhLeftBWidth, USHORT nInhRightBWidth ) :
213 aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ),
214 aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ),
215 pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ),
216 nMin( 0 ), nMax( 0 ),
217 nRows( nRws ), nCols( nCls ),
218 nLeftMargin( nLMargin ), nRightMargin( nRMargin ),
219 nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ),
220 nRelLeftFill( 0 ), nRelRightFill( 0 ),
221 nRelTabWidth( 0 ), nWidthOption( nWdth ),
222 nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ),
223 nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ),
224 nInhLeftBorderWidth( nInhLeftBWidth ),
225 nInhRightBorderWidth( nInhRightBWidth ),
226 nBorderWidth( nBWidth ),
227 nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ),
228 nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ),
229 bColsOption( bColsOpt ), bColTags( bColTgs ),
230 bPrcWidthOption( bPrcWdth ), bUseRelWidth( FALSE ),
231 bMustResize( TRUE ), bExportable( TRUE ), bBordersChanged( FALSE ),
232 bMustNotResize( FALSE ), bMustNotRecalc( FALSE )
234 aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout,
235 DelayedResize_Impl ) );
238 SwHTMLTableLayout::~SwHTMLTableLayout()
240 USHORT i;
242 for( i = 0; i < nCols; i++ )
243 delete aColumns[i];
244 delete[] aColumns;
246 USHORT nCount = nRows*nCols;
247 for( i=0; i<nCount; i++ )
248 delete aCells[i];
249 delete[] aCells;
252 // Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet:
253 // Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING
254 // Innere Umrandung: CELLSPACING + CELLPADDING
255 // Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn
256 // bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird.
257 // MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden,
258 // und zwar auch dann, wenn wenn nur die gegenueberliegende Seite
259 // eine Umrandung hat.
260 USHORT SwHTMLTableLayout::GetLeftCellSpace( USHORT nCol, USHORT nColSpan,
261 BOOL bSwBorders ) const
263 USHORT nSpace = nCellSpacing + nCellPadding;
265 if( nCol == 0 )
267 nSpace = nSpace + nBorder;
269 if( bSwBorders && nSpace < nLeftBorderWidth )
270 nSpace = nLeftBorderWidth;
272 else if( bSwBorders )
274 if( GetColumn(nCol)->HasLeftBorder() )
276 if( nSpace < nBorderWidth )
277 nSpace = nBorderWidth;
279 else if( nCol+nColSpan == nCols && nRightBorderWidth &&
280 nSpace < MIN_BORDER_DIST )
282 ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" );
283 // Wenn die Gegenueberliegende Seite umrandet ist muessen
284 // wir zumindest den minimalen Abstand zum Inhalt
285 // beruecksichtigen. (Koennte man zusaetzlich auch an
286 // nCellPadding festmachen.)
287 nSpace = MIN_BORDER_DIST;
291 return nSpace;
294 USHORT SwHTMLTableLayout::GetRightCellSpace( USHORT nCol, USHORT nColSpan,
295 BOOL bSwBorders ) const
297 USHORT nSpace = nCellPadding;
299 if( nCol+nColSpan == nCols )
301 nSpace += nBorder + nCellSpacing;
302 if( bSwBorders && nSpace < nRightBorderWidth )
303 nSpace = nRightBorderWidth;
305 else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() &&
306 nSpace < MIN_BORDER_DIST )
308 ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" );
309 // Wenn die Gegenueberliegende Seite umrandet ist muessen
310 // wir zumindest den minimalen Abstand zum Inhalt
311 // beruecksichtigen. (Koennte man zusaetzlich auch an
312 // nCellPadding festmachen.)
313 nSpace = MIN_BORDER_DIST;
316 return nSpace;
319 void SwHTMLTableLayout::AddBorderWidth( ULONG &rMin, ULONG &rMax,
320 ULONG &rAbsMin,
321 USHORT nCol, USHORT nColSpan,
322 BOOL bSwBorders ) const
324 ULONG nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) +
325 GetRightCellSpace( nCol, nColSpan, bSwBorders );
327 rMin += nAdd;
328 rMax += nAdd;
329 rAbsMin += nAdd;
332 void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, USHORT nCol,
333 USHORT nColSpan ) const
335 SwFrmFmt *pFrmFmt = pBox->GetFrmFmt();
337 // die Breite der Box berechnen
338 SwTwips nFrmWidth = 0;
339 while( nColSpan-- )
340 nFrmWidth += GetColumn( nCol++ )->GetRelColWidth();
342 // und neu setzen
344 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 ));
347 void SwHTMLTableLayout::GetAvail( USHORT nCol, USHORT nColSpan,
348 USHORT& rAbsAvail, USHORT& rRelAvail ) const
350 rAbsAvail = 0;
351 rRelAvail = 0;
352 for( USHORT i=nCol; i<nCol+nColSpan;i++ )
354 const SwHTMLTableLayoutColumn *pColumn = GetColumn(i);
355 rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth();
356 rRelAvail = rRelAvail + pColumn->GetRelColWidth();
360 USHORT SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc )
362 ViewShell *pVSh = 0;
363 rDoc.GetEditShell( &pVSh );
364 if( pVSh )
366 return (USHORT)pVSh->GetBrowseWidth();
369 return 0;
372 USHORT SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc )
374 // Wenn ein Layout da ist, koennen wir die Breite dort herholen.
375 const SwRootFrm *pRootFrm = rDoc.GetRootFrm();
376 if( pRootFrm )
378 const SwFrm *pPageFrm = pRootFrm->GetLower();
379 if( pPageFrm )
380 return (USHORT)pPageFrm->Prt().Width();
383 // Sonst versuchen wir es ueber die ViewShell
384 USHORT nWidth = GetBrowseWidthByVisArea( rDoc );
385 if( !nWidth )
387 // Und wenn das auch nicht geht, gibt es noch die ActualSize an der
388 // DocShell.
389 if( rDoc.GetDocShell() && GetpApp() && GetpApp()->GetDefaultDevice() )
391 // this case shouldn't happen because the filter always waits until
392 // a view has been created
394 nWidth = (USHORT)Application::GetDefaultDevice()
395 ->PixelToLogic( rDoc.GetDocShell()->GetActualSize(),
396 MapMode( MAP_TWIP ) ).Width();
398 ASSERT( nWidth, "No browse width available" );
400 #ifndef PRODUCT
401 else
403 // und wenn das auch nicht klappt, gibt es zur Zeit keine Breite
404 ASSERT( nWidth, "No browse width available" );
406 #endif
408 return nWidth;
411 USHORT SwHTMLTableLayout::GetBrowseWidthByTabFrm(
412 const SwTabFrm& rTabFrm ) const
414 SwTwips nWidth = 0;
416 const SwFrm *pUpper = rTabFrm.GetUpper();
417 if( MayBeInFlyFrame() && pUpper->IsFlyFrm() &&
418 ((const SwFlyFrm *)pUpper)->GetAnchorFrm() )
420 // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist
421 // die Breite Ankers und nicht die Breite Rahmens von Bedeutung.
422 // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet.
423 const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm();
424 if( pAnchor->IsTxtFrm() )
425 nWidth = pAnchor->Frm().Width();
426 else
427 nWidth = pAnchor->Prt().Width();
429 else
431 nWidth = pUpper->Prt().Width();
434 SwTwips nUpperDummy = 0;
435 long nRightOffset = 0,
436 nLeftOffset = 0;
437 rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset );
438 nWidth -= (nLeftOffset + nRightOffset);
440 return nWidth < USHRT_MAX ? static_cast<USHORT>(nWidth) : USHRT_MAX;
443 USHORT SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const
445 USHORT nBrowseWidth = 0;
446 SwClientIter aIter( *(SwModify*)pSwTable->GetFrmFmt() );
447 SwClient* pCli = aIter.First( TYPE( SwTabFrm ));
448 if( pCli )
450 nBrowseWidth = GetBrowseWidthByTabFrm( *(SwTabFrm*)pCli );
452 else
454 nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc );
457 return nBrowseWidth;
460 const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const
462 const SwStartNode *pBoxSttNd;
464 const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0];
465 while( 0 == (pBoxSttNd = pBox->GetSttNd()) )
467 ASSERT( pBox->GetTabLines().Count() > 0,
468 "Box ohne Start-Node und Lines" );
469 ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0,
470 "Line ohne Boxen" );
471 pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
474 return pBoxSttNd;
477 SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const
479 const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode();
480 ASSERT( pTblNd, "Kein Table-Node?" );
481 return pTblNd->GetFlyFmt();
484 static void lcl_GetMinMaxSize( ULONG& rMinNoAlignCnts, ULONG& rMaxNoAlignCnts,
485 ULONG& rAbsMinNoAlignCnts,
486 #ifdef FIX41370
487 BOOL& rHR,
488 #endif
489 SwTxtNode *pTxtNd, ULONG nIdx, BOOL bNoBreak )
491 pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts,
492 rAbsMinNoAlignCnts );
493 ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts,
494 "GetMinMaxSize: absmin > min" );
495 ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts,
496 "GetMinMaxSize: max > min" );
498 //Bei einen <PRE>-Absatz entspricht die maximale Breite der
499 // minimalen breite
500 const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl();
501 while( pColl && !pColl->IsDefault() &&
502 (USER_FMT & pColl->GetPoolFmtId()) )
504 pColl = (const SwFmtColl *)pColl->DerivedFrom();
507 // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht
508 // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken.
509 if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak )
511 rMinNoAlignCnts = rMaxNoAlignCnts;
512 rAbsMinNoAlignCnts = rMaxNoAlignCnts;
514 #ifdef FIX41370
515 else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() )
517 rHR |= !pTxtNd->HasSwAttrSet() ||
518 SFX_ITEM_SET != pTxtNd->GetpSwAttrSet()
519 ->GetItemState( RES_LR_SPACE, FALSE );
521 #endif
524 void SwHTMLTableLayout::AutoLayoutPass1()
526 nPass1Done++;
528 ClearPass1Info();
530 BOOL bFixRelWidths = FALSE;
531 USHORT i;
533 SwHTMLTableLayoutConstraints *pConstraints = 0;
535 for( i=0; i<nCols; i++ )
537 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
538 pColumn->ClearPass1Info( !HasColTags() );
539 USHORT nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir
540 // berechnete Breite bezieht
541 USHORT nColSkip = USHRT_MAX; // Wie viele Spalten muessen
542 // uebersprungen werden
544 for( USHORT j=0; j<nRows; j++ )
546 SwHTMLTableLayoutCell *pCell = GetCell(j,i);
547 SwHTMLTableLayoutCnts *pCnts = pCell->GetContents();
549 // fix #31488#: Zum Ermitteln der naechsten zu berechnenden
550 // Spalte muessen alle Zeilen herangezogen werden
551 USHORT nColSpan = pCell->GetColSpan();
552 if( nColSpan < nColSkip )
553 nColSkip = nColSpan;
555 if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) )
557 // die Zelle ist leer oder ihr Inhalt wurde nich nicht
558 // bearbeitet
559 if( nColSpan < nMinColSpan )
560 nMinColSpan = nColSpan;
562 ULONG nMinNoAlignCell = 0;
563 ULONG nMaxNoAlignCell = 0;
564 ULONG nAbsMinNoAlignCell = 0;
565 ULONG nMaxTableCell = 0;
566 ULONG nAbsMinTableCell = 0;
567 #ifdef FIX41370
568 BOOL bHR = FALSE;
569 #endif
571 while( pCnts )
573 const SwStartNode *pSttNd = pCnts->GetStartNode();
574 if( pSttNd )
576 const SwDoc *pDoc = pSttNd->GetDoc();
577 ULONG nIdx = pSttNd->GetIndex();
578 while( !(pDoc->GetNodes()[nIdx])->IsEndNode() )
580 SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode();
581 if( pTxtNd )
583 ULONG nMinNoAlignCnts = 0;
584 ULONG nMaxNoAlignCnts = 0;
585 ULONG nAbsMinNoAlignCnts = 0;
587 lcl_GetMinMaxSize( nMinNoAlignCnts,
588 nMaxNoAlignCnts,
589 nAbsMinNoAlignCnts,
590 #ifdef FIX41370
591 bHR,
592 #endif
593 pTxtNd, nIdx,
594 pCnts->HasNoBreakTag() );
596 if( nMinNoAlignCnts > nMinNoAlignCell )
597 nMinNoAlignCell = nMinNoAlignCnts;
598 if( nMaxNoAlignCnts > nMaxNoAlignCell )
599 nMaxNoAlignCell = nMaxNoAlignCnts;
600 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell )
601 nAbsMinNoAlignCell = nAbsMinNoAlignCnts;
603 else
605 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode();
606 if( pTabNd )
608 SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout();
609 if( pChild )
611 pChild->AutoLayoutPass1();
612 ULONG nMaxTableCnts = pChild->nMax;
613 ULONG nAbsMinTableCnts = pChild->nMin;
615 // Eine feste Tabellen-Breite wird als Minimum
616 // und Maximum gleichzeitig uebernommen
617 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
619 ULONG nTabWidth = pChild->nWidthOption;
620 if( nTabWidth >= nAbsMinTableCnts )
622 nMaxTableCnts = nTabWidth;
623 nAbsMinTableCnts = nTabWidth;
625 else
627 nMaxTableCnts = nAbsMinTableCnts;
631 if( nMaxTableCnts > nMaxTableCell )
632 nMaxTableCell = nMaxTableCnts;
633 if( nAbsMinTableCnts > nAbsMinTableCell )
634 nAbsMinTableCell = nAbsMinTableCnts;
636 nIdx = pTabNd->EndOfSectionNode()->GetIndex();
639 nIdx++;
642 else
644 ASSERT( !this, "Sub tables in HTML import?" )
645 SwHTMLTableLayout *pChild = pCnts->GetTable();
646 pChild->AutoLayoutPass1();
647 ULONG nMaxTableCnts = pChild->nMax;
648 ULONG nAbsMinTableCnts = pChild->nMin;
650 // Eine feste Tabellen-Breite wird als Minimum
651 // und Maximum gleichzeitig uebernommen
652 if( !pChild->bPrcWidthOption && pChild->nWidthOption )
654 ULONG nTabWidth = pChild->nWidthOption;
655 if( nTabWidth >= nAbsMinTableCnts )
657 nMaxTableCnts = nTabWidth;
658 nAbsMinTableCnts = nTabWidth;
660 else
662 nMaxTableCnts = nAbsMinTableCnts;
666 if( nMaxTableCnts > nMaxTableCell )
667 nMaxTableCell = nMaxTableCnts;
668 if( nAbsMinTableCnts > nAbsMinTableCell )
669 nAbsMinTableCell = nAbsMinTableCnts;
671 pCnts->SetPass1Done( nPass1Done );
672 pCnts = pCnts->GetNext();
675 // War frueher hinter AddBorderWidth
676 // Wenn die Breite einer Tabelle in der Zelle breiter ist als
677 // das, was wir fuer sonstigen Inhalt berechnet haben, mussen
678 // wir die Breite der Tabelle nutzen
679 if( nMaxTableCell > nMaxNoAlignCell )
680 nMaxNoAlignCell = nMaxTableCell;
681 if( nAbsMinTableCell > nAbsMinNoAlignCell )
683 nAbsMinNoAlignCell = nAbsMinTableCell;
684 if( nMinNoAlignCell < nAbsMinNoAlignCell )
685 nMinNoAlignCell = nAbsMinNoAlignCell;
686 if( nMaxNoAlignCell < nMinNoAlignCell )
687 nMaxNoAlignCell = nMinNoAlignCell;
689 // War frueher hinter AddBorderWidth
691 BOOL bRelWidth = pCell->IsPrcWidthOption();
692 USHORT nWidth = pCell->GetWidthOption();
694 // Eine NOWRAP-Option bezieht sich auf Text und auf
695 // Tabellen, wird aber bei fester Zellenbreite
696 // nicht uebernommen. Stattdessen wirkt die angegebene
697 // Zellenbreite wie eine Mindestbreite.
698 if( pCell->HasNoWrapOption() )
700 if( nWidth==0 || bRelWidth )
702 nMinNoAlignCell = nMaxNoAlignCell;
703 nAbsMinNoAlignCell = nMaxNoAlignCell;
705 else
707 if( nWidth>nMinNoAlignCell )
708 nMinNoAlignCell = nWidth;
709 if( nWidth>nAbsMinNoAlignCell )
710 nAbsMinNoAlignCell = nWidth;
713 #ifdef FIX41370
714 else if( bHR && nWidth>0 && !bRelWidth )
716 // Ein kleiner Hack, um einen Bug in Netscape 4.0
717 // nachzubilden (siehe #41370#). Wenn eine Zelle eine
718 // fixe Breite besitzt und gleichzeitig ein HR, wird
719 // sie nie schmaler als die angegebene Breite.
720 // (Genaugenomen scheint die Zelle nie schmaler zu werden
721 // als die HR-Linie, denn wenn man fuer die Linie eine
722 // Breite angibt, die breiter ist als die der Zelle, dann
723 // wird die Zelle so breit wie die Linie. Das bekommen wir
724 // natuerlich nicht hin.)
725 if( nWidth>nMinNoAlignCell )
726 nMinNoAlignCell = nWidth;
727 if( nWidth>nAbsMinNoAlignCell )
728 nAbsMinNoAlignCell = nWidth;
730 #endif
732 // Mindestbreite fuer Inhalt einhalten
733 if( nMinNoAlignCell < MINLAY )
734 nMinNoAlignCell = MINLAY;
735 if( nMaxNoAlignCell < MINLAY )
736 nMaxNoAlignCell = MINLAY;
737 if( nAbsMinNoAlignCell < MINLAY )
738 nAbsMinNoAlignCell = MINLAY;
740 // Umrandung und Abstand zum Inhalt beachten.
741 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell,
742 nAbsMinNoAlignCell, i, nColSpan );
744 if( 1==nColSpan )
746 // die Werte direkt uebernehmen
747 pColumn->MergeMinMaxNoAlign( nMinNoAlignCell,
748 nMaxNoAlignCell,
749 nAbsMinNoAlignCell );
751 // bei den WIDTH angaben gewinnt die breiteste
752 if( !HasColTags() )
753 pColumn->MergeCellWidthOption( nWidth, bRelWidth );
755 else
757 // die Angaben erst am Ende, und zwar zeilenweise von
758 // links nach rechts bearbeiten
760 // Wann welche Werte wie uebernommen werden ist weiter
761 // unten erklaert.
762 if( !HasColTags() && nWidth && !bRelWidth )
764 ULONG nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0;
765 AddBorderWidth( nAbsWidth, nDummy, nDummy2,
766 i, nColSpan, FALSE );
768 if( nAbsWidth >= nMinNoAlignCell )
770 nMaxNoAlignCell = nAbsWidth;
771 if( HasColsOption() )
772 nMinNoAlignCell = nAbsWidth;
774 else if( nAbsWidth >= nAbsMinNoAlignCell )
776 nMaxNoAlignCell = nAbsWidth;
777 nMinNoAlignCell = nAbsWidth;
779 else
781 nMaxNoAlignCell = nAbsMinNoAlignCell;
782 nMinNoAlignCell = nAbsMinNoAlignCell;
785 else if( HasColsOption() || HasColTags() )
786 nMinNoAlignCell = nAbsMinNoAlignCell;
788 SwHTMLTableLayoutConstraints *pConstr =
789 new SwHTMLTableLayoutConstraints( nMinNoAlignCell,
790 nMaxNoAlignCell, j, i, nColSpan );
791 if( pConstraints )
792 pConstraints = pConstraints->InsertNext( pConstr );
793 else
794 pConstraints = pConstr;
799 ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan,
800 "Layout Pass 1: Da werden Spalten vergessen!" );
801 ASSERT( nMinColSpan!=USHRT_MAX,
802 "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" );
804 if( 1==nMinColSpan )
806 // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle
807 // Werte in pColumn
809 // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen:
811 // WIDTH: kein COLS COLS
813 // keine min = min min = absmin
814 // max = max max = max
816 // >= min min = min min = width
817 // max = width max = width
819 // >= absmin min = wdith(*) min = width
820 // max = width max = width
822 // < absmin min = absmin min = absmin
823 // max = absmin max = absmin
825 // (*) Netscape benutzt hier die Mindestbreite ohne einen
826 // Umbruch vor der letzten Grafik. Haben wir (noch?) nicht,
827 // also belassen wir es bei width.^
829 if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() )
831 // absolute Breiten als Minimal- und Maximalbreite
832 // uebernehmen.
833 ULONG nAbsWidth = pColumn->GetWidthOption();
834 ULONG nDummy = 0, nDummy2 = 0;
835 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, FALSE );
837 if( nAbsWidth >= pColumn->GetMinNoAlign() )
839 pColumn->SetMinMax( HasColsOption() ? nAbsWidth
840 : pColumn->GetMinNoAlign(),
841 nAbsWidth );
843 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() )
845 pColumn->SetMinMax( nAbsWidth, nAbsWidth );
847 else
849 pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(),
850 pColumn->GetAbsMinNoAlign() );
853 else
855 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign()
856 : pColumn->GetMinNoAlign(),
857 pColumn->GetMaxNoAlign() );
860 else if( USHRT_MAX!=nMinColSpan )
862 // kann irgendwas !=0 sein, weil es durch die Constraints
863 // angepasst wird.
864 pColumn->SetMinMax( MINLAY, MINLAY );
866 // die naechsten Spalten muessen nicht bearbeitet werden
867 i += (nColSkip-1);
870 nMin += pColumn->GetMin();
871 nMax += pColumn->GetMax();
872 bFixRelWidths |= pColumn->IsRelWidthOption();
875 // jetzt noch die Constrains verarbeiten
876 SwHTMLTableLayoutConstraints *pConstr = pConstraints;
877 while( pConstr )
879 // Erstmal muss die Breite analog zu den den Spaltenbreiten
880 // aufbereitet werden
881 USHORT nCol = pConstr->GetColumn();
882 USHORT nColSpan = pConstr->GetColSpan();
883 ULONG nConstrMin = pConstr->GetMinNoAlign();
884 ULONG nConstrMax = pConstr->GetMaxNoAlign();
886 // jetzt holen wir uns die bisherige Breite der ueberspannten
887 // Spalten
888 ULONG nColsMin = 0;
889 ULONG nColsMax = 0;
890 for( USHORT j=nCol; j<nCol+nColSpan; j++ )
892 SwHTMLTableLayoutColumn *pColumn = GetColumn( j );
893 nColsMin += pColumn->GetMin();
894 nColsMax += pColumn->GetMax();
897 if( nColsMin<nConstrMin )
899 // den Minimalwert anteilig auf die Spalten verteilen
900 ULONG nMinD = nConstrMin-nColsMin;
902 if( nConstrMin > nColsMax )
904 // Anteilig anhand der Mindestbreiten
905 USHORT nEndCol = nCol+nColSpan;
906 ULONG nDiff = nMinD;
907 for( USHORT ic=nCol; ic<nEndCol; ic++ )
909 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
911 ULONG nColMin = pColumn->GetMin();
912 ULONG nColMax = pColumn->GetMax();
914 nMin -= nColMin;
915 ULONG nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin
916 : nDiff;
917 nColMin += nAdd;
918 nMin += nColMin;
919 ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" );
920 nDiff -= nAdd;
922 if( nColMax < nColMin )
924 nMax -= nColMax;
925 nColsMax -= nColMax;
926 nColMax = nColMin;
927 nMax += nColMax;
928 nColsMax += nColMax;
931 pColumn->SetMinMax( nColMin, nColMax );
934 else
936 // Anteilig anhand der Differenz zwischen Max und Min
937 for( USHORT ic=nCol; ic<nCol+nColSpan; ic++ )
939 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
941 ULONG nDiff = pColumn->GetMax()-pColumn->GetMin();
942 if( nMinD < nDiff )
943 nDiff = nMinD;
945 pColumn->AddToMin( nDiff );
947 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
948 "Wieso ist die SPalte auf einmal zu schmal?" )
950 nMin += nDiff;
951 nMinD -= nDiff;
956 if( !HasColTags() && nColsMax<nConstrMax )
958 ULONG nMaxD = nConstrMax-nColsMax;
960 for( USHORT ic=nCol; ic<nCol+nColSpan; ic++ )
962 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic );
964 nMax -= pColumn->GetMax();
966 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax );
968 nMax += pColumn->GetMax();
972 pConstr = pConstr->GetNext();
976 if( bFixRelWidths )
978 if( HasColTags() )
980 // Zum Anpassen der relativen Breiten werden im 1. Schritt die
981 // Minmalbreiten aller anzupassenden Zellen jeweils mit der
982 // relativen Breite einer Spalte multipliziert. Dadurch stimmen
983 // dann die Breitenverhaeltnisse der Spalten untereinander.
984 // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch
985 // breiter gworden ist als die Minmalbreite.
986 // Im 2. Schritt werden dann die berechneten Breiten durch diesen
987 // Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle
988 // erhalten und dient als Ausgangsbasis fuer die andern Breiten.
989 // Es werden auch hier nur die Maximalbreiten beeinflusst!
991 ULONG nAbsMin = 0; // absolte Min-Breite alter Spalten mit
992 // relativer Breite
993 ULONG nRel = 0; // Summe der relativen Breiten aller Spalten
994 for( i=0; i<nCols; i++ )
996 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
997 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
999 nAbsMin += pColumn->GetMin();
1000 nRel += pColumn->GetWidthOption();
1004 ULONG nQuot = ULONG_MAX;
1005 for( i=0; i<nCols; i++ )
1007 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1008 if( pColumn->IsRelWidthOption() )
1010 nMax -= pColumn->GetMax();
1011 if( pColumn->GetWidthOption() && pColumn->GetMin() )
1013 pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() );
1014 ULONG nColQuot = pColumn->GetMax() / pColumn->GetMin();
1015 if( nColQuot<nQuot )
1016 nQuot = nColQuot;
1020 ASSERT( 0==nRel || nQuot!=ULONG_MAX,
1021 "Wo sind die relativen Spalten geblieben?" );
1022 for( i=0; i<nCols; i++ )
1024 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1025 if( pColumn->IsRelWidthOption() )
1027 if( pColumn->GetWidthOption() )
1028 pColumn->SetMax( pColumn->GetMax() / nQuot );
1029 else
1030 pColumn->SetMax( pColumn->GetMin() );
1031 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
1032 "Maximale Spaltenbreite kleiner als Minimale" );
1033 nMax += pColumn->GetMax();
1037 else
1039 USHORT nRel = 0; // Summe der relativen Breiten aller Spalten
1040 USHORT nRelCols = 0; // Anzahl Spalten mit relativer Angabe
1041 ULONG nRelMax = 0; // Anteil am Maximum dieser Spalten
1042 for( i=0; i<nCols; i++ )
1044 ASSERT( nRel<=100, "relative Breite aller Spalten>100%" );
1045 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1046 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1048 // Sicherstellen, dass die relativen breiten nicht
1049 // ueber 100% landen
1050 USHORT nColWidth = pColumn->GetWidthOption();
1051 if( nRel+nColWidth > 100 )
1053 nColWidth = 100 - nRel;
1054 pColumn->SetWidthOption( nColWidth, TRUE, FALSE );
1056 nRelMax += pColumn->GetMax();
1057 nRel = nRel + nColWidth;
1058 nRelCols++;
1060 else if( !pColumn->GetMin() )
1062 // Die Spalte ist leer (wurde also auschliesslich
1063 // durch COLSPAN erzeugt) und darf deshalb auch
1064 // keine %-Breite zugewiesen bekommen.
1065 nRelCols++;
1069 // Eventuell noch vorhandene Prozente werden auf die Spalten ohne
1070 // eine Breiten-Angabe verteilt. Wie in Netscape werden die
1071 // verbleibenden Prozente enstprechend der Verhaeltnisse
1072 // der Maximalbreiten der in Frage kommenden Spalten
1073 // untereinander verteilt.
1074 // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten
1075 // mit fester Breite. Ist das richtig???
1076 if( nRel < 100 && nRelCols < nCols )
1078 USHORT nRelLeft = 100 - nRel;
1079 ULONG nFixMax = nMax - nRelMax;
1080 for( i=0; i<nCols; i++ )
1082 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1083 if( !pColumn->IsRelWidthOption() &&
1084 !pColumn->GetWidthOption() &&
1085 pColumn->GetMin() )
1087 // den Rest bekommt die naechste Spalte
1088 USHORT nColWidth =
1089 (USHORT)((pColumn->GetMax() * nRelLeft) / nFixMax);
1090 pColumn->SetWidthOption( nColWidth, TRUE, FALSE );
1095 // nun die Maximalbreiten entsprechend anpassen
1096 ULONG nQuotMax = ULONG_MAX;
1097 ULONG nOldMax = nMax;
1098 nMax = 0;
1099 for( i=0; i<nCols; i++ )
1101 // Spalten mit %-Angaben werden enstprechend angepasst.
1102 // Spalten, die
1103 // - keine %-Angabe besitzen und in einer Tabelle mit COLS
1104 // oder WIDTH vorkommen, oder
1105 // - als Breite 0% angegeben haben erhalten die Minimalbreite
1106 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1107 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1109 ULONG nNewMax;
1110 ULONG nColQuotMax;
1111 if( !nWidthOption )
1113 nNewMax = nOldMax * pColumn->GetWidthOption();
1114 nColQuotMax = nNewMax / pColumn->GetMax();
1116 else
1118 nNewMax = nMin * pColumn->GetWidthOption();
1119 nColQuotMax = nNewMax / pColumn->GetMin();
1121 pColumn->SetMax( nNewMax );
1122 if( nColQuotMax < nQuotMax )
1123 nQuotMax = nColQuotMax;
1125 else if( HasColsOption() || nWidthOption ||
1126 (pColumn->IsRelWidthOption() &&
1127 !pColumn->GetWidthOption()) )
1128 pColumn->SetMax( pColumn->GetMin() );
1130 // und durch den Quotienten teilen
1131 ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" );
1132 for( i=0; i<nCols; i++ )
1134 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1135 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() )
1137 if( pColumn->GetWidthOption() )
1139 pColumn->SetMax( pColumn->GetMax() / nQuotMax );
1140 ASSERT( pColumn->GetMax() >= pColumn->GetMin(),
1141 "Minimalbreite ein Spalte Groesser Maximum" );
1142 if( pColumn->GetMax() < pColumn->GetMin() )
1143 pColumn->SetMax( pColumn->GetMin() );
1146 nMax += pColumn->GetMax();
1151 delete pConstraints;
1154 // nAbsAvail ist der verfuegbare Platz in TWIPS.
1155 // nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0
1156 // nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle
1157 // fur die Umrandung und den Abstand zum Inhalt reserviert ist.
1158 void SwHTMLTableLayout::AutoLayoutPass2( USHORT nAbsAvail, USHORT nRelAvail,
1159 USHORT nAbsLeftSpace,
1160 USHORT nAbsRightSpace,
1161 USHORT nParentInhAbsSpace )
1163 // Erstmal fuehren wie jede Menge Plausibilaets-Test durch
1165 // Eine abolute zur Verfuegung stehende Breite muss immer uebergeben
1166 // werden.
1167 ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" );
1169 // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer
1170 // Tabellen in Tabellen uebergeben
1171 ASSERT( IsTopTable() == (nRelAvail==0),
1172 "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" );
1174 // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein
1175 // als das die Maximalbreite.
1176 ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" );
1178 // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken.
1179 // (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung
1180 // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.)
1181 nLastResizeAbsAvail = nAbsAvail;
1183 // Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender,
1184 // vorhandene Filler-Zellen und Abstande angepasst
1186 // Abstand zum Inhalt und Unrandung
1187 USHORT nAbsLeftFill = 0, nAbsRightFill = 0;
1188 if( !IsTopTable() &&
1189 GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail )
1191 nAbsLeftFill = nAbsLeftSpace;
1192 nAbsRightFill = nAbsRightSpace;
1195 // Linker und rechter Abstand
1196 if( nLeftMargin || nRightMargin )
1198 if( IsTopTable() )
1200 // fuer die Top-Table beruecksichtigen wir die Raender immer,
1201 // den die Minimalbreite der Tabelle wird hier nie unterschritten
1202 nAbsAvail -= (nLeftMargin + nRightMargin);
1204 else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail )
1206 // sonst beruecksichtigen wir die Raender nur, wenn auch Platz
1207 // fuer sie da ist (nMin ist hier bereits berechnet!)
1208 nAbsLeftFill = nAbsLeftFill + nLeftMargin;
1209 nAbsRightFill = nAbsRightFill + nRightMargin;
1213 // Filler-Zellen
1214 if( !IsTopTable() )
1216 if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth )
1217 nAbsLeftFill = MINLAY+nInhLeftBorderWidth;
1218 if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth )
1219 nAbsRightFill = MINLAY+nInhRightBorderWidth;
1222 // Anpassen des verfuegbaren Platzes.
1223 nRelLeftFill = 0;
1224 nRelRightFill = 0;
1225 if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) )
1227 ULONG nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill;
1229 nRelLeftFill = (USHORT)((nAbsLeftFillL * nRelAvail) / nAbsAvail);
1230 nRelRightFill = (USHORT)((nAbsRightFillL * nRelAvail) / nAbsAvail);
1232 nAbsAvail -= (nAbsLeftFill + nAbsRightFill);
1233 if( nRelAvail )
1234 nRelAvail -= (nRelLeftFill + nRelRightFill);
1238 // Schritt 2: Die absolute Tabellenbreite wird berechnet.
1239 USHORT nAbsTabWidth = 0;
1240 bUseRelWidth = FALSE;
1241 if( nWidthOption )
1243 if( bPrcWidthOption )
1245 ASSERT( nWidthOption<=100, "Prozentangabe zu gross" );
1246 if( nWidthOption > 100 )
1247 nWidthOption = 100;
1249 // Die absolute Breite entspricht den angegeben Prozent der
1250 // zur Verfuegung stehenden Breite.
1251 // Top-Tabellen bekommen nur eine relative Breite, wenn der
1252 // verfuegbare Platz *echt groesser* ist als die Minimalbreite.
1253 // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel
1254 // von einer relativen Breite zu einer absoluten Breite durch
1255 // Resize sonst zu einer Endlosschleife fuehrt.
1256 // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird,
1257 // wenn der Rahmen eine nicht-relative Breite besitzt, koennen
1258 // wir da solche Spielchen nicht spielen
1259 // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen
1260 // jetzt doch. Dort war eine Grafik in einer 1%-breiten
1261 // Tabelle und hat da natuerlich nicht hineingepasst.
1262 nAbsTabWidth = (USHORT)( ((ULONG)nAbsAvail * nWidthOption) / 100 );
1263 if( IsTopTable() &&
1264 ( /*MayBeInFlyFrame() ||*/ (ULONG)nAbsTabWidth > nMin ) )
1266 nRelAvail = USHRT_MAX;
1267 bUseRelWidth = TRUE;
1270 else
1272 nAbsTabWidth = nWidthOption;
1273 if( nAbsTabWidth > MAX_TABWIDTH )
1274 nAbsTabWidth = MAX_TABWIDTH;
1276 // Tabellen in Tabellen duerfen niemals breiter werden als der
1277 // verfuegbare Platz.
1278 if( !IsTopTable() && nAbsTabWidth > nAbsAvail )
1279 nAbsTabWidth = nAbsAvail;
1283 ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail,
1284 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" );
1285 ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail,
1286 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" );
1288 // Catch fuer die beiden Asserts von oben (man weiss ja nie!)
1289 if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail )
1290 nAbsTabWidth = nAbsAvail;
1293 // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der
1294 // absoluten und relativen Tabellenbreiten.
1295 if( (!IsTopTable() && nMin > (ULONG)nAbsAvail) ||
1296 nMin > MAX_TABWIDTH )
1298 // Wenn
1299 // - das Minumum einer inneren Tabelle groesser ist als der
1300 // verfuegbare Platz, oder
1301 // - das Minumum einer Top-Table groesser ist als USHRT_MAX
1302 // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX
1303 // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten
1304 // untereinander erhalten.
1306 nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail;
1307 nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth );
1309 // First of all, we check wether we can fit the layout constrains,
1310 // that are: Every cell's width excluding the borders must be at least
1311 // MINLAY:
1313 ULONG nRealMin = 0;
1314 for( USHORT i=0; i<nCols; i++ )
1316 ULONG nRealColMin = MINLAY, nDummy1, nDummy2;
1317 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1318 nRealMin += nRealColMin;
1320 if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) )
1322 // "Nichts geht mehr". We cannot get the minimum column widths
1323 // the layout wants to have.
1325 USHORT nAbs = 0, nRel = 0;
1326 SwHTMLTableLayoutColumn *pColumn;
1327 for( USHORT i=0; i<nCols-1; i++ )
1329 pColumn = GetColumn( i );
1330 ULONG nColMin = pColumn->GetMin();
1331 if( nColMin <= USHRT_MAX )
1333 pColumn->SetAbsColWidth(
1334 (USHORT)((nColMin * nAbsTabWidth) / nMin) );
1335 pColumn->SetRelColWidth(
1336 (USHORT)((nColMin * nRelTabWidth) / nMin) );
1338 else
1340 double nColMinD = nColMin;
1341 pColumn->SetAbsColWidth(
1342 (USHORT)((nColMinD * nAbsTabWidth) / nMin) );
1343 pColumn->SetRelColWidth(
1344 (USHORT)((nColMinD * nRelTabWidth) / nMin) );
1347 nAbs = nAbs + (USHORT)pColumn->GetAbsColWidth();
1348 nRel = nRel + (USHORT)pColumn->GetRelColWidth();
1350 pColumn = GetColumn( nCols-1 );
1351 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1352 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1354 else
1356 ULONG nDistAbs = nAbsTabWidth - nRealMin;
1357 ULONG nDistRel = nRelTabWidth - nRealMin;
1358 ULONG nDistMin = nMin - nRealMin;
1359 USHORT nAbs = 0, nRel = 0;
1360 SwHTMLTableLayoutColumn *pColumn;
1361 for( USHORT i=0; i<nCols-1; i++ )
1363 pColumn = GetColumn( i );
1364 ULONG nColMin = pColumn->GetMin();
1365 ULONG nRealColMin = MINLAY, nDummy1, nDummy2;
1366 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 );
1368 if( nColMin <= USHRT_MAX )
1370 pColumn->SetAbsColWidth(
1371 (USHORT)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1372 pColumn->SetRelColWidth(
1373 (USHORT)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1375 else
1377 double nColMinD = nColMin;
1378 pColumn->SetAbsColWidth(
1379 (USHORT)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) );
1380 pColumn->SetRelColWidth(
1381 (USHORT)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) );
1384 nAbs = nAbs + (USHORT)pColumn->GetAbsColWidth();
1385 nRel = nRel + (USHORT)pColumn->GetRelColWidth();
1387 pColumn = GetColumn( nCols-1 );
1388 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs );
1389 pColumn->SetRelColWidth( nRelTabWidth - nRel );
1392 else if( nMax <= (ULONG)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) )
1394 // Wenn
1395 // - die Tabelle eine fixe Breite besitzt und das Maximum der
1396 // Tabelle kleiner ist, oder
1397 // - das Maximum kleiner ist als der verfuegbare Platz
1398 // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur
1399 // unter Beruecksichtigung des Maxumums an die fixe Breite
1400 // angepasst werden.
1402 // Keine fixe Breite, dann das Maximum nehmen.
1403 if( !nAbsTabWidth )
1404 nAbsTabWidth = (USHORT)nMax;
1406 // Eine Top-Table darf auch beriter werden als der verfuegbare Platz.
1407 if( nAbsTabWidth > nAbsAvail )
1409 ASSERT( IsTopTable(),
1410 "Tabelle in Tabelle soll breiter werden als umgebende Zelle" );
1411 nAbsAvail = nAbsTabWidth;
1414 // Nur den Anteil der relativen Breite verwenden, der auch fuer
1415 // die absolute Breite verwendet wuerde.
1416 ULONG nAbsTabWidthL = nAbsTabWidth;
1417 nRelTabWidth =
1418 ( nRelAvail ? (USHORT)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1419 : nAbsTabWidth );
1421 // Gibt es Spalten mit und Spalten ohne %-Angabe?
1422 ULONG nFixMax = nMax;
1423 for( USHORT i=0; i<nCols; i++ )
1425 const SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1426 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 )
1427 nFixMax -= pColumn->GetMax();
1430 if( nFixMax > 0 && nFixMax < nMax )
1432 // ja, dann den zu verteilenden Platz nur auf die Spalten
1433 // mit %-Angabe verteilen.
1435 // In diesem (und nur in diesem) Fall gibt es Spalten,
1436 // die ihre Maximalbreite genau einhalten, also weder
1437 // schmaler noch breiter werden. Beim zurueckrechnen der
1438 // absoluten Breite aus der relativen Breite kann es
1439 // zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen
1440 // werden zuerst die fixen Breiten entsprechend korrigiert
1441 // eingestellt und erst danach die relativen.
1443 USHORT nAbs = 0, nRel = 0;
1444 USHORT nFixedCols = 0;
1445 USHORT i;
1447 for( i = 0; i < nCols; i++ )
1449 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1450 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() )
1452 // Die Spalte behaelt ihre Breite bei.
1453 nFixedCols++;
1454 ULONG nColMax = pColumn->GetMax();
1455 pColumn->SetAbsColWidth( (USHORT)nColMax );
1457 ULONG nRelColWidth =
1458 (nColMax * nRelTabWidth) / nAbsTabWidth;
1459 ULONG nChkWidth =
1460 (nRelColWidth * nAbsTabWidth) / nRelTabWidth;
1461 if( nChkWidth < nColMax )
1462 nRelColWidth++;
1463 else if( nChkWidth > nColMax )
1464 nRelColWidth--;
1465 pColumn->SetRelColWidth( (USHORT)nRelColWidth );
1467 nAbs = nAbs + (USHORT)nColMax;
1468 nRel = nRel + (USHORT)nRelColWidth;
1472 // Zu verteilende Anteile des Maximums und der relativen und
1473 // absoluten Breiten. nFixMax entspricht an dieser Stelle
1474 // nAbs, so dass man gleich nFixMax haette nehmen koennen.
1475 // Der Code ist so aber verstaendlicher.
1476 ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" )
1477 ULONG nDistMax = nMax - nFixMax;
1478 USHORT nDistAbsTabWidth = nAbsTabWidth - nAbs;
1479 USHORT nDistRelTabWidth = nRelTabWidth - nRel;
1481 for( i=0; i<nCols; i++ )
1483 SwHTMLTableLayoutColumn *pColumn = GetColumn( i );
1484 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 )
1486 // Die Spalte wird anteilig breiter.
1487 nFixedCols++;
1488 if( nFixedCols == nCols )
1490 pColumn->SetAbsColWidth( nAbsTabWidth-nAbs );
1491 pColumn->SetRelColWidth( nRelTabWidth-nRel );
1493 else
1495 ULONG nColMax = pColumn->GetMax();
1496 pColumn->SetAbsColWidth(
1497 (USHORT)((nColMax * nDistAbsTabWidth) / nDistMax) );
1498 pColumn->SetRelColWidth(
1499 (USHORT)((nColMax * nDistRelTabWidth) / nDistMax) );
1501 nAbs = nAbs + pColumn->GetAbsColWidth();
1502 nRel = nRel + pColumn->GetRelColWidth();
1505 ASSERT( nCols==nFixedCols, "Spalte vergessen!" );
1507 else
1509 // nein, dann den zu verteilenden Platz auf alle Spalten
1510 // gleichmaessig vertilen.
1511 for( USHORT i=0; i<nCols; i++ )
1513 ULONG nColMax = GetColumn( i )->GetMax();
1514 GetColumn( i )->SetAbsColWidth(
1515 (USHORT)((nColMax * nAbsTabWidth) / nMax) );
1516 GetColumn( i )->SetRelColWidth(
1517 (USHORT)((nColMax * nRelTabWidth) / nMax) );
1521 else
1523 // den ueber die Minimalbreite herausgehenden Platz entsprechend
1524 // den einzelnen Spalten anteilig zuschlagen
1525 if( !nAbsTabWidth )
1526 nAbsTabWidth = nAbsAvail;
1527 if( nAbsTabWidth < nMin )
1528 nAbsTabWidth = (USHORT)nMin;
1530 if( nAbsTabWidth > nAbsAvail )
1532 ASSERT( IsTopTable(),
1533 "Tabelle in Tabelle soll breiter werden als Platz da ist" );
1534 nAbsAvail = nAbsTabWidth;
1537 ULONG nAbsTabWidthL = nAbsTabWidth;
1538 nRelTabWidth =
1539 ( nRelAvail ? (USHORT)((nAbsTabWidthL * nRelAvail) / nAbsAvail)
1540 : nAbsTabWidth );
1541 double nW = nAbsTabWidth - nMin;
1542 double nD = (nMax==nMin ? 1 : nMax-nMin);
1543 USHORT nAbs = 0, nRel = 0;
1544 for( USHORT i=0; i<nCols-1; i++ )
1546 double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin();
1547 ULONG nAbsColWidth = GetColumn( i )->GetMin() + (ULONG)((nd*nW)/nD);
1548 ULONG nRelColWidth = nRelAvail
1549 ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth
1550 : nAbsColWidth;
1552 GetColumn( i )->SetAbsColWidth( (USHORT)nAbsColWidth );
1553 GetColumn( i )->SetRelColWidth( (USHORT)nRelColWidth );
1554 nAbs = nAbs + (USHORT)nAbsColWidth;
1555 nRel = nRel + (USHORT)nRelColWidth;
1557 GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs );
1558 GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel );
1562 // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts
1563 // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet.
1564 nInhAbsLeftSpace = 0;
1565 nInhAbsRightSpace = 0;
1566 if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 ||
1567 nAbsTabWidth<nAbsAvail) )
1569 // Die Breite von zusaetzlichen Zellen zur Ausrichtung der
1570 // inneren Tabelle bestimmen
1571 USHORT nAbsDist = (USHORT)(nAbsAvail-nAbsTabWidth);
1572 USHORT nRelDist = (USHORT)(nRelAvail-nRelTabWidth);
1573 USHORT nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0;
1575 // Groesse und Position der zusaetzlichen Zellen bestimmen
1576 switch( eTableAdjust )
1578 case SVX_ADJUST_RIGHT:
1579 nAbsLeftFill = nAbsLeftFill + nAbsDist;
1580 nRelLeftFill = nRelLeftFill + nRelDist;
1581 nParentInhAbsLeftSpace = nParentInhAbsSpace;
1582 break;
1583 case SVX_ADJUST_CENTER:
1585 USHORT nAbsLeftDist = nAbsDist / 2;
1586 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist;
1587 nAbsRightFill += nAbsDist - nAbsLeftDist;
1588 USHORT nRelLeftDist = nRelDist / 2;
1589 nRelLeftFill = nRelLeftFill + nRelLeftDist;
1590 nRelRightFill += nRelDist - nRelLeftDist;
1591 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2;
1592 nParentInhAbsRightSpace = nParentInhAbsSpace -
1593 nParentInhAbsLeftSpace;
1595 break;
1596 case SVX_ADJUST_LEFT:
1597 default:
1598 nAbsRightFill = nAbsRightFill + nAbsDist;
1599 nRelRightFill = nRelRightFill + nRelDist;
1600 nParentInhAbsRightSpace = nParentInhAbsSpace;
1601 break;
1604 ASSERT( !pLeftFillerBox || nRelLeftFill>0,
1605 "Fuer linke Filler-Box ist keine Breite da!" );
1606 ASSERT( !pRightFillerBox || nRelRightFill>0,
1607 "Fuer rechte Filler-Box ist keine Breite da!" );
1609 // Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn
1610 // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0)
1611 // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und
1612 // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir
1613 // die Tabelle wahrscheinlich selbst exportiert)
1614 if( nRelLeftFill && !pLeftFillerBox &&
1615 ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth ||
1616 (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) )
1617 // (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) )
1619 SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 );
1620 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill );
1621 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill );
1622 nRelLeftFill = 0;
1623 nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace;
1625 if( nRelRightFill && !pRightFillerBox &&
1626 ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth ||
1627 (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) )
1628 // (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) )
1630 SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 );
1631 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill );
1632 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill );
1633 nRelRightFill = 0;
1634 nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace;
1639 static BOOL lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara );
1641 static BOOL lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara )
1643 USHORT *pWidth = (USHORT *)pPara;
1645 if( !rpBox->GetSttNd() )
1647 USHORT nWidth = 0;
1648 ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth );
1649 rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1650 *pWidth = *pWidth + nWidth;
1652 else
1654 *pWidth = *pWidth + (USHORT)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width();
1657 return TRUE;
1660 static BOOL lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara )
1662 USHORT *pWidth = (USHORT *)pPara;
1663 #ifndef PRODUCT
1664 USHORT nOldWidth = *pWidth;
1665 #endif
1666 *pWidth = 0;
1667 ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth );
1669 #ifndef PRODUCT
1670 ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY,
1671 "Zeilen einer Box sind unterschiedlich lang" );
1672 #endif
1674 return TRUE;
1677 void SwHTMLTableLayout::SetWidths( BOOL bCallPass2, USHORT nAbsAvail,
1678 USHORT nRelAvail, USHORT nAbsLeftSpace,
1679 USHORT nAbsRightSpace,
1680 USHORT nParentInhAbsSpace )
1682 // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen
1683 // worden sein.
1684 nWidthSet++;
1686 // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus
1687 // aufgerufen.
1688 if( bCallPass2 )
1689 AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace,
1690 nParentInhAbsSpace );
1692 // Schritt 1: Setzten der neuen Breite an allen Content-Boxen.
1693 // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird
1694 // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen
1695 // in Tabellen wird rekursiv SetWidth aufgerufen.
1696 for( USHORT i=0; i<nRows; i++ )
1698 for( USHORT j=0; j<nCols; j++ )
1700 SwHTMLTableLayoutCell *pCell = GetCell( i, j );
1702 SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents();
1703 while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) )
1705 SwTableBox *pBox = pCntnts->GetTableBox();
1706 if( pBox )
1708 SetBoxWidth( pBox, j, pCell->GetColSpan() );
1710 else
1712 USHORT nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0,
1713 nInhSpace = 0;
1714 if( bCallPass2 )
1716 USHORT nColSpan = pCell->GetColSpan();
1717 GetAvail( j, nColSpan, nAbs, nRel );
1718 nLSpace = GetLeftCellSpace( j, nColSpan );
1719 nRSpace = GetRightCellSpace( j, nColSpan );
1720 nInhSpace = GetInhCellSpace( j, nColSpan );
1722 pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel,
1723 nLSpace, nRSpace,
1724 nInhSpace );
1727 pCntnts->SetWidthSet( nWidthSet );
1728 pCntnts = pCntnts->GetNext();
1733 // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate
1734 // der Nicht-Content-Boxen angepasst. Da diese aufgrund der
1735 // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen
1736 // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch
1737 // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden
1738 // stattdessen die Breiten der Filler-Zellen gesetzt.
1739 if( IsTopTable() )
1741 USHORT nCalcTabWidth = 0;
1742 ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine,
1743 &nCalcTabWidth );
1744 ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY,
1745 "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." );
1747 // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst
1748 // die Boxformate erneut angepasst werden. Ausserdem muss eine
1749 // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben.
1750 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt();
1751 ((SwTable *)pSwTable)->LockModify();
1752 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() );
1753 aFrmSize.SetWidth( nRelTabWidth );
1754 BOOL bRel = bUseRelWidth &&
1755 text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient();
1756 aFrmSize.SetWidthPercent( (BYTE)(bRel ? nWidthOption : 0) );
1757 pFrmFmt->SetFmtAttr( aFrmSize );
1758 ((SwTable *)pSwTable)->UnlockModify();
1760 // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen
1761 // breite angepasst werden.
1762 if( MayBeInFlyFrame() )
1764 SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt();
1765 if( pFlyFrmFmt )
1767 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY );
1769 if( bUseRelWidth )
1771 // Bei %-Angaben wird die Breite auf das Minimum gesetzt.
1772 aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX
1773 : nMin );
1774 aFlyFrmSize.SetWidthPercent( (BYTE)nWidthOption );
1776 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize );
1780 #ifndef PRODUCT
1782 // steht im tblrwcl.cxx
1783 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1785 // checke doch mal ob die Tabellen korrekte Breiten haben
1786 SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth();
1787 const SwTableLines& rLines = pSwTable->GetTabLines();
1788 for( USHORT n = 0; n < rLines.Count(); ++n )
1789 _CheckBoxWidth( *rLines[ n ], nSize );
1791 #endif
1794 else
1796 if( pLeftFillerBox )
1798 pLeftFillerBox->GetFrmFmt()->SetFmtAttr(
1799 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 ));
1801 if( pRightFillerBox )
1803 pRightFillerBox->GetFrmFmt()->SetFmtAttr(
1804 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 ));
1809 void SwHTMLTableLayout::_Resize( USHORT nAbsAvail, BOOL bRecalc )
1811 // Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas
1812 // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt
1813 // werden.
1814 if( bRecalc )
1815 AutoLayoutPass1();
1817 SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetRootFrm();
1818 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1819 pRoot->StartAllAction();
1821 // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils
1822 // noch der Pass 2 laufen muss.
1823 SetWidths( TRUE, nAbsAvail );
1825 if ( pRoot && pRoot->IsCallbackActionEnabled() )
1826 pRoot->EndAllAction( TRUE ); //True per VirDev (Browsen ruhiger)
1829 IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG )
1831 #ifdef TEST_DELAYED_RESIZE
1832 Sound::Beep( SOUND_WARNING );
1833 #endif
1834 pThis->aResizeTimer.Stop();
1835 pThis->_Resize( pThis->nDelayedResizeAbsAvail,
1836 pThis->bDelayedResizeRecalc );
1838 return 0;
1842 BOOL SwHTMLTableLayout::Resize( USHORT nAbsAvail, BOOL bRecalc,
1843 BOOL bForce, ULONG nDelay )
1845 if( 0 == nAbsAvail )
1846 return FALSE;
1847 ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" );
1849 // Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem?
1850 if( bMustNotResize && !bForce )
1851 return FALSE;
1853 // Darf ein Recalc der Tabelle durchgefuehrt werden?
1854 if( bMustNotRecalc && !bForce )
1855 bRecalc = FALSE;
1857 const SwDoc *pDoc = GetDoc();
1859 // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames
1860 // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen
1861 // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden,
1862 // weil sond die Umschaltung von relativ nach absolut nicht funktioniert.
1863 if( pDoc->GetRootFrm() && pDoc->get(IDocumentSettingAccess::BROWSE_MODE) )
1865 USHORT nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc );
1866 if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() )
1867 nAbsAvail = nVisAreaWidth;
1870 if( nDelay==0 && aResizeTimer.IsActive() )
1872 // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones
1873 // Resize aussteht, dann werden nur die neuen Werte uebernommen.
1875 bRecalc |= bDelayedResizeRecalc;
1876 nDelayedResizeAbsAvail = nAbsAvail;
1877 return FALSE;
1880 // Optimierung:
1881 // Wenn die Minima/Maxima nicht neu berechnet werden sollen und
1882 // - die Breite der Tabelle nie neu berechnet werden muss, oder
1883 // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder
1884 // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist
1885 // und die Tabelle bereits die Minimalbreite besitzt, oder
1886 // - der verfuegbare Platz groesser ist als die Maximalbreite und
1887 // die Tabelle bereits die Maximalbreite besitzt
1888 // wird sich an der Tabelle nichts aendern.
1889 if( !bRecalc && ( !bMustResize ||
1890 (nLastResizeAbsAvail==nAbsAvail) ||
1891 (nAbsAvail<=nMin && nRelTabWidth==nMin) ||
1892 (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) )
1893 return FALSE;
1895 if( nDelay==HTMLTABLE_RESIZE_NOW )
1897 if( aResizeTimer.IsActive() )
1898 aResizeTimer.Stop();
1899 _Resize( nAbsAvail, bRecalc );
1901 else if( nDelay > 0 )
1903 nDelayedResizeAbsAvail = nAbsAvail;
1904 bDelayedResizeRecalc = bRecalc;
1905 aResizeTimer.SetTimeout( nDelay );
1906 aResizeTimer.Start();
1907 #ifdef TEST_DELAYED_RESIZE
1908 Sound::Beep( SOUND_DEFAULT );
1909 #endif
1911 else
1913 _Resize( nAbsAvail, bRecalc );
1916 return TRUE;
1919 void SwHTMLTableLayout::BordersChanged( USHORT nAbsAvail, BOOL bRecalc )
1921 bBordersChanged = TRUE;
1923 Resize( nAbsAvail, bRecalc );