diff options
Diffstat (limited to 'sw/source/core/layout/tabfrm.cxx')
-rw-r--r-- | sw/source/core/layout/tabfrm.cxx | 5798 |
1 files changed, 5798 insertions, 0 deletions
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx new file mode 100644 index 000000000000..08f756d65b87 --- /dev/null +++ b/sw/source/core/layout/tabfrm.cxx @@ -0,0 +1,5798 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "viewsh.hxx" +#include "doc.hxx" +#include "docsh.hxx" +#include "viewimp.hxx" +#include "swtable.hxx" +#include "dflyobj.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "frmfmt.hxx" +#include "dcontact.hxx" +#include <anchoreddrawobject.hxx> +#include <fmtanchr.hxx> +#include "viewopt.hxx" +#include "hints.hxx" +#include "dbg_lay.hxx" +#include <ftnidx.hxx> +#include <svl/itemiter.hxx> +#include <docary.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/boxitem.hxx> +#include <vcl/outdev.hxx> +#include <fmtlsplt.hxx> +#include <fmtrowsplt.hxx> +#include <fmtsrnd.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fmtfsize.hxx> +#include <swtblfmt.hxx> +#include <ndtxt.hxx> +#include "tabfrm.hxx" +#include "rowfrm.hxx" +#include "cellfrm.hxx" +#include "flyfrms.hxx" +#include "txtfrm.hxx" //HasFtn() +#include "htmltbl.hxx" +#include "sectfrm.hxx" //SwSectionFrm +#include <fmtfollowtextflow.hxx> +#include <sortedobjs.hxx> +#include <objectformatter.hxx> +#include <layouter.hxx> +#include <switerator.hxx> + +extern void AppendObjs( const SwSpzFrmFmts *pTbl, sal_uLong nIndex, + SwFrm *pFrm, SwPageFrm *pPage ); + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwTabFrm::SwTabFrm(), ~SwTabFrm() +|* +|*************************************************************************/ +SwTabFrm::SwTabFrm( SwTable &rTab, SwFrm* pSib ): + SwLayoutFrm( rTab.GetFrmFmt(), pSib ), + SwFlowFrm( (SwFrm&)*this ), + pTable( &rTab ) +{ + bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove = + bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = + bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; + // --> OD 2004-10-04 #i26945# + bConsiderObjsForMinCellHeight = sal_True; + bObjsDoesFit = sal_True; + // <-- + bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. + nType = FRMC_TAB; + + //Gleich die Zeilen erzeugen und einfuegen. + const SwTableLines &rLines = rTab.GetTabLines(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + SwRowFrm *pNew = new SwRowFrm( *rLines[i], this ); + if( pNew->Lower() ) + { + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } + else + delete pNew; + } + OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "SwTabFrm::SwTabFrm: No rows." ); +} + +SwTabFrm::SwTabFrm( SwTabFrm &rTab ) : + SwLayoutFrm( rTab.GetFmt(), &rTab ), + SwFlowFrm( (SwFrm&)*this ), + pTable( rTab.GetTable() ) +{ + bIsFollow = sal_True; + bLockJoin = bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove = + bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = + bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; + // --> OD 2004-10-04 #i26945# + bConsiderObjsForMinCellHeight = sal_True; + bObjsDoesFit = sal_True; + // <-- + bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. + nType = FRMC_TAB; + + SetFollow( rTab.GetFollow() ); + rTab.SetFollow( this ); +} + +extern const SwTable *pColumnCacheLastTable; +extern const SwTabFrm *pColumnCacheLastTabFrm; +extern const SwFrm *pColumnCacheLastCellFrm; +extern const SwTable *pRowCacheLastTable; +extern const SwTabFrm *pRowCacheLastTabFrm; +extern const SwFrm *pRowCacheLastCellFrm; + +SwTabFrm::~SwTabFrm() +{ + // There is some terrible code in fetab.cxx, that + // makes use of these global pointers. Obviously + // this code did not consider that a TabFrm can be + // deleted. + if ( this == pColumnCacheLastTabFrm ) + { + pColumnCacheLastTable = NULL; + pColumnCacheLastTabFrm = NULL; + pColumnCacheLastCellFrm= NULL; + pRowCacheLastTable = NULL; + pRowCacheLastTabFrm = NULL; + pRowCacheLastCellFrm= NULL; + } +} + +/************************************************************************* +|* +|* SwTabFrm::JoinAndDelFollows() +|* +|*************************************************************************/ +void SwTabFrm::JoinAndDelFollows() +{ + SwTabFrm *pFoll = GetFollow(); + if ( pFoll->HasFollow() ) + pFoll->JoinAndDelFollows(); + pFoll->Cut(); + SetFollow( pFoll->GetFollow() ); + delete pFoll; +} + +/************************************************************************* +|* +|* SwTabFrm::RegistFlys() +|* +|*************************************************************************/ +void SwTabFrm::RegistFlys() +{ + OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "Keine Zeilen." ); + + SwPageFrm *pPage = FindPageFrm(); + if ( pPage ) + { + SwRowFrm *pRow = (SwRowFrm*)Lower(); + do + { + pRow->RegistFlys( pPage ); + pRow = (SwRowFrm*)pRow->GetNext(); + } while ( pRow ); + } +} + +/************************************************************************* +|* Some prototypes +|*************************************************************************/ +void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ); +void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ); +sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ); +// --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control +// that only row and cell frames are formatted. +sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, + long nBottom, + bool _bOnlyRowsAndCells = false ); +// <-- +// OD 2004-02-18 #106629# - correct type of 1st parameter +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to +// control, if floating screen objects have to be considered for the minimal +// cell height. +SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm *pRow, + const sal_Bool _bConsiderObjs ); +// <-- +SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm&, const SwBorderAttrs& ); + +/************************************************************************* +|* START: local helper functions for repeated headlines +|*************************************************************************/ + +SwTwips lcl_GetHeightOfRows( const SwFrm* pStart, long nCount ) +{ + if ( !nCount || !pStart) + return 0; + + SwTwips nRet = 0; + SWRECTFN( pStart ) + while ( pStart && nCount > 0 ) + { + nRet += (pStart->Frm().*fnRect->fnGetHeight)(); + pStart = pStart->GetNext(); + --nCount; + } + + return nRet; +} + +/************************************************************************* +|* END: local helper functions for repeated headlines +|*************************************************************************/ + +/************************************************************************* +|* START: local helper functions for splitting row frames +|*************************************************************************/ + +// +// Local helper function to insert a new follow flow line +// +SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, bool bRowSpanLine ) +{ + OSL_ENSURE( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" ); + const SwRowFrm& rRow = (SwRowFrm&)rTmpRow; + + rTab.SetFollowFlowLine( sal_True ); + SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), &rTab, false ); + pFollowFlowLine->SetRowSpanLine( bRowSpanLine ); + SwFrm* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow(); + pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow ); + return pFollowFlowLine; +} + +// --> OD 2004-11-05 #i26945# - local helper function to invalidate all lower +// objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if +// additionally the objects are moved 'out of range'. +void lcl_InvalidateLowerObjs( SwLayoutFrm& _rLayoutFrm, + const bool _bMoveObjsOutOfRange = false, + SwPageFrm* _pPageFrm = 0L ) +{ + // determine page frame, if needed + if ( !_pPageFrm ) + { + _pPageFrm = _rLayoutFrm.FindPageFrm(); + OSL_ENSURE( _pPageFrm, + "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" ); + if ( !_pPageFrm ) + { + return; + } + } + + // loop on lower frames + SwFrm* pLowerFrm = _rLayoutFrm.Lower(); + while ( pLowerFrm ) + { + if ( pLowerFrm->IsLayoutFrm() ) + { + ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pLowerFrm)), + _bMoveObjsOutOfRange, _pPageFrm ); + } + if ( pLowerFrm->GetDrawObjs() ) + { + for ( sal_uInt16 i = 0; i < pLowerFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pLowerFrm->GetDrawObjs())[i]; + + // invalidate position of anchored object + pAnchoredObj->SetTmpConsiderWrapInfluence( false ); + pAnchoredObj->SetConsiderForTextWrap( false ); + pAnchoredObj->UnlockPosition(); + pAnchoredObj->InvalidateObjPos(); + + // move anchored object 'out of range' + if ( _bMoveObjsOutOfRange ) + { + // indicate, that positioning is progress to avoid + // modification of the anchored object resp. its attributes + // due to the movement + SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); + pAnchoredObj->SetObjLeft( _pPageFrm->Frm().Right() ); + // --> OD 2004-11-24 #115759# - reset character rectangle, + // top of line and relative position in order to assure, + // that anchored object is correctly positioned. + pAnchoredObj->ClearCharRectAndTopOfLine(); + pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); + if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() + == FLY_AS_CHAR ) + { + pAnchoredObj->AnchorFrm() + ->Prepare( PREP_FLY_ATTR_CHG, + &(pAnchoredObj->GetFrmFmt()) ); + } + // <-- + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + pFly->GetVirtDrawObj()->SetRectsDirty(); + pFly->GetVirtDrawObj()->SetChanged(); + } + } + + // If anchored object is a fly frame, invalidate its lower objects + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrm ); + } + } + } + pLowerFrm = pLowerFrm->GetNext(); + } +} +// <-- +// +// Local helper function to shrink all lowers of rRow to 0 height +// +void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow ) +{ + SwCellFrm* pCurrMasterCell = static_cast<SwCellFrm*>(rRow.Lower()); + SWRECTFN( pCurrMasterCell ) + + while ( pCurrMasterCell ) + { + // NEW TABLES + SwCellFrm& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ? + const_cast<SwCellFrm&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true, true )) : + *pCurrMasterCell; + + // --> OD 2004-10-04 #i26945# + // all lowers should have the correct position + lcl_ArrangeLowers( &rToAdjust, + (rToAdjust.*fnRect->fnGetPrtTop)(), + sal_False ); + // <-- + // TODO: Optimize number of frames which are set to 0 height + // we have to start with the last lower frame, otherwise + // the shrink will not shrink the current cell + SwFrm* pTmp = rToAdjust.GetLastLower(); + + if ( pTmp && pTmp->IsRowFrm() ) + { + SwRowFrm* pTmpRow = (SwRowFrm*)pTmp; + lcl_ShrinkCellsAndAllContent( *pTmpRow ); + } + else + { + // TODO: Optimize number of frames which are set to 0 height + while ( pTmp ) + { + // the frames have to be shrunk + if ( pTmp && pTmp->IsTabFrm() ) + { + SwRowFrm* pTmpRow = (SwRowFrm*)((SwTabFrm*)pTmp)->Lower(); + while ( pTmpRow ) + { + lcl_ShrinkCellsAndAllContent( *pTmpRow ); + pTmpRow = (SwRowFrm*)pTmpRow->GetNext(); + } + } + else + { + pTmp->Shrink( (pTmp->Frm().*fnRect->fnGetHeight)() ); + (pTmp->Prt().*fnRect->fnSetTop)( 0 ); + (pTmp->Prt().*fnRect->fnSetHeight)( 0 ); + } + + pTmp = pTmp->GetPrev(); + } + + // all lowers should have the correct position + lcl_ArrangeLowers( &rToAdjust, + (rToAdjust.*fnRect->fnGetPrtTop)(), + sal_False ); + } + + pCurrMasterCell = static_cast<SwCellFrm*>(pCurrMasterCell->GetNext()); + } +} + +// +// Local helper function to move the content from rSourceLine to rDestLine +// The content is inserted behind the last content in the corresponding +// cell in rDestLine. +// +void lcl_MoveRowContent( SwRowFrm& rSourceLine, SwRowFrm& rDestLine ) +{ + SwCellFrm* pCurrDestCell = (SwCellFrm*)rDestLine.Lower(); + SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); + + // Move content of follow cells into master cells + while ( pCurrSourceCell ) + { + if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() ) + { + SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + while ( pTmpSourceRow ) + { + // --> FME 2006-01-10 #125926# Achtung! It is possible, + // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow + // cannot be found. In this case, we have to move the complete + // row. + SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower(); + // <-- + + if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow ) + { + // move content from follow flow row to pTmpDestRow: + while ( pTmpDestRow->GetNext() ) + pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext(); + + OSL_ENSURE( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Knoten in der Tabelle" ); + + lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow ); + pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() ); + pTmpSourceRow->Remove(); + delete pTmpSourceRow; + } + else + { + // move complete row: + pTmpSourceRow->Remove(); + pTmpSourceRow->InsertBefore( pCurrDestCell, 0 ); + } + + pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + } + } + else + { + SwFrm *pTmp = ::SaveCntnt( (SwCellFrm*)pCurrSourceCell ); + if ( pTmp ) + { + // NEW TABLES + SwCellFrm* pDestCell = static_cast<SwCellFrm*>(pCurrDestCell); + if ( pDestCell->GetTabBox()->getRowSpan() < 1 ) + pDestCell = & const_cast<SwCellFrm&>(pDestCell->FindStartEndOfRowSpanCell( true, true )); + + // Find last content + SwFrm* pFrm = pDestCell->GetLastLower(); + ::RestoreCntnt( pTmp, pDestCell, pFrm, true ); + } + } + pCurrDestCell = (SwCellFrm*)pCurrDestCell->GetNext(); + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + } +} + +// +// Local helper function to move all footnotes in rRowFrm from +// the footnote boss of rSource to the footnote boss of rDest. +// +void lcl_MoveFootnotes( SwTabFrm& rSource, SwTabFrm& rDest, SwLayoutFrm& rRowFrm ) +{ + if ( 0 != rSource.GetFmt()->GetDoc()->GetFtnIdxs().Count() ) + { + SwFtnBossFrm* pOldBoss = rSource.FindFtnBossFrm( sal_True ); + SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( sal_True ); + rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, sal_True ); + } +} + +// +// Local helper function to handle nested table cells before the split process +// +void lcl_PreprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine, + SwRowFrm& rFollowFlowLine, SwTwips nRemain ) +{ + SwCellFrm* pCurrLastLineCell = (SwCellFrm*)rLastLine.Lower(); + SwCellFrm* pCurrFollowFlowLineCell = (SwCellFrm*)rFollowFlowLine.Lower(); + + SWRECTFN( pCurrLastLineCell ) + + // + // Move content of follow cells into master cells + // + while ( pCurrLastLineCell ) + { + if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrm() ) + { + SwTwips nTmpCut = nRemain; + SwRowFrm* pTmpLastLineRow = (SwRowFrm*)pCurrLastLineCell->Lower(); + + // --> OD 2004-10-04 #i26945# + SwTwips nCurrentHeight = + lcl_CalcMinRowHeight( pTmpLastLineRow, + rTab.IsConsiderObjsForMinCellHeight() ); + // <-- + while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight ) + { + nTmpCut -= nCurrentHeight; + pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); + // --> OD 2004-10-04 #i26945# + nCurrentHeight = + lcl_CalcMinRowHeight( pTmpLastLineRow, + rTab.IsConsiderObjsForMinCellHeight() ); + // <-- + } + + // + // pTmpLastLineRow does not fit to the line or it is the last line + // + if ( pTmpLastLineRow ) + { + // + // Check if we can move pTmpLastLineRow to the follow table, + // or if we have to split the line: + // + SwFrm* pCell = pTmpLastLineRow->Lower(); + bool bTableLayoutToComplex = false; + long nMinHeight = 0; + + // + // We have to take into account: + // 1. The fixed height of the row + // 2. The borders of the cells inside the row + // 3. The minimum height of the row + // + if ( pTmpLastLineRow->HasFixSize() ) + nMinHeight = (pTmpLastLineRow->Frm().*fnRect->fnGetHeight)(); + else + { + while ( pCell ) + { + if ( ((SwCellFrm*)pCell)->Lower() && + ((SwCellFrm*)pCell)->Lower()->IsRowFrm() ) + { + bTableLayoutToComplex = true; + break; + } + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nMinHeight = Max( nMinHeight, lcl_CalcTopAndBottomMargin( *(SwLayoutFrm*)pCell, rAttrs ) ); + pCell = pCell->GetNext(); + } + + const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize(); + if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE ) + nMinHeight = Max( nMinHeight, rSz.GetHeight() ); + } + + // + // 1. Case: + // The line completely fits into the master table. + // Nevertheless, we build a follow (otherwise painting problems + // with empty cell). + // + // 2. Case: + // The line has to be split, the minimum height still fits into + // the master table, and the table structure is not to complex. + // + if ( nTmpCut > nCurrentHeight || + ( pTmpLastLineRow->IsRowSplitAllowed() && + !bTableLayoutToComplex && nMinHeight < nTmpCut ) ) + { + // The line has to be split: + SwRowFrm* pNewRow = new SwRowFrm( *pTmpLastLineRow->GetTabLine(), &rTab, false ); + pNewRow->SetFollowFlowRow( true ); + pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() ); + pTmpLastLineRow->SetFollowRow( pNewRow ); + pNewRow->InsertBehind( pCurrFollowFlowLineCell, 0 ); + pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); + } + + // + // The following lines have to be moved: + // + while ( pTmpLastLineRow ) + { + SwRowFrm* pTmp = (SwRowFrm*)pTmpLastLineRow->GetNext(); + lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow ); + pTmpLastLineRow->Remove(); + pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, 0 ); + pTmpLastLineRow->Shrink( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); + pCurrFollowFlowLineCell->Grow( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); + pTmpLastLineRow = pTmp; + } + } + } + + pCurrLastLineCell = (SwCellFrm*)pCurrLastLineCell->GetNext(); + pCurrFollowFlowLineCell = (SwCellFrm*)pCurrFollowFlowLineCell->GetNext(); + } +} + +// +// Local helper function to handle nested table cells after the split process +// +void lcl_PostprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine ) +{ + SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); + while ( pCurrMasterCell ) + { + if ( pCurrMasterCell->Lower() && + pCurrMasterCell->Lower()->IsRowFrm() ) + { + SwRowFrm* pRowFrm = static_cast<SwRowFrm*>(pCurrMasterCell->GetLastLower()); + + if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() ) + { + OSL_ENSURE( pRowFrm->GetFollowRow(), "Deleting row frame without follow" ); + + // The footnotes have to be moved: + lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrm ); + pRowFrm->Cut(); + SwRowFrm* pFollowRow = pRowFrm->GetFollowRow(); + pRowFrm->Paste( pFollowRow->GetUpper(), pFollowRow ); + pRowFrm->SetFollowRow( pFollowRow->GetFollowRow() ); + lcl_MoveRowContent( *pFollowRow, *pRowFrm ); + pFollowRow->Cut(); + delete pFollowRow; + ::SwInvalidateAll( pCurrMasterCell, LONG_MAX ); + } + } + + pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); + } +} + +// +// Local helper function to re-calculate the split line. +// +inline void TableSplitRecalcLock( SwFlowFrm *pTab ) { pTab->LockJoin(); } +inline void TableSplitRecalcUnlock( SwFlowFrm *pTab ) { pTab->UnlockJoin(); } + +bool lcl_RecalcSplitLine( SwRowFrm& rLastLine, SwRowFrm& rFollowLine, + SwTwips nRemainingSpaceForLastRow ) +{ + bool bRet = true; + + SwTabFrm& rTab = (SwTabFrm&)*rLastLine.GetUpper(); + + // + // If there are nested cells in rLastLine, the recalculation of the last + // line needs some preprocessing. + // + lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow ); + + // + // Here the recalculation process starts: + // + rTab.SetRebuildLastLine( sal_True ); + // --> OD 2004-10-15 #i26945# + rTab.SetDoesObjsFit( sal_True ); + // <-- + SWRECTFN( rTab.GetUpper() ) + + // --> OD 2004-11-05 #i26945# - invalidate and move floating screen + // objects 'out of range' + ::lcl_InvalidateLowerObjs( rLastLine, true ); + // <-- + // + // manipulate row and cell sizes + // + // --> OD 2004-10-04 #i26945# - Do *not* consider floating screen objects + // for the minimal cell height. + rTab.SetConsiderObjsForMinCellHeight( sal_False ); + ::lcl_ShrinkCellsAndAllContent( rLastLine ); + rTab.SetConsiderObjsForMinCellHeight( sal_True ); + // <-- + + // + // invalidate last line + // + ::SwInvalidateAll( &rLastLine, LONG_MAX ); + + // + // Lock this tab frame and its follow + // + bool bUnlockMaster = false; + bool bUnlockFollow = false; + SwTabFrm* pMaster = rTab.IsFollow() ? (SwTabFrm*)rTab.FindMaster() : 0; + if ( pMaster && !pMaster->IsJoinLocked() ) + { + bUnlockMaster = true; + ::TableSplitRecalcLock( pMaster ); + } + if ( !rTab.GetFollow()->IsJoinLocked() ) + { + bUnlockFollow = true; + ::TableSplitRecalcLock( rTab.GetFollow() ); + } + + // + // Do the recalculation + // + lcl_RecalcRow( rLastLine, LONG_MAX ); + // --> OD 2004-11-23 #115759# - force a format of the last line in order to + // get the correct height. + rLastLine.InvalidateSize(); + rLastLine.Calc(); + // <-- + + // + // Unlock this tab frame and its follow + // + if ( bUnlockFollow ) + ::TableSplitRecalcUnlock( rTab.GetFollow() ); + if ( bUnlockMaster ) + ::TableSplitRecalcUnlock( pMaster ); + + // + // If there are nested cells in rLastLine, the recalculation of the last + // line needs some postprocessing. + // + lcl_PostprocessRowsInCells( rTab, rLastLine ); + + // + // Do a couple of checks on the current situation. + // + // If we are not happy with the current situation we return false. + // This will start a new try to split the table, this time we do not + // try to split the table rows. + // + + // + // 1. Check if table fits to its upper. + // --> OD 2004-10-15 #i26945# - include check, if objects fit + // + const SwTwips nDistanceToUpperPrtBottom = + (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)()); + if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() ) + bRet = false; + // <-- + + // + // 2. Check if each cell in the last line has at least one content frame. + // + // Note: a FollowFlowRow may contains empty cells! + // + if ( bRet ) + { + if ( !rLastLine.IsInFollowFlowRow() ) + { + SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); + while ( pCurrMasterCell ) + { + if ( !pCurrMasterCell->ContainsCntnt() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 ) + { + bRet = false; + break; + } + pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); + } + } + } + + // + // 3. Check if last line does not contain any content: + // + if ( bRet ) + { + if ( !rLastLine.ContainsCntnt() ) + { + bRet = false; + } + } + + + // + // 4. Check if follow flow line does not contain content: + // + if ( bRet ) + { + if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsCntnt() ) + { + bRet = false; + } + } + + if ( bRet ) + { + // + // Everything looks fine. Splitting seems to be successful. We invalidate + // rFollowLine to force a new formatting. + // + ::SwInvalidateAll( &rFollowLine, LONG_MAX ); + } + else + { + // + // Splitting the table row gave us an unexpected result. + // Everything has to be prepared for a second try to split + // the table, this time without splitting the row. + // + ::SwInvalidateAll( &rLastLine, LONG_MAX ); + } + + rTab.SetRebuildLastLine( sal_False ); + // --> OD 2004-10-15 #i26945# + rTab.SetDoesObjsFit( sal_True ); + // <-- + + return bRet; +} + +// +// Sets the correct height for all spanned cells +// +void lcl_AdjustRowSpanCells( SwRowFrm* pRow ) +{ + SWRECTFN( pRow ) + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pRow->GetLower()); + while ( pCellFrm ) + { + const long nLayoutRowSpan = pCellFrm->GetLayoutRowSpan(); + if ( nLayoutRowSpan > 1 ) + { + // calculate height of cell: + const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan ); + const long nDiff = nNewCellHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); + } + + pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); + } +} + +// +// Returns the maximum layout row span of the row +// Looking for the next row that contains no covered cells: +long lcl_GetMaximumLayoutRowSpan( const SwRowFrm& rRow ) +{ + long nRet = 1; + + const SwRowFrm* pCurrentRowFrm = static_cast<const SwRowFrm*>(rRow.GetNext()); + bool bNextRow = false; + + while ( pCurrentRowFrm ) + { + // if there is any covered cell, we proceed to the next row frame + const SwCellFrm* pLower = static_cast<const SwCellFrm*>( pCurrentRowFrm->Lower()); + while ( pLower ) + { + if ( pLower->GetTabBox()->getRowSpan() < 0 ) + { + ++nRet; + bNextRow = true; + break; + } + pLower = static_cast<const SwCellFrm*>(pLower->GetNext()); + } + pCurrentRowFrm = bNextRow ? + static_cast<const SwRowFrm*>(pCurrentRowFrm->GetNext() ) : + 0; + } + + return nRet; +} + +/************************************************************************* +|* END: local helper functions for splitting row frames +|*************************************************************************/ + +// +// Function to remove the FollowFlowLine of rTab. +// The content of the FollowFlowLine is moved to the associated line in the +// master table. +// +bool SwTabFrm::RemoveFollowFlowLine() +{ + // find FollowFlowLine + SwRowFrm* pFollowFlowLine = static_cast<SwRowFrm*>(GetFollow()->GetFirstNonHeadlineRow()); + + // find last row in master + SwFrm* pLastLine = GetLastLower(); + + OSL_ENSURE( HasFollowFlowLine() && + pFollowFlowLine && + pLastLine, "There should be a flowline in the follow" ); + + // We have to reset the flag here, because lcl_MoveRowContent + // calls a GrowFrm(), which has a different bahavior if + // this flag is set. + SetFollowFlowLine( sal_False ); + + // --> FME 2007-07-19 #140081# Make code robust. + if ( !pFollowFlowLine || !pLastLine ) + return true; + + // Move content + lcl_MoveRowContent( *pFollowFlowLine, *(SwRowFrm*)pLastLine ); + + // NEW TABLES + // If a row span follow flow line is removed, we want to move the whole span + // to the master: + long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine ); + + if ( nRowsToMove > 1 ) + { + SWRECTFN( this ) + SwFrm* pRow = pFollowFlowLine->GetNext(); + SwFrm* pInsertBehind = GetLastLower(); + SwTwips nGrow = 0; + + while ( pRow && nRowsToMove-- > 1 ) + { + SwFrm* pNxt = pRow->GetNext(); + nGrow += (pRow->Frm().*fnRect->fnGetHeight)(); + + // The footnotes have to be moved: + lcl_MoveFootnotes( *GetFollow(), *this, (SwRowFrm&)*pRow ); + + pRow->Remove(); + pRow->InsertBehind( this, pInsertBehind ); + pRow->_InvalidateAll(); + pRow->CheckDirChange(); + pInsertBehind = pRow; + pRow = pNxt; + } + + SwFrm* pFirstRow = Lower(); + while ( pFirstRow ) + { + lcl_AdjustRowSpanCells( static_cast<SwRowFrm*>(pFirstRow) ); + pFirstRow = pFirstRow->GetNext(); + } + + Grow( nGrow ); + GetFollow()->Shrink( nGrow ); + } + + bool bJoin = !pFollowFlowLine->GetNext(); + pFollowFlowLine->Cut(); + delete pFollowFlowLine; + + return bJoin; +} + +// --> OD 2004-10-04 #i26945# - Floating screen objects are no longer searched. +bool lcl_FindSectionsInRow( const SwRowFrm& rRow ) +{ + bool bRet = false; + SwCellFrm* pLower = (SwCellFrm*)rRow.Lower(); + while ( pLower ) + { + if ( pLower->IsVertical() != rRow.IsVertical() ) + return true; + + SwFrm* pTmpFrm = pLower->Lower(); + while ( pTmpFrm ) + { + if ( pTmpFrm->IsRowFrm() ) + { + bRet = lcl_FindSectionsInRow( *(SwRowFrm*)pTmpFrm ); + } + else + { + // --> OD 2004-10-04 #i26945# - search only for sections + bRet = pTmpFrm->IsSctFrm(); + // <-- + } + + if ( bRet ) + return true; + pTmpFrm = pTmpFrm->GetNext(); + } + + pLower = (SwCellFrm*)pLower->GetNext(); + } + return bRet; +} + +/************************************************************************* +|* +|* SwTabFrm::Split(), Join() +|* +|*************************************************************************/ +bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep ) +{ + bool bRet = true; + + SWRECTFN( this ) + + // --> OD 2004-10-14 #i26745# - format row and cell frames of table + { + this->Lower()->_InvalidatePos(); + // --> OD 2005-03-30 #i43913# - correction: + // call method <lcl_InnerCalcLayout> with first lower. + lcl_InnerCalcLayout( this->Lower(), LONG_MAX, true ); + // <-- + } + // <-- + + //Um die Positionen der Zellen mit der CutPos zu vergleichen muessen sie + //ausgehend von der Tabelle nacheinander berechnet werden. Sie koennen + //wg. Positionsaenderungen der Tabelle durchaus ungueltig sein. + SwRowFrm *pRow = static_cast<SwRowFrm*>(Lower()); + if( !pRow ) + return bRet; + + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + sal_uInt16 nRowCount = 0; // pRow currently points to the first row + + SwTwips nRemainingSpaceForLastRow = + (*fnRect->fnYDiff)( nCutPos, (Frm().*fnRect->fnGetTop)() ); + nRemainingSpaceForLastRow -= (this->*fnRect->fnGetTopMargin)(); + + // + // Make pRow point to the line that does not fit anymore: + // + while( pRow->GetNext() && + nRemainingSpaceForLastRow >= ( (pRow->Frm().*fnRect->fnGetHeight)() + + (IsCollapsingBorders() ? + pRow->GetBottomLineSize() : + 0 ) ) ) + { + if( bTryToSplit || !pRow->IsRowSpanLine() || + 0 != (pRow->Frm().*fnRect->fnGetHeight)() ) + ++nRowCount; + nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)(); + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + } + + // + // bSplitRowAllowed: Row may be split according to its attributes. + // bTryToSplit: Row will never be split if bTryToSplit = false. + // This can either be passed as a parameter, indicating + // that we are currently doing the second try to split the + // table, or it will be set to falseunder certain + // conditions that are not suitable for splitting + // the row. + // + bool bSplitRowAllowed = pRow->IsRowSplitAllowed(); + + // --> FME 2004-06-03 #i29438# + // --> OD 2004-10-04 #i26945# - Floating screen objects no longer forbid + // a splitting of the table row. + // Special DoNotSplit case 1: + // Search for sections inside pRow: + // + if ( lcl_FindSectionsInRow( *pRow ) ) + { + bTryToSplit = false; + } + // <-- + + // --> FME 2004-06-07 #i29771# + // To avoid loops, we do some checks before actually trying to split + // the row. Maybe we should keep the next row in this table. + // Note: This is only done if we are at the beginning of our upper + bool bKeepNextRow = false; + if ( nRowCount < nRepeat ) + { + // + // First case: One of the repeated headline does not fit to the page anymore. + // At least one more non-heading row has to stay in this table in + // order to avoid loops: + // + OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" ); + bKeepNextRow = true; + } + else if ( !GetIndPrev() && nRepeat == nRowCount ) + { + // + // Second case: The first non-headline row does not fit to the page. + // If it is not allowed to be split, or it contains a sub-row that + // is not allowed to be split, we keep the row in this table: + // + if ( bTryToSplit && bSplitRowAllowed ) + { + // Check if there are (first) rows inside this row, + // which are not allowed to be split. + SwCellFrm* pLowerCell = pRow ? (SwCellFrm*)pRow->Lower() : 0; + while ( pLowerCell ) + { + if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrm() ) + { + const SwRowFrm* pLowerRow = (SwRowFrm*)pLowerCell->Lower(); + if ( !pLowerRow->IsRowSplitAllowed() && + (pLowerRow->Frm().*fnRect->fnGetHeight)() > + nRemainingSpaceForLastRow ) + { + bKeepNextRow = true; + break; + } + } + pLowerCell = (SwCellFrm*)pLowerCell->GetNext(); + } + } + else + bKeepNextRow = true; + } + + // + // Better keep the next row in this table: + // + if ( bKeepNextRow ) + { + pRow = GetFirstNonHeadlineRow(); + if( pRow && pRow->IsRowSpanLine() && 0 == (pRow->Frm().*fnRect->fnGetHeight)() ) + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + if ( pRow ) + { + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + ++nRowCount; + } + } + + // + // No more row to split or to move to follow table: + // + if ( !pRow ) + return bRet; + + // + // We try to split the row if + // - the attributes of the row are set accordingly and + // - we are allowed to do so + // - the it should not keep with the next row + // + bSplitRowAllowed = bSplitRowAllowed && bTryToSplit && + ( !bTableRowKeep || + !pRow->ShouldRowKeepWithNext() ); + + // Adjust pRow according to the keep-with-next attribute: + if ( !bSplitRowAllowed && bTableRowKeep ) + { + SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pRow->GetPrev()); + SwRowFrm* pOldRow = pRow; + while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() && + nRowCount > nRepeat ) + { + pRow = pTmpRow; + --nRowCount; + pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetPrev()); + } + + // loop prevention + if ( nRowCount == nRepeat && !GetIndPrev()) + { + pRow = pOldRow; + } + } + + // + // If we do not indent to split pRow, we check if we are + // allowed to move pRow to a follow. Otherwise we return + // false, indicating an error + // + if ( !bSplitRowAllowed ) + { + SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); + if ( pRow == pFirstNonHeadlineRow ) + return false; + + // --> OD 2008-10-21 #i91764# + // Ignore row span lines + SwRowFrm* pTmpRow = pFirstNonHeadlineRow; + while ( pTmpRow && pTmpRow->IsRowSpanLine() ) + { + pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetNext()); + } + if ( !pTmpRow || pRow == pTmpRow ) + { + return false; + } + // <-- + } + + // + // Build follow table if not already done: + // + sal_Bool bNewFollow; + SwTabFrm *pFoll; + if ( GetFollow() ) + { + pFoll = GetFollow(); + bNewFollow = sal_False; + } + else + { + bNewFollow = sal_True; + pFoll = new SwTabFrm( *this ); + + // + // We give the follow table an initial width. + // + (pFoll->Frm().*fnRect->fnAddWidth)( (Frm().*fnRect->fnGetWidth)() ); + (pFoll->Prt().*fnRect->fnAddWidth)( (Prt().*fnRect->fnGetWidth)() ); + (pFoll->Frm().*fnRect->fnSetLeft)( (Frm().*fnRect->fnGetLeft)() ); + + // + // Insert the new follow table + // + pFoll->InsertBehind( GetUpper(), this ); + + // + // Repeat the headlines. + // + for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount ) + { + // Insert new headlines: + bDontCreateObjects = sal_True; //frmtool + SwRowFrm* pHeadline = new SwRowFrm( + *GetTable()->GetTabLines()[ nRowCount ], this ); + pHeadline->SetRepeatedHeadline( true ); + bDontCreateObjects = sal_False; + pHeadline->InsertBefore( pFoll, 0 ); + + SwPageFrm *pPage = pHeadline->FindPageFrm(); + const SwSpzFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts(); + if( pTbl->Count() ) + { + sal_uLong nIndex; + SwCntntFrm* pFrm = pHeadline->ContainsCntnt(); + while( pFrm ) + { + nIndex = pFrm->GetNode()->GetIndex(); + AppendObjs( pTbl, nIndex, pFrm, pPage ); + pFrm = pFrm->GetNextCntntFrm(); + if( !pHeadline->IsAnLower( pFrm ) ) + break; + } + } + } + } + + SwRowFrm* pLastRow = 0; // will point to the last remaining line in master + SwRowFrm* pFollowRow = 0; // points to either the follow flow line of the + // first regular line in the follow + + if ( bSplitRowAllowed ) + { + // If the row that does not fit anymore is allowed + // to be split, the next row has to be moved to the follow table. + pLastRow = pRow; + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + + // new follow flow line for last row of master table + pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false ); + } + else + { + pFollowRow = pRow; + + // NEW TABLES + // check if we will break a row span by moving pFollowRow to the follow: + // In this case we want to reformat the last line. + const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>(pFollowRow->GetLower()); + while ( pCellFrm ) + { + if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) + { + pLastRow = static_cast<SwRowFrm*>(pRow->GetPrev()); + break; + } + + pCellFrm = static_cast<const SwCellFrm*>(pCellFrm->GetNext()); + } + + // new follow flow line for last row of master table + if ( pLastRow ) + pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true ); + } + + SwTwips nRet = 0; + + //Optimierung beim neuen Follow braucht's kein Paste und dann kann + //das Optimierte Insert verwendet werden (nur dann treten gluecklicher weise + //auch groessere Mengen von Rows auf). + if ( bNewFollow ) + { + SwFrm* pNxt = 0; + SwFrm* pInsertBehind = pFoll->GetLastLower(); + + while ( pRow ) + { + pNxt = pRow->GetNext(); + nRet += (pRow->Frm().*fnRect->fnGetHeight)(); + // The footnotes do not have to be moved, this is done in the + // MoveFwd of the follow table!!! + pRow->Remove(); + pRow->InsertBehind( pFoll, pInsertBehind ); + pRow->_InvalidateAll(); + pInsertBehind = pRow; + pRow = static_cast<SwRowFrm*>(pNxt); + } + } + else + { + SwFrm* pNxt = 0; + SwFrm* pPasteBefore = HasFollowFlowLine() ? + pFollowRow->GetNext() : + pFoll->GetFirstNonHeadlineRow(); + + while ( pRow ) + { + pNxt = pRow->GetNext(); + nRet += (pRow->Frm().*fnRect->fnGetHeight)(); + + // The footnotes have to be moved: + lcl_MoveFootnotes( *this, *GetFollow(), *pRow ); + + pRow->Remove(); + pRow->Paste( pFoll, pPasteBefore ); + + pRow->CheckDirChange(); + pRow = static_cast<SwRowFrm*>(pNxt); + } + } + + Shrink( nRet ); + + // we rebuild the last line to assure that it will be fully formatted + if ( pLastRow ) + { + // recalculate the split line + bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow ); + + // NEW TABLES + // check if each cell in the row span line has a good height + if ( bRet && pFollowRow->IsRowSpanLine() ) + lcl_AdjustRowSpanCells( pFollowRow ); + + // We The RowSplitLine stuff did not work. In this case we conceal the split error: + if ( !bRet && !bSplitRowAllowed ) + { + bRet = true; + } + } + + return bRet; +} + +bool SwTabFrm::Join() +{ + OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" ); + + SwTabFrm *pFoll = GetFollow(); + + if ( !pFoll->IsJoinLocked() ) + { + SWRECTFN( this ) + pFoll->Cut(); //Erst ausschneiden um unuetze Benachrichtigungen zu + //minimieren. + + SwFrm *pRow = pFoll->GetFirstNonHeadlineRow(), + *pNxt; + + SwFrm* pPrv = GetLastLower(); + + SwTwips nHeight = 0; //Gesamthoehe der eingefuegten Zeilen als Return. + while ( pRow ) + { + pNxt = pRow->GetNext(); + nHeight += (pRow->Frm().*fnRect->fnGetHeight)(); + pRow->Remove(); + pRow->_InvalidateAll(); + pRow->InsertBehind( this, pPrv ); + pRow->CheckDirChange(); + pPrv = pRow; + pRow = pNxt; + } + + SetFollow( pFoll->GetFollow() ); + SetFollowFlowLine( pFoll->HasFollowFlowLine() ); + delete pFoll; + + Grow( nHeight ); + } + + return true; +} + +/************************************************************************* +|* +|* SwTabFrm::MakeAll() +|* +|*************************************************************************/ +void MA_FASTCALL SwInvalidatePositions( SwFrm *pFrm, long nBottom ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + SWRECTFN( pFrm ) + do + { pFrm->_InvalidatePos(); + pFrm->_InvalidateSize(); + if( pFrm->IsLayoutFrm() ) + { + if ( ((SwLayoutFrm*)pFrm)->Lower() ) + { + ::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom); + // --> OD 2004-11-05 #i26945# + ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pFrm)) ); + // <-- + } + } + else + pFrm->Prepare( PREP_ADJUST_FRM ); + pFrm = pFrm->GetNext(); + } while ( pFrm && + ( bAll || + (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); +} + +void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + SWRECTFN( pFrm ) + do + { + pFrm->_InvalidatePos(); + pFrm->_InvalidateSize(); + pFrm->_InvalidatePrt(); + if( pFrm->IsLayoutFrm() ) + { + // NEW TABLES + SwLayoutFrm* pToInvalidate = static_cast<SwLayoutFrm*>(pFrm); + SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); + if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) + { + pToInvalidate = & const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); + pToInvalidate->_InvalidatePos(); + pToInvalidate->_InvalidateSize(); + pToInvalidate->_InvalidatePrt(); + } + + if ( pToInvalidate->Lower() ) + ::SwInvalidateAll( pToInvalidate->Lower(), nBottom); + } + else + pFrm->Prepare( PREP_CLEAR ); + + pFrm = pFrm->GetNext(); + } while ( pFrm && + ( bAll || + (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); +} + +// --> collapsing borders FME 2005-05-27 #i29550# +void lcl_InvalidateAllLowersPrt( SwLayoutFrm* pLayFrm ) +{ + pLayFrm->_InvalidatePrt(); + pLayFrm->_InvalidateSize(); + pLayFrm->SetCompletePaint(); + + SwFrm* pFrm = pLayFrm->Lower(); + + while ( pFrm ) + { + if ( pFrm->IsLayoutFrm() ) + lcl_InvalidateAllLowersPrt( (SwLayoutFrm*)pFrm ); + else + { + pFrm->_InvalidatePrt(); + pFrm->_InvalidateSize(); + pFrm->SetCompletePaint(); + } + + pFrm = pFrm->GetNext(); + } +} +// <-- collapsing + +bool SwCntntFrm::CalcLowers( SwLayoutFrm* pLay, const SwLayoutFrm* pDontLeave, + long nBottom, bool bSkipRowSpanCells ) +{ + if ( !pLay ) + return sal_True; + + // LONG_MAX == nBottom means we have to calculate all + bool bAll = LONG_MAX == nBottom; + bool bRet = sal_False; + SwCntntFrm *pCnt = pLay->ContainsCntnt(); + SWRECTFN( pLay ) + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns = 0; + const sal_uInt16 nLoopControlMax = 10; + const SwModify* pLoopControlCond = 0; + + while ( pCnt && pDontLeave->IsAnLower( pCnt ) ) + { + // --> OD 2004-11-23 #115759# - check, if a format of content frame is + // possible. Thus, 'copy' conditions, found at the beginning of + // <SwCntntFrm::MakeAll(..)>, and check these. + const bool bFormatPossible = !pCnt->IsJoinLocked() && + ( !pCnt->IsTxtFrm() || + !static_cast<SwTxtFrm*>(pCnt)->IsLocked() ) && + ( pCnt->IsFollow() || !StackHack::IsLocked() ); + + // NEW TABLES + bool bSkipContent = false; + if ( bSkipRowSpanCells && pCnt->IsInTab() ) + { + const SwFrm* pCell = pCnt->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + if ( pCell && 1 != static_cast<const SwCellFrm*>( pCell )->GetLayoutRowSpan() ) + bSkipContent = true; + } + + if ( bFormatPossible && !bSkipContent ) + { + bRet |= !pCnt->IsValid(); + // --> OD 2004-10-06 #i26945# - no extra invalidation of floating + // screen objects needed. + // Thus, delete call of method <SwFrm::InvalidateObjs( true )> + // <-- + pCnt->Calc(); + // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrm(..)> + // to format the floating screen objects + // --> OD 2005-05-03 #i46941# - frame has to be valid + // Note: frame could be invalid after calling its format, if it's locked. + OSL_ENSURE( !pCnt->IsTxtFrm() || + pCnt->IsValid() || + static_cast<SwTxtFrm*>(pCnt)->IsJoinLocked(), + "<SwCntntFrm::CalcLowers(..)> - text frame invalid and not locked." ); + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame to + // the object formatter + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + // <-- + { + if ( pCnt->GetRegisteredIn() == pLoopControlCond ) + ++nLoopControlRuns; + else + { + nLoopControlRuns = 0; + pLoopControlCond = pCnt->GetRegisteredIn(); + } + + if ( nLoopControlRuns < nLoopControlMax ) + { + // restart format with first content + pCnt = pLay->ContainsCntnt(); + continue; + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl in SwCntntFrm::CalcLowers" ) +#endif + } + } + pCnt->GetUpper()->Calc(); + } + // <-- + if( ! bAll && (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 ) + break; + pCnt = pCnt->GetNextCntntFrm(); + } + return bRet; +} + +// --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control +// that only row and cell frames are formatted. +sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, + long nBottom, + bool _bOnlyRowsAndCells ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + sal_Bool bRet = sal_False; + const SwFrm* pOldUp = pFrm->GetUpper(); + SWRECTFN( pFrm ) + do + { + // --> OD 2004-10-15 #i26945# - parameter <_bOnlyRowsAndCells> controls, + // if only row and cell frames are formatted. + if ( pFrm->IsLayoutFrm() && + ( !_bOnlyRowsAndCells || pFrm->IsRowFrm() || pFrm->IsCellFrm() ) ) + // <-- + { + // --> FME 2006-02-23 #130744# An invalid locked table frame will + // not be calculated => It will not become valid => + // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet. + bRet |= !pFrm->IsValid() && ( !pFrm->IsTabFrm() || !static_cast<SwTabFrm*>(pFrm)->IsJoinLocked() ); + // <-- + pFrm->Calc(); + if( static_cast<SwLayoutFrm*>(pFrm)->Lower() ) + bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrm*>(pFrm)->Lower(), nBottom); + + // NEW TABLES + SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); + if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) + { + SwCellFrm& rToCalc = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); + bRet |= !rToCalc.IsValid(); + rToCalc.Calc(); + if ( rToCalc.Lower() ) + bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom); + } + } + pFrm = pFrm->GetNext(); + } while( pFrm && + ( bAll || + (*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 ) + && pFrm->GetUpper() == pOldUp ); + return bRet; +} + +void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ) +{ + // --> OD 2004-10-05 #i26945# - For correct appliance of the 'straightforward + // object positioning process, it's needed to notify that the page frame, + // on which the given layout frame is in, is in its layout process. + SwPageFrm* pPageFrm = rRow.FindPageFrm(); + if ( pPageFrm && !pPageFrm->IsLayoutInProgress() ) + pPageFrm->SetLayoutInProgress( true ); + else + pPageFrm = 0L; + // <-- + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_1 = 0; + sal_uInt16 nLoopControlStage_1 = 0; + const sal_uInt16 nLoopControlMax = 10; + + bool bCheck = true; + do + { + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_2 = 0; + sal_uInt16 nLoopControlStage_2 = 0; + + while( lcl_InnerCalcLayout( &rRow, nBottom ) ) + { + if ( ++nLoopControlRuns_2 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" ); + OSL_ENSURE( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" ); + OSL_ENSURE( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" ); +#endif + rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ ); + nLoopControlRuns_2 = 0; + if( nLoopControlStage_2 > 2 ) + break; + } + + bCheck = true; + } + + if( bCheck ) + { + // --> OD 2004-11-23 #115759# - force another format of the + // lowers, if at least one of it was invalid. + bCheck = SwCntntFrm::CalcLowers( &rRow, rRow.GetUpper(), nBottom, true ); + // <-- + + // NEW TABLES + // First we calculate the cells with row span of < 1, afterwards + // all cells with row span of > 1: + for ( int i = 0; i < 2; ++i ) + { + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(rRow.Lower()); + while ( pCellFrm ) + { + const bool bCalc = 0 == i ? + pCellFrm->GetLayoutRowSpan() < 1 : + pCellFrm->GetLayoutRowSpan() > 1; + + if ( bCalc ) + { + SwCellFrm& rToRecalc = 0 == i ? + const_cast<SwCellFrm&>(pCellFrm->FindStartEndOfRowSpanCell( true, true )) : + *pCellFrm; + bCheck |= SwCntntFrm::CalcLowers( &rToRecalc, &rToRecalc, nBottom, false ); + } + + pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); + } + } + + if ( bCheck ) + { + if ( ++nLoopControlRuns_1 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" ); + OSL_ENSURE( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" ); + OSL_ENSURE( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" ); +#endif + rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ ); + nLoopControlRuns_1 = 0; + if( nLoopControlStage_1 > 2 ) + break; + } + + continue; + } + } + break; + } while( true ); + + // --> OD 2004-10-05 #i26945# + if ( pPageFrm ) + pPageFrm->SetLayoutInProgress( false ); + // <-- +} + +void MA_FASTCALL lcl_RecalcTable( SwTabFrm& rTab, + SwLayoutFrm *pFirstRow, + SwLayNotify &rNotify ) +{ + if ( rTab.Lower() ) + { + if ( !pFirstRow ) + { + pFirstRow = (SwLayoutFrm*)rTab.Lower(); + rNotify.SetLowersComplete( sal_True ); + } + ::SwInvalidatePositions( pFirstRow, LONG_MAX ); + lcl_RecalcRow( static_cast<SwRowFrm&>(*pFirstRow), LONG_MAX ); + } +} + +// This is a new function to check the first condition whether +// a tab frame may move backward. It replaces the formerly used +// GetIndPrev(), which did not work correctly for #i5947# +bool lcl_NoPrev( const SwFrm& rFrm ) +{ + // --> OD 2007-09-04 #i79774#, #b6596954# + // skip empty sections on investigation of direct previous frame. + // use information, that at least one empty section is skipped in the following code. + bool bSkippedDirectPrevEmptySection( false ); + if ( rFrm.GetPrev() ) + { + const SwFrm* pPrev( rFrm.GetPrev() ); + while ( pPrev && + pPrev->IsSctFrm() && + !dynamic_cast<const SwSectionFrm*>(pPrev)->GetSection() ) + { + pPrev = pPrev->GetPrev(); + bSkippedDirectPrevEmptySection = true; + } + if ( pPrev ) + { + return false; + } + } + + if ( ( !bSkippedDirectPrevEmptySection && !rFrm.GetIndPrev() ) || + ( bSkippedDirectPrevEmptySection && + ( !rFrm.IsInSct() || !rFrm._GetIndPrev() ) ) ) + { + return true; + } + // <-- + + // I do not have a direct prev, but I have an indirect prev. + // In section frames I have to check if I'm located inside + // the first column: + if ( rFrm.IsInSct() ) + { + const SwFrm* pSct = rFrm.GetUpper(); + if ( pSct && pSct->IsColBodyFrm() && + (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() ) + { + const SwFrm* pPrevCol = rFrm.GetUpper()->GetUpper()->GetPrev(); + if ( pPrevCol ) + // I'm not inside the first column and do not have a direct + // prev. I can try to go backward. + return true; + } + } + + return false; +} + +#define KEEPTAB ( !GetFollow() && !IsFollow() ) + +// --> OD 2005-09-28 #b6329202# - helper method to find next content frame of +// a table frame and format it to assure keep attribute. +// method return true, if a next content frame is formatted. +// Precondition: The given table frame hasn't a follow and isn't a follow. +SwFrm* lcl_FormatNextCntntForKeep( SwTabFrm* pTabFrm ) +{ + // find next content, table or section + SwFrm* pNxt = pTabFrm->FindNext(); + + // skip empty sections + while ( pNxt && pNxt->IsSctFrm() && + !static_cast<SwSectionFrm*>(pNxt)->GetSection() ) + { + pNxt = pNxt->FindNext(); + } + + // if found next frame is a section, get its first content. + if ( pNxt && pNxt->IsSctFrm() ) + { + pNxt = static_cast<SwSectionFrm*>(pNxt)->ContainsAny(); + } + + // format found next frame. + // if table frame is inside another table, method <SwFrm::MakeAll()> is + // called to avoid that the superior table frame is formatted. + if ( pNxt ) + { + if ( pTabFrm->GetUpper()->IsInTab() ) + pNxt->MakeAll(); + else + pNxt->Calc(); + } + + return pNxt; +} + +void SwTabFrm::MakeAll() +{ + if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) + return; + + if ( HasFollow() ) + { + SwTabFrm* pFollowFrm = (SwTabFrm*)GetFollow(); + OSL_ENSURE( !pFollowFrm->IsJoinLocked() || !pFollowFrm->IsRebuildLastLine(), + "SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" ); + if ( pFollowFrm->IsJoinLocked() && pFollowFrm->IsRebuildLastLine() ) + return; + } + + PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) + + LockJoin(); //Ich lass mich nicht unterwegs vernichten. + SwLayNotify aNotify( this ); //uebernimmt im DTor die Benachrichtigung + // If pos is invalid, we have to call a SetInvaKeep at aNotify. + // Otherwise the keep atribute would not work in front of a table. + const sal_Bool bOldValidPos = GetValidPosFlag(); + + //Wenn mein direkter Nachbar gleichzeitig mein Follow ist + //verleibe ich mir das Teil ein. + // OD 09.04.2003 #108698# - join all follows, which are placed on the + // same page/column. + // OD 29.04.2003 #109213# - join follow, only if join for the follow + // is not locked. Otherwise, join will not be performed and this loop + // will be endless. + while ( GetNext() && GetNext() == GetFollow() && + !GetFollow()->IsJoinLocked() + ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + + // The bRemoveFollowFlowLinePending is set if the split attribute of the + // last line is set: + if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() ) + { + if ( RemoveFollowFlowLine() ) + Join(); + SetRemoveFollowFlowLinePending( sal_False ); + } + + if ( bResizeHTMLTable ) //Optimiertes Zusammenspiel mit Grow/Shrink des Inhaltes + { + bResizeHTMLTable = sal_False; + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if ( pLayout ) + bCalcLowers = pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + } + + + sal_Bool bMakePage = sal_True; //solange sal_True kann eine neue Seite + //angelegt werden (genau einmal) + sal_Bool bMovedBwd = sal_False; //Wird sal_True wenn der Frame zurueckfliesst + sal_Bool bMovedFwd = sal_False; //solange sal_False kann der Frm zurueck- + //fliessen (solange, bis er einmal + //vorwaerts ge'moved wurde). + sal_Bool bSplit = sal_False; //Wird sal_True wenn der Frm gesplittet wurde. + const sal_Bool bFtnsInDoc = 0 != GetFmt()->GetDoc()->GetFtnIdxs().Count(); + sal_Bool bMoveable; + const sal_Bool bFly = IsInFly(); + + SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs *pAttrs = pAccess->Get(); + + // The beloved keep attribute + const bool bKeep = IsKeep( pAttrs->GetAttrSet() ); + + // All rows should keep together + // OD 2004-05-25 #i21478# - don't split table, if it has to keep with next + const bool bDontSplit = !IsFollow() && + ( !GetFmt()->GetLayoutSplit().GetValue() || bKeep ); + + // The number of repeated headlines + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + + // This flag indicates that we are allowed to try to split the + // table rows. + bool bTryToSplit = true; + + // --> FME 2006-02-16 #131283# + // Indicates that two individual rows may keep together, based on the keep + // attribute set at the first paragraph in the first cell. + const bool bTableRowKeep = !bDontSplit && GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP); + + // The Magic Move: Used for the table row keep feature. + // If only the last row of the table wants to keep (implicitely by setting + // keep for the first paragraph in the first cell), and this table does + // not have a next, the last line will be cut. Loop prevention: Only + // one try. + bool bLastRowHasToMoveToFollow = false; + bool bLastRowMoveNoMoreTries = false; + + // Join follow table, if this table is not allowed to split: + if ( bDontSplit ) + { + while ( GetFollow() && !GetFollow()->IsJoinLocked() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + // Join follow table, if this does not have enough (repeated) lines: + if ( nRepeat ) + { + if( GetFollow() && !GetFollow()->IsJoinLocked() && + 0 == GetFirstNonHeadlineRow() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + // Join follow table, if last row of this table should keep: + if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() ) + { + const SwRowFrm* pTmpRow = static_cast<const SwRowFrm*>(GetLastLower()); + if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + //Einen Frischling moven wir gleich schon einmal vorwaerts... + if ( !Frm().Top() && IsFollow() ) + { + SwFrm *pPre = GetPrev(); + if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) + { + if ( !MoveFwd( bMakePage, sal_False ) ) + bMakePage = sal_False; + bMovedFwd = sal_True; + } + } + + int nUnSplitted = 5; // Just another loop control :-( + SWRECTFN( this ) + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + if ( sal_True == (bMoveable = IsMoveable()) ) + if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) ) + { + bMovedFwd = sal_True; + bCalcLowers = sal_True; + // --> OD 2009-08-12 #i99267# + // reset <bSplit> after forward move to assure that follows + // can be joined, if further space is available. + bSplit = sal_False; + // <-- + } + + Point aOldPos( (Frm().*fnRect->fnGetPos)() ); + MakePos(); + + if ( aOldPos != (Frm().*fnRect->fnGetPos)() ) + { + if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() ) + { + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if( pLayout ) + { + delete pAccess; + bCalcLowers |= pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + + bValidPrtArea = sal_False; + aNotify.SetLowersComplete( sal_False ); + } + SwFrm *pPre; + if ( bKeep || (0 != (pPre = FindPrev()) && + pPre->GetAttrSet()->GetKeep().GetValue()) ) + { + bCalcLowers = sal_True; + // --> OD 2009-03-06 #i99267# + // reset <bSplit> after forward move to assure that follows + // can be joined, if further space is available. + bSplit = sal_False; + // <-- + } + } + + //Wir muessen die Hoehe der ersten Zeile kennen, denn nur wenn diese + //kleiner wird muss ggf. der Master angestossen werden um noetigenfalls + //die Zeile aufzunehmen. + long n1StLineHeight = 0; + if ( IsFollow() ) + { + SwFrm* pFrm = GetFirstNonHeadlineRow(); + if ( pFrm ) + n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)(); + } + + if ( !bValidSize || !bValidPrtArea ) + { + const long nOldPrtWidth = (Prt().*fnRect->fnGetWidth)(); + const long nOldFrmWidth = (Frm().*fnRect->fnGetWidth)(); + const Point aOldPrtPos = (Prt().*fnRect->fnGetPos)(); + Format( pAttrs ); + + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if ( pLayout && + ((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth || + (Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) ) + { + delete pAccess; + bCalcLowers |= pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + if ( aOldPrtPos != (Prt().*fnRect->fnGetPos)() ) + aNotify.SetLowersComplete( sal_False ); + } + + //Wenn ich der erste einer Kette bin koennte ich mal sehen ob + //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll). + //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts + //geflosssen sein. + if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) ) + { + //Bei Follows muss der Master benachrichtigt + //werden. Der Follow muss nur dann Moven, wenn er leere Blaetter + //ueberspringen muss. + if ( IsFollow() ) + { + //Nur wenn die Hoehe der ersten Zeile kleiner geworder ist. + SwFrm *pFrm = GetFirstNonHeadlineRow(); + if( pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight )() ) + { + SwTabFrm *pMaster = (SwTabFrm*)FindMaster(); + sal_Bool bDummy; + if ( ShouldBwdMoved( pMaster->GetUpper(), sal_False, bDummy ) ) + pMaster->InvalidatePos(); + } + } + SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( sal_True ) : 0; + sal_Bool bReformat; + if ( MoveBwd( bReformat ) ) + { + SWREFRESHFN( this ) + bMovedBwd = sal_True; + aNotify.SetLowersComplete( sal_False ); + if ( bFtnsInDoc ) + MoveLowerFtns( 0, pOldBoss, 0, sal_True ); + if ( bReformat || bKeep ) + { + long nOldTop = (Frm().*fnRect->fnGetTop)(); + MakePos(); + if( nOldTop != (Frm().*fnRect->fnGetTop)() ) + { + SwHTMLTableLayout *pHTMLLayout = + GetTable()->GetHTMLTableLayout(); + if( pHTMLLayout ) + { + delete pAccess; + bCalcLowers |= pHTMLLayout->Resize( + pHTMLLayout->GetBrowseWidthByTabFrm( *this ), + sal_False ); + + pAccess= new SwBorderAttrAccess( + SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + + bValidPrtArea = sal_False; + Format( pAttrs ); + } + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + if ( bKeep && KEEPTAB ) + { + // --> OD 2005-09-28 #b6329202# + // Consider case that table is inside another table, + // because it has to be avoided, that superior table + // is formatted. + // Thus, find next content, table or section + // and, if a section is found, get its first + // content. + if ( 0 != lcl_FormatNextCntntForKeep( this ) && !GetNext() ) + { + bValidPos = sal_False; + } + // <-- + } + } + } + } + + //Wieder ein Wert ungueltig? - dann nochmal das ganze... + if ( !bValidPos || !bValidSize || !bValidPrtArea ) + continue; + + // check, if calculation of table frame is ready. + + /// OD 23.10.2002 #103517# - Local variable <nDistanceToUpperPrtBottom> + /// Introduce local variable and init it with the distance from the + /// table frame bottom to the bottom of the upper printing area. + /// Note: negative values denotes the situation that table frame doesn't + /// fit in its upper. + + SwTwips nDistanceToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + + /// OD 23.10.2002 #103517# - In online layout try to grow upper of table + /// frame, if table frame doesn't fit in its upper. + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode ) + { + if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) ) + { + // upper is grown --> recalculate <nDistanceToUpperPrtBottom> + nDistanceToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + } + } + + // If there is still some space left in the upper, we check if we + // can join some rows of the follow. + // Setting bLastRowHasToMoveToFollow to true means we want to force + // the table to be split! Only skip this if condition once. + if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow ) + { + // OD 23.10.2002 - translate german commentary + // If there is space left in the upper printing area, join as for trial + // at least one further row of an existing follow. + if ( !bSplit && GetFollow() ) + { + sal_Bool bDummy; + if ( GetFollow()->ShouldBwdMoved( GetUpper(), sal_False, bDummy ) ) + { + SwFrm *pTmp = GetUpper(); + SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)(); + if ( bBrowseMode ) + nDeadLine += pTmp->Grow( LONG_MAX, sal_True ); + if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 ) + { + // + // First, we remove an existing follow flow line. + // + if ( HasFollowFlowLine() ) + { + SwFrm* pLastLine = const_cast<SwFrm*>(GetLastLower()); + RemoveFollowFlowLine(); + // invalidate and rebuild last row + if ( pLastLine ) + { + ::SwInvalidateAll( pLastLine, LONG_MAX ); + SetRebuildLastLine( sal_True ); + lcl_RecalcRow( static_cast<SwRowFrm&>(*pLastLine), LONG_MAX ); + SetRebuildLastLine( sal_False ); + } + + SwFrm* pRow = GetFollow()->GetFirstNonHeadlineRow(); + + if ( !pRow || !pRow->GetNext() ) + //Der Follow wird leer und damit ueberfluessig. + Join(); + + continue; + } + + // + // If there is no follow flow line, we move the first + // row in the follow table to the master table. + // + SwRowFrm *pRow = GetFollow()->GetFirstNonHeadlineRow(); + + //Der Follow wird leer und damit ueberfluessig. + if ( !pRow ) + { + Join(); + continue; + } + + const SwTwips nOld = (Frm().*fnRect->fnGetHeight)(); + long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow ); + SwFrm* pRowToMove = pRow; + + while ( pRowToMove && nRowsToMove-- > 0 ) + { + const sal_Bool bMoveFtns = bFtnsInDoc && !GetFollow()->IsJoinLocked(); + + SwFtnBossFrm *pOldBoss = 0; + if ( bMoveFtns ) + pOldBoss = pRowToMove->FindFtnBossFrm( sal_True ); + + SwFrm* pNextRow = pRowToMove->GetNext(); + + if ( !pNextRow ) + //Der Follow wird leer und damit ueberfluessig. + Join(); + else + { + pRowToMove->Cut(); + pRowToMove->Paste( this ); + } + + //Die Fussnoten verschieben! + if ( bMoveFtns ) + if ( ((SwLayoutFrm*)pRowToMove)->MoveLowerFtns( + 0, pOldBoss, FindFtnBossFrm( sal_True ), sal_True ) ) + GetUpper()->Calc(); + + pRowToMove = pNextRow; + } + + if ( nOld != (Frm().*fnRect->fnGetHeight)() ) + lcl_RecalcTable( *this, (SwLayoutFrm*)pRow, aNotify ); + + continue; + } + } + } + else if ( KEEPTAB ) + { + bool bFormat = false; + if ( bKeep ) + bFormat = true; + else if ( bTableRowKeep && !bLastRowMoveNoMoreTries ) + { + // We only want to give the last row one chance to move + // to the follow table. Set the flag as early as possible: + bLastRowMoveNoMoreTries = true; + + // The last line of the table has to be cut off if: + // 1. The table does not want to keep with its next + // 2. The compatibility option is set and the table is allowed to split + // 3. We did not already cut off the last row + // 4. There is not break after attribute set at the table + // 5. There is no break before attribute set behind the table + // 6. There is no section change behind the table (see IsKeep) + // 7. The last table row wants to keep with its next. + const SwRowFrm* pLastRow = static_cast<const SwRowFrm*>(GetLastLower()); + if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) && + pLastRow->ShouldRowKeepWithNext() ) + bFormat = true; + } + + if ( bFormat ) + { + delete pAccess; + + // --> OD 2005-09-28 #b6329202# + // Consider case that table is inside another table, because + // it has to be avoided, that superior table is formatted. + // Thus, find next content, table or section and, if a section + // is found, get its first content. + const SwFrm* pTmpNxt = lcl_FormatNextCntntForKeep( this ); + // <-- + + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + + // The last row wants to keep with the frame behind the table. + // Check if the next frame is on a different page and valid. + // In this case we do a magic trick: + if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->IsValid() ) + { + bValidPos = sal_False; + bLastRowHasToMoveToFollow = true; + } + } + } + + if ( IsValid() ) + { + if ( bCalcLowers ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } + else if ( bONECalcLowers ) + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bONECalcLowers = sal_False; + } + } + continue; + } + + //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt + //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen + + //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe + //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man + //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und + //zwar mit aller Kraft. + if ( !bMoveable ) + { + if ( bCalcLowers && IsValid() ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } + else if ( bONECalcLowers ) + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bONECalcLowers = sal_False; + } + + // It does not make sense to cut off the last line if we are + // not moveable: + bLastRowHasToMoveToFollow = false; + + continue; + } + + if ( bCalcLowers && IsValid() ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + if( !IsValid() ) + continue; + } + + // + // First try to split the table. Condition: + // 1. We have at least one non headline row + // 2. If this row wants to keep, we need an additional row + // 3. The table is allowed to split or we do not have an pIndPrev: + // + SwFrm* pIndPrev = GetIndPrev(); + const SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); + + if ( pFirstNonHeadlineRow && nUnSplitted > 0 && + ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() || !pFirstNonHeadlineRow->ShouldRowKeepWithNext() ) && + ( !bDontSplit || !pIndPrev ) ) + { + // --> FME 2004-06-03 #i29438# + // Special DoNotSplit case: + // We better avoid splitting of a row frame if we are inside a columned + // section which has a height of 0, because this is not growable and thus + // all kinds of unexpected things could happen. + if ( IsInSct() && + (FindSctFrm())->Lower()->IsColumnFrm() && + 0 == (GetUpper()->Frm().*fnRect->fnGetHeight)() ) + { + bTryToSplit = false; + } + // <-- + + // 1. Try: bTryToSplit = true => Try to split the row. + // 2. Try: bTryToSplit = false => Split the table between the rows. + if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit ) + { + SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE) + nDeadLine = (*fnRect->fnYInc)( nDeadLine, + GetUpper()->Grow( LONG_MAX, sal_True ) ); + + ::lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), nDeadLine ); + bLowersFormatted = sal_True; + aNotify.SetLowersComplete( sal_True ); + + // One more check if its really necessary to split the table. + // 1. The table either has to exceed the deadline or + // 2. We explicitly want to cut off the last row. + if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 && !bLastRowHasToMoveToFollow ) + { + continue; + } + + // Set to false again as early as possible. + bLastRowHasToMoveToFollow = false; + + // --> FME 2005-08-03 #i52781# + // YaSC - Yet another special case: + // If our upper is inside a table cell which is not allowed + // to split, we do not try to split: + if ( GetUpper()->IsInTab() ) + { + const SwFrm* pTmpRow = GetUpper(); + while ( pTmpRow && !pTmpRow->IsRowFrm() ) + pTmpRow = pTmpRow->GetUpper(); + if ( pTmpRow && !static_cast<const SwRowFrm*>(pTmpRow)->IsRowSplitAllowed() ) + continue; + } + // <-- + + sal_uInt16 nMinNumOfLines = nRepeat; + + if ( bTableRowKeep ) + { + const SwRowFrm* pTmpRow = pFirstNonHeadlineRow; + while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) + { + ++nMinNumOfLines; + pTmpRow = static_cast<const SwRowFrm*>(pTmpRow->GetNext()); + } + // Check if all lines want to keep together and we + // have a pIndPrev. In this case we set nDeadLine + // to 0, forcing the table to move forward. + if ( !pTmpRow && pIndPrev ) + nDeadLine = 0; + } + + if ( !bTryToSplit ) + ++nMinNumOfLines; + + const SwTwips nBreakLine = (*fnRect->fnYInc)( + (Frm().*fnRect->fnGetTop)(), + (this->*fnRect->fnGetTopMargin)() + + lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) ); + + // Some more checks if we want to call the split algorithm or not: + // The repeating lines / keeping lines still fit into the upper or + // if we do not have an (in)direkt Prev, we split anyway. + if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev ) + { + aNotify.SetLowersComplete( sal_False ); + bSplit = sal_True; + + // + // An existing follow flow line has to be removed. + // + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + + const bool bSplitError = !Split( nDeadLine, bTryToSplit, bTableRowKeep ); + if( !bTryToSplit && !bSplitError && nUnSplitted > 0 ) + --nUnSplitted; + + // --> FME 2004-06-09 #i29771# Two tries to split the table: + // If an error occurred during splitting. We start a second + // try, this time without splitting of table rows. + if ( bSplitError ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + } + + // --> FME 2005-02-10 #119477# + // If splitting the table was successfull or not, + // we do not want to have 'empty' follow tables. + if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() ) + Join(); + // <-- + + + // We want to restore the situation before the failed + // split operation as good as possible. Therefore we + // do some more calculations. Note: Restricting this + // to nDeadLine may not be enough. + if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426 + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bValidPos = sal_False; + bTryToSplit = false; + continue; + } + // <-- + + bTryToSplit = !bSplitError; + + //Damit es nicht zu Oszillationen kommt, muss der + //Follow gleich gueltig gemacht werden. + if ( GetFollow() ) + { + // --> OD 2007-11-30 #i80924# + // After a successful split assure that the first row + // is invalid. When graphics are present, this isn't hold. + // Note: defect i80924 could also be fixed, if it is + // assured, that <SwLayNotify::bLowersComplete> is only + // set, if all lower are valid *and* are correct laid out. + if ( !bSplitError && GetFollow()->GetLower() ) + { + GetFollow()->GetLower()->InvalidatePos(); + } + // <-- + SWRECTFNX( GetFollow() ) + + static sal_uInt8 nStack = 0; + if ( !StackHack::IsLocked() && nStack < 4 ) + { + ++nStack; + StackHack aHack; + delete pAccess; + + GetFollow()->MakeAll(); + + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + + ((SwTabFrm*)GetFollow())->SetLowersFormatted(sal_False); + // --> OD 2005-03-30 #i43913# - lock follow table + // to avoid its formatting during the format of + // its content. + const bool bOldJoinLock = GetFollow()->IsJoinLocked(); + GetFollow()->LockJoin(); + // <-- + ::lcl_RecalcRow( static_cast<SwRowFrm&>(*GetFollow()->Lower()), + (GetFollow()->GetUpper()->Frm().*fnRectX->fnGetBottom)() ); + // --> OD 2005-03-30 #i43913# + // --> FME 2006-04-05 #i63632# Do not unlock the + // follow if it wasn't locked before. + if ( !bOldJoinLock ) + GetFollow()->UnlockJoin(); + // <-- + + if ( !GetFollow()->GetFollow() ) + { + SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext(); + if ( pNxt ) + { + // OD 26.08.2003 #i18103# - no formatting + // of found next frame, if its a follow + // section of the 'ColLocked' section, + // the follow table is in. + bool bCalcNxt = true; + if ( GetFollow()->IsInSct() && pNxt->IsSctFrm() ) + { + SwSectionFrm* pSct = GetFollow()->FindSctFrm(); + if ( pSct->IsColLocked() && + pSct->GetFollow() == pNxt ) + { + bCalcNxt = false; + } + } + if ( bCalcNxt ) + { + pNxt->Calc(); + } + } + } + --nStack; + } + else if ( GetFollow() == GetNext() ) + ((SwTabFrm*)GetFollow())->MoveFwd( sal_True, sal_False ); + } + continue; + } + } + } + + // Set to false again as early as possible. + bLastRowHasToMoveToFollow = false; + + if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() && + GetUpper()->GetUpper()->GetUpper()->IsSctFrm() && + ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) && + ((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) ) + bMovedFwd = sal_False; + + // --> FME 2004-06-09 #i29771# Reset bTryToSplit flag on change of upper + const SwFrm* pOldUpper = GetUpper(); + // <-- + + //Mal sehen ob ich irgenwo Platz finde... + if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) ) + bMakePage = sal_False; + + // --> FME 2004-06-09 #i29771# Reset bSplitError flag on change of upper + if ( GetUpper() != pOldUpper ) + { + bTryToSplit = true; + nUnSplitted = 5; + } + // <-- + + SWREFRESHFN( this ) + bMovedFwd = bCalcLowers = sal_True; + aNotify.SetLowersComplete( sal_False ); + if ( IsFollow() ) + { //Um Oszillationen zu vermeiden sollte kein ungueltiger Master + //zurueckbleiben. + SwTabFrm *pTab = FindMaster(); + if ( pTab->GetUpper() ) + pTab->GetUpper()->Calc(); + pTab->Calc(); + pTab->SetLowersFormatted( sal_False ); + } + + //Wenn mein direkter Nachbar jetzt gleichzeitig mein Follow ist + //verleibe ich mir das Teil ein. + if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + if ( GetFollow() ) + Join(); + } + + if ( bMovedBwd && GetUpper() ) + //Beim zurueckfliessen wurde der Upper angeregt sich vollstaendig + //zu Painten, dass koennen wir uns jetzt nach dem hin und her + //fliessen sparen. + GetUpper()->ResetCompletePaint(); + + if ( bCalcLowers && IsValid() ) + { + // --> OD 2005-05-11 #i44910# - format of lower frames unnecessary + // and can cause layout loops, if table doesn't fit and isn't + // allowed to split. + SwTwips nDistToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + if ( nDistToUpperPrtBottom >= 0 || bTryToSplit ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OSL_FAIL( "debug assertion: <SwTabFrm::MakeAll()> - format of table lowers suppressed by fix i44910" ); + } +#endif + // <-- + } + + } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) + + //Wenn mein direkter Vorgaenger jetzt mein Master ist, so kann er mich + //bei der nachstbesten Gelegenheit vernichten. + if ( IsFollow() ) + { + SwFrm *pPre = GetPrev(); + if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) + pPre->InvalidatePos(); + } + + bCalcLowers = bONECalcLowers = sal_False; + delete pAccess; + UnlockJoin(); + if ( bMovedFwd || bMovedBwd || !bOldValidPos ) + aNotify.SetInvaKeep(); +} + +/************************************************************************* +|* +|* SwTabFrm::CalcFlyOffsets() +|* +|* Beschreibung: Berechnet die Offsets, die durch FlyFrames +|* entstehen. +|* +|*************************************************************************/ +sal_Bool SwTabFrm::CalcFlyOffsets( SwTwips& rUpper, + long& rLeftOffset, + long& rRightOffset ) const +{ + sal_Bool bInvalidatePrtArea = sal_False; + const SwPageFrm *pPage = FindPageFrm(); + const SwFlyFrm* pMyFly = FindFlyFrm(); + + // --> #108724# Page header/footer content doesn't have to wrap around + // floating screen objects + + const IDocumentSettingAccess* pIDSA = GetFmt()->getIDocumentSettingAccess(); + const bool bWrapAllowed = pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) || + ( !IsInFtn() && 0 == FindFooterOrHeader() ); + // <-- + + if ( pPage->GetSortedObjs() && bWrapAllowed ) + { + SWRECTFN( this ) + const bool bConsiderWrapOnObjPos = pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION); + long nPrtPos = (Frm().*fnRect->fnGetTop)(); + nPrtPos = (*fnRect->fnYInc)( nPrtPos, rUpper ); + SwRect aRect( Frm() ); + long nYDiff = (*fnRect->fnYDiff)( (Prt().*fnRect->fnGetTop)(), rUpper ); + if( nYDiff > 0 ) + (aRect.*fnRect->fnAddBottom)( -nYDiff ); + for ( sal_uInt16 i = 0; i < pPage->GetSortedObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + const SwRect aFlyRect = pFly->GetObjRectWithSpaces(); + // --> OD 2004-10-07 #i26945# - correction of conditions, + // if Writer fly frame has to be considered: + // - no need to check, if top of Writer fly frame differs + // from WEIT_WECH, because its also check, if the Writer + // fly frame rectangle overlaps with <aRect> + // - no check, if bottom of anchor frame is prior the top of + // the table, because Writer fly frames can be negative positioned. + // - correct check, if the Writer fly frame is an lower of the + // table, because table lines/rows can split and a at-character + // anchored Writer fly frame could be positioned in the follow + // flow line. + // - add condition, that an existing anchor character text frame + // has to be on the same page as the table. + // E.g., it could happen, that the fly frame is still registered + // at the page frame, the table is on, but it's anchor character + // text frame has already changed its page. + const SwTxtFrm* pAnchorCharFrm = pFly->FindAnchorCharFrm(); + bool bConsiderFly = + // --> OD 2005-04-06 #i46807# - do not consider invalid + // Writer fly frames. + pFly->IsValid() && + // <-- + // fly anchored at character + pFly->IsFlyAtCntFrm() && + // fly overlaps with corresponding table rectangle + aFlyRect.IsOver( aRect ) && + // fly isn't lower of table and + // anchor character frame of fly isn't lower of table + ( !IsAnLower( pFly ) && + ( !pAnchorCharFrm || !IsAnLower( pAnchorCharFrm ) ) ) && + // table isn't lower of fly + !pFly->IsAnLower( this ) && + // fly is lower of fly, the table is in + // --> OD 2005-05-31 #123274# - correction: + // assure that fly isn't a lower of a fly, the table isn't in. + // E.g., a table in the body doesn't wrap around a graphic, + // which is inside a frame. + ( ( !pMyFly || + pMyFly->IsAnLower( pFly ) ) && + pMyFly == pFly->GetAnchorFrmContainingAnchPos()->FindFlyFrm() ) && + // <-- + // anchor frame not on following page + pPage->GetPhyPageNum() >= + pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() && + // anchor character text frame on same page + ( !pAnchorCharFrm || + pAnchorCharFrm->FindPageFrm()->GetPhyPageNum() == + pPage->GetPhyPageNum() ); + + if ( bConsiderFly ) + { + const SwFrm* pFlyHeaderFooterFrm = pFly->GetAnchorFrm()->FindFooterOrHeader(); + const SwFrm* pThisHeaderFooterFrm = FindFooterOrHeader(); + + if ( pFlyHeaderFooterFrm != pThisHeaderFooterFrm && + // --> FME 2007-07-02 #148493# If bConsiderWrapOnObjPos is set, + // we want to consider the fly if it is located in the header and + // the table is located in the body: + ( !bConsiderWrapOnObjPos || 0 != pThisHeaderFooterFrm || !pFlyHeaderFooterFrm->IsHeaderFrm() ) ) + bConsiderFly = false; + // <-- + } + + if ( bConsiderFly ) + // <-- + { + const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround(); + const SwFmtHoriOrient &rHori= pFly->GetFmt()->GetHoriOrient(); + if ( SURROUND_NONE == rSur.GetSurround() ) + { + long nBottom = (aFlyRect.*fnRect->fnGetBottom)(); + if( (*fnRect->fnYDiff)( nPrtPos, nBottom ) < 0 ) + nPrtPos = nBottom; + bInvalidatePrtArea = sal_True; + } + if ( (SURROUND_RIGHT == rSur.GetSurround() || + SURROUND_PARALLEL == rSur.GetSurround())&& + text::HoriOrientation::LEFT == rHori.GetHoriOrient() ) + { + const long nWidth = (*fnRect->fnXDiff)( + (aFlyRect.*fnRect->fnGetRight)(), + (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetLeft)() ); + rLeftOffset = Max( rLeftOffset, nWidth ); + bInvalidatePrtArea = sal_True; + } + if ( (SURROUND_LEFT == rSur.GetSurround() || + SURROUND_PARALLEL == rSur.GetSurround())&& + text::HoriOrientation::RIGHT == rHori.GetHoriOrient() ) + { + const long nWidth = (*fnRect->fnXDiff)( + (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetRight)(), + (aFlyRect.*fnRect->fnGetLeft)() ); + rRightOffset = Max( rRightOffset, nWidth ); + bInvalidatePrtArea = sal_True; + } + } + } + } + rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() ); + } + + return bInvalidatePrtArea; +} + +/************************************************************************* +|* +|* SwTabFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea +|* Die Fixsize wird hier nicht eingestellt. +|* +|*************************************************************************/ +void SwTabFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "TabFrm::Format, pAttrs ist 0." ); + + SWRECTFN( this ) + if ( !bValidSize ) + { + long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() - + (Frm().*fnRect->fnGetWidth)(); + if( nDiff ) + (aFrm.*fnRect->fnAddRight)( nDiff ); + } + + //VarSize ist immer die Hoehe. + //Fuer den oberen/unteren Rand gelten die selben Regeln wie fuer + //cntfrms (sie MakePrtArea() von diesen). + + SwTwips nUpper = CalcUpperSpace( pAttrs ); + + //Wir wollen Rahmen ausweichen. Zwei Moeglichkeiten: + //1. Es gibt Rahmen mit SurroundNone, diesen wird vollsaendig ausgewichen + //2. Es gibt Rahmen mit Umlauf nur rechts bzw. nur links und diese sind + // rechts bzw. links ausgerichtet, diese geben ein Minimum fuer die + // Raender vor. + long nTmpRight = -1000000, + nLeftOffset = 0; + if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) ) + bValidPrtArea = sal_False; + long nRightOffset = Max( 0L, nTmpRight ); + + SwTwips nLower = pAttrs->CalcBottomLine(); + // --> collapsing borders FME 2005-05-27 #i29550# + if ( IsCollapsingBorders() ) + nLower += GetBottomLineSize(); + // <-- collapsing + + if ( !bValidPrtArea ) + { bValidPrtArea = sal_True; + + //Die Breite der PrtArea wird vom FrmFmt vorgegeben, die Raender + //sind entsprechend einzustellen. + //Mindestraender werden von Umrandung und Schatten vorgegeben. + //Die Rander werden so eingestellt, dass die PrtArea nach dem + //angegebenen Adjustment im Frm ausgerichtet wird. + //Wenn das Adjustment 0 ist, so werden die Rander anhand des + //Randattributes eingestellt. + + const SwTwips nOldHeight = (Prt().*fnRect->fnGetHeight)(); + const SwTwips nMax = (aFrm.*fnRect->fnGetWidth)(); + + // OD 14.03.2003 #i9040# - adjust variable names. + const SwTwips nLeftLine = pAttrs->CalcLeftLine(); + const SwTwips nRightLine = pAttrs->CalcRightLine(); + + //Die Breite ist evtl. eine Prozentangabe. Wenn die Tabelle irgendwo + //'drinsteckt bezieht sie sich auf die Umgebung. Ist es der Body, so + //bezieht sie sich in der BrowseView auf die Bildschirmbreite. + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + // OD 14.03.2003 #i9040# - adjust variable name. + const SwTwips nWishedTableWidth = CalcRel( rSz, sal_True ); + + sal_Bool bCheckBrowseWidth = sal_False; + + // OD 14.03.2003 #i9040# - insert new variables for left/right spacing. + SwTwips nLeftSpacing = 0; + SwTwips nRightSpacing = 0; + switch ( GetFmt()->GetHoriOrient().GetHoriOrient() ) + { + case text::HoriOrientation::LEFT: + { + // left indent: + nLeftSpacing = nLeftLine + nLeftOffset; + // OD 06.03.2003 #i9040# - correct calculation of right indent: + // - Consider right indent given by right line attributes. + // - Consider negative right indent. + // wished right indent determined by wished table width and + // left offset given by surround fly frames on the left: + const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset; + if ( nRightOffset > 0 ) + { + // surrounding fly frames on the right + // -> right indent is maximun of given right offset + // and wished right offset. + nRightSpacing = nRightLine + Max( nRightOffset, nWishRight ); + } + else + { + // no surrounding fly frames on the right + // If intrinsic right indent (intrinsic means not considering + // determined left indent) is negative, + // then hold this intrinsic indent, + // otherwise non negative wished right indent is hold. + nRightSpacing = nRightLine + + ( ( (nWishRight+nLeftOffset) < 0 ) ? + (nWishRight+nLeftOffset) : + Max( 0L, nWishRight ) ); + } + } + break; + case text::HoriOrientation::RIGHT: + { + // right indent: + nRightSpacing = nRightLine + nRightOffset; + // OD 06.03.2003 #i9040# - correct calculation of left indent: + // - Consider left indent given by left line attributes. + // - Consider negative left indent. + // wished left indent determined by wished table width and + // right offset given by surrounding fyl frames on the right: + const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset; + if ( nLeftOffset > 0 ) + { + // surrounding fly frames on the left + // -> right indent is maximun of given left offset + // and wished left offset. + nLeftSpacing = nLeftLine + Max( nLeftOffset, nWishLeft ); + } + else + { + // no surrounding fly frames on the left + // If intrinsic left indent (intrinsic = not considering + // determined right indent) is negative, + // then hold this intrinsic indent, + // otherwise non negative wished left indent is hold. + nLeftSpacing = nLeftLine + + ( ( (nWishLeft+nRightOffset) < 0 ) ? + (nWishLeft+nRightOffset) : + Max( 0L, nWishLeft ) ); + } + } + break; + case text::HoriOrientation::CENTER: + { + // OD 07.03.2003 #i9040# - consider left/right line attribute. + // OD 10.03.2003 #i9040# - + const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2; + nLeftSpacing = nLeftLine + + ( (nLeftOffset > 0) ? + Max( nCenterSpacing, nLeftOffset ) : + nCenterSpacing ); + nRightSpacing = nRightLine + + ( (nRightOffset > 0) ? + Max( nCenterSpacing, nRightOffset ) : + nCenterSpacing ); + } + break; + case text::HoriOrientation::FULL: + //Das Teil dehnt sich ueber die gesamte Breite aus. + //Nur die fuer die Umrandung benoetigten Freiraeume + //werden beruecksichtigt. + //Die Attributwerte von LRSpace werden bewusst missachtet! + bCheckBrowseWidth = sal_True; + nLeftSpacing = nLeftLine + nLeftOffset; + nRightSpacing = nRightLine + nRightOffset; + break; + case text::HoriOrientation::NONE: + { + //Die Raender werden vom Randattribut bestimmt. + nLeftSpacing = pAttrs->CalcLeft( this ); + if( nLeftOffset ) + { + // OD 07.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of left spacing and left offset. + // OD 10.03.2003 #i9040# - consider left line attribute. + nLeftSpacing = Max( nLeftSpacing, ( nLeftOffset + nLeftLine ) ); + } + // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> + nRightSpacing = pAttrs->CalcRight( this ); + if( nRightOffset ) + { + // OD 07.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of right spacing and right offset. + // OD 10.03.2003 #i9040# - consider right line attribute. + nRightSpacing = Max( nRightSpacing, ( nRightOffset + nRightLine ) ); + } + } + break; + case text::HoriOrientation::LEFT_AND_WIDTH: + { + //Linker Rand und die Breite zaehlen (Word-Spezialitaet) + // OD 10.03.2003 #i9040# - no width alignment in online mode. + //bCheckBrowseWidth = sal_True; + nLeftSpacing = pAttrs->CalcLeft( this ); + if( nLeftOffset ) + { + // OD 10.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of right spacing and right offset. + // OD 10.03.2003 #i9040# - consider left line attribute. + nLeftSpacing = Max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) ); + } + // OD 10.03.2003 #i9040# - consider right and left line attribute. + const SwTwips nWishRight = + nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth; + nRightSpacing = nRightLine + + ( (nRightOffset > 0) ? + Max( nWishRight, nRightOffset ) : + nWishRight ); + } + break; + default: + OSL_FAIL( "Ungueltige orientation fuer Table." ); + } + + // --> OD 2004-07-15 #i26250# - extend bottom printing area, if table + // is last content inside a table cell. + if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) && + GetUpper()->IsInTab() && !GetIndNext() ) + { + nLower += pAttrs->GetULSpace().GetLower(); + } + // <-- + (this->*fnRect->fnSetYMargins)( nUpper, nLower ); + if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) ) + (this->*fnRect->fnSetXMargins)( 0, 0 ); + else + (this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing ); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( bCheckBrowseWidth && + pSh && pSh->GetViewOptions()->getBrowseMode() && + GetUpper()->IsPageBodyFrm() && // nur PageBodyFrms, nicht etwa ColBodyFrms + pSh->VisArea().Width() ) + { + //Nicht ueber die Kante des sichbaren Bereiches hinausragen. + //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite" + //geben kann (RootFrm::ImplCalcBrowseWidth()) + long nWidth = pSh->GetBrowseWidth(); + nWidth -= Prt().Left(); + nWidth -= pAttrs->CalcRightLine(); + Prt().Width( Min( nWidth, Prt().Width() ) ); + } + + if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() ) + bValidSize = sal_False; + } + + if ( !bValidSize ) + { + bValidSize = sal_True; + + //Die Groesse wird durch den Inhalt plus den Raendern bestimmt. + SwTwips nRemaining = 0, nDiff; + SwFrm *pFrm = pLower; + while ( pFrm ) + { + nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + //Jetzt noch die Raender addieren + nRemaining += nUpper + nLower; + + nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining; + if ( nDiff > 0 ) + Shrink( nDiff ); + else if ( nDiff < 0 ) + Grow( -nDiff ); + } +} +/************************************************************************* +|* +|* SwTabFrm::GrowFrm() +|* +|*************************************************************************/ +SwTwips SwTabFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + SwTwips nHeight =(Frm().*fnRect->fnGetHeight)(); + if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) ) + nDist = LONG_MAX - nHeight; + + if ( bTst && !IsRestrictTableGrowth() ) + return nDist; + + if ( GetUpper() ) + { + SwRect aOldFrm( Frm() ); + + //Der Upper wird nur soweit wie notwendig gegrowed. In nReal wird erstmal + //die bereits zur Verfuegung stehende Strecke bereitgestellt. + SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)(); + SwFrm *pFrm = GetUpper()->Lower(); + while ( pFrm && GetFollow() != pFrm ) + { + nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + + if ( nReal < nDist ) + { + long nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo ); + + if ( IsRestrictTableGrowth() ) + { + nTmp = Min( nDist, nReal + nTmp ); + nDist = nTmp < 0 ? 0 : nTmp; + } + } + + if ( !bTst ) + { + (Frm().*fnRect->fnAddBottom)( nDist ); + + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm ); + } + } + } + + if ( !bTst && ( nDist || IsRestrictTableGrowth() ) ) + { + SwPageFrm *pPage = FindPageFrm(); + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + } + // --> OD 2004-07-05 #i28701# - Due to the new object positioning the + // frame on the next page/column can flow backward (e.g. it was moved + // forward due to the positioning of its objects ). Thus, invalivate this + // next frame, if document compatibility option 'Consider wrapping style + // influence on object positioning' is ON. + else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + InvalidateNextPos(); + } + // <-- + _InvalidateAll(); + InvalidatePage( pPage ); + SetComplete(); + + const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos(); + if ( GPOS_NONE != ePos && GPOS_TILED != ePos ) + SetCompletePaint(); + } + + return nDist; +} +/************************************************************************* +|* +|* SwTabFrm::Modify() +|* +|*************************************************************************/ +void SwTabFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + + if( bAttrSetChg ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + if ( nInvFlags & 0x02 ) + _InvalidatePrt(); + if ( nInvFlags & 0x40 ) + _InvalidatePos(); + SwFrm *pTmp; + if ( 0 != (pTmp = GetIndNext()) ) + { + if ( nInvFlags & 0x04 ) + { + pTmp->_InvalidatePrt(); + if ( pTmp->IsCntntFrm() ) + pTmp->InvalidatePage( pPage ); + } + if ( nInvFlags & 0x10 ) + pTmp->SetCompletePaint(); + } + if ( nInvFlags & 0x08 && 0 != (pTmp = GetPrev()) ) + { + pTmp->_InvalidatePrt(); + if ( pTmp->IsCntntFrm() ) + pTmp->InvalidatePage( pPage ); + } + if ( nInvFlags & 0x20 ) + { + if ( pPage && pPage->GetUpper() && !IsFollow() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); + } + if ( nInvFlags & 0x80 ) + InvalidateNextPos(); + } +} + +void SwTabFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { + case RES_TBLHEADLINECHG: + if ( IsFollow() ) + { + // Delete remaining headlines: + SwRowFrm* pLowerRow = 0; + while ( 0 != ( pLowerRow = (SwRowFrm*)Lower() ) && pLowerRow->IsRepeatedHeadline() ) + { + pLowerRow->Cut(); + delete pLowerRow; + } + + // insert new headlines + const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat(); + for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx ) + { + bDontCreateObjects = sal_True; //frmtool + SwRowFrm* pHeadline = new SwRowFrm( *GetTable()->GetTabLines()[ nIdx ], this ); + pHeadline->SetRepeatedHeadline( true ); + bDontCreateObjects = sal_False; + pHeadline->Paste( this, pLowerRow ); + } + } + rInvFlags |= 0x02; + break; + + case RES_FRM_SIZE: + case RES_HORI_ORIENT: + rInvFlags |= 0x22; + break; + + case RES_PAGEDESC: //Attributaenderung (an/aus) + if ( IsInDocBody() ) + { + rInvFlags |= 0x40; + SwPageFrm *pPage = FindPageFrm(); + if ( !GetPrev() ) + CheckPageDescs( pPage ); + if ( pPage && GetFmt()->GetPageDesc().GetNumOffset() ) + ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( sal_True ); + SwDocPosUpdate aMsgHnt( pPage->Frm().Top() ); + GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt ); + } + break; + + case RES_BREAK: + rInvFlags |= 0xC0; + break; + + case RES_LAYOUT_SPLIT: + if ( !IsFollow() ) + rInvFlags |= 0x40; + break; + case RES_FRAMEDIR : + SetDerivedR2L( sal_False ); + CheckDirChange(); + break; + case RES_COLLAPSING_BORDERS : + rInvFlags |= 0x02; + lcl_InvalidateAllLowersPrt( this ); + break; + case RES_UL_SPACE: + rInvFlags |= 0x1C; + /* kein Break hier */ + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrm::Modify( pOld, pNew ); + } +} + +/************************************************************************* +|* +|* SwTabFrm::GetInfo() +|* +|*************************************************************************/ +sal_Bool SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const +{ + if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && !IsFollow() ) + { + SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt; + const SwPageFrm *pPage = FindPageFrm(); + if ( pPage ) + { + if ( pPage == rInfo.GetOrigPage() && !GetPrev() ) + { + //Das sollte er sein (kann allenfalls temporaer anders sein, + // sollte uns das beunruhigen?) + rInfo.SetInfo( pPage, this ); + return sal_False; + } + if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() && + (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum())) + { + //Das koennte er sein. + rInfo.SetInfo( pPage, this ); + } + } + } + return sal_True; +} + +/************************************************************************* +|* +|* SwTabFrm::FindLastCntnt() +|* +|*************************************************************************/ +SwCntntFrm *SwTabFrm::FindLastCntnt() +{ + SwFrm *pRet = pLower; + + while ( pRet && !pRet->IsCntntFrm() ) + { + SwFrm *pOld = pRet; + + SwFrm *pTmp = pRet; // To skip empty section frames + while ( pRet->GetNext() ) + { + pRet = pRet->GetNext(); + if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() ) + pTmp = pRet; + } + pRet = pTmp; + + if ( pRet->GetLower() ) + pRet = pRet->GetLower(); + if ( pRet == pOld ) + { + // Wenn am Ende der letzten Zelle ein spaltiger Bereich steht, + // der eine leere letzte Spalte hat, muessen wir noch die anderen + // Spalten abklappern, dies erledigt SwSectionFrm::FindLastCntnt + if( pRet->IsColBodyFrm() ) + { +#if OSL_DEBUG_LEVEL > 1 + SwSectionFrm* pSect = pRet->FindSctFrm(); + OSL_ENSURE( pSect, "Wo kommt denn die Spalte her?"); + OSL_ENSURE( IsAnLower( pSect ), "Gespaltene Zelle?" ); +#endif + return pRet->FindSctFrm()->FindLastCntnt(); + } + + // + // pRet may be a cell frame without a lower (cell has been split). + // We have to find the last content the hard way: + // + OSL_ENSURE( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" ); + const SwFrm* pRow = pRet->GetUpper(); + while ( pRow && !pRow->GetUpper()->IsTabFrm() ) + pRow = pRow->GetUpper(); + SwCntntFrm* pCntntFrm = ((SwLayoutFrm*)pRow)->ContainsCntnt(); + pRet = 0; + + while ( pCntntFrm && ((SwLayoutFrm*)pRow)->IsAnLower( pCntntFrm ) ) + { + pRet = pCntntFrm; + pCntntFrm = pCntntFrm->GetNextCntntFrm(); + } + } + } + + // #112929# There actually is a situation, which results in pRet = 0: + // Insert frame, insert table via text <-> table. This gives you a frame + // containing a table without any other content frames. Split the table + // and undo the splitting. This operation gives us a table frame without + // a lower. + if ( pRet ) + { + while ( pRet->GetNext() ) + pRet = pRet->GetNext(); + + if( pRet->IsSctFrm() ) + pRet = ((SwSectionFrm*)pRet)->FindLastCntnt(); + } + + return (SwCntntFrm*)pRet; +} + +/************************************************************************* +|* +|* SwTabFrm::GetLeaf() +|* +|*************************************************************************/ +SwLayoutFrm *SwTabFrm::GetLeaf( MakePageType eMakePage, sal_Bool bFwd ) +{ + SwLayoutFrm *pRet; + if ( bFwd ) + { + pRet = GetNextLeaf( eMakePage ); + while ( IsAnLower( pRet ) ) + pRet = pRet->GetNextLeaf( eMakePage ); + } + else + pRet = GetPrevLeaf(); + if ( pRet ) + pRet->Calc(); + return pRet; +} + +/************************************************************************* +|* +|* SwTabFrm::ShouldBwdMoved() +|* +|* Beschreibung Returnwert sagt ob der Frm verschoben werden sollte +|* +|*************************************************************************/ +sal_Bool SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, sal_Bool, sal_Bool &rReformat ) +{ + rReformat = sal_False; + if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()) ) + { + //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv. + //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen + //moechte die FixSize die gleiche ist, die der Frm selbst hat. + //In diesem Fall kann einfach geprueft werden, ob der Frm genug + //Platz fuer seine VarSize findet, ist dies nicht der Fall kann + //gleich auf das Verschieben verzichtet werden. + //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst + //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise + //aufspalten kann. + //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind + //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn + //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt + //etwas Platz zur Verfuegung steht). + + //Die FixSize der Umgebungen in denen Tabellen herumlungern ist immer + //Die Breite. + + SwPageFrm *pOldPage = FindPageFrm(), + *pNewPage = pNewUpper->FindPageFrm(); + sal_Bool bMoveAnyway = sal_False; + SwTwips nSpace = 0; + + SWRECTFN( this ) + if ( !SwFlowFrm::IsMoveBwdJump() ) + { + + long nOldWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + SWRECTFNX( pNewUpper ); + long nNewWidth = (pNewUpper->Prt().*fnRectX->fnGetWidth)(); + if( Abs( nNewWidth - nOldWidth ) < 2 ) + { + if( sal_False == + ( bMoveAnyway = BwdMoveNecessary( pOldPage, Frm() ) > 1 ) ) + { + SwRect aRect( pNewUpper->Prt() ); + aRect.Pos() += pNewUpper->Frm().Pos(); + const SwFrm *pPrevFrm = pNewUpper->Lower(); + while ( pPrevFrm && pPrevFrm != this ) + { + (aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX-> + fnGetBottom)() ); + pPrevFrm = pPrevFrm->GetNext(); + } + bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1; + + // --> FME 2006-01-20 #i54861# Due to changes made in PrepareMake, + // the tabfrm may not have a correct position. Therefore + // it is possible that pNewUpper->Prt().Height == 0. In this + // case the above calculation of nSpace might give wrong + // results and we really do not want to MoveBackwrd into a + // 0 height frame. If nTmpSpace is already <= 0, we take this + // value: + const SwTwips nTmpSpace = (aRect.*fnRectX->fnGetHeight)(); + if ( (pNewUpper->Prt().*fnRectX->fnGetHeight)() > 0 || nTmpSpace <= 0 ) + nSpace = nTmpSpace; + // <-- + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + nSpace += pNewUpper->Grow( LONG_MAX, sal_True ); + } + } + else if( !bLockBackMove ) + bMoveAnyway = sal_True; + } + else if( !bLockBackMove ) + bMoveAnyway = sal_True; + + if ( bMoveAnyway ) + return rReformat = sal_True; + else if ( !bLockBackMove && nSpace > 0 ) + { + // --> OD 2004-10-05 #i26945# - check, if follow flow line + // contains frame, which are moved forward due to its object + // positioning. + SwRowFrm* pFirstRow = GetFirstNonHeadlineRow(); + if ( pFirstRow && pFirstRow->IsInFollowFlowRow() && + SwLayouter::DoesRowContainMovedFwdFrm( + *(pFirstRow->GetFmt()->GetDoc()), + *(pFirstRow) ) ) + { + return sal_False; + } + // <-- + SwTwips nTmpHeight = CalcHeightOfFirstContentLine(); + + // --> FME 2005-01-17 #118840# + // For some mysterious reason, I changed the good old + // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'. + // This obviously results in problems with table frames in + // sections. Remember: Every twip is sacred. + return nTmpHeight <= nSpace; + // <-- + } + } + return sal_False; +} + +/************************************************************************* +|* +|* SwTabFrm::Cut() +|* +|*************************************************************************/ +void SwTabFrm::Cut() +{ + OSL_ENSURE( GetUpper(), "Cut ohne Upper()." ); + + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + SwFrm *pFrm = GetNext(); + if( pFrm ) + { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger + //berechnet der ist jetzt wo er der erste wird obsolete + pFrm->_InvalidatePrt(); + pFrm->_InvalidatePos(); + if ( pFrm->IsCntntFrm() ) + pFrm->InvalidatePage( pPage ); + if( IsInSct() && !GetPrev() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + } + else + { + InvalidateNextPos(); + //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper + if ( 0 != (pFrm = GetPrev()) ) + { pFrm->SetRetouche(); + pFrm->Prepare( PREP_WIDOWS_ORPHANS ); + pFrm->_InvalidatePos(); + if ( pFrm->IsCntntFrm() ) + pFrm->InvalidatePage( pPage ); + } + //Wenn ich der einzige FlowFrm in meinem Upper bin (war), so muss + //er die Retouche uebernehmen. + //Ausserdem kann eine Leerseite entstanden sein. + else + { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); + pRoot->SetSuperfluous(); + GetUpper()->SetCompletePaint(); + if( IsInSct() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + } + } + + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + SWRECTFN( this ) + Remove(); + if ( pUp ) + { + OSL_ENSURE( !pUp->IsFtnFrm(), "Tabelle in Fussnote." ); + SwSectionFrm *pSct = 0; + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + if ( !pUp->Lower() && pUp->IsInSct() && + !(pSct = pUp->FindSctFrm())->ContainsCntnt() && + !pSct->ContainsAny( true ) ) + // <-- + { + if ( pUp->GetUpper() ) + { + pSct->DelEmpty( sal_False ); + pSct->_InvalidateSize(); + } + } + else if( (Frm().*fnRect->fnGetHeight)() ) + { + // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section - + // undo changes of fix for #104992# + pUp->Shrink( Frm().Height() ); + } + } + + if ( pPage && !IsFollow() && pPage->GetUpper() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); +} + +/************************************************************************* +|* +|* SwTabFrm::Paste() +|* +|*************************************************************************/ +void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + _InvalidateAll(); + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + GetNext()->_InvalidatePrt(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + } + + SWRECTFN( this ) + if( (Frm().*fnRect->fnGetHeight)() ) + pParent->Grow( (Frm().*fnRect->fnGetHeight)() ); + + if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() ) + Prepare( PREP_FIXSIZE_CHG ); + if ( GetPrev() ) + { + if ( !IsFollow() ) + { + GetPrev()->InvalidateSize(); + if ( GetPrev()->IsCntntFrm() ) + GetPrev()->InvalidatePage( pPage ); + } + } + else if ( GetNext() ) + //Bei CntntFrm's gilt es den Abstand zum Vorgaenger/Nachfolger + //zu beachten. Faelle (beide treten immer gleichzeitig auf): + //a) Der Cntnt wird der erste einer Kette + //b) Der neue Nachfolger war vorher der erste einer Kette + GetNext()->_InvalidatePrt(); + + if ( pPage && !IsFollow() ) + { + if ( pPage->GetUpper() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); + + if ( !GetPrev() )//Mindestens fuer HTML mit Tabelle am Anfang notwendig. + { + const SwPageDesc *pDesc = GetFmt()->GetPageDesc().GetPageDesc(); + if ( (pDesc && pDesc != pPage->GetPageDesc()) || + (!pDesc && pPage->GetPageDesc() != + &(const_cast<const SwDoc *>(GetFmt()->GetDoc()) + ->GetPageDesc(0))) ) + CheckPageDescs( pPage, sal_True ); + } + } +} + +/************************************************************************* +|* +|* SwTabFrm::Prepare() +|* +|*************************************************************************/ +void SwTabFrm::Prepare( const PrepareHint eHint, const void *, sal_Bool ) +{ + if( PREP_BOSS_CHGD == eHint ) + CheckDirChange(); +} + +/************************************************************************* +|* +|* SwRowFrm::SwRowFrm(), ~SwRowFrm() +|* +|*************************************************************************/ +SwRowFrm::SwRowFrm( const SwTableLine &rLine, SwFrm* pSib, bool bInsertContent ): + SwLayoutFrm( rLine.GetFrmFmt(), pSib ), + pTabLine( &rLine ), + pFollowRow( 0 ), + // --> collapsing borders FME 2005-05-27 #i29550# + mnTopMarginForLowers( 0 ), + mnBottomMarginForLowers( 0 ), + mnBottomLineSize( 0 ), + // <-- collapsing + // --> split table rows + bIsFollowFlowRow( false ), + // <-- split table rows + bIsRepeatedHeadline( false ), + mbIsRowSpanLine( false ) +{ + nType = FRMC_ROW; + + //Gleich die Boxen erzeugen und einfuegen. + const SwTableBoxes &rBoxes = rLine.GetTabBoxes(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + { + SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], this, bInsertContent ); + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } +} + +SwRowFrm::~SwRowFrm() +{ + SwModify* pMod = GetFmt(); + if( pMod ) + { + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen + } +} + +/************************************************************************* +|* +|* SwRowFrm::RegistFlys() +|* +|*************************************************************************/ +void SwRowFrm::RegistFlys( SwPageFrm *pPage ) +{ + ::RegistFlys( pPage ? pPage : FindPageFrm(), this ); +} + +/************************************************************************* +|* +|* SwRowFrm::Modify() +|* +|*************************************************************************/ +void SwRowFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + const SfxPoolItem *pItem = 0; + + if( bAttrSetChg ) + { + const SwAttrSet* pChgSet = ((SwAttrSetChg*)pNew)->GetChgSet(); + pChgSet->GetItemState( RES_FRM_SIZE, sal_False, &pItem); + if ( !pItem ) + pChgSet->GetItemState( RES_ROW_SPLIT, sal_False, &pItem); + } + else if ( RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which() ) + pItem = pNew; + + if ( pItem ) + { + SwTabFrm *pTab = FindTabFrm(); + if ( pTab ) + { + const bool bInFirstNonHeadlineRow = pTab->IsFollow() && + this == pTab->GetFirstNonHeadlineRow(); + // --> FME 2004-10-27 #i35063# + // Invalidation required is pRow is last row + if ( bInFirstNonHeadlineRow || !GetNext() ) + // <-- + { + if ( bInFirstNonHeadlineRow ) + pTab = pTab->FindMaster(); + pTab->InvalidatePos(); + } + } + } + + SwLayoutFrm::Modify( pOld, pNew ); +} + + + +/************************************************************************* +|* +|* SwRowFrm::MakeAll() +|* +|*************************************************************************/ +void SwRowFrm::MakeAll() +{ + if ( !GetNext() ) + bValidSize = sal_False; + SwLayoutFrm::MakeAll(); +} + +/************************************************************************* +|* +|* SwRowFrm::Format() +|* +|*************************************************************************/ +long MA_FASTCALL CalcHeightWidthFlys( const SwFrm *pFrm ) +{ + SWRECTFN( pFrm ) + long nHeight = 0; + const SwFrm* pTmp = pFrm->IsSctFrm() ? + ((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm; + while( pTmp ) + { + // --> OD 2004-10-08 #i26945# - consider follow text frames + const SwSortedObjs* pObjs( 0L ); + bool bIsFollow( false ); + if ( pTmp->IsTxtFrm() && static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) + { + const SwFrm* pMaster; + // --> FME 2005-04-01 #i46450# Master does not necessarily have + // to exist if this function is called from JoinFrm() -> + // Cut() -> Shrink() + const SwTxtFrm* pTmpFrm = static_cast<const SwTxtFrm*>(pTmp); + if ( pTmpFrm->GetPrev() && pTmpFrm->GetPrev()->IsTxtFrm() && + static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() && + static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() != pTmp ) + pMaster = 0; + else + pMaster = pTmpFrm->FindMaster(); + + if ( pMaster ) + { + pObjs = static_cast<const SwTxtFrm*>(pTmp)->FindMaster()->GetDrawObjs(); + bIsFollow = true; + } + } + else + { + pObjs = pTmp->GetDrawObjs(); + } + if ( pObjs ) + // <-- + { + for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + // --> OD 2004-10-08 #i26945# - if <pTmp> is follow, the + // anchor character frame has to be <pTmp>. + if ( bIsFollow && + const_cast<SwAnchoredObject*>(pAnchoredObj)->FindAnchorCharFrm() != pTmp ) + { + continue; + } + // <-- + // --> OD 2004-10-04 #i26945# - consider also drawing objects + { + // OD 30.09.2003 #i18732# - only objects, which follow + // the text flow have to be considered. + const SwFrmFmt& rFrmFmt = pAnchoredObj->GetFrmFmt(); + const bool bConsiderObj = + (rFrmFmt.GetAnchor().GetAnchorId() != FLY_AS_CHAR) && + pAnchoredObj->GetObjRect().Top() != WEIT_WECH && + rFrmFmt.GetFollowTextFlow().GetValue() && + pAnchoredObj->GetPageFrm() == pTmp->FindPageFrm(); + if ( bConsiderObj ) + { + const SwFmtFrmSize &rSz = rFrmFmt.GetFrmSize(); + if( !rSz.GetHeightPercent() ) + { + const SwTwips nDistOfFlyBottomToAnchorTop = + (pAnchoredObj->GetObjRect().*fnRect->fnGetHeight)() + + ( bVert ? + pAnchoredObj->GetCurrRelPos().X() : + pAnchoredObj->GetCurrRelPos().Y() ); + + const SwTwips nFrmDiff = + (*fnRect->fnYDiff)( + (pTmp->Frm().*fnRect->fnGetTop)(), + (pFrm->Frm().*fnRect->fnGetTop)() ); + + nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop + nFrmDiff - + (pFrm->Frm().*fnRect->fnGetHeight)() ); + + // --> FME 2006-01-24 #i56115# The first height calculation + // gives wrong results if pFrm->Prt().Y() > 0. We do + // a second calculation based on the actual rectangles of + // pFrm and pAnchoredObj, and use the maximum of the results. + // I do not want to remove the first calculation because + // if clipping has been applied, using the GetCurrRelPos + // might be the better option to calculate nHeight. + const SwTwips nDistOfFlyBottomToAnchorTop2 = (*fnRect->fnYDiff)( + (pAnchoredObj->GetObjRect().*fnRect->fnGetBottom)(), + (pFrm->Frm().*fnRect->fnGetBottom)() ); + + nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop2 ); + // <-- + } + } + } + // <-- + } + } + if( !pFrm->IsSctFrm() ) + break; + pTmp = pTmp->FindNextCnt(); + if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) ) + break; + } + return nHeight; +} + +SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm& rCell, const SwBorderAttrs& rAttrs ) +{ + const SwTabFrm* pTab = rCell.FindTabFrm(); + SwTwips nTopSpace = 0; + SwTwips nBottomSpace = 0; + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrm() ) + { + nTopSpace = ((SwRowFrm*)rCell.GetUpper())->GetTopMarginForLowers(); + nBottomSpace = ((SwRowFrm*)rCell.GetUpper())->GetBottomMarginForLowers(); + } + // <-- collapsing + else + { + if ( pTab->IsVertical() != rCell.IsVertical() ) + { + nTopSpace = rAttrs.CalcLeft( &rCell ); + nBottomSpace = rAttrs.CalcRight( &rCell ); + } + else + { + nTopSpace = rAttrs.CalcTop(); + nBottomSpace = rAttrs.CalcBottom(); + } + } + + return nTopSpace + nBottomSpace; +} + + +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to +// control, if floating screen objects have to be considered for the minimal +// cell height. +SwTwips MA_FASTCALL lcl_CalcMinCellHeight( const SwLayoutFrm *_pCell, + const sal_Bool _bConsiderObjs, + const SwBorderAttrs *pAttrs = 0 ) +{ + SWRECTFN( _pCell ) + SwTwips nHeight = 0; + const SwFrm* pLow = _pCell->Lower(); + if ( pLow ) + { + long nFlyAdd = 0; + while ( pLow ) + { + // OD 2004-02-18 #106629# - change condition and switch then-body + // and else-body + if ( pLow->IsRowFrm() ) + { + // --> OD 2004-10-04 #i26945# + nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrm*>(pLow), + _bConsiderObjs ); + // <-- + } + else + { + long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)(); + nHeight += nLowHeight; + // --> OD 2004-10-04 #i26945# + if ( _bConsiderObjs ) + { + nFlyAdd = Max( 0L, nFlyAdd - nLowHeight ); + nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) ); + } + // <-- + } + + pLow = pLow->GetNext(); + } + if ( nFlyAdd ) + nHeight += nFlyAdd; + } + //Der Border will natuerlich auch mitspielen, er kann leider nicht + //aus PrtArea und Frm errechnet werden, da diese in beliebiger + //Kombination ungueltig sein koennen. + if ( _pCell->Lower() ) + { + if ( pAttrs ) + nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs ); + else + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), _pCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs ); + } + } + return nHeight; +} + +// OD 2004-02-18 #106629# - correct type of 1st parameter +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to control, +// if floating screen objects have to be considered for the minimal cell height +SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm* _pRow, + const sal_Bool _bConsiderObjs ) +{ + SWRECTFN( _pRow ) + + const SwFmtFrmSize &rSz = _pRow->GetFmt()->GetFrmSize(); + + if ( _pRow->HasFixSize() && !_pRow->IsRowSpanLine() ) + { + OSL_ENSURE( ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size" ); + return rSz.GetHeight(); + } + + SwTwips nHeight = 0; + const SwCellFrm* pLow = static_cast<const SwCellFrm*>(_pRow->Lower()); + while ( pLow ) + { + SwTwips nTmp = 0; + const long nRowSpan = pLow->GetLayoutRowSpan(); + // --> NEW TABLES + // Consider height of + // 1. current cell if RowSpan == 1 + // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1 + // 3. master cell if RowSpan == -1 + if ( 1 == nRowSpan ) + { + nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs ); + } + else if ( -1 == nRowSpan ) + { + // Height of the last cell of a row span is height of master cell + // minus the height of the other rows which are covered by the master + // cell: + const SwCellFrm& rMaster = pLow->FindStartEndOfRowSpanCell( true, true ); + nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs ); + const SwFrm* pMasterRow = rMaster.GetUpper(); + while ( pMasterRow && pMasterRow != _pRow ) + { + nTmp -= (pMasterRow->Frm().*fnRect->fnGetHeight)(); + pMasterRow = pMasterRow->GetNext(); + } + } + // <-- NEW TABLES + + // Do not consider rotated cells: + if ( ( 0 != pLow->IsVertical() ) == ( 0 != bVert ) && nTmp > nHeight ) + nHeight = nTmp; + + pLow = static_cast<const SwCellFrm*>(pLow->GetNext()); + } + if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE && !_pRow->IsRowSpanLine() ) + nHeight = Max( nHeight, rSz.GetHeight() ); + return nHeight; +} + +// --> collapsing borders FME 2005-05-27 #i29550# + +// Calculate the maximum of (TopLineSize + TopLineDist) over all lowers: +sal_uInt16 lcl_GetTopSpace( const SwRowFrm& rRow ) +{ + sal_uInt16 nTopSpace = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpTopSpace = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + nTmpTopSpace = lcl_GetTopSpace( *(SwRowFrm*)pCurrLower->Lower() ); + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpTopSpace = rBoxItem.CalcLineSpace( BOX_LINE_TOP, sal_True ); + } + nTopSpace = Max( nTopSpace, nTmpTopSpace ); + } + return nTopSpace; +} + +// Calculate the maximum of TopLineDist over all lowers: +sal_uInt16 lcl_GetTopLineDist( const SwRowFrm& rRow ) +{ + sal_uInt16 nTopLineDist = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpTopLineDist = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + nTmpTopLineDist = lcl_GetTopLineDist( *(SwRowFrm*)pCurrLower->Lower() ); + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpTopLineDist = rBoxItem.GetDistance( BOX_LINE_TOP ); + } + nTopLineDist = Max( nTopLineDist, nTmpTopLineDist ); + } + return nTopLineDist; +} + +// Calculate the maximum of BottomLineSize over all lowers: +sal_uInt16 lcl_GetBottomLineSize( const SwRowFrm& rRow ) +{ + sal_uInt16 nBottomLineSize = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpBottomLineSize = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + { + const SwFrm* pRow = pCurrLower->GetLastLower(); + nTmpBottomLineSize = lcl_GetBottomLineSize( *(SwRowFrm*)pRow ); + } + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpBottomLineSize = rBoxItem.CalcLineSpace( BOX_LINE_BOTTOM, sal_True ) - + rBoxItem.GetDistance( BOX_LINE_BOTTOM ); + } + nBottomLineSize = Max( nBottomLineSize, nTmpBottomLineSize ); + } + return nBottomLineSize; +} + +// Calculate the maximum of BottomLineDist over all lowers: +sal_uInt16 lcl_GetBottomLineDist( const SwRowFrm& rRow ) +{ + sal_uInt16 nBottomLineDist = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpBottomLineDist = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + { + const SwFrm* pRow = pCurrLower->GetLastLower(); + nTmpBottomLineDist = lcl_GetBottomLineDist( *(SwRowFrm*)pRow ); + } + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpBottomLineDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM ); + } + nBottomLineDist = Max( nBottomLineDist, nTmpBottomLineDist ); + } + return nBottomLineDist; +} + +// <-- collapsing + +void SwRowFrm::Format( const SwBorderAttrs *pAttrs ) +{ + SWRECTFN( this ) + OSL_ENSURE( pAttrs, "SwRowFrm::Format ohne Attrs." ); + + const sal_Bool bFix = bFixSize; + + if ( !bValidPrtArea ) + { + //RowFrms haben keine Umrandung usw. also entspricht die PrtArea immer + //dem Frm. + bValidPrtArea = sal_True; + aPrt.Left( 0 ); + aPrt.Top( 0 ); + aPrt.Width ( aFrm.Width() ); + aPrt.Height( aFrm.Height() ); + + // --> collapsing borders FME 2005-05-27 #i29550# + // Here we calculate the top-printing area for the lower cell frames + SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->IsCollapsingBorders() ) + { + const sal_uInt16 nTopSpace = lcl_GetTopSpace( *this ); + const sal_uInt16 nTopLineDist = lcl_GetTopLineDist( *this ); + const sal_uInt16 nBottomLineSize = lcl_GetBottomLineSize( *this ); + const sal_uInt16 nBottomLineDist = lcl_GetBottomLineDist( *this ); + + + const SwRowFrm* pPreviousRow = 0; + + // --> FME 2004-09-14 #i32456# + // In order to calculate the top printing area for the lower cell + // frames, we have to find the 'previous' row frame and compare + // the bottom values of the 'previous' row with the 'top' values + // of this row. The best way to find the 'previous' row is to + // use the table structure: + const SwTable* pTable = pTabFrm->GetTable(); + const SwTableLine* pPrevTabLine = 0; + const SwRowFrm* pTmpRow = this; + + while ( pTmpRow && !pPrevTabLine ) + { + sal_uInt16 nIdx = 0; + const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ? + pTmpRow->GetTabLine()->GetUpper()->GetTabLines() : + pTable->GetTabLines(); + + while ( rLines[ nIdx ] != pTmpRow->GetTabLine() ) + ++nIdx; + + if ( nIdx > 0 ) + { + // pTmpRow has a 'previous' row in the table structure: + pPrevTabLine = rLines[ nIdx - 1 ]; + } + else + { + // pTmpRow is a first row in the table structue. + // We go up in the table structure: + pTmpRow = pTmpRow->GetUpper()->GetUpper() && + pTmpRow->GetUpper()->GetUpper()->IsRowFrm() ? + static_cast<const SwRowFrm*>( pTmpRow->GetUpper()->GetUpper() ) : + 0; + } + } + + // If we found a 'previous' row, we look for the appropriate row frame: + if ( pPrevTabLine ) + { + SwIterator<SwRowFrm,SwFmt> aIter( *pPrevTabLine->GetFrmFmt() ); + for ( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() ) + { + // --> OD 2004-11-23 #115759# - do *not* take repeated + // headlines, because during split of table it can be + // invalid and thus can't provide correct border values. + if ( pRow->GetTabLine() == pPrevTabLine && + !pRow->IsRepeatedHeadline() ) + // <-- + { + pPreviousRow = pRow; + break; + } + } + } + // <-- + + sal_uInt16 nTopPrtMargin = nTopSpace; + if ( pPreviousRow ) + { + const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist; + if ( nTmpPrtMargin > nTopPrtMargin ) + nTopPrtMargin = nTmpPrtMargin; + } + + // table has to be notified if it has to change its lower + // margin due to changes of nBottomLineSize: + if ( !GetNext() && nBottomLineSize != GetBottomLineSize() ) + pTabFrm->_InvalidatePrt(); + + // If there are rows nested inside this row, the nested rows + // may not have been calculated yet. Therefore the + // ::lcl_CalcMinRowHeight( this ) operation later in this + // function cannot consider the correct border values. We + // have to trigger the invalidation of the outer row frame + // manually: + // Note: If any further invalidations should be necessary, we + // should consider moving the invalidation stuff to the + // appropriate SwNotify object. + if ( GetUpper()->GetUpper()->IsRowFrm() && + ( nBottomLineDist != GetBottomMarginForLowers() || + nTopPrtMargin != GetTopMarginForLowers() ) ) + GetUpper()->GetUpper()->_InvalidateSize(); + + SetBottomMarginForLowers( nBottomLineDist ); // 3. + SetBottomLineSize( nBottomLineSize ); // 4. + SetTopMarginForLowers( nTopPrtMargin ); // 5. + + } +// <-- collapsing + } + + while ( !bValidSize ) + { + bValidSize = sal_True; + +#if OSL_DEBUG_LEVEL > 1 + if ( HasFixSize() ) + { + const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize(); + OSL_ENSURE( rFrmSize.GetSize().Height() > 0, "Hat ihn" ); + } +#endif + const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() - + ( HasFixSize() && !IsRowSpanLine() + ? pAttrs->GetSize().Height() + // --> OD 2004-10-04 #i26945# + : ::lcl_CalcMinRowHeight( this, + FindTabFrm()->IsConsiderObjsForMinCellHeight() ) ); + // <-- + if ( nDiff ) + { + bFixSize = sal_False; + if ( nDiff > 0 ) + Shrink( nDiff, sal_False, sal_True ); + else if ( nDiff < 0 ) + Grow( -nDiff ); + bFixSize = bFix; + } + } + + // last row will fill the space in its upper. + if ( !GetNext() ) + { + //Der letzte fuellt den verbleibenden Raum im Upper aus. + SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)(); + SwFrm *pSibling = GetUpper()->Lower(); + do + { nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)(); + pSibling = pSibling->GetNext(); + } while ( pSibling ); + if ( nDiff > 0 ) + { + bFixSize = sal_False; + Grow( nDiff ); + bFixSize = bFix; + bValidSize = sal_True; + } + } +} + +/************************************************************************* +|* +|* SwRowFrm::AdjustCells() +|* +|*************************************************************************/ +void SwRowFrm::AdjustCells( const SwTwips nHeight, const sal_Bool bHeight ) +{ + SwFrm *pFrm = Lower(); + if ( bHeight ) + { + SwRootFrm *pRootFrm = getRootFrm(); + SWRECTFN( this ) + SwRect aOldFrm; + + while ( pFrm ) + { + SwFrm* pNotify = 0; + + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pFrm); + + // NEW TABLES + // Which cells need to be adjusted if the current row changes + // its height? + + // Current frame is a covered frame: + // Set new height for covered cell and adjust master cell: + if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) + { + // Set height of current (covered) cell to new line height. + const long nDiff = nHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + { + (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); + pCellFrm->_InvalidatePrt(); + } + } + + SwCellFrm* pToAdjust = 0; + SwFrm* pToAdjustRow = 0; + + // If current frame is covered frame, we still want to adjust the + // height of the cell starting the row span + if ( pCellFrm->GetLayoutRowSpan() < 1 ) + { + pToAdjust = const_cast< SwCellFrm*>(&pCellFrm->FindStartEndOfRowSpanCell( true, true )); + pToAdjustRow = pToAdjust->GetUpper(); + } + else + { + pToAdjust = pCellFrm; + pToAdjustRow = this; + } + + // Set height of master cell to height of all lines spanned by this line. + long nRowSpan = pToAdjust->GetLayoutRowSpan(); + SwTwips nSumRowHeight = 0; + while ( pToAdjustRow ) + { + // Use new height for the current row: + nSumRowHeight += pToAdjustRow == this ? + nHeight : + (pToAdjustRow->Frm().*fnRect->fnGetHeight)(); + + if ( nRowSpan-- == 1 ) + break; + + pToAdjustRow = pToAdjustRow->GetNext(); + } + + if ( pToAdjustRow && pToAdjustRow != this ) + pToAdjustRow->_InvalidateSize(); + + const long nDiff = nSumRowHeight - (pToAdjust->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + { + aOldFrm = pToAdjust->Frm(); + (pToAdjust->Frm().*fnRect->fnAddBottom)( nDiff ); + pNotify = pToAdjust; + } + + if ( pNotify ) + { + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && pRootFrm->GetCurrShell() ) + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pNotify, aOldFrm ); + + pNotify->_InvalidatePrt(); + } + + pFrm = pFrm->GetNext(); + } + } + else + { while ( pFrm ) + { + pFrm->_InvalidateAll(); + pFrm = pFrm->GetNext(); + } + } + InvalidatePage(); +} + +/************************************************************************* +|* +|* SwRowFrm::Cut() +|* +|*************************************************************************/ +void SwRowFrm::Cut() +{ + SwTabFrm *pTab = FindTabFrm(); + if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() ) + { + pTab->FindMaster()->InvalidatePos(); + } + + // --> OD 2010-02-17 #i103961# + // notification for accessibility + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell* pVSh = pRootFrm->GetCurrShell(); + if ( pVSh && pVSh->Imp() ) + { + SwFrm* pCellFrm( GetLower() ); + while ( pCellFrm ) + { + OSL_ENSURE( pCellFrm->IsCellFrm(), + "<SwRowFrm::Cut()> - unexpected type of SwRowFrm lower." ); + pVSh->Imp()->DisposeAccessibleFrm( pCellFrm ); + + pCellFrm = pCellFrm->GetNext(); + } + } + } + } + // <-- + + SwLayoutFrm::Cut(); +} + +/************************************************************************* +|* +|* SwRowFrm::GrowFrm() +|* +|*************************************************************************/ + + +SwTwips SwRowFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SwTwips nReal = 0; + + SwTabFrm* pTab = FindTabFrm(); + SWRECTFN( pTab ) + + bool bRestrictTableGrowth; + bool bHasFollowFlowLine = pTab->HasFollowFlowLine(); + + if ( GetUpper()->IsTabFrm() ) + { + const SwRowFrm* pFollowFlowRow = IsInSplitTableRow(); + bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine(); + } + else + { + OSL_ENSURE( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" ); + bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine; + OSL_ENSURE( !bRestrictTableGrowth || !GetNext(), + "GetFollowRow for row frame that has a Next" ); + + // + // There may still be some space left in my direct upper: + // + const SwTwips nAdditionalSpace = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->GetUpper()->*fnRect->fnGetPrtBottom)() ); + if ( bRestrictTableGrowth && nAdditionalSpace > 0 ) + { + nReal = Min( nAdditionalSpace, nDist ); + nDist -= nReal; + if ( !bTst ) + (Frm().*fnRect->fnAddBottom)( nReal ); + } + } + + if ( bRestrictTableGrowth ) + pTab->SetRestrictTableGrowth( sal_True ); + else + { + // Ok, this looks like a hack, indeed, it is a hack. + // If the current row frame is inside another cell frame, + // and the current row frame has no follow, it should not + // be allowed to grow. In fact, setting bRestrictTableGrowth + // to 'false' does not work, because the surrounding RowFrm + // would set this to 'true'. + pTab->SetFollowFlowLine( sal_False ); + } + + nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo); + + pTab->SetRestrictTableGrowth( sal_False ); + pTab->SetFollowFlowLine( bHasFollowFlowLine ); + + //Hoehe der Zellen auf den neuesten Stand bringen. + if ( !bTst ) + { + SWRECTFNX( this ) + AdjustCells( (Prt().*fnRectX->fnGetHeight)() + nReal, sal_True ); + if ( nReal ) + SetCompletePaint(); + } + + return nReal; +} + +/************************************************************************* +|* +|* SwRowFrm::ShrinkFrm() +|* +|*************************************************************************/ +SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + if( HasFixSize() ) + { + AdjustCells( (Prt().*fnRect->fnGetHeight)(), sal_True ); + return 0L; + } + + //bInfo wird ggf. vom SwRowFrm::Format auf sal_True gesetzt, hier muss dann + //entsprechend reagiert werden + const sal_Bool bShrinkAnyway = bInfo; + + //Nur soweit Shrinken, wie es der Inhalt der groessten Zelle zulaesst. + SwTwips nRealDist = nDist; + { + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? + rSz.GetHeight() : + 0; + + // Only necessary to calculate minimal row height if height + // of pRow is at least nMinHeight. Otherwise nMinHeight is the + // minimum height. + if( nMinHeight < (Frm().*fnRect->fnGetHeight)() ) + { + // --> OD 2004-10-04 #i26945# + OSL_ENSURE( FindTabFrm(), "<SwRowFrm::ShrinkFrm(..)> - no table frame -> crash." ); + const bool bConsiderObjs( FindTabFrm()->IsConsiderObjsForMinCellHeight() ); + // <-- + nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs ); + } + + if ( ((Frm().*fnRect->fnGetHeight)() - nRealDist) < nMinHeight ) + nRealDist = (Frm().*fnRect->fnGetHeight)() - nMinHeight; + } + if ( nRealDist < 0 ) + nRealDist = 0; + + SwTwips nReal = nRealDist; + if ( nReal ) + { + if ( !bTst ) + { + SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( nHeight - nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !bRev ) + Frm().Pos().X() += nReal; + } + + SwTwips nTmp = GetUpper()->Shrink( nReal, bTst ); + if ( !bShrinkAnyway && !GetNext() && nTmp != nReal ) + { + //Der letzte bekommt den Rest im Upper und nimmt deshalb + //ggf. Ruecksichten (sonst: Endlosschleife) + if ( !bTst ) + { + nReal -= nTmp; + SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( nHeight + nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !bRev ) + Frm().Pos().X() -= nReal; + } + nReal = nTmp; + } + } + + //Geeignet invalidieren und die Hoehe der Zellen auf den neuesten + //Stand bringen. + if ( !bTst ) + { + if ( nReal ) + { + if ( GetNext() ) + GetNext()->_InvalidatePos(); + _InvalidateAll(); + SetCompletePaint(); + + SwTabFrm *pTab = FindTabFrm(); + if ( !pTab->IsRebuildLastLine() && pTab->IsFollow() && + this == pTab->GetFirstNonHeadlineRow() ) + { + SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() ); + pMasterTab->InvalidatePos(); + } + } + AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, sal_True ); + } + return nReal; +} + +/************************************************************************* +|* +|* SwRowFrm::IsRowSplitAllowed() +|* +|*************************************************************************/ +bool SwRowFrm::IsRowSplitAllowed() const +{ + // Fixed size rows are never allowed to split: + if ( HasFixSize() ) + { + OSL_ENSURE( ATT_FIX_SIZE == GetFmt()->GetFrmSize().GetHeightSizeType(), "pRow claims to have fixed size" ); + return false; + } + + // Repeated headlines are never allowed to split: + const SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->GetTable()->GetRowsToRepeat() > 0 && + pTabFrm->IsInHeadline( *this ) ) + return false; + + const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)GetTabLine()->GetFrmFmt(); + const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit(); + return 0 != rLP.GetValue(); +} + +/************************************************************************* +|* +|* SwRowFrm::ShouldRowKeepWithNext() +|* +|*************************************************************************/ +bool SwRowFrm::ShouldRowKeepWithNext() const +{ + bool bRet = false; + + const SwCellFrm* pCell = static_cast<const SwCellFrm*>(Lower()); + const SwFrm* pTxt = pCell->Lower(); + + if ( pTxt && pTxt->IsTxtFrm() ) + { + bRet = static_cast<const SwTxtFrm*>(pTxt)->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue(); + } + return bRet; +} + +/************************************************************************* +|* +|* SwCellFrm::SwCellFrm(), ~SwCellFrm() +|* +|*************************************************************************/ +SwCellFrm::SwCellFrm( const SwTableBox &rBox, SwFrm* pSib, bool bInsertContent ) : + SwLayoutFrm( rBox.GetFrmFmt(), pSib ), + pTabBox( &rBox ) +{ + nType = FRMC_CELL; + + if ( !bInsertContent ) + return; + + //Wenn ein StartIdx vorhanden ist, so werden CntntFrms in der Zelle + //angelegt, andernfalls muessen Rows vorhanden sein und diese werden + //angelegt. + if ( rBox.GetSttIdx() ) + { + sal_uLong nIndex = rBox.GetSttIdx(); + ::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex ); + } + else + { + const SwTableLines &rLines = rBox.GetTabLines(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + SwRowFrm *pNew = new SwRowFrm( *rLines[i], this, bInsertContent ); + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } + } +} + +SwCellFrm::~SwCellFrm() +{ + SwModify* pMod = GetFmt(); + if( pMod ) + { + // At this stage the lower frames aren't destroyed already, + // therfor we have to do a recursive dispose. + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, sal_True ); + } + + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen + } +} + +/************************************************************************* +|* +|* SwCellFrm::Format() +|* +|*************************************************************************/ +sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ) +{ + sal_Bool bRet = sal_False; + SwFrm *pFrm = pLay->Lower(); + SWRECTFN( pLay ) + while ( pFrm ) + { + long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)(); + if( nFrmTop != lYStart ) + { + bRet = sal_True; + const long lDiff = (*fnRect->fnYDiff)( lYStart, nFrmTop ); + const long lDiffX = lYStart - nFrmTop; + (pFrm->Frm().*fnRect->fnSubTop)( -lDiff ); + (pFrm->Frm().*fnRect->fnAddBottom)( lDiff ); + pFrm->SetCompletePaint(); + if ( !pFrm->GetNext() ) + pFrm->SetRetouche(); + if( bInva ) + pFrm->Prepare( PREP_POS_CHGD ); + if ( pFrm->IsLayoutFrm() && ((SwLayoutFrm*)pFrm)->Lower() ) + lcl_ArrangeLowers( (SwLayoutFrm*)pFrm, + (((SwLayoutFrm*)pFrm)->Lower()->Frm().*fnRect->fnGetTop)() + + lDiffX, bInva ); + if ( pFrm->GetDrawObjs() ) + { + for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + // --> OD 2004-10-08 #i26945# - check, if anchored object + // is lower of layout frame by checking, if the anchor + // frame, which contains the anchor position, is a lower + // of the layout frame. + if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrmContainingAnchPos() ) ) + { + continue; + } + // <-- + // --> OD 2005-08-08 #i52904# - distinguish between anchored + // objects, whose vertical position depends on its anchor + // frame and whose vertical position is independent + // from its anchor frame. + bool bVertPosDepOnAnchor( true ); + { + SwFmtVertOrient aVert( pAnchoredObj->GetFrmFmt().GetVertOrient() ); + switch ( aVert.GetRelationOrient() ) + { + case text::RelOrientation::PAGE_FRAME: + case text::RelOrientation::PAGE_PRINT_AREA: + bVertPosDepOnAnchor = false; + break; + default: break; + } + } + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + + // OD 2004-05-18 #i28701# - no direct move of objects, + // which are anchored to-paragraph/to-character, if + // the wrapping style influence has to be considered + // on the object positioning. + // --> OD 2005-08-08 #i52904# - no direct move of objects, + // whose vertical position doesn't depend on anchor frame. + const bool bDirectMove = + WEIT_WECH != pFly->Frm().Top() && + bVertPosDepOnAnchor && + !pFly->ConsiderObjWrapInfluenceOnObjPos(); + // <-- + if ( bDirectMove ) + { + (pFly->Frm().*fnRect->fnSubTop)( -lDiff ); + (pFly->Frm().*fnRect->fnAddBottom)( lDiff ); + pFly->GetVirtDrawObj()->SetRectsDirty(); + // --> OD 2004-08-17 - also notify view of <SdrObject> + // instance, which represents the Writer fly frame in + // the drawing layer + pFly->GetVirtDrawObj()->SetChanged(); + // <-- + // --> OD 2006-10-13 #i58280# + pFly->InvalidateObjRectWithSpaces(); + // <-- + } + + if ( pFly->IsFlyInCntFrm() ) + { + static_cast<SwFlyInCntFrm*>(pFly)->AddRefOfst( lDiff ); + // --> OD 2004-12-02 #115759# - reset current relative + // position to get re-positioned, if not directly moved. + if ( !bDirectMove ) + { + pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); + } + // <-- + } + else if( pFly->IsAutoPos() ) + { + pFly->AddLastCharY( lDiff ); + // OD 2004-05-18 #i28701# - follow-up of #i22341# + // <mnLastTopOfLine> has also been adjusted. + pFly->AddLastTopOfLineY( lDiff ); + } + // --> OD 2004-11-05 #i26945# - re-registration at + // page frame of anchor frame, if table frame isn't + // a follow table and table frame isn't in its + // rebuild of last line. + const SwTabFrm* pTabFrm = pLay->FindTabFrm(); + // --> OD 2004-11-23 #115759# + // - save: check, if table frame is found. + if ( pTabFrm && + !( pTabFrm->IsFollow() && + pTabFrm->FindMaster()->IsRebuildLastLine() ) && + pFly->IsFlyFreeFrm() ) + // <-- + { + SwPageFrm* pPageFrm = pFly->GetPageFrm(); + SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); + if ( pPageFrm != pPageOfAnchor ) + { + pFly->InvalidatePos(); + if ( pPageFrm ) + pPageFrm->MoveFly( pFly, pPageOfAnchor ); + else + pPageOfAnchor->AppendFlyToPage( pFly ); + } + } + // <-- + // OD 2004-05-11 #i28701# - Because of the introduction + // of new positionings and alignments (e.g. aligned at + // page area, but anchored at-character), the position + // of the Writer fly frame has to be invalidated. + pFly->InvalidatePos(); + + // --> OD 2004-11-04 #i26945# - follow-up of #i3317# + // No arrangement of lowers, if Writer fly frame isn't + // moved + if ( bDirectMove && + ::lcl_ArrangeLowers( pFly, + (pFly->*fnRect->fnGetPrtTop)(), + bInva ) ) + // <-- + { + pFly->SetCompletePaint(); + } + } + else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) + { + // --> OD 2004-11-05 #i26945# + const SwTabFrm* pTabFrm = pLay->FindTabFrm(); + if ( pTabFrm && + !( pTabFrm->IsFollow() && + pTabFrm->FindMaster()->IsRebuildLastLine() ) && + !pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() + == FLY_AS_CHAR ) + { + SwPageFrm* pPageFrm = pAnchoredObj->GetPageFrm(); + SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); + if ( pPageFrm != pPageOfAnchor ) + { + pAnchoredObj->InvalidateObjPos(); + if ( pPageFrm ) + { + pPageFrm->RemoveDrawObjFromPage( *pAnchoredObj ); + } + pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj ); + } + } + // --> OD 2004-07-01 #i28701# - adjust last character + // rectangle and last top of line. + pAnchoredObj->AddLastCharY( lDiff ); + pAnchoredObj->AddLastTopOfLineY( lDiff ); + // --> OD 2005-08-08 #i52904# - re-introduce direct move + // of drawing objects + const bool bDirectMove = + static_cast<const SwDrawFrmFmt&>(pAnchoredObj->GetFrmFmt()).IsPosAttrSet() && + bVertPosDepOnAnchor && + !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos(); + if ( bDirectMove ) + { + SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); + if ( bVert ) + { + pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) ); + } + else + { + pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) ); + } + // --> OD 2006-10-13 #i58280# + pAnchoredObj->InvalidateObjRectWithSpaces(); + // <-- + } + // <-- + pAnchoredObj->InvalidateObjPos(); + } + else + { + OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" ); + } + } + } + } + // Columns and cells are ordered horizontal, not vertical + if( !pFrm->IsColumnFrm() && !pFrm->IsCellFrm() ) + lYStart = (*fnRect->fnYInc)( lYStart, + (pFrm->Frm().*fnRect->fnGetHeight)() ); + + // Nowadays, the content inside a cell can flow into the follow table. + // Thus, the cell may only grow up to the end of the environment. + // So the content may have grown, but the cell could not grow. + // Therefore we have to trigger a formatting for the frames, which do + // not fit into the cell anymore: + SwTwips nDistanceToUpperPrtBottom = + (pFrm->Frm().*fnRect->fnBottomDist)( (pLay->*fnRect->fnGetPrtBottom)()); + // --> OD 2006-01-19 #i56146# - Revise fix of issue #i26945# + // do *not* consider content inside fly frames, if it's an undersized paragraph. + // --> OD 2004-10-08 #i26945# - consider content inside fly frames + if ( nDistanceToUpperPrtBottom < 0 && + ( ( pFrm->IsInFly() && + ( !pFrm->IsTxtFrm() || + !static_cast<SwTxtFrm*>(pFrm)->IsUndersized() ) ) || + pFrm->IsInSplitTableRow() ) ) + // <-- + { + pFrm->InvalidatePos(); + } + + pFrm = pFrm->GetNext(); + } + return bRet; +} + +void SwCellFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "CellFrm::Format, pAttrs ist 0." ); + const SwTabFrm* pTab = FindTabFrm(); + SWRECTFN( pTab ) + + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + + //Position einstellen. + if ( Lower() ) + { + SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace; + // --> collapsing borders FME 2005-05-27 #i29550# + if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrm() ) + { + const SvxBoxItem& rBoxItem = pAttrs->GetBox(); + nLeftSpace = rBoxItem.GetDistance( BOX_LINE_LEFT ); + nRightSpace = rBoxItem.GetDistance( BOX_LINE_RIGHT ); + nTopSpace = ((SwRowFrm*)GetUpper())->GetTopMarginForLowers(); + nBottomSpace = ((SwRowFrm*)GetUpper())->GetBottomMarginForLowers(); + } + else + { + // <-- collapsing + // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> + nLeftSpace = pAttrs->CalcLeft( this ); + nRightSpace = pAttrs->CalcRight( this ); + nTopSpace = pAttrs->CalcTop(); + nBottomSpace = pAttrs->CalcBottom(); + } + (this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace ); + (this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace ); + } + } + // --> OD 2004-10-04 #i26945# + long nRemaining = GetTabBox()->getRowSpan() >= 1 ? + ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) : + 0; + // <-- + if ( !bValidSize ) + { + bValidSize = sal_True; + + //Die VarSize der CellFrms ist immer die Breite. + //Tatsaechlich ist die Breite jedoch nicht Variabel, sie wird durch das + //Format vorgegeben. Dieser Vorgegebene Wert muss aber nun wiederum + //nicht der tatsaechlichen Breite entsprechen. Die Breite wird auf + //Basis des Attributes errechnet, der Wert im Attribut passt zu dem + //gewuenschten Wert des TabFrms. Anpassungen die dort vorgenommen + //wurden werden hier Proportional beruecksichtigt. + //Wenn die Celle keinen Nachbarn mehr hat beruecksichtigt sie nicht + //die Attribute, sonder greift sich einfach den Rest des + //Uppers + SwTwips nWidth; + if ( GetNext() ) + { + const SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth(); + nWidth = pAttrs->GetSize().Width(); + + OSL_ENSURE( nWish, "Tabelle ohne Breite?" ); + OSL_ENSURE( nWidth <= nWish, "Zelle breiter als Tabelle." ); + OSL_ENSURE( nWidth > 0, "Box without width" ); + + const long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); + if ( nWish != nPrtWidth ) + { + // Avoid rounding problems, at least for the new table model + if ( pTab->GetTable()->IsNewModel() ) + { + // 1. sum of widths of cells up to this cell (in model) + const SwTableLine* pTabLine = GetTabBox()->GetUpper(); + const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes(); + const SwTableBox* pTmpBox = 0; + + SwTwips nSumWidth = 0; + sal_uInt16 i = 0; + do + { + pTmpBox = rBoxes[ i++ ]; + nSumWidth += pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth(); + } + while ( pTmpBox != GetTabBox() ); + + // 2. calculate actual width of cells up to this one + double nTmpWidth = nSumWidth; + nTmpWidth *= nPrtWidth; + nTmpWidth /= nWish; + nWidth = (SwTwips)nTmpWidth; + + // 3. calculate frame widths of cells up to this one: + const SwFrm* pTmpCell = static_cast<const SwLayoutFrm*>(GetUpper())->Lower(); + SwTwips nSumFrameWidths = 0; + while ( pTmpCell != this ) + { + nSumFrameWidths += (pTmpCell->Frm().*fnRect->fnGetWidth)(); + pTmpCell = pTmpCell->GetNext(); + } + + nWidth = nWidth - nSumFrameWidths; + } + else + { + // #i12092# use double instead of long, + // otherwise this could lead to overflows + double nTmpWidth = nWidth; + nTmpWidth *= nPrtWidth; + nTmpWidth /= nWish; + nWidth = (SwTwips)nTmpWidth; + } + } + } + else + { + OSL_ENSURE( pAttrs->GetSize().Width() > 0, "Box without width" ); + nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + SwFrm *pPre = GetUpper()->Lower(); + while ( pPre != this ) + { + nWidth -= (pPre->Frm().*fnRect->fnGetWidth)(); + pPre = pPre->GetNext(); + } + } + const long nDiff = nWidth - (Frm().*fnRect->fnGetWidth)(); + if( IsNeighbourFrm() && IsRightToLeft() ) + (Frm().*fnRect->fnSubLeft)( nDiff ); + else + (Frm().*fnRect->fnAddRight)( nDiff ); + (Prt().*fnRect->fnAddRight)( nDiff ); + + //Jetzt die Hoehe einstellen, sie wird vom Inhalt und den Raendern + //bestimmt. + const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)(); + if ( nDiffHeight ) + { + if ( nDiffHeight > 0 ) + { + //Wieder validieren wenn kein Wachstum stattgefunden hat. + //Invalidiert wird durch AdjustCells von der Row. + if ( !Grow( nDiffHeight ) ) + bValidSize = bValidPrtArea = sal_True; + } + else + { + //Nur dann invalidiert lassen, wenn tatsaechlich + //geshrinkt wurde; das kann abgelehnt werden, weil alle + //nebeneinanderliegenden Zellen gleichgross sein muessen. + if ( !Shrink( -nDiffHeight ) ) + bValidSize = bValidPrtArea = sal_True; + } + } + } + const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient(); + + if ( !Lower() ) + return; + + // From now on, all operations are related to the table cell. + SWREFRESHFN( this ) + + SwPageFrm* pPg = 0; + if ( !FindTabFrm()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() && + // --> OD 2008-07-16 #158225# no vertical alignment of covered cells + !IsCoveredCell() && + // <-- + // --> FME 2004-06-29 #116532# Do not consider vertical alignment in grid mode + !(pPg = FindPageFrm())->HasGrid() ) + // <-- + { + if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() && !Lower()->IsTabFrm() ) + { + // OSL_ENSURE(fuer HTML-Import! + OSL_ENSURE( !this, "VAlign an Zelle ohne Inhalt" ); + return; + } + sal_Bool bVertDir = sal_True; + // --> OD 2005-03-30 #i43913# - no vertical alignment, if wrapping + // style influence is considered on object positioning and + // an object is anchored inside the cell. + const bool bConsiderWrapOnObjPos( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ); + // <-- + //Keine Ausrichtung wenn Rahmen mit Umlauf in die Zelle ragen. + if ( pPg->GetSortedObjs() ) + { + SwRect aRect( Prt() ); aRect += Frm().Pos(); + for ( sal_uInt16 i = 0; i < pPg->GetSortedObjs()->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pPg->GetSortedObjs())[i]; + SwRect aTmp( pAnchoredObj->GetObjRect() ); + if ( aTmp.IsOver( aRect ) ) + { + const SwFrmFmt& rAnchoredObjFrmFmt = pAnchoredObj->GetFrmFmt(); + const SwFmtSurround &rSur = rAnchoredObjFrmFmt.GetSurround(); + + if ( SURROUND_THROUGHT != rSur.GetSurround() ) + { + // frames, which the cell is a lower of, aren't relevant + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = + static_cast<const SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsAnLower( this ) ) + continue; + } + + const SwFrm* pAnch = pAnchoredObj->GetAnchorFrm(); + // --> OD 2005-03-30 #i43913# + // --> OD 2005-08-08 #i52904# - no vertical alignment, + // if object, anchored inside cell, has temporarly + // consider its wrapping style on object positioning. + // --> FME 2006-02-01 #i58806# - no vertical alignment + // if object does not follow the text flow. + if ( bConsiderWrapOnObjPos || + !IsAnLower( pAnch ) || + pAnchoredObj->IsTmpConsiderWrapInfluence() || + !rAnchoredObjFrmFmt.GetFollowTextFlow().GetValue() ) + // <-- + { + bVertDir = sal_False; + break; + } + } + } + } + } + + long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) || + (Lower()->Frm().*fnRect->fnGetTop)() != (this->*fnRect->fnGetPrtTop)() ) + { + long nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining; + if ( nDiff >= 0 ) + { + long lTopOfst = 0; + if ( bVertDir ) + { + switch ( rOri.GetVertOrient() ) + { + case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break; + case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break; + default: break; + }; + } + long nTmp = (*fnRect->fnYInc)( + (this->*fnRect->fnGetPrtTop)(), lTopOfst ); + if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) ) + SetCompletePaint(); + } + } + } + else + { + //Ist noch eine alte Ausrichtung beruecksichtigt worden? + if ( Lower()->IsCntntFrm() ) + { + const long lYStart = (this->*fnRect->fnGetPrtTop)(); + lcl_ArrangeLowers( this, lYStart, sal_True ); + } + } +} + +/************************************************************************* +|* +|* SwCellFrm::Modify() +|* +|*************************************************************************/ + +void SwCellFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + const SfxPoolItem *pItem = 0; + + if( bAttrSetChg ) + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, sal_False, &pItem); + else if ( RES_VERT_ORIENT == pNew->Which() ) + pItem = pNew; + + if ( pItem ) + { + sal_Bool bInva = sal_True; + if ( text::VertOrientation::NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() && + // OD 04.11.2003 #112910# + Lower() && Lower()->IsCntntFrm() ) + { + SWRECTFN( this ) + const long lYStart = (this->*fnRect->fnGetPrtTop)(); + bInva = lcl_ArrangeLowers( this, lYStart, sal_False ); + } + if ( bInva ) + { + SetCompletePaint(); + InvalidatePrt(); + } + } + + if ( ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, sal_False ) ) || + RES_PROTECT == pNew->Which() ) + { + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetLayout()->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this ); + } + + if ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, sal_False, &pItem ) ) + { + SetDerivedVert( sal_False ); + CheckDirChange(); + } + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_BOX, sal_False, &pItem ) ) + { + SwFrm* pTmpUpper = GetUpper(); + while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrm() ) + pTmpUpper = pTmpUpper->GetUpper(); + + SwTabFrm* pTabFrm = (SwTabFrm*)pTmpUpper->GetUpper(); + if ( pTabFrm->IsCollapsingBorders() ) + { + // Invalidate lowers of this and next row: + lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); + pTmpUpper = pTmpUpper->GetNext(); + if ( pTmpUpper ) + lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); + else + pTabFrm->InvalidatePrt(); + } + } + // <-- collapsing + + SwLayoutFrm::Modify( pOld, pNew ); +} + +/************************************************************************* +|* SwCellFrm::GetLayoutRowSpan() const +|*************************************************************************/ + +long SwCellFrm::GetLayoutRowSpan() const +{ + long nRet = GetTabBox()->getRowSpan(); + if ( nRet < 1 ) + { + const SwFrm* pRow = GetUpper(); + const SwTabFrm* pTab = static_cast<const SwTabFrm*>(pRow->GetUpper()); + + if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() ) + nRet = -nRet; + } + return nRet; +} + +// --> OD 2010-02-17 #i103961# +void SwCellFrm::Cut() +{ + // notification for accessibility + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell* pVSh = pRootFrm->GetCurrShell(); + if ( pVSh && pVSh->Imp() ) + { + pVSh->Imp()->DisposeAccessibleFrm( this ); + } + } + } + + SwLayoutFrm::Cut(); +} +// <-- + +// +// Helper functions for repeated headlines: +// + +/* + * SwTabFrm::IsInHeadline( const SwFrm& rFrm ) + */ +bool SwTabFrm::IsInHeadline( const SwFrm& rFrm ) const +{ + OSL_ENSURE( IsAnLower( &rFrm ) && rFrm.IsInTab(), + "SwTabFrm::IsInHeadline called for frame not lower of table" ); + + const SwFrm* pTmp = &rFrm; + while ( !pTmp->GetUpper()->IsTabFrm() ) + pTmp = pTmp->GetUpper(); + + return GetTable()->IsHeadline( *((SwRowFrm*)pTmp)->GetTabLine() ); +} + +/* + * SwTabFrm::GetFirstNonHeadlineRow() + * + * If this is a master table, we can may assume, that there are at least + * nRepeat lines in the table. + * If this is a follow table, there are intermediate states for the table + * layout, e.g., during deletion of rows, which makes it necessary to find + * the first non-headline row by evaluating the headline flag at the row frame. + */ +SwRowFrm* SwTabFrm::GetFirstNonHeadlineRow() const +{ + SwRowFrm* pRet = (SwRowFrm*)Lower(); + if ( pRet ) + { + if ( IsFollow() ) + { + while ( pRet && pRet->IsRepeatedHeadline() ) + pRet = (SwRowFrm*)pRet->GetNext(); + } + else + { + sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + while ( pRet && nRepeat > 0 ) + { + pRet = (SwRowFrm*)pRet->GetNext(); + --nRepeat; + } + } + } + + return (SwRowFrm*)pRet; +} + +/* + * SwTable::IsHeadline() + */ +bool SwTable::IsHeadline( const SwTableLine& rLine ) const +{ + for ( sal_uInt16 i = 0; i < GetRowsToRepeat(); ++i ) + if ( GetTabLines()[ i ] == &rLine ) + return true; + + return false; +} + +bool SwTabFrm::IsLayoutSplitAllowed() const +{ + return GetFmt()->GetLayoutSplit().GetValue(); +} + +// --> collapsing borders FME 2005-05-27 #i29550# + +sal_uInt16 SwTabFrm::GetBottomLineSize() const +{ + OSL_ENSURE( IsCollapsingBorders(), + "BottomLineSize only required for collapsing borders" ); + + OSL_ENSURE( Lower(), "Warning! Trying to prevent a crash, please inform FME" ); + + const SwFrm* pTmp = GetLastLower(); + + // --> FME 2005-12-07 #124755# Try to make code robust: + if ( !pTmp ) return 0; + // <-- + + return static_cast<const SwRowFrm*>(pTmp)->GetBottomLineSize(); +} + +bool SwTabFrm::IsCollapsingBorders() const +{ + return ((SfxBoolItem&)GetFmt()->GetAttrSet().Get( RES_COLLAPSING_BORDERS )).GetValue(); +} + +// <-- collapsing + + +// +// Local helper function to calculate height of first text row +// +SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrm& rSourceLine ) +{ + // Find corresponding split line in master table + const SwTabFrm* pTab = rSourceLine.FindTabFrm(); + SWRECTFN( pTab ) + const SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); + + // + // 1. Case: rSourceLine is a follow flow line. + // In this case we have to return the minimum of the heights + // of the first lines in rSourceLine. + // + // 2. Case: rSourceLine is not a follow flow line. + // In this case we have to return the maximum of the heights + // of the first lines in rSourceLine. + // + bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow(); + SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0; + + while ( pCurrSourceCell ) + { + // NEW TABLES + // Skip cells which are not responsible for the height of + // the follow flow line: + if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 ) + { + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + continue; + } + + const SwFrm *pTmp = pCurrSourceCell->Lower(); + if ( pTmp ) + { + SwTwips nTmpHeight = USHRT_MAX; + // --> FME 2004-09-14 #i32456# Consider lower row frames + if ( pTmp->IsRowFrm() ) + { + const SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow ); + } + // <-- + if ( pTmp->IsTabFrm() ) + { + nTmpHeight = ((SwTabFrm*)pTmp)->CalcHeightOfFirstContentLine(); + } + else if ( pTmp->IsTxtFrm() ) + { + SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp; + pTxtFrm->GetFormatted(); + nTmpHeight = pTxtFrm->FirstLineHeight(); + } + + if ( USHRT_MAX != nTmpHeight ) + { + const SwCellFrm* pPrevCell = pCurrSourceCell->GetPreviousCell(); + if ( pPrevCell ) + { + // If we are in a split row, there may be some space + // left in the cell frame of the master row. + // We look for the minimum of all first line heights; + SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)(); + const SwFrm* pFrm = pPrevCell->Lower(); + const SwFrm* pLast = pFrm; + while ( pFrm ) + { + nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); + pLast = pFrm; + pFrm = pFrm->GetNext(); + } + + // --> FME, OD 2004-07-15 #i26831#, #i26520# + // The additional lower space of the current last. + // --> OD 2004-11-25 #115759# - do *not* consider the + // additional lower space for 'master' text frames + if ( pLast && pLast->IsFlowFrm() && + ( !pLast->IsTxtFrm() || + !static_cast<const SwTxtFrm*>(pLast)->GetFollow() ) ) + // <-- + { + nReal += SwFlowFrm::CastFlowFrm(pLast)->CalcAddLowerSpaceAsLastInTableCell(); + } + // Don't forget the upper space and lower space, + // --> OD 2004-11-25 #115759# - do *not* consider the upper + // and the lower space for follow text frames. + if ( pTmp->IsFlowFrm() && + ( !pTmp->IsTxtFrm() || + !static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace( NULL, pLast); + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); + } + // <-- + // --> OD 2004-11-25 #115759# - consider additional lower + // space of <pTmp>, if contains only one line. + // In this case it would be the new last text frame, which + // would have no follow and thus would add this space. + if ( pTmp->IsTxtFrm() && + const_cast<SwTxtFrm*>(static_cast<const SwTxtFrm*>(pTmp)) + ->GetLineCount( STRING_LEN ) == 1 ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp) + ->CalcAddLowerSpaceAsLastInTableCell(); + } + // <-- + if ( nReal > 0 ) + nTmpHeight -= nReal; + } + else + { + // pFirstRow is not a FollowFlowRow. In this case, + // we look for the maximum of all first line heights: + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCurrSourceCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom(); + // --> OD 2004-07-16 #i26250# + // Don't forget the upper space and lower space, + if ( pTmp->IsFlowFrm() ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace(); + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); + } + // <-- + } + } + + if ( bIsInFollowFlowLine ) + { + // minimum + if ( nTmpHeight < nHeight ) + nHeight = nTmpHeight; + } + else + { + // maximum + if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight ) + nHeight = nTmpHeight; + } + } + + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + } + + return ( LONG_MAX == nHeight ) ? 0 : nHeight; +} + +// +// Function to calculate height of first text row +// +SwTwips SwTabFrm::CalcHeightOfFirstContentLine() const +{ + SWRECTFN( this ) + + const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue(); + + if ( bDontSplit ) + { + // Table is not allowed to split: Take the whole height, that's all + return (Frm().*fnRect->fnGetHeight)(); + } + + SwRowFrm* pFirstRow = 0; + SwTwips nTmpHeight = 0; + + pFirstRow = GetFirstNonHeadlineRow(); + OSL_ENSURE( !IsFollow() || pFirstRow, "FollowTable without Lower" ); + + // NEW TABLES + if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() ) + pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); + + // Calculate the height of the headlines: + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0; + + // Calculate the height of the keeping lines + // (headlines + following keeping lines): + SwTwips nKeepHeight = nRepeatHeight; + if ( GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) ) + { + sal_uInt16 nKeepRows = nRepeat; + + // Check how many rows want to keep together + while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() ) + { + ++nKeepRows; + pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); + } + + if ( nKeepRows > nRepeat ) + nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows ); + } + + // For master tables, the height of the headlines + the heigth of the + // keeping lines (if any) has to be considered. For follow tables, we + // only consider the height of the keeping rows without the repeated lines: + if ( !IsFollow() ) + { + nTmpHeight = nKeepHeight; + } + else + { + nTmpHeight = nKeepHeight - nRepeatHeight; + } + + // pFirstRow row is the first non-heading row. + // nTmpHeight is the height of the heading row if we are a follow. + if ( pFirstRow ) + { + const bool bSplittable = pFirstRow->IsRowSplitAllowed(); + const SwTwips nFirstLineHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)(); + + if ( !bSplittable ) + { + // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow + // actually is determined by a lower cell with rowspan = -1. In this case we should not + // just return the height of the first line. Basically we need to get the height of the + // line as it would be on the last page. Since this is quite complicated to calculate, + // we olny calculate the height of the first line. + if ( pFirstRow->GetPrev() && + static_cast<SwRowFrm*>(pFirstRow->GetPrev())->IsRowSpanLine() ) + { + // Calculate maximum height of all cells with rowspan = 1: + SwTwips nMaxHeight = 0; + const SwCellFrm* pLower2 = static_cast<const SwCellFrm*>(pFirstRow->Lower()); + while ( pLower2 ) + { + if ( 1 == pLower2->GetTabBox()->getRowSpan() ) + { + const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, sal_True ); + nMaxHeight = Max( nCellHeight, nMaxHeight ); + } + pLower2 = static_cast<const SwCellFrm*>(pLower2->GetNext()); + } + nTmpHeight += nMaxHeight; + } + else + { + nTmpHeight += nFirstLineHeight; + } + } + + // --> FME 2004-11-18 #118411# + // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger + // a formatting of the row frame (via the GetFormatted()). We don't + // want this formatting if the row does not have a height. + else if ( 0 != nFirstLineHeight ) + // <-- + { + const bool bOldJoinLock = IsJoinLocked(); + ((SwTabFrm*)this)->LockJoin(); + const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow ); + + // Consider minimum row height: + const SwFmtFrmSize &rSz = static_cast<const SwRowFrm*>(pFirstRow)->GetFmt()->GetFrmSize(); + const SwTwips nMinRowHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? + rSz.GetHeight() : 0; + + nTmpHeight += Max( nHeightOfFirstContentLine, nMinRowHeight ); + + if ( !bOldJoinLock ) + ((SwTabFrm*)this)->UnlockJoin(); + } + } + + return nTmpHeight; +} + +// +// Some more functions for covered/covering cells. This way inclusion of +// SwCellFrm can be avoided +// + +bool SwFrm::IsLeaveUpperAllowed() const +{ + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + return pThisCell && pThisCell->GetLayoutRowSpan() > 1; +} + +bool SwFrm::IsCoveredCell() const +{ + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + return pThisCell && pThisCell->GetLayoutRowSpan() < 1; +} + +bool SwFrm::IsInCoveredCell() const +{ + bool bRet = false; + + const SwFrm* pThis = this; + while ( pThis && !pThis->IsCellFrm() ) + pThis = pThis->GetUpper(); + + if ( pThis ) + bRet = pThis->IsCoveredCell(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |