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 "pagefrm.hxx" 27 #include "rootfrm.hxx" 28 #include "cntfrm.hxx" 29 #include "viewsh.hxx" 30 #include "doc.hxx" 31 #include "docsh.hxx" 32 #include "viewimp.hxx" 33 #include "swtable.hxx" 34 #include "dflyobj.hxx" 35 #include "flyfrm.hxx" 36 #include "frmtool.hxx" 37 #include "frmfmt.hxx" 38 #include "dcontact.hxx" 39 #include <anchoreddrawobject.hxx> 40 #include <fmtanchr.hxx> 41 #include "viewopt.hxx" 42 #include "hints.hxx" 43 #include "dbg_lay.hxx" 44 #include <ftnidx.hxx> 45 #include <svl/itemiter.hxx> 46 #include <docary.hxx> 47 #include <editeng/keepitem.hxx> 48 #include <editeng/ulspitem.hxx> 49 #include <editeng/lrspitem.hxx> 50 #include <editeng/brshitem.hxx> 51 #include <editeng/boxitem.hxx> 52 #include <vcl/outdev.hxx> 53 #include <fmtlsplt.hxx> 54 #include <fmtrowsplt.hxx> 55 #include <fmtsrnd.hxx> 56 #include <fmtornt.hxx> 57 #include <fmtpdsc.hxx> 58 #include <fmtfsize.hxx> 59 #include <swtblfmt.hxx> 60 #include <ndtxt.hxx> 61 #include "tabfrm.hxx" 62 #include "rowfrm.hxx" 63 #include "cellfrm.hxx" 64 #include "flyfrms.hxx" 65 #include "txtfrm.hxx" //HasFtn() 66 #include "htmltbl.hxx" 67 #include "sectfrm.hxx" //SwSectionFrm 68 #include <fmtfollowtextflow.hxx> 69 #include <sortedobjs.hxx> 70 #include <objectformatter.hxx> 71 #include <layouter.hxx> 72 #include <switerator.hxx> 73 74 extern void AppendObjs( const SwSpzFrmFmts *pTbl, sal_uLong nIndex, 75 SwFrm *pFrm, SwPageFrm *pPage ); 76 77 using namespace ::com::sun::star; 78 79 80 /************************************************************************* 81 |* 82 |* SwTabFrm::SwTabFrm(), ~SwTabFrm() 83 |* 84 |* Ersterstellung MA 09. Mar. 93 85 |* Letzte Aenderung MA 30. May. 96 86 |* 87 |*************************************************************************/ 88 SwTabFrm::SwTabFrm( SwTable &rTab, SwFrm* pSib ): 89 SwLayoutFrm( rTab.GetFrmFmt(), pSib ), 90 SwFlowFrm( (SwFrm&)*this ), 91 pTable( &rTab ) 92 { 93 bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove = 94 bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = 95 bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; 96 bConsiderObjsForMinCellHeight = sal_True; 97 bObjsDoesFit = sal_True; 98 mbInRecalcLowerRow = false; 99 bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. 100 nType = FRMC_TAB; 101 102 //Gleich die Zeilen erzeugen und einfuegen. 103 const SwTableLines &rLines = rTab.GetTabLines(); 104 SwFrm *pTmpPrev = 0; 105 for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) 106 { 107 SwRowFrm *pNew = new SwRowFrm( *rLines[i], this ); 108 if( pNew->Lower() ) 109 { 110 pNew->InsertBehind( this, pTmpPrev ); 111 pTmpPrev = pNew; 112 } 113 else 114 delete pNew; 115 } 116 ASSERT( Lower() && Lower()->IsRowFrm(), "SwTabFrm::SwTabFrm: No rows." ); 117 } 118 119 SwTabFrm::SwTabFrm( SwTabFrm &rTab ) : 120 SwLayoutFrm( rTab.GetFmt(), &rTab ), 121 SwFlowFrm( (SwFrm&)*this ), 122 pTable( rTab.GetTable() ) 123 { 124 bIsFollow = sal_True; 125 bLockJoin = bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove = 126 bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = 127 bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; 128 bConsiderObjsForMinCellHeight = sal_True; 129 bObjsDoesFit = sal_True; 130 mbInRecalcLowerRow = false; 131 bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. 132 nType = FRMC_TAB; 133 134 SetFollow( rTab.GetFollow() ); 135 rTab.SetFollow( this ); 136 } 137 138 extern const SwTable *pColumnCacheLastTable; 139 extern const SwTabFrm *pColumnCacheLastTabFrm; 140 extern const SwFrm *pColumnCacheLastCellFrm; 141 extern const SwTable *pRowCacheLastTable; 142 extern const SwTabFrm *pRowCacheLastTabFrm; 143 extern const SwFrm *pRowCacheLastCellFrm; 144 145 SwTabFrm::~SwTabFrm() 146 { 147 // There is some terrible code in fetab.cxx, that 148 // makes use of these global pointers. Obviously 149 // this code did not consider that a TabFrm can be 150 // deleted. 151 if ( this == pColumnCacheLastTabFrm ) 152 { 153 pColumnCacheLastTable = NULL; 154 pColumnCacheLastTabFrm = NULL; 155 pColumnCacheLastCellFrm= NULL; 156 pRowCacheLastTable = NULL; 157 pRowCacheLastTabFrm = NULL; 158 pRowCacheLastCellFrm= NULL; 159 } 160 } 161 162 /************************************************************************* 163 |* 164 |* SwTabFrm::JoinAndDelFollows() 165 |* 166 |* Ersterstellung MA 30. May. 96 167 |* Letzte Aenderung MA 30. May. 96 168 |* 169 |*************************************************************************/ 170 void SwTabFrm::JoinAndDelFollows() 171 { 172 SwTabFrm *pFoll = GetFollow(); 173 if ( pFoll->HasFollow() ) 174 pFoll->JoinAndDelFollows(); 175 pFoll->Cut(); 176 SetFollow( pFoll->GetFollow() ); 177 delete pFoll; 178 } 179 180 /************************************************************************* 181 |* 182 |* SwTabFrm::RegistFlys() 183 |* 184 |* Ersterstellung MA 08. Jul. 93 185 |* Letzte Aenderung MA 27. Jan. 99 186 |* 187 |*************************************************************************/ 188 void SwTabFrm::RegistFlys() 189 { 190 ASSERT( Lower() && Lower()->IsRowFrm(), "Keine Zeilen." ); 191 192 SwPageFrm *pPage = FindPageFrm(); 193 if ( pPage ) 194 { 195 SwRowFrm *pRow = (SwRowFrm*)Lower(); 196 do 197 { 198 pRow->RegistFlys( pPage ); 199 pRow = (SwRowFrm*)pRow->GetNext(); 200 } while ( pRow ); 201 } 202 } 203 204 /************************************************************************* 205 |* Some prototypes 206 |*************************************************************************/ 207 void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ); 208 void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ); 209 sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ); 210 // --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control 211 // that only row and cell frames are formatted. 212 sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, 213 long nBottom, 214 bool _bOnlyRowsAndCells = false ); 215 // <-- 216 // OD 2004-02-18 #106629# - correct type of 1st parameter 217 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to 218 // control, if floating screen objects have to be considered for the minimal 219 // cell height. 220 SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm *pRow, 221 const sal_Bool _bConsiderObjs ); 222 // <-- 223 SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm&, const SwBorderAttrs& ); 224 225 /************************************************************************* 226 |* START: local helper functions for repeated headlines 227 |*************************************************************************/ 228 229 SwTwips lcl_GetHeightOfRows( const SwFrm* pStart, long nCount ) 230 { 231 if ( !nCount || !pStart) 232 return 0; 233 234 SwTwips nRet = 0; 235 SWRECTFN( pStart ) 236 while ( pStart && nCount > 0 ) 237 { 238 nRet += (pStart->Frm().*fnRect->fnGetHeight)(); 239 pStart = pStart->GetNext(); 240 --nCount; 241 } 242 243 return nRet; 244 } 245 246 /************************************************************************* 247 |* END: local helper functions for repeated headlines 248 |*************************************************************************/ 249 250 /************************************************************************* 251 |* START: local helper functions for splitting row frames 252 |*************************************************************************/ 253 254 // 255 // Local helper function to insert a new follow flow line 256 // 257 SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, bool bRowSpanLine ) 258 { 259 ASSERT( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" ) 260 const SwRowFrm& rRow = (SwRowFrm&)rTmpRow; 261 262 rTab.SetFollowFlowLine( sal_True ); 263 SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), &rTab, false ); 264 pFollowFlowLine->SetRowSpanLine( bRowSpanLine ); 265 SwFrm* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow(); 266 pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow ); 267 return pFollowFlowLine; 268 } 269 270 // --> OD 2004-11-05 #i26945# - local helper function to invalidate all lower 271 // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if 272 // additionally the objects are moved 'out of range'. 273 void lcl_InvalidateLowerObjs( SwLayoutFrm& _rLayoutFrm, 274 const bool _bMoveObjsOutOfRange = false, 275 SwPageFrm* _pPageFrm = 0L ) 276 { 277 // determine page frame, if needed 278 if ( !_pPageFrm ) 279 { 280 _pPageFrm = _rLayoutFrm.FindPageFrm(); 281 ASSERT( _pPageFrm, 282 "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" ); 283 if ( !_pPageFrm ) 284 { 285 return; 286 } 287 } 288 289 // loop on lower frames 290 SwFrm* pLowerFrm = _rLayoutFrm.Lower(); 291 while ( pLowerFrm ) 292 { 293 if ( pLowerFrm->IsLayoutFrm() ) 294 { 295 ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pLowerFrm)), 296 _bMoveObjsOutOfRange, _pPageFrm ); 297 } 298 if ( pLowerFrm->GetDrawObjs() ) 299 { 300 for ( sal_uInt16 i = 0; i < pLowerFrm->GetDrawObjs()->Count(); ++i ) 301 { 302 SwAnchoredObject* pAnchoredObj = (*pLowerFrm->GetDrawObjs())[i]; 303 304 // invalidate position of anchored object 305 pAnchoredObj->SetTmpConsiderWrapInfluence( false ); 306 pAnchoredObj->SetConsiderForTextWrap( false ); 307 pAnchoredObj->UnlockPosition(); 308 pAnchoredObj->InvalidateObjPos(); 309 310 // move anchored object 'out of range' 311 if ( _bMoveObjsOutOfRange ) 312 { 313 // indicate, that positioning is progress to avoid 314 // modification of the anchored object resp. its attributes 315 // due to the movement 316 SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); 317 pAnchoredObj->SetObjLeft( _pPageFrm->Frm().Right() ); 318 // --> OD 2004-11-24 #115759# - reset character rectangle, 319 // top of line and relative position in order to assure, 320 // that anchored object is correctly positioned. 321 pAnchoredObj->ClearCharRectAndTopOfLine(); 322 pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); 323 if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() 324 == FLY_AS_CHAR ) 325 { 326 pAnchoredObj->AnchorFrm() 327 ->Prepare( PREP_FLY_ATTR_CHG, 328 &(pAnchoredObj->GetFrmFmt()) ); 329 } 330 // <-- 331 if ( pAnchoredObj->ISA(SwFlyFrm) ) 332 { 333 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); 334 pFly->GetVirtDrawObj()->SetRectsDirty(); 335 pFly->GetVirtDrawObj()->SetChanged(); 336 } 337 } 338 339 // If anchored object is a fly frame, invalidate its lower objects 340 if ( pAnchoredObj->ISA(SwFlyFrm) ) 341 { 342 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); 343 ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrm ); 344 } 345 } 346 } 347 pLowerFrm = pLowerFrm->GetNext(); 348 } 349 } 350 // <-- 351 // 352 // Local helper function to shrink all lowers of rRow to 0 height 353 // 354 void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow ) 355 { 356 SwCellFrm* pCurrMasterCell = static_cast<SwCellFrm*>(rRow.Lower()); 357 SWRECTFN( pCurrMasterCell ) 358 359 while ( pCurrMasterCell ) 360 { 361 // NEW TABLES 362 SwCellFrm& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ? 363 const_cast<SwCellFrm&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true, true )) : 364 *pCurrMasterCell; 365 366 // --> OD 2004-10-04 #i26945# 367 // all lowers should have the correct position 368 lcl_ArrangeLowers( &rToAdjust, 369 (rToAdjust.*fnRect->fnGetPrtTop)(), 370 sal_False ); 371 // <-- 372 // TODO: Optimize number of frames which are set to 0 height 373 // we have to start with the last lower frame, otherwise 374 // the shrink will not shrink the current cell 375 SwFrm* pTmp = rToAdjust.GetLastLower(); 376 377 if ( pTmp && pTmp->IsRowFrm() ) 378 { 379 SwRowFrm* pTmpRow = (SwRowFrm*)pTmp; 380 lcl_ShrinkCellsAndAllContent( *pTmpRow ); 381 } 382 else 383 { 384 // TODO: Optimize number of frames which are set to 0 height 385 while ( pTmp ) 386 { 387 // the frames have to be shrunk 388 if ( pTmp && pTmp->IsTabFrm() ) 389 { 390 SwRowFrm* pTmpRow = (SwRowFrm*)((SwTabFrm*)pTmp)->Lower(); 391 while ( pTmpRow ) 392 { 393 lcl_ShrinkCellsAndAllContent( *pTmpRow ); 394 pTmpRow = (SwRowFrm*)pTmpRow->GetNext(); 395 } 396 } 397 else 398 { 399 pTmp->Shrink( (pTmp->Frm().*fnRect->fnGetHeight)() ); 400 (pTmp->Prt().*fnRect->fnSetTop)( 0 ); 401 (pTmp->Prt().*fnRect->fnSetHeight)( 0 ); 402 } 403 404 pTmp = pTmp->GetPrev(); 405 } 406 407 // all lowers should have the correct position 408 lcl_ArrangeLowers( &rToAdjust, 409 (rToAdjust.*fnRect->fnGetPrtTop)(), 410 sal_False ); 411 } 412 413 pCurrMasterCell = static_cast<SwCellFrm*>(pCurrMasterCell->GetNext()); 414 } 415 } 416 417 // 418 // Local helper function to move the content from rSourceLine to rDestLine 419 // The content is inserted behind the last content in the corresponding 420 // cell in rDestLine. 421 // 422 void lcl_MoveRowContent( SwRowFrm& rSourceLine, SwRowFrm& rDestLine ) 423 { 424 SwCellFrm* pCurrDestCell = (SwCellFrm*)rDestLine.Lower(); 425 SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); 426 427 // Move content of follow cells into master cells 428 while ( pCurrSourceCell ) 429 { 430 if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() ) 431 { 432 SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); 433 while ( pTmpSourceRow ) 434 { 435 // --> FME 2006-01-10 #125926# Achtung! It is possible, 436 // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow 437 // cannot be found. In this case, we have to move the complete 438 // row. 439 SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower(); 440 // <-- 441 442 if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow ) 443 { 444 // move content from follow flow row to pTmpDestRow: 445 while ( pTmpDestRow->GetNext() ) 446 pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext(); 447 448 ASSERT( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Knoten in der Tabelle" ) 449 450 lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow ); 451 pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() ); 452 pTmpSourceRow->Remove(); 453 delete pTmpSourceRow; 454 } 455 else 456 { 457 // move complete row: 458 pTmpSourceRow->Remove(); 459 pTmpSourceRow->InsertBefore( pCurrDestCell, 0 ); 460 } 461 462 pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); 463 } 464 } 465 else 466 { 467 SwFrm *pTmp = ::SaveCntnt( (SwCellFrm*)pCurrSourceCell ); 468 if ( pTmp ) 469 { 470 // NEW TABLES 471 SwCellFrm* pDestCell = static_cast<SwCellFrm*>(pCurrDestCell); 472 if ( pDestCell->GetTabBox()->getRowSpan() < 1 ) 473 pDestCell = & const_cast<SwCellFrm&>(pDestCell->FindStartEndOfRowSpanCell( true, true )); 474 475 // Find last content 476 SwFrm* pFrm = pDestCell->GetLastLower(); 477 ::RestoreCntnt( pTmp, pDestCell, pFrm, true ); 478 } 479 } 480 pCurrDestCell = (SwCellFrm*)pCurrDestCell->GetNext(); 481 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); 482 } 483 } 484 485 // 486 // Local helper function to move all footnotes in rRowFrm from 487 // the footnote boss of rSource to the footnote boss of rDest. 488 // 489 void lcl_MoveFootnotes( SwTabFrm& rSource, SwTabFrm& rDest, SwLayoutFrm& rRowFrm ) 490 { 491 if ( 0 != rSource.GetFmt()->GetDoc()->GetFtnIdxs().Count() ) 492 { 493 SwFtnBossFrm* pOldBoss = rSource.FindFtnBossFrm( sal_True ); 494 SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( sal_True ); 495 rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, sal_True ); 496 } 497 } 498 499 // 500 // Local helper function to handle nested table cells before the split process 501 // 502 void lcl_PreprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine, 503 SwRowFrm& rFollowFlowLine, SwTwips nRemain ) 504 { 505 SwCellFrm* pCurrLastLineCell = (SwCellFrm*)rLastLine.Lower(); 506 SwCellFrm* pCurrFollowFlowLineCell = (SwCellFrm*)rFollowFlowLine.Lower(); 507 508 SWRECTFN( pCurrLastLineCell ) 509 510 // 511 // Move content of follow cells into master cells 512 // 513 while ( pCurrLastLineCell ) 514 { 515 if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrm() ) 516 { 517 SwTwips nTmpCut = nRemain; 518 SwRowFrm* pTmpLastLineRow = (SwRowFrm*)pCurrLastLineCell->Lower(); 519 520 // --> OD 2004-10-04 #i26945# 521 SwTwips nCurrentHeight = 522 lcl_CalcMinRowHeight( pTmpLastLineRow, 523 rTab.IsConsiderObjsForMinCellHeight() ); 524 // <-- 525 while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight ) 526 { 527 nTmpCut -= nCurrentHeight; 528 pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); 529 // --> OD 2004-10-04 #i26945# 530 nCurrentHeight = 531 lcl_CalcMinRowHeight( pTmpLastLineRow, 532 rTab.IsConsiderObjsForMinCellHeight() ); 533 // <-- 534 } 535 536 // 537 // pTmpLastLineRow does not fit to the line or it is the last line 538 // 539 if ( pTmpLastLineRow ) 540 { 541 // 542 // Check if we can move pTmpLastLineRow to the follow table, 543 // or if we have to split the line: 544 // 545 SwFrm* pCell = pTmpLastLineRow->Lower(); 546 bool bTableLayoutToComplex = false; 547 long nMinHeight = 0; 548 549 // 550 // We have to take into account: 551 // 1. The fixed height of the row 552 // 2. The borders of the cells inside the row 553 // 3. The minimum height of the row 554 // 555 if ( pTmpLastLineRow->HasFixSize() ) 556 nMinHeight = (pTmpLastLineRow->Frm().*fnRect->fnGetHeight)(); 557 else 558 { 559 while ( pCell ) 560 { 561 if ( ((SwCellFrm*)pCell)->Lower() && 562 ((SwCellFrm*)pCell)->Lower()->IsRowFrm() ) 563 { 564 bTableLayoutToComplex = true; 565 break; 566 } 567 568 SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell ); 569 const SwBorderAttrs &rAttrs = *aAccess.Get(); 570 nMinHeight = Max( nMinHeight, lcl_CalcTopAndBottomMargin( *(SwLayoutFrm*)pCell, rAttrs ) ); 571 pCell = pCell->GetNext(); 572 } 573 574 const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize(); 575 if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE ) 576 nMinHeight = Max( nMinHeight, rSz.GetHeight() ); 577 } 578 579 // 580 // 1. Case: 581 // The line completely fits into the master table. 582 // Nevertheless, we build a follow (otherwise painting problems 583 // with empty cell). 584 // 585 // 2. Case: 586 // The line has to be split, the minimum height still fits into 587 // the master table, and the table structure is not to complex. 588 // 589 if ( nTmpCut > nCurrentHeight || 590 ( pTmpLastLineRow->IsRowSplitAllowed() && 591 !bTableLayoutToComplex && nMinHeight < nTmpCut ) ) 592 { 593 // The line has to be split: 594 SwRowFrm* pNewRow = new SwRowFrm( *pTmpLastLineRow->GetTabLine(), &rTab, false ); 595 pNewRow->SetFollowFlowRow( true ); 596 pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() ); 597 pTmpLastLineRow->SetFollowRow( pNewRow ); 598 pNewRow->InsertBehind( pCurrFollowFlowLineCell, 0 ); 599 pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); 600 } 601 602 // 603 // The following lines have to be moved: 604 // 605 while ( pTmpLastLineRow ) 606 { 607 SwRowFrm* pTmp = (SwRowFrm*)pTmpLastLineRow->GetNext(); 608 lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow ); 609 pTmpLastLineRow->Remove(); 610 pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, 0 ); 611 pTmpLastLineRow->Shrink( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); 612 pCurrFollowFlowLineCell->Grow( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); 613 pTmpLastLineRow = pTmp; 614 } 615 } 616 } 617 618 pCurrLastLineCell = (SwCellFrm*)pCurrLastLineCell->GetNext(); 619 pCurrFollowFlowLineCell = (SwCellFrm*)pCurrFollowFlowLineCell->GetNext(); 620 } 621 } 622 623 // 624 // Local helper function to handle nested table cells after the split process 625 // 626 void lcl_PostprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine ) 627 { 628 SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); 629 while ( pCurrMasterCell ) 630 { 631 if ( pCurrMasterCell->Lower() && 632 pCurrMasterCell->Lower()->IsRowFrm() ) 633 { 634 SwRowFrm* pRowFrm = static_cast<SwRowFrm*>(pCurrMasterCell->GetLastLower()); 635 636 if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() ) 637 { 638 ASSERT( pRowFrm->GetFollowRow(), "Deleting row frame without follow" ) 639 640 // The footnotes have to be moved: 641 lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrm ); 642 pRowFrm->Cut(); 643 SwRowFrm* pFollowRow = pRowFrm->GetFollowRow(); 644 pRowFrm->Paste( pFollowRow->GetUpper(), pFollowRow ); 645 pRowFrm->SetFollowRow( pFollowRow->GetFollowRow() ); 646 lcl_MoveRowContent( *pFollowRow, *pRowFrm ); 647 pFollowRow->Cut(); 648 delete pFollowRow; 649 ::SwInvalidateAll( pCurrMasterCell, LONG_MAX ); 650 } 651 } 652 653 pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); 654 } 655 } 656 657 // 658 // Local helper function to re-calculate the split line. 659 // 660 inline void TableSplitRecalcLock( SwFlowFrm *pTab ) { pTab->LockJoin(); } 661 inline void TableSplitRecalcUnlock( SwFlowFrm *pTab ) { pTab->UnlockJoin(); } 662 663 bool lcl_RecalcSplitLine( SwRowFrm& rLastLine, SwRowFrm& rFollowLine, 664 SwTwips nRemainingSpaceForLastRow ) 665 { 666 bool bRet = true; 667 668 SwTabFrm& rTab = (SwTabFrm&)*rLastLine.GetUpper(); 669 670 // 671 // If there are nested cells in rLastLine, the recalculation of the last 672 // line needs some preprocessing. 673 // 674 lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow ); 675 676 // 677 // Here the recalculation process starts: 678 // 679 rTab.SetRebuildLastLine( sal_True ); 680 // --> OD 2004-10-15 #i26945# 681 rTab.SetDoesObjsFit( sal_True ); 682 // <-- 683 SWRECTFN( rTab.GetUpper() ) 684 685 // --> OD 2004-11-05 #i26945# - invalidate and move floating screen 686 // objects 'out of range' 687 ::lcl_InvalidateLowerObjs( rLastLine, true ); 688 // <-- 689 // 690 // manipulate row and cell sizes 691 // 692 // --> OD 2004-10-04 #i26945# - Do *not* consider floating screen objects 693 // for the minimal cell height. 694 rTab.SetConsiderObjsForMinCellHeight( sal_False ); 695 ::lcl_ShrinkCellsAndAllContent( rLastLine ); 696 rTab.SetConsiderObjsForMinCellHeight( sal_True ); 697 // <-- 698 699 // 700 // invalidate last line 701 // 702 ::SwInvalidateAll( &rLastLine, LONG_MAX ); 703 704 // 705 // Lock this tab frame and its follow 706 // 707 bool bUnlockMaster = false; 708 bool bUnlockFollow = false; 709 SwTabFrm* pMaster = rTab.IsFollow() ? (SwTabFrm*)rTab.FindMaster() : 0; 710 if ( pMaster && !pMaster->IsJoinLocked() ) 711 { 712 bUnlockMaster = true; 713 ::TableSplitRecalcLock( pMaster ); 714 } 715 if ( !rTab.GetFollow()->IsJoinLocked() ) 716 { 717 bUnlockFollow = true; 718 ::TableSplitRecalcLock( rTab.GetFollow() ); 719 } 720 721 // 722 // TODO: e.g., for i71806: What shall we do if the table already 723 // exceeds its upper? I think we have to adjust the heights of the 724 // table, rLastRow and all cells in rLastRow 725 // 726 /*SwTwips nDistanceToUpperPrtBottom = 727 (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)()); 728 729 if ( nDistanceToUpperPrtBottom < 0 ) 730 { 731 (rTab.Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 732 (rTab.Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 733 734 (rLastLine.Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 735 (rLastLine.Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 736 737 SwFrm* pTmpCell = rLastLine.Lower(); 738 while ( pTmpCell ) 739 { 740 (pTmpCell->Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 741 (pTmpCell->Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom ); 742 743 pTmpCell = pTmpCell->GetNext(); 744 } 745 }*/ 746 747 // 748 // Do the recalculation 749 // 750 lcl_RecalcRow( rLastLine, LONG_MAX ); 751 // --> OD 2004-11-23 #115759# - force a format of the last line in order to 752 // get the correct height. 753 rLastLine.InvalidateSize(); 754 rLastLine.Calc(); 755 // <-- 756 757 // 758 // Unlock this tab frame and its follow 759 // 760 if ( bUnlockFollow ) 761 ::TableSplitRecalcUnlock( rTab.GetFollow() ); 762 if ( bUnlockMaster ) 763 ::TableSplitRecalcUnlock( pMaster ); 764 765 // 766 // If there are nested cells in rLastLine, the recalculation of the last 767 // line needs some postprocessing. 768 // 769 lcl_PostprocessRowsInCells( rTab, rLastLine ); 770 771 // 772 // Do a couple of checks on the current situation. 773 // 774 // If we are not happy with the current situation we return false. 775 // This will start a new try to split the table, this time we do not 776 // try to split the table rows. 777 // 778 779 // 780 // 1. Check if table fits to its upper. 781 // --> OD 2004-10-15 #i26945# - include check, if objects fit 782 // 783 const SwTwips nDistanceToUpperPrtBottom = 784 (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)()); 785 if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() ) 786 bRet = false; 787 // <-- 788 789 // 790 // 2. Check if each cell in the last line has at least one content frame. 791 // 792 // Note: a FollowFlowRow may contains empty cells! 793 // 794 if ( bRet ) 795 { 796 if ( !rLastLine.IsInFollowFlowRow() ) 797 { 798 SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); 799 while ( pCurrMasterCell ) 800 { 801 if ( !pCurrMasterCell->ContainsCntnt() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 ) 802 { 803 bRet = false; 804 break; 805 } 806 pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); 807 } 808 } 809 } 810 811 // 812 // 3. Check if last line does not contain any content: 813 // 814 if ( bRet ) 815 { 816 if ( !rLastLine.ContainsCntnt() ) 817 { 818 bRet = false; 819 } 820 } 821 822 823 // 824 // 4. Check if follow flow line does not contain content: 825 // 826 if ( bRet ) 827 { 828 if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsCntnt() ) 829 { 830 bRet = false; 831 } 832 } 833 834 if ( bRet ) 835 { 836 // 837 // Everything looks fine. Splitting seems to be successful. We invalidate 838 // rFollowLine to force a new formatting. 839 // 840 ::SwInvalidateAll( &rFollowLine, LONG_MAX ); 841 } 842 else 843 { 844 // 845 // Splitting the table row gave us an unexpected result. 846 // Everything has to be prepared for a second try to split 847 // the table, this time without splitting the row. 848 // 849 ::SwInvalidateAll( &rLastLine, LONG_MAX ); 850 } 851 852 rTab.SetRebuildLastLine( sal_False ); 853 // --> OD 2004-10-15 #i26945# 854 rTab.SetDoesObjsFit( sal_True ); 855 // <-- 856 857 return bRet; 858 } 859 860 // 861 // Sets the correct height for all spanned cells 862 // 863 void lcl_AdjustRowSpanCells( SwRowFrm* pRow ) 864 { 865 SWRECTFN( pRow ) 866 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pRow->GetLower()); 867 while ( pCellFrm ) 868 { 869 const long nLayoutRowSpan = pCellFrm->GetLayoutRowSpan(); 870 if ( nLayoutRowSpan > 1 ) 871 { 872 // calculate height of cell: 873 const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan ); 874 const long nDiff = nNewCellHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); 875 if ( nDiff ) 876 (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); 877 } 878 879 pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); 880 } 881 } 882 883 // 884 // Returns the maximum layout row span of the row 885 // Looking for the next row that contains no covered cells: 886 long lcl_GetMaximumLayoutRowSpan( const SwRowFrm& rRow ) 887 { 888 long nRet = 1; 889 890 const SwRowFrm* pCurrentRowFrm = static_cast<const SwRowFrm*>(rRow.GetNext()); 891 bool bNextRow = false; 892 893 while ( pCurrentRowFrm ) 894 { 895 // if there is any covered cell, we proceed to the next row frame 896 const SwCellFrm* pLower = static_cast<const SwCellFrm*>( pCurrentRowFrm->Lower()); 897 while ( pLower ) 898 { 899 if ( pLower->GetTabBox()->getRowSpan() < 0 ) 900 { 901 ++nRet; 902 bNextRow = true; 903 break; 904 } 905 pLower = static_cast<const SwCellFrm*>(pLower->GetNext()); 906 } 907 pCurrentRowFrm = bNextRow ? 908 static_cast<const SwRowFrm*>(pCurrentRowFrm->GetNext() ) : 909 0; 910 } 911 912 return nRet; 913 } 914 915 /************************************************************************* 916 |* END: local helper functions for splitting row frames 917 |*************************************************************************/ 918 919 // 920 // Function to remove the FollowFlowLine of rTab. 921 // The content of the FollowFlowLine is moved to the associated line in the 922 // master table. 923 // 924 bool SwTabFrm::RemoveFollowFlowLine() 925 { 926 // find FollowFlowLine 927 SwRowFrm* pFollowFlowLine = static_cast<SwRowFrm*>(GetFollow()->GetFirstNonHeadlineRow()); 928 929 // find last row in master 930 SwFrm* pLastLine = GetLastLower(); 931 932 ASSERT( HasFollowFlowLine() && 933 pFollowFlowLine && 934 pLastLine, "There should be a flowline in the follow" ) 935 936 // We have to reset the flag here, because lcl_MoveRowContent 937 // calls a GrowFrm(), which has a different bahavior if 938 // this flag is set. 939 SetFollowFlowLine( sal_False ); 940 941 // --> FME 2007-07-19 #140081# Make code robust. 942 if ( !pFollowFlowLine || !pLastLine ) 943 return true; 944 945 // Move content 946 lcl_MoveRowContent( *pFollowFlowLine, *(SwRowFrm*)pLastLine ); 947 948 // NEW TABLES 949 // If a row span follow flow line is removed, we want to move the whole span 950 // to the master: 951 SwTwips nGrow = 0; 952 long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine ); 953 954 if ( nRowsToMove > 1 ) 955 { 956 SWRECTFN( this ) 957 SwFrm* pRow = pFollowFlowLine->GetNext(); 958 SwFrm* pInsertBehind = GetLastLower(); 959 960 while ( pRow && nRowsToMove-- > 1 ) 961 { 962 SwFrm* pNxt = pRow->GetNext(); 963 nGrow += (pRow->Frm().*fnRect->fnGetHeight)(); 964 965 // The footnotes have to be moved: 966 lcl_MoveFootnotes( *GetFollow(), *this, (SwRowFrm&)*pRow ); 967 968 pRow->Remove(); 969 pRow->InsertBehind( this, pInsertBehind ); 970 pRow->_InvalidateAll(); 971 pRow->CheckDirChange(); 972 pInsertBehind = pRow; 973 pRow = pNxt; 974 } 975 976 SwFrm* pFirstRow = Lower(); 977 while ( pFirstRow ) 978 { 979 lcl_AdjustRowSpanCells( static_cast<SwRowFrm*>(pFirstRow) ); 980 pFirstRow = pFirstRow->GetNext(); 981 } 982 983 Grow( nGrow ); 984 GetFollow()->Shrink( nGrow ); 985 } 986 987 bool bJoin = !pFollowFlowLine->GetNext(); 988 pFollowFlowLine->Cut(); 989 delete pFollowFlowLine; 990 991 return bJoin; 992 } 993 994 // --> OD 2004-10-04 #i26945# - Floating screen objects are no longer searched. 995 bool lcl_FindSectionsInRow( const SwRowFrm& rRow ) 996 { 997 bool bRet = false; 998 SwCellFrm* pLower = (SwCellFrm*)rRow.Lower(); 999 while ( pLower ) 1000 { 1001 if ( pLower->IsVertical() != rRow.IsVertical() ) 1002 return true; 1003 1004 SwFrm* pTmpFrm = pLower->Lower(); 1005 while ( pTmpFrm ) 1006 { 1007 if ( pTmpFrm->IsRowFrm() ) 1008 { 1009 bRet = lcl_FindSectionsInRow( *(SwRowFrm*)pTmpFrm ); 1010 } 1011 else 1012 { 1013 // --> OD 2004-10-04 #i26945# - search only for sections 1014 bRet = pTmpFrm->IsSctFrm(); 1015 // <-- 1016 } 1017 1018 if ( bRet ) 1019 return true; 1020 pTmpFrm = pTmpFrm->GetNext(); 1021 } 1022 1023 pLower = (SwCellFrm*)pLower->GetNext(); 1024 } 1025 return bRet; 1026 } 1027 1028 /************************************************************************* 1029 |* 1030 |* SwTabFrm::Split(), Join() 1031 |* 1032 |* Ersterstellung MA 03. Jun. 93 1033 |* Letzte Aenderung MA 03. Sep. 96 1034 |* 1035 |*************************************************************************/ 1036 bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep ) 1037 { 1038 bool bRet = true; 1039 1040 SWRECTFN( this ) 1041 //ASSERT( bVert ? nCutPos >= Frm().Left() && 1042 // nCutPos <= Frm().Left() + Frm().Width() : 1043 // nCutPos >= Frm().Top() && nCutPos <= Frm().Bottom(), "SplitLine out of table." ); 1044 1045 // --> OD 2004-10-14 #i26745# - format row and cell frames of table 1046 { 1047 this->Lower()->_InvalidatePos(); 1048 // --> OD 2005-03-30 #i43913# - correction: 1049 // call method <lcl_InnerCalcLayout> with first lower. 1050 lcl_InnerCalcLayout( this->Lower(), LONG_MAX, true ); 1051 // <-- 1052 } 1053 // <-- 1054 1055 //Um die Positionen der Zellen mit der CutPos zu vergleichen muessen sie 1056 //ausgehend von der Tabelle nacheinander berechnet werden. Sie koennen 1057 //wg. Positionsaenderungen der Tabelle durchaus ungueltig sein. 1058 SwRowFrm *pRow = static_cast<SwRowFrm*>(Lower()); 1059 if( !pRow ) 1060 return bRet; 1061 1062 const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); 1063 sal_uInt16 nRowCount = 0; // pRow currently points to the first row 1064 1065 SwTwips nRemainingSpaceForLastRow = 1066 (*fnRect->fnYDiff)( nCutPos, (Frm().*fnRect->fnGetTop)() ); 1067 nRemainingSpaceForLastRow -= (this->*fnRect->fnGetTopMargin)(); 1068 1069 // 1070 // Make pRow point to the line that does not fit anymore: 1071 // 1072 while( pRow->GetNext() && 1073 nRemainingSpaceForLastRow >= ( (pRow->Frm().*fnRect->fnGetHeight)() + 1074 (IsCollapsingBorders() ? 1075 pRow->GetBottomLineSize() : 1076 0 ) ) ) 1077 { 1078 if( bTryToSplit || !pRow->IsRowSpanLine() || 1079 0 != (pRow->Frm().*fnRect->fnGetHeight)() ) 1080 ++nRowCount; 1081 nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)(); 1082 pRow = static_cast<SwRowFrm*>(pRow->GetNext()); 1083 } 1084 1085 // 1086 // bSplitRowAllowed: Row may be split according to its attributes. 1087 // bTryToSplit: Row will never be split if bTryToSplit = false. 1088 // This can either be passed as a parameter, indicating 1089 // that we are currently doing the second try to split the 1090 // table, or it will be set to falseunder certain 1091 // conditions that are not suitable for splitting 1092 // the row. 1093 // 1094 bool bSplitRowAllowed = pRow->IsRowSplitAllowed(); 1095 1096 // --> FME 2004-06-03 #i29438# 1097 // --> OD 2004-10-04 #i26945# - Floating screen objects no longer forbid 1098 // a splitting of the table row. 1099 // Special DoNotSplit case 1: 1100 // Search for sections inside pRow: 1101 // 1102 if ( lcl_FindSectionsInRow( *pRow ) ) 1103 { 1104 bTryToSplit = false; 1105 } 1106 // <-- 1107 1108 // --> FME 2004-06-07 #i29771# 1109 // To avoid loops, we do some checks before actually trying to split 1110 // the row. Maybe we should keep the next row in this table. 1111 // Note: This is only done if we are at the beginning of our upper 1112 bool bKeepNextRow = false; 1113 if ( nRowCount < nRepeat ) 1114 { 1115 // 1116 // First case: One of the repeated headline does not fit to the page anymore. 1117 // At least one more non-heading row has to stay in this table in 1118 // order to avoid loops: 1119 // 1120 ASSERT( !GetIndPrev(), "Table is supposed to be at beginning" ) 1121 bKeepNextRow = true; 1122 } 1123 else if ( !GetIndPrev() && nRepeat == nRowCount ) 1124 { 1125 // 1126 // Second case: The first non-headline row does not fit to the page. 1127 // If it is not allowed to be split, or it contains a sub-row that 1128 // is not allowed to be split, we keep the row in this table: 1129 // 1130 if ( bTryToSplit && bSplitRowAllowed ) 1131 { 1132 // Check if there are (first) rows inside this row, 1133 // which are not allowed to be split. 1134 SwCellFrm* pLowerCell = pRow ? (SwCellFrm*)pRow->Lower() : 0; 1135 while ( pLowerCell ) 1136 { 1137 if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrm() ) 1138 { 1139 const SwRowFrm* pLowerRow = (SwRowFrm*)pLowerCell->Lower(); 1140 if ( !pLowerRow->IsRowSplitAllowed() && 1141 (pLowerRow->Frm().*fnRect->fnGetHeight)() > 1142 nRemainingSpaceForLastRow ) 1143 { 1144 bKeepNextRow = true; 1145 break; 1146 } 1147 } 1148 pLowerCell = (SwCellFrm*)pLowerCell->GetNext(); 1149 } 1150 } 1151 else 1152 bKeepNextRow = true; 1153 } 1154 1155 // 1156 // Better keep the next row in this table: 1157 // 1158 if ( bKeepNextRow ) 1159 { 1160 pRow = GetFirstNonHeadlineRow(); 1161 if( pRow && pRow->IsRowSpanLine() && 0 == (pRow->Frm().*fnRect->fnGetHeight)() ) 1162 pRow = static_cast<SwRowFrm*>(pRow->GetNext()); 1163 if ( pRow ) 1164 { 1165 pRow = static_cast<SwRowFrm*>(pRow->GetNext()); 1166 ++nRowCount; 1167 } 1168 } 1169 1170 // 1171 // No more row to split or to move to follow table: 1172 // 1173 if ( !pRow ) 1174 return bRet; 1175 1176 // 1177 // We try to split the row if 1178 // - the attributes of the row are set accordingly and 1179 // - we are allowed to do so 1180 // - the it should not keep with the next row 1181 // 1182 bSplitRowAllowed = bSplitRowAllowed && bTryToSplit && 1183 ( !bTableRowKeep || 1184 !pRow->ShouldRowKeepWithNext() ); 1185 1186 // Adjust pRow according to the keep-with-next attribute: 1187 if ( !bSplitRowAllowed && bTableRowKeep ) 1188 { 1189 SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pRow->GetPrev()); 1190 SwRowFrm* pOldRow = pRow; 1191 while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() && 1192 nRowCount > nRepeat ) 1193 { 1194 pRow = pTmpRow; 1195 --nRowCount; 1196 pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetPrev()); 1197 } 1198 1199 // loop prevention 1200 if ( nRowCount == nRepeat && !GetIndPrev()) 1201 { 1202 pRow = pOldRow; 1203 } 1204 } 1205 1206 // 1207 // If we do not indent to split pRow, we check if we are 1208 // allowed to move pRow to a follow. Otherwise we return 1209 // false, indicating an error 1210 // 1211 if ( !bSplitRowAllowed ) 1212 { 1213 SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); 1214 if ( pRow == pFirstNonHeadlineRow ) 1215 return false; 1216 1217 // --> OD 2008-10-21 #i91764# 1218 // Ignore row span lines 1219 SwRowFrm* pTmpRow = pFirstNonHeadlineRow; 1220 while ( pTmpRow && pTmpRow->IsRowSpanLine() ) 1221 { 1222 pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetNext()); 1223 } 1224 if ( !pTmpRow || pRow == pTmpRow ) 1225 { 1226 return false; 1227 } 1228 // <-- 1229 } 1230 1231 // 1232 // Build follow table if not already done: 1233 // 1234 sal_Bool bNewFollow; 1235 SwTabFrm *pFoll; 1236 if ( GetFollow() ) 1237 { 1238 pFoll = GetFollow(); 1239 bNewFollow = sal_False; 1240 } 1241 else 1242 { 1243 bNewFollow = sal_True; 1244 pFoll = new SwTabFrm( *this ); 1245 1246 // 1247 // We give the follow table an initial width. 1248 // 1249 (pFoll->Frm().*fnRect->fnAddWidth)( (Frm().*fnRect->fnGetWidth)() ); 1250 (pFoll->Prt().*fnRect->fnAddWidth)( (Prt().*fnRect->fnGetWidth)() ); 1251 (pFoll->Frm().*fnRect->fnSetLeft)( (Frm().*fnRect->fnGetLeft)() ); 1252 1253 // 1254 // Insert the new follow table 1255 // 1256 pFoll->InsertBehind( GetUpper(), this ); 1257 1258 // 1259 // Repeat the headlines. 1260 // 1261 for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount ) 1262 { 1263 // Insert new headlines: 1264 bDontCreateObjects = sal_True; //frmtool 1265 SwRowFrm* pHeadline = new SwRowFrm( 1266 *GetTable()->GetTabLines()[ nRowCount ], this ); 1267 pHeadline->SetRepeatedHeadline( true ); 1268 bDontCreateObjects = sal_False; 1269 pHeadline->InsertBefore( pFoll, 0 ); 1270 1271 SwPageFrm *pPage = pHeadline->FindPageFrm(); 1272 const SwSpzFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts(); 1273 if( pTbl->Count() ) 1274 { 1275 sal_uLong nIndex; 1276 SwCntntFrm* pFrm = pHeadline->ContainsCntnt(); 1277 while( pFrm ) 1278 { 1279 nIndex = pFrm->GetNode()->GetIndex(); 1280 AppendObjs( pTbl, nIndex, pFrm, pPage ); 1281 pFrm = pFrm->GetNextCntntFrm(); 1282 if( !pHeadline->IsAnLower( pFrm ) ) 1283 break; 1284 } 1285 } 1286 } 1287 } 1288 1289 SwRowFrm* pLastRow = 0; // will point to the last remaining line in master 1290 SwRowFrm* pFollowRow = 0; // points to either the follow flow line of the 1291 // first regular line in the follow 1292 1293 if ( bSplitRowAllowed ) 1294 { 1295 // If the row that does not fit anymore is allowed 1296 // to be split, the next row has to be moved to the follow table. 1297 pLastRow = pRow; 1298 pRow = static_cast<SwRowFrm*>(pRow->GetNext()); 1299 1300 // new follow flow line for last row of master table 1301 pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false ); 1302 } 1303 else 1304 { 1305 pFollowRow = pRow; 1306 1307 // NEW TABLES 1308 // check if we will break a row span by moving pFollowRow to the follow: 1309 // In this case we want to reformat the last line. 1310 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>(pFollowRow->GetLower()); 1311 while ( pCellFrm ) 1312 { 1313 if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) 1314 { 1315 pLastRow = static_cast<SwRowFrm*>(pRow->GetPrev()); 1316 break; 1317 } 1318 1319 pCellFrm = static_cast<const SwCellFrm*>(pCellFrm->GetNext()); 1320 } 1321 1322 // new follow flow line for last row of master table 1323 if ( pLastRow ) 1324 pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true ); 1325 } 1326 1327 SwTwips nRet = 0; 1328 1329 //Optimierung beim neuen Follow braucht's kein Paste und dann kann 1330 //das Optimierte Insert verwendet werden (nur dann treten gluecklicher weise 1331 //auch groessere Mengen von Rows auf). 1332 if ( bNewFollow ) 1333 { 1334 SwFrm* pNxt = 0; 1335 SwFrm* pInsertBehind = pFoll->GetLastLower(); 1336 1337 while ( pRow ) 1338 { 1339 pNxt = pRow->GetNext(); 1340 nRet += (pRow->Frm().*fnRect->fnGetHeight)(); 1341 // The footnotes do not have to be moved, this is done in the 1342 // MoveFwd of the follow table!!! 1343 pRow->Remove(); 1344 pRow->InsertBehind( pFoll, pInsertBehind ); 1345 pRow->_InvalidateAll(); 1346 pInsertBehind = pRow; 1347 pRow = static_cast<SwRowFrm*>(pNxt); 1348 } 1349 } 1350 else 1351 { 1352 SwFrm* pNxt = 0; 1353 SwFrm* pPasteBefore = HasFollowFlowLine() ? 1354 pFollowRow->GetNext() : 1355 pFoll->GetFirstNonHeadlineRow(); 1356 1357 while ( pRow ) 1358 { 1359 pNxt = pRow->GetNext(); 1360 nRet += (pRow->Frm().*fnRect->fnGetHeight)(); 1361 1362 // The footnotes have to be moved: 1363 lcl_MoveFootnotes( *this, *GetFollow(), *pRow ); 1364 1365 pRow->Remove(); 1366 pRow->Paste( pFoll, pPasteBefore ); 1367 1368 pRow->CheckDirChange(); 1369 pRow = static_cast<SwRowFrm*>(pNxt); 1370 } 1371 } 1372 1373 Shrink( nRet ); 1374 1375 // we rebuild the last line to assure that it will be fully formatted 1376 if ( pLastRow ) 1377 { 1378 // recalculate the split line 1379 bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow ); 1380 1381 // NEW TABLES 1382 // check if each cell in the row span line has a good height 1383 if ( bRet && pFollowRow->IsRowSpanLine() ) 1384 lcl_AdjustRowSpanCells( pFollowRow ); 1385 1386 // We The RowSplitLine stuff did not work. In this case we conceal the split error: 1387 if ( !bRet && !bSplitRowAllowed ) 1388 { 1389 bRet = true; 1390 } 1391 } 1392 1393 return bRet; 1394 } 1395 1396 bool SwTabFrm::Join() 1397 { 1398 ASSERT( !HasFollowFlowLine(), "Joining follow flow line" ) 1399 1400 SwTabFrm *pFoll = GetFollow(); 1401 SwTwips nHeight = 0; //Gesamthoehe der eingefuegten Zeilen als Return. 1402 1403 if ( !pFoll->IsJoinLocked() ) 1404 { 1405 SWRECTFN( this ) 1406 pFoll->Cut(); //Erst ausschneiden um unuetze Benachrichtigungen zu 1407 //minimieren. 1408 1409 SwFrm *pRow = pFoll->GetFirstNonHeadlineRow(), 1410 *pNxt; 1411 1412 SwFrm* pPrv = GetLastLower(); 1413 1414 while ( pRow ) 1415 { 1416 pNxt = pRow->GetNext(); 1417 nHeight += (pRow->Frm().*fnRect->fnGetHeight)(); 1418 pRow->Remove(); 1419 pRow->_InvalidateAll(); 1420 pRow->InsertBehind( this, pPrv ); 1421 pRow->CheckDirChange(); 1422 pPrv = pRow; 1423 pRow = pNxt; 1424 } 1425 1426 SetFollow( pFoll->GetFollow() ); 1427 SetFollowFlowLine( pFoll->HasFollowFlowLine() ); 1428 delete pFoll; 1429 1430 Grow( nHeight ); 1431 } 1432 1433 return true; 1434 } 1435 1436 /************************************************************************* 1437 |* 1438 |* SwTabFrm::MakeAll() 1439 |* 1440 |* Ersterstellung MA 09. Mar. 93 1441 |* Letzte Aenderung MA 10. Apr. 97 1442 |* 1443 |*************************************************************************/ 1444 void MA_FASTCALL SwInvalidatePositions( SwFrm *pFrm, long nBottom ) 1445 { 1446 // LONG_MAX == nBottom means we have to calculate all 1447 sal_Bool bAll = LONG_MAX == nBottom; 1448 SWRECTFN( pFrm ) 1449 do 1450 { pFrm->_InvalidatePos(); 1451 pFrm->_InvalidateSize(); 1452 if( pFrm->IsLayoutFrm() ) 1453 { 1454 if ( ((SwLayoutFrm*)pFrm)->Lower() ) 1455 { 1456 ::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom); 1457 // --> OD 2004-11-05 #i26945# 1458 ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pFrm)) ); 1459 // <-- 1460 } 1461 } 1462 else 1463 pFrm->Prepare( PREP_ADJUST_FRM ); 1464 pFrm = pFrm->GetNext(); 1465 } while ( pFrm && 1466 ( bAll || 1467 (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); 1468 } 1469 1470 void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ) 1471 { 1472 // LONG_MAX == nBottom means we have to calculate all 1473 sal_Bool bAll = LONG_MAX == nBottom; 1474 SWRECTFN( pFrm ) 1475 do 1476 { 1477 pFrm->_InvalidatePos(); 1478 pFrm->_InvalidateSize(); 1479 pFrm->_InvalidatePrt(); 1480 if( pFrm->IsLayoutFrm() ) 1481 { 1482 // NEW TABLES 1483 SwLayoutFrm* pToInvalidate = static_cast<SwLayoutFrm*>(pFrm); 1484 SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); 1485 if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) 1486 { 1487 pToInvalidate = & const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); 1488 pToInvalidate->_InvalidatePos(); 1489 pToInvalidate->_InvalidateSize(); 1490 pToInvalidate->_InvalidatePrt(); 1491 } 1492 1493 if ( pToInvalidate->Lower() ) 1494 ::SwInvalidateAll( pToInvalidate->Lower(), nBottom); 1495 } 1496 else 1497 pFrm->Prepare( PREP_CLEAR ); 1498 1499 pFrm = pFrm->GetNext(); 1500 } while ( pFrm && 1501 ( bAll || 1502 (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); 1503 } 1504 1505 // --> collapsing borders FME 2005-05-27 #i29550# 1506 void lcl_InvalidateAllLowersPrt( SwLayoutFrm* pLayFrm ) 1507 { 1508 pLayFrm->_InvalidatePrt(); 1509 pLayFrm->_InvalidateSize(); 1510 pLayFrm->SetCompletePaint(); 1511 1512 SwFrm* pFrm = pLayFrm->Lower(); 1513 1514 while ( pFrm ) 1515 { 1516 if ( pFrm->IsLayoutFrm() ) 1517 lcl_InvalidateAllLowersPrt( (SwLayoutFrm*)pFrm ); 1518 else 1519 { 1520 pFrm->_InvalidatePrt(); 1521 pFrm->_InvalidateSize(); 1522 pFrm->SetCompletePaint(); 1523 } 1524 1525 pFrm = pFrm->GetNext(); 1526 } 1527 } 1528 // <-- collapsing 1529 1530 bool SwCntntFrm::CalcLowers( SwLayoutFrm* pLay, const SwLayoutFrm* pDontLeave, 1531 long nBottom, bool bSkipRowSpanCells ) 1532 { 1533 if ( !pLay ) 1534 return sal_True; 1535 1536 // LONG_MAX == nBottom means we have to calculate all 1537 bool bAll = LONG_MAX == nBottom; 1538 bool bRet = sal_False; 1539 bool bPrune; 1540 SwCntntFrm *pCnt = pLay->ContainsCntnt(); 1541 SWRECTFN( pLay ) 1542 1543 // FME 2007-08-30 #i81146# new loop control 1544 sal_uInt16 nLoopControlRuns = 0; 1545 const sal_uInt16 nLoopControlMax = 10; 1546 const SwModify* pLoopControlCond = 0; 1547 1548 while ( pCnt && pDontLeave->IsAnLower( pCnt ) ) 1549 { 1550 // --> OD 2004-11-23 #115759# - check, if a format of content frame is 1551 // possible. Thus, 'copy' conditions, found at the beginning of 1552 // <SwCntntFrm::MakeAll(..)>, and check these. 1553 const bool bFormatPossible = !pCnt->IsJoinLocked() && 1554 ( !pCnt->IsTxtFrm() || 1555 !static_cast<SwTxtFrm*>(pCnt)->IsLocked() ) && 1556 ( pCnt->IsFollow() || !StackHack::IsLocked() ); 1557 1558 // NEW TABLES 1559 bool bSkipContent = false; 1560 if ( bSkipRowSpanCells && pCnt->IsInTab() ) 1561 { 1562 const SwFrm* pCell = pCnt->GetUpper(); 1563 while ( pCell && !pCell->IsCellFrm() ) 1564 pCell = pCell->GetUpper(); 1565 if ( pCell && 1 != static_cast<const SwCellFrm*>( pCell )->GetLayoutRowSpan() ) 1566 bSkipContent = true; 1567 } 1568 1569 if ( bFormatPossible && !bSkipContent ) 1570 { 1571 bRet |= !pCnt->IsValid(); 1572 // --> OD 2004-10-06 #i26945# - no extra invalidation of floating 1573 // screen objects needed. 1574 // Thus, delete call of method <SwFrm::InvalidateObjs( true )> 1575 // <-- 1576 pCnt->Calc(); 1577 // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrm(..)> 1578 // to format the floating screen objects 1579 // --> OD 2005-05-03 #i46941# - frame has to be valid 1580 // Note: frame could be invalid after calling its format, if it's locked. 1581 ASSERT( !pCnt->IsTxtFrm() || 1582 pCnt->IsValid() || 1583 static_cast<SwTxtFrm*>(pCnt)->IsJoinLocked(), 1584 "<SwCntntFrm::CalcLowers(..)> - text frame invalid and not locked." ); 1585 if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) 1586 { 1587 // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame to 1588 // the object formatter 1589 if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, 1590 *(pCnt->FindPageFrm()) ) ) 1591 // <-- 1592 { 1593 if ( pCnt->GetRegisteredIn() == pLoopControlCond ) 1594 ++nLoopControlRuns; 1595 else 1596 { 1597 nLoopControlRuns = 0; 1598 pLoopControlCond = pCnt->GetRegisteredIn(); 1599 } 1600 1601 if ( nLoopControlRuns < nLoopControlMax ) 1602 { 1603 // restart format with first content 1604 pCnt = pLay->ContainsCntnt(); 1605 continue; 1606 } 1607 1608 #if OSL_DEBUG_LEVEL > 1 1609 ASSERT( false, "LoopControl in SwCntntFrm::CalcLowers" ) 1610 #endif 1611 } 1612 } 1613 pCnt->GetUpper()->Calc(); 1614 } 1615 // <-- 1616 bPrune = !bAll && ( (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 ); 1617 pCnt = pCnt->GetNextCntntFrm( bPrune ); 1618 } 1619 return bRet; 1620 } 1621 1622 // --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control 1623 // that only row and cell frames are formatted. 1624 sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, 1625 long nBottom, 1626 bool _bOnlyRowsAndCells ) 1627 { 1628 // LONG_MAX == nBottom means we have to calculate all 1629 sal_Bool bAll = LONG_MAX == nBottom; 1630 sal_Bool bRet = sal_False; 1631 const SwFrm* pOldUp = pFrm->GetUpper(); 1632 SWRECTFN( pFrm ) 1633 do 1634 { 1635 // --> OD 2004-10-15 #i26945# - parameter <_bOnlyRowsAndCells> controls, 1636 // if only row and cell frames are formatted. 1637 if ( pFrm->IsLayoutFrm() && 1638 ( !_bOnlyRowsAndCells || pFrm->IsRowFrm() || pFrm->IsCellFrm() ) ) 1639 // <-- 1640 { 1641 // --> FME 2006-02-23 #130744# An invalid locked table frame will 1642 // not be calculated => It will not become valid => 1643 // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet. 1644 bRet |= !pFrm->IsValid() && ( !pFrm->IsTabFrm() || !static_cast<SwTabFrm*>(pFrm)->IsJoinLocked() ); 1645 // <-- 1646 pFrm->Calc(); 1647 if( static_cast<SwLayoutFrm*>(pFrm)->Lower() ) 1648 bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrm*>(pFrm)->Lower(), nBottom); 1649 1650 // NEW TABLES 1651 SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); 1652 if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) 1653 { 1654 SwCellFrm& rToCalc = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); 1655 bRet |= !rToCalc.IsValid(); 1656 rToCalc.Calc(); 1657 if ( rToCalc.Lower() ) 1658 bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom); 1659 } 1660 } 1661 pFrm = pFrm->GetNext(); 1662 } while( pFrm && 1663 ( bAll || 1664 (*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 ) 1665 && pFrm->GetUpper() == pOldUp ); 1666 return bRet; 1667 } 1668 1669 void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ) 1670 { 1671 // --> OD 2004-10-05 #i26945# - For correct appliance of the 'straightforward 1672 // object positioning process, it's needed to notify that the page frame, 1673 // on which the given layout frame is in, is in its layout process. 1674 SwPageFrm* pPageFrm = rRow.FindPageFrm(); 1675 if ( pPageFrm && !pPageFrm->IsLayoutInProgress() ) 1676 pPageFrm->SetLayoutInProgress( true ); 1677 else 1678 pPageFrm = 0L; 1679 // <-- 1680 1681 // FME 2007-08-30 #i81146# new loop control 1682 sal_uInt16 nLoopControlRuns_1 = 0; 1683 sal_uInt16 nLoopControlStage_1 = 0; 1684 const sal_uInt16 nLoopControlMax = 10; 1685 1686 bool bCheck = true; 1687 do 1688 { 1689 // FME 2007-08-30 #i81146# new loop control 1690 sal_uInt16 nLoopControlRuns_2 = 0; 1691 sal_uInt16 nLoopControlStage_2 = 0; 1692 1693 while( lcl_InnerCalcLayout( &rRow, nBottom ) ) 1694 { 1695 if ( ++nLoopControlRuns_2 > nLoopControlMax ) 1696 { 1697 #if OSL_DEBUG_LEVEL > 1 1698 ASSERT( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" ); 1699 ASSERT( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" ); 1700 ASSERT( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" ); 1701 #endif 1702 rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ ); 1703 nLoopControlRuns_2 = 0; 1704 if( nLoopControlStage_2 > 2 ) 1705 break; 1706 } 1707 1708 bCheck = true; 1709 } 1710 1711 if( bCheck ) 1712 { 1713 // --> OD 2004-11-23 #115759# - force another format of the 1714 // lowers, if at least one of it was invalid. 1715 bCheck = SwCntntFrm::CalcLowers( &rRow, rRow.GetUpper(), nBottom, true ); 1716 // <-- 1717 1718 // NEW TABLES 1719 // First we calculate the cells with row span of < 1, afterwards 1720 // all cells with row span of > 1: 1721 for ( int i = 0; i < 2; ++i ) 1722 { 1723 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(rRow.Lower()); 1724 while ( pCellFrm ) 1725 { 1726 const bool bCalc = 0 == i ? 1727 pCellFrm->GetLayoutRowSpan() < 1 : 1728 pCellFrm->GetLayoutRowSpan() > 1; 1729 1730 if ( bCalc ) 1731 { 1732 SwCellFrm& rToRecalc = 0 == i ? 1733 const_cast<SwCellFrm&>(pCellFrm->FindStartEndOfRowSpanCell( true, true )) : 1734 *pCellFrm; 1735 bCheck |= SwCntntFrm::CalcLowers( &rToRecalc, &rToRecalc, nBottom, false ); 1736 } 1737 1738 pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); 1739 } 1740 } 1741 1742 if ( bCheck ) 1743 { 1744 if ( ++nLoopControlRuns_1 > nLoopControlMax ) 1745 { 1746 #if OSL_DEBUG_LEVEL > 1 1747 ASSERT( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" ); 1748 ASSERT( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" ); 1749 ASSERT( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" ); 1750 #endif 1751 rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ ); 1752 nLoopControlRuns_1 = 0; 1753 if( nLoopControlStage_1 > 2 ) 1754 break; 1755 } 1756 1757 continue; 1758 } 1759 } 1760 break; 1761 } while( true ); 1762 1763 // --> OD 2004-10-05 #i26945# 1764 if ( pPageFrm ) 1765 pPageFrm->SetLayoutInProgress( false ); 1766 // <-- 1767 } 1768 1769 void MA_FASTCALL lcl_RecalcTable( SwTabFrm& rTab, 1770 SwLayoutFrm *pFirstRow, 1771 SwLayNotify &rNotify ) 1772 { 1773 if ( rTab.Lower() ) 1774 { 1775 if ( !pFirstRow ) 1776 { 1777 pFirstRow = (SwLayoutFrm*)rTab.Lower(); 1778 rNotify.SetLowersComplete( sal_True ); 1779 } 1780 ::SwInvalidatePositions( pFirstRow, LONG_MAX ); 1781 lcl_RecalcRow( static_cast<SwRowFrm&>(*pFirstRow), LONG_MAX ); 1782 } 1783 } 1784 1785 // This is a new function to check the first condition whether 1786 // a tab frame may move backward. It replaces the formerly used 1787 // GetIndPrev(), which did not work correctly for #i5947# 1788 bool lcl_NoPrev( const SwFrm& rFrm ) 1789 { 1790 // --> OD 2007-09-04 #i79774#, #b6596954# 1791 // skip empty sections on investigation of direct previous frame. 1792 // use information, that at least one empty section is skipped in the following code. 1793 bool bSkippedDirectPrevEmptySection( false ); 1794 if ( rFrm.GetPrev() ) 1795 { 1796 const SwFrm* pPrev( rFrm.GetPrev() ); 1797 while ( pPrev && 1798 pPrev->IsSctFrm() && 1799 !dynamic_cast<const SwSectionFrm*>(pPrev)->GetSection() ) 1800 { 1801 pPrev = pPrev->GetPrev(); 1802 bSkippedDirectPrevEmptySection = true; 1803 } 1804 if ( pPrev ) 1805 { 1806 return false; 1807 } 1808 } 1809 1810 if ( ( !bSkippedDirectPrevEmptySection && !rFrm.GetIndPrev() ) || 1811 ( bSkippedDirectPrevEmptySection && 1812 ( !rFrm.IsInSct() || !rFrm._GetIndPrev() ) ) ) 1813 { 1814 return true; 1815 } 1816 // <-- 1817 1818 // I do not have a direct prev, but I have an indirect prev. 1819 // In section frames I have to check if I'm located inside 1820 // the first column: 1821 if ( rFrm.IsInSct() ) 1822 { 1823 const SwFrm* pSct = rFrm.GetUpper(); 1824 if ( pSct && pSct->IsColBodyFrm() && 1825 (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() ) 1826 { 1827 const SwFrm* pPrevCol = rFrm.GetUpper()->GetUpper()->GetPrev(); 1828 if ( pPrevCol ) 1829 // I'm not inside the first column and do not have a direct 1830 // prev. I can try to go backward. 1831 return true; 1832 } 1833 } 1834 1835 return false; 1836 } 1837 1838 #define KEEPTAB ( !GetFollow() && !IsFollow() ) 1839 1840 // --> OD 2005-09-28 #b6329202# - helper method to find next content frame of 1841 // a table frame and format it to assure keep attribute. 1842 // method return true, if a next content frame is formatted. 1843 // Precondition: The given table frame hasn't a follow and isn't a follow. 1844 SwFrm* lcl_FormatNextCntntForKeep( SwTabFrm* pTabFrm ) 1845 { 1846 // find next content, table or section 1847 SwFrm* pNxt = pTabFrm->FindNext(); 1848 1849 // skip empty sections 1850 while ( pNxt && pNxt->IsSctFrm() && 1851 !static_cast<SwSectionFrm*>(pNxt)->GetSection() ) 1852 { 1853 pNxt = pNxt->FindNext(); 1854 } 1855 1856 // if found next frame is a section, get its first content. 1857 if ( pNxt && pNxt->IsSctFrm() ) 1858 { 1859 pNxt = static_cast<SwSectionFrm*>(pNxt)->ContainsAny(); 1860 } 1861 1862 // format found next frame. 1863 // if table frame is inside another table, method <SwFrm::MakeAll()> is 1864 // called to avoid that the superior table frame is formatted. 1865 if ( pNxt ) 1866 { 1867 if ( pTabFrm->GetUpper()->IsInTab() ) 1868 pNxt->MakeAll(); 1869 else 1870 pNxt->Calc(); 1871 } 1872 1873 return pNxt; 1874 } 1875 1876 namespace { 1877 bool AreAllRowsKeepWithNext( const SwRowFrm* pFirstRowFrm ) 1878 { 1879 bool bRet = pFirstRowFrm != 0 && 1880 pFirstRowFrm->ShouldRowKeepWithNext(); 1881 1882 while ( bRet && pFirstRowFrm->GetNext() != 0 ) 1883 { 1884 pFirstRowFrm = dynamic_cast<const SwRowFrm*>(pFirstRowFrm->GetNext()); 1885 bRet = pFirstRowFrm != 0 && 1886 pFirstRowFrm->ShouldRowKeepWithNext(); 1887 } 1888 1889 return bRet; 1890 } 1891 } 1892 void SwTabFrm::MakeAll() 1893 { 1894 if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) 1895 return; 1896 1897 if ( HasFollow() ) 1898 { 1899 SwTabFrm* pFollowFrm = (SwTabFrm*)GetFollow(); 1900 ASSERT( !pFollowFrm->IsJoinLocked() || !pFollowFrm->IsRebuildLastLine(), 1901 "SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" ) 1902 if ( pFollowFrm->IsJoinLocked() && pFollowFrm->IsRebuildLastLine() ) 1903 return; 1904 } 1905 1906 PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) 1907 1908 LockJoin(); //Ich lass mich nicht unterwegs vernichten. 1909 SwLayNotify aNotify( this ); //uebernimmt im DTor die Benachrichtigung 1910 // If pos is invalid, we have to call a SetInvaKeep at aNotify. 1911 // Otherwise the keep attribute would not work in front of a table. 1912 const sal_Bool bOldValidPos = GetValidPosFlag(); 1913 1914 //Wenn mein direkter Nachbar gleichzeitig mein Follow ist 1915 //verleibe ich mir das Teil ein. 1916 // OD 09.04.2003 #108698# - join all follows, which are placed on the 1917 // same page/column. 1918 // OD 29.04.2003 #109213# - join follow, only if join for the follow 1919 // is not locked. Otherwise, join will not be performed and this loop 1920 // will be endless. 1921 while ( GetNext() && GetNext() == GetFollow() && 1922 !GetFollow()->IsJoinLocked() 1923 ) 1924 { 1925 if ( HasFollowFlowLine() ) 1926 RemoveFollowFlowLine(); 1927 Join(); 1928 } 1929 1930 // The bRemoveFollowFlowLinePending is set if the split attribute of the 1931 // last line is set: 1932 if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() ) 1933 { 1934 if ( RemoveFollowFlowLine() ) 1935 Join(); 1936 SetRemoveFollowFlowLinePending( sal_False ); 1937 } 1938 1939 if ( bResizeHTMLTable ) //Optimiertes Zusammenspiel mit Grow/Shrink des Inhaltes 1940 { 1941 bResizeHTMLTable = sal_False; 1942 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); 1943 if ( pLayout ) 1944 bCalcLowers = pLayout->Resize( 1945 pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); 1946 } 1947 1948 1949 sal_Bool bMakePage = sal_True; //solange sal_True kann eine neue Seite 1950 //angelegt werden (genau einmal) 1951 sal_Bool bMovedBwd = sal_False; //Wird sal_True wenn der Frame zurueckfliesst 1952 sal_Bool bMovedFwd = sal_False; //solange sal_False kann der Frm zurueck- 1953 //fliessen (solange, bis er einmal 1954 //vorwaerts ge'moved wurde). 1955 sal_Bool bSplit = sal_False; //Wird sal_True wenn der Frm gesplittet wurde. 1956 const sal_Bool bFtnsInDoc = 0 != GetFmt()->GetDoc()->GetFtnIdxs().Count(); 1957 sal_Bool bMoveable; 1958 const sal_Bool bFly = IsInFly(); 1959 1960 SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); 1961 const SwBorderAttrs *pAttrs = pAccess->Get(); 1962 1963 // The beloved keep attribute 1964 const bool bKeep = IsKeep( pAttrs->GetAttrSet() ); 1965 1966 // All rows should keep together 1967 // OD 2004-05-25 #i21478# - don't split table, if it has to keep with next 1968 const bool bDontSplit = !IsFollow() && 1969 ( !GetFmt()->GetLayoutSplit().GetValue() || bKeep ); 1970 1971 // The number of repeated headlines 1972 const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); 1973 1974 // This flag indicates that we are allowed to try to split the 1975 // table rows. 1976 bool bTryToSplit = true; 1977 1978 // --> FME 2006-02-16 #131283# 1979 // Indicates that two individual rows may keep together, based on the keep 1980 // attribute set at the first paragraph in the first cell. 1981 const bool bTableRowKeep = !bDontSplit && GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP); 1982 1983 // The Magic Move: Used for the table row keep feature. 1984 // If only the last row of the table wants to keep (implicitely by setting 1985 // keep for the first paragraph in the first cell), and this table does 1986 // not have a next, the last line will be cut. Loop prevention: Only 1987 // one try. 1988 bool bLastRowHasToMoveToFollow = false; 1989 bool bLastRowMoveNoMoreTries = false; 1990 1991 // Join follow table, if this table is not allowed to split: 1992 if ( bDontSplit ) 1993 { 1994 while ( GetFollow() && !GetFollow()->IsJoinLocked() ) 1995 { 1996 if ( HasFollowFlowLine() ) 1997 RemoveFollowFlowLine(); 1998 Join(); 1999 } 2000 } 2001 2002 // Join follow table, if this does not have enough (repeated) lines: 2003 if ( nRepeat ) 2004 { 2005 if( GetFollow() && !GetFollow()->IsJoinLocked() && 2006 0 == GetFirstNonHeadlineRow() ) 2007 { 2008 if ( HasFollowFlowLine() ) 2009 RemoveFollowFlowLine(); 2010 Join(); 2011 } 2012 } 2013 2014 // Join follow table, if last row of this table should keep: 2015 if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() ) 2016 { 2017 const SwRowFrm* pTmpRow = static_cast<const SwRowFrm*>(GetLastLower()); 2018 if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) 2019 { 2020 if ( HasFollowFlowLine() ) 2021 RemoveFollowFlowLine(); 2022 Join(); 2023 } 2024 } 2025 2026 //Einen Frischling moven wir gleich schon einmal vorwaerts... 2027 if ( !Frm().Top() && IsFollow() ) 2028 { 2029 SwFrm *pPre = GetPrev(); 2030 if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) 2031 { 2032 if ( !MoveFwd( bMakePage, sal_False ) ) 2033 bMakePage = sal_False; 2034 bMovedFwd = sal_True; 2035 } 2036 } 2037 2038 int nUnSplitted = 5; // Just another loop control :-( 2039 SWRECTFN( this ) 2040 while ( !bValidPos || !bValidSize || !bValidPrtArea ) 2041 { 2042 if ( sal_True == (bMoveable = IsMoveable()) ) 2043 if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) ) 2044 { 2045 bMovedFwd = sal_True; 2046 bCalcLowers = sal_True; 2047 // --> OD 2009-08-12 #i99267# 2048 // reset <bSplit> after forward move to assure that follows 2049 // can be joined, if further space is available. 2050 bSplit = sal_False; 2051 // <-- 2052 } 2053 2054 Point aOldPos( (Frm().*fnRect->fnGetPos)() ); 2055 MakePos(); 2056 2057 if ( aOldPos != (Frm().*fnRect->fnGetPos)() ) 2058 { 2059 if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() ) 2060 { 2061 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); 2062 if( pLayout ) 2063 { 2064 delete pAccess; 2065 bCalcLowers |= pLayout->Resize( 2066 pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); 2067 pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this ); 2068 pAttrs = pAccess->Get(); 2069 } 2070 2071 bValidPrtArea = sal_False; 2072 aNotify.SetLowersComplete( sal_False ); 2073 } 2074 SwFrm *pPre; 2075 if ( bKeep || (0 != (pPre = FindPrev()) && 2076 pPre->GetAttrSet()->GetKeep().GetValue()) ) 2077 { 2078 bCalcLowers = sal_True; 2079 } 2080 } 2081 2082 //Wir muessen die Hoehe der ersten Zeile kennen, denn nur wenn diese 2083 //kleiner wird muss ggf. der Master angestossen werden um noetigenfalls 2084 //die Zeile aufzunehmen. 2085 long n1StLineHeight = 0; 2086 if ( IsFollow() ) 2087 { 2088 SwFrm* pFrm = GetFirstNonHeadlineRow(); 2089 if ( pFrm ) 2090 n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)(); 2091 } 2092 2093 if ( !bValidSize || !bValidPrtArea ) 2094 { 2095 const long nOldPrtWidth = (Prt().*fnRect->fnGetWidth)(); 2096 const long nOldFrmWidth = (Frm().*fnRect->fnGetWidth)(); 2097 const Point aOldPrtPos = (Prt().*fnRect->fnGetPos)(); 2098 Format( pAttrs ); 2099 2100 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); 2101 if ( pLayout && 2102 ((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth || 2103 (Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) ) 2104 { 2105 delete pAccess; 2106 bCalcLowers |= pLayout->Resize( 2107 pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); 2108 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); 2109 pAttrs = pAccess->Get(); 2110 } 2111 if ( aOldPrtPos != (Prt().*fnRect->fnGetPos)() ) 2112 aNotify.SetLowersComplete( sal_False ); 2113 } 2114 2115 //Wenn ich der erste einer Kette bin koennte ich mal sehen ob 2116 //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll). 2117 //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts 2118 //geflosssen sein. 2119 if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) ) 2120 { 2121 //Bei Follows muss der Master benachrichtigt 2122 //werden. Der Follow muss nur dann Moven, wenn er leere Blaetter 2123 //ueberspringen muss. 2124 if ( IsFollow() ) 2125 { 2126 //Nur wenn die Hoehe der ersten Zeile kleiner geworder ist. 2127 SwFrm *pFrm = GetFirstNonHeadlineRow(); 2128 if( pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight )() ) 2129 { 2130 SwTabFrm *pMaster = (SwTabFrm*)FindMaster(); 2131 sal_Bool bDummy; 2132 if ( ShouldBwdMoved( pMaster->GetUpper(), sal_False, bDummy ) ) 2133 pMaster->InvalidatePos(); 2134 } 2135 } 2136 SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( sal_True ) : 0; 2137 sal_Bool bReformat; 2138 if ( MoveBwd( bReformat ) ) 2139 { 2140 SWREFRESHFN( this ) 2141 bMovedBwd = sal_True; 2142 aNotify.SetLowersComplete( sal_False ); 2143 if ( bFtnsInDoc ) 2144 MoveLowerFtns( 0, pOldBoss, 0, sal_True ); 2145 if ( bReformat || bKeep ) 2146 { 2147 long nOldTop = (Frm().*fnRect->fnGetTop)(); 2148 MakePos(); 2149 if( nOldTop != (Frm().*fnRect->fnGetTop)() ) 2150 { 2151 SwHTMLTableLayout *pHTMLLayout = 2152 GetTable()->GetHTMLTableLayout(); 2153 if( pHTMLLayout ) 2154 { 2155 delete pAccess; 2156 bCalcLowers |= pHTMLLayout->Resize( 2157 pHTMLLayout->GetBrowseWidthByTabFrm( *this ), 2158 sal_False ); 2159 2160 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); 2161 pAttrs = pAccess->Get(); 2162 } 2163 2164 bValidPrtArea = sal_False; 2165 Format( pAttrs ); 2166 } 2167 lcl_RecalcTable( *this, 0, aNotify ); 2168 bLowersFormatted = sal_True; 2169 if ( bKeep && KEEPTAB ) 2170 { 2171 if ( 0 != lcl_FormatNextCntntForKeep( this ) && !GetNext() ) 2172 { 2173 bValidPos = sal_False; 2174 } 2175 } 2176 } 2177 } 2178 } 2179 2180 //Wieder ein Wert ungueltig? - dann nochmal das ganze... 2181 if ( !bValidPos || !bValidSize || !bValidPrtArea ) 2182 continue; 2183 2184 // check, if calculation of table frame is ready. 2185 2186 // Local variable <nDistanceToUpperPrtBottom> 2187 // Introduce local variable and init it with the distance from the 2188 // table frame bottom to the bottom of the upper printing area. 2189 // Note: negative values denotes the situation that table frame doesn't fit in its upper. 2190 SwTwips nDistanceToUpperPrtBottom = 2191 (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); 2192 2193 // In online layout try to grow upper of table frame, if table frame doesn't fit in its upper. 2194 const ViewShell *pSh = getRootFrm()->GetCurrShell(); 2195 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); 2196 if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode ) 2197 { 2198 if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) ) 2199 { 2200 // upper is grown --> recalculate <nDistanceToUpperPrtBottom> 2201 nDistanceToUpperPrtBottom = (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); 2202 } 2203 } 2204 2205 // If there is still some space left in the upper, we check if we 2206 // can join some rows of the follow. 2207 // Setting bLastRowHasToMoveToFollow to true means we want to force 2208 // the table to be split! Only skip this if condition once. 2209 if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow ) 2210 { 2211 // If there is space left in the upper printing area, join as for trial 2212 // at least one further row of an existing follow. 2213 if ( !bSplit && GetFollow() ) 2214 { 2215 sal_Bool bDummy; 2216 if ( GetFollow()->ShouldBwdMoved( GetUpper(), sal_False, bDummy ) ) 2217 { 2218 SwFrm *pTmp = GetUpper(); 2219 SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)(); 2220 if ( bBrowseMode ) 2221 nDeadLine += pTmp->Grow( LONG_MAX, sal_True ); 2222 if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 ) 2223 { 2224 // 2225 // First, we remove an existing follow flow line. 2226 // 2227 if ( HasFollowFlowLine() ) 2228 { 2229 SwFrm* pLastLine = const_cast<SwFrm*>(GetLastLower()); 2230 RemoveFollowFlowLine(); 2231 // invalidate and rebuild last row 2232 if ( pLastLine ) 2233 { 2234 ::SwInvalidateAll( pLastLine, LONG_MAX ); 2235 SetRebuildLastLine( sal_True ); 2236 lcl_RecalcRow( static_cast<SwRowFrm&>(*pLastLine), LONG_MAX ); 2237 SetRebuildLastLine( sal_False ); 2238 } 2239 2240 SwFrm* pRow = GetFollow()->GetFirstNonHeadlineRow(); 2241 2242 if ( !pRow || !pRow->GetNext() ) 2243 //Der Follow wird leer und damit ueberfluessig. 2244 Join(); 2245 2246 continue; 2247 } 2248 2249 // 2250 // If there is no follow flow line, we move the first 2251 // row in the follow table to the master table. 2252 // 2253 SwRowFrm *pRow = GetFollow()->GetFirstNonHeadlineRow(); 2254 2255 //Der Follow wird leer und damit ueberfluessig. 2256 if ( !pRow ) 2257 { 2258 Join(); 2259 continue; 2260 } 2261 2262 const SwTwips nOld = (Frm().*fnRect->fnGetHeight)(); 2263 long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow ); 2264 SwFrm* pRowToMove = pRow; 2265 2266 while ( pRowToMove && nRowsToMove-- > 0 ) 2267 { 2268 const sal_Bool bMoveFtns = bFtnsInDoc && !GetFollow()->IsJoinLocked(); 2269 2270 SwFtnBossFrm *pOldBoss = 0; 2271 if ( bMoveFtns ) 2272 pOldBoss = pRowToMove->FindFtnBossFrm( sal_True ); 2273 2274 SwFrm* pNextRow = pRowToMove->GetNext(); 2275 2276 if ( !pNextRow ) 2277 { 2278 //Der Follow wird leer und damit ueberfluessig. 2279 Join(); 2280 } 2281 else 2282 { 2283 pRowToMove->Cut(); 2284 pRowToMove->Paste( this ); 2285 } 2286 2287 //Die Fussnoten verschieben! 2288 if ( bMoveFtns ) 2289 if ( ((SwLayoutFrm*)pRowToMove)->MoveLowerFtns( 0, pOldBoss, FindFtnBossFrm( sal_True ), sal_True ) ) 2290 GetUpper()->Calc(); 2291 2292 pRowToMove = pNextRow; 2293 } 2294 2295 if ( nOld != (Frm().*fnRect->fnGetHeight)() ) 2296 lcl_RecalcTable( *this, (SwLayoutFrm*)pRow, aNotify ); 2297 2298 continue; 2299 } 2300 } 2301 } 2302 else if ( KEEPTAB ) 2303 { 2304 bool bFormat = false; 2305 if ( bKeep ) 2306 bFormat = true; 2307 else if ( bTableRowKeep && !bLastRowMoveNoMoreTries ) 2308 { 2309 // We only want to give the last row one chance to move 2310 // to the follow table. Set the flag as early as possible: 2311 bLastRowMoveNoMoreTries = true; 2312 2313 // The last line of the table has to be cut off if: 2314 // 1. The table does not want to keep with its next 2315 // 2. The compatibility option is set and the table is allowed to split 2316 // 3. We did not already cut off the last row 2317 // 4. There is not break after attribute set at the table 2318 // 5. There is no break before attribute set behind the table 2319 // 6. There is no section change behind the table (see IsKeep) 2320 // 7. The last table row wants to keep with its next. 2321 const SwRowFrm* pLastRow = static_cast<const SwRowFrm*>(GetLastLower()); 2322 if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) && 2323 pLastRow->ShouldRowKeepWithNext() ) 2324 bFormat = true; 2325 } 2326 2327 if ( bFormat ) 2328 { 2329 delete pAccess; 2330 2331 // --> OD 2005-09-28 #b6329202# 2332 // Consider case that table is inside another table, because 2333 // it has to be avoided, that superior table is formatted. 2334 // Thus, find next content, table or section and, if a section 2335 // is found, get its first content. 2336 const SwFrm* pTmpNxt = lcl_FormatNextCntntForKeep( this ); 2337 // <-- 2338 2339 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); 2340 pAttrs = pAccess->Get(); 2341 2342 // The last row wants to keep with the frame behind the table. 2343 // Check if the next frame is on a different page and valid. 2344 // In this case we do a magic trick: 2345 if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->IsValid() ) 2346 { 2347 bValidPos = sal_False; 2348 bLastRowHasToMoveToFollow = true; 2349 } 2350 } 2351 } 2352 2353 if ( IsValid() ) 2354 { 2355 if ( bCalcLowers ) 2356 { 2357 lcl_RecalcTable( *this, 0, aNotify ); 2358 bLowersFormatted = sal_True; 2359 bCalcLowers = sal_False; 2360 } 2361 else if ( bONECalcLowers ) 2362 { 2363 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); 2364 bONECalcLowers = sal_False; 2365 } 2366 } 2367 continue; 2368 } 2369 2370 //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt 2371 //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen 2372 2373 //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe 2374 //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man 2375 //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und 2376 //zwar mit aller Kraft. 2377 if ( !bMoveable ) 2378 { 2379 if ( bCalcLowers && IsValid() ) 2380 { 2381 lcl_RecalcTable( *this, 0, aNotify ); 2382 bLowersFormatted = sal_True; 2383 bCalcLowers = sal_False; 2384 } 2385 else if ( bONECalcLowers ) 2386 { 2387 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); 2388 bONECalcLowers = sal_False; 2389 } 2390 2391 // It does not make sense to cut off the last line if we are 2392 // not moveable: 2393 bLastRowHasToMoveToFollow = false; 2394 2395 continue; 2396 } 2397 2398 if ( bCalcLowers && IsValid() ) 2399 { 2400 lcl_RecalcTable( *this, 0, aNotify ); 2401 bLowersFormatted = sal_True; 2402 bCalcLowers = sal_False; 2403 if( !IsValid() ) 2404 continue; 2405 } 2406 2407 // 2408 // First try to split the table. Condition: 2409 // 1. We have at least one non headline row 2410 // 2. If this row wants to keep, we need an additional row 2411 // 3. The table is allowed to split or we do not have an pIndPrev: 2412 // 2413 SwFrm* pIndPrev = GetIndPrev(); 2414 const SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); 2415 // #120016# if this row wants to keep, allow split in case that all rows want to keep with next, 2416 // the table can not move forward as it is the first one and a split is in general allowed. 2417 const bool bAllowSplitOfRow = ( bTableRowKeep && 2418 AreAllRowsKeepWithNext( pFirstNonHeadlineRow ) ) && 2419 !pIndPrev && 2420 !bDontSplit; 2421 2422 if ( pFirstNonHeadlineRow && nUnSplitted > 0 && 2423 ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() || !pFirstNonHeadlineRow->ShouldRowKeepWithNext() || bAllowSplitOfRow ) && 2424 ( !bDontSplit || !pIndPrev ) ) 2425 { 2426 // --> FME 2004-06-03 #i29438# 2427 // Special DoNotSplit case: 2428 // We better avoid splitting of a row frame if we are inside a columned 2429 // section which has a height of 0, because this is not growable and thus 2430 // all kinds of unexpected things could happen. 2431 const SwSectionFrm* pTmpSct = 0; 2432 if ( IsInSct() && 2433 (pTmpSct = FindSctFrm())->Lower()->IsColumnFrm() && 2434 0 == (GetUpper()->Frm().*fnRect->fnGetHeight)() ) 2435 { 2436 bTryToSplit = false; 2437 } 2438 // <-- 2439 2440 // 1. Try: bTryToSplit = true => Try to split the row. 2441 // 2. Try: bTryToSplit = false => Split the table between the rows. 2442 if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit ) 2443 { 2444 SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); 2445 if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE) 2446 nDeadLine = (*fnRect->fnYInc)( nDeadLine, 2447 GetUpper()->Grow( LONG_MAX, sal_True ) ); 2448 2449 { 2450 SetInRecalcLowerRow( true ); 2451 ::lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), nDeadLine ); 2452 SetInRecalcLowerRow( false ); 2453 } 2454 bLowersFormatted = sal_True; 2455 aNotify.SetLowersComplete( sal_True ); 2456 2457 // One more check if its really necessary to split the table. 2458 // 1. The table either has to exceed the deadline or 2459 // 2. We explicitly want to cut off the last row. 2460 if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 && !bLastRowHasToMoveToFollow ) 2461 { 2462 continue; 2463 } 2464 2465 // Set to false again as early as possible. 2466 bLastRowHasToMoveToFollow = false; 2467 2468 // --> FME 2005-08-03 #i52781# 2469 // YaSC - Yet another special case: 2470 // If our upper is inside a table cell which is not allowed 2471 // to split, we do not try to split: 2472 if ( GetUpper()->IsInTab() ) 2473 { 2474 const SwFrm* pTmpRow = GetUpper(); 2475 while ( pTmpRow && !pTmpRow->IsRowFrm() ) 2476 pTmpRow = pTmpRow->GetUpper(); 2477 if ( pTmpRow && !static_cast<const SwRowFrm*>(pTmpRow)->IsRowSplitAllowed() ) 2478 continue; 2479 } 2480 // <-- 2481 2482 sal_uInt16 nMinNumOfLines = nRepeat; 2483 2484 if ( bTableRowKeep ) 2485 { 2486 const SwRowFrm* pTmpRow = pFirstNonHeadlineRow; 2487 while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) 2488 { 2489 ++nMinNumOfLines; 2490 pTmpRow = static_cast<const SwRowFrm*>(pTmpRow->GetNext()); 2491 } 2492 // Check if all lines want to keep together and we 2493 // have a pIndPrev. In this case we set nDeadLine 2494 // to 0, forcing the table to move forward. 2495 if ( !pTmpRow && pIndPrev ) 2496 nDeadLine = 0; 2497 } 2498 2499 if ( !bTryToSplit ) 2500 ++nMinNumOfLines; 2501 2502 const SwTwips nBreakLine = (*fnRect->fnYInc)( 2503 (Frm().*fnRect->fnGetTop)(), 2504 (this->*fnRect->fnGetTopMargin)() + 2505 lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) ); 2506 2507 // Some more checks if we want to call the split algorithm or not: 2508 // The repeating lines / keeping lines still fit into the upper or 2509 // if we do not have an (in)direkt Prev, we split anyway. 2510 if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev ) 2511 { 2512 aNotify.SetLowersComplete( sal_False ); 2513 bSplit = sal_True; 2514 2515 // 2516 // An existing follow flow line has to be removed. 2517 // 2518 if ( HasFollowFlowLine() ) 2519 { 2520 RemoveFollowFlowLine(); 2521 } 2522 2523 const bool bSplitError = !Split( nDeadLine, bTryToSplit, ( bTableRowKeep && !bAllowSplitOfRow ) ); 2524 if( !bTryToSplit && !bSplitError && nUnSplitted > 0 ) 2525 { 2526 --nUnSplitted; 2527 } 2528 2529 // --> FME 2004-06-09 #i29771# Two tries to split the table: 2530 // If an error occurred during splitting. We start a second 2531 // try, this time without splitting of table rows. 2532 if ( bSplitError ) 2533 { 2534 if ( HasFollowFlowLine() ) 2535 RemoveFollowFlowLine(); 2536 } 2537 2538 // --> FME 2005-02-10 #119477# 2539 // If splitting the table was successful or not, 2540 // we do not want to have 'empty' follow tables. 2541 if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() ) 2542 Join(); 2543 // <-- 2544 2545 2546 // We want to restore the situation before the failed 2547 // split operation as good as possible. Therefore we 2548 // do some more calculations. Note: Restricting this 2549 // to nDeadLine may not be enough. 2550 if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426 2551 { 2552 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); 2553 bValidPos = sal_False; 2554 bTryToSplit = false; 2555 continue; 2556 } 2557 // <-- 2558 2559 bTryToSplit = !bSplitError; 2560 2561 //Damit es nicht zu Oszillationen kommt, muss der 2562 //Follow gleich gueltig gemacht werden. 2563 if ( GetFollow() ) 2564 { 2565 // --> OD 2007-11-30 #i80924# 2566 // After a successful split assure that the first row 2567 // is invalid. When graphics are present, this isn't hold. 2568 // Note: defect i80924 could also be fixed, if it is 2569 // assured, that <SwLayNotify::bLowersComplete> is only 2570 // set, if all lower are valid *and* are correct laid out. 2571 if ( !bSplitError && GetFollow()->GetLower() ) 2572 { 2573 GetFollow()->GetLower()->InvalidatePos(); 2574 } 2575 // <-- 2576 SWRECTFNX( GetFollow() ) 2577 2578 static sal_uInt8 nStack = 0; 2579 if ( !StackHack::IsLocked() && nStack < 4 ) 2580 { 2581 ++nStack; 2582 StackHack aHack; 2583 delete pAccess; 2584 2585 GetFollow()->MakeAll(); 2586 2587 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); 2588 pAttrs = pAccess->Get(); 2589 2590 ((SwTabFrm*)GetFollow())->SetLowersFormatted(sal_False); 2591 // --> OD 2005-03-30 #i43913# - lock follow table 2592 // to avoid its formatting during the format of 2593 // its content. 2594 const bool bOldJoinLock = GetFollow()->IsJoinLocked(); 2595 GetFollow()->LockJoin(); 2596 // <-- 2597 ::lcl_RecalcRow( static_cast<SwRowFrm&>(*GetFollow()->Lower()), 2598 (GetFollow()->GetUpper()->Frm().*fnRectX->fnGetBottom)() ); 2599 // --> OD 2005-03-30 #i43913# 2600 // --> FME 2006-04-05 #i63632# Do not unlock the 2601 // follow if it wasn't locked before. 2602 if ( !bOldJoinLock ) 2603 GetFollow()->UnlockJoin(); 2604 // <-- 2605 2606 if ( !GetFollow()->GetFollow() ) 2607 { 2608 SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext(); 2609 if ( pNxt ) 2610 { 2611 // no formatting of found next frame, if its a follow 2612 // section of the 'ColLocked' section, the follow table is in. 2613 bool bCalcNxt = true; 2614 if ( GetFollow()->IsInSct() && pNxt->IsSctFrm() ) 2615 { 2616 SwSectionFrm* pSct = GetFollow()->FindSctFrm(); 2617 if ( pSct->IsColLocked() && 2618 pSct->GetFollow() == pNxt ) 2619 { 2620 bCalcNxt = false; 2621 } 2622 } 2623 if ( bCalcNxt ) 2624 { 2625 pNxt->Calc(); 2626 } 2627 } 2628 } 2629 --nStack; 2630 } 2631 else if ( GetFollow() == GetNext() ) 2632 ((SwTabFrm*)GetFollow())->MoveFwd( sal_True, sal_False ); 2633 } 2634 continue; 2635 } 2636 } 2637 } 2638 2639 // Set to false again as early as possible. 2640 bLastRowHasToMoveToFollow = false; 2641 2642 if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() && 2643 GetUpper()->GetUpper()->GetUpper()->IsSctFrm() && 2644 ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) && 2645 ((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) ) 2646 { 2647 bMovedFwd = sal_False; 2648 } 2649 2650 // --> FME 2004-06-09 #i29771# Reset bTryToSplit flag on change of upper 2651 const SwFrm* pOldUpper = GetUpper(); 2652 // <-- 2653 2654 //Mal sehen ob ich irgenwo Platz finde... 2655 if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) ) 2656 bMakePage = sal_False; 2657 2658 // Reset bSplitError flag on change of upper 2659 if ( GetUpper() != pOldUpper ) 2660 { 2661 bTryToSplit = true; 2662 nUnSplitted = 5; 2663 } 2664 2665 SWREFRESHFN( this ) 2666 bMovedFwd = bCalcLowers = sal_True; 2667 aNotify.SetLowersComplete( sal_False ); 2668 if ( IsFollow() ) 2669 { 2670 //Um Oszillationen zu vermeiden sollte kein ungueltiger Master 2671 //zurueckbleiben. 2672 SwTabFrm *pTab = FindMaster(); 2673 if ( pTab->GetUpper() ) 2674 pTab->GetUpper()->Calc(); 2675 pTab->Calc(); 2676 pTab->SetLowersFormatted( sal_False ); 2677 } 2678 2679 //Wenn mein direkter Nachbar jetzt gleichzeitig mein Follow ist 2680 //verleibe ich mir das Teil ein. 2681 if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() ) 2682 { 2683 if ( HasFollowFlowLine() ) 2684 RemoveFollowFlowLine(); 2685 if ( GetFollow() ) 2686 Join(); 2687 } 2688 2689 if ( bMovedBwd && GetUpper() ) 2690 { 2691 //Beim zurueckfliessen wurde der Upper angeregt sich vollstaendig 2692 //zu Painten, dass koennen wir uns jetzt nach dem hin und her 2693 //fliessen sparen. 2694 GetUpper()->ResetCompletePaint(); 2695 } 2696 2697 if ( bCalcLowers && IsValid() ) 2698 { 2699 // format of lower frames unnecessary and can cause layout loops, 2700 // if table doesn't fit and isn't allowed to split. 2701 SwTwips nDistToUpperPrtBottom = 2702 (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); 2703 if ( nDistToUpperPrtBottom >= 0 || bTryToSplit ) 2704 { 2705 lcl_RecalcTable( *this, 0, aNotify ); 2706 bLowersFormatted = sal_True; 2707 bCalcLowers = sal_False; 2708 } 2709 #if OSL_DEBUG_LEVEL > 1 2710 else 2711 { 2712 ASSERT( false, "debug assertion: <SwTabFrm::MakeAll()> - format of table lowers suppressed by fix i44910" ); 2713 } 2714 #endif 2715 } 2716 2717 } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) 2718 2719 //Wenn mein direkter Vorgaenger jetzt mein Master ist, so kann er mich 2720 //bei der nachstbesten Gelegenheit vernichten. 2721 if ( IsFollow() ) 2722 { 2723 SwFrm *pPre = GetPrev(); 2724 if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) 2725 pPre->InvalidatePos(); 2726 } 2727 2728 bCalcLowers = bONECalcLowers = sal_False; 2729 delete pAccess; 2730 UnlockJoin(); 2731 if ( bMovedFwd || bMovedBwd || !bOldValidPos ) 2732 aNotify.SetInvaKeep(); 2733 } 2734 2735 /************************************************************************* 2736 |* 2737 |* SwTabFrm::CalcFlyOffsets() 2738 |* 2739 |* Beschreibung: Berechnet die Offsets, die durch FlyFrames 2740 |* entstehen. 2741 |* Ersterstellung MA/MIB 14. Apr. 99 2742 |* Letzte Aenderung 2743 |* 2744 |*************************************************************************/ 2745 sal_Bool SwTabFrm::CalcFlyOffsets( SwTwips& rUpper, 2746 long& rLeftOffset, 2747 long& rRightOffset ) const 2748 { 2749 sal_Bool bInvalidatePrtArea = sal_False; 2750 const SwPageFrm *pPage = FindPageFrm(); 2751 const SwFlyFrm* pMyFly = FindFlyFrm(); 2752 2753 // --> #108724# Page header/footer content doesn't have to wrap around 2754 // floating screen objects 2755 2756 const IDocumentSettingAccess* pIDSA = GetFmt()->getIDocumentSettingAccess(); 2757 const bool bWrapAllowed = pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) || 2758 ( !IsInFtn() && 0 == FindFooterOrHeader() ); 2759 // <-- 2760 2761 if ( pPage->GetSortedObjs() && bWrapAllowed ) 2762 { 2763 SWRECTFN( this ) 2764 const bool bConsiderWrapOnObjPos = pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION); 2765 long nPrtPos = (Frm().*fnRect->fnGetTop)(); 2766 nPrtPos = (*fnRect->fnYInc)( nPrtPos, rUpper ); 2767 SwRect aRect( Frm() ); 2768 long nYDiff = (*fnRect->fnYDiff)( (Prt().*fnRect->fnGetTop)(), rUpper ); 2769 if( nYDiff > 0 ) 2770 (aRect.*fnRect->fnAddBottom)( -nYDiff ); 2771 for ( sal_uInt16 i = 0; i < pPage->GetSortedObjs()->Count(); ++i ) 2772 { 2773 SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i]; 2774 if ( pAnchoredObj->ISA(SwFlyFrm) ) 2775 { 2776 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); 2777 const SwRect aFlyRect = pFly->GetObjRectWithSpaces(); 2778 // --> OD 2004-10-07 #i26945# - correction of conditions, 2779 // if Writer fly frame has to be considered: 2780 // - no need to check, if top of Writer fly frame differs 2781 // from WEIT_WECH, because its also check, if the Writer 2782 // fly frame rectangle overlaps with <aRect> 2783 // - no check, if bottom of anchor frame is prior the top of 2784 // the table, because Writer fly frames can be negative positioned. 2785 // - correct check, if the Writer fly frame is an lower of the 2786 // table, because table lines/rows can split and a at-character 2787 // anchored Writer fly frame could be positioned in the follow 2788 // flow line. 2789 // - add condition, that an existing anchor character text frame 2790 // has to be on the same page as the table. 2791 // E.g., it could happen, that the fly frame is still registered 2792 // at the page frame, the table is on, but it's anchor character 2793 // text frame has already changed its page. 2794 //if ( WEIT_WECH != (pFly->Frm().*fnRect->fnGetTop)() && 2795 // pFly->IsFlyAtCntFrm() && aFlyRect.IsOver( aRect ) && 2796 // // OD 25.02.2003 #i9040# - use '<=' instead of '<' 2797 // (*fnRect->fnYDiff)( 2798 // (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetBottom)(), 2799 // (Frm().*fnRect->fnGetTop)() ) <= 0 && 2800 // !IsAnLower( pFly ) && !pFly->IsAnLower( this ) && 2801 // ( !pMyFly || pMyFly->IsAnLower( pFly ) ) && 2802 // pPage->GetPhyPageNum() >= 2803 // pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() && 2804 // // anchor should be in same page body/header/footer 2805 // ( pFly->GetAnchorFrm()->FindFooterOrHeader() == 2806 // FindFooterOrHeader() ) ) 2807 const SwTxtFrm* pAnchorCharFrm = pFly->FindAnchorCharFrm(); 2808 bool bConsiderFly = 2809 // --> OD 2005-04-06 #i46807# - do not consider invalid 2810 // Writer fly frames. 2811 pFly->IsValid() && 2812 // <-- 2813 // fly anchored at character 2814 pFly->IsFlyAtCntFrm() && 2815 // fly overlaps with corresponding table rectangle 2816 aFlyRect.IsOver( aRect ) && 2817 // fly isn't lower of table and 2818 // anchor character frame of fly isn't lower of table 2819 ( !IsAnLower( pFly ) && 2820 ( !pAnchorCharFrm || !IsAnLower( pAnchorCharFrm ) ) ) && 2821 // table isn't lower of fly 2822 !pFly->IsAnLower( this ) && 2823 // fly is lower of fly, the table is in 2824 // --> OD 2005-05-31 #123274# - correction: 2825 // assure that fly isn't a lower of a fly, the table isn't in. 2826 // E.g., a table in the body doesn't wrap around a graphic, 2827 // which is inside a frame. 2828 ( ( !pMyFly || 2829 pMyFly->IsAnLower( pFly ) ) && 2830 pMyFly == pFly->GetAnchorFrmContainingAnchPos()->FindFlyFrm() ) && 2831 // <-- 2832 // anchor frame not on following page 2833 pPage->GetPhyPageNum() >= 2834 pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() && 2835 // anchor character text frame on same page 2836 ( !pAnchorCharFrm || 2837 pAnchorCharFrm->FindPageFrm()->GetPhyPageNum() == 2838 pPage->GetPhyPageNum() ); 2839 2840 if ( bConsiderFly ) 2841 { 2842 const SwFrm* pFlyHeaderFooterFrm = pFly->GetAnchorFrm()->FindFooterOrHeader(); 2843 const SwFrm* pThisHeaderFooterFrm = FindFooterOrHeader(); 2844 2845 if ( pFlyHeaderFooterFrm != pThisHeaderFooterFrm && 2846 // --> FME 2007-07-02 #148493# If bConsiderWrapOnObjPos is set, 2847 // we want to consider the fly if it is located in the header and 2848 // the table is located in the body: 2849 ( !bConsiderWrapOnObjPos || 0 != pThisHeaderFooterFrm || !pFlyHeaderFooterFrm->IsHeaderFrm() ) ) 2850 bConsiderFly = false; 2851 // <-- 2852 } 2853 2854 if ( bConsiderFly ) 2855 // <-- 2856 { 2857 const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround(); 2858 const SwFmtHoriOrient &rHori= pFly->GetFmt()->GetHoriOrient(); 2859 if ( SURROUND_NONE == rSur.GetSurround() ) 2860 { 2861 long nBottom = (aFlyRect.*fnRect->fnGetBottom)(); 2862 if( (*fnRect->fnYDiff)( nPrtPos, nBottom ) < 0 ) 2863 nPrtPos = nBottom; 2864 bInvalidatePrtArea = sal_True; 2865 } 2866 if ( (SURROUND_RIGHT == rSur.GetSurround() || 2867 SURROUND_PARALLEL == rSur.GetSurround())&& 2868 text::HoriOrientation::LEFT == rHori.GetHoriOrient() ) 2869 { 2870 const long nWidth = (*fnRect->fnXDiff)( 2871 (aFlyRect.*fnRect->fnGetRight)(), 2872 (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetLeft)() ); 2873 rLeftOffset = Max( rLeftOffset, nWidth ); 2874 bInvalidatePrtArea = sal_True; 2875 } 2876 if ( (SURROUND_LEFT == rSur.GetSurround() || 2877 SURROUND_PARALLEL == rSur.GetSurround())&& 2878 text::HoriOrientation::RIGHT == rHori.GetHoriOrient() ) 2879 { 2880 const long nWidth = (*fnRect->fnXDiff)( 2881 (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetRight)(), 2882 (aFlyRect.*fnRect->fnGetLeft)() ); 2883 rRightOffset = Max( rRightOffset, nWidth ); 2884 bInvalidatePrtArea = sal_True; 2885 } 2886 } 2887 } 2888 } 2889 rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() ); 2890 } 2891 2892 return bInvalidatePrtArea; 2893 } 2894 2895 /************************************************************************* 2896 |* 2897 |* SwTabFrm::Format() 2898 |* 2899 |* Beschreibung: "Formatiert" den Frame; Frm und PrtArea 2900 |* Die Fixsize wird hier nicht eingestellt. 2901 |* Ersterstellung MA 09. Mar. 93 2902 |* Letzte Aenderung MA 18. Jun. 97 2903 |* 2904 |*************************************************************************/ 2905 void SwTabFrm::Format( const SwBorderAttrs *pAttrs ) 2906 { 2907 ASSERT( pAttrs, "TabFrm::Format, pAttrs ist 0." ); 2908 2909 SWRECTFN( this ) 2910 if ( !bValidSize ) 2911 { 2912 long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() - 2913 (Frm().*fnRect->fnGetWidth)(); 2914 if( nDiff ) 2915 (aFrm.*fnRect->fnAddRight)( nDiff ); 2916 } 2917 2918 //VarSize ist immer die Hoehe. 2919 //Fuer den oberen/unteren Rand gelten die selben Regeln wie fuer 2920 //cntfrms (sie MakePrtArea() von diesen). 2921 2922 SwTwips nUpper = CalcUpperSpace( pAttrs ); 2923 2924 //Wir wollen Rahmen ausweichen. Zwei Moeglichkeiten: 2925 //1. Es gibt Rahmen mit SurroundNone, diesen wird vollsaendig ausgewichen 2926 //2. Es gibt Rahmen mit Umlauf nur rechts bzw. nur links und diese sind 2927 // rechts bzw. links ausgerichtet, diese geben ein Minimum fuer die 2928 // Raender vor. 2929 long nTmpRight = -1000000, 2930 nLeftOffset = 0; 2931 if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) ) 2932 bValidPrtArea = sal_False; 2933 long nRightOffset = Max( 0L, nTmpRight ); 2934 2935 SwTwips nLower = pAttrs->CalcBottomLine(); 2936 // --> collapsing borders FME 2005-05-27 #i29550# 2937 if ( IsCollapsingBorders() ) 2938 nLower += GetBottomLineSize(); 2939 // <-- collapsing 2940 2941 if ( !bValidPrtArea ) 2942 { bValidPrtArea = sal_True; 2943 2944 //Die Breite der PrtArea wird vom FrmFmt vorgegeben, die Raender 2945 //sind entsprechend einzustellen. 2946 //Mindestraender werden von Umrandung und Schatten vorgegeben. 2947 //Die Rander werden so eingestellt, dass die PrtArea nach dem 2948 //angegebenen Adjustment im Frm ausgerichtet wird. 2949 //Wenn das Adjustment 0 ist, so werden die Rander anhand des 2950 //Randattributes eingestellt. 2951 2952 const SwTwips nOldHeight = (Prt().*fnRect->fnGetHeight)(); 2953 const SwTwips nMax = (aFrm.*fnRect->fnGetWidth)(); 2954 2955 // OD 14.03.2003 #i9040# - adjust variable names. 2956 const SwTwips nLeftLine = pAttrs->CalcLeftLine(); 2957 const SwTwips nRightLine = pAttrs->CalcRightLine(); 2958 2959 //Die Breite ist evtl. eine Prozentangabe. Wenn die Tabelle irgendwo 2960 //'drinsteckt bezieht sie sich auf die Umgebung. Ist es der Body, so 2961 //bezieht sie sich in der BrowseView auf die Bildschirmbreite. 2962 const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); 2963 // OD 14.03.2003 #i9040# - adjust variable name. 2964 const SwTwips nWishedTableWidth = CalcRel( rSz, sal_True ); 2965 2966 sal_Bool bCheckBrowseWidth = sal_False; 2967 2968 // OD 14.03.2003 #i9040# - insert new variables for left/right spacing. 2969 SwTwips nLeftSpacing = 0; 2970 SwTwips nRightSpacing = 0; 2971 switch ( GetFmt()->GetHoriOrient().GetHoriOrient() ) 2972 { 2973 case text::HoriOrientation::LEFT: 2974 { 2975 // left indent: 2976 nLeftSpacing = nLeftLine + nLeftOffset; 2977 // OD 06.03.2003 #i9040# - correct calculation of right indent: 2978 // - Consider right indent given by right line attributes. 2979 // - Consider negative right indent. 2980 // wished right indent determined by wished table width and 2981 // left offset given by surround fly frames on the left: 2982 const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset; 2983 if ( nRightOffset > 0 ) 2984 { 2985 // surrounding fly frames on the right 2986 // -> right indent is maximun of given right offset 2987 // and wished right offset. 2988 nRightSpacing = nRightLine + Max( nRightOffset, nWishRight ); 2989 } 2990 else 2991 { 2992 // no surrounding fly frames on the right 2993 // If intrinsic right indent (intrinsic means not considering 2994 // determined left indent) is negative, 2995 // then hold this intrinsic indent, 2996 // otherwise non negative wished right indent is hold. 2997 nRightSpacing = nRightLine + 2998 ( ( (nWishRight+nLeftOffset) < 0 ) ? 2999 (nWishRight+nLeftOffset) : 3000 Max( 0L, nWishRight ) ); 3001 } 3002 } 3003 break; 3004 case text::HoriOrientation::RIGHT: 3005 { 3006 // right indent: 3007 nRightSpacing = nRightLine + nRightOffset; 3008 // OD 06.03.2003 #i9040# - correct calculation of left indent: 3009 // - Consider left indent given by left line attributes. 3010 // - Consider negative left indent. 3011 // wished left indent determined by wished table width and 3012 // right offset given by surrounding fyl frames on the right: 3013 const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset; 3014 if ( nLeftOffset > 0 ) 3015 { 3016 // surrounding fly frames on the left 3017 // -> right indent is maximun of given left offset 3018 // and wished left offset. 3019 nLeftSpacing = nLeftLine + Max( nLeftOffset, nWishLeft ); 3020 } 3021 else 3022 { 3023 // no surrounding fly frames on the left 3024 // If intrinsic left indent (intrinsic = not considering 3025 // determined right indent) is negative, 3026 // then hold this intrinsic indent, 3027 // otherwise non negative wished left indent is hold. 3028 nLeftSpacing = nLeftLine + 3029 ( ( (nWishLeft+nRightOffset) < 0 ) ? 3030 (nWishLeft+nRightOffset) : 3031 Max( 0L, nWishLeft ) ); 3032 } 3033 } 3034 break; 3035 case text::HoriOrientation::CENTER: 3036 { 3037 // OD 07.03.2003 #i9040# - consider left/right line attribute. 3038 // OD 10.03.2003 #i9040# - 3039 const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2; 3040 nLeftSpacing = nLeftLine + 3041 ( (nLeftOffset > 0) ? 3042 Max( nCenterSpacing, nLeftOffset ) : 3043 nCenterSpacing ); 3044 nRightSpacing = nRightLine + 3045 ( (nRightOffset > 0) ? 3046 Max( nCenterSpacing, nRightOffset ) : 3047 nCenterSpacing ); 3048 } 3049 break; 3050 case text::HoriOrientation::FULL: 3051 //Das Teil dehnt sich ueber die gesamte Breite aus. 3052 //Nur die fuer die Umrandung benoetigten Freiraeume 3053 //werden beruecksichtigt. 3054 //Die Attributwerte von LRSpace werden bewusst missachtet! 3055 bCheckBrowseWidth = sal_True; 3056 nLeftSpacing = nLeftLine + nLeftOffset; 3057 nRightSpacing = nRightLine + nRightOffset; 3058 break; 3059 case text::HoriOrientation::NONE: 3060 { 3061 //Die Raender werden vom Randattribut bestimmt. 3062 nLeftSpacing = pAttrs->CalcLeft( this ); 3063 if( nLeftOffset ) 3064 { 3065 // OD 07.03.2003 #i9040# - surround fly frames only, if 3066 // they overlap with the table. 3067 // Thus, take maximun of left spacing and left offset. 3068 // OD 10.03.2003 #i9040# - consider left line attribute. 3069 nLeftSpacing = Max( nLeftSpacing, ( nLeftOffset + nLeftLine ) ); 3070 } 3071 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> 3072 nRightSpacing = pAttrs->CalcRight( this ); 3073 if( nRightOffset ) 3074 { 3075 // OD 07.03.2003 #i9040# - surround fly frames only, if 3076 // they overlap with the table. 3077 // Thus, take maximun of right spacing and right offset. 3078 // OD 10.03.2003 #i9040# - consider right line attribute. 3079 nRightSpacing = Max( nRightSpacing, ( nRightOffset + nRightLine ) ); 3080 } 3081 // OD 10.03.2003 #i9040# - do not hold wished table width. 3082 /* 3083 if ( !pAttrs->GetLRSpace().GetRight() ) 3084 nRight = Max( nRight, nMax - (nWish + nLeft + nRight)); 3085 */ 3086 } 3087 break; 3088 case text::HoriOrientation::LEFT_AND_WIDTH: 3089 { 3090 //Linker Rand und die Breite zaehlen (Word-Spezialitaet) 3091 // OD 10.03.2003 #i9040# - no width alignment in online mode. 3092 //bCheckBrowseWidth = sal_True; 3093 nLeftSpacing = pAttrs->CalcLeft( this ); 3094 if( nLeftOffset ) 3095 { 3096 // OD 10.03.2003 #i9040# - surround fly frames only, if 3097 // they overlap with the table. 3098 // Thus, take maximun of right spacing and right offset. 3099 // OD 10.03.2003 #i9040# - consider left line attribute. 3100 nLeftSpacing = Max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) ); 3101 } 3102 // OD 10.03.2003 #i9040# - consider right and left line attribute. 3103 const SwTwips nWishRight = 3104 nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth; 3105 nRightSpacing = nRightLine + 3106 ( (nRightOffset > 0) ? 3107 Max( nWishRight, nRightOffset ) : 3108 nWishRight ); 3109 } 3110 break; 3111 default: 3112 ASSERT( sal_False, "Ungueltige orientation fuer Table." ); 3113 } 3114 3115 // --> OD 2004-07-15 #i26250# - extend bottom printing area, if table 3116 // is last content inside a table cell. 3117 if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) && 3118 GetUpper()->IsInTab() && !GetIndNext() ) 3119 { 3120 nLower += pAttrs->GetULSpace().GetLower(); 3121 } 3122 // <-- 3123 (this->*fnRect->fnSetYMargins)( nUpper, nLower ); 3124 if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) ) 3125 (this->*fnRect->fnSetXMargins)( 0, 0 ); 3126 else 3127 (this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing ); 3128 3129 ViewShell *pSh = getRootFrm()->GetCurrShell(); 3130 if ( bCheckBrowseWidth && 3131 pSh && pSh->GetViewOptions()->getBrowseMode() && 3132 GetUpper()->IsPageBodyFrm() && // nur PageBodyFrms, nicht etwa ColBodyFrms 3133 pSh->VisArea().Width() ) 3134 { 3135 //Nicht ueber die Kante des sichbaren Bereiches hinausragen. 3136 //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite" 3137 //geben kann (RootFrm::ImplCalcBrowseWidth()) 3138 long nWidth = pSh->GetBrowseWidth(); 3139 nWidth -= Prt().Left(); 3140 nWidth -= pAttrs->CalcRightLine(); 3141 Prt().Width( Min( nWidth, Prt().Width() ) ); 3142 } 3143 3144 if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() ) 3145 bValidSize = sal_False; 3146 } 3147 3148 if ( !bValidSize ) 3149 { 3150 bValidSize = sal_True; 3151 3152 //Die Groesse wird durch den Inhalt plus den Raendern bestimmt. 3153 SwTwips nRemaining = 0, nDiff; 3154 SwFrm *pFrm = pLower; 3155 while ( pFrm ) 3156 { 3157 nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); 3158 pFrm = pFrm->GetNext(); 3159 } 3160 //Jetzt noch die Raender addieren 3161 nRemaining += nUpper + nLower; 3162 3163 nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining; 3164 if ( nDiff > 0 ) 3165 Shrink( nDiff ); 3166 else if ( nDiff < 0 ) 3167 Grow( -nDiff ); 3168 } 3169 } 3170 /************************************************************************* 3171 |* 3172 |* SwTabFrm::GrowFrm() 3173 |* 3174 |* Ersterstellung MA 12. Mar. 93 3175 |* Letzte Aenderung MA 23. Sep. 96 3176 |* 3177 |*************************************************************************/ 3178 SwTwips SwTabFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) 3179 { 3180 SWRECTFN( this ) 3181 SwTwips nHeight =(Frm().*fnRect->fnGetHeight)(); 3182 if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) ) 3183 nDist = LONG_MAX - nHeight; 3184 3185 if ( bTst && !IsRestrictTableGrowth() ) 3186 return nDist; 3187 3188 if ( GetUpper() ) 3189 { 3190 SwRect aOldFrm( Frm() ); 3191 3192 //Der Upper wird nur soweit wie notwendig gegrowed. In nReal wird erstmal 3193 //die bereits zur Verfuegung stehende Strecke bereitgestellt. 3194 SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)(); 3195 SwFrm *pFrm = GetUpper()->Lower(); 3196 while ( pFrm && GetFollow() != pFrm ) 3197 { 3198 nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); 3199 pFrm = pFrm->GetNext(); 3200 } 3201 3202 long nTmp = 0; 3203 if ( nReal < nDist ) 3204 { 3205 nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo ); 3206 3207 if ( IsRestrictTableGrowth() ) 3208 { 3209 nTmp = Min( nDist, nReal + nTmp ); 3210 nDist = nTmp < 0 ? 0 : nTmp; 3211 } 3212 } 3213 3214 if ( !bTst ) 3215 { 3216 (Frm().*fnRect->fnAddBottom)( nDist ); 3217 3218 SwRootFrm *pRootFrm = getRootFrm(); 3219 if( pRootFrm && pRootFrm->IsAnyShellAccessible() && 3220 pRootFrm->GetCurrShell() ) 3221 { 3222 pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm ); 3223 } 3224 } 3225 } 3226 3227 if ( !bTst && ( nDist || IsRestrictTableGrowth() ) ) 3228 { 3229 SwPageFrm *pPage = FindPageFrm(); 3230 if ( GetNext() ) 3231 { 3232 GetNext()->_InvalidatePos(); 3233 if ( GetNext()->IsCntntFrm() ) 3234 GetNext()->InvalidatePage( pPage ); 3235 } 3236 // --> OD 2004-07-05 #i28701# - Due to the new object positioning the 3237 // frame on the next page/column can flow backward (e.g. it was moved 3238 // forward due to the positioning of its objects ). Thus, invalivate this 3239 // next frame, if document compatibility option 'Consider wrapping style 3240 // influence on object positioning' is ON. 3241 else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) 3242 { 3243 InvalidateNextPos(); 3244 } 3245 // <-- 3246 _InvalidateAll(); 3247 InvalidatePage( pPage ); 3248 SetComplete(); 3249 3250 const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos(); 3251 if ( GPOS_NONE != ePos && GPOS_TILED != ePos ) 3252 SetCompletePaint(); 3253 } 3254 3255 return nDist; 3256 } 3257 /************************************************************************* 3258 |* 3259 |* SwTabFrm::Modify() 3260 |* 3261 |* Ersterstellung MA 14. Mar. 93 3262 |* Letzte Aenderung MA 06. Dec. 96 3263 |* 3264 |*************************************************************************/ 3265 void SwTabFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) 3266 { 3267 sal_uInt8 nInvFlags = 0; 3268 sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); 3269 3270 if( bAttrSetChg ) 3271 { 3272 SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); 3273 SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); 3274 SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); 3275 SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); 3276 while( sal_True ) 3277 { 3278 _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), 3279 (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, 3280 &aOldSet, &aNewSet ); 3281 if( aNIter.IsAtEnd() ) 3282 break; 3283 aNIter.NextItem(); 3284 aOIter.NextItem(); 3285 } 3286 if ( aOldSet.Count() || aNewSet.Count() ) 3287 SwLayoutFrm::Modify( &aOldSet, &aNewSet ); 3288 } 3289 else 3290 _UpdateAttr( pOld, pNew, nInvFlags ); 3291 3292 if ( nInvFlags != 0 ) 3293 { 3294 SwPageFrm *pPage = FindPageFrm(); 3295 InvalidatePage( pPage ); 3296 // if ( nInvFlags & 0x01 ) 3297 // SetCompletePaint(); 3298 if ( nInvFlags & 0x02 ) 3299 _InvalidatePrt(); 3300 if ( nInvFlags & 0x40 ) 3301 _InvalidatePos(); 3302 SwFrm *pTmp; 3303 if ( 0 != (pTmp = GetIndNext()) ) 3304 { 3305 if ( nInvFlags & 0x04 ) 3306 { 3307 pTmp->_InvalidatePrt(); 3308 if ( pTmp->IsCntntFrm() ) 3309 pTmp->InvalidatePage( pPage ); 3310 } 3311 if ( nInvFlags & 0x10 ) 3312 pTmp->SetCompletePaint(); 3313 } 3314 if ( nInvFlags & 0x08 && 0 != (pTmp = GetPrev()) ) 3315 { 3316 pTmp->_InvalidatePrt(); 3317 if ( pTmp->IsCntntFrm() ) 3318 pTmp->InvalidatePage( pPage ); 3319 } 3320 if ( nInvFlags & 0x20 ) 3321 { 3322 if ( pPage && pPage->GetUpper() && !IsFollow() ) 3323 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); 3324 } 3325 if ( nInvFlags & 0x80 ) 3326 InvalidateNextPos(); 3327 } 3328 } 3329 3330 void SwTabFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, 3331 sal_uInt8 &rInvFlags, 3332 SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) 3333 { 3334 sal_Bool bClear = sal_True; 3335 const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; 3336 switch( nWhich ) 3337 { 3338 case RES_TBLHEADLINECHG: 3339 if ( IsFollow() ) 3340 { 3341 // Delete remaining headlines: 3342 SwRowFrm* pLowerRow = 0; 3343 while ( 0 != ( pLowerRow = (SwRowFrm*)Lower() ) && pLowerRow->IsRepeatedHeadline() ) 3344 { 3345 pLowerRow->Cut(); 3346 delete pLowerRow; 3347 } 3348 3349 // insert new headlines 3350 const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat(); 3351 for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx ) 3352 { 3353 bDontCreateObjects = sal_True; //frmtool 3354 SwRowFrm* pHeadline = new SwRowFrm( *GetTable()->GetTabLines()[ nIdx ], this ); 3355 pHeadline->SetRepeatedHeadline( true ); 3356 bDontCreateObjects = sal_False; 3357 pHeadline->Paste( this, pLowerRow ); 3358 } 3359 } 3360 rInvFlags |= 0x02; 3361 break; 3362 3363 case RES_FRM_SIZE: 3364 case RES_HORI_ORIENT: 3365 rInvFlags |= 0x22; 3366 break; 3367 3368 case RES_PAGEDESC: //Attributaenderung (an/aus) 3369 if ( IsInDocBody() ) 3370 { 3371 rInvFlags |= 0x40; 3372 SwPageFrm *pPage = FindPageFrm(); 3373 if ( !GetPrev() ) 3374 CheckPageDescs( pPage ); 3375 if ( pPage && GetFmt()->GetPageDesc().GetNumOffset() ) 3376 ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( sal_True ); 3377 SwDocPosUpdate aMsgHnt( pPage->Frm().Top() ); 3378 GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt ); 3379 } 3380 break; 3381 3382 case RES_BREAK: 3383 rInvFlags |= 0xC0; 3384 break; 3385 3386 case RES_LAYOUT_SPLIT: 3387 if ( !IsFollow() ) 3388 rInvFlags |= 0x40; 3389 break; 3390 case RES_FRAMEDIR : 3391 SetDerivedR2L( sal_False ); 3392 CheckDirChange(); 3393 break; 3394 case RES_COLLAPSING_BORDERS : 3395 rInvFlags |= 0x02; 3396 lcl_InvalidateAllLowersPrt( this ); 3397 break; 3398 case RES_UL_SPACE: 3399 rInvFlags |= 0x1C; 3400 /* kein Break hier */ 3401 3402 default: 3403 bClear = sal_False; 3404 } 3405 if ( bClear ) 3406 { 3407 if ( pOldSet || pNewSet ) 3408 { 3409 if ( pOldSet ) 3410 pOldSet->ClearItem( nWhich ); 3411 if ( pNewSet ) 3412 pNewSet->ClearItem( nWhich ); 3413 } 3414 else 3415 SwLayoutFrm::Modify( pOld, pNew ); 3416 } 3417 } 3418 3419 /************************************************************************* 3420 |* 3421 |* SwTabFrm::GetInfo() 3422 |* 3423 |* Ersterstellung MA 06. Dec. 96 3424 |* Letzte Aenderung MA 26. Jun. 98 3425 |* 3426 |*************************************************************************/ 3427 sal_Bool SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const 3428 { 3429 if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && !IsFollow() ) 3430 { 3431 SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt; 3432 const SwPageFrm *pPage = FindPageFrm(); 3433 if ( pPage ) 3434 { 3435 if ( pPage == rInfo.GetOrigPage() && !GetPrev() ) 3436 { 3437 //Das sollte er sein (kann allenfalls temporaer anders sein, 3438 // sollte uns das beunruhigen?) 3439 rInfo.SetInfo( pPage, this ); 3440 return sal_False; 3441 } 3442 if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() && 3443 (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum())) 3444 { 3445 //Das koennte er sein. 3446 rInfo.SetInfo( pPage, this ); 3447 } 3448 } 3449 } 3450 return sal_True; 3451 } 3452 3453 /************************************************************************* 3454 |* 3455 |* SwTabFrm::FindLastCntnt() 3456 |* 3457 |* Ersterstellung MA 13. Apr. 93 3458 |* Letzte Aenderung MA 15. May. 98 3459 |* 3460 |*************************************************************************/ 3461 SwCntntFrm *SwTabFrm::FindLastCntnt() 3462 { 3463 SwFrm *pRet = pLower; 3464 3465 while ( pRet && !pRet->IsCntntFrm() ) 3466 { 3467 SwFrm *pOld = pRet; 3468 3469 SwFrm *pTmp = pRet; // To skip empty section frames 3470 while ( pRet->GetNext() ) 3471 { 3472 pRet = pRet->GetNext(); 3473 if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() ) 3474 pTmp = pRet; 3475 } 3476 pRet = pTmp; 3477 3478 if ( pRet->GetLower() ) 3479 pRet = pRet->GetLower(); 3480 if ( pRet == pOld ) 3481 { 3482 // Wenn am Ende der letzten Zelle ein spaltiger Bereich steht, 3483 // der eine leere letzte Spalte hat, muessen wir noch die anderen 3484 // Spalten abklappern, dies erledigt SwSectionFrm::FindLastCntnt 3485 if( pRet->IsColBodyFrm() ) 3486 { 3487 #ifdef DBG_UTIL 3488 SwSectionFrm* pSect = pRet->FindSctFrm(); 3489 ASSERT( pSect, "Wo kommt denn die Spalte her?") 3490 ASSERT( IsAnLower( pSect ), "Gespaltene Zelle?" ); 3491 #endif 3492 return pRet->FindSctFrm()->FindLastCntnt(); 3493 } 3494 3495 // 3496 // pRet may be a cell frame without a lower (cell has been split). 3497 // We have to find the last content the hard way: 3498 // 3499 ASSERT( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" ) 3500 const SwFrm* pRow = pRet->GetUpper(); 3501 while ( pRow && !pRow->GetUpper()->IsTabFrm() ) 3502 pRow = pRow->GetUpper(); 3503 SwCntntFrm* pCntntFrm = ((SwLayoutFrm*)pRow)->ContainsCntnt(); 3504 pRet = 0; 3505 3506 while ( pCntntFrm && ((SwLayoutFrm*)pRow)->IsAnLower( pCntntFrm ) ) 3507 { 3508 pRet = pCntntFrm; 3509 pCntntFrm = pCntntFrm->GetNextCntntFrm(); 3510 } 3511 } 3512 } 3513 3514 // #112929# There actually is a situation, which results in pRet = 0: 3515 // Insert frame, insert table via text <-> table. This gives you a frame 3516 // containing a table without any other content frames. Split the table 3517 // and undo the splitting. This operation gives us a table frame without 3518 // a lower. 3519 if ( pRet ) 3520 { 3521 while ( pRet->GetNext() ) 3522 pRet = pRet->GetNext(); 3523 3524 if( pRet->IsSctFrm() ) 3525 pRet = ((SwSectionFrm*)pRet)->FindLastCntnt(); 3526 } 3527 3528 return (SwCntntFrm*)pRet; 3529 } 3530 3531 /************************************************************************* 3532 |* 3533 |* SwTabFrm::GetLeaf() 3534 |* 3535 |* Ersterstellung MA 19. Mar. 93 3536 |* Letzte Aenderung MA 25. Apr. 95 3537 |* 3538 |*************************************************************************/ 3539 SwLayoutFrm *SwTabFrm::GetLeaf( MakePageType eMakePage, sal_Bool bFwd ) 3540 { 3541 SwLayoutFrm *pRet; 3542 if ( bFwd ) 3543 { 3544 pRet = GetNextLeaf( eMakePage ); 3545 while ( IsAnLower( pRet ) ) 3546 pRet = pRet->GetNextLeaf( eMakePage ); 3547 } 3548 else 3549 pRet = GetPrevLeaf(); 3550 if ( pRet ) 3551 pRet->Calc(); 3552 return pRet; 3553 } 3554 3555 /************************************************************************* 3556 |* 3557 |* SwTabFrm::ShouldBwdMoved() 3558 |* 3559 |* Beschreibung Returnwert sagt ob der Frm verschoben werden sollte 3560 |* Ersterstellung MA 10. Jul. 95 3561 |* Letzte Aenderung MA 04. Mar. 97 3562 |* 3563 |*************************************************************************/ 3564 sal_Bool SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, sal_Bool, sal_Bool &rReformat ) 3565 { 3566 rReformat = sal_False; 3567 if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()) ) 3568 { 3569 //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv. 3570 //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen 3571 //moechte die FixSize die gleiche ist, die der Frm selbst hat. 3572 //In diesem Fall kann einfach geprueft werden, ob der Frm genug 3573 //Platz fuer seine VarSize findet, ist dies nicht der Fall kann 3574 //gleich auf das Verschieben verzichtet werden. 3575 //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst 3576 //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise 3577 //aufspalten kann. 3578 //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind 3579 //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn 3580 //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt 3581 //etwas Platz zur Verfuegung steht). 3582 3583 //Die FixSize der Umgebungen in denen Tabellen herumlungern ist immer 3584 //Die Breite. 3585 3586 SwPageFrm *pOldPage = FindPageFrm(), 3587 *pNewPage = pNewUpper->FindPageFrm(); 3588 sal_Bool bMoveAnyway = sal_False; 3589 SwTwips nSpace = 0; 3590 3591 SWRECTFN( this ) 3592 if ( !SwFlowFrm::IsMoveBwdJump() ) 3593 { 3594 3595 long nOldWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); 3596 SWRECTFNX( pNewUpper ); 3597 long nNewWidth = (pNewUpper->Prt().*fnRectX->fnGetWidth)(); 3598 if( Abs( nNewWidth - nOldWidth ) < 2 ) 3599 { 3600 if( sal_False == 3601 ( bMoveAnyway = BwdMoveNecessary( pOldPage, Frm() ) > 1 ) ) 3602 { 3603 SwRect aRect( pNewUpper->Prt() ); 3604 aRect.Pos() += pNewUpper->Frm().Pos(); 3605 const SwFrm *pPrevFrm = pNewUpper->Lower(); 3606 while ( pPrevFrm && pPrevFrm != this ) 3607 { 3608 (aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX-> 3609 fnGetBottom)() ); 3610 pPrevFrm = pPrevFrm->GetNext(); 3611 } 3612 bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1; 3613 3614 // --> FME 2006-01-20 #i54861# Due to changes made in PrepareMake, 3615 // the tabfrm may not have a correct position. Therefore 3616 // it is possible that pNewUpper->Prt().Height == 0. In this 3617 // case the above calculation of nSpace might give wrong 3618 // results and we really do not want to MoveBackwrd into a 3619 // 0 height frame. If nTmpSpace is already <= 0, we take this 3620 // value: 3621 const SwTwips nTmpSpace = (aRect.*fnRectX->fnGetHeight)(); 3622 if ( (pNewUpper->Prt().*fnRectX->fnGetHeight)() > 0 || nTmpSpace <= 0 ) 3623 nSpace = nTmpSpace; 3624 // <-- 3625 3626 const ViewShell *pSh = getRootFrm()->GetCurrShell(); 3627 if( pSh && pSh->GetViewOptions()->getBrowseMode() ) 3628 nSpace += pNewUpper->Grow( LONG_MAX, sal_True ); 3629 } 3630 } 3631 else if( !bLockBackMove ) 3632 bMoveAnyway = sal_True; 3633 } 3634 else if( !bLockBackMove ) 3635 bMoveAnyway = sal_True; 3636 3637 if ( bMoveAnyway ) 3638 return rReformat = sal_True; 3639 else if ( !bLockBackMove && nSpace > 0 ) 3640 { 3641 // --> OD 2004-10-05 #i26945# - check, if follow flow line 3642 // contains frame, which are moved forward due to its object 3643 // positioning. 3644 SwRowFrm* pFirstRow = GetFirstNonHeadlineRow(); 3645 if ( pFirstRow && pFirstRow->IsInFollowFlowRow() && 3646 SwLayouter::DoesRowContainMovedFwdFrm( 3647 *(pFirstRow->GetFmt()->GetDoc()), 3648 *(pFirstRow) ) ) 3649 { 3650 return sal_False; 3651 } 3652 // <-- 3653 SwTwips nTmpHeight = CalcHeightOfFirstContentLine(); 3654 3655 // --> FME 2005-01-17 #118840# 3656 // For some mysterious reason, I changed the good old 3657 // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'. 3658 // This obviously results in problems with table frames in 3659 // sections. Remember: Every twip is sacred. 3660 return nTmpHeight <= nSpace; 3661 // <-- 3662 } 3663 } 3664 return sal_False; 3665 } 3666 3667 /************************************************************************* 3668 |* 3669 |* SwTabFrm::Cut() 3670 |* 3671 |* Ersterstellung MA 23. Feb. 94 3672 |* Letzte Aenderung MA 09. Sep. 98 3673 |* 3674 |*************************************************************************/ 3675 void SwTabFrm::Cut() 3676 { 3677 ASSERT( GetUpper(), "Cut ohne Upper()." ); 3678 3679 SwPageFrm *pPage = FindPageFrm(); 3680 InvalidatePage( pPage ); 3681 SwFrm *pFrm = GetNext(); 3682 if( pFrm ) 3683 { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger 3684 //berechnet der ist jetzt wo er der erste wird obsolete 3685 pFrm->_InvalidatePrt(); 3686 pFrm->_InvalidatePos(); 3687 if ( pFrm->IsCntntFrm() ) 3688 pFrm->InvalidatePage( pPage ); 3689 if( IsInSct() && !GetPrev() ) 3690 { 3691 SwSectionFrm* pSct = FindSctFrm(); 3692 if( !pSct->IsFollow() ) 3693 { 3694 pSct->_InvalidatePrt(); 3695 pSct->InvalidatePage( pPage ); 3696 } 3697 } 3698 } 3699 else 3700 { 3701 InvalidateNextPos(); 3702 //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper 3703 if ( 0 != (pFrm = GetPrev()) ) 3704 { pFrm->SetRetouche(); 3705 pFrm->Prepare( PREP_WIDOWS_ORPHANS ); 3706 pFrm->_InvalidatePos(); 3707 if ( pFrm->IsCntntFrm() ) 3708 pFrm->InvalidatePage( pPage ); 3709 } 3710 //Wenn ich der einzige FlowFrm in meinem Upper bin (war), so muss 3711 //er die Retouche uebernehmen. 3712 //Ausserdem kann eine Leerseite entstanden sein. 3713 else 3714 { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); 3715 pRoot->SetSuperfluous(); 3716 GetUpper()->SetCompletePaint(); 3717 if( IsInSct() ) 3718 { 3719 SwSectionFrm* pSct = FindSctFrm(); 3720 if( !pSct->IsFollow() ) 3721 { 3722 pSct->_InvalidatePrt(); 3723 pSct->InvalidatePage( pPage ); 3724 } 3725 } 3726 } 3727 } 3728 3729 //Erst removen, dann Upper Shrinken. 3730 SwLayoutFrm *pUp = GetUpper(); 3731 SWRECTFN( this ) 3732 Remove(); 3733 if ( pUp ) 3734 { 3735 ASSERT( !pUp->IsFtnFrm(), "Tabelle in Fussnote." ); 3736 SwSectionFrm *pSct = 0; 3737 // --> OD 2006-01-04 #126020# - adjust check for empty section 3738 // --> OD 2006-02-01 #130797# - correct fix #126020# 3739 if ( !pUp->Lower() && pUp->IsInSct() && 3740 !(pSct = pUp->FindSctFrm())->ContainsCntnt() && 3741 !pSct->ContainsAny( true ) ) 3742 // <-- 3743 { 3744 if ( pUp->GetUpper() ) 3745 { 3746 pSct->DelEmpty( sal_False ); 3747 pSct->_InvalidateSize(); 3748 } 3749 } 3750 else if( (Frm().*fnRect->fnGetHeight)() ) 3751 { 3752 // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section - 3753 // undo changes of fix for #104992# 3754 pUp->Shrink( Frm().Height() ); 3755 } 3756 } 3757 3758 if ( pPage && !IsFollow() && pPage->GetUpper() ) 3759 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); 3760 } 3761 3762 /************************************************************************* 3763 |* 3764 |* SwTabFrm::Paste() 3765 |* 3766 |* Ersterstellung MA 23. Feb. 94 3767 |* Letzte Aenderung MA 09. Sep. 98 3768 |* 3769 |*************************************************************************/ 3770 void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) 3771 { 3772 ASSERT( pParent, "Kein Parent fuer Paste." ); 3773 ASSERT( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); 3774 ASSERT( pParent != this, "Bin selbst der Parent." ); 3775 ASSERT( pSibling != this, "Bin mein eigener Nachbar." ); 3776 ASSERT( !GetPrev() && !GetNext() && !GetUpper(), 3777 "Bin noch irgendwo angemeldet." ); 3778 3779 //In den Baum einhaengen. 3780 InsertBefore( (SwLayoutFrm*)pParent, pSibling ); 3781 3782 _InvalidateAll(); 3783 SwPageFrm *pPage = FindPageFrm(); 3784 InvalidatePage( pPage ); 3785 3786 if ( GetNext() ) 3787 { 3788 GetNext()->_InvalidatePos(); 3789 GetNext()->_InvalidatePrt(); 3790 if ( GetNext()->IsCntntFrm() ) 3791 GetNext()->InvalidatePage( pPage ); 3792 } 3793 3794 SWRECTFN( this ) 3795 if( (Frm().*fnRect->fnGetHeight)() ) 3796 pParent->Grow( (Frm().*fnRect->fnGetHeight)() ); 3797 3798 if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() ) 3799 Prepare( PREP_FIXSIZE_CHG ); 3800 if ( GetPrev() ) 3801 { 3802 if ( !IsFollow() ) 3803 { 3804 GetPrev()->InvalidateSize(); 3805 if ( GetPrev()->IsCntntFrm() ) 3806 GetPrev()->InvalidatePage( pPage ); 3807 } 3808 } 3809 else if ( GetNext() ) 3810 //Bei CntntFrm's gilt es den Abstand zum Vorgaenger/Nachfolger 3811 //zu beachten. Faelle (beide treten immer gleichzeitig auf): 3812 //a) Der Cntnt wird der erste einer Kette 3813 //b) Der neue Nachfolger war vorher der erste einer Kette 3814 GetNext()->_InvalidatePrt(); 3815 3816 if ( pPage && !IsFollow() ) 3817 { 3818 if ( pPage->GetUpper() ) 3819 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); 3820 3821 if ( !GetPrev() )//Mindestens fuer HTML mit Tabelle am Anfang notwendig. 3822 { 3823 const SwPageDesc *pDesc = GetFmt()->GetPageDesc().GetPageDesc(); 3824 if ( (pDesc && pDesc != pPage->GetPageDesc()) || 3825 (!pDesc && pPage->GetPageDesc() != 3826 &(const_cast<const SwDoc *>(GetFmt()->GetDoc()) 3827 ->GetPageDesc(0))) ) 3828 CheckPageDescs( pPage, sal_True ); 3829 } 3830 } 3831 } 3832 3833 /************************************************************************* 3834 |* 3835 |* SwTabFrm::Prepare() 3836 |* 3837 |* Created AMA 01/10/02 3838 |* Last Change AMA 01/10/02 3839 |* 3840 |*************************************************************************/ 3841 void SwTabFrm::Prepare( const PrepareHint eHint, const void *, sal_Bool ) 3842 { 3843 if( PREP_BOSS_CHGD == eHint ) 3844 CheckDirChange(); 3845 } 3846 3847 /************************************************************************* 3848 |* 3849 |* SwRowFrm::SwRowFrm(), ~SwRowFrm() 3850 |* 3851 |* Ersterstellung MA 09. Mar. 93 3852 |* Letzte Aenderung MA 30. May. 96 3853 |* 3854 |*************************************************************************/ 3855 SwRowFrm::SwRowFrm( const SwTableLine &rLine, SwFrm* pSib, bool bInsertContent ): 3856 SwLayoutFrm( rLine.GetFrmFmt(), pSib ), 3857 pTabLine( &rLine ), 3858 pFollowRow( 0 ), 3859 // --> collapsing borders FME 2005-05-27 #i29550# 3860 mnTopMarginForLowers( 0 ), 3861 mnBottomMarginForLowers( 0 ), 3862 mnBottomLineSize( 0 ), 3863 // <-- collapsing 3864 // --> split table rows 3865 bIsFollowFlowRow( false ), 3866 // <-- split table rows 3867 bIsRepeatedHeadline( false ), 3868 mbIsRowSpanLine( false ) 3869 { 3870 nType = FRMC_ROW; 3871 3872 //Gleich die Boxen erzeugen und einfuegen. 3873 const SwTableBoxes &rBoxes = rLine.GetTabBoxes(); 3874 SwFrm *pTmpPrev = 0; 3875 for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) 3876 { 3877 SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], this, bInsertContent ); 3878 pNew->InsertBehind( this, pTmpPrev ); 3879 pTmpPrev = pNew; 3880 } 3881 } 3882 3883 SwRowFrm::~SwRowFrm() 3884 { 3885 SwModify* pMod = GetFmt(); 3886 if( pMod ) 3887 { 3888 pMod->Remove( this ); // austragen, 3889 if( !pMod->GetDepends() ) 3890 delete pMod; // und loeschen 3891 } 3892 } 3893 3894 /************************************************************************* 3895 |* 3896 |* SwRowFrm::RegistFlys() 3897 |* 3898 |* Ersterstellung MA 08. Jul. 93 3899 |* Letzte Aenderung MA 08. Jul. 93 3900 |* 3901 |*************************************************************************/ 3902 void SwRowFrm::RegistFlys( SwPageFrm *pPage ) 3903 { 3904 ::RegistFlys( pPage ? pPage : FindPageFrm(), this ); 3905 } 3906 3907 /************************************************************************* 3908 |* 3909 |* SwRowFrm::Modify() 3910 |* 3911 |* Ersterstellung MA 12. Nov. 97 3912 |* Letzte Aenderung MA 12. Nov. 97 3913 |* 3914 |*************************************************************************/ 3915 void SwRowFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) 3916 { 3917 sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); 3918 const SfxPoolItem *pItem = 0; 3919 3920 if( bAttrSetChg ) 3921 { 3922 const SwAttrSet* pChgSet = ((SwAttrSetChg*)pNew)->GetChgSet(); 3923 pChgSet->GetItemState( RES_FRM_SIZE, sal_False, &pItem); 3924 if ( !pItem ) 3925 pChgSet->GetItemState( RES_ROW_SPLIT, sal_False, &pItem); 3926 } 3927 else if ( RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which() ) 3928 pItem = pNew; 3929 3930 if ( pItem ) 3931 { 3932 SwTabFrm *pTab = FindTabFrm(); 3933 if ( pTab ) 3934 { 3935 const bool bInFirstNonHeadlineRow = pTab->IsFollow() && 3936 this == pTab->GetFirstNonHeadlineRow(); 3937 // --> FME 2004-10-27 #i35063# 3938 // Invalidation required is pRow is last row 3939 if ( bInFirstNonHeadlineRow || !GetNext() ) 3940 // <-- 3941 { 3942 if ( bInFirstNonHeadlineRow ) 3943 pTab = pTab->FindMaster(); 3944 pTab->InvalidatePos(); 3945 } 3946 } 3947 } 3948 3949 SwLayoutFrm::Modify( pOld, pNew ); 3950 } 3951 3952 3953 3954 /************************************************************************* 3955 |* 3956 |* SwRowFrm::MakeAll() 3957 |* 3958 |* Ersterstellung MA 01. Mar. 94 3959 |* Letzte Aenderung MA 01. Mar. 94 3960 |* 3961 |*************************************************************************/ 3962 void SwRowFrm::MakeAll() 3963 { 3964 if ( !GetNext() ) 3965 bValidSize = sal_False; 3966 SwLayoutFrm::MakeAll(); 3967 } 3968 3969 /************************************************************************* 3970 |* 3971 |* SwRowFrm::Format() 3972 |* 3973 |* Ersterstellung MA 13. Mar. 93 3974 |* Letzte Aenderung MA 20. Jun. 96 3975 |* 3976 |*************************************************************************/ 3977 long MA_FASTCALL CalcHeightWidthFlys( const SwFrm *pFrm ) 3978 { 3979 SWRECTFN( pFrm ) 3980 long nHeight = 0; 3981 const SwFrm* pTmp = pFrm->IsSctFrm() ? 3982 ((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm; 3983 while( pTmp ) 3984 { 3985 // --> OD 2004-10-08 #i26945# - consider follow text frames 3986 const SwSortedObjs* pObjs( 0L ); 3987 bool bIsFollow( false ); 3988 if ( pTmp->IsTxtFrm() && static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) 3989 { 3990 const SwFrm* pMaster; 3991 // --> FME 2005-04-01 #i46450# Master does not necessarily have 3992 // to exist if this function is called from JoinFrm() -> 3993 // Cut() -> Shrink() 3994 const SwTxtFrm* pTmpFrm = static_cast<const SwTxtFrm*>(pTmp); 3995 if ( pTmpFrm->GetPrev() && pTmpFrm->GetPrev()->IsTxtFrm() && 3996 static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() && 3997 static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() != pTmp ) 3998 pMaster = 0; 3999 else 4000 pMaster = pTmpFrm->FindMaster(); 4001 4002 if ( pMaster ) 4003 { 4004 pObjs = static_cast<const SwTxtFrm*>(pTmp)->FindMaster()->GetDrawObjs(); 4005 bIsFollow = true; 4006 } 4007 } 4008 else 4009 { 4010 pObjs = pTmp->GetDrawObjs(); 4011 } 4012 if ( pObjs ) 4013 // <-- 4014 { 4015 for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i ) 4016 { 4017 const SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; 4018 // --> OD 2004-10-08 #i26945# - if <pTmp> is follow, the 4019 // anchor character frame has to be <pTmp>. 4020 if ( bIsFollow && 4021 const_cast<SwAnchoredObject*>(pAnchoredObj)->FindAnchorCharFrm() != pTmp ) 4022 { 4023 continue; 4024 } 4025 // <-- 4026 // --> OD 2004-10-04 #i26945# - consider also drawing objects 4027 { 4028 // OD 30.09.2003 #i18732# - only objects, which follow 4029 // the text flow have to be considered. 4030 const SwFrmFmt& rFrmFmt = pAnchoredObj->GetFrmFmt(); 4031 const bool bConsiderObj = 4032 (rFrmFmt.GetAnchor().GetAnchorId() != FLY_AS_CHAR) && 4033 pAnchoredObj->GetObjRect().Top() != WEIT_WECH && 4034 rFrmFmt.GetFollowTextFlow().GetValue() && 4035 pAnchoredObj->GetPageFrm() == pTmp->FindPageFrm(); 4036 if ( bConsiderObj ) 4037 { 4038 const SwFmtFrmSize &rSz = rFrmFmt.GetFrmSize(); 4039 if( !rSz.GetHeightPercent() ) 4040 { 4041 const SwTwips nDistOfFlyBottomToAnchorTop = 4042 (pAnchoredObj->GetObjRect().*fnRect->fnGetHeight)() + 4043 ( bVert ? 4044 pAnchoredObj->GetCurrRelPos().X() : 4045 pAnchoredObj->GetCurrRelPos().Y() ); 4046 4047 const SwTwips nFrmDiff = 4048 (*fnRect->fnYDiff)( 4049 (pTmp->Frm().*fnRect->fnGetTop)(), 4050 (pFrm->Frm().*fnRect->fnGetTop)() ); 4051 4052 nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop + nFrmDiff - 4053 (pFrm->Frm().*fnRect->fnGetHeight)() ); 4054 4055 // --> FME 2006-01-24 #i56115# The first height calculation 4056 // gives wrong results if pFrm->Prt().Y() > 0. We do 4057 // a second calculation based on the actual rectangles of 4058 // pFrm and pAnchoredObj, and use the maximum of the results. 4059 // I do not want to remove the first calculation because 4060 // if clipping has been applied, using the GetCurrRelPos 4061 // might be the better option to calculate nHeight. 4062 const SwTwips nDistOfFlyBottomToAnchorTop2 = (*fnRect->fnYDiff)( 4063 (pAnchoredObj->GetObjRect().*fnRect->fnGetBottom)(), 4064 (pFrm->Frm().*fnRect->fnGetBottom)() ); 4065 4066 nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop2 ); 4067 // <-- 4068 } 4069 } 4070 } 4071 // <-- 4072 } 4073 } 4074 if( !pFrm->IsSctFrm() ) 4075 break; 4076 pTmp = pTmp->FindNextCnt(); 4077 if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) ) 4078 break; 4079 } 4080 return nHeight; 4081 } 4082 4083 SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm& rCell, const SwBorderAttrs& rAttrs ) 4084 { 4085 const SwTabFrm* pTab = rCell.FindTabFrm(); 4086 SwTwips nTopSpace = 0; 4087 SwTwips nBottomSpace = 0; 4088 4089 // --> collapsing borders FME 2005-05-27 #i29550# 4090 if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrm() ) 4091 { 4092 nTopSpace = ((SwRowFrm*)rCell.GetUpper())->GetTopMarginForLowers(); 4093 nBottomSpace = ((SwRowFrm*)rCell.GetUpper())->GetBottomMarginForLowers(); 4094 } 4095 // <-- collapsing 4096 else 4097 { 4098 if ( pTab->IsVertical() != rCell.IsVertical() ) 4099 { 4100 nTopSpace = rAttrs.CalcLeft( &rCell ); 4101 nBottomSpace = rAttrs.CalcRight( &rCell ); 4102 } 4103 else 4104 { 4105 nTopSpace = rAttrs.CalcTop(); 4106 nBottomSpace = rAttrs.CalcBottom(); 4107 } 4108 } 4109 4110 return nTopSpace + nBottomSpace; 4111 } 4112 4113 4114 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to 4115 // control, if floating screen objects have to be considered for the minimal 4116 // cell height. 4117 SwTwips MA_FASTCALL lcl_CalcMinCellHeight( const SwLayoutFrm *_pCell, 4118 const sal_Bool _bConsiderObjs, 4119 const SwBorderAttrs *pAttrs = 0 ) 4120 { 4121 SWRECTFN( _pCell ) 4122 SwTwips nHeight = 0; 4123 const SwFrm* pLow = _pCell->Lower(); 4124 if ( pLow ) 4125 { 4126 long nFlyAdd = 0; 4127 while ( pLow ) 4128 { 4129 // OD 2004-02-18 #106629# - change condition and switch then-body 4130 // and else-body 4131 if ( pLow->IsRowFrm() ) 4132 { 4133 // --> OD 2004-10-04 #i26945# 4134 nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrm*>(pLow), 4135 _bConsiderObjs ); 4136 // <-- 4137 } 4138 else 4139 { 4140 long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)(); 4141 nHeight += nLowHeight; 4142 // --> OD 2004-10-04 #i26945# 4143 if ( _bConsiderObjs ) 4144 { 4145 nFlyAdd = Max( 0L, nFlyAdd - nLowHeight ); 4146 nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) ); 4147 } 4148 // <-- 4149 } 4150 4151 pLow = pLow->GetNext(); 4152 } 4153 if ( nFlyAdd ) 4154 nHeight += nFlyAdd; 4155 } 4156 //Der Border will natuerlich auch mitspielen, er kann leider nicht 4157 //aus PrtArea und Frm errechnet werden, da diese in beliebiger 4158 //Kombination ungueltig sein koennen. 4159 if ( _pCell->Lower() ) 4160 { 4161 if ( pAttrs ) 4162 nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs ); 4163 else 4164 { 4165 SwBorderAttrAccess aAccess( SwFrm::GetCache(), _pCell ); 4166 const SwBorderAttrs &rAttrs = *aAccess.Get(); 4167 nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs ); 4168 } 4169 } 4170 return nHeight; 4171 } 4172 4173 // OD 2004-02-18 #106629# - correct type of 1st parameter 4174 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to control, 4175 // if floating screen objects have to be considered for the minimal cell height 4176 SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm* _pRow, 4177 const sal_Bool _bConsiderObjs ) 4178 { 4179 SWRECTFN( _pRow ) 4180 4181 const SwFmtFrmSize &rSz = _pRow->GetFmt()->GetFrmSize(); 4182 4183 if ( _pRow->HasFixSize() && !_pRow->IsRowSpanLine() ) 4184 { 4185 ASSERT( ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size" ) 4186 return rSz.GetHeight(); 4187 } 4188 4189 SwTwips nHeight = 0; 4190 const SwCellFrm* pLow = static_cast<const SwCellFrm*>(_pRow->Lower()); 4191 while ( pLow ) 4192 { 4193 SwTwips nTmp = 0; 4194 const long nRowSpan = pLow->GetLayoutRowSpan(); 4195 // --> NEW TABLES 4196 // Consider height of 4197 // 1. current cell if RowSpan == 1 4198 // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1 4199 // 3. master cell if RowSpan == -1 4200 if ( 1 == nRowSpan ) 4201 { 4202 nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs ); 4203 } 4204 else if ( -1 == nRowSpan ) 4205 { 4206 // Height of the last cell of a row span is height of master cell 4207 // minus the height of the other rows which are covered by the master 4208 // cell: 4209 const SwCellFrm& rMaster = pLow->FindStartEndOfRowSpanCell( true, true ); 4210 nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs ); 4211 const SwFrm* pMasterRow = rMaster.GetUpper(); 4212 while ( pMasterRow && pMasterRow != _pRow ) 4213 { 4214 nTmp -= (pMasterRow->Frm().*fnRect->fnGetHeight)(); 4215 pMasterRow = pMasterRow->GetNext(); 4216 } 4217 } 4218 // <-- NEW TABLES 4219 4220 // Do not consider rotated cells: 4221 if ( ( 0 != pLow->IsVertical() ) == ( 0 != bVert ) && nTmp > nHeight ) 4222 nHeight = nTmp; 4223 4224 pLow = static_cast<const SwCellFrm*>(pLow->GetNext()); 4225 } 4226 if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE && !_pRow->IsRowSpanLine() ) 4227 nHeight = Max( nHeight, rSz.GetHeight() ); 4228 return nHeight; 4229 } 4230 4231 // --> collapsing borders FME 2005-05-27 #i29550# 4232 4233 // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers: 4234 sal_uInt16 lcl_GetTopSpace( const SwRowFrm& rRow ) 4235 { 4236 sal_uInt16 nTopSpace = 0; 4237 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; 4238 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) 4239 { 4240 sal_uInt16 nTmpTopSpace = 0; 4241 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) 4242 nTmpTopSpace = lcl_GetTopSpace( *(SwRowFrm*)pCurrLower->Lower() ); 4243 else 4244 { 4245 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); 4246 const SvxBoxItem& rBoxItem = rSet.GetBox(); 4247 nTmpTopSpace = rBoxItem.CalcLineSpace( BOX_LINE_TOP, sal_True ); 4248 } 4249 nTopSpace = Max( nTopSpace, nTmpTopSpace ); 4250 } 4251 return nTopSpace; 4252 } 4253 4254 // Calculate the maximum of TopLineDist over all lowers: 4255 sal_uInt16 lcl_GetTopLineDist( const SwRowFrm& rRow ) 4256 { 4257 sal_uInt16 nTopLineDist = 0; 4258 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; 4259 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) 4260 { 4261 sal_uInt16 nTmpTopLineDist = 0; 4262 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) 4263 nTmpTopLineDist = lcl_GetTopLineDist( *(SwRowFrm*)pCurrLower->Lower() ); 4264 else 4265 { 4266 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); 4267 const SvxBoxItem& rBoxItem = rSet.GetBox(); 4268 nTmpTopLineDist = rBoxItem.GetDistance( BOX_LINE_TOP ); 4269 } 4270 nTopLineDist = Max( nTopLineDist, nTmpTopLineDist ); 4271 } 4272 return nTopLineDist; 4273 } 4274 4275 // Calculate the maximum of BottomLineSize over all lowers: 4276 sal_uInt16 lcl_GetBottomLineSize( const SwRowFrm& rRow ) 4277 { 4278 sal_uInt16 nBottomLineSize = 0; 4279 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; 4280 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) 4281 { 4282 sal_uInt16 nTmpBottomLineSize = 0; 4283 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) 4284 { 4285 const SwFrm* pRow = pCurrLower->GetLastLower(); 4286 nTmpBottomLineSize = lcl_GetBottomLineSize( *(SwRowFrm*)pRow ); 4287 } 4288 else 4289 { 4290 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); 4291 const SvxBoxItem& rBoxItem = rSet.GetBox(); 4292 nTmpBottomLineSize = rBoxItem.CalcLineSpace( BOX_LINE_BOTTOM, sal_True ) - 4293 rBoxItem.GetDistance( BOX_LINE_BOTTOM ); 4294 } 4295 nBottomLineSize = Max( nBottomLineSize, nTmpBottomLineSize ); 4296 } 4297 return nBottomLineSize; 4298 } 4299 4300 // Calculate the maximum of BottomLineDist over all lowers: 4301 sal_uInt16 lcl_GetBottomLineDist( const SwRowFrm& rRow ) 4302 { 4303 sal_uInt16 nBottomLineDist = 0; 4304 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; 4305 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) 4306 { 4307 sal_uInt16 nTmpBottomLineDist = 0; 4308 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) 4309 { 4310 const SwFrm* pRow = pCurrLower->GetLastLower(); 4311 nTmpBottomLineDist = lcl_GetBottomLineDist( *(SwRowFrm*)pRow ); 4312 } 4313 else 4314 { 4315 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); 4316 const SvxBoxItem& rBoxItem = rSet.GetBox(); 4317 nTmpBottomLineDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM ); 4318 } 4319 nBottomLineDist = Max( nBottomLineDist, nTmpBottomLineDist ); 4320 } 4321 return nBottomLineDist; 4322 } 4323 4324 // <-- collapsing 4325 4326 void SwRowFrm::Format( const SwBorderAttrs *pAttrs ) 4327 { 4328 SWRECTFN( this ) 4329 ASSERT( pAttrs, "SwRowFrm::Format ohne Attrs." ); 4330 4331 const sal_Bool bFix = bFixSize; 4332 4333 if ( !bValidPrtArea ) 4334 { 4335 //RowFrms haben keine Umrandung usw. also entspricht die PrtArea immer 4336 //dem Frm. 4337 bValidPrtArea = sal_True; 4338 aPrt.Left( 0 ); 4339 aPrt.Top( 0 ); 4340 aPrt.Width ( aFrm.Width() ); 4341 aPrt.Height( aFrm.Height() ); 4342 4343 // --> collapsing borders FME 2005-05-27 #i29550# 4344 // Here we calculate the top-printing area for the lower cell frames 4345 SwTabFrm* pTabFrm = FindTabFrm(); 4346 if ( pTabFrm->IsCollapsingBorders() ) 4347 { 4348 const sal_uInt16 nTopSpace = lcl_GetTopSpace( *this ); 4349 const sal_uInt16 nTopLineDist = lcl_GetTopLineDist( *this ); 4350 const sal_uInt16 nBottomLineSize = lcl_GetBottomLineSize( *this ); 4351 const sal_uInt16 nBottomLineDist = lcl_GetBottomLineDist( *this ); 4352 4353 4354 const SwRowFrm* pPreviousRow = 0; 4355 4356 // --> FME 2004-09-14 #i32456# 4357 // In order to calculate the top printing area for the lower cell 4358 // frames, we have to find the 'previous' row frame and compare 4359 // the bottom values of the 'previous' row with the 'top' values 4360 // of this row. The best way to find the 'previous' row is to 4361 // use the table structure: 4362 const SwTable* pTable = pTabFrm->GetTable(); 4363 const SwTableLine* pPrevTabLine = 0; 4364 const SwRowFrm* pTmpRow = this; 4365 4366 while ( pTmpRow && !pPrevTabLine ) 4367 { 4368 sal_uInt16 nIdx = 0; 4369 const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ? 4370 pTmpRow->GetTabLine()->GetUpper()->GetTabLines() : 4371 pTable->GetTabLines(); 4372 4373 while ( rLines[ nIdx ] != pTmpRow->GetTabLine() ) 4374 ++nIdx; 4375 4376 if ( nIdx > 0 ) 4377 { 4378 // pTmpRow has a 'previous' row in the table structure: 4379 pPrevTabLine = rLines[ nIdx - 1 ]; 4380 } 4381 else 4382 { 4383 // pTmpRow is a first row in the table structue. 4384 // We go up in the table structure: 4385 pTmpRow = pTmpRow->GetUpper()->GetUpper() && 4386 pTmpRow->GetUpper()->GetUpper()->IsRowFrm() ? 4387 static_cast<const SwRowFrm*>( pTmpRow->GetUpper()->GetUpper() ) : 4388 0; 4389 } 4390 } 4391 4392 // If we found a 'previous' row, we look for the appropriate row frame: 4393 if ( pPrevTabLine ) 4394 { 4395 SwIterator<SwRowFrm,SwFmt> aIter( *pPrevTabLine->GetFrmFmt() ); 4396 for ( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() ) 4397 { 4398 // --> OD 2004-11-23 #115759# - do *not* take repeated 4399 // headlines, because during split of table it can be 4400 // invalid and thus can't provide correct border values. 4401 if ( pRow->GetTabLine() == pPrevTabLine && 4402 !pRow->IsRepeatedHeadline() ) 4403 // <-- 4404 { 4405 pPreviousRow = pRow; 4406 break; 4407 } 4408 } 4409 } 4410 // <-- 4411 4412 sal_uInt16 nTopPrtMargin = nTopSpace; 4413 if ( pPreviousRow ) 4414 { 4415 const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist; 4416 if ( nTmpPrtMargin > nTopPrtMargin ) 4417 nTopPrtMargin = nTmpPrtMargin; 4418 } 4419 4420 // table has to be notified if it has to change its lower 4421 // margin due to changes of nBottomLineSize: 4422 if ( !GetNext() && nBottomLineSize != GetBottomLineSize() ) 4423 pTabFrm->_InvalidatePrt(); 4424 4425 // If there are rows nested inside this row, the nested rows 4426 // may not have been calculated yet. Therefore the 4427 // ::lcl_CalcMinRowHeight( this ) operation later in this 4428 // function cannot consider the correct border values. We 4429 // have to trigger the invalidation of the outer row frame 4430 // manually: 4431 // Note: If any further invalidations should be necessary, we 4432 // should consider moving the invalidation stuff to the 4433 // appropriate SwNotify object. 4434 if ( GetUpper()->GetUpper()->IsRowFrm() && 4435 ( nBottomLineDist != GetBottomMarginForLowers() || 4436 nTopPrtMargin != GetTopMarginForLowers() ) ) 4437 GetUpper()->GetUpper()->_InvalidateSize(); 4438 4439 SetBottomMarginForLowers( nBottomLineDist ); // 3. 4440 SetBottomLineSize( nBottomLineSize ); // 4. 4441 SetTopMarginForLowers( nTopPrtMargin ); // 5. 4442 4443 } 4444 // <-- collapsing 4445 } 4446 4447 while ( !bValidSize ) 4448 { 4449 bValidSize = sal_True; 4450 4451 #ifdef DBG_UTIL 4452 if ( HasFixSize() ) 4453 { 4454 const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize(); 4455 ASSERT( rFrmSize.GetSize().Height() > 0, "Hat ihn" ); 4456 } 4457 #endif 4458 const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() - 4459 ( HasFixSize() && !IsRowSpanLine() 4460 ? pAttrs->GetSize().Height() 4461 // --> OD 2004-10-04 #i26945# 4462 : ::lcl_CalcMinRowHeight( this, 4463 FindTabFrm()->IsConsiderObjsForMinCellHeight() ) ); 4464 // <-- 4465 if ( nDiff ) 4466 { 4467 bFixSize = sal_False; 4468 if ( nDiff > 0 ) 4469 Shrink( nDiff, sal_False, sal_True ); 4470 else if ( nDiff < 0 ) 4471 Grow( -nDiff ); 4472 bFixSize = bFix; 4473 } 4474 } 4475 4476 // last row will fill the space in its upper. 4477 if ( !GetNext() ) 4478 { 4479 //Der letzte fuellt den verbleibenden Raum im Upper aus. 4480 SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)(); 4481 SwFrm *pSibling = GetUpper()->Lower(); 4482 do 4483 { nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)(); 4484 pSibling = pSibling->GetNext(); 4485 } while ( pSibling ); 4486 if ( nDiff > 0 ) 4487 { 4488 bFixSize = sal_False; 4489 Grow( nDiff ); 4490 bFixSize = bFix; 4491 bValidSize = sal_True; 4492 } 4493 } 4494 } 4495 4496 /************************************************************************* 4497 |* 4498 |* SwRowFrm::AdjustCells() 4499 |* 4500 |* Ersterstellung MA 10. Aug. 93 4501 |* Letzte Aenderung MA 16. Dec. 96 4502 |* 4503 |*************************************************************************/ 4504 void SwRowFrm::AdjustCells( const SwTwips nHeight, const sal_Bool bHeight ) 4505 { 4506 SwFrm *pFrm = Lower(); 4507 if ( bHeight ) 4508 { 4509 SwRootFrm *pRootFrm = getRootFrm(); 4510 SWRECTFN( this ) 4511 SwRect aOldFrm; 4512 4513 while ( pFrm ) 4514 { 4515 SwFrm* pNotify = 0; 4516 4517 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pFrm); 4518 4519 // NEW TABLES 4520 // Which cells need to be adjusted if the current row changes 4521 // its height? 4522 4523 // Current frame is a covered frame: 4524 // Set new height for covered cell and adjust master cell: 4525 if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) 4526 { 4527 // Set height of current (covered) cell to new line height. 4528 const long nDiff = nHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); 4529 if ( nDiff ) 4530 { 4531 (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); 4532 pCellFrm->_InvalidatePrt(); 4533 } 4534 } 4535 4536 SwCellFrm* pToAdjust = 0; 4537 SwFrm* pToAdjustRow = 0; 4538 4539 // If current frame is covered frame, we still want to adjust the 4540 // height of the cell starting the row span 4541 if ( pCellFrm->GetLayoutRowSpan() < 1 ) 4542 { 4543 pToAdjust = const_cast< SwCellFrm*>(&pCellFrm->FindStartEndOfRowSpanCell( true, true )); 4544 pToAdjustRow = pToAdjust->GetUpper(); 4545 } 4546 else 4547 { 4548 pToAdjust = pCellFrm; 4549 pToAdjustRow = this; 4550 } 4551 4552 // Set height of master cell to height of all lines spanned by this line. 4553 long nRowSpan = pToAdjust->GetLayoutRowSpan(); 4554 SwTwips nSumRowHeight = 0; 4555 while ( pToAdjustRow ) 4556 { 4557 // Use new height for the current row: 4558 nSumRowHeight += pToAdjustRow == this ? 4559 nHeight : 4560 (pToAdjustRow->Frm().*fnRect->fnGetHeight)(); 4561 4562 if ( nRowSpan-- == 1 ) 4563 break; 4564 4565 pToAdjustRow = pToAdjustRow->GetNext(); 4566 } 4567 4568 if ( pToAdjustRow && pToAdjustRow != this ) 4569 pToAdjustRow->_InvalidateSize(); 4570 4571 const long nDiff = nSumRowHeight - (pToAdjust->Frm().*fnRect->fnGetHeight)(); 4572 if ( nDiff ) 4573 { 4574 aOldFrm = pToAdjust->Frm(); 4575 (pToAdjust->Frm().*fnRect->fnAddBottom)( nDiff ); 4576 pNotify = pToAdjust; 4577 } 4578 4579 if ( pNotify ) 4580 { 4581 if( pRootFrm && pRootFrm->IsAnyShellAccessible() && pRootFrm->GetCurrShell() ) 4582 pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pNotify, aOldFrm ); 4583 4584 pNotify->_InvalidatePrt(); 4585 } 4586 4587 pFrm = pFrm->GetNext(); 4588 } 4589 } 4590 else 4591 { while ( pFrm ) 4592 { 4593 pFrm->_InvalidateAll(); 4594 pFrm = pFrm->GetNext(); 4595 } 4596 } 4597 InvalidatePage(); 4598 } 4599 4600 /************************************************************************* 4601 |* 4602 |* SwRowFrm::Cut() 4603 |* 4604 |* Ersterstellung MA 12. Nov. 97 4605 |* Letzte Aenderung MA 12. Nov. 97 4606 |* 4607 |*************************************************************************/ 4608 void SwRowFrm::Cut() 4609 { 4610 SwTabFrm *pTab = FindTabFrm(); 4611 if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() ) 4612 { 4613 pTab->FindMaster()->InvalidatePos(); 4614 } 4615 4616 // --> OD 2010-02-17 #i103961# 4617 // notification for accessibility 4618 { 4619 SwRootFrm *pRootFrm = getRootFrm(); 4620 if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) 4621 { 4622 ViewShell* pVSh = pRootFrm->GetCurrShell(); 4623 if ( pVSh && pVSh->Imp() ) 4624 { 4625 SwFrm* pCellFrm( GetLower() ); 4626 while ( pCellFrm ) 4627 { 4628 ASSERT( pCellFrm->IsCellFrm(), 4629 "<SwRowFrm::Cut()> - unexpected type of SwRowFrm lower." ); 4630 pVSh->Imp()->DisposeAccessibleFrm( pCellFrm ); 4631 4632 pCellFrm = pCellFrm->GetNext(); 4633 } 4634 } 4635 } 4636 } 4637 // <-- 4638 4639 SwLayoutFrm::Cut(); 4640 } 4641 4642 /************************************************************************* 4643 |* 4644 |* SwRowFrm::GrowFrm() 4645 |* 4646 |* Ersterstellung MA 15. Mar. 93 4647 |* Letzte Aenderung MA 05. May. 94 4648 |* 4649 |*************************************************************************/ 4650 4651 4652 SwTwips SwRowFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) 4653 { 4654 SwTwips nReal = 0; 4655 4656 SwTabFrm* pTab = FindTabFrm(); 4657 SWRECTFN( pTab ) 4658 4659 bool bRestrictTableGrowth; 4660 bool bHasFollowFlowLine = pTab->HasFollowFlowLine(); 4661 4662 if ( GetUpper()->IsTabFrm() ) 4663 { 4664 const SwRowFrm* pFollowFlowRow = IsInSplitTableRow(); 4665 bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine(); 4666 } 4667 else 4668 { 4669 ASSERT( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" ) 4670 bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine; 4671 ASSERT( !bRestrictTableGrowth || !GetNext(), 4672 "GetFollowRow for row frame that has a Next" ) 4673 4674 // 4675 // There may still be some space left in my direct upper: 4676 // 4677 const SwTwips nAdditionalSpace = 4678 (Frm().*fnRect->fnBottomDist)( (GetUpper()->GetUpper()->*fnRect->fnGetPrtBottom)() ); 4679 if ( bRestrictTableGrowth && nAdditionalSpace > 0 ) 4680 { 4681 nReal = Min( nAdditionalSpace, nDist ); 4682 nDist -= nReal; 4683 if ( !bTst ) 4684 (Frm().*fnRect->fnAddBottom)( nReal ); 4685 } 4686 } 4687 4688 if ( bRestrictTableGrowth ) 4689 pTab->SetRestrictTableGrowth( sal_True ); 4690 else 4691 { 4692 // Ok, this looks like a hack, indeed, it is a hack. 4693 // If the current row frame is inside another cell frame, 4694 // and the current row frame has no follow, it should not 4695 // be allowed to grow. In fact, setting bRestrictTableGrowth 4696 // to 'false' does not work, because the surrounding RowFrm 4697 // would set this to 'true'. 4698 pTab->SetFollowFlowLine( sal_False ); 4699 } 4700 4701 nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo); 4702 4703 pTab->SetRestrictTableGrowth( sal_False ); 4704 pTab->SetFollowFlowLine( bHasFollowFlowLine ); 4705 4706 //Hoehe der Zellen auf den neuesten Stand bringen. 4707 if ( !bTst ) 4708 { 4709 SWRECTFNX( this ) 4710 AdjustCells( (Prt().*fnRectX->fnGetHeight)() + nReal, sal_True ); 4711 if ( nReal ) 4712 SetCompletePaint(); 4713 } 4714 4715 return nReal; 4716 } 4717 4718 /************************************************************************* 4719 |* 4720 |* SwRowFrm::ShrinkFrm() 4721 |* 4722 |* Ersterstellung MA 15. Mar. 93 4723 |* Letzte Aenderung MA 20. Jun. 96 4724 |* 4725 |*************************************************************************/ 4726 SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) 4727 { 4728 SWRECTFN( this ) 4729 if( HasFixSize() ) 4730 { 4731 AdjustCells( (Prt().*fnRect->fnGetHeight)(), sal_True ); 4732 return 0L; 4733 } 4734 4735 //bInfo wird ggf. vom SwRowFrm::Format auf sal_True gesetzt, hier muss dann 4736 //entsprechend reagiert werden 4737 const sal_Bool bShrinkAnyway = bInfo; 4738 4739 //Nur soweit Shrinken, wie es der Inhalt der groessten Zelle zulaesst. 4740 SwTwips nRealDist = nDist; 4741 { 4742 const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); 4743 SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? 4744 rSz.GetHeight() : 4745 0; 4746 4747 // Only necessary to calculate minimal row height if height 4748 // of pRow is at least nMinHeight. Otherwise nMinHeight is the 4749 // minimum height. 4750 if( nMinHeight < (Frm().*fnRect->fnGetHeight)() ) 4751 { 4752 // --> OD 2004-10-04 #i26945# 4753 ASSERT( FindTabFrm(), "<SwRowFrm::ShrinkFrm(..)> - no table frame -> crash." ); 4754 const bool bConsiderObjs( FindTabFrm()->IsConsiderObjsForMinCellHeight() ); 4755 // <-- 4756 nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs ); 4757 } 4758 4759 if ( ((Frm().*fnRect->fnGetHeight)() - nRealDist) < nMinHeight ) 4760 nRealDist = (Frm().*fnRect->fnGetHeight)() - nMinHeight; 4761 } 4762 if ( nRealDist < 0 ) 4763 nRealDist = 0; 4764 4765 SwTwips nReal = nRealDist; 4766 if ( nReal ) 4767 { 4768 if ( !bTst ) 4769 { 4770 SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); 4771 (Frm().*fnRect->fnSetHeight)( nHeight - nReal ); 4772 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 4773 if( IsVertical() && !IsVertLR() && !bRev ) 4774 Frm().Pos().X() += nReal; 4775 } 4776 4777 SwTwips nTmp = GetUpper()->Shrink( nReal, bTst ); 4778 if ( !bShrinkAnyway && !GetNext() && nTmp != nReal ) 4779 { 4780 //Der letzte bekommt den Rest im Upper und nimmt deshalb 4781 //ggf. Ruecksichten (sonst: Endlosschleife) 4782 if ( !bTst ) 4783 { 4784 nReal -= nTmp; 4785 SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); 4786 (Frm().*fnRect->fnSetHeight)( nHeight + nReal ); 4787 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 4788 if( IsVertical() && !IsVertLR() && !bRev ) 4789 Frm().Pos().X() -= nReal; 4790 } 4791 nReal = nTmp; 4792 } 4793 } 4794 4795 //Geeignet invalidieren und die Hoehe der Zellen auf den neuesten 4796 //Stand bringen. 4797 if ( !bTst ) 4798 { 4799 if ( nReal ) 4800 { 4801 if ( GetNext() ) 4802 GetNext()->_InvalidatePos(); 4803 _InvalidateAll(); 4804 SetCompletePaint(); 4805 4806 SwTabFrm *pTab = FindTabFrm(); 4807 if ( !pTab->IsRebuildLastLine() 4808 && pTab->IsFollow() 4809 && this == pTab->GetFirstNonHeadlineRow() 4810 && !pTab->IsInRecalcLowerRow() ) 4811 { 4812 SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() ); 4813 pMasterTab->InvalidatePos(); 4814 } 4815 } 4816 AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, sal_True ); 4817 } 4818 return nReal; 4819 } 4820 4821 /************************************************************************* 4822 |* 4823 |* SwRowFrm::IsRowSplitAllowed() 4824 |* 4825 |*************************************************************************/ 4826 bool SwRowFrm::IsRowSplitAllowed() const 4827 { 4828 // Fixed size rows are never allowed to split: 4829 if ( HasFixSize() ) 4830 { 4831 ASSERT( ATT_FIX_SIZE == GetFmt()->GetFrmSize().GetHeightSizeType(), "pRow claims to have fixed size" ) 4832 return false; 4833 } 4834 4835 // Repeated headlines are never allowed to split: 4836 const SwTabFrm* pTabFrm = FindTabFrm(); 4837 if ( pTabFrm->GetTable()->GetRowsToRepeat() > 0 && 4838 pTabFrm->IsInHeadline( *this ) ) 4839 return false; 4840 4841 const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)GetTabLine()->GetFrmFmt(); 4842 const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit(); 4843 return 0 != rLP.GetValue(); 4844 } 4845 4846 /************************************************************************* 4847 |* 4848 |* SwRowFrm::ShouldRowKeepWithNext() 4849 |* 4850 |*************************************************************************/ 4851 bool SwRowFrm::ShouldRowKeepWithNext() const 4852 { 4853 bool bRet = false; 4854 4855 const SwCellFrm* pCell = static_cast<const SwCellFrm*>(Lower()); 4856 const SwFrm* pTxt = pCell->Lower(); 4857 4858 if ( pTxt && pTxt->IsTxtFrm() ) 4859 { 4860 bRet = static_cast<const SwTxtFrm*>(pTxt)->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue(); 4861 } 4862 return bRet; 4863 } 4864 4865 /************************************************************************* 4866 |* 4867 |* SwCellFrm::SwCellFrm(), ~SwCellFrm() 4868 |* 4869 |* Ersterstellung MA 09. Mar. 93 4870 |* Letzte Aenderung MA 30. May. 96 4871 |* 4872 |*************************************************************************/ 4873 SwCellFrm::SwCellFrm( const SwTableBox &rBox, SwFrm* pSib, bool bInsertContent ) : 4874 SwLayoutFrm( rBox.GetFrmFmt(), pSib ), 4875 pTabBox( &rBox ) 4876 { 4877 nType = FRMC_CELL; 4878 4879 if ( !bInsertContent ) 4880 return; 4881 4882 //Wenn ein StartIdx vorhanden ist, so werden CntntFrms in der Zelle 4883 //angelegt, andernfalls muessen Rows vorhanden sein und diese werden 4884 //angelegt. 4885 if ( rBox.GetSttIdx() ) 4886 { 4887 sal_uLong nIndex = rBox.GetSttIdx(); 4888 ::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex ); 4889 } 4890 else 4891 { 4892 const SwTableLines &rLines = rBox.GetTabLines(); 4893 SwFrm *pTmpPrev = 0; 4894 for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) 4895 { 4896 SwRowFrm *pNew = new SwRowFrm( *rLines[i], this, bInsertContent ); 4897 pNew->InsertBehind( this, pTmpPrev ); 4898 pTmpPrev = pNew; 4899 } 4900 } 4901 } 4902 4903 SwCellFrm::~SwCellFrm() 4904 { 4905 SwModify* pMod = GetFmt(); 4906 if( pMod ) 4907 { 4908 // At this stage the lower frames aren't destroyed already, 4909 // therfor we have to do a recursive dispose. 4910 SwRootFrm *pRootFrm = getRootFrm(); 4911 if( pRootFrm && pRootFrm->IsAnyShellAccessible() && 4912 pRootFrm->GetCurrShell() ) 4913 { 4914 pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, sal_True ); 4915 } 4916 4917 pMod->Remove( this ); // austragen, 4918 if( !pMod->GetDepends() ) 4919 delete pMod; // und loeschen 4920 } 4921 } 4922 4923 /************************************************************************* 4924 |* 4925 |* SwCellFrm::Format() 4926 |* 4927 |* Ersterstellung MA 09. Mar. 93 4928 |* Letzte Aenderung MA 29. Jan. 98 4929 |* 4930 |*************************************************************************/ 4931 sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ) 4932 { 4933 sal_Bool bRet = sal_False; 4934 SwFrm *pFrm = pLay->Lower(); 4935 SWRECTFN( pLay ) 4936 while ( pFrm ) 4937 { 4938 long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)(); 4939 if( nFrmTop != lYStart ) 4940 { 4941 bRet = sal_True; 4942 const long lDiff = (*fnRect->fnYDiff)( lYStart, nFrmTop ); 4943 const long lDiffX = lYStart - nFrmTop; 4944 (pFrm->Frm().*fnRect->fnSubTop)( -lDiff ); 4945 (pFrm->Frm().*fnRect->fnAddBottom)( lDiff ); 4946 pFrm->SetCompletePaint(); 4947 if ( !pFrm->GetNext() ) 4948 pFrm->SetRetouche(); 4949 if( bInva ) 4950 pFrm->Prepare( PREP_POS_CHGD ); 4951 if ( pFrm->IsLayoutFrm() && ((SwLayoutFrm*)pFrm)->Lower() ) 4952 lcl_ArrangeLowers( (SwLayoutFrm*)pFrm, 4953 (((SwLayoutFrm*)pFrm)->Lower()->Frm().*fnRect->fnGetTop)() 4954 + lDiffX, bInva ); 4955 if ( pFrm->GetDrawObjs() ) 4956 { 4957 for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) 4958 { 4959 SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; 4960 // --> OD 2004-10-08 #i26945# - check, if anchored object 4961 // is lower of layout frame by checking, if the anchor 4962 // frame, which contains the anchor position, is a lower 4963 // of the layout frame. 4964 if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrmContainingAnchPos() ) ) 4965 { 4966 continue; 4967 } 4968 // <-- 4969 // --> OD 2005-08-08 #i52904# - distinguish between anchored 4970 // objects, whose vertical position depends on its anchor 4971 // frame and whose vertical position is independent 4972 // from its anchor frame. 4973 bool bVertPosDepOnAnchor( true ); 4974 { 4975 SwFmtVertOrient aVert( pAnchoredObj->GetFrmFmt().GetVertOrient() ); 4976 switch ( aVert.GetRelationOrient() ) 4977 { 4978 case text::RelOrientation::PAGE_FRAME: 4979 case text::RelOrientation::PAGE_PRINT_AREA: 4980 bVertPosDepOnAnchor = false; 4981 break; 4982 default: break; 4983 } 4984 } 4985 if ( pAnchoredObj->ISA(SwFlyFrm) ) 4986 { 4987 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); 4988 4989 // OD 2004-05-18 #i28701# - no direct move of objects, 4990 // which are anchored to-paragraph/to-character, if 4991 // the wrapping style influence has to be considered 4992 // on the object positioning. 4993 // --> OD 2005-08-08 #i52904# - no direct move of objects, 4994 // whose vertical position doesn't depend on anchor frame. 4995 const bool bDirectMove = 4996 WEIT_WECH != pFly->Frm().Top() && 4997 bVertPosDepOnAnchor && 4998 !pFly->ConsiderObjWrapInfluenceOnObjPos(); 4999 // <-- 5000 if ( bDirectMove ) 5001 { 5002 (pFly->Frm().*fnRect->fnSubTop)( -lDiff ); 5003 (pFly->Frm().*fnRect->fnAddBottom)( lDiff ); 5004 pFly->GetVirtDrawObj()->SetRectsDirty(); 5005 // --> OD 2004-08-17 - also notify view of <SdrObject> 5006 // instance, which represents the Writer fly frame in 5007 // the drawing layer 5008 pFly->GetVirtDrawObj()->SetChanged(); 5009 // <-- 5010 // --> OD 2006-10-13 #i58280# 5011 pFly->InvalidateObjRectWithSpaces(); 5012 // <-- 5013 } 5014 5015 if ( pFly->IsFlyInCntFrm() ) 5016 { 5017 static_cast<SwFlyInCntFrm*>(pFly)->AddRefOfst( lDiff ); 5018 // --> OD 2004-12-02 #115759# - reset current relative 5019 // position to get re-positioned, if not directly moved. 5020 if ( !bDirectMove ) 5021 { 5022 pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); 5023 } 5024 // <-- 5025 } 5026 else if( pFly->IsAutoPos() ) 5027 { 5028 pFly->AddLastCharY( lDiff ); 5029 // OD 2004-05-18 #i28701# - follow-up of #i22341# 5030 // <mnLastTopOfLine> has also been adjusted. 5031 pFly->AddLastTopOfLineY( lDiff ); 5032 } 5033 // --> OD 2004-11-05 #i26945# - re-registration at 5034 // page frame of anchor frame, if table frame isn't 5035 // a follow table and table frame isn't in its 5036 // rebuild of last line. 5037 const SwTabFrm* pTabFrm = pLay->FindTabFrm(); 5038 // --> OD 2004-11-23 #115759# 5039 // - save: check, if table frame is found. 5040 if ( pTabFrm && 5041 !( pTabFrm->IsFollow() && 5042 pTabFrm->FindMaster()->IsRebuildLastLine() ) && 5043 pFly->IsFlyFreeFrm() ) 5044 // <-- 5045 { 5046 SwPageFrm* pPageFrm = pFly->GetPageFrm(); 5047 SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); 5048 if ( pPageFrm != pPageOfAnchor ) 5049 { 5050 pFly->InvalidatePos(); 5051 if ( pPageFrm ) 5052 pPageFrm->MoveFly( pFly, pPageOfAnchor ); 5053 else 5054 pPageOfAnchor->AppendFlyToPage( pFly ); 5055 } 5056 } 5057 // <-- 5058 // OD 2004-05-11 #i28701# - Because of the introduction 5059 // of new positionings and alignments (e.g. aligned at 5060 // page area, but anchored at-character), the position 5061 // of the Writer fly frame has to be invalidated. 5062 pFly->InvalidatePos(); 5063 5064 // --> OD 2004-11-04 #i26945# - follow-up of #i3317# 5065 // No arrangement of lowers, if Writer fly frame isn't 5066 // moved 5067 if ( bDirectMove && 5068 ::lcl_ArrangeLowers( pFly, 5069 (pFly->*fnRect->fnGetPrtTop)(), 5070 bInva ) ) 5071 // <-- 5072 { 5073 pFly->SetCompletePaint(); 5074 } 5075 } 5076 else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) 5077 { 5078 // --> OD 2004-11-05 #i26945# 5079 const SwTabFrm* pTabFrm = pLay->FindTabFrm(); 5080 if ( pTabFrm && 5081 !( pTabFrm->IsFollow() && 5082 pTabFrm->FindMaster()->IsRebuildLastLine() ) && 5083 !pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() 5084 == FLY_AS_CHAR ) 5085 { 5086 SwPageFrm* pPageFrm = pAnchoredObj->GetPageFrm(); 5087 SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); 5088 if ( pPageFrm != pPageOfAnchor ) 5089 { 5090 pAnchoredObj->InvalidateObjPos(); 5091 if ( pPageFrm ) 5092 { 5093 pPageFrm->RemoveDrawObjFromPage( *pAnchoredObj ); 5094 } 5095 pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj ); 5096 } 5097 } 5098 // --> OD 2004-07-01 #i28701# - adjust last character 5099 // rectangle and last top of line. 5100 pAnchoredObj->AddLastCharY( lDiff ); 5101 pAnchoredObj->AddLastTopOfLineY( lDiff ); 5102 // --> OD 2005-08-08 #i52904# - re-introduce direct move 5103 // of drawing objects 5104 const bool bDirectMove = 5105 static_cast<const SwDrawFrmFmt&>(pAnchoredObj->GetFrmFmt()).IsPosAttrSet() && 5106 bVertPosDepOnAnchor && 5107 !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos(); 5108 if ( bDirectMove ) 5109 { 5110 SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); 5111 if ( bVert ) 5112 { 5113 pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) ); 5114 } 5115 else 5116 { 5117 pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) ); 5118 } 5119 // --> OD 2006-10-13 #i58280# 5120 pAnchoredObj->InvalidateObjRectWithSpaces(); 5121 // <-- 5122 } 5123 // <-- 5124 pAnchoredObj->InvalidateObjPos(); 5125 } 5126 else 5127 { 5128 ASSERT( false, 5129 "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" ); 5130 } 5131 } 5132 } 5133 } 5134 // Columns and cells are ordered horizontal, not vertical 5135 if( !pFrm->IsColumnFrm() && !pFrm->IsCellFrm() ) 5136 lYStart = (*fnRect->fnYInc)( lYStart, 5137 (pFrm->Frm().*fnRect->fnGetHeight)() ); 5138 5139 // Nowadays, the content inside a cell can flow into the follow table. 5140 // Thus, the cell may only grow up to the end of the environment. 5141 // So the content may have grown, but the cell could not grow. 5142 // Therefore we have to trigger a formatting for the frames, which do 5143 // not fit into the cell anymore: 5144 SwTwips nDistanceToUpperPrtBottom = 5145 (pFrm->Frm().*fnRect->fnBottomDist)( (pLay->*fnRect->fnGetPrtBottom)()); 5146 // --> OD 2006-01-19 #i56146# - Revise fix of issue #i26945# 5147 // do *not* consider content inside fly frames, if it's an undersized paragraph. 5148 // --> OD 2004-10-08 #i26945# - consider content inside fly frames 5149 if ( nDistanceToUpperPrtBottom < 0 && 5150 ( ( pFrm->IsInFly() && 5151 ( !pFrm->IsTxtFrm() || 5152 !static_cast<SwTxtFrm*>(pFrm)->IsUndersized() ) ) || 5153 pFrm->IsInSplitTableRow() ) ) 5154 // <-- 5155 { 5156 pFrm->InvalidatePos(); 5157 } 5158 5159 pFrm = pFrm->GetNext(); 5160 } 5161 return bRet; 5162 } 5163 5164 void SwCellFrm::Format( const SwBorderAttrs *pAttrs ) 5165 { 5166 ASSERT( pAttrs, "CellFrm::Format, pAttrs ist 0." ); 5167 const SwTabFrm* pTab = FindTabFrm(); 5168 SWRECTFN( pTab ) 5169 5170 if ( !bValidPrtArea ) 5171 { 5172 bValidPrtArea = sal_True; 5173 5174 //Position einstellen. 5175 if ( Lower() ) 5176 { 5177 SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace; 5178 // --> collapsing borders FME 2005-05-27 #i29550# 5179 if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrm() ) 5180 { 5181 const SvxBoxItem& rBoxItem = pAttrs->GetBox(); 5182 nLeftSpace = rBoxItem.GetDistance( BOX_LINE_LEFT ); 5183 nRightSpace = rBoxItem.GetDistance( BOX_LINE_RIGHT ); 5184 nTopSpace = ((SwRowFrm*)GetUpper())->GetTopMarginForLowers(); 5185 nBottomSpace = ((SwRowFrm*)GetUpper())->GetBottomMarginForLowers(); 5186 } 5187 else 5188 { 5189 // <-- collapsing 5190 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> 5191 nLeftSpace = pAttrs->CalcLeft( this ); 5192 nRightSpace = pAttrs->CalcRight( this ); 5193 nTopSpace = pAttrs->CalcTop(); 5194 nBottomSpace = pAttrs->CalcBottom(); 5195 } 5196 (this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace ); 5197 (this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace ); 5198 } 5199 } 5200 // --> OD 2004-10-04 #i26945# 5201 long nRemaining = GetTabBox()->getRowSpan() >= 1 ? 5202 ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) : 5203 0; 5204 // <-- 5205 if ( !bValidSize ) 5206 { 5207 bValidSize = sal_True; 5208 5209 //Die VarSize der CellFrms ist immer die Breite. 5210 //Tatsaechlich ist die Breite jedoch nicht Variabel, sie wird durch das 5211 //Format vorgegeben. Dieser Vorgegebene Wert muss aber nun wiederum 5212 //nicht der tatsaechlichen Breite entsprechen. Die Breite wird auf 5213 //Basis des Attributes errechnet, der Wert im Attribut passt zu dem 5214 //gewuenschten Wert des TabFrms. Anpassungen die dort vorgenommen 5215 //wurden werden hier Proportional beruecksichtigt. 5216 //Wenn die Celle keinen Nachbarn mehr hat beruecksichtigt sie nicht 5217 //die Attribute, sonder greift sich einfach den Rest des 5218 //Uppers 5219 SwTwips nWidth; 5220 if ( GetNext() ) 5221 { 5222 const SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth(); 5223 nWidth = pAttrs->GetSize().Width(); 5224 5225 ASSERT( nWish, "Tabelle ohne Breite?" ); 5226 ASSERT( nWidth <= nWish, "Zelle breiter als Tabelle." ); 5227 ASSERT( nWidth > 0, "Box without width" ); 5228 5229 const long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); 5230 if ( nWish != nPrtWidth ) 5231 { 5232 // Avoid rounding problems, at least for the new table model 5233 if ( pTab->GetTable()->IsNewModel() ) 5234 { 5235 // 1. sum of widths of cells up to this cell (in model) 5236 const SwTableLine* pTabLine = GetTabBox()->GetUpper(); 5237 const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes(); 5238 const SwTableBox* pTmpBox = 0; 5239 5240 SwTwips nSumWidth = 0; 5241 sal_uInt16 i = 0; 5242 do 5243 { 5244 pTmpBox = rBoxes[ i++ ]; 5245 nSumWidth += pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth(); 5246 } 5247 while ( pTmpBox != GetTabBox() ); 5248 5249 // 2. calculate actual width of cells up to this one 5250 double nTmpWidth = nSumWidth; 5251 nTmpWidth *= nPrtWidth; 5252 nTmpWidth /= nWish; 5253 nWidth = (SwTwips)nTmpWidth; 5254 5255 // 3. calculate frame widths of cells up to this one: 5256 const SwFrm* pTmpCell = static_cast<const SwLayoutFrm*>(GetUpper())->Lower(); 5257 SwTwips nSumFrameWidths = 0; 5258 while ( pTmpCell != this ) 5259 { 5260 nSumFrameWidths += (pTmpCell->Frm().*fnRect->fnGetWidth)(); 5261 pTmpCell = pTmpCell->GetNext(); 5262 } 5263 5264 nWidth = nWidth - nSumFrameWidths; 5265 } 5266 else 5267 { 5268 // #i12092# use double instead of long, 5269 // otherwise this could lead to overflows 5270 double nTmpWidth = nWidth; 5271 nTmpWidth *= nPrtWidth; 5272 nTmpWidth /= nWish; 5273 nWidth = (SwTwips)nTmpWidth; 5274 } 5275 } 5276 } 5277 else 5278 { 5279 ASSERT( pAttrs->GetSize().Width() > 0, "Box without width" ); 5280 nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); 5281 SwFrm *pPre = GetUpper()->Lower(); 5282 while ( pPre != this ) 5283 { 5284 nWidth -= (pPre->Frm().*fnRect->fnGetWidth)(); 5285 pPre = pPre->GetNext(); 5286 } 5287 } 5288 const long nDiff = nWidth - (Frm().*fnRect->fnGetWidth)(); 5289 if( IsNeighbourFrm() && IsRightToLeft() ) 5290 (Frm().*fnRect->fnSubLeft)( nDiff ); 5291 else 5292 (Frm().*fnRect->fnAddRight)( nDiff ); 5293 (Prt().*fnRect->fnAddRight)( nDiff ); 5294 5295 //Jetzt die Hoehe einstellen, sie wird vom Inhalt und den Raendern 5296 //bestimmt. 5297 const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)(); 5298 if ( nDiffHeight ) 5299 { 5300 if ( nDiffHeight > 0 ) 5301 { 5302 //Wieder validieren wenn kein Wachstum stattgefunden hat. 5303 //Invalidiert wird durch AdjustCells von der Row. 5304 if ( !Grow( nDiffHeight ) ) 5305 bValidSize = bValidPrtArea = sal_True; 5306 } 5307 else 5308 { 5309 //Nur dann invalidiert lassen, wenn tatsaechlich 5310 //geshrinkt wurde; das kann abgelehnt werden, weil alle 5311 //nebeneinanderliegenden Zellen gleichgross sein muessen. 5312 if ( !Shrink( -nDiffHeight ) ) 5313 bValidSize = bValidPrtArea = sal_True; 5314 } 5315 } 5316 } 5317 const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient(); 5318 5319 if ( !Lower() ) 5320 return; 5321 5322 // From now on, all operations are related to the table cell. 5323 SWREFRESHFN( this ) 5324 5325 SwPageFrm* pPg = 0; 5326 if ( !FindTabFrm()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() && 5327 // --> OD 2008-07-16 #158225# no vertical alignment of covered cells 5328 !IsCoveredCell() && 5329 // <-- 5330 (pPg = FindPageFrm())!=NULL ) 5331 { 5332 if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() && !Lower()->IsTabFrm() ) 5333 { 5334 //ASSERT fuer HTML-Import! 5335 ASSERT( sal_False, "VAlign to cell without content" ); 5336 return; 5337 } 5338 sal_Bool bVertDir = sal_True; 5339 // --> OD 2005-03-30 #i43913# - no vertical alignment, if wrapping 5340 // style influence is considered on object positioning and 5341 // an object is anchored inside the cell. 5342 const bool bConsiderWrapOnObjPos( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ); 5343 // <-- 5344 //Keine Ausrichtung wenn Rahmen mit Umlauf in die Zelle ragen. 5345 if ( pPg->GetSortedObjs() ) 5346 { 5347 SwRect aRect( Prt() ); aRect += Frm().Pos(); 5348 for ( sal_uInt16 i = 0; i < pPg->GetSortedObjs()->Count(); ++i ) 5349 { 5350 const SwAnchoredObject* pAnchoredObj = (*pPg->GetSortedObjs())[i]; 5351 SwRect aTmp( pAnchoredObj->GetObjRect() ); 5352 if ( aTmp.IsOver( aRect ) ) 5353 { 5354 const SwFrmFmt& rAnchoredObjFrmFmt = pAnchoredObj->GetFrmFmt(); 5355 const SwFmtSurround &rSur = rAnchoredObjFrmFmt.GetSurround(); 5356 5357 if ( SURROUND_THROUGHT != rSur.GetSurround() ) 5358 { 5359 // frames, which the cell is a lower of, aren't relevant 5360 if ( pAnchoredObj->ISA(SwFlyFrm) ) 5361 { 5362 const SwFlyFrm *pFly = 5363 static_cast<const SwFlyFrm*>(pAnchoredObj); 5364 if ( pFly->IsAnLower( this ) ) 5365 continue; 5366 } 5367 5368 const SwFrm* pAnch = pAnchoredObj->GetAnchorFrm(); 5369 // --> OD 2005-03-30 #i43913# 5370 // --> OD 2005-08-08 #i52904# - no vertical alignment, 5371 // if object, anchored inside cell, has temporarly 5372 // consider its wrapping style on object positioning. 5373 // --> FME 2006-02-01 #i58806# - no vertical alignment 5374 // if object does not follow the text flow. 5375 if ( bConsiderWrapOnObjPos || 5376 !IsAnLower( pAnch ) || 5377 pAnchoredObj->IsTmpConsiderWrapInfluence() || 5378 !rAnchoredObjFrmFmt.GetFollowTextFlow().GetValue() ) 5379 // <-- 5380 { 5381 bVertDir = sal_False; 5382 break; 5383 } 5384 } 5385 } 5386 } 5387 } 5388 5389 long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); 5390 if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) || 5391 (Lower()->Frm().*fnRect->fnGetTop)() != (this->*fnRect->fnGetPrtTop)() ) 5392 { 5393 long lTopOfst = 0, 5394 nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining; 5395 if ( nDiff >= 0 ) 5396 { 5397 if ( bVertDir ) 5398 { 5399 switch ( rOri.GetVertOrient() ) 5400 { 5401 case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break; 5402 case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break; 5403 default: break; 5404 }; 5405 } 5406 long nTmp = (*fnRect->fnYInc)( 5407 (this->*fnRect->fnGetPrtTop)(), lTopOfst ); 5408 if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) ) 5409 SetCompletePaint(); 5410 } 5411 } 5412 } 5413 else 5414 { 5415 //Ist noch eine alte Ausrichtung beruecksichtigt worden? 5416 if ( Lower()->IsCntntFrm() ) 5417 { 5418 const long lYStart = (this->*fnRect->fnGetPrtTop)(); 5419 lcl_ArrangeLowers( this, lYStart, sal_True ); 5420 } 5421 } 5422 } 5423 5424 /************************************************************************* 5425 |* 5426 |* SwCellFrm::Modify() 5427 |* 5428 |* Ersterstellung MA 20. Dec. 96 5429 |* Letzte Aenderung MA 20. Dec. 96 5430 |* 5431 |*************************************************************************/ 5432 5433 void SwCellFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) 5434 { 5435 sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); 5436 const SfxPoolItem *pItem = 0; 5437 5438 if( bAttrSetChg ) 5439 ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, sal_False, &pItem); 5440 else if ( RES_VERT_ORIENT == pNew->Which() ) 5441 pItem = pNew; 5442 5443 if ( pItem ) 5444 { 5445 sal_Bool bInva = sal_True; 5446 if ( text::VertOrientation::NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() && 5447 // OD 04.11.2003 #112910# 5448 Lower() && Lower()->IsCntntFrm() ) 5449 { 5450 SWRECTFN( this ) 5451 const long lYStart = (this->*fnRect->fnGetPrtTop)(); 5452 bInva = lcl_ArrangeLowers( this, lYStart, sal_False ); 5453 } 5454 if ( bInva ) 5455 { 5456 SetCompletePaint(); 5457 InvalidatePrt(); 5458 } 5459 } 5460 5461 if ( ( bAttrSetChg && 5462 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, sal_False ) ) || 5463 RES_PROTECT == pNew->Which() ) 5464 { 5465 ViewShell *pSh = getRootFrm()->GetCurrShell(); 5466 if( pSh && pSh->GetLayout()->IsAnyShellAccessible() ) 5467 pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this ); 5468 } 5469 5470 if ( bAttrSetChg && 5471 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, sal_False, &pItem ) ) 5472 { 5473 SetDerivedVert( sal_False ); 5474 CheckDirChange(); 5475 } 5476 5477 // --> collapsing borders FME 2005-05-27 #i29550# 5478 if ( bAttrSetChg && 5479 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_BOX, sal_False, &pItem ) ) 5480 { 5481 SwFrm* pTmpUpper = GetUpper(); 5482 while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrm() ) 5483 pTmpUpper = pTmpUpper->GetUpper(); 5484 5485 SwTabFrm* pTabFrm = (SwTabFrm*)pTmpUpper->GetUpper(); 5486 if ( pTabFrm->IsCollapsingBorders() ) 5487 { 5488 // Invalidate lowers of this and next row: 5489 lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); 5490 pTmpUpper = pTmpUpper->GetNext(); 5491 if ( pTmpUpper ) 5492 lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); 5493 else 5494 pTabFrm->InvalidatePrt(); 5495 } 5496 } 5497 // <-- collapsing 5498 5499 SwLayoutFrm::Modify( pOld, pNew ); 5500 } 5501 5502 /************************************************************************* 5503 |* SwCellFrm::GetLayoutRowSpan() const 5504 |*************************************************************************/ 5505 5506 long SwCellFrm::GetLayoutRowSpan() const 5507 { 5508 long nRet = GetTabBox()->getRowSpan(); 5509 if ( nRet < 1 ) 5510 { 5511 const SwFrm* pRow = GetUpper(); 5512 const SwTabFrm* pTab = static_cast<const SwTabFrm*>(pRow->GetUpper()); 5513 5514 if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() ) 5515 nRet = -nRet; 5516 } 5517 return nRet; 5518 } 5519 5520 // --> OD 2010-02-17 #i103961# 5521 void SwCellFrm::Cut() 5522 { 5523 // notification for accessibility 5524 { 5525 SwRootFrm *pRootFrm = getRootFrm(); 5526 if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) 5527 { 5528 ViewShell* pVSh = pRootFrm->GetCurrShell(); 5529 if ( pVSh && pVSh->Imp() ) 5530 { 5531 pVSh->Imp()->DisposeAccessibleFrm( this ); 5532 } 5533 } 5534 } 5535 5536 SwLayoutFrm::Cut(); 5537 } 5538 // <-- 5539 5540 // 5541 // Helper functions for repeated headlines: 5542 // 5543 5544 /* 5545 * SwTabFrm::IsInHeadline( const SwFrm& rFrm ) 5546 */ 5547 bool SwTabFrm::IsInHeadline( const SwFrm& rFrm ) const 5548 { 5549 ASSERT( IsAnLower( &rFrm ) && rFrm.IsInTab(), 5550 "SwTabFrm::IsInHeadline called for frame not lower of table" ) 5551 5552 const SwFrm* pTmp = &rFrm; 5553 while ( !pTmp->GetUpper()->IsTabFrm() ) 5554 pTmp = pTmp->GetUpper(); 5555 5556 return GetTable()->IsHeadline( *((SwRowFrm*)pTmp)->GetTabLine() ); 5557 } 5558 5559 /* 5560 * SwTabFrm::GetFirstNonHeadlineRow() 5561 * 5562 * If this is a master table, we can may assume, that there are at least 5563 * nRepeat lines in the table. 5564 * If this is a follow table, there are intermediate states for the table 5565 * layout, e.g., during deletion of rows, which makes it necessary to find 5566 * the first non-headline row by evaluating the headline flag at the row frame. 5567 */ 5568 SwRowFrm* SwTabFrm::GetFirstNonHeadlineRow() const 5569 { 5570 SwRowFrm* pRet = (SwRowFrm*)Lower(); 5571 if ( pRet ) 5572 { 5573 if ( IsFollow() ) 5574 { 5575 while ( pRet && pRet->IsRepeatedHeadline() ) 5576 pRet = (SwRowFrm*)pRet->GetNext(); 5577 } 5578 else 5579 { 5580 sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); 5581 while ( pRet && nRepeat > 0 ) 5582 { 5583 pRet = (SwRowFrm*)pRet->GetNext(); 5584 --nRepeat; 5585 } 5586 } 5587 } 5588 5589 return (SwRowFrm*)pRet; 5590 } 5591 5592 /* 5593 * SwTable::IsHeadline() 5594 */ 5595 bool SwTable::IsHeadline( const SwTableLine& rLine ) const 5596 { 5597 for ( sal_uInt16 i = 0; i < GetRowsToRepeat(); ++i ) 5598 if ( GetTabLines()[ i ] == &rLine ) 5599 return true; 5600 5601 return false; 5602 } 5603 5604 bool SwTabFrm::IsLayoutSplitAllowed() const 5605 { 5606 return GetFmt()->GetLayoutSplit().GetValue(); 5607 } 5608 5609 // --> collapsing borders FME 2005-05-27 #i29550# 5610 5611 sal_uInt16 SwTabFrm::GetBottomLineSize() const 5612 { 5613 ASSERT( IsCollapsingBorders(), 5614 "BottomLineSize only required for collapsing borders" ) 5615 5616 ASSERT( Lower(), "Warning! Trying to prevent a crash, please inform FME" ) 5617 5618 const SwFrm* pTmp = GetLastLower(); 5619 5620 // --> FME 2005-12-07 #124755# Try to make code robust: 5621 if ( !pTmp ) return 0; 5622 // <-- 5623 5624 return static_cast<const SwRowFrm*>(pTmp)->GetBottomLineSize(); 5625 } 5626 5627 bool SwTabFrm::IsCollapsingBorders() const 5628 { 5629 return ((SfxBoolItem&)GetFmt()->GetAttrSet().Get( RES_COLLAPSING_BORDERS )).GetValue(); 5630 } 5631 5632 // <-- collapsing 5633 5634 5635 // 5636 // Local helper function to calculate height of first text row 5637 // 5638 SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrm& rSourceLine ) 5639 { 5640 // Find corresponding split line in master table 5641 const SwTabFrm* pTab = rSourceLine.FindTabFrm(); 5642 SWRECTFN( pTab ) 5643 const SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); 5644 5645 // 5646 // 1. Case: rSourceLine is a follow flow line. 5647 // In this case we have to return the minimum of the heights 5648 // of the first lines in rSourceLine. 5649 // 5650 // 2. Case: rSourceLine is not a follow flow line. 5651 // In this case we have to return the maximum of the heights 5652 // of the first lines in rSourceLine. 5653 // 5654 bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow(); 5655 SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0; 5656 5657 while ( pCurrSourceCell ) 5658 { 5659 // NEW TABLES 5660 // Skip cells which are not responsible for the height of 5661 // the follow flow line: 5662 if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 ) 5663 { 5664 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); 5665 continue; 5666 } 5667 5668 const SwFrm *pTmp = pCurrSourceCell->Lower(); 5669 if ( pTmp ) 5670 { 5671 SwTwips nTmpHeight = USHRT_MAX; 5672 // --> FME 2004-09-14 #i32456# Consider lower row frames 5673 if ( pTmp->IsRowFrm() ) 5674 { 5675 const SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); 5676 nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow ); 5677 } 5678 // <-- 5679 if ( pTmp->IsTabFrm() ) 5680 { 5681 nTmpHeight = ((SwTabFrm*)pTmp)->CalcHeightOfFirstContentLine(); 5682 } 5683 else if ( pTmp->IsTxtFrm() ) 5684 { 5685 SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp; 5686 pTxtFrm->GetFormatted(); 5687 nTmpHeight = pTxtFrm->FirstLineHeight(); 5688 } 5689 5690 if ( USHRT_MAX != nTmpHeight ) 5691 { 5692 const SwCellFrm* pPrevCell = pCurrSourceCell->GetPreviousCell(); 5693 if ( pPrevCell ) 5694 { 5695 // If we are in a split row, there may be some space 5696 // left in the cell frame of the master row. 5697 // We look for the minimum of all first line heights; 5698 SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)(); 5699 const SwFrm* pFrm = pPrevCell->Lower(); 5700 const SwFrm* pLast = pFrm; 5701 while ( pFrm ) 5702 { 5703 nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); 5704 pLast = pFrm; 5705 pFrm = pFrm->GetNext(); 5706 } 5707 5708 // --> FME, OD 2004-07-15 #i26831#, #i26520# 5709 // The additional lower space of the current last. 5710 // --> OD 2004-11-25 #115759# - do *not* consider the 5711 // additional lower space for 'master' text frames 5712 if ( pLast && pLast->IsFlowFrm() && 5713 ( !pLast->IsTxtFrm() || 5714 !static_cast<const SwTxtFrm*>(pLast)->GetFollow() ) ) 5715 // <-- 5716 { 5717 nReal += SwFlowFrm::CastFlowFrm(pLast)->CalcAddLowerSpaceAsLastInTableCell(); 5718 } 5719 // Don't forget the upper space and lower space, 5720 // --> OD 2004-11-25 #115759# - do *not* consider the upper 5721 // and the lower space for follow text frames. 5722 if ( pTmp->IsFlowFrm() && 5723 ( !pTmp->IsTxtFrm() || 5724 !static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) ) 5725 { 5726 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace( NULL, pLast); 5727 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); 5728 } 5729 // <-- 5730 // --> OD 2004-11-25 #115759# - consider additional lower 5731 // space of <pTmp>, if contains only one line. 5732 // In this case it would be the new last text frame, which 5733 // would have no follow and thus would add this space. 5734 if ( pTmp->IsTxtFrm() && 5735 const_cast<SwTxtFrm*>(static_cast<const SwTxtFrm*>(pTmp)) 5736 ->GetLineCount( STRING_LEN ) == 1 ) 5737 { 5738 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp) 5739 ->CalcAddLowerSpaceAsLastInTableCell(); 5740 } 5741 // <-- 5742 if ( nReal > 0 ) 5743 nTmpHeight -= nReal; 5744 } 5745 else 5746 { 5747 // pFirstRow is not a FollowFlowRow. In this case, 5748 // we look for the maximum of all first line heights: 5749 SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCurrSourceCell ); 5750 const SwBorderAttrs &rAttrs = *aAccess.Get(); 5751 nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom(); 5752 // --> OD 2004-07-16 #i26250# 5753 // Don't forget the upper space and lower space, 5754 if ( pTmp->IsFlowFrm() ) 5755 { 5756 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace(); 5757 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); 5758 } 5759 // <-- 5760 } 5761 } 5762 5763 if ( bIsInFollowFlowLine ) 5764 { 5765 // minimum 5766 if ( nTmpHeight < nHeight ) 5767 nHeight = nTmpHeight; 5768 } 5769 else 5770 { 5771 // maximum 5772 if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight ) 5773 nHeight = nTmpHeight; 5774 } 5775 } 5776 5777 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); 5778 } 5779 5780 return ( LONG_MAX == nHeight ) ? 0 : nHeight; 5781 } 5782 5783 // 5784 // Function to calculate height of first text row 5785 // 5786 SwTwips SwTabFrm::CalcHeightOfFirstContentLine() const 5787 { 5788 SWRECTFN( this ) 5789 5790 const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue(); 5791 5792 if ( bDontSplit ) 5793 { 5794 // Table is not allowed to split: Take the whole height, that's all 5795 return (Frm().*fnRect->fnGetHeight)(); 5796 } 5797 5798 SwRowFrm* pFirstRow = 0; 5799 SwTwips nTmpHeight = 0; 5800 5801 pFirstRow = GetFirstNonHeadlineRow(); 5802 ASSERT( !IsFollow() || pFirstRow, "FollowTable without Lower" ) 5803 5804 // NEW TABLES 5805 if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() ) 5806 pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); 5807 5808 // Calculate the height of the headlines: 5809 const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); 5810 SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0; 5811 5812 // Calculate the height of the keeping lines 5813 // (headlines + following keeping lines): 5814 SwTwips nKeepHeight = nRepeatHeight; 5815 if ( GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) ) 5816 { 5817 sal_uInt16 nKeepRows = nRepeat; 5818 5819 // Check how many rows want to keep together 5820 while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() ) 5821 { 5822 ++nKeepRows; 5823 pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); 5824 } 5825 5826 if ( nKeepRows > nRepeat ) 5827 nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows ); 5828 } 5829 5830 // For master tables, the height of the headlines + the heigth of the 5831 // keeping lines (if any) has to be considered. For follow tables, we 5832 // only consider the height of the keeping rows without the repeated lines: 5833 if ( !IsFollow() ) 5834 { 5835 nTmpHeight = nKeepHeight; 5836 } 5837 else 5838 { 5839 nTmpHeight = nKeepHeight - nRepeatHeight; 5840 } 5841 5842 // pFirstRow row is the first non-heading row. 5843 // nTmpHeight is the height of the heading row if we are a follow. 5844 if ( pFirstRow ) 5845 { 5846 const bool bSplittable = pFirstRow->IsRowSplitAllowed(); 5847 const SwTwips nFirstLineHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)(); 5848 5849 if ( !bSplittable ) 5850 { 5851 // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow 5852 // actually is determined by a lower cell with rowspan = -1. In this case we should not 5853 // just return the height of the first line. Basically we need to get the height of the 5854 // line as it would be on the last page. Since this is quite complicated to calculate, 5855 // we olny calculate the height of the first line. 5856 if ( pFirstRow->GetPrev() && 5857 static_cast<SwRowFrm*>(pFirstRow->GetPrev())->IsRowSpanLine() ) 5858 { 5859 // Calculate maximum height of all cells with rowspan = 1: 5860 SwTwips nMaxHeight = 0; 5861 const SwCellFrm* pLower2 = static_cast<const SwCellFrm*>(pFirstRow->Lower()); 5862 while ( pLower2 ) 5863 { 5864 if ( 1 == pLower2->GetTabBox()->getRowSpan() ) 5865 { 5866 const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, sal_True ); 5867 nMaxHeight = Max( nCellHeight, nMaxHeight ); 5868 } 5869 pLower2 = static_cast<const SwCellFrm*>(pLower2->GetNext()); 5870 } 5871 nTmpHeight += nMaxHeight; 5872 } 5873 else 5874 { 5875 nTmpHeight += nFirstLineHeight; 5876 } 5877 } 5878 5879 // --> FME 2004-11-18 #118411# 5880 // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger 5881 // a formatting of the row frame (via the GetFormatted()). We don't 5882 // want this formatting if the row does not have a height. 5883 else if ( 0 != nFirstLineHeight ) 5884 // <-- 5885 { 5886 const bool bOldJoinLock = IsJoinLocked(); 5887 ((SwTabFrm*)this)->LockJoin(); 5888 const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow ); 5889 5890 // Consider minimum row height: 5891 const SwFmtFrmSize &rSz = static_cast<const SwRowFrm*>(pFirstRow)->GetFmt()->GetFrmSize(); 5892 const SwTwips nMinRowHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? 5893 rSz.GetHeight() : 0; 5894 5895 nTmpHeight += Max( nHeightOfFirstContentLine, nMinRowHeight ); 5896 5897 if ( !bOldJoinLock ) 5898 ((SwTabFrm*)this)->UnlockJoin(); 5899 } 5900 } 5901 5902 return nTmpHeight; 5903 } 5904 5905 // 5906 // Some more functions for covered/covering cells. This way inclusion of 5907 // SwCellFrm can be avoided 5908 // 5909 5910 bool SwFrm::IsLeaveUpperAllowed() const 5911 { 5912 const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); 5913 return pThisCell && pThisCell->GetLayoutRowSpan() > 1; 5914 } 5915 5916 bool SwFrm::IsCoveredCell() const 5917 { 5918 const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); 5919 return pThisCell && pThisCell->GetLayoutRowSpan() < 1; 5920 } 5921 5922 bool SwFrm::IsInCoveredCell() const 5923 { 5924 bool bRet = false; 5925 5926 const SwFrm* pThis = this; 5927 while ( pThis && !pThis->IsCellFrm() ) 5928 pThis = pThis->GetUpper(); 5929 5930 if ( pThis ) 5931 bRet = pThis->IsCoveredCell(); 5932 5933 return bRet; 5934 } 5935 5936