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