Update ooo320-m1
[ooovba.git] / sw / source / core / layout / tabfrm.cxx
blob60b5ae3e4d6d36175471e9afcbcdb8ae63dc501d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tabfrm.cxx,v $
10 * $Revision: 1.105.58.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include "pagefrm.hxx"
34 #include "rootfrm.hxx"
35 #include "cntfrm.hxx"
36 #include "viewsh.hxx"
37 #include "doc.hxx"
38 #include "docsh.hxx"
39 #include "viewimp.hxx"
40 #include "swtable.hxx"
41 #include "dflyobj.hxx"
42 #include "flyfrm.hxx"
43 #include "frmtool.hxx"
44 #include "frmfmt.hxx"
45 #include "dcontact.hxx"
46 #include "viewopt.hxx"
47 #include "hints.hxx"
48 #include "dbg_lay.hxx"
50 #include <ftnidx.hxx>
51 #include <svtools/itemiter.hxx>
52 #include <docary.hxx>
53 #include <svx/keepitem.hxx>
54 #include <svx/ulspitem.hxx>
55 #include <svx/lrspitem.hxx>
56 #include <svx/brshitem.hxx>
57 // --> collapsing borders FME 2005-05-27 #i29550#
58 #include <svx/boxitem.hxx>
59 // <--
60 #ifndef _OUTDEV_HXX //autogen
61 #include <vcl/outdev.hxx>
62 #endif
63 #include <fmtlsplt.hxx>
64 #include <fmtrowsplt.hxx>
65 #include <fmtsrnd.hxx>
66 #include <fmtornt.hxx>
67 #include <fmtpdsc.hxx>
68 #include <fmtfsize.hxx>
69 #include <swtblfmt.hxx>
70 #include <ndtxt.hxx>
72 #include "tabfrm.hxx"
73 #include "rowfrm.hxx"
74 #include "cellfrm.hxx"
75 #include "flyfrms.hxx"
76 #include "txtfrm.hxx" //HasFtn()
77 #include "htmltbl.hxx"
78 #include "sectfrm.hxx" //SwSectionFrm
79 // OD 30.09.2003 #i18732#
80 #include <fmtfollowtextflow.hxx>
81 // --> OD 2004-06-28 #i28701#
82 #include <sortedobjs.hxx>
83 #include <objectformatter.hxx>
84 // <--
85 // --> OD 2004-10-05 #i26945#
86 #include <layouter.hxx>
87 // <--
89 extern void AppendObjs( const SwSpzFrmFmts *pTbl, ULONG nIndex,
90 SwFrm *pFrm, SwPageFrm *pPage );
92 using namespace ::com::sun::star;
95 /*************************************************************************
97 |* SwTabFrm::SwTabFrm(), ~SwTabFrm()
99 |* Ersterstellung MA 09. Mar. 93
100 |* Letzte Aenderung MA 30. May. 96
102 |*************************************************************************/
103 SwTabFrm::SwTabFrm( SwTable &rTab ):
104 SwLayoutFrm( rTab.GetFrmFmt() ),
105 SwFlowFrm( (SwFrm&)*this ),
106 pTable( &rTab )
108 bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove =
109 bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
110 bRestrictTableGrowth = bRemoveFollowFlowLinePending = FALSE;
111 // --> OD 2004-10-04 #i26945#
112 bConsiderObjsForMinCellHeight = TRUE;
113 bObjsDoesFit = TRUE;
114 // <--
115 bFixSize = FALSE; //Nicht nochmal auf die Importfilter hereinfallen.
116 nType = FRMC_TAB;
118 //Gleich die Zeilen erzeugen und einfuegen.
119 const SwTableLines &rLines = rTab.GetTabLines();
120 SwFrm *pTmpPrev = 0;
121 for ( USHORT i = 0; i < rLines.Count(); ++i )
123 SwRowFrm *pNew = new SwRowFrm( *rLines[i] );
124 if( pNew->Lower() )
126 pNew->InsertBehind( this, pTmpPrev );
127 pTmpPrev = pNew;
129 else
130 delete pNew;
132 ASSERT( Lower() && Lower()->IsRowFrm(), "SwTabFrm::SwTabFrm: No rows." );
135 SwTabFrm::SwTabFrm( SwTabFrm &rTab ) :
136 SwLayoutFrm( rTab.GetFmt() ),
137 SwFlowFrm( (SwFrm&)*this ),
138 pTable( rTab.GetTable() )
140 bIsFollow = TRUE;
141 bLockJoin = bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove =
142 bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
143 bRestrictTableGrowth = bRemoveFollowFlowLinePending = FALSE;
144 // --> OD 2004-10-04 #i26945#
145 bConsiderObjsForMinCellHeight = TRUE;
146 bObjsDoesFit = TRUE;
147 // <--
148 bFixSize = FALSE; //Nicht nochmal auf die Importfilter hereinfallen.
149 nType = FRMC_TAB;
151 SetFollow( rTab.GetFollow() );
152 rTab.SetFollow( this );
155 extern const SwTable *pColumnCacheLastTable;
156 extern const SwTabFrm *pColumnCacheLastTabFrm;
157 extern const SwFrm *pColumnCacheLastCellFrm;
158 extern const SwTable *pRowCacheLastTable;
159 extern const SwTabFrm *pRowCacheLastTabFrm;
160 extern const SwFrm *pRowCacheLastCellFrm;
162 SwTabFrm::~SwTabFrm()
164 // There is some terrible code in fetab.cxx, that
165 // makes use of these global pointers. Obviously
166 // this code did not consider that a TabFrm can be
167 // deleted.
168 if ( this == pColumnCacheLastTabFrm )
170 pColumnCacheLastTable = NULL;
171 pColumnCacheLastTabFrm = NULL;
172 pColumnCacheLastCellFrm= NULL;
173 pRowCacheLastTable = NULL;
174 pRowCacheLastTabFrm = NULL;
175 pRowCacheLastCellFrm= NULL;
179 /*************************************************************************
181 |* SwTabFrm::JoinAndDelFollows()
183 |* Ersterstellung MA 30. May. 96
184 |* Letzte Aenderung MA 30. May. 96
186 |*************************************************************************/
187 void SwTabFrm::JoinAndDelFollows()
189 SwTabFrm *pFoll = GetFollow();
190 if ( pFoll->HasFollow() )
191 pFoll->JoinAndDelFollows();
192 pFoll->Cut();
193 SetFollow( pFoll->GetFollow() );
194 delete pFoll;
197 /*************************************************************************
199 |* SwTabFrm::RegistFlys()
201 |* Ersterstellung MA 08. Jul. 93
202 |* Letzte Aenderung MA 27. Jan. 99
204 |*************************************************************************/
205 void SwTabFrm::RegistFlys()
207 ASSERT( Lower() && Lower()->IsRowFrm(), "Keine Zeilen." );
209 SwPageFrm *pPage = FindPageFrm();
210 if ( pPage )
212 SwRowFrm *pRow = (SwRowFrm*)Lower();
215 pRow->RegistFlys( pPage );
216 pRow = (SwRowFrm*)pRow->GetNext();
217 } while ( pRow );
221 /*************************************************************************
222 |* Some prototypes
223 |*************************************************************************/
224 void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom );
225 bool MA_FASTCALL lcl_CalcLowers( SwLayoutFrm *pLay, const SwLayoutFrm* pDontLeave,
226 long nBottom, bool bSkipRowSpanCells );
227 void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom );
228 BOOL lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, BOOL bInva );
229 // --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control
230 // that only row and cell frames are formatted.
231 BOOL MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm,
232 long nBottom,
233 bool _bOnlyRowsAndCells = false );
234 // <--
235 // OD 2004-02-18 #106629# - correct type of 1st parameter
236 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to
237 // control, if floating screen objects have to be considered for the minimal
238 // cell height.
239 SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm *pRow,
240 const BOOL _bConsiderObjs );
241 // <--
242 SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm&, const SwBorderAttrs& );
244 /*************************************************************************
245 |* START: local helper functions for repeated headlines
246 |*************************************************************************/
248 SwTwips lcl_GetHeightOfRows( const SwFrm* pStart, long nCount )
250 if ( !nCount || !pStart)
251 return 0;
253 SwTwips nRet = 0;
254 SWRECTFN( pStart )
255 while ( pStart && nCount > 0 )
257 nRet += (pStart->Frm().*fnRect->fnGetHeight)();
258 pStart = pStart->GetNext();
259 --nCount;
262 return nRet;
265 /*************************************************************************
266 |* END: local helper functions for repeated headlines
267 |*************************************************************************/
269 /*************************************************************************
270 |* START: local helper functions for splitting row frames
271 |*************************************************************************/
274 // Local helper function to insert a new follow flow line
276 SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, bool bRowSpanLine )
278 ASSERT( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" )
279 const SwRowFrm& rRow = (SwRowFrm&)rTmpRow;
281 rTab.SetFollowFlowLine( TRUE );
282 SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), false );
283 pFollowFlowLine->SetRowSpanLine( bRowSpanLine );
284 SwFrm* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow();
285 pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow );
286 return pFollowFlowLine;
289 // --> OD 2004-11-05 #i26945# - local helper function to invalidate all lower
290 // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if
291 // additionally the objects are moved 'out of range'.
292 void lcl_InvalidateLowerObjs( SwLayoutFrm& _rLayoutFrm,
293 const bool _bMoveObjsOutOfRange = false,
294 SwPageFrm* _pPageFrm = 0L )
296 // determine page frame, if needed
297 if ( !_pPageFrm )
299 _pPageFrm = _rLayoutFrm.FindPageFrm();
300 ASSERT( _pPageFrm,
301 "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" );
302 if ( !_pPageFrm )
304 return;
308 // loop on lower frames
309 SwFrm* pLowerFrm = _rLayoutFrm.Lower();
310 while ( pLowerFrm )
312 if ( pLowerFrm->IsLayoutFrm() )
314 ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pLowerFrm)),
315 _bMoveObjsOutOfRange, _pPageFrm );
317 if ( pLowerFrm->GetDrawObjs() )
319 for ( USHORT i = 0; i < pLowerFrm->GetDrawObjs()->Count(); ++i )
321 SwAnchoredObject* pAnchoredObj = (*pLowerFrm->GetDrawObjs())[i];
323 // invalidate position of anchored object
324 pAnchoredObj->SetTmpConsiderWrapInfluence( false );
325 pAnchoredObj->SetConsiderForTextWrap( false );
326 pAnchoredObj->UnlockPosition();
327 pAnchoredObj->InvalidateObjPos();
329 // move anchored object 'out of range'
330 if ( _bMoveObjsOutOfRange )
332 // indicate, that positioning is progress to avoid
333 // modification of the anchored object resp. its attributes
334 // due to the movement
335 SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
336 pAnchoredObj->SetObjLeft( _pPageFrm->Frm().Right() );
337 // --> OD 2004-11-24 #115759# - reset character rectangle,
338 // top of line and relative position in order to assure,
339 // that anchored object is correctly positioned.
340 pAnchoredObj->ClearCharRectAndTopOfLine();
341 pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
342 if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
343 == FLY_IN_CNTNT )
345 pAnchoredObj->AnchorFrm()
346 ->Prepare( PREP_FLY_ATTR_CHG,
347 &(pAnchoredObj->GetFrmFmt()) );
349 // <--
350 if ( pAnchoredObj->ISA(SwFlyFrm) )
352 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
353 pFly->GetVirtDrawObj()->SetRectsDirty();
354 pFly->GetVirtDrawObj()->SetChanged();
358 // If anchored object is a fly frame, invalidate its lower objects
359 if ( pAnchoredObj->ISA(SwFlyFrm) )
361 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
362 ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrm );
366 pLowerFrm = pLowerFrm->GetNext();
369 // <--
371 // Local helper function to shrink all lowers of rRow to 0 height
373 void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow )
375 SwCellFrm* pCurrMasterCell = static_cast<SwCellFrm*>(rRow.Lower());
376 SWRECTFN( pCurrMasterCell )
378 while ( pCurrMasterCell )
380 // NEW TABLES
381 SwCellFrm& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ?
382 const_cast<SwCellFrm&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true, true )) :
383 *pCurrMasterCell;
385 // --> OD 2004-10-04 #i26945#
386 // all lowers should have the correct position
387 lcl_ArrangeLowers( &rToAdjust,
388 (rToAdjust.*fnRect->fnGetPrtTop)(),
389 sal_False );
390 // <--
391 // TODO: Optimize number of frames which are set to 0 height
392 // we have to start with the last lower frame, otherwise
393 // the shrink will not shrink the current cell
394 SwFrm* pTmp = rToAdjust.GetLastLower();
396 if ( pTmp && pTmp->IsRowFrm() )
398 SwRowFrm* pTmpRow = (SwRowFrm*)pTmp;
399 lcl_ShrinkCellsAndAllContent( *pTmpRow );
401 else
403 // TODO: Optimize number of frames which are set to 0 height
404 while ( pTmp )
406 // the frames have to be shrunk
407 if ( pTmp && pTmp->IsTabFrm() )
409 SwRowFrm* pTmpRow = (SwRowFrm*)((SwTabFrm*)pTmp)->Lower();
410 while ( pTmpRow )
412 lcl_ShrinkCellsAndAllContent( *pTmpRow );
413 pTmpRow = (SwRowFrm*)pTmpRow->GetNext();
416 else
418 pTmp->Shrink( (pTmp->Frm().*fnRect->fnGetHeight)() );
419 (pTmp->Prt().*fnRect->fnSetTop)( 0 );
420 (pTmp->Prt().*fnRect->fnSetHeight)( 0 );
423 pTmp = pTmp->GetPrev();
426 // all lowers should have the correct position
427 lcl_ArrangeLowers( &rToAdjust,
428 (rToAdjust.*fnRect->fnGetPrtTop)(),
429 sal_False );
432 pCurrMasterCell = static_cast<SwCellFrm*>(pCurrMasterCell->GetNext());
437 // Local helper function to move the content from rSourceLine to rDestLine
438 // The content is inserted behind the last content in the corresponding
439 // cell in rDestLine.
441 void lcl_MoveRowContent( SwRowFrm& rSourceLine, SwRowFrm& rDestLine )
443 SwCellFrm* pCurrDestCell = (SwCellFrm*)rDestLine.Lower();
444 SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower();
446 // Move content of follow cells into master cells
447 while ( pCurrSourceCell )
449 if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() )
451 SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
452 while ( pTmpSourceRow )
454 // --> FME 2006-01-10 #125926# Achtung! It is possible,
455 // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow
456 // cannot be found. In this case, we have to move the complete
457 // row.
458 SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower();
459 // <--
461 if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow )
463 // move content from follow flow row to pTmpDestRow:
464 while ( pTmpDestRow->GetNext() )
465 pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext();
467 ASSERT( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Knoten in der Tabelle" )
469 lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow );
470 pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() );
471 pTmpSourceRow->Remove();
472 delete pTmpSourceRow;
474 else
476 // move complete row:
477 pTmpSourceRow->Remove();
478 pTmpSourceRow->InsertBefore( pCurrDestCell, 0 );
481 pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
484 else
486 SwFrm *pTmp = ::SaveCntnt( (SwCellFrm*)pCurrSourceCell );
487 if ( pTmp )
489 // NEW TABLES
490 SwCellFrm* pDestCell = static_cast<SwCellFrm*>(pCurrDestCell);
491 if ( pDestCell->GetTabBox()->getRowSpan() < 1 )
492 pDestCell = & const_cast<SwCellFrm&>(pDestCell->FindStartEndOfRowSpanCell( true, true ));
494 // Find last content
495 SwFrm* pFrm = pDestCell->GetLastLower();
496 ::RestoreCntnt( pTmp, pDestCell, pFrm, true );
499 pCurrDestCell = (SwCellFrm*)pCurrDestCell->GetNext();
500 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
505 // Local helper function to move all footnotes in rRowFrm from
506 // the footnote boss of rSource to the footnote boss of rDest.
508 void lcl_MoveFootnotes( SwTabFrm& rSource, SwTabFrm& rDest, SwLayoutFrm& rRowFrm )
510 if ( 0 != rSource.GetFmt()->GetDoc()->GetFtnIdxs().Count() )
512 SwFtnBossFrm* pOldBoss = rSource.FindFtnBossFrm( TRUE );
513 SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( TRUE );
514 rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, TRUE );
519 // Local helper function to handle nested table cells before the split process
521 void lcl_PreprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine,
522 SwRowFrm& rFollowFlowLine, SwTwips nRemain )
524 SwCellFrm* pCurrLastLineCell = (SwCellFrm*)rLastLine.Lower();
525 SwCellFrm* pCurrFollowFlowLineCell = (SwCellFrm*)rFollowFlowLine.Lower();
527 SWRECTFN( pCurrLastLineCell )
530 // Move content of follow cells into master cells
532 while ( pCurrLastLineCell )
534 if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrm() )
536 SwTwips nTmpCut = nRemain;
537 SwRowFrm* pTmpLastLineRow = (SwRowFrm*)pCurrLastLineCell->Lower();
539 // --> OD 2004-10-04 #i26945#
540 SwTwips nCurrentHeight =
541 lcl_CalcMinRowHeight( pTmpLastLineRow,
542 rTab.IsConsiderObjsForMinCellHeight() );
543 // <--
544 while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight )
546 nTmpCut -= nCurrentHeight;
547 pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext();
548 // --> OD 2004-10-04 #i26945#
549 nCurrentHeight =
550 lcl_CalcMinRowHeight( pTmpLastLineRow,
551 rTab.IsConsiderObjsForMinCellHeight() );
552 // <--
556 // pTmpLastLineRow does not fit to the line or it is the last line
558 if ( pTmpLastLineRow )
561 // Check if we can move pTmpLastLineRow to the follow table,
562 // or if we have to split the line:
564 SwFrm* pCell = pTmpLastLineRow->Lower();
565 bool bTableLayoutToComplex = false;
566 long nMinHeight = 0;
569 // We have to take into account:
570 // 1. The fixed height of the row
571 // 2. The borders of the cells inside the row
572 // 3. The minimum height of the row
574 if ( pTmpLastLineRow->HasFixSize() )
575 nMinHeight = (pTmpLastLineRow->Frm().*fnRect->fnGetHeight)();
576 else
578 while ( pCell )
580 if ( ((SwCellFrm*)pCell)->Lower() &&
581 ((SwCellFrm*)pCell)->Lower()->IsRowFrm() )
583 bTableLayoutToComplex = true;
584 break;
587 SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell );
588 const SwBorderAttrs &rAttrs = *aAccess.Get();
589 nMinHeight = Max( nMinHeight, lcl_CalcTopAndBottomMargin( *(SwLayoutFrm*)pCell, rAttrs ) );
590 pCell = pCell->GetNext();
593 const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize();
594 if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE )
595 nMinHeight = Max( nMinHeight, rSz.GetHeight() );
599 // 1. Case:
600 // The line completely fits into the master table.
601 // Nevertheless, we build a follow (otherwise painting problems
602 // with empty cell).
604 // 2. Case:
605 // The line has to be split, the minimum height still fits into
606 // the master table, and the table structure is not to complex.
608 if ( nTmpCut > nCurrentHeight ||
609 ( pTmpLastLineRow->IsRowSplitAllowed() &&
610 !bTableLayoutToComplex && nMinHeight < nTmpCut ) )
612 // The line has to be split:
613 SwRowFrm* pNewRow = new SwRowFrm( *pTmpLastLineRow->GetTabLine(), false );
614 pNewRow->SetFollowFlowRow( true );
615 pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() );
616 pTmpLastLineRow->SetFollowRow( pNewRow );
617 pNewRow->InsertBehind( pCurrFollowFlowLineCell, 0 );
618 pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext();
622 // The following lines have to be moved:
624 while ( pTmpLastLineRow )
626 SwRowFrm* pTmp = (SwRowFrm*)pTmpLastLineRow->GetNext();
627 lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow );
628 pTmpLastLineRow->Remove();
629 pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, 0 );
630 pTmpLastLineRow->Shrink( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() );
631 pCurrFollowFlowLineCell->Grow( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() );
632 pTmpLastLineRow = pTmp;
637 pCurrLastLineCell = (SwCellFrm*)pCurrLastLineCell->GetNext();
638 pCurrFollowFlowLineCell = (SwCellFrm*)pCurrFollowFlowLineCell->GetNext();
643 // Local helper function to handle nested table cells after the split process
645 void lcl_PostprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine )
647 SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
648 while ( pCurrMasterCell )
650 if ( pCurrMasterCell->Lower() &&
651 pCurrMasterCell->Lower()->IsRowFrm() )
653 SwRowFrm* pRowFrm = static_cast<SwRowFrm*>(pCurrMasterCell->GetLastLower());
655 if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() )
657 ASSERT( pRowFrm->GetFollowRow(), "Deleting row frame without follow" )
659 // The footnotes have to be moved:
660 lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrm );
661 pRowFrm->Cut();
662 SwRowFrm* pFollowRow = pRowFrm->GetFollowRow();
663 pRowFrm->Paste( pFollowRow->GetUpper(), pFollowRow );
664 pRowFrm->SetFollowRow( pFollowRow->GetFollowRow() );
665 lcl_MoveRowContent( *pFollowRow, *pRowFrm );
666 pFollowRow->Cut();
667 delete pFollowRow;
668 ::SwInvalidateAll( pCurrMasterCell, LONG_MAX );
672 pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext();
677 // Local helper function to re-calculate the split line.
679 inline void TableSplitRecalcLock( SwFlowFrm *pTab ) { pTab->LockJoin(); }
680 inline void TableSplitRecalcUnlock( SwFlowFrm *pTab ) { pTab->UnlockJoin(); }
682 bool lcl_RecalcSplitLine( SwRowFrm& rLastLine, SwRowFrm& rFollowLine,
683 SwTwips nRemainingSpaceForLastRow )
685 bool bRet = true;
687 SwTabFrm& rTab = (SwTabFrm&)*rLastLine.GetUpper();
690 // If there are nested cells in rLastLine, the recalculation of the last
691 // line needs some preprocessing.
693 lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow );
696 // Here the recalculation process starts:
698 rTab.SetRebuildLastLine( TRUE );
699 // --> OD 2004-10-15 #i26945#
700 rTab.SetDoesObjsFit( TRUE );
701 // <--
702 SWRECTFN( rTab.GetUpper() )
704 // --> OD 2004-11-05 #i26945# - invalidate and move floating screen
705 // objects 'out of range'
706 ::lcl_InvalidateLowerObjs( rLastLine, true );
707 // <--
709 // manipulate row and cell sizes
711 // --> OD 2004-10-04 #i26945# - Do *not* consider floating screen objects
712 // for the minimal cell height.
713 rTab.SetConsiderObjsForMinCellHeight( FALSE );
714 ::lcl_ShrinkCellsAndAllContent( rLastLine );
715 rTab.SetConsiderObjsForMinCellHeight( TRUE );
716 // <--
719 // invalidate last line
721 ::SwInvalidateAll( &rLastLine, LONG_MAX );
724 // Lock this tab frame and its follow
726 bool bUnlockMaster = false;
727 bool bUnlockFollow = false;
728 SwTabFrm* pMaster = rTab.IsFollow() ? (SwTabFrm*)rTab.FindMaster() : 0;
729 if ( pMaster && !pMaster->IsJoinLocked() )
731 bUnlockMaster = true;
732 ::TableSplitRecalcLock( pMaster );
734 if ( !rTab.GetFollow()->IsJoinLocked() )
736 bUnlockFollow = true;
737 ::TableSplitRecalcLock( rTab.GetFollow() );
741 // TODO: e.g., for i71806: What shall we do if the table already
742 // exceeds its upper? I think we have to adjust the heights of the
743 // table, rLastRow and all cells in rLastRow
745 /*SwTwips nDistanceToUpperPrtBottom =
746 (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)());
748 if ( nDistanceToUpperPrtBottom < 0 )
750 (rTab.Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
751 (rTab.Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
753 (rLastLine.Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
754 (rLastLine.Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
756 SwFrm* pTmpCell = rLastLine.Lower();
757 while ( pTmpCell )
759 (pTmpCell->Frm().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
760 (pTmpCell->Prt().*fnRect->fnAddBottom)( nDistanceToUpperPrtBottom );
762 pTmpCell = pTmpCell->GetNext();
767 // Do the recalculation
769 lcl_RecalcRow( rLastLine, LONG_MAX );
770 // --> OD 2004-11-23 #115759# - force a format of the last line in order to
771 // get the correct height.
772 rLastLine.InvalidateSize();
773 rLastLine.Calc();
774 // <--
777 // Unlock this tab frame and its follow
779 if ( bUnlockFollow )
780 ::TableSplitRecalcUnlock( rTab.GetFollow() );
781 if ( bUnlockMaster )
782 ::TableSplitRecalcUnlock( pMaster );
785 // If there are nested cells in rLastLine, the recalculation of the last
786 // line needs some postprocessing.
788 lcl_PostprocessRowsInCells( rTab, rLastLine );
791 // Do a couple of checks on the current situation.
793 // If we are not happy with the current situation we return false.
794 // This will start a new try to split the table, this time we do not
795 // try to split the table rows.
799 // 1. Check if table fits to its upper.
800 // --> OD 2004-10-15 #i26945# - include check, if objects fit
802 const SwTwips nDistanceToUpperPrtBottom =
803 (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)());
804 if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() )
805 bRet = false;
806 // <--
809 // 2. Check if each cell in the last line has at least one content frame.
811 // Note: a FollowFlowRow may contains empty cells!
813 if ( bRet )
815 if ( !rLastLine.IsInFollowFlowRow() )
817 SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
818 while ( pCurrMasterCell )
820 if ( !pCurrMasterCell->ContainsCntnt() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 )
822 bRet = false;
823 break;
825 pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext();
831 // 3. Check if last line does not contain any content:
833 if ( bRet )
835 if ( !rLastLine.ContainsCntnt() )
837 bRet = false;
843 // 4. Check if follow flow line does not contain content:
845 if ( bRet )
847 if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsCntnt() )
849 bRet = false;
853 if ( bRet )
856 // Everything looks fine. Splitting seems to be successful. We invalidate
857 // rFollowLine to force a new formatting.
859 ::SwInvalidateAll( &rFollowLine, LONG_MAX );
861 else
864 // Splitting the table row gave us an unexpected result.
865 // Everything has to be prepared for a second try to split
866 // the table, this time without splitting the row.
868 ::SwInvalidateAll( &rLastLine, LONG_MAX );
871 rTab.SetRebuildLastLine( FALSE );
872 // --> OD 2004-10-15 #i26945#
873 rTab.SetDoesObjsFit( TRUE );
874 // <--
876 return bRet;
880 // Sets the correct height for all spanned cells
882 void lcl_AdjustRowSpanCells( SwRowFrm* pRow )
884 SWRECTFN( pRow )
885 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pRow->GetLower());
886 while ( pCellFrm )
888 const long nLayoutRowSpan = pCellFrm->GetLayoutRowSpan();
889 if ( nLayoutRowSpan > 1 )
891 // calculate height of cell:
892 const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan );
893 const long nDiff = nNewCellHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)();
894 if ( nDiff )
895 (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff );
898 pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext());
903 // Returns the maximum layout row span of the row
904 // Looking for the next row that contains no covered cells:
905 long lcl_GetMaximumLayoutRowSpan( const SwRowFrm& rRow )
907 long nRet = 1;
909 const SwRowFrm* pCurrentRowFrm = static_cast<const SwRowFrm*>(rRow.GetNext());
910 bool bNextRow = false;
912 while ( pCurrentRowFrm )
914 // if there is any covered cell, we proceed to the next row frame
915 const SwCellFrm* pLower = static_cast<const SwCellFrm*>( pCurrentRowFrm->Lower());
916 while ( pLower )
918 if ( pLower->GetTabBox()->getRowSpan() < 0 )
920 ++nRet;
921 bNextRow = true;
922 break;
924 pLower = static_cast<const SwCellFrm*>(pLower->GetNext());
926 pCurrentRowFrm = bNextRow ?
927 static_cast<const SwRowFrm*>(pCurrentRowFrm->GetNext() ) :
931 return nRet;
934 /*************************************************************************
935 |* END: local helper functions for splitting row frames
936 |*************************************************************************/
939 // Function to remove the FollowFlowLine of rTab.
940 // The content of the FollowFlowLine is moved to the associated line in the
941 // master table.
943 bool SwTabFrm::RemoveFollowFlowLine()
945 // find FollowFlowLine
946 SwRowFrm* pFollowFlowLine = static_cast<SwRowFrm*>(GetFollow()->GetFirstNonHeadlineRow());
948 // find last row in master
949 SwFrm* pLastLine = GetLastLower();
951 ASSERT( HasFollowFlowLine() &&
952 pFollowFlowLine &&
953 pLastLine, "There should be a flowline in the follow" )
955 // We have to reset the flag here, because lcl_MoveRowContent
956 // calls a GrowFrm(), which has a different bahavior if
957 // this flag is set.
958 SetFollowFlowLine( FALSE );
960 // --> FME 2007-07-19 #140081# Make code robust.
961 if ( !pFollowFlowLine || !pLastLine )
962 return true;
964 // Move content
965 lcl_MoveRowContent( *pFollowFlowLine, *(SwRowFrm*)pLastLine );
967 // NEW TABLES
968 // If a row span follow flow line is removed, we want to move the whole span
969 // to the master:
970 SwTwips nGrow = 0;
971 long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine );
973 if ( nRowsToMove > 1 )
975 SWRECTFN( this )
976 SwFrm* pRow = pFollowFlowLine->GetNext();
977 SwFrm* pInsertBehind = GetLastLower();
979 while ( pRow && nRowsToMove-- > 1 )
981 SwFrm* pNxt = pRow->GetNext();
982 nGrow += (pRow->Frm().*fnRect->fnGetHeight)();
984 // The footnotes have to be moved:
985 lcl_MoveFootnotes( *GetFollow(), *this, (SwRowFrm&)*pRow );
987 pRow->Remove();
988 pRow->InsertBehind( this, pInsertBehind );
989 pRow->_InvalidateAll();
990 pRow->CheckDirChange();
991 pInsertBehind = pRow;
992 pRow = pNxt;
995 SwFrm* pFirstRow = Lower();
996 while ( pFirstRow )
998 lcl_AdjustRowSpanCells( static_cast<SwRowFrm*>(pFirstRow) );
999 pFirstRow = pFirstRow->GetNext();
1002 Grow( nGrow );
1003 GetFollow()->Shrink( nGrow );
1006 bool bJoin = !pFollowFlowLine->GetNext();
1007 pFollowFlowLine->Cut();
1008 delete pFollowFlowLine;
1010 return bJoin;
1013 // --> OD 2004-10-04 #i26945# - Floating screen objects are no longer searched.
1014 bool lcl_FindSectionsInRow( const SwRowFrm& rRow )
1016 bool bRet = false;
1017 SwCellFrm* pLower = (SwCellFrm*)rRow.Lower();
1018 while ( pLower )
1020 if ( pLower->IsVertical() != rRow.IsVertical() )
1021 return true;
1023 SwFrm* pTmpFrm = pLower->Lower();
1024 while ( pTmpFrm )
1026 if ( pTmpFrm->IsRowFrm() )
1028 bRet = lcl_FindSectionsInRow( *(SwRowFrm*)pTmpFrm );
1030 else
1032 // --> OD 2004-10-04 #i26945# - search only for sections
1033 bRet = pTmpFrm->IsSctFrm();
1034 // <--
1037 if ( bRet )
1038 return true;
1039 pTmpFrm = pTmpFrm->GetNext();
1042 pLower = (SwCellFrm*)pLower->GetNext();
1044 return bRet;
1047 /*************************************************************************
1049 |* SwTabFrm::Split(), Join()
1051 |* Ersterstellung MA 03. Jun. 93
1052 |* Letzte Aenderung MA 03. Sep. 96
1054 |*************************************************************************/
1055 bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep )
1057 bool bRet = true;
1059 SWRECTFN( this )
1060 //ASSERT( bVert ? nCutPos >= Frm().Left() &&
1061 // nCutPos <= Frm().Left() + Frm().Width() :
1062 // nCutPos >= Frm().Top() && nCutPos <= Frm().Bottom(), "SplitLine out of table." );
1064 // --> OD 2004-10-14 #i26745# - format row and cell frames of table
1066 this->Lower()->_InvalidatePos();
1067 // --> OD 2005-03-30 #i43913# - correction:
1068 // call method <lcl_InnerCalcLayout> with first lower.
1069 lcl_InnerCalcLayout( this->Lower(), LONG_MAX, true );
1070 // <--
1072 // <--
1074 //Um die Positionen der Zellen mit der CutPos zu vergleichen muessen sie
1075 //ausgehend von der Tabelle nacheinander berechnet werden. Sie koennen
1076 //wg. Positionsaenderungen der Tabelle durchaus ungueltig sein.
1077 SwRowFrm *pRow = static_cast<SwRowFrm*>(Lower());
1078 if( !pRow )
1079 return bRet;
1081 const USHORT nRepeat = GetTable()->GetRowsToRepeat();
1082 USHORT nRowCount = 0; // pRow currently points to the first row
1084 SwTwips nRemainingSpaceForLastRow =
1085 (*fnRect->fnYDiff)( nCutPos, (Frm().*fnRect->fnGetTop)() );
1086 nRemainingSpaceForLastRow -= (this->*fnRect->fnGetTopMargin)();
1089 // Make pRow point to the line that does not fit anymore:
1091 while( pRow->GetNext() &&
1092 nRemainingSpaceForLastRow >= ( (pRow->Frm().*fnRect->fnGetHeight)() +
1093 (IsCollapsingBorders() ?
1094 pRow->GetBottomLineSize() :
1095 0 ) ) )
1097 if( bTryToSplit || !pRow->IsRowSpanLine() ||
1098 0 != (pRow->Frm().*fnRect->fnGetHeight)() )
1099 ++nRowCount;
1100 nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)();
1101 pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1105 // bSplitRowAllowed: Row may be split according to its attributes.
1106 // bTryToSplit: Row will never be split if bTryToSplit = false.
1107 // This can either be passed as a parameter, indicating
1108 // that we are currently doing the second try to split the
1109 // table, or it will be set to falseunder certain
1110 // conditions that are not suitable for splitting
1111 // the row.
1113 bool bSplitRowAllowed = pRow->IsRowSplitAllowed();
1115 // --> FME 2004-06-03 #i29438#
1116 // --> OD 2004-10-04 #i26945# - Floating screen objects no longer forbid
1117 // a splitting of the table row.
1118 // Special DoNotSplit case 1:
1119 // Search for sections inside pRow:
1121 if ( lcl_FindSectionsInRow( *pRow ) )
1123 bTryToSplit = false;
1125 // <--
1127 // --> FME 2004-06-07 #i29771#
1128 // To avoid loops, we do some checks before actually trying to split
1129 // the row. Maybe we should keep the next row in this table.
1130 // Note: This is only done if we are at the beginning of our upper
1131 bool bKeepNextRow = false;
1132 if ( nRowCount < nRepeat )
1135 // First case: One of the repeated headline does not fit to the page anymore.
1136 // At least one more non-heading row has to stay in this table in
1137 // order to avoid loops:
1139 ASSERT( !GetIndPrev(), "Table is supposed to be at beginning" )
1140 bKeepNextRow = true;
1142 else if ( !GetIndPrev() && nRepeat == nRowCount )
1145 // Second case: The first non-headline row does not fit to the page.
1146 // If it is not allowed to be split, or it contains a sub-row that
1147 // is not allowed to be split, we keep the row in this table:
1149 if ( bTryToSplit && bSplitRowAllowed )
1151 // Check if there are (first) rows inside this row,
1152 // which are not allowed to be split.
1153 SwCellFrm* pLowerCell = pRow ? (SwCellFrm*)pRow->Lower() : 0;
1154 while ( pLowerCell )
1156 if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrm() )
1158 const SwRowFrm* pLowerRow = (SwRowFrm*)pLowerCell->Lower();
1159 if ( !pLowerRow->IsRowSplitAllowed() &&
1160 (pLowerRow->Frm().*fnRect->fnGetHeight)() >
1161 nRemainingSpaceForLastRow )
1163 bKeepNextRow = true;
1164 break;
1167 pLowerCell = (SwCellFrm*)pLowerCell->GetNext();
1170 else
1171 bKeepNextRow = true;
1175 // Better keep the next row in this table:
1177 if ( bKeepNextRow )
1179 pRow = GetFirstNonHeadlineRow();
1180 if( pRow && pRow->IsRowSpanLine() && 0 == (pRow->Frm().*fnRect->fnGetHeight)() )
1181 pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1182 if ( pRow )
1184 pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1185 ++nRowCount;
1190 // No more row to split or to move to follow table:
1192 if ( !pRow )
1193 return bRet;
1196 // We try to split the row if
1197 // - the attributes of the row are set accordingly and
1198 // - we are allowed to do so
1199 // - the it should not keep with the next row
1201 bSplitRowAllowed = bSplitRowAllowed && bTryToSplit &&
1202 ( !bTableRowKeep ||
1203 !pRow->ShouldRowKeepWithNext() );
1205 // Adjust pRow according to the keep-with-next attribute:
1206 if ( !bSplitRowAllowed && bTableRowKeep )
1208 SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pRow->GetPrev());
1209 SwRowFrm* pOldRow = pRow;
1210 while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() &&
1211 nRowCount > nRepeat )
1213 pRow = pTmpRow;
1214 --nRowCount;
1215 pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetPrev());
1218 // loop prevention
1219 if ( nRowCount == nRepeat && !GetIndPrev())
1221 pRow = pOldRow;
1226 // If we do not indent to split pRow, we check if we are
1227 // allowed to move pRow to a follow. Otherwise we return
1228 // false, indicating an error
1230 if ( !bSplitRowAllowed )
1232 SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
1233 if ( pRow == pFirstNonHeadlineRow )
1234 return false;
1236 // --> OD 2008-10-21 #i91764#
1237 // Ignore row span lines
1238 SwRowFrm* pTmpRow = pFirstNonHeadlineRow;
1239 while ( pTmpRow && pTmpRow->IsRowSpanLine() )
1241 pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetNext());
1243 if ( !pTmpRow || pRow == pTmpRow )
1245 return false;
1247 // <--
1251 // Build follow table if not already done:
1253 BOOL bNewFollow;
1254 SwTabFrm *pFoll;
1255 if ( GetFollow() )
1257 pFoll = GetFollow();
1258 bNewFollow = FALSE;
1260 else
1262 bNewFollow = TRUE;
1263 pFoll = new SwTabFrm( *this );
1266 // We give the follow table an initial width.
1268 (pFoll->Frm().*fnRect->fnAddWidth)( (Frm().*fnRect->fnGetWidth)() );
1269 (pFoll->Prt().*fnRect->fnAddWidth)( (Prt().*fnRect->fnGetWidth)() );
1270 (pFoll->Frm().*fnRect->fnSetLeft)( (Frm().*fnRect->fnGetLeft)() );
1273 // Insert the new follow table
1275 pFoll->InsertBehind( GetUpper(), this );
1278 // Repeat the headlines.
1280 for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount )
1282 // Insert new headlines:
1283 bDontCreateObjects = TRUE; //frmtool
1284 SwRowFrm* pHeadline = new SwRowFrm(
1285 *GetTable()->GetTabLines()[ nRowCount ] );
1286 pHeadline->SetRepeatedHeadline( true );
1287 bDontCreateObjects = FALSE;
1288 pHeadline->InsertBefore( pFoll, 0 );
1290 SwPageFrm *pPage = pHeadline->FindPageFrm();
1291 const SwSpzFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts();
1292 if( pTbl->Count() )
1294 ULONG nIndex;
1295 SwCntntFrm* pFrm = pHeadline->ContainsCntnt();
1296 while( pFrm )
1298 nIndex = pFrm->GetNode()->GetIndex();
1299 AppendObjs( pTbl, nIndex, pFrm, pPage );
1300 pFrm = pFrm->GetNextCntntFrm();
1301 if( !pHeadline->IsAnLower( pFrm ) )
1302 break;
1308 SwRowFrm* pLastRow = 0; // will point to the last remaining line in master
1309 SwRowFrm* pFollowRow = 0; // points to either the follow flow line of the
1310 // first regular line in the follow
1312 if ( bSplitRowAllowed )
1314 // If the row that does not fit anymore is allowed
1315 // to be split, the next row has to be moved to the follow table.
1316 pLastRow = pRow;
1317 pRow = static_cast<SwRowFrm*>(pRow->GetNext());
1319 // new follow flow line for last row of master table
1320 pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false );
1322 else
1324 pFollowRow = pRow;
1326 // NEW TABLES
1327 // check if we will break a row span by moving pFollowRow to the follow:
1328 // In this case we want to reformat the last line.
1329 const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>(pFollowRow->GetLower());
1330 while ( pCellFrm )
1332 if ( pCellFrm->GetTabBox()->getRowSpan() < 1 )
1334 pLastRow = static_cast<SwRowFrm*>(pRow->GetPrev());
1335 break;
1338 pCellFrm = static_cast<const SwCellFrm*>(pCellFrm->GetNext());
1341 // new follow flow line for last row of master table
1342 if ( pLastRow )
1343 pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true );
1346 SwTwips nRet = 0;
1348 //Optimierung beim neuen Follow braucht's kein Paste und dann kann
1349 //das Optimierte Insert verwendet werden (nur dann treten gluecklicher weise
1350 //auch groessere Mengen von Rows auf).
1351 if ( bNewFollow )
1353 SwFrm* pNxt = 0;
1354 SwFrm* pInsertBehind = pFoll->GetLastLower();
1356 while ( pRow )
1358 pNxt = pRow->GetNext();
1359 nRet += (pRow->Frm().*fnRect->fnGetHeight)();
1360 // The footnotes do not have to be moved, this is done in the
1361 // MoveFwd of the follow table!!!
1362 pRow->Remove();
1363 pRow->InsertBehind( pFoll, pInsertBehind );
1364 pRow->_InvalidateAll();
1365 pInsertBehind = pRow;
1366 pRow = static_cast<SwRowFrm*>(pNxt);
1369 else
1371 SwFrm* pNxt = 0;
1372 SwFrm* pPasteBefore = HasFollowFlowLine() ?
1373 pFollowRow->GetNext() :
1374 pFoll->GetFirstNonHeadlineRow();
1376 while ( pRow )
1378 pNxt = pRow->GetNext();
1379 nRet += (pRow->Frm().*fnRect->fnGetHeight)();
1381 // The footnotes have to be moved:
1382 lcl_MoveFootnotes( *this, *GetFollow(), *pRow );
1384 pRow->Remove();
1385 pRow->Paste( pFoll, pPasteBefore );
1387 pRow->CheckDirChange();
1388 pRow = static_cast<SwRowFrm*>(pNxt);
1392 Shrink( nRet );
1394 // we rebuild the last line to assure that it will be fully formatted
1395 if ( pLastRow )
1397 // recalculate the split line
1398 bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow );
1400 // NEW TABLES
1401 // check if each cell in the row span line has a good height
1402 if ( bRet && pFollowRow->IsRowSpanLine() )
1403 lcl_AdjustRowSpanCells( pFollowRow );
1405 // We The RowSplitLine stuff did not work. In this case we conceal the split error:
1406 if ( !bRet && !bSplitRowAllowed )
1408 bRet = true;
1412 return bRet;
1415 bool SwTabFrm::Join()
1417 ASSERT( !HasFollowFlowLine(), "Joining follow flow line" )
1419 SwTabFrm *pFoll = GetFollow();
1420 SwTwips nHeight = 0; //Gesamthoehe der eingefuegten Zeilen als Return.
1422 if ( !pFoll->IsJoinLocked() )
1424 SWRECTFN( this )
1425 pFoll->Cut(); //Erst ausschneiden um unuetze Benachrichtigungen zu
1426 //minimieren.
1428 SwFrm *pRow = pFoll->GetFirstNonHeadlineRow(),
1429 *pNxt;
1431 SwFrm* pPrv = GetLastLower();
1433 while ( pRow )
1435 pNxt = pRow->GetNext();
1436 nHeight += (pRow->Frm().*fnRect->fnGetHeight)();
1437 pRow->Remove();
1438 pRow->_InvalidateAll();
1439 pRow->InsertBehind( this, pPrv );
1440 pRow->CheckDirChange();
1441 pPrv = pRow;
1442 pRow = pNxt;
1445 SetFollow( pFoll->GetFollow() );
1446 SetFollowFlowLine( pFoll->HasFollowFlowLine() );
1447 delete pFoll;
1449 Grow( nHeight );
1452 return true;
1455 /*************************************************************************
1457 |* SwTabFrm::MakeAll()
1459 |* Ersterstellung MA 09. Mar. 93
1460 |* Letzte Aenderung MA 10. Apr. 97
1462 |*************************************************************************/
1463 void MA_FASTCALL SwInvalidatePositions( SwFrm *pFrm, long nBottom )
1465 // LONG_MAX == nBottom means we have to calculate all
1466 BOOL bAll = LONG_MAX == nBottom;
1467 SWRECTFN( pFrm )
1469 { pFrm->_InvalidatePos();
1470 pFrm->_InvalidateSize();
1471 if( pFrm->IsLayoutFrm() )
1473 if ( ((SwLayoutFrm*)pFrm)->Lower() )
1475 ::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom);
1476 // --> OD 2004-11-05 #i26945#
1477 ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pFrm)) );
1478 // <--
1481 else
1482 pFrm->Prepare( PREP_ADJUST_FRM );
1483 pFrm = pFrm->GetNext();
1484 } while ( pFrm &&
1485 ( bAll ||
1486 (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
1489 void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom )
1491 // LONG_MAX == nBottom means we have to calculate all
1492 BOOL bAll = LONG_MAX == nBottom;
1493 SWRECTFN( pFrm )
1496 pFrm->_InvalidatePos();
1497 pFrm->_InvalidateSize();
1498 pFrm->_InvalidatePrt();
1499 if( pFrm->IsLayoutFrm() )
1501 // NEW TABLES
1502 SwLayoutFrm* pToInvalidate = static_cast<SwLayoutFrm*>(pFrm);
1503 SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm);
1504 if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1506 pToInvalidate = & const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true ));
1507 pToInvalidate->_InvalidatePos();
1508 pToInvalidate->_InvalidateSize();
1509 pToInvalidate->_InvalidatePrt();
1512 if ( pToInvalidate->Lower() )
1513 ::SwInvalidateAll( pToInvalidate->Lower(), nBottom);
1515 else
1516 pFrm->Prepare( PREP_CLEAR );
1518 pFrm = pFrm->GetNext();
1519 } while ( pFrm &&
1520 ( bAll ||
1521 (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
1524 // --> collapsing borders FME 2005-05-27 #i29550#
1525 void lcl_InvalidateAllLowersPrt( SwLayoutFrm* pLayFrm )
1527 pLayFrm->_InvalidatePrt();
1528 pLayFrm->_InvalidateSize();
1529 pLayFrm->SetCompletePaint();
1531 SwFrm* pFrm = pLayFrm->Lower();
1533 while ( pFrm )
1535 if ( pFrm->IsLayoutFrm() )
1536 lcl_InvalidateAllLowersPrt( (SwLayoutFrm*)pFrm );
1537 else
1539 pFrm->_InvalidatePrt();
1540 pFrm->_InvalidateSize();
1541 pFrm->SetCompletePaint();
1544 pFrm = pFrm->GetNext();
1547 // <-- collapsing
1549 bool MA_FASTCALL lcl_CalcLowers( SwLayoutFrm* pLay, const SwLayoutFrm* pDontLeave,
1550 long nBottom, bool bSkipRowSpanCells )
1552 if ( !pLay )
1553 return TRUE;
1555 // LONG_MAX == nBottom means we have to calculate all
1556 bool bAll = LONG_MAX == nBottom;
1557 bool bRet = FALSE;
1558 SwCntntFrm *pCnt = pLay->ContainsCntnt();
1559 SWRECTFN( pLay )
1561 // FME 2007-08-30 #i81146# new loop control
1562 USHORT nLoopControlRuns = 0;
1563 const USHORT nLoopControlMax = 10;
1564 const SwModify* pLoopControlCond = 0;
1566 while ( pCnt && pDontLeave->IsAnLower( pCnt ) )
1568 // --> OD 2004-11-23 #115759# - check, if a format of content frame is
1569 // possible. Thus, 'copy' conditions, found at the beginning of
1570 // <SwCntntFrm::MakeAll(..)>, and check these.
1571 const bool bFormatPossible = !pCnt->IsJoinLocked() &&
1572 ( !pCnt->IsTxtFrm() ||
1573 !static_cast<SwTxtFrm*>(pCnt)->IsLocked() ) &&
1574 ( pCnt->IsFollow() || !StackHack::IsLocked() );
1576 // NEW TABLES
1577 bool bSkipContent = false;
1578 if ( bSkipRowSpanCells && pCnt->IsInTab() )
1580 const SwFrm* pCell = pCnt->GetUpper();
1581 while ( pCell && !pCell->IsCellFrm() )
1582 pCell = pCell->GetUpper();
1583 if ( pCell && 1 != static_cast<const SwCellFrm*>( pCell )->GetLayoutRowSpan() )
1584 bSkipContent = true;
1587 if ( bFormatPossible && !bSkipContent )
1589 bRet |= !pCnt->IsValid();
1590 // --> OD 2004-10-06 #i26945# - no extra invalidation of floating
1591 // screen objects needed.
1592 // Thus, delete call of method <SwFrm::InvalidateObjs( true )>
1593 // <--
1594 pCnt->Calc();
1595 // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrm(..)>
1596 // to format the floating screen objects
1597 // --> OD 2005-05-03 #i46941# - frame has to be valid
1598 // Note: frame could be invalid after calling its format, if it's locked.
1599 ASSERT( !pCnt->IsTxtFrm() ||
1600 pCnt->IsValid() ||
1601 static_cast<SwTxtFrm*>(pCnt)->IsJoinLocked(),
1602 "<lcl_CalcLowers(..)> - text frame invalid and not locked." );
1603 if ( pCnt->IsTxtFrm() && pCnt->IsValid() )
1605 // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame to
1606 // the object formatter
1607 if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt,
1608 *(pCnt->FindPageFrm()) ) )
1609 // <--
1611 if ( pCnt->GetRegisteredIn() == pLoopControlCond )
1612 ++nLoopControlRuns;
1613 else
1615 nLoopControlRuns = 0;
1616 pLoopControlCond = pCnt->GetRegisteredIn();
1619 if ( nLoopControlRuns < nLoopControlMax )
1621 // restart format with first content
1622 pCnt = pLay->ContainsCntnt();
1623 continue;
1626 #if OSL_DEBUG_LEVEL > 1
1627 ASSERT( false, "LoopControl in lcl_CalcLowers" )
1628 #endif
1631 pCnt->GetUpper()->Calc();
1633 // <--
1634 if( ! bAll && (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 )
1635 break;
1636 pCnt = pCnt->GetNextCntntFrm();
1638 return bRet;
1641 // --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control
1642 // that only row and cell frames are formatted.
1643 BOOL MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm,
1644 long nBottom,
1645 bool _bOnlyRowsAndCells )
1647 // LONG_MAX == nBottom means we have to calculate all
1648 BOOL bAll = LONG_MAX == nBottom;
1649 BOOL bRet = FALSE;
1650 const SwFrm* pOldUp = pFrm->GetUpper();
1651 SWRECTFN( pFrm )
1654 // --> OD 2004-10-15 #i26945# - parameter <_bOnlyRowsAndCells> controls,
1655 // if only row and cell frames are formatted.
1656 if ( pFrm->IsLayoutFrm() &&
1657 ( !_bOnlyRowsAndCells || pFrm->IsRowFrm() || pFrm->IsCellFrm() ) )
1658 // <--
1660 // --> FME 2006-02-23 #130744# An invalid locked table frame will
1661 // not be calculated => It will not become valid =>
1662 // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
1663 bRet |= !pFrm->IsValid() && ( !pFrm->IsTabFrm() || !static_cast<SwTabFrm*>(pFrm)->IsJoinLocked() );
1664 // <--
1665 pFrm->Calc();
1666 if( static_cast<SwLayoutFrm*>(pFrm)->Lower() )
1667 bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrm*>(pFrm)->Lower(), nBottom);
1669 // NEW TABLES
1670 SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm);
1671 if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1673 SwCellFrm& rToCalc = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true ));
1674 bRet |= !rToCalc.IsValid();
1675 rToCalc.Calc();
1676 if ( rToCalc.Lower() )
1677 bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom);
1680 pFrm = pFrm->GetNext();
1681 } while( pFrm &&
1682 ( bAll ||
1683 (*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 )
1684 && pFrm->GetUpper() == pOldUp );
1685 return bRet;
1688 void MA_FASTCALL lcl_FirstTabCalc( SwTabFrm *pTab )
1690 SWRECTFN( pTab )
1691 if ( !pTab->IsFollow() && !pTab->GetTable()->IsTblComplex() )
1693 SwLayoutFrm* pRow = (SwLayoutFrm*)pTab->Lower();
1694 // --> FME 2006-07-17 #134526# TabFrm without a lower? Better we check
1695 // it before crashing. However, I still don't know how this can happen!
1696 while ( pRow )
1698 SwLayoutFrm *pCell = (SwLayoutFrm*)pRow->Lower();
1699 SwFrm *pCnt = pCell->Lower();
1700 // --> OD 2006-11-08 #i70641# - make code robust
1701 if ( pCnt )
1703 pCnt->Calc();
1704 const long nCellHeight = (pCell->Frm().*fnRect->fnGetHeight)();
1705 const long nCellY = (pCell->Frm().*fnRect->fnGetTop)()-1;
1706 const long nCntHeight = (pCnt->Frm().*fnRect->fnGetHeight)();
1707 const long nCntY = (pCnt->Frm().*fnRect->fnGetTop)()-1;
1708 if ( 0 != (pCell = (SwLayoutFrm*)pCell->GetNext()) )
1712 (pCell->Frm().*fnRect->fnSetTopAndHeight)( nCellY, nCellHeight );
1713 (pCell->Prt().*fnRect->fnSetHeight)( nCellHeight );
1714 pCell->_InvalidateAll();
1716 pCnt = pCell->Lower();
1717 if ( pCnt )
1719 (pCnt->Frm().*fnRect->fnSetTopAndHeight)(nCntY, nCntHeight);
1720 (pCnt->Prt().*fnRect->fnSetHeight)( nCntHeight );
1721 pCnt->_InvalidateAll();
1724 pCell = (SwLayoutFrm*)pCell->GetNext();
1725 } while ( pCell );
1728 SwTwips nRowTop = (pRow->Frm().*fnRect->fnGetTop)();
1729 SwTwips nUpBot = (pTab->GetUpper()->Frm().*fnRect->fnGetBottom)();
1730 if( (*fnRect->fnYDiff)( nUpBot, nRowTop ) < 0 )
1731 break;
1733 // <--
1734 pRow = (SwLayoutFrm*)pRow->GetNext();
1737 SwFrm *pUp = pTab->GetUpper();
1738 long nBottom = (pUp->*fnRect->fnGetPrtBottom)();
1739 if ( pTab->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) )
1740 nBottom += pUp->Grow( LONG_MAX, TRUE );
1741 lcl_CalcLowers( (SwLayoutFrm*)pTab->Lower(), pTab, LONG_MAX, false );
1744 void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom )
1746 // --> OD 2004-10-05 #i26945# - For correct appliance of the 'straightforward
1747 // object positioning process, it's needed to notify that the page frame,
1748 // on which the given layout frame is in, is in its layout process.
1749 SwPageFrm* pPageFrm = rRow.FindPageFrm();
1750 if ( pPageFrm && !pPageFrm->IsLayoutInProgress() )
1751 pPageFrm->SetLayoutInProgress( true );
1752 else
1753 pPageFrm = 0L;
1754 // <--
1756 // FME 2007-08-30 #i81146# new loop control
1757 USHORT nLoopControlRuns_1 = 0;
1758 USHORT nLoopControlStage_1 = 0;
1759 const USHORT nLoopControlMax = 10;
1761 bool bCheck = true;
1764 // FME 2007-08-30 #i81146# new loop control
1765 USHORT nLoopControlRuns_2 = 0;
1766 USHORT nLoopControlStage_2 = 0;
1768 while( lcl_InnerCalcLayout( &rRow, nBottom ) )
1770 if ( ++nLoopControlRuns_2 > nLoopControlMax )
1772 #if OSL_DEBUG_LEVEL > 1
1773 ASSERT( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" );
1774 ASSERT( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" );
1775 ASSERT( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" );
1776 #endif
1777 rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ );
1778 nLoopControlRuns_2 = 0;
1779 if( nLoopControlStage_2 > 2 )
1780 break;
1783 bCheck = true;
1786 if( bCheck )
1788 // --> OD 2004-11-23 #115759# - force another format of the
1789 // lowers, if at least one of it was invalid.
1790 bCheck = lcl_CalcLowers( &rRow, rRow.GetUpper(), nBottom, true );
1791 // <--
1793 // NEW TABLES
1794 // First we calculate the cells with row span of < 1, afterwards
1795 // all cells with row span of > 1:
1796 for ( int i = 0; i < 2; ++i )
1798 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(rRow.Lower());
1799 while ( pCellFrm )
1801 const bool bCalc = 0 == i ?
1802 pCellFrm->GetLayoutRowSpan() < 1 :
1803 pCellFrm->GetLayoutRowSpan() > 1;
1805 if ( bCalc )
1807 SwCellFrm& rToRecalc = 0 == i ?
1808 const_cast<SwCellFrm&>(pCellFrm->FindStartEndOfRowSpanCell( true, true )) :
1809 *pCellFrm;
1810 bCheck |= lcl_CalcLowers( &rToRecalc, &rToRecalc, nBottom, false );
1813 pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext());
1817 if ( bCheck )
1819 if ( ++nLoopControlRuns_1 > nLoopControlMax )
1821 #if OSL_DEBUG_LEVEL > 1
1822 ASSERT( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" );
1823 ASSERT( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" );
1824 ASSERT( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" );
1825 #endif
1826 rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ );
1827 nLoopControlRuns_1 = 0;
1828 if( nLoopControlStage_1 > 2 )
1829 break;
1832 continue;
1835 break;
1836 } while( true );
1838 // --> OD 2004-10-05 #i26945#
1839 if ( pPageFrm )
1840 pPageFrm->SetLayoutInProgress( false );
1841 // <--
1844 void MA_FASTCALL lcl_RecalcTable( SwTabFrm& rTab,
1845 SwLayoutFrm *pFirstRow,
1846 SwLayNotify &rNotify )
1848 if ( rTab.Lower() )
1850 if ( !pFirstRow )
1852 pFirstRow = (SwLayoutFrm*)rTab.Lower();
1853 rNotify.SetLowersComplete( TRUE );
1855 ::SwInvalidatePositions( pFirstRow, LONG_MAX );
1856 lcl_RecalcRow( static_cast<SwRowFrm&>(*pFirstRow), LONG_MAX );
1860 // This is a new function to check the first condition whether
1861 // a tab frame may move backward. It replaces the formerly used
1862 // GetIndPrev(), which did not work correctly for #i5947#
1863 bool lcl_NoPrev( const SwFrm& rFrm )
1865 // --> OD 2007-09-04 #i79774#, #b6596954#
1866 // skip empty sections on investigation of direct previous frame.
1867 // use information, that at least one empty section is skipped in the following code.
1868 bool bSkippedDirectPrevEmptySection( false );
1869 if ( rFrm.GetPrev() )
1871 const SwFrm* pPrev( rFrm.GetPrev() );
1872 while ( pPrev &&
1873 pPrev->IsSctFrm() &&
1874 !dynamic_cast<const SwSectionFrm*>(pPrev)->GetSection() )
1876 pPrev = pPrev->GetPrev();
1877 bSkippedDirectPrevEmptySection = true;
1879 if ( pPrev )
1881 return false;
1885 if ( ( !bSkippedDirectPrevEmptySection && !rFrm.GetIndPrev() ) ||
1886 ( bSkippedDirectPrevEmptySection &&
1887 ( !rFrm.IsInSct() || !rFrm._GetIndPrev() ) ) )
1889 return true;
1891 // <--
1893 // I do not have a direct prev, but I have an indirect prev.
1894 // In section frames I have to check if I'm located inside
1895 // the first column:
1896 if ( rFrm.IsInSct() )
1898 const SwFrm* pSct = rFrm.GetUpper();
1899 if ( pSct && pSct->IsColBodyFrm() &&
1900 (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() )
1902 const SwFrm* pPrevCol = rFrm.GetUpper()->GetUpper()->GetPrev();
1903 if ( pPrevCol )
1904 // I'm not inside the first column and do not have a direct
1905 // prev. I can try to go backward.
1906 return true;
1910 return false;
1913 #define KEEPTAB ( !GetFollow() && !IsFollow() )
1915 // --> OD 2005-09-28 #b6329202# - helper method to find next content frame of
1916 // a table frame and format it to assure keep attribute.
1917 // method return true, if a next content frame is formatted.
1918 // Precondition: The given table frame hasn't a follow and isn't a follow.
1919 SwFrm* lcl_FormatNextCntntForKeep( SwTabFrm* pTabFrm )
1921 // find next content, table or section
1922 SwFrm* pNxt = pTabFrm->FindNext();
1924 // skip empty sections
1925 while ( pNxt && pNxt->IsSctFrm() &&
1926 !static_cast<SwSectionFrm*>(pNxt)->GetSection() )
1928 pNxt = pNxt->FindNext();
1931 // if found next frame is a section, get its first content.
1932 if ( pNxt && pNxt->IsSctFrm() )
1934 pNxt = static_cast<SwSectionFrm*>(pNxt)->ContainsAny();
1937 // format found next frame.
1938 // if table frame is inside another table, method <SwFrm::MakeAll()> is
1939 // called to avoid that the superior table frame is formatted.
1940 if ( pNxt )
1942 if ( pTabFrm->GetUpper()->IsInTab() )
1943 pNxt->MakeAll();
1944 else
1945 pNxt->Calc();
1948 return pNxt;
1951 void SwTabFrm::MakeAll()
1953 if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
1954 return;
1956 if ( HasFollow() )
1958 SwTabFrm* pFollowFrm = (SwTabFrm*)GetFollow();
1959 ASSERT( !pFollowFrm->IsJoinLocked() || !pFollowFrm->IsRebuildLastLine(),
1960 "SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" )
1961 if ( pFollowFrm->IsJoinLocked() && pFollowFrm->IsRebuildLastLine() )
1962 return;
1965 PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
1967 LockJoin(); //Ich lass mich nicht unterwegs vernichten.
1968 SwLayNotify aNotify( this ); //uebernimmt im DTor die Benachrichtigung
1969 // If pos is invalid, we have to call a SetInvaKeep at aNotify.
1970 // Otherwise the keep atribute would not work in front of a table.
1971 const BOOL bOldValidPos = GetValidPosFlag();
1973 //Wenn mein direkter Nachbar gleichzeitig mein Follow ist
1974 //verleibe ich mir das Teil ein.
1975 // OD 09.04.2003 #108698# - join all follows, which are placed on the
1976 // same page/column.
1977 // OD 29.04.2003 #109213# - join follow, only if join for the follow
1978 // is not locked. Otherwise, join will not be performed and this loop
1979 // will be endless.
1980 while ( GetNext() && GetNext() == GetFollow() &&
1981 !GetFollow()->IsJoinLocked()
1984 if ( HasFollowFlowLine() )
1985 RemoveFollowFlowLine();
1986 Join();
1989 // The bRemoveFollowFlowLinePending is set if the split attribute of the
1990 // last line is set:
1991 if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() )
1993 if ( RemoveFollowFlowLine() )
1994 Join();
1995 SetRemoveFollowFlowLinePending( FALSE );
1998 if ( bResizeHTMLTable ) //Optimiertes Zusammenspiel mit Grow/Shrink des Inhaltes
2000 bResizeHTMLTable = FALSE;
2001 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
2002 if ( pLayout )
2003 bCalcLowers = pLayout->Resize(
2004 pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
2008 BOOL bMakePage = TRUE; //solange TRUE kann eine neue Seite
2009 //angelegt werden (genau einmal)
2010 BOOL bMovedBwd = FALSE; //Wird TRUE wenn der Frame zurueckfliesst
2011 BOOL bMovedFwd = FALSE; //solange FALSE kann der Frm zurueck-
2012 //fliessen (solange, bis er einmal
2013 //vorwaerts ge'moved wurde).
2014 BOOL bSplit = FALSE; //Wird TRUE wenn der Frm gesplittet wurde.
2015 const BOOL bFtnsInDoc = 0 != GetFmt()->GetDoc()->GetFtnIdxs().Count();
2016 BOOL bMoveable;
2017 const BOOL bFly = IsInFly();
2019 SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2020 const SwBorderAttrs *pAttrs = pAccess->Get();
2022 // The beloved keep attribute
2023 const bool bKeep = IsKeep( pAttrs->GetAttrSet() );
2025 // All rows should keep together
2026 // OD 2004-05-25 #i21478# - don't split table, if it has to keep with next
2027 const bool bDontSplit = !IsFollow() &&
2028 ( !GetFmt()->GetLayoutSplit().GetValue() || bKeep );
2030 // The number of repeated headlines
2031 const USHORT nRepeat = GetTable()->GetRowsToRepeat();
2033 // This flag indicates that we are allowed to try to split the
2034 // table rows.
2035 bool bTryToSplit = true;
2037 // --> FME 2006-02-16 #131283#
2038 // Indicates that two individual rows may keep together, based on the keep
2039 // attribute set at the first paragraph in the first cell.
2040 const bool bTableRowKeep = !bDontSplit && GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP);
2042 // The Magic Move: Used for the table row keep feature.
2043 // If only the last row of the table wants to keep (implicitely by setting
2044 // keep for the first paragraph in the first cell), and this table does
2045 // not have a next, the last line will be cut. Loop prevention: Only
2046 // one try.
2047 bool bLastRowHasToMoveToFollow = false;
2048 bool bLastRowMoveNoMoreTries = false;
2050 // Join follow table, if this table is not allowed to split:
2051 if ( bDontSplit )
2053 while ( GetFollow() && !GetFollow()->IsJoinLocked() )
2055 if ( HasFollowFlowLine() )
2056 RemoveFollowFlowLine();
2057 Join();
2061 // Join follow table, if this does not have enough (repeated) lines:
2062 if ( nRepeat )
2064 if( GetFollow() && !GetFollow()->IsJoinLocked() &&
2065 0 == GetFirstNonHeadlineRow() )
2067 if ( HasFollowFlowLine() )
2068 RemoveFollowFlowLine();
2069 Join();
2073 // Join follow table, if last row of this table should keep:
2074 if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() )
2076 const SwRowFrm* pTmpRow = static_cast<const SwRowFrm*>(GetLastLower());
2077 if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
2079 if ( HasFollowFlowLine() )
2080 RemoveFollowFlowLine();
2081 Join();
2085 //Einen Frischling moven wir gleich schon einmal vorwaerts...
2086 if ( !Frm().Top() && IsFollow() )
2088 SwFrm *pPre = GetPrev();
2089 if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this)
2091 if ( !MoveFwd( bMakePage, FALSE ) )
2092 bMakePage = FALSE;
2093 bMovedFwd = TRUE;
2097 int nUnSplitted = 5; // Just another loop control :-(
2098 SWRECTFN( this )
2099 while ( !bValidPos || !bValidSize || !bValidPrtArea )
2101 if ( TRUE == (bMoveable = IsMoveable()) )
2102 if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) )
2104 bMovedFwd = TRUE;
2105 bCalcLowers = TRUE;
2106 // --> OD 2009-08-12 #i99267#
2107 // reset <bSplit> after forward move to assure that follows
2108 // can be joined, if further space is available.
2109 bSplit = FALSE;
2110 // <--
2113 Point aOldPos( (Frm().*fnRect->fnGetPos)() );
2114 MakePos();
2116 if ( aOldPos != (Frm().*fnRect->fnGetPos)() )
2118 if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() )
2120 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
2121 if( pLayout )
2123 delete pAccess;
2124 bCalcLowers |= pLayout->Resize(
2125 pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
2126 pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
2127 pAttrs = pAccess->Get();
2130 bValidPrtArea = FALSE;
2131 aNotify.SetLowersComplete( FALSE );
2133 SwFrm *pPre;
2134 if ( bKeep || (0 != (pPre = FindPrev()) &&
2135 pPre->GetAttrSet()->GetKeep().GetValue()) )
2137 bCalcLowers = TRUE;
2138 // --> OD 2009-03-06 #i99267#
2139 // reset <bSplit> after forward move to assure that follows
2140 // can be joined, if further space is available.
2141 bSplit = FALSE;
2142 // <--
2146 //Wir muessen die Hoehe der ersten Zeile kennen, denn nur wenn diese
2147 //kleiner wird muss ggf. der Master angestossen werden um noetigenfalls
2148 //die Zeile aufzunehmen.
2149 long n1StLineHeight = 0;
2150 if ( IsFollow() )
2152 SwFrm* pFrm = GetFirstNonHeadlineRow();
2153 if ( pFrm )
2154 n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)();
2157 if ( !bValidSize || !bValidPrtArea )
2159 // HB #i101593# no optimization as it leeds to not layouting certain nested tables
2160 // const BOOL bOptLower = (Frm().*fnRect->fnGetHeight)() == 0;
2161 const BOOL bOptLower = FALSE;
2163 const long nOldPrtWidth = (Prt().*fnRect->fnGetWidth)();
2164 const long nOldFrmWidth = (Frm().*fnRect->fnGetWidth)();
2165 const Point aOldPrtPos = (Prt().*fnRect->fnGetPos)();
2166 Format( pAttrs );
2168 SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
2169 if ( /*!bOptLower &&*/ pLayout &&
2170 ((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth ||
2171 (Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) )
2173 delete pAccess;
2174 bCalcLowers |= pLayout->Resize(
2175 pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
2176 // GetFmt()->GetDoc()->GetDocShell()->IsReadOnly() ? FALSE : TRUE );
2177 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2178 pAttrs = pAccess->Get();
2180 if ( !bOptLower && aOldPrtPos != (Prt().*fnRect->fnGetPos)() )
2181 aNotify.SetLowersComplete( FALSE );
2183 if ( bOptLower && Lower() )
2185 //MA 24. May. 95: Optimierungsversuch!
2186 //Ganz nigel nagel neu das Teil. Damit wir nicht n-fach
2187 //MakeAll'en formatieren wir flugs den Inhalt.
2188 //Das erste Format mussten wir allerdings abwarten, damit
2189 //die Breiten Stimmen!
2190 //MA: Fix, Kein Calc wenn evtl. noch Seitengebunde Flys
2191 //an den Cntnt haengen (siehe frmtool.cxx, ~SwCntntNotify).
2192 SwDoc *pDoc = GetFmt()->GetDoc();
2193 if ( !pDoc->GetSpzFrmFmts()->Count() ||
2194 pDoc->IsLoaded() || pDoc->IsNewDoc() )
2196 //MA 28. Nov. 95: Und wieder ein Trick, gleich mal sehen
2197 //ob ein Rueckfluss lohnt.
2198 if ( bMoveable && !GetPrev() )
2200 GetLeaf( MAKEPAGE_NONE, FALSE ); //setzt das BackMoveJump
2201 if ( SwFlowFrm::IsMoveBwdJump() )
2203 BOOL bDummy;
2204 SwFtnBossFrm *pOldBoss = bFtnsInDoc ?
2205 FindFtnBossFrm( TRUE ) : 0;
2206 const BOOL bOldPrev = GetPrev() != 0;
2207 if ( MoveBwd( bDummy ) )
2209 SWREFRESHFN( this )
2210 bMovedBwd = TRUE;
2211 if ( bFtnsInDoc )
2212 MoveLowerFtns( 0, pOldBoss, 0, TRUE );
2214 long nOldTop = (Frm().*fnRect->fnGetTop)();
2215 MakePos();
2216 if( nOldTop != (Frm().*fnRect->fnGetTop)() )
2218 SwHTMLTableLayout *pHTMLLayout =
2219 GetTable()->GetHTMLTableLayout();
2220 if( pHTMLLayout )
2222 delete pAccess;
2223 bCalcLowers |= pHTMLLayout->Resize(
2224 pHTMLLayout->GetBrowseWidthByTabFrm(
2225 *this ), FALSE );
2226 pAccess= new SwBorderAttrAccess(
2227 SwFrm::GetCache(), this );
2228 pAttrs = pAccess->Get();
2232 if ( bOldPrev != (0 != GetPrev()) )
2234 //Abstand nicht vergessen!
2235 bValidPrtArea = FALSE;
2236 Format( pAttrs );
2238 if ( bKeep && KEEPTAB )
2240 // --> OD 2005-09-28 #b6329202#
2241 // Consider case that table is inside another
2242 // table, because it has to be avoided, that
2243 // superior table is formatted.
2244 // Thus, find next content, table or section
2245 // and, if a section is found, get its first
2246 // content.
2247 // SwFrm *pNxt = FindNextCnt();
2248 // // FindNextCnt geht ggf. in einen Bereich
2249 // // hinein, in eine Tabelle allerdings auch
2250 // if( pNxt && pNxt->IsInTab() )
2251 // pNxt = pNxt->FindTabFrm();
2252 // if ( pNxt )
2253 // {
2254 // pNxt->Calc();
2255 // if ( !GetNext() )
2256 // bValidPos = FALSE;
2257 // }
2258 if ( 0 != lcl_FormatNextCntntForKeep( this ) &&
2259 !GetNext() )
2261 bValidPos = FALSE;
2263 // <--
2268 ::lcl_FirstTabCalc( this );
2269 bValidSize = bValidPrtArea = FALSE;
2270 Format( pAttrs );
2271 aNotify.SetLowersComplete( TRUE );
2276 //Wenn ich der erste einer Kette bin koennte ich mal sehen ob
2277 //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll).
2278 //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts
2279 //geflosssen sein.
2280 if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) )
2282 //Bei Follows muss der Master benachrichtigt
2283 //werden. Der Follow muss nur dann Moven, wenn er leere Blaetter
2284 //ueberspringen muss.
2285 if ( IsFollow() )
2287 //Nur wenn die Hoehe der ersten Zeile kleiner geworder ist.
2288 SwFrm *pFrm = GetFirstNonHeadlineRow();
2289 if( pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight )() )
2291 SwTabFrm *pMaster = (SwTabFrm*)FindMaster();
2292 BOOL bDummy;
2293 if ( ShouldBwdMoved( pMaster->GetUpper(), FALSE, bDummy ) )
2294 pMaster->InvalidatePos();
2297 SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( TRUE ) : 0;
2298 BOOL bReformat;
2299 if ( MoveBwd( bReformat ) )
2301 SWREFRESHFN( this )
2302 bMovedBwd = TRUE;
2303 aNotify.SetLowersComplete( FALSE );
2304 if ( bFtnsInDoc )
2305 MoveLowerFtns( 0, pOldBoss, 0, TRUE );
2306 if ( bReformat || bKeep )
2308 long nOldTop = (Frm().*fnRect->fnGetTop)();
2309 MakePos();
2310 if( nOldTop != (Frm().*fnRect->fnGetTop)() )
2312 SwHTMLTableLayout *pHTMLLayout =
2313 GetTable()->GetHTMLTableLayout();
2314 if( pHTMLLayout )
2316 delete pAccess;
2317 bCalcLowers |= pHTMLLayout->Resize(
2318 pHTMLLayout->GetBrowseWidthByTabFrm( *this ),
2319 FALSE );
2321 pAccess= new SwBorderAttrAccess(
2322 SwFrm::GetCache(), this );
2323 pAttrs = pAccess->Get();
2326 bValidPrtArea = FALSE;
2327 Format( pAttrs );
2329 lcl_RecalcTable( *this, 0, aNotify );
2330 bLowersFormatted = TRUE;
2331 if ( bKeep && KEEPTAB )
2333 // --> OD 2005-09-28 #b6329202#
2334 // Consider case that table is inside another table,
2335 // because it has to be avoided, that superior table
2336 // is formatted.
2337 // Thus, find next content, table or section
2338 // and, if a section is found, get its first
2339 // content.
2340 // SwFrm *pNxt = FindNextCnt();
2341 // if( pNxt && pNxt->IsInTab() )
2342 // pNxt = pNxt->FindTabFrm();
2343 // if ( pNxt )
2344 // {
2345 // pNxt->Calc();
2346 // if ( !GetNext() )
2347 // bValidPos = FALSE;
2348 // }
2349 if ( 0 != lcl_FormatNextCntntForKeep( this ) && !GetNext() )
2351 bValidPos = FALSE;
2353 // <--
2359 //Wieder ein Wert ungueltig? - dann nochmal das ganze...
2360 if ( !bValidPos || !bValidSize || !bValidPrtArea )
2361 continue;
2363 // check, if calculation of table frame is ready.
2365 /// OD 23.10.2002 #103517# - Local variable <nDistanceToUpperPrtBottom>
2366 /// Introduce local variable and init it with the distance from the
2367 /// table frame bottom to the bottom of the upper printing area.
2368 /// Note: negative values denotes the situation that table frame doesn't
2369 /// fit in its upper.
2371 SwTwips nDistanceToUpperPrtBottom =
2372 (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2374 /// OD 23.10.2002 #103517# - In online layout try to grow upper of table
2375 /// frame, if table frame doesn't fit in its upper.
2376 const bool bBrowseMode = GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE);
2377 if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode )
2379 if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) )
2381 // upper is grown --> recalculate <nDistanceToUpperPrtBottom>
2382 nDistanceToUpperPrtBottom =
2383 (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2387 // If there is still some space left in the upper, we check if we
2388 // can join some rows of the follow.
2389 // Setting bLastRowHasToMoveToFollow to true means we want to force
2390 // the table to be split! Only skip this if condition once.
2391 if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow )
2393 // OD 23.10.2002 - translate german commentary
2394 // If there is space left in the upper printing area, join as for trial
2395 // at least one further row of an existing follow.
2396 if ( !bSplit && GetFollow() )
2398 BOOL bDummy;
2399 if ( GetFollow()->ShouldBwdMoved( GetUpper(), FALSE, bDummy ) )
2401 SwFrm *pTmp = GetUpper();
2402 SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)();
2403 if ( bBrowseMode )
2404 nDeadLine += pTmp->Grow( LONG_MAX, TRUE );
2405 if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 )
2408 // First, we remove an existing follow flow line.
2410 if ( HasFollowFlowLine() )
2412 SwFrm* pLastLine = const_cast<SwFrm*>(GetLastLower());
2413 RemoveFollowFlowLine();
2414 // invalidate and rebuild last row
2415 if ( pLastLine )
2417 ::SwInvalidateAll( pLastLine, LONG_MAX );
2418 SetRebuildLastLine( TRUE );
2419 lcl_RecalcRow( static_cast<SwRowFrm&>(*pLastLine), LONG_MAX );
2420 SetRebuildLastLine( FALSE );
2423 SwFrm* pRow = GetFollow()->GetFirstNonHeadlineRow();
2425 if ( !pRow || !pRow->GetNext() )
2426 //Der Follow wird leer und damit ueberfluessig.
2427 Join();
2429 continue;
2433 // If there is no follow flow line, we move the first
2434 // row in the follow table to the master table.
2436 SwRowFrm *pRow = GetFollow()->GetFirstNonHeadlineRow();
2438 //Der Follow wird leer und damit ueberfluessig.
2439 if ( !pRow )
2441 Join();
2442 continue;
2445 const SwTwips nOld = (Frm().*fnRect->fnGetHeight)();
2446 long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow );
2447 SwFrm* pRowToMove = pRow;
2449 while ( pRowToMove && nRowsToMove-- > 0 )
2451 const BOOL bMoveFtns = bFtnsInDoc && !GetFollow()->IsJoinLocked();
2453 SwFtnBossFrm *pOldBoss = 0;
2454 if ( bMoveFtns )
2455 pOldBoss = pRowToMove->FindFtnBossFrm( TRUE );
2457 SwFrm* pNextRow = pRowToMove->GetNext();
2459 if ( !pNextRow )
2460 //Der Follow wird leer und damit ueberfluessig.
2461 Join();
2462 else
2464 pRowToMove->Cut();
2465 pRowToMove->Paste( this );
2468 //Die Fussnoten verschieben!
2469 if ( bMoveFtns )
2470 if ( ((SwLayoutFrm*)pRowToMove)->MoveLowerFtns(
2471 0, pOldBoss, FindFtnBossFrm( TRUE ), TRUE ) )
2472 GetUpper()->Calc();
2474 pRowToMove = pNextRow;
2477 if ( nOld != (Frm().*fnRect->fnGetHeight)() )
2478 lcl_RecalcTable( *this, (SwLayoutFrm*)pRow, aNotify );
2480 continue;
2484 else if ( KEEPTAB )
2486 bool bFormat = false;
2487 if ( bKeep )
2488 bFormat = true;
2489 else if ( bTableRowKeep && !bLastRowMoveNoMoreTries )
2491 // We only want to give the last row one chance to move
2492 // to the follow table. Set the flag as early as possible:
2493 bLastRowMoveNoMoreTries = true;
2495 // The last line of the table has to be cut off if:
2496 // 1. The table does not want to keep with its next
2497 // 2. The compatibility option is set and the table is allowed to split
2498 // 3. We did not already cut off the last row
2499 // 4. There is not break after attribute set at the table
2500 // 5. There is no break before attribute set behind the table
2501 // 6. There is no section change behind the table (see IsKeep)
2502 // 7. The last table row wants to keep with its next.
2503 const SwRowFrm* pLastRow = static_cast<const SwRowFrm*>(GetLastLower());
2504 if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) &&
2505 pLastRow->ShouldRowKeepWithNext() )
2506 bFormat = true;
2509 if ( bFormat )
2511 delete pAccess;
2513 // --> OD 2005-09-28 #b6329202#
2514 // Consider case that table is inside another table, because
2515 // it has to be avoided, that superior table is formatted.
2516 // Thus, find next content, table or section and, if a section
2517 // is found, get its first content.
2518 const SwFrm* pTmpNxt = lcl_FormatNextCntntForKeep( this );
2519 // <--
2521 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2522 pAttrs = pAccess->Get();
2524 // The last row wants to keep with the frame behind the table.
2525 // Check if the next frame is on a different page and valid.
2526 // In this case we do a magic trick:
2527 if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->IsValid() )
2529 bValidPos = FALSE;
2530 bLastRowHasToMoveToFollow = true;
2535 if ( IsValid() )
2537 if ( bCalcLowers )
2539 lcl_RecalcTable( *this, 0, aNotify );
2540 bLowersFormatted = TRUE;
2541 bCalcLowers = FALSE;
2543 else if ( bONECalcLowers )
2545 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2546 bONECalcLowers = FALSE;
2549 continue;
2552 //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt
2553 //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen
2555 //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe
2556 //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man
2557 //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und
2558 //zwar mit aller Kraft.
2559 if ( !bMoveable )
2561 if ( bCalcLowers && IsValid() )
2563 lcl_RecalcTable( *this, 0, aNotify );
2564 bLowersFormatted = TRUE;
2565 bCalcLowers = FALSE;
2567 else if ( bONECalcLowers )
2569 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2570 bONECalcLowers = FALSE;
2573 // It does not make sense to cut off the last line if we are
2574 // not moveable:
2575 bLastRowHasToMoveToFollow = false;
2577 continue;
2580 if ( bCalcLowers && IsValid() )
2582 lcl_RecalcTable( *this, 0, aNotify );
2583 bLowersFormatted = TRUE;
2584 bCalcLowers = FALSE;
2585 if( !IsValid() )
2586 continue;
2590 // First try to split the table. Condition:
2591 // 1. We have at least one non headline row
2592 // 2. If this row wants to keep, we need an additional row
2593 // 3. The table is allowed to split or we do not have an pIndPrev:
2595 SwFrm* pIndPrev = GetIndPrev();
2596 const SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
2598 if ( pFirstNonHeadlineRow && nUnSplitted > 0 &&
2599 ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() || !pFirstNonHeadlineRow->ShouldRowKeepWithNext() ) &&
2600 ( !bDontSplit || !pIndPrev ) )
2602 // --> FME 2004-06-03 #i29438#
2603 // Special DoNotSplit case:
2604 // We better avoid splitting of a row frame if we are inside a columned
2605 // section which has a height of 0, because this is not growable and thus
2606 // all kinds of unexpected things could happen.
2607 const SwSectionFrm* pTmpSct = 0;
2608 if ( IsInSct() &&
2609 (pTmpSct = FindSctFrm())->Lower()->IsColumnFrm() &&
2610 0 == (GetUpper()->Frm().*fnRect->fnGetHeight)() )
2612 bTryToSplit = false;
2614 // <--
2616 // 1. Try: bTryToSplit = true => Try to split the row.
2617 // 2. Try: bTryToSplit = false => Split the table between the rows.
2618 if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit )
2620 SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
2621 if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE)
2622 nDeadLine = (*fnRect->fnYInc)( nDeadLine,
2623 GetUpper()->Grow( LONG_MAX, TRUE ) );
2625 ::lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), nDeadLine );
2626 bLowersFormatted = TRUE;
2627 aNotify.SetLowersComplete( TRUE );
2629 // One more check if its really necessary to split the table.
2630 // 1. The table either has to exceed the deadline or
2631 // 2. We explicitly want to cut off the last row.
2632 if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 && !bLastRowHasToMoveToFollow )
2634 continue;
2637 // Set to false again as early as possible.
2638 bLastRowHasToMoveToFollow = false;
2640 // --> FME 2005-08-03 #i52781#
2641 // YaSC - Yet another special case:
2642 // If our upper is inside a table cell which is not allowed
2643 // to split, we do not try to split:
2644 if ( GetUpper()->IsInTab() )
2646 const SwFrm* pTmpRow = GetUpper();
2647 while ( pTmpRow && !pTmpRow->IsRowFrm() )
2648 pTmpRow = pTmpRow->GetUpper();
2649 if ( pTmpRow && !static_cast<const SwRowFrm*>(pTmpRow)->IsRowSplitAllowed() )
2650 continue;
2652 // <--
2654 USHORT nMinNumOfLines = nRepeat;
2656 if ( bTableRowKeep )
2658 const SwRowFrm* pTmpRow = pFirstNonHeadlineRow;
2659 while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
2661 ++nMinNumOfLines;
2662 pTmpRow = static_cast<const SwRowFrm*>(pTmpRow->GetNext());
2664 // Check if all lines want to keep together and we
2665 // have a pIndPrev. In this case we set nDeadLine
2666 // to 0, forcing the table to move forward.
2667 if ( !pTmpRow && pIndPrev )
2668 nDeadLine = 0;
2671 if ( !bTryToSplit )
2672 ++nMinNumOfLines;
2674 const SwTwips nBreakLine = (*fnRect->fnYInc)(
2675 (Frm().*fnRect->fnGetTop)(),
2676 (this->*fnRect->fnGetTopMargin)() +
2677 lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) );
2679 // Some more checks if we want to call the split algorithm or not:
2680 // The repeating lines / keeping lines still fit into the upper or
2681 // if we do not have an (in)direkt Prev, we split anyway.
2682 if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev )
2684 aNotify.SetLowersComplete( FALSE );
2685 bSplit = TRUE;
2688 // An existing follow flow line has to be removed.
2690 if ( HasFollowFlowLine() )
2691 RemoveFollowFlowLine();
2693 const bool bSplitError = !Split( nDeadLine, bTryToSplit, bTableRowKeep );
2694 if( !bTryToSplit && !bSplitError && nUnSplitted > 0 )
2695 --nUnSplitted;
2697 // --> FME 2004-06-09 #i29771# Two tries to split the table:
2698 // If an error occured during splitting. We start a second
2699 // try, this time without splitting of table rows.
2700 if ( bSplitError )
2702 if ( HasFollowFlowLine() )
2703 RemoveFollowFlowLine();
2706 // --> FME 2005-02-10 #119477#
2707 // If splitting the table was successfull or not,
2708 // we do not want to have 'empty' follow tables.
2709 if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() )
2710 Join();
2711 // <--
2714 // We want to restore the situation before the failed
2715 // split operation as good as possible. Therefore we
2716 // do some more calculations. Note: Restricting this
2717 // to nDeadLine may not be enough.
2718 if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426
2720 lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX );
2721 bValidPos = FALSE;
2722 bTryToSplit = false;
2723 continue;
2725 // <--
2727 bTryToSplit = !bSplitError;
2729 //Damit es nicht zu Oszillationen kommt, muss der
2730 //Follow gleich gueltig gemacht werden.
2731 if ( GetFollow() )
2733 // --> OD 2007-11-30 #i80924#
2734 // After a successful split assure that the first row
2735 // is invalid. When graphics are present, this isn't hold.
2736 // Note: defect i80924 could also be fixed, if it is
2737 // assured, that <SwLayNotify::bLowersComplete> is only
2738 // set, if all lower are valid *and* are correct laid out.
2739 if ( !bSplitError && GetFollow()->GetLower() )
2741 GetFollow()->GetLower()->InvalidatePos();
2743 // <--
2744 SWRECTFNX( GetFollow() )
2746 static BYTE nStack = 0;
2747 if ( !StackHack::IsLocked() && nStack < 4 )
2749 ++nStack;
2750 StackHack aHack;
2751 delete pAccess;
2753 GetFollow()->MakeAll();
2755 pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2756 pAttrs = pAccess->Get();
2758 ((SwTabFrm*)GetFollow())->SetLowersFormatted(FALSE);
2759 // --> OD 2005-03-30 #i43913# - lock follow table
2760 // to avoid its formatting during the format of
2761 // its content.
2762 const bool bOldJoinLock = GetFollow()->IsJoinLocked();
2763 GetFollow()->LockJoin();
2764 // <--
2765 ::lcl_RecalcRow( static_cast<SwRowFrm&>(*GetFollow()->Lower()),
2766 (GetFollow()->GetUpper()->Frm().*fnRectX->fnGetBottom)() );
2767 // --> OD 2005-03-30 #i43913#
2768 // --> FME 2006-04-05 #i63632# Do not unlock the
2769 // follow if it wasn't locked before.
2770 if ( !bOldJoinLock )
2771 GetFollow()->UnlockJoin();
2772 // <--
2774 if ( !GetFollow()->GetFollow() )
2776 SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext();
2777 if ( pNxt )
2779 // OD 26.08.2003 #i18103# - no formatting
2780 // of found next frame, if its a follow
2781 // section of the 'ColLocked' section,
2782 // the follow table is in.
2783 bool bCalcNxt = true;
2784 if ( GetFollow()->IsInSct() && pNxt->IsSctFrm() )
2786 SwSectionFrm* pSct = GetFollow()->FindSctFrm();
2787 if ( pSct->IsColLocked() &&
2788 pSct->GetFollow() == pNxt )
2790 bCalcNxt = false;
2793 if ( bCalcNxt )
2795 pNxt->Calc();
2799 --nStack;
2801 else if ( GetFollow() == GetNext() )
2802 ((SwTabFrm*)GetFollow())->MoveFwd( TRUE, FALSE );
2803 ViewShell *pSh;
2804 if ( 0 != (pSh = GetShell()) )
2805 pSh->Imp()->ResetScroll();
2807 continue;
2812 // Set to false again as early as possible.
2813 bLastRowHasToMoveToFollow = false;
2815 if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() &&
2816 GetUpper()->GetUpper()->GetUpper()->IsSctFrm() &&
2817 ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
2818 ((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
2819 bMovedFwd = FALSE;
2821 // --> FME 2004-06-09 #i29771# Reset bTryToSplit flag on change of upper
2822 const SwFrm* pOldUpper = GetUpper();
2823 // <--
2825 //Mal sehen ob ich irgenwo Platz finde...
2826 if ( !bMovedFwd && !MoveFwd( bMakePage, FALSE ) )
2827 bMakePage = FALSE;
2829 // --> FME 2004-06-09 #i29771# Reset bSplitError flag on change of upper
2830 if ( GetUpper() != pOldUpper )
2832 bTryToSplit = true;
2833 nUnSplitted = 5;
2835 // <--
2837 SWREFRESHFN( this )
2838 bMovedFwd = bCalcLowers = TRUE;
2839 aNotify.SetLowersComplete( FALSE );
2840 if ( IsFollow() )
2841 { //Um Oszillationen zu vermeiden sollte kein ungueltiger Master
2842 //zurueckbleiben.
2843 SwTabFrm *pTab = FindMaster();
2844 if ( pTab->GetUpper() )
2845 pTab->GetUpper()->Calc();
2846 pTab->Calc();
2847 pTab->SetLowersFormatted( FALSE );
2850 //Wenn mein direkter Nachbar jetzt gleichzeitig mein Follow ist
2851 //verleibe ich mir das Teil ein.
2852 if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
2854 if ( HasFollowFlowLine() )
2855 RemoveFollowFlowLine();
2856 if ( GetFollow() )
2857 Join();
2860 if ( bMovedBwd && GetUpper() )
2861 //Beim zurueckfliessen wurde der Upper angeregt sich vollstaendig
2862 //zu Painten, dass koennen wir uns jetzt nach dem hin und her
2863 //fliessen sparen.
2864 GetUpper()->ResetCompletePaint();
2866 if ( bCalcLowers && IsValid() )
2868 // --> OD 2005-05-11 #i44910# - format of lower frames unnecessary
2869 // and can cause layout loops, if table doesn't fit and isn't
2870 // allowed to split.
2871 SwTwips nDistToUpperPrtBottom =
2872 (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
2873 if ( nDistToUpperPrtBottom >= 0 || bTryToSplit )
2875 lcl_RecalcTable( *this, 0, aNotify );
2876 bLowersFormatted = TRUE;
2877 bCalcLowers = FALSE;
2879 #if OSL_DEBUG_LEVEL > 1
2880 else
2882 ASSERT( false, "debug assertion: <SwTabFrm::MakeAll()> - format of table lowers suppressed by fix i44910" );
2884 #endif
2885 // <--
2888 } //while ( !bValidPos || !bValidSize || !bValidPrtArea )
2890 //Wenn mein direkter Vorgaenger jetzt mein Master ist, so kann er mich
2891 //bei der nachstbesten Gelegenheit vernichten.
2892 if ( IsFollow() )
2894 SwFrm *pPre = GetPrev();
2895 if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this)
2896 pPre->InvalidatePos();
2899 bCalcLowers = bONECalcLowers = FALSE;
2900 delete pAccess;
2901 UnlockJoin();
2902 if ( bMovedFwd || bMovedBwd || !bOldValidPos )
2903 aNotify.SetInvaKeep();
2906 /*************************************************************************
2908 |* SwTabFrm::CalcFlyOffsets()
2910 |* Beschreibung: Berechnet die Offsets, die durch FlyFrames
2911 |* entstehen.
2912 |* Ersterstellung MA/MIB 14. Apr. 99
2913 |* Letzte Aenderung
2915 |*************************************************************************/
2916 BOOL SwTabFrm::CalcFlyOffsets( SwTwips& rUpper,
2917 long& rLeftOffset,
2918 long& rRightOffset ) const
2920 BOOL bInvalidatePrtArea = FALSE;
2921 const SwPageFrm *pPage = FindPageFrm();
2922 const SwFlyFrm* pMyFly = FindFlyFrm();
2924 // --> #108724# Page header/footer content doesn't have to wrap around
2925 // floating screen objects
2927 const IDocumentSettingAccess* pIDSA = GetFmt()->getIDocumentSettingAccess();
2928 const bool bWrapAllowed = pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
2929 ( !IsInFtn() && 0 == FindFooterOrHeader() );
2930 // <--
2932 if ( pPage->GetSortedObjs() && bWrapAllowed )
2934 SWRECTFN( this )
2935 const bool bConsiderWrapOnObjPos = pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION);
2936 long nPrtPos = (Frm().*fnRect->fnGetTop)();
2937 nPrtPos = (*fnRect->fnYInc)( nPrtPos, rUpper );
2938 SwRect aRect( Frm() );
2939 long nYDiff = (*fnRect->fnYDiff)( (Prt().*fnRect->fnGetTop)(), rUpper );
2940 if( nYDiff > 0 )
2941 (aRect.*fnRect->fnAddBottom)( -nYDiff );
2942 for ( USHORT i = 0; i < pPage->GetSortedObjs()->Count(); ++i )
2944 SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
2945 if ( pAnchoredObj->ISA(SwFlyFrm) )
2947 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
2948 const SwRect aFlyRect = pFly->GetObjRectWithSpaces();
2949 // --> OD 2004-10-07 #i26945# - correction of conditions,
2950 // if Writer fly frame has to be considered:
2951 // - no need to check, if top of Writer fly frame differs
2952 // from WEIT_WECH, because its also check, if the Writer
2953 // fly frame rectangle overlaps with <aRect>
2954 // - no check, if bottom of anchor frame is prior the top of
2955 // the table, because Writer fly frames can be negative positioned.
2956 // - correct check, if the Writer fly frame is an lower of the
2957 // table, because table lines/rows can split and a at-character
2958 // anchored Writer fly frame could be positioned in the follow
2959 // flow line.
2960 // - add condition, that an existing anchor character text frame
2961 // has to be on the same page as the table.
2962 // E.g., it could happen, that the fly frame is still registered
2963 // at the page frame, the table is on, but it's anchor character
2964 // text frame has already changed its page.
2965 //if ( WEIT_WECH != (pFly->Frm().*fnRect->fnGetTop)() &&
2966 // pFly->IsFlyAtCntFrm() && aFlyRect.IsOver( aRect ) &&
2967 // // OD 25.02.2003 #i9040# - use '<=' instead of '<'
2968 // (*fnRect->fnYDiff)(
2969 // (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetBottom)(),
2970 // (Frm().*fnRect->fnGetTop)() ) <= 0 &&
2971 // !IsAnLower( pFly ) && !pFly->IsAnLower( this ) &&
2972 // ( !pMyFly || pMyFly->IsAnLower( pFly ) ) &&
2973 // pPage->GetPhyPageNum() >=
2974 // pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() &&
2975 // // anchor should be in same page body/header/footer
2976 // ( pFly->GetAnchorFrm()->FindFooterOrHeader() ==
2977 // FindFooterOrHeader() ) )
2978 const SwTxtFrm* pAnchorCharFrm = pFly->FindAnchorCharFrm();
2979 bool bConsiderFly =
2980 // --> OD 2005-04-06 #i46807# - do not consider invalid
2981 // Writer fly frames.
2982 pFly->IsValid() &&
2983 // <--
2984 // fly anchored at character
2985 pFly->IsFlyAtCntFrm() &&
2986 // fly overlaps with corresponding table rectangle
2987 aFlyRect.IsOver( aRect ) &&
2988 // fly isn't lower of table and
2989 // anchor character frame of fly isn't lower of table
2990 ( !IsAnLower( pFly ) &&
2991 ( !pAnchorCharFrm || !IsAnLower( pAnchorCharFrm ) ) ) &&
2992 // table isn't lower of fly
2993 !pFly->IsAnLower( this ) &&
2994 // fly is lower of fly, the table is in
2995 // --> OD 2005-05-31 #123274# - correction:
2996 // assure that fly isn't a lower of a fly, the table isn't in.
2997 // E.g., a table in the body doesn't wrap around a graphic,
2998 // which is inside a frame.
2999 ( ( !pMyFly ||
3000 pMyFly->IsAnLower( pFly ) ) &&
3001 pMyFly == pFly->GetAnchorFrmContainingAnchPos()->FindFlyFrm() ) &&
3002 // <--
3003 // anchor frame not on following page
3004 pPage->GetPhyPageNum() >=
3005 pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() &&
3006 // anchor character text frame on same page
3007 ( !pAnchorCharFrm ||
3008 pAnchorCharFrm->FindPageFrm()->GetPhyPageNum() ==
3009 pPage->GetPhyPageNum() );
3011 if ( bConsiderFly )
3013 const SwFrm* pFlyHeaderFooterFrm = pFly->GetAnchorFrm()->FindFooterOrHeader();
3014 const SwFrm* pThisHeaderFooterFrm = FindFooterOrHeader();
3016 if ( pFlyHeaderFooterFrm != pThisHeaderFooterFrm &&
3017 // --> FME 2007-07-02 #148493# If bConsiderWrapOnObjPos is set,
3018 // we want to consider the fly if it is located in the header and
3019 // the table is located in the body:
3020 ( !bConsiderWrapOnObjPos || 0 != pThisHeaderFooterFrm || !pFlyHeaderFooterFrm->IsHeaderFrm() ) )
3021 bConsiderFly = false;
3022 // <--
3025 if ( bConsiderFly )
3026 // <--
3028 const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround();
3029 const SwFmtHoriOrient &rHori= pFly->GetFmt()->GetHoriOrient();
3030 if ( SURROUND_NONE == rSur.GetSurround() )
3032 long nBottom = (aFlyRect.*fnRect->fnGetBottom)();
3033 if( (*fnRect->fnYDiff)( nPrtPos, nBottom ) < 0 )
3034 nPrtPos = nBottom;
3035 bInvalidatePrtArea = TRUE;
3037 if ( (SURROUND_RIGHT == rSur.GetSurround() ||
3038 SURROUND_PARALLEL == rSur.GetSurround())&&
3039 text::HoriOrientation::LEFT == rHori.GetHoriOrient() )
3041 const long nWidth = (*fnRect->fnXDiff)(
3042 (aFlyRect.*fnRect->fnGetRight)(),
3043 (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetLeft)() );
3044 rLeftOffset = Max( rLeftOffset, nWidth );
3045 bInvalidatePrtArea = TRUE;
3047 if ( (SURROUND_LEFT == rSur.GetSurround() ||
3048 SURROUND_PARALLEL == rSur.GetSurround())&&
3049 text::HoriOrientation::RIGHT == rHori.GetHoriOrient() )
3051 const long nWidth = (*fnRect->fnXDiff)(
3052 (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetRight)(),
3053 (aFlyRect.*fnRect->fnGetLeft)() );
3054 rRightOffset = Max( rRightOffset, nWidth );
3055 bInvalidatePrtArea = TRUE;
3060 rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() );
3063 return bInvalidatePrtArea;
3066 /*************************************************************************
3068 |* SwTabFrm::Format()
3070 |* Beschreibung: "Formatiert" den Frame; Frm und PrtArea
3071 |* Die Fixsize wird hier nicht eingestellt.
3072 |* Ersterstellung MA 09. Mar. 93
3073 |* Letzte Aenderung MA 18. Jun. 97
3075 |*************************************************************************/
3076 void SwTabFrm::Format( const SwBorderAttrs *pAttrs )
3078 ASSERT( pAttrs, "TabFrm::Format, pAttrs ist 0." );
3080 SWRECTFN( this )
3081 if ( !bValidSize )
3083 long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() -
3084 (Frm().*fnRect->fnGetWidth)();
3085 if( nDiff )
3086 (aFrm.*fnRect->fnAddRight)( nDiff );
3089 //VarSize ist immer die Hoehe.
3090 //Fuer den oberen/unteren Rand gelten die selben Regeln wie fuer
3091 //cntfrms (sie MakePrtArea() von diesen).
3093 SwTwips nUpper = CalcUpperSpace( pAttrs );
3095 //Wir wollen Rahmen ausweichen. Zwei Moeglichkeiten:
3096 //1. Es gibt Rahmen mit SurroundNone, diesen wird vollsaendig ausgewichen
3097 //2. Es gibt Rahmen mit Umlauf nur rechts bzw. nur links und diese sind
3098 // rechts bzw. links ausgerichtet, diese geben ein Minimum fuer die
3099 // Raender vor.
3100 long nTmpRight = -1000000,
3101 nLeftOffset = 0;
3102 if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
3103 bValidPrtArea = FALSE;
3104 long nRightOffset = Max( 0L, nTmpRight );
3106 SwTwips nLower = pAttrs->CalcBottomLine();
3107 // --> collapsing borders FME 2005-05-27 #i29550#
3108 if ( IsCollapsingBorders() )
3109 nLower += GetBottomLineSize();
3110 // <-- collapsing
3112 if ( !bValidPrtArea )
3113 { bValidPrtArea = TRUE;
3115 //Die Breite der PrtArea wird vom FrmFmt vorgegeben, die Raender
3116 //sind entsprechend einzustellen.
3117 //Mindestraender werden von Umrandung und Schatten vorgegeben.
3118 //Die Rander werden so eingestellt, dass die PrtArea nach dem
3119 //angegebenen Adjustment im Frm ausgerichtet wird.
3120 //Wenn das Adjustment 0 ist, so werden die Rander anhand des
3121 //Randattributes eingestellt.
3123 const SwTwips nOldHeight = (Prt().*fnRect->fnGetHeight)();
3124 const SwTwips nMax = (aFrm.*fnRect->fnGetWidth)();
3126 // OD 14.03.2003 #i9040# - adjust variable names.
3127 const SwTwips nLeftLine = pAttrs->CalcLeftLine();
3128 const SwTwips nRightLine = pAttrs->CalcRightLine();
3130 //Die Breite ist evtl. eine Prozentangabe. Wenn die Tabelle irgendwo
3131 //'drinsteckt bezieht sie sich auf die Umgebung. Ist es der Body, so
3132 //bezieht sie sich in der BrowseView auf die Bildschirmbreite.
3133 const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize();
3134 // OD 14.03.2003 #i9040# - adjust variable name.
3135 const SwTwips nWishedTableWidth = CalcRel( rSz, TRUE );
3137 BOOL bCheckBrowseWidth = FALSE;
3139 // OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
3140 SwTwips nLeftSpacing = 0;
3141 SwTwips nRightSpacing = 0;
3142 switch ( GetFmt()->GetHoriOrient().GetHoriOrient() )
3144 case text::HoriOrientation::LEFT:
3146 // left indent:
3147 nLeftSpacing = nLeftLine + nLeftOffset;
3148 // OD 06.03.2003 #i9040# - correct calculation of right indent:
3149 // - Consider right indent given by right line attributes.
3150 // - Consider negative right indent.
3151 // wished right indent determined by wished table width and
3152 // left offset given by surround fly frames on the left:
3153 const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset;
3154 if ( nRightOffset > 0 )
3156 // surrounding fly frames on the right
3157 // -> right indent is maximun of given right offset
3158 // and wished right offset.
3159 nRightSpacing = nRightLine + Max( nRightOffset, nWishRight );
3161 else
3163 // no surrounding fly frames on the right
3164 // If intrinsic right indent (intrinsic means not considering
3165 // determined left indent) is negative,
3166 // then hold this intrinsic indent,
3167 // otherwise non negative wished right indent is hold.
3168 nRightSpacing = nRightLine +
3169 ( ( (nWishRight+nLeftOffset) < 0 ) ?
3170 (nWishRight+nLeftOffset) :
3171 Max( 0L, nWishRight ) );
3174 break;
3175 case text::HoriOrientation::RIGHT:
3177 // right indent:
3178 nRightSpacing = nRightLine + nRightOffset;
3179 // OD 06.03.2003 #i9040# - correct calculation of left indent:
3180 // - Consider left indent given by left line attributes.
3181 // - Consider negative left indent.
3182 // wished left indent determined by wished table width and
3183 // right offset given by surrounding fyl frames on the right:
3184 const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset;
3185 if ( nLeftOffset > 0 )
3187 // surrounding fly frames on the left
3188 // -> right indent is maximun of given left offset
3189 // and wished left offset.
3190 nLeftSpacing = nLeftLine + Max( nLeftOffset, nWishLeft );
3192 else
3194 // no surrounding fly frames on the left
3195 // If intrinsic left indent (intrinsic = not considering
3196 // determined right indent) is negative,
3197 // then hold this intrinsic indent,
3198 // otherwise non negative wished left indent is hold.
3199 nLeftSpacing = nLeftLine +
3200 ( ( (nWishLeft+nRightOffset) < 0 ) ?
3201 (nWishLeft+nRightOffset) :
3202 Max( 0L, nWishLeft ) );
3205 break;
3206 case text::HoriOrientation::CENTER:
3208 // OD 07.03.2003 #i9040# - consider left/right line attribute.
3209 // OD 10.03.2003 #i9040# -
3210 const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2;
3211 nLeftSpacing = nLeftLine +
3212 ( (nLeftOffset > 0) ?
3213 Max( nCenterSpacing, nLeftOffset ) :
3214 nCenterSpacing );
3215 nRightSpacing = nRightLine +
3216 ( (nRightOffset > 0) ?
3217 Max( nCenterSpacing, nRightOffset ) :
3218 nCenterSpacing );
3220 break;
3221 case text::HoriOrientation::FULL:
3222 //Das Teil dehnt sich ueber die gesamte Breite aus.
3223 //Nur die fuer die Umrandung benoetigten Freiraeume
3224 //werden beruecksichtigt.
3225 //Die Attributwerte von LRSpace werden bewusst missachtet!
3226 bCheckBrowseWidth = TRUE;
3227 nLeftSpacing = nLeftLine + nLeftOffset;
3228 nRightSpacing = nRightLine + nRightOffset;
3229 break;
3230 case text::HoriOrientation::NONE:
3232 //Die Raender werden vom Randattribut bestimmt.
3233 nLeftSpacing = pAttrs->CalcLeft( this );
3234 if( nLeftOffset )
3236 // OD 07.03.2003 #i9040# - surround fly frames only, if
3237 // they overlap with the table.
3238 // Thus, take maximun of left spacing and left offset.
3239 // OD 10.03.2003 #i9040# - consider left line attribute.
3240 nLeftSpacing = Max( nLeftSpacing, ( nLeftOffset + nLeftLine ) );
3242 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
3243 nRightSpacing = pAttrs->CalcRight( this );
3244 if( nRightOffset )
3246 // OD 07.03.2003 #i9040# - surround fly frames only, if
3247 // they overlap with the table.
3248 // Thus, take maximun of right spacing and right offset.
3249 // OD 10.03.2003 #i9040# - consider right line attribute.
3250 nRightSpacing = Max( nRightSpacing, ( nRightOffset + nRightLine ) );
3252 // OD 10.03.2003 #i9040# - do not hold wished table width.
3254 if ( !pAttrs->GetLRSpace().GetRight() )
3255 nRight = Max( nRight, nMax - (nWish + nLeft + nRight));
3258 break;
3259 case text::HoriOrientation::LEFT_AND_WIDTH:
3261 //Linker Rand und die Breite zaehlen (Word-Spezialitaet)
3262 // OD 10.03.2003 #i9040# - no width alignment in online mode.
3263 //bCheckBrowseWidth = TRUE;
3264 nLeftSpacing = pAttrs->CalcLeft( this );
3265 if( nLeftOffset )
3267 // OD 10.03.2003 #i9040# - surround fly frames only, if
3268 // they overlap with the table.
3269 // Thus, take maximun of right spacing and right offset.
3270 // OD 10.03.2003 #i9040# - consider left line attribute.
3271 nLeftSpacing = Max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) );
3273 // OD 10.03.2003 #i9040# - consider right and left line attribute.
3274 const SwTwips nWishRight =
3275 nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth;
3276 nRightSpacing = nRightLine +
3277 ( (nRightOffset > 0) ?
3278 Max( nWishRight, nRightOffset ) :
3279 nWishRight );
3281 break;
3282 default:
3283 ASSERT( FALSE, "Ungueltige orientation fuer Table." );
3286 // --> OD 2004-07-15 #i26250# - extend bottom printing area, if table
3287 // is last content inside a table cell.
3288 if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) &&
3289 GetUpper()->IsInTab() && !GetIndNext() )
3291 nLower += pAttrs->GetULSpace().GetLower();
3293 // <--
3294 (this->*fnRect->fnSetYMargins)( nUpper, nLower );
3295 if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) )
3296 (this->*fnRect->fnSetXMargins)( 0, 0 );
3297 else
3298 (this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing );
3300 ViewShell *pSh;
3301 if ( bCheckBrowseWidth &&
3302 GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) &&
3303 GetUpper()->IsPageBodyFrm() && // nur PageBodyFrms, nicht etwa ColBodyFrms
3304 0 != (pSh = GetShell()) && pSh->VisArea().Width() )
3306 //Nicht ueber die Kante des sichbaren Bereiches hinausragen.
3307 //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite"
3308 //geben kann (RootFrm::ImplCalcBrowseWidth())
3309 long nWidth = pSh->GetBrowseWidth();
3310 nWidth -= Prt().Left();
3311 nWidth -= pAttrs->CalcRightLine();
3312 Prt().Width( Min( nWidth, Prt().Width() ) );
3315 if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() )
3316 bValidSize = FALSE;
3319 if ( !bValidSize )
3321 bValidSize = TRUE;
3323 //Die Groesse wird durch den Inhalt plus den Raendern bestimmt.
3324 SwTwips nRemaining = 0, nDiff;
3325 SwFrm *pFrm = pLower;
3326 while ( pFrm )
3328 nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)();
3329 pFrm = pFrm->GetNext();
3331 //Jetzt noch die Raender addieren
3332 nRemaining += nUpper + nLower;
3334 nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining;
3335 if ( nDiff > 0 )
3336 Shrink( nDiff );
3337 else if ( nDiff < 0 )
3338 Grow( -nDiff );
3341 /*************************************************************************
3343 |* SwTabFrm::GrowFrm()
3345 |* Ersterstellung MA 12. Mar. 93
3346 |* Letzte Aenderung MA 23. Sep. 96
3348 |*************************************************************************/
3349 SwTwips SwTabFrm::GrowFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
3351 SWRECTFN( this )
3352 SwTwips nHeight =(Frm().*fnRect->fnGetHeight)();
3353 if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) )
3354 nDist = LONG_MAX - nHeight;
3356 if ( bTst && !IsRestrictTableGrowth() )
3357 return nDist;
3359 if ( GetUpper() )
3361 SwRect aOldFrm( Frm() );
3363 //Der Upper wird nur soweit wie notwendig gegrowed. In nReal wird erstmal
3364 //die bereits zur Verfuegung stehende Strecke bereitgestellt.
3365 SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)();
3366 SwFrm *pFrm = GetUpper()->Lower();
3367 while ( pFrm && GetFollow() != pFrm )
3369 nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
3370 pFrm = pFrm->GetNext();
3373 long nTmp = 0;
3374 if ( nReal < nDist )
3376 nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo );
3378 if ( IsRestrictTableGrowth() )
3380 nTmp = Min( nDist, nReal + nTmp );
3381 nDist = nTmp < 0 ? 0 : nTmp;
3385 if ( !bTst )
3387 (Frm().*fnRect->fnAddBottom)( nDist );
3389 SwRootFrm *pRootFrm = FindRootFrm();
3390 if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
3391 pRootFrm->GetCurrShell() )
3393 pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm );
3398 if ( !bTst && ( nDist || IsRestrictTableGrowth() ) )
3400 SwPageFrm *pPage = FindPageFrm();
3401 if ( GetNext() )
3403 GetNext()->_InvalidatePos();
3404 if ( GetNext()->IsCntntFrm() )
3405 GetNext()->InvalidatePage( pPage );
3407 // --> OD 2004-07-05 #i28701# - Due to the new object positioning the
3408 // frame on the next page/column can flow backward (e.g. it was moved
3409 // forward due to the positioning of its objects ). Thus, invalivate this
3410 // next frame, if document compatibility option 'Consider wrapping style
3411 // influence on object positioning' is ON.
3412 else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) )
3414 InvalidateNextPos();
3416 // <--
3417 _InvalidateAll();
3418 InvalidatePage( pPage );
3419 SetComplete();
3421 const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos();
3422 if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
3423 SetCompletePaint();
3426 return nDist;
3428 /*************************************************************************
3430 |* SwTabFrm::Modify()
3432 |* Ersterstellung MA 14. Mar. 93
3433 |* Letzte Aenderung MA 06. Dec. 96
3435 |*************************************************************************/
3436 void SwTabFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
3438 BYTE nInvFlags = 0;
3439 BOOL bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
3441 if( bAttrSetChg )
3443 SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() );
3444 SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() );
3445 SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld );
3446 SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew );
3447 while( TRUE )
3449 _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(),
3450 (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags,
3451 &aOldSet, &aNewSet );
3452 if( aNIter.IsAtEnd() )
3453 break;
3454 aNIter.NextItem();
3455 aOIter.NextItem();
3457 if ( aOldSet.Count() || aNewSet.Count() )
3458 SwLayoutFrm::Modify( &aOldSet, &aNewSet );
3460 else
3461 _UpdateAttr( pOld, pNew, nInvFlags );
3463 if ( nInvFlags != 0 )
3465 SwPageFrm *pPage = FindPageFrm();
3466 InvalidatePage( pPage );
3467 // if ( nInvFlags & 0x01 )
3468 // SetCompletePaint();
3469 if ( nInvFlags & 0x02 )
3470 _InvalidatePrt();
3471 if ( nInvFlags & 0x40 )
3472 _InvalidatePos();
3473 SwFrm *pTmp;
3474 if ( 0 != (pTmp = GetIndNext()) )
3476 if ( nInvFlags & 0x04 )
3478 pTmp->_InvalidatePrt();
3479 if ( pTmp->IsCntntFrm() )
3480 pTmp->InvalidatePage( pPage );
3482 if ( nInvFlags & 0x10 )
3483 pTmp->SetCompletePaint();
3485 if ( nInvFlags & 0x08 && 0 != (pTmp = GetPrev()) )
3487 pTmp->_InvalidatePrt();
3488 if ( pTmp->IsCntntFrm() )
3489 pTmp->InvalidatePage( pPage );
3491 if ( nInvFlags & 0x20 )
3493 if ( pPage && pPage->GetUpper() && !IsFollow() )
3494 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3496 if ( nInvFlags & 0x80 )
3497 InvalidateNextPos();
3501 void SwTabFrm::_UpdateAttr( SfxPoolItem *pOld, SfxPoolItem *pNew,
3502 BYTE &rInvFlags,
3503 SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
3505 BOOL bClear = TRUE;
3506 const USHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
3507 switch( nWhich )
3509 case RES_TBLHEADLINECHG:
3510 if ( IsFollow() )
3512 // Delete remaining headlines:
3513 SwRowFrm* pLowerRow = 0;
3514 while ( 0 != ( pLowerRow = (SwRowFrm*)Lower() ) && pLowerRow->IsRepeatedHeadline() )
3516 pLowerRow->Cut();
3517 delete pLowerRow;
3520 // insert new headlines
3521 const USHORT nNewRepeat = GetTable()->GetRowsToRepeat();
3522 for ( USHORT nIdx = 0; nIdx < nNewRepeat; ++nIdx )
3524 bDontCreateObjects = TRUE; //frmtool
3525 SwRowFrm* pHeadline = new SwRowFrm( *GetTable()->GetTabLines()[ nIdx ] );
3526 pHeadline->SetRepeatedHeadline( true );
3527 bDontCreateObjects = FALSE;
3528 pHeadline->Paste( this, pLowerRow );
3531 rInvFlags |= 0x02;
3532 break;
3534 case RES_FRM_SIZE:
3535 case RES_HORI_ORIENT:
3536 rInvFlags |= 0x22;
3537 break;
3539 case RES_PAGEDESC: //Attributaenderung (an/aus)
3540 if ( IsInDocBody() )
3542 rInvFlags |= 0x40;
3543 SwPageFrm *pPage = FindPageFrm();
3544 if ( !GetPrev() )
3545 CheckPageDescs( pPage );
3546 if ( pPage && GetFmt()->GetPageDesc().GetNumOffset() )
3547 ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( TRUE );
3548 SwDocPosUpdate aMsgHnt( pPage->Frm().Top() );
3549 GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt );
3551 break;
3553 case RES_BREAK:
3554 rInvFlags |= 0xC0;
3555 break;
3557 case RES_LAYOUT_SPLIT:
3558 if ( !IsFollow() )
3559 rInvFlags |= 0x40;
3560 break;
3561 case RES_FRAMEDIR :
3562 SetDerivedR2L( sal_False );
3563 CheckDirChange();
3564 break;
3565 case RES_COLLAPSING_BORDERS :
3566 rInvFlags |= 0x02;
3567 lcl_InvalidateAllLowersPrt( this );
3568 break;
3569 case RES_UL_SPACE:
3570 rInvFlags |= 0x1C;
3571 /* kein Break hier */
3573 default:
3574 bClear = FALSE;
3576 if ( bClear )
3578 if ( pOldSet || pNewSet )
3580 if ( pOldSet )
3581 pOldSet->ClearItem( nWhich );
3582 if ( pNewSet )
3583 pNewSet->ClearItem( nWhich );
3585 else
3586 SwLayoutFrm::Modify( pOld, pNew );
3590 /*************************************************************************
3592 |* SwTabFrm::GetInfo()
3594 |* Ersterstellung MA 06. Dec. 96
3595 |* Letzte Aenderung MA 26. Jun. 98
3597 |*************************************************************************/
3598 BOOL SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const
3600 if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && !IsFollow() )
3602 SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt;
3603 const SwPageFrm *pPage = FindPageFrm();
3604 if ( pPage )
3606 if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
3608 //Das sollte er sein (kann allenfalls temporaer anders sein,
3609 // sollte uns das beunruhigen?)
3610 rInfo.SetInfo( pPage, this );
3611 return FALSE;
3613 if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
3614 (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
3616 //Das koennte er sein.
3617 rInfo.SetInfo( pPage, this );
3621 return TRUE;
3624 /*************************************************************************
3626 |* SwTabFrm::FindLastCntnt()
3628 |* Ersterstellung MA 13. Apr. 93
3629 |* Letzte Aenderung MA 15. May. 98
3631 |*************************************************************************/
3632 SwCntntFrm *SwTabFrm::FindLastCntnt()
3634 SwFrm *pRet = pLower;
3636 while ( pRet && !pRet->IsCntntFrm() )
3638 SwFrm *pOld = pRet;
3640 SwFrm *pTmp = pRet; // To skip empty section frames
3641 while ( pRet->GetNext() )
3643 pRet = pRet->GetNext();
3644 if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() )
3645 pTmp = pRet;
3647 pRet = pTmp;
3649 if ( pRet->GetLower() )
3650 pRet = pRet->GetLower();
3651 if ( pRet == pOld )
3653 // Wenn am Ende der letzten Zelle ein spaltiger Bereich steht,
3654 // der eine leere letzte Spalte hat, muessen wir noch die anderen
3655 // Spalten abklappern, dies erledigt SwSectionFrm::FindLastCntnt
3656 if( pRet->IsColBodyFrm() )
3658 #ifndef PRODUCT
3659 SwSectionFrm* pSect = pRet->FindSctFrm();
3660 ASSERT( pSect, "Wo kommt denn die Spalte her?")
3661 ASSERT( IsAnLower( pSect ), "Gespaltene Zelle?" );
3662 #endif
3663 return pRet->FindSctFrm()->FindLastCntnt();
3667 // pRet may be a cell frame without a lower (cell has been split).
3668 // We have to find the last content the hard way:
3670 ASSERT( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" )
3671 const SwFrm* pRow = pRet->GetUpper();
3672 while ( pRow && !pRow->GetUpper()->IsTabFrm() )
3673 pRow = pRow->GetUpper();
3674 SwCntntFrm* pCntntFrm = ((SwLayoutFrm*)pRow)->ContainsCntnt();
3675 pRet = 0;
3677 while ( pCntntFrm && ((SwLayoutFrm*)pRow)->IsAnLower( pCntntFrm ) )
3679 pRet = pCntntFrm;
3680 pCntntFrm = pCntntFrm->GetNextCntntFrm();
3685 // #112929# There actually is a situation, which results in pRet = 0:
3686 // Insert frame, insert table via text <-> table. This gives you a frame
3687 // containing a table without any other content frames. Split the table
3688 // and undo the splitting. This operation gives us a table frame without
3689 // a lower.
3690 if ( pRet )
3692 while ( pRet->GetNext() )
3693 pRet = pRet->GetNext();
3695 if( pRet->IsSctFrm() )
3696 pRet = ((SwSectionFrm*)pRet)->FindLastCntnt();
3699 return (SwCntntFrm*)pRet;
3702 /*************************************************************************
3704 |* SwTabFrm::GetLeaf()
3706 |* Ersterstellung MA 19. Mar. 93
3707 |* Letzte Aenderung MA 25. Apr. 95
3709 |*************************************************************************/
3710 SwLayoutFrm *SwTabFrm::GetLeaf( MakePageType eMakePage, BOOL bFwd )
3712 SwLayoutFrm *pRet;
3713 if ( bFwd )
3715 pRet = GetNextLeaf( eMakePage );
3716 while ( IsAnLower( pRet ) )
3717 pRet = pRet->GetNextLeaf( eMakePage );
3719 else
3720 pRet = GetPrevLeaf();
3721 if ( pRet )
3722 pRet->Calc();
3723 return pRet;
3726 /*************************************************************************
3728 |* SwTabFrm::ShouldBwdMoved()
3730 |* Beschreibung Returnwert sagt ob der Frm verschoben werden sollte
3731 |* Ersterstellung MA 10. Jul. 95
3732 |* Letzte Aenderung MA 04. Mar. 97
3734 |*************************************************************************/
3735 BOOL SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, BOOL, BOOL &rReformat )
3737 rReformat = FALSE;
3738 if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()) )
3740 //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv.
3741 //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen
3742 //moechte die FixSize die gleiche ist, die der Frm selbst hat.
3743 //In diesem Fall kann einfach geprueft werden, ob der Frm genug
3744 //Platz fuer seine VarSize findet, ist dies nicht der Fall kann
3745 //gleich auf das Verschieben verzichtet werden.
3746 //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst
3747 //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise
3748 //aufspalten kann.
3749 //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind
3750 //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn
3751 //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt
3752 //etwas Platz zur Verfuegung steht).
3754 //Die FixSize der Umgebungen in denen Tabellen herumlungern ist immer
3755 //Die Breite.
3757 SwPageFrm *pOldPage = FindPageFrm(),
3758 *pNewPage = pNewUpper->FindPageFrm();
3759 BOOL bMoveAnyway = FALSE;
3760 SwTwips nSpace = 0;
3762 SWRECTFN( this )
3763 if ( !SwFlowFrm::IsMoveBwdJump() )
3766 long nOldWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
3767 SWRECTFNX( pNewUpper );
3768 long nNewWidth = (pNewUpper->Prt().*fnRectX->fnGetWidth)();
3769 if( Abs( nNewWidth - nOldWidth ) < 2 )
3771 if( FALSE ==
3772 ( bMoveAnyway = BwdMoveNecessary( pOldPage, Frm() ) > 1 ) )
3774 SwRect aRect( pNewUpper->Prt() );
3775 aRect.Pos() += pNewUpper->Frm().Pos();
3776 const SwFrm *pPrevFrm = pNewUpper->Lower();
3777 while ( pPrevFrm && pPrevFrm != this )
3779 (aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX->
3780 fnGetBottom)() );
3781 pPrevFrm = pPrevFrm->GetNext();
3783 bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1;
3785 // --> FME 2006-01-20 #i54861# Due to changes made in PrepareMake,
3786 // the tabfrm may not have a correct position. Therefore
3787 // it is possible that pNewUpper->Prt().Height == 0. In this
3788 // case the above calculation of nSpace might give wrong
3789 // results and we really do not want to MoveBackwrd into a
3790 // 0 height frame. If nTmpSpace is already <= 0, we take this
3791 // value:
3792 const SwTwips nTmpSpace = (aRect.*fnRectX->fnGetHeight)();
3793 if ( (pNewUpper->Prt().*fnRectX->fnGetHeight)() > 0 || nTmpSpace <= 0 )
3794 nSpace = nTmpSpace;
3795 // <--
3797 if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) )
3798 nSpace += pNewUpper->Grow( LONG_MAX, TRUE );
3801 else if( !bLockBackMove )
3802 bMoveAnyway = TRUE;
3804 else if( !bLockBackMove )
3805 bMoveAnyway = TRUE;
3807 if ( bMoveAnyway )
3808 return rReformat = TRUE;
3809 else if ( !bLockBackMove && nSpace > 0 )
3811 // --> OD 2004-10-05 #i26945# - check, if follow flow line
3812 // contains frame, which are moved forward due to its object
3813 // positioning.
3814 SwRowFrm* pFirstRow = GetFirstNonHeadlineRow();
3815 if ( pFirstRow && pFirstRow->IsInFollowFlowRow() &&
3816 SwLayouter::DoesRowContainMovedFwdFrm(
3817 *(pFirstRow->GetFmt()->GetDoc()),
3818 *(pFirstRow) ) )
3820 return FALSE;
3822 // <--
3823 SwTwips nTmpHeight = CalcHeightOfFirstContentLine();
3825 // --> FME 2005-01-17 #118840#
3826 // For some mysterious reason, I changed the good old
3827 // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
3828 // This obviously results in problems with table frames in
3829 // sections. Remember: Every twip is sacred.
3830 return nTmpHeight <= nSpace;
3831 // <--
3834 return FALSE;
3837 /*************************************************************************
3839 |* SwTabFrm::Cut()
3841 |* Ersterstellung MA 23. Feb. 94
3842 |* Letzte Aenderung MA 09. Sep. 98
3844 |*************************************************************************/
3845 void SwTabFrm::Cut()
3847 ASSERT( GetUpper(), "Cut ohne Upper()." );
3849 SwPageFrm *pPage = FindPageFrm();
3850 InvalidatePage( pPage );
3851 SwFrm *pFrm = GetNext();
3852 if( pFrm )
3853 { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger
3854 //berechnet der ist jetzt wo er der erste wird obsolete
3855 pFrm->_InvalidatePrt();
3856 pFrm->_InvalidatePos();
3857 if ( pFrm->IsCntntFrm() )
3858 pFrm->InvalidatePage( pPage );
3859 if( IsInSct() && !GetPrev() )
3861 SwSectionFrm* pSct = FindSctFrm();
3862 if( !pSct->IsFollow() )
3864 pSct->_InvalidatePrt();
3865 pSct->InvalidatePage( pPage );
3869 else
3871 InvalidateNextPos();
3872 //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper
3873 if ( 0 != (pFrm = GetPrev()) )
3874 { pFrm->SetRetouche();
3875 pFrm->Prepare( PREP_WIDOWS_ORPHANS );
3876 pFrm->_InvalidatePos();
3877 if ( pFrm->IsCntntFrm() )
3878 pFrm->InvalidatePage( pPage );
3880 //Wenn ich der einzige FlowFrm in meinem Upper bin (war), so muss
3881 //er die Retouche uebernehmen.
3882 //Ausserdem kann eine Leerseite entstanden sein.
3883 else
3884 { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper();
3885 pRoot->SetSuperfluous();
3886 GetUpper()->SetCompletePaint();
3887 if( IsInSct() )
3889 SwSectionFrm* pSct = FindSctFrm();
3890 if( !pSct->IsFollow() )
3892 pSct->_InvalidatePrt();
3893 pSct->InvalidatePage( pPage );
3899 //Erst removen, dann Upper Shrinken.
3900 SwLayoutFrm *pUp = GetUpper();
3901 SWRECTFN( this )
3902 Remove();
3903 if ( pUp )
3905 ASSERT( !pUp->IsFtnFrm(), "Tabelle in Fussnote." );
3906 SwSectionFrm *pSct = 0;
3907 // --> OD 2006-01-04 #126020# - adjust check for empty section
3908 // --> OD 2006-02-01 #130797# - correct fix #126020#
3909 if ( !pUp->Lower() && pUp->IsInSct() &&
3910 !(pSct = pUp->FindSctFrm())->ContainsCntnt() &&
3911 !pSct->ContainsAny( true ) )
3912 // <--
3914 if ( pUp->GetUpper() )
3916 pSct->DelEmpty( FALSE );
3917 pSct->_InvalidateSize();
3920 else if( (Frm().*fnRect->fnGetHeight)() )
3922 // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
3923 // undo changes of fix for #104992#
3924 pUp->Shrink( Frm().Height() );
3928 if ( pPage && !IsFollow() && pPage->GetUpper() )
3929 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3932 /*************************************************************************
3934 |* SwTabFrm::Paste()
3936 |* Ersterstellung MA 23. Feb. 94
3937 |* Letzte Aenderung MA 09. Sep. 98
3939 |*************************************************************************/
3940 void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling )
3942 ASSERT( pParent, "Kein Parent fuer Paste." );
3943 ASSERT( pParent->IsLayoutFrm(), "Parent ist CntntFrm." );
3944 ASSERT( pParent != this, "Bin selbst der Parent." );
3945 ASSERT( pSibling != this, "Bin mein eigener Nachbar." );
3946 ASSERT( !GetPrev() && !GetNext() && !GetUpper(),
3947 "Bin noch irgendwo angemeldet." );
3949 //In den Baum einhaengen.
3950 InsertBefore( (SwLayoutFrm*)pParent, pSibling );
3952 _InvalidateAll();
3953 SwPageFrm *pPage = FindPageFrm();
3954 InvalidatePage( pPage );
3956 if ( GetNext() )
3958 GetNext()->_InvalidatePos();
3959 GetNext()->_InvalidatePrt();
3960 if ( GetNext()->IsCntntFrm() )
3961 GetNext()->InvalidatePage( pPage );
3964 SWRECTFN( this )
3965 if( (Frm().*fnRect->fnGetHeight)() )
3966 pParent->Grow( (Frm().*fnRect->fnGetHeight)() );
3968 if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() )
3969 Prepare( PREP_FIXSIZE_CHG );
3970 if ( GetPrev() )
3972 if ( !IsFollow() )
3974 GetPrev()->InvalidateSize();
3975 if ( GetPrev()->IsCntntFrm() )
3976 GetPrev()->InvalidatePage( pPage );
3979 else if ( GetNext() )
3980 //Bei CntntFrm's gilt es den Abstand zum Vorgaenger/Nachfolger
3981 //zu beachten. Faelle (beide treten immer gleichzeitig auf):
3982 //a) Der Cntnt wird der erste einer Kette
3983 //b) Der neue Nachfolger war vorher der erste einer Kette
3984 GetNext()->_InvalidatePrt();
3986 if ( pPage && !IsFollow() )
3988 if ( pPage->GetUpper() )
3989 ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
3991 if ( !GetPrev() )//Mindestens fuer HTML mit Tabelle am Anfang notwendig.
3993 const SwPageDesc *pDesc = GetFmt()->GetPageDesc().GetPageDesc();
3994 if ( (pDesc && pDesc != pPage->GetPageDesc()) ||
3995 (!pDesc && pPage->GetPageDesc() !=
3996 &(const_cast<const SwDoc *>(GetFmt()->GetDoc())
3997 ->GetPageDesc(0))) )
3998 CheckPageDescs( pPage, TRUE );
4003 /*************************************************************************
4005 |* SwTabFrm::Prepare()
4007 |* Created AMA 01/10/02
4008 |* Last Change AMA 01/10/02
4010 |*************************************************************************/
4011 void SwTabFrm::Prepare( const PrepareHint eHint, const void *, BOOL )
4013 if( PREP_BOSS_CHGD == eHint )
4014 CheckDirChange();
4017 /*************************************************************************
4019 |* SwRowFrm::SwRowFrm(), ~SwRowFrm()
4021 |* Ersterstellung MA 09. Mar. 93
4022 |* Letzte Aenderung MA 30. May. 96
4024 |*************************************************************************/
4025 SwRowFrm::SwRowFrm( const SwTableLine &rLine, bool bInsertContent ):
4026 SwLayoutFrm( rLine.GetFrmFmt() ),
4027 pTabLine( &rLine ),
4028 pFollowRow( 0 ),
4029 // --> collapsing borders FME 2005-05-27 #i29550#
4030 mnTopMarginForLowers( 0 ),
4031 mnBottomMarginForLowers( 0 ),
4032 mnBottomLineSize( 0 ),
4033 // <-- collapsing
4034 // --> split table rows
4035 bIsFollowFlowRow( false ),
4036 // <-- split table rows
4037 bIsRepeatedHeadline( false ),
4038 mbIsRowSpanLine( false )
4040 nType = FRMC_ROW;
4042 //Gleich die Boxen erzeugen und einfuegen.
4043 const SwTableBoxes &rBoxes = rLine.GetTabBoxes();
4044 SwFrm *pTmpPrev = 0;
4045 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
4047 SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], bInsertContent );
4048 pNew->InsertBehind( this, pTmpPrev );
4049 pTmpPrev = pNew;
4053 SwRowFrm::~SwRowFrm()
4055 SwModify* pMod = GetFmt();
4056 if( pMod )
4058 pMod->Remove( this ); // austragen,
4059 if( !pMod->GetDepends() )
4060 delete pMod; // und loeschen
4064 /*************************************************************************
4066 |* SwRowFrm::RegistFlys()
4068 |* Ersterstellung MA 08. Jul. 93
4069 |* Letzte Aenderung MA 08. Jul. 93
4071 |*************************************************************************/
4072 void SwRowFrm::RegistFlys( SwPageFrm *pPage )
4074 ::RegistFlys( pPage ? pPage : FindPageFrm(), this );
4077 /*************************************************************************
4079 |* SwRowFrm::Modify()
4081 |* Ersterstellung MA 12. Nov. 97
4082 |* Letzte Aenderung MA 12. Nov. 97
4084 |*************************************************************************/
4085 void SwRowFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
4087 BOOL bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
4088 const SfxPoolItem *pItem = 0;
4090 if( bAttrSetChg )
4092 const SwAttrSet* pChgSet = ((SwAttrSetChg*)pNew)->GetChgSet();
4093 pChgSet->GetItemState( RES_FRM_SIZE, FALSE, &pItem);
4094 if ( !pItem )
4095 pChgSet->GetItemState( RES_ROW_SPLIT, FALSE, &pItem);
4097 else if ( RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which() )
4098 pItem = pNew;
4100 if ( pItem )
4102 SwTabFrm *pTab = FindTabFrm();
4103 if ( pTab )
4105 const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
4106 this == pTab->GetFirstNonHeadlineRow();
4107 // --> FME 2004-10-27 #i35063#
4108 // Invalidation required is pRow is last row
4109 if ( bInFirstNonHeadlineRow || !GetNext() )
4110 // <--
4112 if ( bInFirstNonHeadlineRow )
4113 pTab = pTab->FindMaster();
4114 pTab->InvalidatePos();
4119 SwLayoutFrm::Modify( pOld, pNew );
4124 /*************************************************************************
4126 |* SwRowFrm::MakeAll()
4128 |* Ersterstellung MA 01. Mar. 94
4129 |* Letzte Aenderung MA 01. Mar. 94
4131 |*************************************************************************/
4132 void SwRowFrm::MakeAll()
4134 if ( !GetNext() )
4135 bValidSize = FALSE;
4136 SwLayoutFrm::MakeAll();
4139 /*************************************************************************
4141 |* SwRowFrm::Format()
4143 |* Ersterstellung MA 13. Mar. 93
4144 |* Letzte Aenderung MA 20. Jun. 96
4146 |*************************************************************************/
4147 long MA_FASTCALL CalcHeightWidthFlys( const SwFrm *pFrm )
4149 SWRECTFN( pFrm )
4150 long nHeight = 0;
4151 const SwFrm* pTmp = pFrm->IsSctFrm() ?
4152 ((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm;
4153 while( pTmp )
4155 // --> OD 2004-10-08 #i26945# - consider follow text frames
4156 const SwSortedObjs* pObjs( 0L );
4157 bool bIsFollow( false );
4158 if ( pTmp->IsTxtFrm() && static_cast<const SwTxtFrm*>(pTmp)->IsFollow() )
4160 const SwFrm* pMaster;
4161 // --> FME 2005-04-01 #i46450# Master does not necessarily have
4162 // to exist if this function is called from JoinFrm() ->
4163 // Cut() -> Shrink()
4164 const SwTxtFrm* pTmpFrm = static_cast<const SwTxtFrm*>(pTmp);
4165 if ( pTmpFrm->GetPrev() && pTmpFrm->GetPrev()->IsTxtFrm() &&
4166 static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() &&
4167 static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() != pTmp )
4168 pMaster = 0;
4169 else
4170 pMaster = pTmpFrm->FindMaster();
4172 if ( pMaster )
4174 pObjs = static_cast<const SwTxtFrm*>(pTmp)->FindMaster()->GetDrawObjs();
4175 bIsFollow = true;
4178 else
4180 pObjs = pTmp->GetDrawObjs();
4182 if ( pObjs )
4183 // <--
4185 for ( USHORT i = 0; i < pObjs->Count(); ++i )
4187 const SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
4188 // --> OD 2004-10-08 #i26945# - if <pTmp> is follow, the
4189 // anchor character frame has to be <pTmp>.
4190 if ( bIsFollow &&
4191 const_cast<SwAnchoredObject*>(pAnchoredObj)->FindAnchorCharFrm() != pTmp )
4193 continue;
4195 // <--
4196 // --> OD 2004-10-04 #i26945# - consider also drawing objects
4198 // OD 30.09.2003 #i18732# - only objects, which follow
4199 // the text flow have to be considered.
4200 const SwFrmFmt& rFrmFmt = pAnchoredObj->GetFrmFmt();
4201 const bool bConsiderObj =
4202 rFrmFmt.GetAnchor().GetAnchorId() != FLY_IN_CNTNT &&
4203 pAnchoredObj->GetObjRect().Top() != WEIT_WECH &&
4204 rFrmFmt.GetFollowTextFlow().GetValue() &&
4205 pAnchoredObj->GetPageFrm() == pTmp->FindPageFrm();
4206 if ( bConsiderObj )
4208 const SwFmtFrmSize &rSz = rFrmFmt.GetFrmSize();
4209 if( !rSz.GetHeightPercent() )
4211 const SwTwips nDistOfFlyBottomToAnchorTop =
4212 (pAnchoredObj->GetObjRect().*fnRect->fnGetHeight)() +
4213 ( bVert ?
4214 pAnchoredObj->GetCurrRelPos().X() :
4215 pAnchoredObj->GetCurrRelPos().Y() );
4217 const SwTwips nFrmDiff =
4218 (*fnRect->fnYDiff)(
4219 (pTmp->Frm().*fnRect->fnGetTop)(),
4220 (pFrm->Frm().*fnRect->fnGetTop)() );
4222 nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop + nFrmDiff -
4223 (pFrm->Frm().*fnRect->fnGetHeight)() );
4225 // --> FME 2006-01-24 #i56115# The first height calculation
4226 // gives wrong results if pFrm->Prt().Y() > 0. We do
4227 // a second calculation based on the actual rectangles of
4228 // pFrm and pAnchoredObj, and use the maximum of the results.
4229 // I do not want to remove the first calculation because
4230 // if clipping has been applied, using the GetCurrRelPos
4231 // might be the better option to calculate nHeight.
4232 const SwTwips nDistOfFlyBottomToAnchorTop2 = (*fnRect->fnYDiff)(
4233 (pAnchoredObj->GetObjRect().*fnRect->fnGetBottom)(),
4234 (pFrm->Frm().*fnRect->fnGetBottom)() );
4236 nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop2 );
4237 // <--
4241 // <--
4244 if( !pFrm->IsSctFrm() )
4245 break;
4246 pTmp = pTmp->FindNextCnt();
4247 if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) )
4248 break;
4250 return nHeight;
4253 SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm& rCell, const SwBorderAttrs& rAttrs )
4255 const SwTabFrm* pTab = rCell.FindTabFrm();
4256 SwTwips nTopSpace = 0;
4257 SwTwips nBottomSpace = 0;
4259 // --> collapsing borders FME 2005-05-27 #i29550#
4260 if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrm() )
4262 nTopSpace = ((SwRowFrm*)rCell.GetUpper())->GetTopMarginForLowers();
4263 nBottomSpace = ((SwRowFrm*)rCell.GetUpper())->GetBottomMarginForLowers();
4265 // <-- collapsing
4266 else
4268 if ( pTab->IsVertical() != rCell.IsVertical() )
4270 nTopSpace = rAttrs.CalcLeft( &rCell );
4271 nBottomSpace = rAttrs.CalcRight( &rCell );
4273 else
4275 nTopSpace = rAttrs.CalcTop();
4276 nBottomSpace = rAttrs.CalcBottom();
4280 return nTopSpace + nBottomSpace;
4284 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to
4285 // control, if floating screen objects have to be considered for the minimal
4286 // cell height.
4287 SwTwips MA_FASTCALL lcl_CalcMinCellHeight( const SwLayoutFrm *_pCell,
4288 const BOOL _bConsiderObjs,
4289 const SwBorderAttrs *pAttrs = 0 )
4291 SWRECTFN( _pCell )
4292 SwTwips nHeight = 0;
4293 const SwFrm* pLow = _pCell->Lower();
4294 if ( pLow )
4296 long nFlyAdd = 0;
4297 while ( pLow )
4299 // OD 2004-02-18 #106629# - change condition and switch then-body
4300 // and else-body
4301 if ( pLow->IsRowFrm() )
4303 // --> OD 2004-10-04 #i26945#
4304 nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrm*>(pLow),
4305 _bConsiderObjs );
4306 // <--
4308 else
4310 long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)();
4311 nHeight += nLowHeight;
4312 // --> OD 2004-10-04 #i26945#
4313 if ( _bConsiderObjs )
4315 nFlyAdd = Max( 0L, nFlyAdd - nLowHeight );
4316 nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) );
4318 // <--
4321 pLow = pLow->GetNext();
4323 if ( nFlyAdd )
4324 nHeight += nFlyAdd;
4326 //Der Border will natuerlich auch mitspielen, er kann leider nicht
4327 //aus PrtArea und Frm errechnet werden, da diese in beliebiger
4328 //Kombination ungueltig sein koennen.
4329 if ( _pCell->Lower() )
4331 if ( pAttrs )
4332 nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs );
4333 else
4335 SwBorderAttrAccess aAccess( SwFrm::GetCache(), _pCell );
4336 const SwBorderAttrs &rAttrs = *aAccess.Get();
4337 nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs );
4340 return nHeight;
4343 // OD 2004-02-18 #106629# - correct type of 1st parameter
4344 // --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to control,
4345 // if floating screen objects have to be considered for the minimal cell height
4346 SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm* _pRow,
4347 const BOOL _bConsiderObjs )
4349 SWRECTFN( _pRow )
4351 const SwFmtFrmSize &rSz = _pRow->GetFmt()->GetFrmSize();
4353 if ( _pRow->HasFixSize() && !_pRow->IsRowSpanLine() )
4355 ASSERT( ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size" )
4356 return rSz.GetHeight();
4359 SwTwips nHeight = 0;
4360 const SwCellFrm* pLow = static_cast<const SwCellFrm*>(_pRow->Lower());
4361 while ( pLow )
4363 SwTwips nTmp = 0;
4364 const long nRowSpan = pLow->GetLayoutRowSpan();
4365 // --> NEW TABLES
4366 // Consider height of
4367 // 1. current cell if RowSpan == 1
4368 // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1
4369 // 3. master cell if RowSpan == -1
4370 if ( 1 == nRowSpan )
4372 nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs );
4374 else if ( -1 == nRowSpan )
4376 // Height of the last cell of a row span is height of master cell
4377 // minus the height of the other rows which are covered by the master
4378 // cell:
4379 const SwCellFrm& rMaster = pLow->FindStartEndOfRowSpanCell( true, true );
4380 nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs );
4381 const SwFrm* pMasterRow = rMaster.GetUpper();
4382 while ( pMasterRow && pMasterRow != _pRow )
4384 nTmp -= (pMasterRow->Frm().*fnRect->fnGetHeight)();
4385 pMasterRow = pMasterRow->GetNext();
4388 // <-- NEW TABLES
4390 // Do not consider rotated cells:
4391 if ( ( 0 != pLow->IsVertical() ) == ( 0 != bVert ) && nTmp > nHeight )
4392 nHeight = nTmp;
4394 pLow = static_cast<const SwCellFrm*>(pLow->GetNext());
4396 if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE && !_pRow->IsRowSpanLine() )
4397 nHeight = Max( nHeight, rSz.GetHeight() );
4398 return nHeight;
4401 // --> collapsing borders FME 2005-05-27 #i29550#
4403 // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers:
4404 USHORT lcl_GetTopSpace( const SwRowFrm& rRow )
4406 USHORT nTopSpace = 0;
4407 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
4408 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
4410 USHORT nTmpTopSpace = 0;
4411 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
4412 nTmpTopSpace = lcl_GetTopSpace( *(SwRowFrm*)pCurrLower->Lower() );
4413 else
4415 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
4416 const SvxBoxItem& rBoxItem = rSet.GetBox();
4417 nTmpTopSpace = rBoxItem.CalcLineSpace( BOX_LINE_TOP, sal_True );
4419 nTopSpace = Max( nTopSpace, nTmpTopSpace );
4421 return nTopSpace;
4424 // Calculate the maximum of TopLineDist over all lowers:
4425 USHORT lcl_GetTopLineDist( const SwRowFrm& rRow )
4427 USHORT nTopLineDist = 0;
4428 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
4429 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
4431 USHORT nTmpTopLineDist = 0;
4432 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
4433 nTmpTopLineDist = lcl_GetTopLineDist( *(SwRowFrm*)pCurrLower->Lower() );
4434 else
4436 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
4437 const SvxBoxItem& rBoxItem = rSet.GetBox();
4438 nTmpTopLineDist = rBoxItem.GetDistance( BOX_LINE_TOP );
4440 nTopLineDist = Max( nTopLineDist, nTmpTopLineDist );
4442 return nTopLineDist;
4445 // Calculate the maximum of BottomLineSize over all lowers:
4446 USHORT lcl_GetBottomLineSize( const SwRowFrm& rRow )
4448 USHORT nBottomLineSize = 0;
4449 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
4450 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
4452 USHORT nTmpBottomLineSize = 0;
4453 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
4455 const SwFrm* pRow = pCurrLower->GetLastLower();
4456 nTmpBottomLineSize = lcl_GetBottomLineSize( *(SwRowFrm*)pRow );
4458 else
4460 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
4461 const SvxBoxItem& rBoxItem = rSet.GetBox();
4462 nTmpBottomLineSize = rBoxItem.CalcLineSpace( BOX_LINE_BOTTOM, sal_True ) -
4463 rBoxItem.GetDistance( BOX_LINE_BOTTOM );
4465 nBottomLineSize = Max( nBottomLineSize, nTmpBottomLineSize );
4467 return nBottomLineSize;
4470 // Calculate the maximum of BottomLineDist over all lowers:
4471 USHORT lcl_GetBottomLineDist( const SwRowFrm& rRow )
4473 USHORT nBottomLineDist = 0;
4474 for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower;
4475 pCurrLower = (SwCellFrm*)pCurrLower->GetNext() )
4477 USHORT nTmpBottomLineDist = 0;
4478 if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() )
4480 const SwFrm* pRow = pCurrLower->GetLastLower();
4481 nTmpBottomLineDist = lcl_GetBottomLineDist( *(SwRowFrm*)pRow );
4483 else
4485 const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet();
4486 const SvxBoxItem& rBoxItem = rSet.GetBox();
4487 nTmpBottomLineDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM );
4489 nBottomLineDist = Max( nBottomLineDist, nTmpBottomLineDist );
4491 return nBottomLineDist;
4494 // <-- collapsing
4496 void SwRowFrm::Format( const SwBorderAttrs *pAttrs )
4498 SWRECTFN( this )
4499 ASSERT( pAttrs, "SwRowFrm::Format ohne Attrs." );
4501 const BOOL bFix = bFixSize;
4503 if ( !bValidPrtArea )
4505 //RowFrms haben keine Umrandung usw. also entspricht die PrtArea immer
4506 //dem Frm.
4507 bValidPrtArea = TRUE;
4508 aPrt.Left( 0 );
4509 aPrt.Top( 0 );
4510 aPrt.Width ( aFrm.Width() );
4511 aPrt.Height( aFrm.Height() );
4513 // --> collapsing borders FME 2005-05-27 #i29550#
4514 // Here we calculate the top-printing area for the lower cell frames
4515 SwTabFrm* pTabFrm = FindTabFrm();
4516 if ( pTabFrm->IsCollapsingBorders() )
4518 const USHORT nTopSpace = lcl_GetTopSpace( *this );
4519 const USHORT nTopLineDist = lcl_GetTopLineDist( *this );
4520 const USHORT nBottomLineSize = lcl_GetBottomLineSize( *this );
4521 const USHORT nBottomLineDist = lcl_GetBottomLineDist( *this );
4524 const SwRowFrm* pPreviousRow = 0;
4526 // --> FME 2004-09-14 #i32456#
4527 // In order to calculate the top printing area for the lower cell
4528 // frames, we have to find the 'previous' row frame and compare
4529 // the bottom values of the 'previous' row with the 'top' values
4530 // of this row. The best way to find the 'previous' row is to
4531 // use the table structure:
4532 const SwTable* pTable = pTabFrm->GetTable();
4533 const SwTableLine* pPrevTabLine = 0;
4534 const SwRowFrm* pTmpRow = this;
4536 while ( pTmpRow && !pPrevTabLine )
4538 USHORT nIdx = 0;
4539 const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ?
4540 pTmpRow->GetTabLine()->GetUpper()->GetTabLines() :
4541 pTable->GetTabLines();
4543 while ( rLines[ nIdx ] != pTmpRow->GetTabLine() )
4544 ++nIdx;
4546 if ( nIdx > 0 )
4548 // pTmpRow has a 'previous' row in the table structure:
4549 pPrevTabLine = rLines[ nIdx - 1 ];
4551 else
4553 // pTmpRow is a first row in the table structue.
4554 // We go up in the table structure:
4555 pTmpRow = pTmpRow->GetUpper()->GetUpper() &&
4556 pTmpRow->GetUpper()->GetUpper()->IsRowFrm() ?
4557 static_cast<const SwRowFrm*>( pTmpRow->GetUpper()->GetUpper() ) :
4562 // If we found a 'previous' row, we look for the appropriate row frame:
4563 if ( pPrevTabLine )
4565 SwClientIter aIter( *pPrevTabLine->GetFrmFmt() );
4566 SwClient* pLast;
4567 for ( pLast = aIter.First( TYPE( SwFrm ) ); pLast; pLast = aIter.Next() )
4569 ASSERT( ((SwFrm*)pLast)->IsRowFrm(),
4570 "Non-row frame registered in table line" )
4571 SwRowFrm* pRow = (SwRowFrm*)pLast;
4572 // --> OD 2004-11-23 #115759# - do *not* take repeated
4573 // headlines, because during split of table it can be
4574 // invalid and thus can't provide correct border values.
4575 if ( pRow->GetTabLine() == pPrevTabLine &&
4576 !pRow->IsRepeatedHeadline() )
4577 // <--
4579 pPreviousRow = pRow;
4580 break;
4584 // <--
4586 USHORT nTopPrtMargin = nTopSpace;
4587 if ( pPreviousRow )
4589 const USHORT nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist;
4590 if ( nTmpPrtMargin > nTopPrtMargin )
4591 nTopPrtMargin = nTmpPrtMargin;
4594 // table has to be notified if it has to change its lower
4595 // margin due to changes of nBottomLineSize:
4596 if ( !GetNext() && nBottomLineSize != GetBottomLineSize() )
4597 pTabFrm->_InvalidatePrt();
4599 // If there are rows nested inside this row, the nested rows
4600 // may not have been calculated yet. Therefore the
4601 // ::lcl_CalcMinRowHeight( this ) operation later in this
4602 // function cannot consider the correct border values. We
4603 // have to trigger the invalidation of the outer row frame
4604 // manually:
4605 // Note: If any further invalidations should be necessary, we
4606 // should consider moving the invalidation stuff to the
4607 // appropriate SwNotify object.
4608 if ( GetUpper()->GetUpper()->IsRowFrm() &&
4609 ( nBottomLineDist != GetBottomMarginForLowers() ||
4610 nTopPrtMargin != GetTopMarginForLowers() ) )
4611 GetUpper()->GetUpper()->_InvalidateSize();
4613 SetBottomMarginForLowers( nBottomLineDist ); // 3.
4614 SetBottomLineSize( nBottomLineSize ); // 4.
4615 SetTopMarginForLowers( nTopPrtMargin ); // 5.
4618 // <-- collapsing
4621 while ( !bValidSize )
4623 bValidSize = TRUE;
4625 #ifndef PRODUCT
4626 if ( HasFixSize() )
4628 const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize();
4629 ASSERT( rFrmSize.GetSize().Height() > 0, "Hat ihn" );
4631 #endif
4632 const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() -
4633 ( HasFixSize() && !IsRowSpanLine()
4634 ? pAttrs->GetSize().Height()
4635 // --> OD 2004-10-04 #i26945#
4636 : ::lcl_CalcMinRowHeight( this,
4637 FindTabFrm()->IsConsiderObjsForMinCellHeight() ) );
4638 // <--
4639 if ( nDiff )
4641 bFixSize = FALSE;
4642 if ( nDiff > 0 )
4643 Shrink( nDiff, FALSE, TRUE );
4644 else if ( nDiff < 0 )
4645 Grow( -nDiff );
4646 bFixSize = bFix;
4650 // last row will fill the space in its upper.
4651 if ( !GetNext() )
4653 //Der letzte fuellt den verbleibenden Raum im Upper aus.
4654 SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)();
4655 SwFrm *pSibling = GetUpper()->Lower();
4657 { nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)();
4658 pSibling = pSibling->GetNext();
4659 } while ( pSibling );
4660 if ( nDiff > 0 )
4662 bFixSize = FALSE;
4663 Grow( nDiff );
4664 bFixSize = bFix;
4665 bValidSize = TRUE;
4670 /*************************************************************************
4672 |* SwRowFrm::AdjustCells()
4674 |* Ersterstellung MA 10. Aug. 93
4675 |* Letzte Aenderung MA 16. Dec. 96
4677 |*************************************************************************/
4678 void SwRowFrm::AdjustCells( const SwTwips nHeight, const BOOL bHeight )
4680 SwFrm *pFrm = Lower();
4681 if ( bHeight )
4683 SwRootFrm *pRootFrm = FindRootFrm();
4684 SWRECTFN( this )
4685 SwRect aOldFrm;
4687 while ( pFrm )
4689 SwFrm* pNotify = 0;
4691 SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pFrm);
4693 // NEW TABLES
4694 // Which cells need to be adjusted if the current row changes
4695 // its height?
4697 // Current frame is a covered frame:
4698 // Set new height for covered cell and adjust master cell:
4699 if ( pCellFrm->GetTabBox()->getRowSpan() < 1 )
4701 // Set height of current (covered) cell to new line height.
4702 const long nDiff = nHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)();
4703 if ( nDiff )
4705 (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff );
4706 pCellFrm->_InvalidatePrt();
4710 SwCellFrm* pToAdjust = 0;
4711 SwFrm* pToAdjustRow = 0;
4713 // If current frame is covered frame, we still want to adjust the
4714 // height of the cell starting the row span
4715 if ( pCellFrm->GetLayoutRowSpan() < 1 )
4717 pToAdjust = const_cast< SwCellFrm*>(&pCellFrm->FindStartEndOfRowSpanCell( true, true ));
4718 pToAdjustRow = pToAdjust->GetUpper();
4720 else
4722 pToAdjust = pCellFrm;
4723 pToAdjustRow = this;
4726 // Set height of master cell to height of all lines spanned by this line.
4727 long nRowSpan = pToAdjust->GetLayoutRowSpan();
4728 SwTwips nSumRowHeight = 0;
4729 while ( pToAdjustRow )
4731 // Use new height for the current row:
4732 nSumRowHeight += pToAdjustRow == this ?
4733 nHeight :
4734 (pToAdjustRow->Frm().*fnRect->fnGetHeight)();
4736 if ( nRowSpan-- == 1 )
4737 break;
4739 pToAdjustRow = pToAdjustRow->GetNext();
4742 if ( pToAdjustRow && pToAdjustRow != this )
4743 pToAdjustRow->_InvalidateSize();
4745 const long nDiff = nSumRowHeight - (pToAdjust->Frm().*fnRect->fnGetHeight)();
4746 if ( nDiff )
4748 aOldFrm = pToAdjust->Frm();
4749 (pToAdjust->Frm().*fnRect->fnAddBottom)( nDiff );
4750 pNotify = pToAdjust;
4753 if ( pNotify )
4755 if( pRootFrm && pRootFrm->IsAnyShellAccessible() && pRootFrm->GetCurrShell() )
4756 pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pNotify, aOldFrm );
4758 pNotify->_InvalidatePrt();
4761 pFrm = pFrm->GetNext();
4764 else
4765 { while ( pFrm )
4767 pFrm->_InvalidateAll();
4768 pFrm = pFrm->GetNext();
4771 InvalidatePage();
4774 /*************************************************************************
4776 |* SwRowFrm::Cut()
4778 |* Ersterstellung MA 12. Nov. 97
4779 |* Letzte Aenderung MA 12. Nov. 97
4781 |*************************************************************************/
4782 void SwRowFrm::Cut()
4784 SwTabFrm *pTab = FindTabFrm();
4785 if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() )
4787 pTab->FindMaster()->InvalidatePos();
4789 SwLayoutFrm::Cut();
4792 /*************************************************************************
4794 |* SwRowFrm::GrowFrm()
4796 |* Ersterstellung MA 15. Mar. 93
4797 |* Letzte Aenderung MA 05. May. 94
4799 |*************************************************************************/
4802 SwTwips SwRowFrm::GrowFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
4804 SwTwips nReal = 0;
4806 SwTabFrm* pTab = FindTabFrm();
4807 SWRECTFN( pTab )
4809 bool bRestrictTableGrowth;
4810 bool bHasFollowFlowLine = pTab->HasFollowFlowLine();
4812 if ( GetUpper()->IsTabFrm() )
4814 const SwRowFrm* pFollowFlowRow = IsInSplitTableRow();
4815 bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine();
4817 else
4819 ASSERT( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" )
4820 bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine;
4821 ASSERT( !bRestrictTableGrowth || !GetNext(),
4822 "GetFollowRow for row frame that has a Next" )
4825 // There may still be some space left in my direct upper:
4827 const SwTwips nAdditionalSpace =
4828 (Frm().*fnRect->fnBottomDist)( (GetUpper()->GetUpper()->*fnRect->fnGetPrtBottom)() );
4829 if ( bRestrictTableGrowth && nAdditionalSpace > 0 )
4831 nReal = Min( nAdditionalSpace, nDist );
4832 nDist -= nReal;
4833 if ( !bTst )
4834 (Frm().*fnRect->fnAddBottom)( nReal );
4838 if ( bRestrictTableGrowth )
4839 pTab->SetRestrictTableGrowth( TRUE );
4840 else
4842 // Ok, this looks like a hack, indeed, it is a hack.
4843 // If the current row frame is inside another cell frame,
4844 // and the current row frame has no follow, it should not
4845 // be allowed to grow. In fact, setting bRestrictTableGrowth
4846 // to 'false' does not work, because the surrounding RowFrm
4847 // would set this to 'true'.
4848 pTab->SetFollowFlowLine( FALSE );
4851 nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo);
4853 pTab->SetRestrictTableGrowth( FALSE );
4854 pTab->SetFollowFlowLine( bHasFollowFlowLine );
4856 //Hoehe der Zellen auf den neuesten Stand bringen.
4857 if ( !bTst )
4859 SWRECTFNX( this )
4860 AdjustCells( (Prt().*fnRectX->fnGetHeight)() + nReal, TRUE );
4861 if ( nReal )
4862 SetCompletePaint();
4865 return nReal;
4868 /*************************************************************************
4870 |* SwRowFrm::ShrinkFrm()
4872 |* Ersterstellung MA 15. Mar. 93
4873 |* Letzte Aenderung MA 20. Jun. 96
4875 |*************************************************************************/
4876 SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
4878 SWRECTFN( this )
4879 if( HasFixSize() )
4881 AdjustCells( (Prt().*fnRect->fnGetHeight)(), TRUE );
4882 return 0L;
4885 //bInfo wird ggf. vom SwRowFrm::Format auf TRUE gesetzt, hier muss dann
4886 //entsprechend reagiert werden
4887 const BOOL bShrinkAnyway = bInfo;
4889 //Nur soweit Shrinken, wie es der Inhalt der groessten Zelle zulaesst.
4890 SwTwips nRealDist = nDist;
4892 const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize();
4893 SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ?
4894 rSz.GetHeight() :
4897 // Only necessary to calculate minimal row height if height
4898 // of pRow is at least nMinHeight. Otherwise nMinHeight is the
4899 // minimum height.
4900 if( nMinHeight < (Frm().*fnRect->fnGetHeight)() )
4902 // --> OD 2004-10-04 #i26945#
4903 ASSERT( FindTabFrm(), "<SwRowFrm::ShrinkFrm(..)> - no table frame -> crash." );
4904 const bool bConsiderObjs( FindTabFrm()->IsConsiderObjsForMinCellHeight() );
4905 // <--
4906 nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs );
4909 if ( ((Frm().*fnRect->fnGetHeight)() - nRealDist) < nMinHeight )
4910 nRealDist = (Frm().*fnRect->fnGetHeight)() - nMinHeight;
4912 if ( nRealDist < 0 )
4913 nRealDist = 0;
4915 SwTwips nReal = nRealDist;
4916 if ( nReal )
4918 if ( !bTst )
4920 SwTwips nHeight = (Frm().*fnRect->fnGetHeight)();
4921 (Frm().*fnRect->fnSetHeight)( nHeight - nReal );
4922 if( IsVertical() && !bRev )
4923 Frm().Pos().X() += nReal;
4926 SwTwips nTmp = GetUpper()->Shrink( nReal, bTst );
4927 if ( !bShrinkAnyway && !GetNext() && nTmp != nReal )
4929 //Der letzte bekommt den Rest im Upper und nimmt deshalb
4930 //ggf. Ruecksichten (sonst: Endlosschleife)
4931 if ( !bTst )
4933 nReal -= nTmp;
4934 SwTwips nHeight = (Frm().*fnRect->fnGetHeight)();
4935 (Frm().*fnRect->fnSetHeight)( nHeight + nReal );
4936 if( IsVertical() && !bRev )
4937 Frm().Pos().X() -= nReal;
4939 nReal = nTmp;
4943 //Geeignet invalidieren und die Hoehe der Zellen auf den neuesten
4944 //Stand bringen.
4945 if ( !bTst )
4947 if ( nReal )
4949 if ( GetNext() )
4950 GetNext()->_InvalidatePos();
4951 _InvalidateAll();
4952 SetCompletePaint();
4954 SwTabFrm *pTab = FindTabFrm();
4955 if ( !pTab->IsRebuildLastLine() && pTab->IsFollow() &&
4956 this == pTab->GetFirstNonHeadlineRow() )
4958 SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() );
4959 pMasterTab->InvalidatePos();
4962 AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, TRUE );
4964 return nReal;
4967 /*************************************************************************
4969 |* SwRowFrm::IsRowSplitAllowed()
4971 |*************************************************************************/
4972 bool SwRowFrm::IsRowSplitAllowed() const
4974 // Fixed size rows are never allowed to split:
4975 if ( HasFixSize() )
4977 ASSERT( ATT_FIX_SIZE == GetFmt()->GetFrmSize().GetHeightSizeType(), "pRow claims to have fixed size" )
4978 return false;
4981 // Repeated headlines are never allowed to split:
4982 const SwTabFrm* pTabFrm = FindTabFrm();
4983 if ( pTabFrm->GetTable()->GetRowsToRepeat() > 0 &&
4984 pTabFrm->IsInHeadline( *this ) )
4985 return false;
4987 const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)GetTabLine()->GetFrmFmt();
4988 const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit();
4989 return 0 != rLP.GetValue();
4992 /*************************************************************************
4994 |* SwRowFrm::ShouldRowKeepWithNext()
4996 |*************************************************************************/
4997 bool SwRowFrm::ShouldRowKeepWithNext() const
4999 bool bRet = false;
5001 const SwCellFrm* pCell = static_cast<const SwCellFrm*>(Lower());
5002 const SwFrm* pTxt = pCell->Lower();
5004 if ( pTxt && pTxt->IsTxtFrm() )
5006 bRet = static_cast<const SwTxtFrm*>(pTxt)->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue();
5008 return bRet;
5011 /*************************************************************************
5013 |* SwCellFrm::SwCellFrm(), ~SwCellFrm()
5015 |* Ersterstellung MA 09. Mar. 93
5016 |* Letzte Aenderung MA 30. May. 96
5018 |*************************************************************************/
5019 SwCellFrm::SwCellFrm( const SwTableBox &rBox, bool bInsertContent ) :
5020 SwLayoutFrm( rBox.GetFrmFmt() ),
5021 pTabBox( &rBox )
5023 nType = FRMC_CELL;
5025 if ( !bInsertContent )
5026 return;
5028 //Wenn ein StartIdx vorhanden ist, so werden CntntFrms in der Zelle
5029 //angelegt, andernfalls muessen Rows vorhanden sein und diese werden
5030 //angelegt.
5031 if ( rBox.GetSttIdx() )
5033 ULONG nIndex = rBox.GetSttIdx();
5034 ::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex );
5036 else
5038 const SwTableLines &rLines = rBox.GetTabLines();
5039 SwFrm *pTmpPrev = 0;
5040 for ( USHORT i = 0; i < rLines.Count(); ++i )
5042 SwRowFrm *pNew = new SwRowFrm( *rLines[i], bInsertContent );
5043 pNew->InsertBehind( this, pTmpPrev );
5044 pTmpPrev = pNew;
5049 SwCellFrm::~SwCellFrm()
5051 SwModify* pMod = GetFmt();
5052 if( pMod )
5054 // At this stage the lower frames aren't destroyed already,
5055 // therfor we have to do a recursive dispose.
5056 SwRootFrm *pRootFrm = FindRootFrm();
5057 if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
5058 pRootFrm->GetCurrShell() )
5060 pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, sal_True );
5063 pMod->Remove( this ); // austragen,
5064 if( !pMod->GetDepends() )
5065 delete pMod; // und loeschen
5069 /*************************************************************************
5071 |* SwCellFrm::Format()
5073 |* Ersterstellung MA 09. Mar. 93
5074 |* Letzte Aenderung MA 29. Jan. 98
5076 |*************************************************************************/
5077 BOOL lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, BOOL bInva )
5079 BOOL bRet = FALSE;
5080 SwFrm *pFrm = pLay->Lower();
5081 SWRECTFN( pLay )
5082 while ( pFrm )
5084 long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)();
5085 if( nFrmTop != lYStart )
5087 bRet = TRUE;
5088 const long lDiff = (*fnRect->fnYDiff)( lYStart, nFrmTop );
5089 const long lDiffX = lYStart - nFrmTop;
5090 (pFrm->Frm().*fnRect->fnSubTop)( -lDiff );
5091 (pFrm->Frm().*fnRect->fnAddBottom)( lDiff );
5092 pFrm->SetCompletePaint();
5093 if ( !pFrm->GetNext() )
5094 pFrm->SetRetouche();
5095 if( bInva )
5096 pFrm->Prepare( PREP_POS_CHGD );
5097 if ( pFrm->IsLayoutFrm() && ((SwLayoutFrm*)pFrm)->Lower() )
5098 lcl_ArrangeLowers( (SwLayoutFrm*)pFrm,
5099 (((SwLayoutFrm*)pFrm)->Lower()->Frm().*fnRect->fnGetTop)()
5100 + lDiffX, bInva );
5101 if ( pFrm->GetDrawObjs() )
5103 for ( USHORT i = 0; i < pFrm->GetDrawObjs()->Count(); ++i )
5105 SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i];
5106 // --> OD 2004-10-08 #i26945# - check, if anchored object
5107 // is lower of layout frame by checking, if the anchor
5108 // frame, which contains the anchor position, is a lower
5109 // of the layout frame.
5110 if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrmContainingAnchPos() ) )
5112 continue;
5114 // <--
5115 // --> OD 2005-08-08 #i52904# - distinguish between anchored
5116 // objects, whose vertical position depends on its anchor
5117 // frame and whose vertical position is independent
5118 // from its anchor frame.
5119 bool bVertPosDepOnAnchor( true );
5121 SwFmtVertOrient aVert( pAnchoredObj->GetFrmFmt().GetVertOrient() );
5122 switch ( aVert.GetRelationOrient() )
5124 case text::RelOrientation::PAGE_FRAME:
5125 case text::RelOrientation::PAGE_PRINT_AREA:
5126 bVertPosDepOnAnchor = false;
5127 break;
5128 default: break;
5131 if ( pAnchoredObj->ISA(SwFlyFrm) )
5133 SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
5135 // OD 2004-05-18 #i28701# - no direct move of objects,
5136 // which are anchored to-paragraph/to-character, if
5137 // the wrapping style influence has to be considered
5138 // on the object positioning.
5139 // --> OD 2005-08-08 #i52904# - no direct move of objects,
5140 // whose vertical position doesn't depend on anchor frame.
5141 const bool bDirectMove =
5142 WEIT_WECH != pFly->Frm().Top() &&
5143 bVertPosDepOnAnchor &&
5144 !pFly->ConsiderObjWrapInfluenceOnObjPos();
5145 // <--
5146 if ( bDirectMove )
5148 (pFly->Frm().*fnRect->fnSubTop)( -lDiff );
5149 (pFly->Frm().*fnRect->fnAddBottom)( lDiff );
5150 pFly->GetVirtDrawObj()->SetRectsDirty();
5151 // --> OD 2004-08-17 - also notify view of <SdrObject>
5152 // instance, which represents the Writer fly frame in
5153 // the drawing layer
5154 pFly->GetVirtDrawObj()->SetChanged();
5155 // <--
5156 // --> OD 2006-10-13 #i58280#
5157 pFly->InvalidateObjRectWithSpaces();
5158 // <--
5161 if ( pFly->IsFlyInCntFrm() )
5163 static_cast<SwFlyInCntFrm*>(pFly)->AddRefOfst( lDiff );
5164 // --> OD 2004-12-02 #115759# - reset current relative
5165 // position to get re-positioned, if not directly moved.
5166 if ( !bDirectMove )
5168 pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
5170 // <--
5172 else if( pFly->IsAutoPos() )
5174 pFly->AddLastCharY( lDiff );
5175 // OD 2004-05-18 #i28701# - follow-up of #i22341#
5176 // <mnLastTopOfLine> has also been adjusted.
5177 pFly->AddLastTopOfLineY( lDiff );
5179 // --> OD 2004-11-05 #i26945# - re-registration at
5180 // page frame of anchor frame, if table frame isn't
5181 // a follow table and table frame isn't in its
5182 // rebuild of last line.
5183 const SwTabFrm* pTabFrm = pLay->FindTabFrm();
5184 // --> OD 2004-11-23 #115759#
5185 // - save: check, if table frame is found.
5186 if ( pTabFrm &&
5187 !( pTabFrm->IsFollow() &&
5188 pTabFrm->FindMaster()->IsRebuildLastLine() ) &&
5189 pFly->IsFlyFreeFrm() )
5190 // <--
5192 SwPageFrm* pPageFrm = pFly->GetPageFrm();
5193 SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm();
5194 if ( pPageFrm != pPageOfAnchor )
5196 pFly->InvalidatePos();
5197 if ( pPageFrm )
5198 pPageFrm->MoveFly( pFly, pPageOfAnchor );
5199 else
5200 pPageOfAnchor->AppendFlyToPage( pFly );
5203 // <--
5204 // OD 2004-05-11 #i28701# - Because of the introduction
5205 // of new positionings and alignments (e.g. aligned at
5206 // page area, but anchored at-character), the position
5207 // of the Writer fly frame has to be invalidated.
5208 pFly->InvalidatePos();
5210 // --> OD 2004-11-04 #i26945# - follow-up of #i3317#
5211 // No arrangement of lowers, if Writer fly frame isn't
5212 // moved
5213 if ( bDirectMove &&
5214 ::lcl_ArrangeLowers( pFly,
5215 (pFly->*fnRect->fnGetPrtTop)(),
5216 bInva ) )
5217 // <--
5219 pFly->SetCompletePaint();
5222 else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) )
5224 // --> OD 2004-11-05 #i26945#
5225 const SwTabFrm* pTabFrm = pLay->FindTabFrm();
5226 if ( pTabFrm &&
5227 !( pTabFrm->IsFollow() &&
5228 pTabFrm->FindMaster()->IsRebuildLastLine() ) &&
5229 !pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
5230 == FLY_IN_CNTNT )
5232 SwPageFrm* pPageFrm = pAnchoredObj->GetPageFrm();
5233 SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm();
5234 if ( pPageFrm != pPageOfAnchor )
5236 pAnchoredObj->InvalidateObjPos();
5237 if ( pPageFrm )
5239 pPageFrm->RemoveDrawObjFromPage( *pAnchoredObj );
5241 pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj );
5244 // --> OD 2004-07-01 #i28701# - adjust last character
5245 // rectangle and last top of line.
5246 pAnchoredObj->AddLastCharY( lDiff );
5247 pAnchoredObj->AddLastTopOfLineY( lDiff );
5248 // --> OD 2005-08-08 #i52904# - re-introduce direct move
5249 // of drawing objects
5250 const bool bDirectMove =
5251 static_cast<const SwDrawFrmFmt&>(pAnchoredObj->GetFrmFmt()).IsPosAttrSet() &&
5252 bVertPosDepOnAnchor &&
5253 !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos();
5254 if ( bDirectMove )
5256 SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
5257 if ( bVert )
5259 pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) );
5261 else
5263 pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) );
5265 // --> OD 2006-10-13 #i58280#
5266 pAnchoredObj->InvalidateObjRectWithSpaces();
5267 // <--
5269 // <--
5270 pAnchoredObj->InvalidateObjPos();
5272 else
5274 ASSERT( false,
5275 "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" );
5280 // Columns and cells are ordered horizontal, not vertical
5281 if( !pFrm->IsColumnFrm() && !pFrm->IsCellFrm() )
5282 lYStart = (*fnRect->fnYInc)( lYStart,
5283 (pFrm->Frm().*fnRect->fnGetHeight)() );
5285 // Nowadays, the content inside a cell can flow into the follow table.
5286 // Thus, the cell may only grow up to the end of the environment.
5287 // So the content may have grown, but the cell could not grow.
5288 // Therefore we have to trigger a formatting for the frames, which do
5289 // not fit into the cell anymore:
5290 SwTwips nDistanceToUpperPrtBottom =
5291 (pFrm->Frm().*fnRect->fnBottomDist)( (pLay->*fnRect->fnGetPrtBottom)());
5292 // --> OD 2006-01-19 #i56146# - Revise fix of issue #i26945#
5293 // do *not* consider content inside fly frames, if it's an undersized paragraph.
5294 // --> OD 2004-10-08 #i26945# - consider content inside fly frames
5295 if ( nDistanceToUpperPrtBottom < 0 &&
5296 ( ( pFrm->IsInFly() &&
5297 ( !pFrm->IsTxtFrm() ||
5298 !static_cast<SwTxtFrm*>(pFrm)->IsUndersized() ) ) ||
5299 pFrm->IsInSplitTableRow() ) )
5300 // <--
5302 pFrm->InvalidatePos();
5305 pFrm = pFrm->GetNext();
5307 return bRet;
5310 void SwCellFrm::Format( const SwBorderAttrs *pAttrs )
5312 ASSERT( pAttrs, "CellFrm::Format, pAttrs ist 0." );
5313 const SwTabFrm* pTab = FindTabFrm();
5314 SWRECTFN( pTab )
5316 if ( !bValidPrtArea )
5318 bValidPrtArea = TRUE;
5320 //Position einstellen.
5321 if ( Lower() )
5323 SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace;
5324 // --> collapsing borders FME 2005-05-27 #i29550#
5325 if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrm() )
5327 const SvxBoxItem& rBoxItem = pAttrs->GetBox();
5328 nLeftSpace = rBoxItem.GetDistance( BOX_LINE_LEFT );
5329 nRightSpace = rBoxItem.GetDistance( BOX_LINE_RIGHT );
5330 nTopSpace = ((SwRowFrm*)GetUpper())->GetTopMarginForLowers();
5331 nBottomSpace = ((SwRowFrm*)GetUpper())->GetBottomMarginForLowers();
5333 else
5335 // <-- collapsing
5336 // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
5337 nLeftSpace = pAttrs->CalcLeft( this );
5338 nRightSpace = pAttrs->CalcRight( this );
5339 nTopSpace = pAttrs->CalcTop();
5340 nBottomSpace = pAttrs->CalcBottom();
5342 (this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace );
5343 (this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace );
5346 // --> OD 2004-10-04 #i26945#
5347 long nRemaining = GetTabBox()->getRowSpan() >= 1 ?
5348 ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) :
5350 // <--
5351 if ( !bValidSize )
5353 bValidSize = TRUE;
5355 //Die VarSize der CellFrms ist immer die Breite.
5356 //Tatsaechlich ist die Breite jedoch nicht Variabel, sie wird durch das
5357 //Format vorgegeben. Dieser Vorgegebene Wert muss aber nun wiederum
5358 //nicht der tatsaechlichen Breite entsprechen. Die Breite wird auf
5359 //Basis des Attributes errechnet, der Wert im Attribut passt zu dem
5360 //gewuenschten Wert des TabFrms. Anpassungen die dort vorgenommen
5361 //wurden werden hier Proportional beruecksichtigt.
5362 //Wenn die Celle keinen Nachbarn mehr hat beruecksichtigt sie nicht
5363 //die Attribute, sonder greift sich einfach den Rest des
5364 //Uppers
5365 SwTwips nWidth;
5366 if ( GetNext() )
5368 const SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth();
5369 nWidth = pAttrs->GetSize().Width();
5371 ASSERT( nWish, "Tabelle ohne Breite?" );
5372 ASSERT( nWidth <= nWish, "Zelle breiter als Tabelle." );
5373 ASSERT( nWidth > 0, "Box without width" );
5375 const long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
5376 if ( nWish != nPrtWidth )
5378 // Avoid rounding problems, at least for the new table model
5379 if ( pTab->GetTable()->IsNewModel() )
5381 // 1. sum of widths of cells up to this cell (in model)
5382 const SwTableLine* pTabLine = GetTabBox()->GetUpper();
5383 const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
5384 const SwTableBox* pTmpBox = 0;
5386 SwTwips nSumWidth = 0;
5387 USHORT i = 0;
5390 pTmpBox = rBoxes[ i++ ];
5391 nSumWidth += pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth();
5393 while ( pTmpBox != GetTabBox() );
5395 // 2. calculate actual width of cells up to this one
5396 double nTmpWidth = nSumWidth;
5397 nTmpWidth *= nPrtWidth;
5398 nTmpWidth /= nWish;
5399 nWidth = (SwTwips)nTmpWidth;
5401 // 3. calculate frame widths of cells up to this one:
5402 const SwFrm* pTmpCell = static_cast<const SwLayoutFrm*>(GetUpper())->Lower();
5403 SwTwips nSumFrameWidths = 0;
5404 while ( pTmpCell != this )
5406 nSumFrameWidths += (pTmpCell->Frm().*fnRect->fnGetWidth)();
5407 pTmpCell = pTmpCell->GetNext();
5410 nWidth = nWidth - nSumFrameWidths;
5412 else
5414 // #i12092# use double instead of long,
5415 // otherwise this could lead to overflows
5416 double nTmpWidth = nWidth;
5417 nTmpWidth *= nPrtWidth;
5418 nTmpWidth /= nWish;
5419 nWidth = (SwTwips)nTmpWidth;
5423 else
5425 ASSERT( pAttrs->GetSize().Width() > 0, "Box without width" );
5426 nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
5427 SwFrm *pPre = GetUpper()->Lower();
5428 while ( pPre != this )
5430 nWidth -= (pPre->Frm().*fnRect->fnGetWidth)();
5431 pPre = pPre->GetNext();
5434 const long nDiff = nWidth - (Frm().*fnRect->fnGetWidth)();
5435 if( IsNeighbourFrm() && IsRightToLeft() )
5436 (Frm().*fnRect->fnSubLeft)( nDiff );
5437 else
5438 (Frm().*fnRect->fnAddRight)( nDiff );
5439 (Prt().*fnRect->fnAddRight)( nDiff );
5441 //Jetzt die Hoehe einstellen, sie wird vom Inhalt und den Raendern
5442 //bestimmt.
5443 const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)();
5444 if ( nDiffHeight )
5446 if ( nDiffHeight > 0 )
5448 //Wieder validieren wenn kein Wachstum stattgefunden hat.
5449 //Invalidiert wird durch AdjustCells von der Row.
5450 if ( !Grow( nDiffHeight ) )
5451 bValidSize = bValidPrtArea = TRUE;
5453 else
5455 //Nur dann invalidiert lassen, wenn tatsaechlich
5456 //geshrinkt wurde; das kann abgelehnt werden, weil alle
5457 //nebeneinanderliegenden Zellen gleichgross sein muessen.
5458 if ( !Shrink( -nDiffHeight ) )
5459 bValidSize = bValidPrtArea = TRUE;
5463 const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient();
5465 if ( !Lower() )
5466 return;
5468 // From now on, all operations are related to the table cell.
5469 SWREFRESHFN( this )
5471 SwPageFrm* pPg = 0;
5472 if ( !FindTabFrm()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() &&
5473 // --> OD 2008-07-16 #158225# no vertical alignment of covered cells
5474 !IsCoveredCell() &&
5475 // <--
5476 // --> FME 2004-06-29 #116532# Do not consider vertical alignment in grid mode
5477 !(pPg = FindPageFrm())->HasGrid() )
5478 // <--
5480 if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() && !Lower()->IsTabFrm() )
5482 //ASSERT fuer HTML-Import!
5483 ASSERT( !this, "VAlign an Zelle ohne Inhalt" );
5484 return;
5486 BOOL bVertDir = TRUE;
5487 // --> OD 2005-03-30 #i43913# - no vertical alignment, if wrapping
5488 // style influence is considered on object positioning and
5489 // an object is anchored inside the cell.
5490 const bool bConsiderWrapOnObjPos( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) );
5491 // <--
5492 //Keine Ausrichtung wenn Rahmen mit Umlauf in die Zelle ragen.
5493 if ( pPg->GetSortedObjs() )
5495 SwRect aRect( Prt() ); aRect += Frm().Pos();
5496 for ( USHORT i = 0; i < pPg->GetSortedObjs()->Count(); ++i )
5498 const SwAnchoredObject* pAnchoredObj = (*pPg->GetSortedObjs())[i];
5499 SwRect aTmp( pAnchoredObj->GetObjRect() );
5500 if ( aTmp.IsOver( aRect ) )
5502 const SwFrmFmt& rAnchoredObjFrmFmt = pAnchoredObj->GetFrmFmt();
5503 const SwFmtSurround &rSur = rAnchoredObjFrmFmt.GetSurround();
5505 if ( SURROUND_THROUGHT != rSur.GetSurround() )
5507 // frames, which the cell is a lower of, aren't relevant
5508 if ( pAnchoredObj->ISA(SwFlyFrm) )
5510 const SwFlyFrm *pFly =
5511 static_cast<const SwFlyFrm*>(pAnchoredObj);
5512 if ( pFly->IsAnLower( this ) )
5513 continue;
5516 const SwFrm* pAnch = pAnchoredObj->GetAnchorFrm();
5517 // --> OD 2005-03-30 #i43913#
5518 // --> OD 2005-08-08 #i52904# - no vertical alignment,
5519 // if object, anchored inside cell, has temporarly
5520 // consider its wrapping style on object positioning.
5521 // --> FME 2006-02-01 #i58806# - no vertical alignment
5522 // if object does not follow the text flow.
5523 if ( bConsiderWrapOnObjPos ||
5524 !IsAnLower( pAnch ) ||
5525 pAnchoredObj->IsTmpConsiderWrapInfluence() ||
5526 !rAnchoredObjFrmFmt.GetFollowTextFlow().GetValue() )
5527 // <--
5529 bVertDir = FALSE;
5530 break;
5537 long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
5538 if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) ||
5539 (Lower()->Frm().*fnRect->fnGetTop)() != (this->*fnRect->fnGetPrtTop)() )
5541 long lTopOfst = 0,
5542 nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining;
5543 if ( nDiff >= 0 )
5545 if ( bVertDir )
5547 switch ( rOri.GetVertOrient() )
5549 case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break;
5550 case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break;
5551 default: break;
5554 long nTmp = (*fnRect->fnYInc)(
5555 (this->*fnRect->fnGetPrtTop)(), lTopOfst );
5556 if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) )
5557 SetCompletePaint();
5561 else
5563 //Ist noch eine alte Ausrichtung beruecksichtigt worden?
5564 if ( Lower()->IsCntntFrm() )
5566 const long lYStart = (this->*fnRect->fnGetPrtTop)();
5567 lcl_ArrangeLowers( this, lYStart, TRUE );
5572 /*************************************************************************
5574 |* SwCellFrm::Modify()
5576 |* Ersterstellung MA 20. Dec. 96
5577 |* Letzte Aenderung MA 20. Dec. 96
5579 |*************************************************************************/
5581 void SwCellFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
5583 BOOL bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
5584 const SfxPoolItem *pItem = 0;
5586 if( bAttrSetChg )
5587 ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, FALSE, &pItem);
5588 else if ( RES_VERT_ORIENT == pNew->Which() )
5589 pItem = pNew;
5591 if ( pItem )
5593 BOOL bInva = TRUE;
5594 if ( text::VertOrientation::NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() &&
5595 // OD 04.11.2003 #112910#
5596 Lower() && Lower()->IsCntntFrm() )
5598 SWRECTFN( this )
5599 const long lYStart = (this->*fnRect->fnGetPrtTop)();
5600 bInva = lcl_ArrangeLowers( this, lYStart, FALSE );
5602 if ( bInva )
5604 SetCompletePaint();
5605 InvalidatePrt();
5609 if ( ( bAttrSetChg &&
5610 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, FALSE ) ) ||
5611 RES_PROTECT == pNew->Which() )
5613 ViewShell *pSh = GetShell();
5614 if( pSh && pSh->GetLayout()->IsAnyShellAccessible() )
5615 pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this );
5618 if ( bAttrSetChg &&
5619 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, FALSE, &pItem ) )
5621 SetDerivedVert( FALSE );
5622 CheckDirChange();
5625 // --> collapsing borders FME 2005-05-27 #i29550#
5626 if ( bAttrSetChg &&
5627 SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_BOX, FALSE, &pItem ) )
5629 SwFrm* pTmpUpper = GetUpper();
5630 while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrm() )
5631 pTmpUpper = pTmpUpper->GetUpper();
5633 SwTabFrm* pTabFrm = (SwTabFrm*)pTmpUpper->GetUpper();
5634 if ( pTabFrm->IsCollapsingBorders() )
5636 // Invalidate lowers of this and next row:
5637 lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper );
5638 pTmpUpper = pTmpUpper->GetNext();
5639 if ( pTmpUpper )
5640 lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper );
5641 else
5642 pTabFrm->InvalidatePrt();
5645 // <-- collapsing
5647 SwLayoutFrm::Modify( pOld, pNew );
5650 /*************************************************************************
5651 |* SwCellFrm::GetLayoutRowSpan() const
5652 |*************************************************************************/
5654 long SwCellFrm::GetLayoutRowSpan() const
5656 long nRet = GetTabBox()->getRowSpan();
5657 if ( nRet < 1 )
5659 const SwFrm* pRow = GetUpper();
5660 const SwTabFrm* pTab = static_cast<const SwTabFrm*>(pRow->GetUpper());
5662 if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() )
5663 nRet = -nRet;
5665 return nRet;
5668 /*************************************************************************
5670 |* SwCellFrm::Modify()
5672 |* Ersterstellung MA 20. Dec. 96
5673 |* Letzte Aenderung MA 20. Dec. 96
5675 |*************************************************************************/
5679 // Helper functions for repeated headlines:
5683 * SwTabFrm::IsInHeadline( const SwFrm& rFrm )
5685 bool SwTabFrm::IsInHeadline( const SwFrm& rFrm ) const
5687 ASSERT( IsAnLower( &rFrm ) && rFrm.IsInTab(),
5688 "SwTabFrm::IsInHeadline called for frame not lower of table" )
5690 const SwFrm* pTmp = &rFrm;
5691 while ( !pTmp->GetUpper()->IsTabFrm() )
5692 pTmp = pTmp->GetUpper();
5694 return GetTable()->IsHeadline( *((SwRowFrm*)pTmp)->GetTabLine() );
5698 * SwTabFrm::GetFirstNonHeadlineRow()
5700 * If this is a master table, we can may assume, that there are at least
5701 * nRepeat lines in the table.
5702 * If this is a follow table, there are intermediate states for the table
5703 * layout, e.g., during deletion of rows, which makes it necessary to find
5704 * the first non-headline row by evaluating the headline flag at the row frame.
5706 SwRowFrm* SwTabFrm::GetFirstNonHeadlineRow() const
5708 SwRowFrm* pRet = (SwRowFrm*)Lower();
5709 if ( pRet )
5711 if ( IsFollow() )
5713 while ( pRet && pRet->IsRepeatedHeadline() )
5714 pRet = (SwRowFrm*)pRet->GetNext();
5716 else
5718 USHORT nRepeat = GetTable()->GetRowsToRepeat();
5719 while ( pRet && nRepeat > 0 )
5721 pRet = (SwRowFrm*)pRet->GetNext();
5722 --nRepeat;
5727 return (SwRowFrm*)pRet;
5731 * SwTable::IsHeadline()
5733 bool SwTable::IsHeadline( const SwTableLine& rLine ) const
5735 for ( USHORT i = 0; i < GetRowsToRepeat(); ++i )
5736 if ( GetTabLines()[ i ] == &rLine )
5737 return true;
5739 return false;
5742 bool SwTabFrm::IsLayoutSplitAllowed() const
5744 return GetFmt()->GetLayoutSplit().GetValue();
5747 // --> collapsing borders FME 2005-05-27 #i29550#
5749 USHORT SwTabFrm::GetBottomLineSize() const
5751 ASSERT( IsCollapsingBorders(),
5752 "BottomLineSize only required for collapsing borders" )
5754 ASSERT( Lower(), "Warning! Trying to prevent a crash, please inform FME" )
5756 const SwFrm* pTmp = GetLastLower();
5758 // --> FME 2005-12-07 #124755# Try to make code robust:
5759 if ( !pTmp ) return 0;
5760 // <--
5762 return static_cast<const SwRowFrm*>(pTmp)->GetBottomLineSize();
5765 bool SwTabFrm::IsCollapsingBorders() const
5767 return ((SfxBoolItem&)GetFmt()->GetAttrSet().Get( RES_COLLAPSING_BORDERS )).GetValue();
5770 // <-- collapsing
5774 // Local helper function to calculate height of first text row
5776 SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrm& rSourceLine )
5778 // Find corresponding split line in master table
5779 const SwTabFrm* pTab = rSourceLine.FindTabFrm();
5780 SWRECTFN( pTab )
5781 const SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower();
5784 // 1. Case: rSourceLine is a follow flow line.
5785 // In this case we have to return the minimum of the heights
5786 // of the first lines in rSourceLine.
5788 // 2. Case: rSourceLine is not a follow flow line.
5789 // In this case we have to return the maximum of the heights
5790 // of the first lines in rSourceLine.
5792 bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow();
5793 SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0;
5795 while ( pCurrSourceCell )
5797 // NEW TABLES
5798 // Skip cells which are not responsible for the height of
5799 // the follow flow line:
5800 if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 )
5802 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
5803 continue;
5806 const SwFrm *pTmp = pCurrSourceCell->Lower();
5807 if ( pTmp )
5809 SwTwips nTmpHeight = USHRT_MAX;
5810 // --> FME 2004-09-14 #i32456# Consider lower row frames
5811 if ( pTmp->IsRowFrm() )
5813 const SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
5814 nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow );
5816 // <--
5817 if ( pTmp->IsTabFrm() )
5819 nTmpHeight = ((SwTabFrm*)pTmp)->CalcHeightOfFirstContentLine();
5821 else if ( pTmp->IsTxtFrm() )
5823 SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp;
5824 pTxtFrm->GetFormatted();
5825 nTmpHeight = pTxtFrm->FirstLineHeight();
5828 if ( USHRT_MAX != nTmpHeight )
5830 const SwCellFrm* pPrevCell = pCurrSourceCell->GetPreviousCell();
5831 if ( pPrevCell )
5833 // If we are in a split row, there may be some space
5834 // left in the cell frame of the master row.
5835 // We look for the minimum of all first line heights;
5836 SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)();
5837 const SwFrm* pFrm = pPrevCell->Lower();
5838 const SwFrm* pLast = pFrm;
5839 while ( pFrm )
5841 nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
5842 pLast = pFrm;
5843 pFrm = pFrm->GetNext();
5846 // --> FME, OD 2004-07-15 #i26831#, #i26520#
5847 // The additional lower space of the current last.
5848 // --> OD 2004-11-25 #115759# - do *not* consider the
5849 // additional lower space for 'master' text frames
5850 if ( pLast && pLast->IsFlowFrm() &&
5851 ( !pLast->IsTxtFrm() ||
5852 !static_cast<const SwTxtFrm*>(pLast)->GetFollow() ) )
5853 // <--
5855 nReal += SwFlowFrm::CastFlowFrm(pLast)->CalcAddLowerSpaceAsLastInTableCell();
5857 // Don't forget the upper space and lower space,
5858 // --> OD 2004-11-25 #115759# - do *not* consider the upper
5859 // and the lower space for follow text frames.
5860 if ( pTmp->IsFlowFrm() &&
5861 ( !pTmp->IsTxtFrm() ||
5862 !static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) )
5864 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace( NULL, pLast);
5865 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace();
5867 // <--
5868 // --> OD 2004-11-25 #115759# - consider additional lower
5869 // space of <pTmp>, if contains only one line.
5870 // In this case it would be the new last text frame, which
5871 // would have no follow and thus would add this space.
5872 if ( pTmp->IsTxtFrm() &&
5873 const_cast<SwTxtFrm*>(static_cast<const SwTxtFrm*>(pTmp))
5874 ->GetLineCount( STRING_LEN ) == 1 )
5876 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)
5877 ->CalcAddLowerSpaceAsLastInTableCell();
5879 // <--
5880 if ( nReal > 0 )
5881 nTmpHeight -= nReal;
5883 else
5885 // pFirstRow is not a FollowFlowRow. In this case,
5886 // we look for the maximum of all first line heights:
5887 SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCurrSourceCell );
5888 const SwBorderAttrs &rAttrs = *aAccess.Get();
5889 nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
5890 // --> OD 2004-07-16 #i26250#
5891 // Don't forget the upper space and lower space,
5892 if ( pTmp->IsFlowFrm() )
5894 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace();
5895 nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace();
5897 // <--
5901 if ( bIsInFollowFlowLine )
5903 // minimum
5904 if ( nTmpHeight < nHeight )
5905 nHeight = nTmpHeight;
5907 else
5909 // maximum
5910 if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight )
5911 nHeight = nTmpHeight;
5915 pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext();
5918 return ( LONG_MAX == nHeight ) ? 0 : nHeight;
5922 // Function to calculate height of first text row
5924 SwTwips SwTabFrm::CalcHeightOfFirstContentLine() const
5926 SWRECTFN( this )
5928 const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue();
5930 if ( bDontSplit )
5932 // Table is not allowed to split: Take the whole height, that's all
5933 return (Frm().*fnRect->fnGetHeight)();
5936 SwRowFrm* pFirstRow = 0;
5937 SwTwips nTmpHeight = 0;
5939 pFirstRow = GetFirstNonHeadlineRow();
5940 ASSERT( !IsFollow() || pFirstRow, "FollowTable without Lower" )
5942 // NEW TABLES
5943 if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() )
5944 pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext());
5946 // Calculate the height of the headlines:
5947 const USHORT nRepeat = GetTable()->GetRowsToRepeat();
5948 SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0;
5950 // Calculate the height of the keeping lines
5951 // (headlines + following keeping lines):
5952 SwTwips nKeepHeight = nRepeatHeight;
5953 if ( GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) )
5955 USHORT nKeepRows = nRepeat;
5957 // Check how many rows want to keep together
5958 while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() )
5960 ++nKeepRows;
5961 pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext());
5964 if ( nKeepRows > nRepeat )
5965 nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows );
5968 // For master tables, the height of the headlines + the heigth of the
5969 // keeping lines (if any) has to be considered. For follow tables, we
5970 // only consider the height of the keeping rows without the repeated lines:
5971 if ( !IsFollow() )
5973 nTmpHeight = nKeepHeight;
5975 else
5977 nTmpHeight = nKeepHeight - nRepeatHeight;
5980 // pFirstRow row is the first non-heading row.
5981 // nTmpHeight is the height of the heading row if we are a follow.
5982 if ( pFirstRow )
5984 const bool bSplittable = pFirstRow->IsRowSplitAllowed();
5985 const SwTwips nFirstLineHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)();
5987 if ( !bSplittable )
5989 // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow
5990 // actually is determined by a lower cell with rowspan = -1. In this case we should not
5991 // just return the height of the first line. Basically we need to get the height of the
5992 // line as it would be on the last page. Since this is quite complicated to calculate,
5993 // we olny calculate the height of the first line.
5994 if ( pFirstRow->GetPrev() &&
5995 static_cast<SwRowFrm*>(pFirstRow->GetPrev())->IsRowSpanLine() )
5997 // Calculate maximum height of all cells with rowspan = 1:
5998 SwTwips nMaxHeight = 0;
5999 const SwCellFrm* pLower2 = static_cast<const SwCellFrm*>(pFirstRow->Lower());
6000 while ( pLower2 )
6002 if ( 1 == pLower2->GetTabBox()->getRowSpan() )
6004 const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, TRUE );
6005 nMaxHeight = Max( nCellHeight, nMaxHeight );
6007 pLower2 = static_cast<const SwCellFrm*>(pLower2->GetNext());
6009 nTmpHeight += nMaxHeight;
6011 else
6013 nTmpHeight += nFirstLineHeight;
6017 // --> FME 2004-11-18 #118411#
6018 // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger
6019 // a formatting of the row frame (via the GetFormatted()). We don't
6020 // want this formatting if the row does not have a height.
6021 else if ( 0 != nFirstLineHeight )
6022 // <--
6024 const bool bOldJoinLock = IsJoinLocked();
6025 ((SwTabFrm*)this)->LockJoin();
6026 const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow );
6028 // Consider minimum row height:
6029 const SwFmtFrmSize &rSz = static_cast<const SwRowFrm*>(pFirstRow)->GetFmt()->GetFrmSize();
6030 const SwTwips nMinRowHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ?
6031 rSz.GetHeight() : 0;
6033 nTmpHeight += Max( nHeightOfFirstContentLine, nMinRowHeight );
6035 if ( !bOldJoinLock )
6036 ((SwTabFrm*)this)->UnlockJoin();
6040 return nTmpHeight;
6044 // Some more functions for covered/covering cells. This way inclusion of
6045 // SwCellFrm can be avoided
6048 bool SwFrm::IsLeaveUpperAllowed() const
6050 const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this);
6051 return pThisCell && pThisCell->GetLayoutRowSpan() > 1;
6054 bool SwFrm::IsCoveredCell() const
6056 const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this);
6057 return pThisCell && pThisCell->GetLayoutRowSpan() < 1;
6060 bool SwFrm::IsInCoveredCell() const
6062 bool bRet = false;
6064 const SwFrm* pThis = this;
6065 while ( pThis && !pThis->IsCellFrm() )
6066 pThis = pThis->GetUpper();
6068 if ( pThis )
6069 bRet = pThis->IsCoveredCell();
6071 return bRet;