1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 #include "hintids.hxx" 31 32 //#define TEST_DELAYED_RESIZE 33 34 #ifdef TEST_DELAYED_RESIZE 35 #include <vcl/sound.hxx> 36 #endif 37 #include <vcl/wrkwin.hxx> 38 #include <vcl/svapp.hxx> 39 #include <sot/storage.hxx> 40 #include <fmtornt.hxx> 41 #include <fmtfsize.hxx> 42 #include <frmfmt.hxx> 43 #include <docary.hxx> 44 #include "ndtxt.hxx" 45 #include "doc.hxx" 46 #include "swtable.hxx" 47 #include "rootfrm.hxx" 48 #include "docsh.hxx" 49 #include "flyfrm.hxx" 50 #include "poolfmt.hxx" 51 #include "viewsh.hxx" 52 #include "tabfrm.hxx" 53 #include "viewopt.hxx" 54 #include "htmltbl.hxx" 55 #include "ndindex.hxx" 56 #include "switerator.hxx" 57 58 using namespace ::com::sun::star; 59 60 61 #define COLFUZZY 20 62 #define MAX_TABWIDTH (USHRT_MAX - 2001) 63 64 65 class SwHTMLTableLayoutConstraints 66 { 67 sal_uInt16 nRow; // Start-Zeile 68 sal_uInt16 nCol; // Start-Spalte 69 sal_uInt16 nColSpan; // COLSPAN der Zelle 70 71 SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung 72 73 sal_uLong nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1 74 75 public: 76 77 SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow, 78 sal_uInt16 nCol, sal_uInt16 nColSp ); 79 ~SwHTMLTableLayoutConstraints(); 80 81 sal_uLong GetMinNoAlign() const { return nMinNoAlign; } 82 sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; } 83 84 SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt ); 85 SwHTMLTableLayoutConstraints* GetNext() const { return pNext; } 86 87 sal_uInt16 GetRow() const { return nRow; } 88 89 sal_uInt16 GetColSpan() const { return nColSpan; } 90 sal_uInt16 GetColumn() const { return nCol; } 91 }; 92 93 /* */ 94 95 SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd, 96 SwHTMLTableLayout* pTab, 97 sal_Bool bNoBrTag, 98 SwHTMLTableLayoutCnts* pNxt ) : 99 pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ), 100 nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag ) 101 {} 102 103 SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts() 104 { 105 delete pNext; 106 delete pTable; 107 } 108 109 const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const 110 { 111 return pBox ? pBox->GetSttNd() : pStartNode; 112 } 113 114 115 /* */ 116 117 SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts, 118 sal_uInt16 nRSpan, sal_uInt16 nCSpan, 119 sal_uInt16 nWidth, sal_Bool bPrcWidth, 120 sal_Bool bNWrapOpt ) : 121 pContents( pCnts ), 122 nRowSpan( nRSpan ), nColSpan( nCSpan ), 123 nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ), 124 bNoWrapOption( bNWrapOpt ) 125 {} 126 127 SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell() 128 { 129 if( nRowSpan==1 && nColSpan==1 ) 130 { 131 delete pContents; 132 } 133 } 134 135 /* */ 136 137 SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth, 138 sal_Bool bRelWidth, 139 sal_Bool bLBorder ) : 140 nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY), 141 nMin(0), nMax(0), 142 nAbsColWidth(0), nRelColWidth(0), 143 nWidthOption( nWidth ), bRelWidthOption( bRelWidth ), 144 bLeftBorder( bLBorder ) 145 {} 146 147 148 /* */ 149 150 SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints( 151 sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ): 152 nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ), 153 pNext( 0 ), 154 nMinNoAlign( nMin ), nMaxNoAlign( nMax ) 155 {} 156 157 SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints() 158 { 159 delete pNext; 160 } 161 162 SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext( 163 SwHTMLTableLayoutConstraints *pNxt ) 164 { 165 SwHTMLTableLayoutConstraints *pPrev = 0; 166 SwHTMLTableLayoutConstraints *pConstr = this; 167 while( pConstr ) 168 { 169 if( pConstr->GetRow() > pNxt->GetRow() || 170 pConstr->GetColumn() > pNxt->GetColumn() ) 171 break; 172 pPrev = pConstr; 173 pConstr = pConstr->GetNext(); 174 } 175 176 if( pPrev ) 177 { 178 pNxt->pNext = pPrev->GetNext(); 179 pPrev->pNext = pNxt; 180 pConstr = this; 181 } 182 else 183 { 184 pNxt->pNext = this; 185 pConstr = pNxt; 186 } 187 188 return pConstr; 189 } 190 191 /* */ 192 193 typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr; 194 typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr; 195 196 SwHTMLTableLayout::SwHTMLTableLayout( 197 const SwTable * pSwTbl, 198 sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs, 199 sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt, 200 sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust, 201 sal_uInt16 nLMargin, sal_uInt16 nRMargin, 202 sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth, 203 sal_uInt16 nRightBWidth, 204 sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) : 205 aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ), 206 aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ), 207 pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ), 208 nMin( 0 ), nMax( 0 ), 209 nRows( nRws ), nCols( nCls ), 210 nLeftMargin( nLMargin ), nRightMargin( nRMargin ), 211 nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ), 212 nRelLeftFill( 0 ), nRelRightFill( 0 ), 213 nRelTabWidth( 0 ), nWidthOption( nWdth ), 214 nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ), 215 nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ), 216 nInhLeftBorderWidth( nInhLeftBWidth ), 217 nInhRightBorderWidth( nInhRightBWidth ), 218 nBorderWidth( nBWidth ), 219 nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ), 220 nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ), 221 bColsOption( bColsOpt ), bColTags( bColTgs ), 222 bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ), 223 bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ), 224 bMustNotResize( sal_False ), bMustNotRecalc( sal_False ) 225 { 226 aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout, 227 DelayedResize_Impl ) ); 228 } 229 230 SwHTMLTableLayout::~SwHTMLTableLayout() 231 { 232 sal_uInt16 i; 233 234 for( i = 0; i < nCols; i++ ) 235 delete aColumns[i]; 236 delete[] aColumns; 237 238 sal_uInt16 nCount = nRows*nCols; 239 for( i=0; i<nCount; i++ ) 240 delete aCells[i]; 241 delete[] aCells; 242 } 243 244 // Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet: 245 // Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING 246 // Innere Umrandung: CELLSPACING + CELLPADDING 247 // Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn 248 // bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird. 249 // MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden, 250 // und zwar auch dann, wenn wenn nur die gegenueberliegende Seite 251 // eine Umrandung hat. 252 sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, 253 sal_Bool bSwBorders ) const 254 { 255 sal_uInt16 nSpace = nCellSpacing + nCellPadding; 256 257 if( nCol == 0 ) 258 { 259 nSpace = nSpace + nBorder; 260 261 if( bSwBorders && nSpace < nLeftBorderWidth ) 262 nSpace = nLeftBorderWidth; 263 } 264 else if( bSwBorders ) 265 { 266 if( GetColumn(nCol)->HasLeftBorder() ) 267 { 268 if( nSpace < nBorderWidth ) 269 nSpace = nBorderWidth; 270 } 271 else if( nCol+nColSpan == nCols && nRightBorderWidth && 272 nSpace < MIN_BORDER_DIST ) 273 { 274 ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" ); 275 // Wenn die Gegenueberliegende Seite umrandet ist muessen 276 // wir zumindest den minimalen Abstand zum Inhalt 277 // beruecksichtigen. (Koennte man zusaetzlich auch an 278 // nCellPadding festmachen.) 279 nSpace = MIN_BORDER_DIST; 280 } 281 } 282 283 return nSpace; 284 } 285 286 sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, 287 sal_Bool bSwBorders ) const 288 { 289 sal_uInt16 nSpace = nCellPadding; 290 291 if( nCol+nColSpan == nCols ) 292 { 293 nSpace += nBorder + nCellSpacing; 294 if( bSwBorders && nSpace < nRightBorderWidth ) 295 nSpace = nRightBorderWidth; 296 } 297 else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() && 298 nSpace < MIN_BORDER_DIST ) 299 { 300 ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" ); 301 // Wenn die Gegenueberliegende Seite umrandet ist muessen 302 // wir zumindest den minimalen Abstand zum Inhalt 303 // beruecksichtigen. (Koennte man zusaetzlich auch an 304 // nCellPadding festmachen.) 305 nSpace = MIN_BORDER_DIST; 306 } 307 308 return nSpace; 309 } 310 311 void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax, 312 sal_uLong &rAbsMin, 313 sal_uInt16 nCol, sal_uInt16 nColSpan, 314 sal_Bool bSwBorders ) const 315 { 316 sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) + 317 GetRightCellSpace( nCol, nColSpan, bSwBorders ); 318 319 rMin += nAdd; 320 rMax += nAdd; 321 rAbsMin += nAdd; 322 } 323 324 void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol, 325 sal_uInt16 nColSpan ) const 326 { 327 SwFrmFmt *pFrmFmt = pBox->GetFrmFmt(); 328 329 // die Breite der Box berechnen 330 SwTwips nFrmWidth = 0; 331 while( nColSpan-- ) 332 nFrmWidth += GetColumn( nCol++ )->GetRelColWidth(); 333 334 // und neu setzen 335 336 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 )); 337 } 338 339 void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan, 340 sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const 341 { 342 rAbsAvail = 0; 343 rRelAvail = 0; 344 for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ ) 345 { 346 const SwHTMLTableLayoutColumn *pColumn = GetColumn(i); 347 rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth(); 348 rRelAvail = rRelAvail + pColumn->GetRelColWidth(); 349 } 350 } 351 352 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc ) 353 { 354 ViewShell *pVSh = 0; 355 rDoc.GetEditShell( &pVSh ); 356 if( pVSh ) 357 { 358 return (sal_uInt16)pVSh->GetBrowseWidth(); 359 } 360 361 return 0; 362 } 363 364 sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc ) 365 { 366 // Wenn ein Layout da ist, koennen wir die Breite dort herholen. 367 const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); //swmod 080218 368 if( pRootFrm ) 369 { 370 const SwFrm *pPageFrm = pRootFrm->GetLower(); 371 if( pPageFrm ) 372 return (sal_uInt16)pPageFrm->Prt().Width(); 373 } 374 375 // --> OD 2010-05-12 #i91658# 376 // Assertion removed which state that no browse width is available. 377 // Investigation reveals that all calls can handle the case that no browse 378 // width is provided. 379 return GetBrowseWidthByVisArea( rDoc ); 380 // <-- 381 } 382 383 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm( 384 const SwTabFrm& rTabFrm ) const 385 { 386 SwTwips nWidth = 0; 387 388 const SwFrm *pUpper = rTabFrm.GetUpper(); 389 if( MayBeInFlyFrame() && pUpper->IsFlyFrm() && 390 ((const SwFlyFrm *)pUpper)->GetAnchorFrm() ) 391 { 392 // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist 393 // die Breite Ankers und nicht die Breite Rahmens von Bedeutung. 394 // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet. 395 const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm(); 396 if( pAnchor->IsTxtFrm() ) 397 nWidth = pAnchor->Frm().Width(); 398 else 399 nWidth = pAnchor->Prt().Width(); 400 } 401 else 402 { 403 nWidth = pUpper->Prt().Width(); 404 } 405 406 SwTwips nUpperDummy = 0; 407 long nRightOffset = 0, 408 nLeftOffset = 0; 409 rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset ); 410 nWidth -= (nLeftOffset + nRightOffset); 411 412 return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX; 413 } 414 415 sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const 416 { 417 sal_uInt16 nBrowseWidth = 0; 418 SwTabFrm* pFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *pSwTable->GetFrmFmt() ); 419 if( pFrm ) 420 { 421 nBrowseWidth = GetBrowseWidthByTabFrm( *pFrm ); 422 } 423 else 424 { 425 nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc ); 426 } 427 428 return nBrowseWidth; 429 } 430 431 const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const 432 { 433 const SwStartNode *pBoxSttNd; 434 435 const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0]; 436 while( 0 == (pBoxSttNd = pBox->GetSttNd()) ) 437 { 438 ASSERT( pBox->GetTabLines().Count() > 0, 439 "Box ohne Start-Node und Lines" ); 440 ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0, 441 "Line ohne Boxen" ); 442 pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; 443 } 444 445 return pBoxSttNd; 446 } 447 448 SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const 449 { 450 const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode(); 451 ASSERT( pTblNd, "Kein Table-Node?" ); 452 return pTblNd->GetFlyFmt(); 453 } 454 455 static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts, 456 sal_uLong& rAbsMinNoAlignCnts, 457 #ifdef FIX41370 458 sal_Bool& rHR, 459 #endif 460 SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak ) 461 { 462 pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts, 463 rAbsMinNoAlignCnts ); 464 ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts, 465 "GetMinMaxSize: absmin > min" ); 466 ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts, 467 "GetMinMaxSize: max > min" ); 468 469 //Bei einen <PRE>-Absatz entspricht die maximale Breite der 470 // minimalen breite 471 const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl(); 472 while( pColl && !pColl->IsDefault() && 473 (USER_FMT & pColl->GetPoolFmtId()) ) 474 { 475 pColl = (const SwFmtColl *)pColl->DerivedFrom(); 476 } 477 478 // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht 479 // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken. 480 if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak ) 481 { 482 rMinNoAlignCnts = rMaxNoAlignCnts; 483 rAbsMinNoAlignCnts = rMaxNoAlignCnts; 484 } 485 #ifdef FIX41370 486 else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() ) 487 { 488 rHR |= !pTxtNd->HasSwAttrSet() || 489 SFX_ITEM_SET != pTxtNd->GetpSwAttrSet() 490 ->GetItemState( RES_LR_SPACE, sal_False ); 491 } 492 #endif 493 } 494 495 void SwHTMLTableLayout::AutoLayoutPass1() 496 { 497 nPass1Done++; 498 499 ClearPass1Info(); 500 501 sal_Bool bFixRelWidths = sal_False; 502 sal_uInt16 i; 503 504 SwHTMLTableLayoutConstraints *pConstraints = 0; 505 506 for( i=0; i<nCols; i++ ) 507 { 508 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 509 pColumn->ClearPass1Info( !HasColTags() ); 510 sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir 511 // berechnete Breite bezieht 512 sal_uInt16 nColSkip = USHRT_MAX; // Wie viele Spalten muessen 513 // uebersprungen werden 514 515 for( sal_uInt16 j=0; j<nRows; j++ ) 516 { 517 SwHTMLTableLayoutCell *pCell = GetCell(j,i); 518 SwHTMLTableLayoutCnts *pCnts = pCell->GetContents(); 519 520 // fix #31488#: Zum Ermitteln der naechsten zu berechnenden 521 // Spalte muessen alle Zeilen herangezogen werden 522 sal_uInt16 nColSpan = pCell->GetColSpan(); 523 if( nColSpan < nColSkip ) 524 nColSkip = nColSpan; 525 526 if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) ) 527 { 528 // die Zelle ist leer oder ihr Inhalt wurde nich nicht 529 // bearbeitet 530 if( nColSpan < nMinColSpan ) 531 nMinColSpan = nColSpan; 532 533 sal_uLong nMinNoAlignCell = 0; 534 sal_uLong nMaxNoAlignCell = 0; 535 sal_uLong nAbsMinNoAlignCell = 0; 536 sal_uLong nMaxTableCell = 0; 537 sal_uLong nAbsMinTableCell = 0; 538 #ifdef FIX41370 539 sal_Bool bHR = sal_False; 540 #endif 541 542 while( pCnts ) 543 { 544 const SwStartNode *pSttNd = pCnts->GetStartNode(); 545 if( pSttNd ) 546 { 547 const SwDoc *pDoc = pSttNd->GetDoc(); 548 sal_uLong nIdx = pSttNd->GetIndex(); 549 while( !(pDoc->GetNodes()[nIdx])->IsEndNode() ) 550 { 551 SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode(); 552 if( pTxtNd ) 553 { 554 sal_uLong nMinNoAlignCnts = 0; 555 sal_uLong nMaxNoAlignCnts = 0; 556 sal_uLong nAbsMinNoAlignCnts = 0; 557 558 lcl_GetMinMaxSize( nMinNoAlignCnts, 559 nMaxNoAlignCnts, 560 nAbsMinNoAlignCnts, 561 #ifdef FIX41370 562 bHR, 563 #endif 564 pTxtNd, nIdx, 565 pCnts->HasNoBreakTag() ); 566 567 if( nMinNoAlignCnts > nMinNoAlignCell ) 568 nMinNoAlignCell = nMinNoAlignCnts; 569 if( nMaxNoAlignCnts > nMaxNoAlignCell ) 570 nMaxNoAlignCell = nMaxNoAlignCnts; 571 if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell ) 572 nAbsMinNoAlignCell = nAbsMinNoAlignCnts; 573 } 574 else 575 { 576 SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode(); 577 if( pTabNd ) 578 { 579 SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout(); 580 if( pChild ) 581 { 582 pChild->AutoLayoutPass1(); 583 sal_uLong nMaxTableCnts = pChild->nMax; 584 sal_uLong nAbsMinTableCnts = pChild->nMin; 585 586 // Eine feste Tabellen-Breite wird als Minimum 587 // und Maximum gleichzeitig uebernommen 588 if( !pChild->bPrcWidthOption && pChild->nWidthOption ) 589 { 590 sal_uLong nTabWidth = pChild->nWidthOption; 591 if( nTabWidth >= nAbsMinTableCnts ) 592 { 593 nMaxTableCnts = nTabWidth; 594 nAbsMinTableCnts = nTabWidth; 595 } 596 else 597 { 598 nMaxTableCnts = nAbsMinTableCnts; 599 } 600 } 601 602 if( nMaxTableCnts > nMaxTableCell ) 603 nMaxTableCell = nMaxTableCnts; 604 if( nAbsMinTableCnts > nAbsMinTableCell ) 605 nAbsMinTableCell = nAbsMinTableCnts; 606 } 607 nIdx = pTabNd->EndOfSectionNode()->GetIndex(); 608 } 609 } 610 nIdx++; 611 } 612 } 613 else 614 { 615 ASSERT( !this, "Sub tables in HTML import?" ) 616 SwHTMLTableLayout *pChild = pCnts->GetTable(); 617 pChild->AutoLayoutPass1(); 618 sal_uLong nMaxTableCnts = pChild->nMax; 619 sal_uLong nAbsMinTableCnts = pChild->nMin; 620 621 // Eine feste Tabellen-Breite wird als Minimum 622 // und Maximum gleichzeitig uebernommen 623 if( !pChild->bPrcWidthOption && pChild->nWidthOption ) 624 { 625 sal_uLong nTabWidth = pChild->nWidthOption; 626 if( nTabWidth >= nAbsMinTableCnts ) 627 { 628 nMaxTableCnts = nTabWidth; 629 nAbsMinTableCnts = nTabWidth; 630 } 631 else 632 { 633 nMaxTableCnts = nAbsMinTableCnts; 634 } 635 } 636 637 if( nMaxTableCnts > nMaxTableCell ) 638 nMaxTableCell = nMaxTableCnts; 639 if( nAbsMinTableCnts > nAbsMinTableCell ) 640 nAbsMinTableCell = nAbsMinTableCnts; 641 } 642 pCnts->SetPass1Done( nPass1Done ); 643 pCnts = pCnts->GetNext(); 644 } 645 646 // War frueher hinter AddBorderWidth 647 // Wenn die Breite einer Tabelle in der Zelle breiter ist als 648 // das, was wir fuer sonstigen Inhalt berechnet haben, mussen 649 // wir die Breite der Tabelle nutzen 650 if( nMaxTableCell > nMaxNoAlignCell ) 651 nMaxNoAlignCell = nMaxTableCell; 652 if( nAbsMinTableCell > nAbsMinNoAlignCell ) 653 { 654 nAbsMinNoAlignCell = nAbsMinTableCell; 655 if( nMinNoAlignCell < nAbsMinNoAlignCell ) 656 nMinNoAlignCell = nAbsMinNoAlignCell; 657 if( nMaxNoAlignCell < nMinNoAlignCell ) 658 nMaxNoAlignCell = nMinNoAlignCell; 659 } 660 // War frueher hinter AddBorderWidth 661 662 sal_Bool bRelWidth = pCell->IsPrcWidthOption(); 663 sal_uInt16 nWidth = pCell->GetWidthOption(); 664 665 // Eine NOWRAP-Option bezieht sich auf Text und auf 666 // Tabellen, wird aber bei fester Zellenbreite 667 // nicht uebernommen. Stattdessen wirkt die angegebene 668 // Zellenbreite wie eine Mindestbreite. 669 if( pCell->HasNoWrapOption() ) 670 { 671 if( nWidth==0 || bRelWidth ) 672 { 673 nMinNoAlignCell = nMaxNoAlignCell; 674 nAbsMinNoAlignCell = nMaxNoAlignCell; 675 } 676 else 677 { 678 if( nWidth>nMinNoAlignCell ) 679 nMinNoAlignCell = nWidth; 680 if( nWidth>nAbsMinNoAlignCell ) 681 nAbsMinNoAlignCell = nWidth; 682 } 683 } 684 #ifdef FIX41370 685 else if( bHR && nWidth>0 && !bRelWidth ) 686 { 687 // Ein kleiner Hack, um einen Bug in Netscape 4.0 688 // nachzubilden (siehe #41370#). Wenn eine Zelle eine 689 // fixe Breite besitzt und gleichzeitig ein HR, wird 690 // sie nie schmaler als die angegebene Breite. 691 // (Genaugenomen scheint die Zelle nie schmaler zu werden 692 // als die HR-Linie, denn wenn man fuer die Linie eine 693 // Breite angibt, die breiter ist als die der Zelle, dann 694 // wird die Zelle so breit wie die Linie. Das bekommen wir 695 // natuerlich nicht hin.) 696 if( nWidth>nMinNoAlignCell ) 697 nMinNoAlignCell = nWidth; 698 if( nWidth>nAbsMinNoAlignCell ) 699 nAbsMinNoAlignCell = nWidth; 700 } 701 #endif 702 703 // Mindestbreite fuer Inhalt einhalten 704 if( nMinNoAlignCell < MINLAY ) 705 nMinNoAlignCell = MINLAY; 706 if( nMaxNoAlignCell < MINLAY ) 707 nMaxNoAlignCell = MINLAY; 708 if( nAbsMinNoAlignCell < MINLAY ) 709 nAbsMinNoAlignCell = MINLAY; 710 711 // Umrandung und Abstand zum Inhalt beachten. 712 AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell, 713 nAbsMinNoAlignCell, i, nColSpan ); 714 715 if( 1==nColSpan ) 716 { 717 // die Werte direkt uebernehmen 718 pColumn->MergeMinMaxNoAlign( nMinNoAlignCell, 719 nMaxNoAlignCell, 720 nAbsMinNoAlignCell ); 721 722 // bei den WIDTH angaben gewinnt die breiteste 723 if( !HasColTags() ) 724 pColumn->MergeCellWidthOption( nWidth, bRelWidth ); 725 } 726 else 727 { 728 // die Angaben erst am Ende, und zwar zeilenweise von 729 // links nach rechts bearbeiten 730 731 // Wann welche Werte wie uebernommen werden ist weiter 732 // unten erklaert. 733 if( !HasColTags() && nWidth && !bRelWidth ) 734 { 735 sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0; 736 AddBorderWidth( nAbsWidth, nDummy, nDummy2, 737 i, nColSpan, sal_False ); 738 739 if( nAbsWidth >= nMinNoAlignCell ) 740 { 741 nMaxNoAlignCell = nAbsWidth; 742 if( HasColsOption() ) 743 nMinNoAlignCell = nAbsWidth; 744 } 745 else if( nAbsWidth >= nAbsMinNoAlignCell ) 746 { 747 nMaxNoAlignCell = nAbsWidth; 748 nMinNoAlignCell = nAbsWidth; 749 } 750 else 751 { 752 nMaxNoAlignCell = nAbsMinNoAlignCell; 753 nMinNoAlignCell = nAbsMinNoAlignCell; 754 } 755 } 756 else if( HasColsOption() || HasColTags() ) 757 nMinNoAlignCell = nAbsMinNoAlignCell; 758 759 SwHTMLTableLayoutConstraints *pConstr = 760 new SwHTMLTableLayoutConstraints( nMinNoAlignCell, 761 nMaxNoAlignCell, j, i, nColSpan ); 762 if( pConstraints ) 763 pConstraints = pConstraints->InsertNext( pConstr ); 764 else 765 pConstraints = pConstr; 766 } 767 } 768 } 769 770 ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan, 771 "Layout Pass 1: Da werden Spalten vergessen!" ); 772 ASSERT( nMinColSpan!=USHRT_MAX, 773 "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" ); 774 775 if( 1==nMinColSpan ) 776 { 777 // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle 778 // Werte in pColumn 779 780 // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen: 781 // 782 // WIDTH: kein COLS COLS 783 // 784 // keine min = min min = absmin 785 // max = max max = max 786 // 787 // >= min min = min min = width 788 // max = width max = width 789 // 790 // >= absmin min = wdith(*) min = width 791 // max = width max = width 792 // 793 // < absmin min = absmin min = absmin 794 // max = absmin max = absmin 795 // 796 // (*) Netscape benutzt hier die Mindestbreite ohne einen 797 // Umbruch vor der letzten Grafik. Haben wir (noch?) nicht, 798 // also belassen wir es bei width.^ 799 800 if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() ) 801 { 802 // absolute Breiten als Minimal- und Maximalbreite 803 // uebernehmen. 804 sal_uLong nAbsWidth = pColumn->GetWidthOption(); 805 sal_uLong nDummy = 0, nDummy2 = 0; 806 AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False ); 807 808 if( nAbsWidth >= pColumn->GetMinNoAlign() ) 809 { 810 pColumn->SetMinMax( HasColsOption() ? nAbsWidth 811 : pColumn->GetMinNoAlign(), 812 nAbsWidth ); 813 } 814 else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() ) 815 { 816 pColumn->SetMinMax( nAbsWidth, nAbsWidth ); 817 } 818 else 819 { 820 pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(), 821 pColumn->GetAbsMinNoAlign() ); 822 } 823 } 824 else 825 { 826 pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign() 827 : pColumn->GetMinNoAlign(), 828 pColumn->GetMaxNoAlign() ); 829 } 830 } 831 else if( USHRT_MAX!=nMinColSpan ) 832 { 833 // kann irgendwas !=0 sein, weil es durch die Constraints 834 // angepasst wird. 835 pColumn->SetMinMax( MINLAY, MINLAY ); 836 837 // die naechsten Spalten muessen nicht bearbeitet werden 838 i += (nColSkip-1); 839 } 840 841 nMin += pColumn->GetMin(); 842 nMax += pColumn->GetMax(); 843 bFixRelWidths |= pColumn->IsRelWidthOption(); 844 } 845 846 // jetzt noch die Constrains verarbeiten 847 SwHTMLTableLayoutConstraints *pConstr = pConstraints; 848 while( pConstr ) 849 { 850 // Erstmal muss die Breite analog zu den den Spaltenbreiten 851 // aufbereitet werden 852 sal_uInt16 nCol = pConstr->GetColumn(); 853 sal_uInt16 nColSpan = pConstr->GetColSpan(); 854 sal_uLong nConstrMin = pConstr->GetMinNoAlign(); 855 sal_uLong nConstrMax = pConstr->GetMaxNoAlign(); 856 857 // jetzt holen wir uns die bisherige Breite der ueberspannten 858 // Spalten 859 sal_uLong nColsMin = 0; 860 sal_uLong nColsMax = 0; 861 for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ ) 862 { 863 SwHTMLTableLayoutColumn *pColumn = GetColumn( j ); 864 nColsMin += pColumn->GetMin(); 865 nColsMax += pColumn->GetMax(); 866 } 867 868 if( nColsMin<nConstrMin ) 869 { 870 // den Minimalwert anteilig auf die Spalten verteilen 871 sal_uLong nMinD = nConstrMin-nColsMin; 872 873 if( nConstrMin > nColsMax ) 874 { 875 // Anteilig anhand der Mindestbreiten 876 sal_uInt16 nEndCol = nCol+nColSpan; 877 sal_uLong nDiff = nMinD; 878 for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ ) 879 { 880 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); 881 882 sal_uLong nColMin = pColumn->GetMin(); 883 sal_uLong nColMax = pColumn->GetMax(); 884 885 nMin -= nColMin; 886 sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin 887 : nDiff; 888 nColMin += nAdd; 889 nMin += nColMin; 890 ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" ); 891 nDiff -= nAdd; 892 893 if( nColMax < nColMin ) 894 { 895 nMax -= nColMax; 896 nColsMax -= nColMax; 897 nColMax = nColMin; 898 nMax += nColMax; 899 nColsMax += nColMax; 900 } 901 902 pColumn->SetMinMax( nColMin, nColMax ); 903 } 904 } 905 else 906 { 907 // Anteilig anhand der Differenz zwischen Max und Min 908 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ ) 909 { 910 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); 911 912 sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin(); 913 if( nMinD < nDiff ) 914 nDiff = nMinD; 915 916 pColumn->AddToMin( nDiff ); 917 918 ASSERT( pColumn->GetMax() >= pColumn->GetMin(), 919 "Wieso ist die SPalte auf einmal zu schmal?" ) 920 921 nMin += nDiff; 922 nMinD -= nDiff; 923 } 924 } 925 } 926 927 if( !HasColTags() && nColsMax<nConstrMax ) 928 { 929 sal_uLong nMaxD = nConstrMax-nColsMax; 930 931 for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ ) 932 { 933 SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); 934 935 nMax -= pColumn->GetMax(); 936 937 pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax ); 938 939 nMax += pColumn->GetMax(); 940 } 941 } 942 943 pConstr = pConstr->GetNext(); 944 } 945 946 947 if( bFixRelWidths ) 948 { 949 if( HasColTags() ) 950 { 951 // Zum Anpassen der relativen Breiten werden im 1. Schritt die 952 // Minmalbreiten aller anzupassenden Zellen jeweils mit der 953 // relativen Breite einer Spalte multipliziert. Dadurch stimmen 954 // dann die Breitenverhaeltnisse der Spalten untereinander. 955 // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch 956 // breiter gworden ist als die Minmalbreite. 957 // Im 2. Schritt werden dann die berechneten Breiten durch diesen 958 // Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle 959 // erhalten und dient als Ausgangsbasis fuer die andern Breiten. 960 // Es werden auch hier nur die Maximalbreiten beeinflusst! 961 962 sal_uLong nAbsMin = 0; // absolte Min-Breite alter Spalten mit 963 // relativer Breite 964 sal_uLong nRel = 0; // Summe der relativen Breiten aller Spalten 965 for( i=0; i<nCols; i++ ) 966 { 967 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 968 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) 969 { 970 nAbsMin += pColumn->GetMin(); 971 nRel += pColumn->GetWidthOption(); 972 } 973 } 974 975 sal_uLong nQuot = ULONG_MAX; 976 for( i=0; i<nCols; i++ ) 977 { 978 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 979 if( pColumn->IsRelWidthOption() ) 980 { 981 nMax -= pColumn->GetMax(); 982 if( pColumn->GetWidthOption() && pColumn->GetMin() ) 983 { 984 pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() ); 985 sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin(); 986 if( nColQuot<nQuot ) 987 nQuot = nColQuot; 988 } 989 } 990 } 991 ASSERT( 0==nRel || nQuot!=ULONG_MAX, 992 "Wo sind die relativen Spalten geblieben?" ); 993 for( i=0; i<nCols; i++ ) 994 { 995 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 996 if( pColumn->IsRelWidthOption() ) 997 { 998 if( pColumn->GetWidthOption() ) 999 pColumn->SetMax( pColumn->GetMax() / nQuot ); 1000 else 1001 pColumn->SetMax( pColumn->GetMin() ); 1002 ASSERT( pColumn->GetMax() >= pColumn->GetMin(), 1003 "Maximale Spaltenbreite kleiner als Minimale" ); 1004 nMax += pColumn->GetMax(); 1005 } 1006 } 1007 } 1008 else 1009 { 1010 sal_uInt16 nRel = 0; // Summe der relativen Breiten aller Spalten 1011 sal_uInt16 nRelCols = 0; // Anzahl Spalten mit relativer Angabe 1012 sal_uLong nRelMax = 0; // Anteil am Maximum dieser Spalten 1013 for( i=0; i<nCols; i++ ) 1014 { 1015 ASSERT( nRel<=100, "relative Breite aller Spalten>100%" ); 1016 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1017 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) 1018 { 1019 // Sicherstellen, dass die relativen breiten nicht 1020 // ueber 100% landen 1021 sal_uInt16 nColWidth = pColumn->GetWidthOption(); 1022 if( nRel+nColWidth > 100 ) 1023 { 1024 nColWidth = 100 - nRel; 1025 pColumn->SetWidthOption( nColWidth, sal_True, sal_False ); 1026 } 1027 nRelMax += pColumn->GetMax(); 1028 nRel = nRel + nColWidth; 1029 nRelCols++; 1030 } 1031 else if( !pColumn->GetMin() ) 1032 { 1033 // Die Spalte ist leer (wurde also auschliesslich 1034 // durch COLSPAN erzeugt) und darf deshalb auch 1035 // keine %-Breite zugewiesen bekommen. 1036 nRelCols++; 1037 } 1038 } 1039 1040 // Eventuell noch vorhandene Prozente werden auf die Spalten ohne 1041 // eine Breiten-Angabe verteilt. Wie in Netscape werden die 1042 // verbleibenden Prozente enstprechend der Verhaeltnisse 1043 // der Maximalbreiten der in Frage kommenden Spalten 1044 // untereinander verteilt. 1045 // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten 1046 // mit fester Breite. Ist das richtig??? 1047 if( nRel < 100 && nRelCols < nCols ) 1048 { 1049 sal_uInt16 nRelLeft = 100 - nRel; 1050 sal_uLong nFixMax = nMax - nRelMax; 1051 for( i=0; i<nCols; i++ ) 1052 { 1053 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1054 if( !pColumn->IsRelWidthOption() && 1055 !pColumn->GetWidthOption() && 1056 pColumn->GetMin() ) 1057 { 1058 // den Rest bekommt die naechste Spalte 1059 sal_uInt16 nColWidth = 1060 (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax); 1061 pColumn->SetWidthOption( nColWidth, sal_True, sal_False ); 1062 } 1063 } 1064 } 1065 1066 // nun die Maximalbreiten entsprechend anpassen 1067 sal_uLong nQuotMax = ULONG_MAX; 1068 sal_uLong nOldMax = nMax; 1069 nMax = 0; 1070 for( i=0; i<nCols; i++ ) 1071 { 1072 // Spalten mit %-Angaben werden enstprechend angepasst. 1073 // Spalten, die 1074 // - keine %-Angabe besitzen und in einer Tabelle mit COLS 1075 // oder WIDTH vorkommen, oder 1076 // - als Breite 0% angegeben haben erhalten die Minimalbreite 1077 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1078 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) 1079 { 1080 sal_uLong nNewMax; 1081 sal_uLong nColQuotMax; 1082 if( !nWidthOption ) 1083 { 1084 nNewMax = nOldMax * pColumn->GetWidthOption(); 1085 nColQuotMax = nNewMax / pColumn->GetMax(); 1086 } 1087 else 1088 { 1089 nNewMax = nMin * pColumn->GetWidthOption(); 1090 nColQuotMax = nNewMax / pColumn->GetMin(); 1091 } 1092 pColumn->SetMax( nNewMax ); 1093 if( nColQuotMax < nQuotMax ) 1094 nQuotMax = nColQuotMax; 1095 } 1096 else if( HasColsOption() || nWidthOption || 1097 (pColumn->IsRelWidthOption() && 1098 !pColumn->GetWidthOption()) ) 1099 pColumn->SetMax( pColumn->GetMin() ); 1100 } 1101 // und durch den Quotienten teilen 1102 ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" ); 1103 for( i=0; i<nCols; i++ ) 1104 { 1105 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1106 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) 1107 { 1108 if( pColumn->GetWidthOption() ) 1109 { 1110 pColumn->SetMax( pColumn->GetMax() / nQuotMax ); 1111 ASSERT( pColumn->GetMax() >= pColumn->GetMin(), 1112 "Minimalbreite ein Spalte Groesser Maximum" ); 1113 if( pColumn->GetMax() < pColumn->GetMin() ) 1114 pColumn->SetMax( pColumn->GetMin() ); 1115 } 1116 } 1117 nMax += pColumn->GetMax(); 1118 } 1119 } 1120 } 1121 1122 delete pConstraints; 1123 } 1124 1125 // nAbsAvail ist der verfuegbare Platz in TWIPS. 1126 // nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0 1127 // nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle 1128 // fur die Umrandung und den Abstand zum Inhalt reserviert ist. 1129 void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail, 1130 sal_uInt16 nAbsLeftSpace, 1131 sal_uInt16 nAbsRightSpace, 1132 sal_uInt16 nParentInhAbsSpace ) 1133 { 1134 // Erstmal fuehren wie jede Menge Plausibilaets-Test durch 1135 1136 // Eine abolute zur Verfuegung stehende Breite muss immer uebergeben 1137 // werden. 1138 ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" ); 1139 1140 // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer 1141 // Tabellen in Tabellen uebergeben 1142 ASSERT( IsTopTable() == (nRelAvail==0), 1143 "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" ); 1144 1145 // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein 1146 // als das die Maximalbreite. 1147 ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" ); 1148 1149 // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken. 1150 // (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung 1151 // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.) 1152 nLastResizeAbsAvail = nAbsAvail; 1153 1154 // Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender, 1155 // vorhandene Filler-Zellen und Abstande angepasst 1156 1157 // Abstand zum Inhalt und Unrandung 1158 sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0; 1159 if( !IsTopTable() && 1160 GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail ) 1161 { 1162 nAbsLeftFill = nAbsLeftSpace; 1163 nAbsRightFill = nAbsRightSpace; 1164 } 1165 1166 // Linker und rechter Abstand 1167 if( nLeftMargin || nRightMargin ) 1168 { 1169 if( IsTopTable() ) 1170 { 1171 // fuer die Top-Table beruecksichtigen wir die Raender immer, 1172 // den die Minimalbreite der Tabelle wird hier nie unterschritten 1173 nAbsAvail -= (nLeftMargin + nRightMargin); 1174 } 1175 else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail ) 1176 { 1177 // sonst beruecksichtigen wir die Raender nur, wenn auch Platz 1178 // fuer sie da ist (nMin ist hier bereits berechnet!) 1179 nAbsLeftFill = nAbsLeftFill + nLeftMargin; 1180 nAbsRightFill = nAbsRightFill + nRightMargin; 1181 } 1182 } 1183 1184 // Filler-Zellen 1185 if( !IsTopTable() ) 1186 { 1187 if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth ) 1188 nAbsLeftFill = MINLAY+nInhLeftBorderWidth; 1189 if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth ) 1190 nAbsRightFill = MINLAY+nInhRightBorderWidth; 1191 } 1192 1193 // Anpassen des verfuegbaren Platzes. 1194 nRelLeftFill = 0; 1195 nRelRightFill = 0; 1196 if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) ) 1197 { 1198 sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill; 1199 1200 nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail); 1201 nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail); 1202 1203 nAbsAvail -= (nAbsLeftFill + nAbsRightFill); 1204 if( nRelAvail ) 1205 nRelAvail -= (nRelLeftFill + nRelRightFill); 1206 } 1207 1208 1209 // Schritt 2: Die absolute Tabellenbreite wird berechnet. 1210 sal_uInt16 nAbsTabWidth = 0; 1211 bUseRelWidth = sal_False; 1212 if( nWidthOption ) 1213 { 1214 if( bPrcWidthOption ) 1215 { 1216 ASSERT( nWidthOption<=100, "Prozentangabe zu gross" ); 1217 if( nWidthOption > 100 ) 1218 nWidthOption = 100; 1219 1220 // Die absolute Breite entspricht den angegeben Prozent der 1221 // zur Verfuegung stehenden Breite. 1222 // Top-Tabellen bekommen nur eine relative Breite, wenn der 1223 // verfuegbare Platz *echt groesser* ist als die Minimalbreite. 1224 // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel 1225 // von einer relativen Breite zu einer absoluten Breite durch 1226 // Resize sonst zu einer Endlosschleife fuehrt. 1227 // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird, 1228 // wenn der Rahmen eine nicht-relative Breite besitzt, koennen 1229 // wir da solche Spielchen nicht spielen 1230 // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen 1231 // jetzt doch. Dort war eine Grafik in einer 1%-breiten 1232 // Tabelle und hat da natuerlich nicht hineingepasst. 1233 nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 ); 1234 if( IsTopTable() && 1235 ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) ) 1236 { 1237 nRelAvail = USHRT_MAX; 1238 bUseRelWidth = sal_True; 1239 } 1240 } 1241 else 1242 { 1243 nAbsTabWidth = nWidthOption; 1244 if( nAbsTabWidth > MAX_TABWIDTH ) 1245 nAbsTabWidth = MAX_TABWIDTH; 1246 1247 // Tabellen in Tabellen duerfen niemals breiter werden als der 1248 // verfuegbare Platz. 1249 if( !IsTopTable() && nAbsTabWidth > nAbsAvail ) 1250 nAbsTabWidth = nAbsAvail; 1251 } 1252 } 1253 1254 ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail, 1255 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" ); 1256 ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail, 1257 "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" ); 1258 1259 // Catch fuer die beiden Asserts von oben (man weiss ja nie!) 1260 if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail ) 1261 nAbsTabWidth = nAbsAvail; 1262 1263 1264 // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der 1265 // absoluten und relativen Tabellenbreiten. 1266 if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) || 1267 nMin > MAX_TABWIDTH ) 1268 { 1269 // Wenn 1270 // - das Minumum einer inneren Tabelle groesser ist als der 1271 // verfuegbare Platz, oder 1272 // - das Minumum einer Top-Table groesser ist als USHRT_MAX 1273 // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX 1274 // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten 1275 // untereinander erhalten. 1276 1277 nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail; 1278 nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth ); 1279 1280 // First of all, we check wether we can fit the layout constrains, 1281 // that are: Every cell's width excluding the borders must be at least 1282 // MINLAY: 1283 1284 sal_uLong nRealMin = 0; 1285 for( sal_uInt16 i=0; i<nCols; i++ ) 1286 { 1287 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2; 1288 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 ); 1289 nRealMin += nRealColMin; 1290 } 1291 if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) ) 1292 { 1293 // "Nichts geht mehr". We cannot get the minimum column widths 1294 // the layout wants to have. 1295 1296 sal_uInt16 nAbs = 0, nRel = 0; 1297 SwHTMLTableLayoutColumn *pColumn; 1298 for( sal_uInt16 i=0; i<nCols-1; i++ ) 1299 { 1300 pColumn = GetColumn( i ); 1301 sal_uLong nColMin = pColumn->GetMin(); 1302 if( nColMin <= USHRT_MAX ) 1303 { 1304 pColumn->SetAbsColWidth( 1305 (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) ); 1306 pColumn->SetRelColWidth( 1307 (sal_uInt16)((nColMin * nRelTabWidth) / nMin) ); 1308 } 1309 else 1310 { 1311 double nColMinD = nColMin; 1312 pColumn->SetAbsColWidth( 1313 (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) ); 1314 pColumn->SetRelColWidth( 1315 (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) ); 1316 } 1317 1318 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); 1319 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); 1320 } 1321 pColumn = GetColumn( nCols-1 ); 1322 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); 1323 pColumn->SetRelColWidth( nRelTabWidth - nRel ); 1324 } 1325 else 1326 { 1327 sal_uLong nDistAbs = nAbsTabWidth - nRealMin; 1328 sal_uLong nDistRel = nRelTabWidth - nRealMin; 1329 sal_uLong nDistMin = nMin - nRealMin; 1330 sal_uInt16 nAbs = 0, nRel = 0; 1331 SwHTMLTableLayoutColumn *pColumn; 1332 for( sal_uInt16 i=0; i<nCols-1; i++ ) 1333 { 1334 pColumn = GetColumn( i ); 1335 sal_uLong nColMin = pColumn->GetMin(); 1336 sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2; 1337 AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 ); 1338 1339 if( nColMin <= USHRT_MAX ) 1340 { 1341 pColumn->SetAbsColWidth( 1342 (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); 1343 pColumn->SetRelColWidth( 1344 (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); 1345 } 1346 else 1347 { 1348 double nColMinD = nColMin; 1349 pColumn->SetAbsColWidth( 1350 (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); 1351 pColumn->SetRelColWidth( 1352 (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); 1353 } 1354 1355 nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); 1356 nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); 1357 } 1358 pColumn = GetColumn( nCols-1 ); 1359 pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); 1360 pColumn->SetRelColWidth( nRelTabWidth - nRel ); 1361 } 1362 } 1363 else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) ) 1364 { 1365 // Wenn 1366 // - die Tabelle eine fixe Breite besitzt und das Maximum der 1367 // Tabelle kleiner ist, oder 1368 // - das Maximum kleiner ist als der verfuegbare Platz 1369 // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur 1370 // unter Beruecksichtigung des Maxumums an die fixe Breite 1371 // angepasst werden. 1372 1373 // Keine fixe Breite, dann das Maximum nehmen. 1374 if( !nAbsTabWidth ) 1375 nAbsTabWidth = (sal_uInt16)nMax; 1376 1377 // Eine Top-Table darf auch beriter werden als der verfuegbare Platz. 1378 if( nAbsTabWidth > nAbsAvail ) 1379 { 1380 ASSERT( IsTopTable(), 1381 "Tabelle in Tabelle soll breiter werden als umgebende Zelle" ); 1382 nAbsAvail = nAbsTabWidth; 1383 } 1384 1385 // Nur den Anteil der relativen Breite verwenden, der auch fuer 1386 // die absolute Breite verwendet wuerde. 1387 sal_uLong nAbsTabWidthL = nAbsTabWidth; 1388 nRelTabWidth = 1389 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) 1390 : nAbsTabWidth ); 1391 1392 // Gibt es Spalten mit und Spalten ohne %-Angabe? 1393 sal_uLong nFixMax = nMax; 1394 for( sal_uInt16 i=0; i<nCols; i++ ) 1395 { 1396 const SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1397 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 ) 1398 nFixMax -= pColumn->GetMax(); 1399 } 1400 1401 if( nFixMax > 0 && nFixMax < nMax ) 1402 { 1403 // ja, dann den zu verteilenden Platz nur auf die Spalten 1404 // mit %-Angabe verteilen. 1405 1406 // In diesem (und nur in diesem) Fall gibt es Spalten, 1407 // die ihre Maximalbreite genau einhalten, also weder 1408 // schmaler noch breiter werden. Beim zurueckrechnen der 1409 // absoluten Breite aus der relativen Breite kann es 1410 // zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen 1411 // werden zuerst die fixen Breiten entsprechend korrigiert 1412 // eingestellt und erst danach die relativen. 1413 1414 sal_uInt16 nAbs = 0, nRel = 0; 1415 sal_uInt16 nFixedCols = 0; 1416 sal_uInt16 i; 1417 1418 for( i = 0; i < nCols; i++ ) 1419 { 1420 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1421 if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() ) 1422 { 1423 // Die Spalte behaelt ihre Breite bei. 1424 nFixedCols++; 1425 sal_uLong nColMax = pColumn->GetMax(); 1426 pColumn->SetAbsColWidth( (sal_uInt16)nColMax ); 1427 1428 sal_uLong nRelColWidth = 1429 (nColMax * nRelTabWidth) / nAbsTabWidth; 1430 sal_uLong nChkWidth = 1431 (nRelColWidth * nAbsTabWidth) / nRelTabWidth; 1432 if( nChkWidth < nColMax ) 1433 nRelColWidth++; 1434 else if( nChkWidth > nColMax ) 1435 nRelColWidth--; 1436 pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth ); 1437 1438 nAbs = nAbs + (sal_uInt16)nColMax; 1439 nRel = nRel + (sal_uInt16)nRelColWidth; 1440 } 1441 } 1442 1443 // Zu verteilende Anteile des Maximums und der relativen und 1444 // absoluten Breiten. nFixMax entspricht an dieser Stelle 1445 // nAbs, so dass man gleich nFixMax haette nehmen koennen. 1446 // Der Code ist so aber verstaendlicher. 1447 ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" ) 1448 sal_uLong nDistMax = nMax - nFixMax; 1449 sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs; 1450 sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel; 1451 1452 for( i=0; i<nCols; i++ ) 1453 { 1454 SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); 1455 if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 ) 1456 { 1457 // Die Spalte wird anteilig breiter. 1458 nFixedCols++; 1459 if( nFixedCols == nCols ) 1460 { 1461 pColumn->SetAbsColWidth( nAbsTabWidth-nAbs ); 1462 pColumn->SetRelColWidth( nRelTabWidth-nRel ); 1463 } 1464 else 1465 { 1466 sal_uLong nColMax = pColumn->GetMax(); 1467 pColumn->SetAbsColWidth( 1468 (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) ); 1469 pColumn->SetRelColWidth( 1470 (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) ); 1471 } 1472 nAbs = nAbs + pColumn->GetAbsColWidth(); 1473 nRel = nRel + pColumn->GetRelColWidth(); 1474 } 1475 } 1476 ASSERT( nCols==nFixedCols, "Spalte vergessen!" ); 1477 } 1478 else 1479 { 1480 // nein, dann den zu verteilenden Platz auf alle Spalten 1481 // gleichmaessig vertilen. 1482 for( sal_uInt16 i=0; i<nCols; i++ ) 1483 { 1484 sal_uLong nColMax = GetColumn( i )->GetMax(); 1485 GetColumn( i )->SetAbsColWidth( 1486 (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) ); 1487 GetColumn( i )->SetRelColWidth( 1488 (sal_uInt16)((nColMax * nRelTabWidth) / nMax) ); 1489 } 1490 } 1491 } 1492 else 1493 { 1494 // den ueber die Minimalbreite herausgehenden Platz entsprechend 1495 // den einzelnen Spalten anteilig zuschlagen 1496 if( !nAbsTabWidth ) 1497 nAbsTabWidth = nAbsAvail; 1498 if( nAbsTabWidth < nMin ) 1499 nAbsTabWidth = (sal_uInt16)nMin; 1500 1501 if( nAbsTabWidth > nAbsAvail ) 1502 { 1503 ASSERT( IsTopTable(), 1504 "Tabelle in Tabelle soll breiter werden als Platz da ist" ); 1505 nAbsAvail = nAbsTabWidth; 1506 } 1507 1508 sal_uLong nAbsTabWidthL = nAbsTabWidth; 1509 nRelTabWidth = 1510 ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) 1511 : nAbsTabWidth ); 1512 double nW = nAbsTabWidth - nMin; 1513 double nD = (nMax==nMin ? 1 : nMax-nMin); 1514 sal_uInt16 nAbs = 0, nRel = 0; 1515 for( sal_uInt16 i=0; i<nCols-1; i++ ) 1516 { 1517 double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin(); 1518 sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD); 1519 sal_uLong nRelColWidth = nRelAvail 1520 ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth 1521 : nAbsColWidth; 1522 1523 GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth ); 1524 GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth ); 1525 nAbs = nAbs + (sal_uInt16)nAbsColWidth; 1526 nRel = nRel + (sal_uInt16)nRelColWidth; 1527 } 1528 GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs ); 1529 GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel ); 1530 1531 } 1532 1533 // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts 1534 // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet. 1535 nInhAbsLeftSpace = 0; 1536 nInhAbsRightSpace = 0; 1537 if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 || 1538 nAbsTabWidth<nAbsAvail) ) 1539 { 1540 // Die Breite von zusaetzlichen Zellen zur Ausrichtung der 1541 // inneren Tabelle bestimmen 1542 sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth); 1543 sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth); 1544 sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0; 1545 1546 // Groesse und Position der zusaetzlichen Zellen bestimmen 1547 switch( eTableAdjust ) 1548 { 1549 case SVX_ADJUST_RIGHT: 1550 nAbsLeftFill = nAbsLeftFill + nAbsDist; 1551 nRelLeftFill = nRelLeftFill + nRelDist; 1552 nParentInhAbsLeftSpace = nParentInhAbsSpace; 1553 break; 1554 case SVX_ADJUST_CENTER: 1555 { 1556 sal_uInt16 nAbsLeftDist = nAbsDist / 2; 1557 nAbsLeftFill = nAbsLeftFill + nAbsLeftDist; 1558 nAbsRightFill += nAbsDist - nAbsLeftDist; 1559 sal_uInt16 nRelLeftDist = nRelDist / 2; 1560 nRelLeftFill = nRelLeftFill + nRelLeftDist; 1561 nRelRightFill += nRelDist - nRelLeftDist; 1562 nParentInhAbsLeftSpace = nParentInhAbsSpace / 2; 1563 nParentInhAbsRightSpace = nParentInhAbsSpace - 1564 nParentInhAbsLeftSpace; 1565 } 1566 break; 1567 case SVX_ADJUST_LEFT: 1568 default: 1569 nAbsRightFill = nAbsRightFill + nAbsDist; 1570 nRelRightFill = nRelRightFill + nRelDist; 1571 nParentInhAbsRightSpace = nParentInhAbsSpace; 1572 break; 1573 } 1574 1575 ASSERT( !pLeftFillerBox || nRelLeftFill>0, 1576 "Fuer linke Filler-Box ist keine Breite da!" ); 1577 ASSERT( !pRightFillerBox || nRelRightFill>0, 1578 "Fuer rechte Filler-Box ist keine Breite da!" ); 1579 1580 // Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn 1581 // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0) 1582 // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und 1583 // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir 1584 // die Tabelle wahrscheinlich selbst exportiert) 1585 if( nRelLeftFill && !pLeftFillerBox && 1586 ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth || 1587 (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) ) 1588 // (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) ) 1589 { 1590 SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 ); 1591 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill ); 1592 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill ); 1593 nRelLeftFill = 0; 1594 nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace; 1595 } 1596 if( nRelRightFill && !pRightFillerBox && 1597 ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth || 1598 (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) ) 1599 // (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) ) 1600 { 1601 SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 ); 1602 pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill ); 1603 pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill ); 1604 nRelRightFill = 0; 1605 nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace; 1606 } 1607 } 1608 } 1609 1610 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ); 1611 1612 static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara ) 1613 { 1614 sal_uInt16 *pWidth = (sal_uInt16 *)pPara; 1615 1616 if( !rpBox->GetSttNd() ) 1617 { 1618 sal_uInt16 nWidth = 0; 1619 ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth ); 1620 rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); 1621 *pWidth = *pWidth + nWidth; 1622 } 1623 else 1624 { 1625 *pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width(); 1626 } 1627 1628 return sal_True; 1629 } 1630 1631 static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ) 1632 { 1633 sal_uInt16 *pWidth = (sal_uInt16 *)pPara; 1634 #ifdef DBG_UTIL 1635 sal_uInt16 nOldWidth = *pWidth; 1636 #endif 1637 *pWidth = 0; 1638 ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth ); 1639 1640 #ifdef DBG_UTIL 1641 ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY, 1642 "Zeilen einer Box sind unterschiedlich lang" ); 1643 #endif 1644 1645 return sal_True; 1646 } 1647 1648 void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail, 1649 sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace, 1650 sal_uInt16 nAbsRightSpace, 1651 sal_uInt16 nParentInhAbsSpace ) 1652 { 1653 // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen 1654 // worden sein. 1655 nWidthSet++; 1656 1657 // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus 1658 // aufgerufen. 1659 if( bCallPass2 ) 1660 AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace, 1661 nParentInhAbsSpace ); 1662 1663 // Schritt 1: Setzten der neuen Breite an allen Content-Boxen. 1664 // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird 1665 // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen 1666 // in Tabellen wird rekursiv SetWidth aufgerufen. 1667 for( sal_uInt16 i=0; i<nRows; i++ ) 1668 { 1669 for( sal_uInt16 j=0; j<nCols; j++ ) 1670 { 1671 SwHTMLTableLayoutCell *pCell = GetCell( i, j ); 1672 1673 SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents(); 1674 while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) ) 1675 { 1676 SwTableBox *pBox = pCntnts->GetTableBox(); 1677 if( pBox ) 1678 { 1679 SetBoxWidth( pBox, j, pCell->GetColSpan() ); 1680 } 1681 else 1682 { 1683 sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0, 1684 nInhSpace = 0; 1685 if( bCallPass2 ) 1686 { 1687 sal_uInt16 nColSpan = pCell->GetColSpan(); 1688 GetAvail( j, nColSpan, nAbs, nRel ); 1689 nLSpace = GetLeftCellSpace( j, nColSpan ); 1690 nRSpace = GetRightCellSpace( j, nColSpan ); 1691 nInhSpace = GetInhCellSpace( j, nColSpan ); 1692 } 1693 pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel, 1694 nLSpace, nRSpace, 1695 nInhSpace ); 1696 } 1697 1698 pCntnts->SetWidthSet( nWidthSet ); 1699 pCntnts = pCntnts->GetNext(); 1700 } 1701 } 1702 } 1703 1704 // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate 1705 // der Nicht-Content-Boxen angepasst. Da diese aufgrund der 1706 // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen 1707 // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch 1708 // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden 1709 // stattdessen die Breiten der Filler-Zellen gesetzt. 1710 if( IsTopTable() ) 1711 { 1712 sal_uInt16 nCalcTabWidth = 0; 1713 ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine, 1714 &nCalcTabWidth ); 1715 ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY, 1716 "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." ); 1717 1718 // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst 1719 // die Boxformate erneut angepasst werden. Ausserdem muss eine 1720 // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben. 1721 SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); 1722 ((SwTable *)pSwTable)->LockModify(); 1723 SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() ); 1724 aFrmSize.SetWidth( nRelTabWidth ); 1725 sal_Bool bRel = bUseRelWidth && 1726 text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient(); 1727 aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) ); 1728 pFrmFmt->SetFmtAttr( aFrmSize ); 1729 ((SwTable *)pSwTable)->UnlockModify(); 1730 1731 // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen 1732 // breite angepasst werden. 1733 if( MayBeInFlyFrame() ) 1734 { 1735 SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt(); 1736 if( pFlyFrmFmt ) 1737 { 1738 SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY ); 1739 1740 if( bUseRelWidth ) 1741 { 1742 // Bei %-Angaben wird die Breite auf das Minimum gesetzt. 1743 aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX 1744 : nMin ); 1745 aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption ); 1746 } 1747 pFlyFrmFmt->SetFmtAttr( aFlyFrmSize ); 1748 } 1749 } 1750 1751 #ifdef DBG_UTIL 1752 { 1753 // steht im tblrwcl.cxx 1754 extern void _CheckBoxWidth( const SwTableLine&, SwTwips ); 1755 1756 // checke doch mal ob die Tabellen korrekte Breiten haben 1757 SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth(); 1758 const SwTableLines& rLines = pSwTable->GetTabLines(); 1759 for( sal_uInt16 n = 0; n < rLines.Count(); ++n ) 1760 _CheckBoxWidth( *rLines[ n ], nSize ); 1761 } 1762 #endif 1763 1764 } 1765 else 1766 { 1767 if( pLeftFillerBox ) 1768 { 1769 pLeftFillerBox->GetFrmFmt()->SetFmtAttr( 1770 SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 )); 1771 } 1772 if( pRightFillerBox ) 1773 { 1774 pRightFillerBox->GetFrmFmt()->SetFmtAttr( 1775 SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 )); 1776 } 1777 } 1778 } 1779 1780 void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc ) 1781 { 1782 // Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas 1783 // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt 1784 // werden. 1785 if( bRecalc ) 1786 AutoLayoutPass1(); 1787 1788 SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetCurrentViewShell()->GetLayout(); 1789 if ( pRoot && pRoot->IsCallbackActionEnabled() ) 1790 pRoot->StartAllAction(); //swmod 071108//swmod 071225 1791 1792 // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils 1793 // noch der Pass 2 laufen muss. 1794 SetWidths( sal_True, nAbsAvail ); 1795 1796 if ( pRoot && pRoot->IsCallbackActionEnabled() ) 1797 pRoot->EndAllAction( sal_True ); //True per VirDev (Browsen ruhiger) //swmod 071108//swmod 071225 1798 } 1799 1800 IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG ) 1801 { 1802 #ifdef TEST_DELAYED_RESIZE 1803 Sound::Beep( SOUND_WARNING ); 1804 #endif 1805 pThis->aResizeTimer.Stop(); 1806 pThis->_Resize( pThis->nDelayedResizeAbsAvail, 1807 pThis->bDelayedResizeRecalc ); 1808 1809 return 0; 1810 } 1811 1812 1813 sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc, 1814 sal_Bool bForce, sal_uLong nDelay ) 1815 { 1816 if( 0 == nAbsAvail ) 1817 return sal_False; 1818 ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" ); 1819 1820 // Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem? 1821 if( bMustNotResize && !bForce ) 1822 return sal_False; 1823 1824 // Darf ein Recalc der Tabelle durchgefuehrt werden? 1825 if( bMustNotRecalc && !bForce ) 1826 bRecalc = sal_False; 1827 1828 const SwDoc *pDoc = GetDoc(); 1829 1830 // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames 1831 // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen 1832 // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden, 1833 // weil sond die Umschaltung von relativ nach absolut nicht funktioniert. 1834 if( pDoc->GetCurrentViewShell() && pDoc->GetCurrentViewShell()->GetViewOptions()->getBrowseMode() ) 1835 { 1836 const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc ); 1837 if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() ) 1838 nAbsAvail = nVisAreaWidth; 1839 } 1840 1841 if( nDelay==0 && aResizeTimer.IsActive() ) 1842 { 1843 // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones 1844 // Resize aussteht, dann werden nur die neuen Werte uebernommen. 1845 1846 bRecalc |= bDelayedResizeRecalc; 1847 nDelayedResizeAbsAvail = nAbsAvail; 1848 return sal_False; 1849 } 1850 1851 // Optimierung: 1852 // Wenn die Minima/Maxima nicht neu berechnet werden sollen und 1853 // - die Breite der Tabelle nie neu berechnet werden muss, oder 1854 // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder 1855 // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist 1856 // und die Tabelle bereits die Minimalbreite besitzt, oder 1857 // - der verfuegbare Platz groesser ist als die Maximalbreite und 1858 // die Tabelle bereits die Maximalbreite besitzt 1859 // wird sich an der Tabelle nichts aendern. 1860 if( !bRecalc && ( !bMustResize || 1861 (nLastResizeAbsAvail==nAbsAvail) || 1862 (nAbsAvail<=nMin && nRelTabWidth==nMin) || 1863 (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) ) 1864 return sal_False; 1865 1866 if( nDelay==HTMLTABLE_RESIZE_NOW ) 1867 { 1868 if( aResizeTimer.IsActive() ) 1869 aResizeTimer.Stop(); 1870 _Resize( nAbsAvail, bRecalc ); 1871 } 1872 else if( nDelay > 0 ) 1873 { 1874 nDelayedResizeAbsAvail = nAbsAvail; 1875 bDelayedResizeRecalc = bRecalc; 1876 aResizeTimer.SetTimeout( nDelay ); 1877 aResizeTimer.Start(); 1878 #ifdef TEST_DELAYED_RESIZE 1879 Sound::Beep( SOUND_DEFAULT ); 1880 #endif 1881 } 1882 else 1883 { 1884 _Resize( nAbsAvail, bRecalc ); 1885 } 1886 1887 return sal_True; 1888 } 1889 1890 void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc ) 1891 { 1892 bBordersChanged = sal_True; 1893 1894 Resize( nAbsAvail, bRecalc ); 1895 } 1896 1897 1898