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