Files
libreoffice/sw/source/core/layout/tabfrm.cxx

4072 lines
143 KiB
C++
Raw Normal View History

2000-09-18 23:08:29 +00:00
/*************************************************************************
*
* $RCSfile: tabfrm.cxx,v $
*
* $Revision: 1.52 $
2000-09-18 23:08:29 +00:00
*
* last change: $Author: obo $ $Date: 2004-03-17 12:50:18 $
2000-09-18 23:08:29 +00:00
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#pragma hdrstop
#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 "viewopt.hxx"
#include "hints.hxx"
2001-10-19 09:25:19 +00:00
#include "dbg_lay.hxx"
2000-09-18 23:08:29 +00:00
#include <ftnidx.hxx>
#ifndef _SFXITEMITER_HXX //autogen
#include <svtools/itemiter.hxx>
#endif
#ifndef _DOCARY_HXX
#include <docary.hxx>
#endif
#ifndef _SVX_KEEPITEM_HXX //autogen
#include <svx/keepitem.hxx>
#endif
#ifndef _SVX_ULSPITEM_HXX //autogen
#include <svx/ulspitem.hxx>
#endif
#ifndef _SVX_LRSPITEM_HXX //autogen
#include <svx/lrspitem.hxx>
#endif
#ifndef _SVX_BRSHITEM_HXX //autogen
#include <svx/brshitem.hxx>
#endif
2001-07-05 09:34:53 +00:00
#ifndef _OUTDEV_HXX //autogen
#include <vcl/outdev.hxx>
#endif
2000-09-18 23:08:29 +00:00
#ifndef _FMTTSPLT_HXX //autogen
#include <fmtlsplt.hxx>
#endif
#ifndef _FMTROWSPLT_HXX //autogen
#include <fmtrowsplt.hxx>
#endif
2000-09-18 23:08:29 +00:00
#ifndef _FMTSRND_HXX //autogen
#include <fmtsrnd.hxx>
#endif
#ifndef _FMTORNT_HXX //autogen
#include <fmtornt.hxx>
#endif
#ifndef _FMTPDSC_HXX //autogen
#include <fmtpdsc.hxx>
#endif
#ifndef _FMTFSIZE_HXX //autogen
#include <fmtfsize.hxx>
#endif
#ifndef _SWTBLFMT_HXX
#include <swtblfmt.hxx>
#endif
2000-09-18 23:08:29 +00:00
#include "tabfrm.hxx"
#include "rowfrm.hxx"
#include "cellfrm.hxx"
#include "flyfrms.hxx"
#include "txtfrm.hxx" //HasFtn()
#include "htmltbl.hxx"
#include "frmsh.hxx"
#include "sectfrm.hxx" //SwSectionFrm
// OD 30.09.2003 #i18732#
#ifndef _FMTFOLLOWTEXTFLOW_HXX
#include <fmtfollowtextflow.hxx>
#endif
2000-09-18 23:08:29 +00:00
extern void AppendObjs( const SwSpzFrmFmts *pTbl, ULONG nIndex,
SwFrm *pFrm, SwPageFrm *pPage );
2000-09-18 23:08:29 +00:00
/*************************************************************************
|*
|* SwTabFrm::SwTabFrm(), ~SwTabFrm()
|*
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 30. May. 96
|*
|*************************************************************************/
SwTabFrm::SwTabFrm( SwTable &rTab ):
SwLayoutFrm( rTab.GetFrmFmt() ),
SwFlowFrm( (SwFrm&)*this ),
pTable( &rTab )
{
bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove =
bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
bRestrictTableGrowth = FALSE;
2001-10-19 09:25:19 +00:00
BFIXHEIGHT = FALSE; //Nicht nochmal auf die Importfilter hereinfallen.
nType = FRMC_TAB;
2000-09-18 23:08:29 +00:00
//Gleich die Zeilen erzeugen und einfuegen.
const SwTableLines &rLines = rTab.GetTabLines();
SwFrm *pPrev = 0;
for ( USHORT i = 0; i < rLines.Count(); ++i )
{
SwRowFrm *pNew = new SwRowFrm( *rLines[i] );
if( pNew->Lower() )
{
pNew->InsertBehind( this, pPrev );
pPrev = pNew;
}
else
delete pNew;
2000-09-18 23:08:29 +00:00
}
}
SwTabFrm::SwTabFrm( SwTabFrm &rTab ) :
SwLayoutFrm( rTab.GetFmt() ),
SwFlowFrm( (SwFrm&)*this ),
pTable( rTab.GetTable() )
{
bIsFollow = TRUE;
bLockJoin = bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove =
bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine =
bRestrictTableGrowth = FALSE;
2001-10-19 09:25:19 +00:00
BFIXHEIGHT = FALSE; //Nicht nochmal auf die Importfilter hereinfallen.
nType = FRMC_TAB;
2000-09-18 23:08:29 +00:00
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;
2000-09-18 23:08:29 +00:00
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;
}
2000-09-18 23:08:29 +00:00
}
/*************************************************************************
|*
|* SwTabFrm::JoinAndDelFollows()
|*
|* Ersterstellung MA 30. May. 96
|* Letzte Aenderung MA 30. May. 96
|*
|*************************************************************************/
void SwTabFrm::JoinAndDelFollows()
{
SwTabFrm *pFoll = GetFollow();
if ( pFoll->HasFollow() )
pFoll->JoinAndDelFollows();
pFoll->Cut();
SetFollow( pFoll->GetFollow() );
delete pFoll;
}
/*************************************************************************
|*
|* SwTabFrm::RegistFlys()
|*
|* Ersterstellung MA 08. Jul. 93
|* Letzte Aenderung MA 27. Jan. 99
|*
|*************************************************************************/
void SwTabFrm::RegistFlys()
{
ASSERT( Lower() && Lower()->IsRowFrm(), "Keine Zeilen." );
SwPageFrm *pPage = FindPageFrm();
if ( pPage )
{
SwRowFrm *pRow = (SwRowFrm*)Lower();
do
{ pRow->RegistFlys( pPage );
pRow = (SwRowFrm*)pRow->GetNext();
} while ( pRow );
}
}
// Prototypes
void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom );
BOOL MA_FASTCALL lcl_CalcLowers( SwLayoutFrm *pLay, long nBottom );
void MA_FASTCALL lcl_CalcLayout( SwLayoutFrm *pLay, long nBottom );
BOOL lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, BOOL bInva );
BOOL MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, long nBottom );
SwTwips MA_FASTCALL lcl_CalcMinRowHeight( SwLayoutFrm *pRow );
//
// Local helper function to change the split attribute for
// an oversized row frame. Loop prevention!
//
void lcl_ChangeSplitAttribute( SwRowFrm& rRow )
{
const SwTableLine* pTabLine = rRow.GetTabLine();
SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)pTabLine->GetFrmFmt();
const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit();
((SwFmtRowSplit&)rLP).SetValue( TRUE );
}
//
// Local helper function to insert a new follow flow line
//
SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, BOOL bRepeat )
{
ASSERT( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" )
const SwRowFrm& rRow = (SwRowFrm&)rTmpRow;
rTab.SetFollowFlowLine( TRUE );
SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), false );
SwFrm* pFirstRow = bRepeat ? rTab.GetFollow()->Lower() : 0;
ASSERT( !bRepeat || pFirstRow, "repeated headline assumes first row in follow tab" )
pFollowFlowLine->InsertBehind( rTab.GetFollow(), pFirstRow );
return pFollowFlowLine;
}
//
// Local helper function to shrink all lowers of rRow to 0 height
//
void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow )
{
SwFrm* pCurrMasterCell = rRow.Lower();
SWRECTFN( pCurrMasterCell )
while ( pCurrMasterCell )
{
// TODO: Optimize number of frames which are set to 0 height
SwFrm* pTmp = ((SwCellFrm*)pCurrMasterCell)->Lower();
// we have to start with the last lower frame, otherwise
// the shrink will not shrink the current cell
while ( pTmp && pTmp->GetNext() )
pTmp = pTmp->GetNext();
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
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( (SwCellFrm*)pCurrMasterCell, (pCurrMasterCell->*fnRect->fnGetPrtTop)(), sal_False );
}
pCurrMasterCell = 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();
SWRECTFN( pCurrDestCell )
// Move content of follow cells into master cells
while ( pCurrSourceCell )
{
if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() )
{
SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
while ( pTmpSourceRow )
{
if ( pTmpSourceRow->IsFollowFlowRow() )
{
// move content from follow flow row to pTmpDestRow:
SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower();
while ( pTmpDestRow->GetNext() )
pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext();
ASSERT( 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 )
{
// Find last content
SwFrm* pFrm = ((SwCellFrm*)pCurrDestCell)->Lower();
while ( pFrm && pFrm->GetNext() )
pFrm = pFrm->GetNext();
::RestoreCntnt( pTmp, (SwCellFrm*)pCurrDestCell, 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( TRUE );
SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( TRUE );
rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, 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();
SwTwips nCurrentHeight = lcl_CalcMinRowHeight( pTmpLastLineRow );;
while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight )
{
nTmpCut -= nCurrentHeight;
pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext();
nCurrentHeight = lcl_CalcMinRowHeight( pTmpLastLineRow );
}
//
// 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, (long)(rAttrs.CalcTop() + rAttrs.CalcBottom()) );
pCell = pCell->GetNext();
}
const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize();
if ( rSz.GetSizeType() == 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(), 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,
SwRowFrm& rFollowFlowLine )
{
SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
while ( pCurrMasterCell )
{
if ( pCurrMasterCell->Lower() &&
pCurrMasterCell->Lower()->IsRowFrm() )
{
SwRowFrm* pRowFrm = (SwRowFrm*)pCurrMasterCell->Lower();
while ( pRowFrm->GetNext() )
pRowFrm = (SwRowFrm*)pRowFrm->GetNext();
if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() )
{
ASSERT( 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 remove the FollowFlowLine of rTab.
// The content of the FollowFlowLine is moved to the associated line in the
// master table.
//
bool lcl_RemoveFollowFlowLine( SwTabFrm& rTab )
{
// find FollowFlowLine
SwFrm* pFollowFlowLine = rTab.GetFollow()->Lower();
const bool bHeadlineRepeat = rTab.GetTable()->IsHeadlineRepeat();
if ( bHeadlineRepeat )
pFollowFlowLine = pFollowFlowLine->GetNext();
ASSERT( rTab.HasFollowFlowLine() &&
pFollowFlowLine, "There should be a flowline in the follow" )
// find last row in master
SwFrm* pLastLine = rTab.Lower();
while ( pLastLine->GetNext() )
pLastLine = pLastLine->GetNext();
// We have to reset the flag here, because lcl_MoveRowContent
// calls a GrowFrm(), which has a different bahavior if
// this flag is set.
rTab.SetFollowFlowLine( FALSE );
lcl_MoveRowContent( *(SwRowFrm*)pFollowFlowLine, *(SwRowFrm*)pLastLine );
bool bJoin = !pFollowFlowLine->GetNext();
pFollowFlowLine->Cut();
delete pFollowFlowLine;
return bJoin;
}
//
// 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( TRUE );
SWRECTFN( rTab.GetUpper() )
//
// manipulate row and cell sizes
//
::lcl_ShrinkCellsAndAllContent( rLastLine );
//
// 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_CalcLayout( &rLastLine, LONG_MAX );
//
// 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, rFollowLine );
//
// There are two situations that make it necessary to
// move the last line to the follow table:
//
// a) There is at least one cell in the master line without content.
// b) The recalculation of the table did not work: The table still does not fit.
//
// This is allowed if either
// a) The master table may give some lines to the follow table or
// b) The master table has a prev and it is not a follow itself:
//
bool bMoveLastLine = false;
const bool bRepeat = rTab.GetTable()->IsHeadlineRepeat();
const bool bHasMoreLines = NULL != rLastLine.GetPrev() &&
( !bRepeat || rLastLine.GetPrev()->GetPrev() );
if ( bHasMoreLines ||
( !rTab.IsFollow() && rTab.GetIndPrev() && !rTab.GetFollow()->IsJoinLocked() ) )
{
//
// Check if each cell in the last line has at least on content frame.
// Otherwise we move the last line to the follow table.
//
SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower();
while ( pCurrMasterCell )
{
if ( !pCurrMasterCell->ContainsCntnt() )
{
bMoveLastLine = true;
break;
}
pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext();
}
//
// Check if table fits to its upper.
//
SwTwips nDistanceToUpperPrtBottom =
(rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)());
if ( nDistanceToUpperPrtBottom < 0 )
bMoveLastLine = true;
}
//
// Finally, we move the last line if necessary:
//
if ( bMoveLastLine )
{
// pLastLine has to be moved to the follow table:
rTab.SetFollowFlowLine( FALSE );
// The footnotes have to be moved:
lcl_MoveFootnotes( rTab, *rTab.GetFollow(), rLastLine );
rLastLine.Cut();
rLastLine.Paste( rTab.GetFollow(), &rFollowLine );
::SwInvalidateAll( &rLastLine, LONG_MAX );
lcl_MoveRowContent( rFollowLine, rLastLine );
rFollowLine.Cut();
delete &rFollowLine;
}
else
::SwInvalidateAll( &rFollowLine, LONG_MAX );
rTab.SetRebuildLastLine( FALSE );
//
// Do some checks if the table is in a good condition:
//
// bRet = false sets the bSplitError flag in SwTabFrm::MakeAll
// and avoids any further splitting operations for rTab.
//
//
// 1. If the new follow flow line is empty, we remove it:
//
if ( rTab.HasFollowFlowLine() && !rFollowLine.ContainsCntnt() )
{
lcl_RemoveFollowFlowLine( rTab );
rTab.SetFollowFlowLine( FALSE );
bRet = false;
}
//
// 2. Check if last row does not contain contents.
// If the last remaining line in rTab does not contain contents, that
// means that most probably a loop will occur. We prevent this by
// moving the first (regular) line from the follow table to rTab
// and return false:
//
SwFrm* pTmp = rTab.Lower();
while ( pTmp && pTmp->GetNext() )
pTmp = pTmp->GetNext();
if ( pTmp && !((SwRowFrm*)pTmp)->ContainsCntnt() )
{
SwFrm* pTmpRow = bRepeat ?
rTab.GetFollow()->Lower()->GetNext() :
rTab.GetFollow()->Lower();
if ( pTmpRow )
{
// Either pTmpRow is the follow flow line or there is no follow
// flow line. In both cases we can set bFollowFlowLine to FALSE:
rTab.SetFollowFlowLine( FALSE );
pTmpRow->Cut();
pTmpRow->Paste( &rTab, 0 );
// delete empty row frame:
pTmp->Cut();
delete pTmp;
bRet = false;
}
}
//
// 3. check if table is out of bounds:
//
SwTwips nDistanceToUpperPrtBottom =
(rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)());
if ( nDistanceToUpperPrtBottom < 0 )
bRet = false;
return bRet;
}
//
// 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 )
{
if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() )
{
SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower();
while ( pTmpSourceRow )
{
// TODO: recursion
pTmpSourceRow = (SwRowFrm*)pTmpSourceRow->GetNext();
}
}
else
{
const SwFrm *pTmp = pCurrSourceCell->Lower();
if ( pTmp && pTmp->IsTxtFrm() )
{
SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp;
pTxtFrm->GetFormatted();
SwTwips 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 if all first line heights;
SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)();
const SwFrm* pFrm = pPrevCell->Lower();
while ( pFrm )
{
nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
pFrm = pFrm->GetNext();
}
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();
}
}
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;
}
#ifndef OD_FLYFRAMES_FINISHED
bool lcl_FindObjectsInRow( const SwRowFrm& rRow )
{
bool bRet = false;
SwCellFrm* pLower = (SwCellFrm*)rRow.Lower();
while ( pLower )
{
SwFrm* pTmpFrm = pLower->Lower();
while ( pTmpFrm )
{
if ( pTmpFrm->IsRowFrm() )
bRet = lcl_FindObjectsInRow( *(SwRowFrm*)pTmpFrm );
else
bRet = 0 != pTmpFrm->GetDrawObjs() || pTmpFrm->IsSctFrm();
if ( bRet )
return true;
pTmpFrm = pTmpFrm->GetNext();
}
pLower = (SwCellFrm*)pLower->GetNext();
}
return bRet;
}
#endif
2000-09-18 23:08:29 +00:00
/*************************************************************************
|*
|* SwTabFrm::Split(), Join()
|*
|* Ersterstellung MA 03. Jun. 93
|* Letzte Aenderung MA 03. Sep. 96
|*
|*************************************************************************/
bool SwTabFrm::Split( const SwTwips nCutPos )
2000-09-18 23:08:29 +00:00
{
bool bRet = true;
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
2001-12-12 13:44:09 +00:00
ASSERT( bVert ? nCutPos >= Frm().Left()
&& nCutPos <= Frm().Left() + Frm().Width() :
2001-11-16 10:40:30 +00:00
nCutPos >= Frm().Top() && nCutPos <= Frm().Bottom(),
"SplitLine out of table." );
2000-09-18 23:08:29 +00:00
//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.
SwFrm *pRow = Lower();
if( !pRow )
return bRet;
2000-09-18 23:08:29 +00:00
const bool bRepeat = GetTable()->IsHeadlineRepeat();
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)() )
2001-11-16 10:40:30 +00:00
{
nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)();
2000-09-18 23:08:29 +00:00
pRow = pRow->GetNext();
}
//
// Check if pRow can be split:
//
bool bSplitRowAllowed = ((SwRowFrm*)pRow)->IsRowSplitAllowed();
#ifndef OD_FLYFRAMES_FINISHED
//
// Search for objects anchored at content inside pRow:
//
bool bObjectsFound = false;
if ( lcl_FindObjectsInRow( *(SwRowFrm*)pRow ) )
2000-09-18 23:08:29 +00:00
{
bObjectsFound = true;
bSplitRowAllowed = false;
}
2000-09-18 23:08:29 +00:00
#endif
if ( bRepeat && pRow == Lower() )
{
//
// First case: 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:
//
ASSERT( !GetIndPrev(), "Table is supposed to be at beginning" )
pRow = pRow->GetNext();
if ( pRow )
2000-09-18 23:08:29 +00:00
pRow = pRow->GetNext();
bSplitRowAllowed = false;
2000-09-18 23:08:29 +00:00
}
else if ( !GetIndPrev() &&
( ( bRepeat && pRow == Lower()->GetNext() ||
!bRepeat && pRow == Lower() ) ) )
{
//
// 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 change the attribute for this row:
//
if ( !bSplitRowAllowed )
{
#ifndef OD_FLYFRAMES_FINISHED
if ( bObjectsFound )
{
// The first non-heading row does not fit to the page.
// It contains objects, therefore it is (currently) not splittable.
// We keep this row in this table:
pRow = pRow->GetNext();
}
else
{
#endif
2000-09-18 23:08:29 +00:00
// Change attributes:
ASSERT( false, "Weird layout! Row frame is to big but not allowed to split. I'll change the attributes now." )
lcl_ChangeSplitAttribute( *(SwRowFrm*)pRow );
bSplitRowAllowed = true;
#ifndef OD_FLYFRAMES_FINISHED
}
#endif
}
// Check if there are (first) rows inside this row,
// which are not allowed to be split.
SwCellFrm* pLower = pRow ? (SwCellFrm*)((SwRowFrm*)pRow)->Lower() : 0;
while ( pLower )
{
if ( pLower->Lower() && pLower->Lower()->IsRowFrm() )
{
const SwRowFrm* pLowerRow = (SwRowFrm*)pLower->Lower();
if ( !pLowerRow->IsRowSplitAllowed() &&
(pLowerRow->Frm().*fnRect->fnGetHeight)() >
nRemainingSpaceForLastRow )
{
// Change attributes:
ASSERT( false, "Weird layout! Row frame is to big but not allowed to split. I'll change the attributes now." )
lcl_ChangeSplitAttribute( *(SwRowFrm*)pLowerRow );
}
}
pLower = (SwCellFrm*)pLower->GetNext();
}
}
//
// No more row to split or to move to follow table:
//
if ( !pRow )
return bRet;
//
// Build follow table if not already done:
//
2000-09-18 23:08:29 +00:00
FASTBOOL bNewFollow;
SwTabFrm *pFoll;
if ( GetFollow() )
{
pFoll = GetFollow();
bNewFollow = FALSE;
}
else
{
bNewFollow = 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)() );
2000-09-18 23:08:29 +00:00
pFoll->InsertBehind( GetUpper(), this );
if( bRepeat )
{ //Ueberschrift wiederholen.
ASSERT( GetTable()->GetTabLines()[0], "Table ohne Zeilen?" );
bDontCreateObjects = TRUE; //frmtool
SwRowFrm *pHeadline = new SwRowFrm(
*GetTable()->GetTabLines()[0] );
bDontCreateObjects = FALSE;
pHeadline->InsertBefore( pFoll, 0 );
SwPageFrm *pPage = pHeadline->FindPageFrm();
const SwSpzFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts();
if( pTbl->Count() )
{
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;
}
}
2000-09-18 23:08:29 +00:00
}
}
// If the row that does not fit anymore is allowed
// to be split, the next row has to be moved to the follow table.
SwRowFrm* pLastRow = (SwRowFrm*)pRow;
SwRowFrm* pFollowRow = 0;
if ( bSplitRowAllowed )
{
pRow = pRow->GetNext();
// new follow flow line for last row of master table
pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, bRepeat );
}
2000-09-18 23:08:29 +00:00
SwTwips nRet = 0;
SwFrm* pNxt;
SwFrm* pPrv;
2000-09-18 23:08:29 +00:00
//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 )
{
if ( bSplitRowAllowed )
{
pPrv = pFoll->Lower();
if ( pPrv && GetTable()->IsHeadlineRepeat() )
pPrv = pPrv->GetNext();
}
else
pPrv = GetTable()->IsHeadlineRepeat() ? pFoll->Lower() : 0;
2000-09-18 23:08:29 +00:00
while ( pRow )
{
pNxt = pRow->GetNext();
2001-11-16 10:40:30 +00:00
nRet += (pRow->Frm().*fnRect->fnGetHeight)();
// The footnotes do not have to be moved, this is done in the
// MoveFwd of the follow table!!!
2000-09-18 23:08:29 +00:00
pRow->Remove();
pRow->InsertBehind( pFoll, pPrv );
pRow->_InvalidateAll();
pPrv = pRow;
pRow = pNxt;
}
}
else
{
pPrv = pFoll->Lower();
2000-09-18 23:08:29 +00:00
if ( pPrv && GetTable()->IsHeadlineRepeat() )
pPrv = pPrv->GetNext();
if ( bSplitRowAllowed )
{
pPrv = pPrv->GetNext();
}
2000-09-18 23:08:29 +00:00
while ( pRow )
{
pNxt = pRow->GetNext();
2001-11-16 10:40:30 +00:00
nRet += (pRow->Frm().*fnRect->fnGetHeight)();
// The footnotes have to be moved:
lcl_MoveFootnotes( *this, *GetFollow(), (SwRowFrm&)*pRow );
2001-11-16 10:40:30 +00:00
pRow->Remove();
pRow->Paste( pFoll, pPrv );
2001-11-16 10:40:30 +00:00
pRow->CheckDirChange();
pRow = pNxt;
}
}
2001-11-16 10:40:30 +00:00
Shrink( nRet );
// we build a new last line to assure that it will be fully formatted
if ( bSplitRowAllowed )
{
ASSERT( pFollowRow, "Table Split: FollowFlowRow is missing" )
// recalculate the split line
bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow );
}
return bRet;
2000-09-18 23:08:29 +00:00
}
bool SwTabFrm::Join()
2000-09-18 23:08:29 +00:00
{
ASSERT( !HasFollowFlowLine(), "Joining follow flow line" )
2000-09-18 23:08:29 +00:00
SwTabFrm *pFoll = GetFollow();
SwTwips nHeight = 0; //Gesamthoehe der eingefuegten Zeilen als Return.
if ( !pFoll->IsJoinLocked() )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
2000-09-18 23:08:29 +00:00
pFoll->Cut(); //Erst ausschneiden um unuetze Benachrichtigungen zu
//minimieren.
SwFrm *pRow = pFoll->Lower(),
*pNxt;
if ( pRow && GetTable()->IsHeadlineRepeat() )
pRow = pRow->GetNext();
SwFrm *pPrv = Lower();
while ( pPrv && pPrv->GetNext() )
pPrv = pPrv->GetNext();
2000-09-18 23:08:29 +00:00
while ( pRow )
{
pNxt = pRow->GetNext();
2001-11-16 10:40:30 +00:00
nHeight += (pRow->Frm().*fnRect->fnGetHeight)();
2000-09-18 23:08:29 +00:00
pRow->Remove();
pRow->_InvalidateAll();
pRow->InsertBehind( this, pPrv );
2001-11-16 10:40:30 +00:00
pRow->CheckDirChange();
2000-09-18 23:08:29 +00:00
pPrv = pRow;
pRow = pNxt;
}
2000-09-18 23:08:29 +00:00
SetFollow( pFoll->GetFollow() );
SetFollowFlowLine( pFoll->HasFollowFlowLine() );
2000-09-18 23:08:29 +00:00
delete pFoll;
2001-10-19 09:25:19 +00:00
Grow( nHeight PHEIGHT );
2000-09-18 23:08:29 +00:00
}
return true;
2000-09-18 23:08:29 +00:00
}
/*************************************************************************
|*
|* SwTabFrm::MakeAll()
|*
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 10. Apr. 97
|*
|*************************************************************************/
void MA_FASTCALL SwInvalidatePositions( SwFrm *pFrm, long nBottom )
{
// LONG_MAX == nBottom means we have to calculate all
BOOL bAll = LONG_MAX == nBottom;
2001-11-16 10:40:30 +00:00
SWRECTFN( pFrm )
2000-09-18 23:08:29 +00:00
do
{ pFrm->_InvalidatePos();
pFrm->_InvalidateSize();
if( pFrm->IsLayoutFrm() )
{
if ( ((SwLayoutFrm*)pFrm)->Lower() )
::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom);
}
else
pFrm->Prepare( PREP_ADJUST_FRM );
pFrm = pFrm->GetNext();
} while ( pFrm &&
( bAll ||
(*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
2000-09-18 23:08:29 +00:00
}
void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom )
{
// LONG_MAX == nBottom means we have to calculate all
BOOL bAll = LONG_MAX == nBottom;
SWRECTFN( pFrm )
do
{ pFrm->_InvalidatePos();
pFrm->_InvalidateSize();
pFrm->_InvalidatePrt();
if( pFrm->IsLayoutFrm() )
{
if ( ((SwLayoutFrm*)pFrm)->Lower() )
::SwInvalidateAll( ((SwLayoutFrm*)pFrm)->Lower(), nBottom);
}
else
pFrm->Prepare( PREP_CLEAR );
pFrm = pFrm->GetNext();
} while ( pFrm &&
( bAll ||
(*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) );
}
2000-09-18 23:08:29 +00:00
BOOL MA_FASTCALL lcl_CalcLowers( SwLayoutFrm *pLay, long nBottom )
{
if ( !pLay )
return TRUE;
// LONG_MAX == nBottom means we have to calculate all
BOOL bAll = LONG_MAX == nBottom;
2000-09-18 23:08:29 +00:00
BOOL bRet = FALSE;
SwCntntFrm *pCnt = pLay->ContainsCntnt();
2001-11-16 10:40:30 +00:00
SWRECTFN( pLay )
2000-09-18 23:08:29 +00:00
while ( pCnt && pLay->GetUpper()->IsAnLower( pCnt ) )
{
bRet |= !pCnt->IsValid();
pCnt->CalcFlys( FALSE );
pCnt->Calc();
pCnt->GetUpper()->Calc();
if( ! bAll && (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 )
2000-09-18 23:08:29 +00:00
break;
pCnt = pCnt->GetNextCntntFrm();
}
return bRet;
}
BOOL MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, long nBottom )
{
// LONG_MAX == nBottom means we have to calculate all
BOOL bAll = LONG_MAX == nBottom;
2000-09-18 23:08:29 +00:00
BOOL bRet = FALSE;
2001-10-19 09:25:19 +00:00
const SwFrm* pOldUp = pFrm->GetUpper();
2001-11-16 10:40:30 +00:00
SWRECTFN( pFrm )
2000-09-18 23:08:29 +00:00
do
{
if( pFrm->IsLayoutFrm() )
{
bRet |= !pFrm->IsValid();
pFrm->Calc();
if( ((SwLayoutFrm*)pFrm)->Lower() )
bRet |= lcl_InnerCalcLayout( ((SwLayoutFrm*)pFrm)->Lower(), nBottom);
}
pFrm = pFrm->GetNext();
2001-11-16 10:40:30 +00:00
} while( pFrm &&
( bAll ||
(*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 )
2001-11-16 10:40:30 +00:00
&& pFrm->GetUpper() == pOldUp );
2000-09-18 23:08:29 +00:00
return bRet;
}
void MA_FASTCALL lcl_CalcLayout( SwLayoutFrm *pLay, long nBottom )
{
BOOL bCheck = TRUE;
do
{
while( lcl_InnerCalcLayout( pLay, nBottom ) )
bCheck = TRUE;
if( bCheck )
{
bCheck = FALSE;
if( lcl_CalcLowers( pLay, nBottom ) )
continue;
}
break;
} while( TRUE );
}
void MA_FASTCALL lcl_FirstTabCalc( SwTabFrm *pTab )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( pTab )
if ( !pTab->IsFollow() && !pTab->GetTable()->IsTblComplex() )
{
SwLayoutFrm *pRow = (SwLayoutFrm*)pTab->Lower();
do
{
SwLayoutFrm *pCell = (SwLayoutFrm*)pRow->Lower();
SwFrm *pCnt = pCell->Lower();
pCnt->Calc();
const long nCellHeight = (pCell->Frm().*fnRect->fnGetHeight)();
const long nCellY = (pCell->Frm().*fnRect->fnGetTop)()-1;
const long nCntHeight = (pCnt->Frm().*fnRect->fnGetHeight)();
const long nCntY = (pCnt->Frm().*fnRect->fnGetTop)()-1;
if ( 0 != (pCell = (SwLayoutFrm*)pCell->GetNext()) )
do
{ (pCell->Frm().*fnRect->fnSetTopAndHeight)
( nCellY, nCellHeight );
(pCell->Prt().*fnRect->fnSetHeight)( nCellHeight );
pCell->_InvalidateAll();
pCnt = pCell->Lower();
(pCnt->Frm().*fnRect->fnSetTopAndHeight)(nCntY, nCntHeight);
(pCnt->Prt().*fnRect->fnSetHeight)( nCntHeight );
pCnt->_InvalidateAll();
pCell = (SwLayoutFrm*)pCell->GetNext();
} while ( pCell );
SwTwips nRowTop = (pRow->Frm().*fnRect->fnGetTop)();
SwTwips nUpBot = (pTab->GetUpper()->Frm().*fnRect->fnGetBottom)();
if( (*fnRect->fnYDiff)( nUpBot, nRowTop ) < 0 )
break;
pRow = (SwLayoutFrm*)pRow->GetNext();
} while ( pRow );
}
SwFrm *pUp = pTab->GetUpper();
2001-12-12 13:44:09 +00:00
long nBottom = (pUp->*fnRect->fnGetPrtBottom)();
2001-11-16 10:40:30 +00:00
if ( pTab->GetFmt()->GetDoc()->IsBrowseMode() )
nBottom += pUp->Grow( LONG_MAX, TRUE );
lcl_CalcLowers( (SwLayoutFrm*)pTab->Lower(), LONG_MAX );
2000-09-18 23:08:29 +00:00
}
void MA_FASTCALL lcl_Recalc( SwTabFrm *pTab,
SwLayoutFrm *pFirstRow,
SwLayNotify &rNotify )
{
if ( pTab->Lower() )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( pTab )
const SwTwips nOldHeight = (pTab->Frm().*fnRect->fnGetHeight)();
const SwTwips nOldWidth = (pTab->Frm().*fnRect->fnGetWidth)();
if ( !pFirstRow )
{
pFirstRow = (SwLayoutFrm*)pTab->Lower();
rNotify.SetLowersComplete( TRUE );
}
::SwInvalidatePositions( pFirstRow, LONG_MAX );
::lcl_CalcLayout( pFirstRow, LONG_MAX );
2000-09-18 23:08:29 +00:00
}
}
// 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 )
{
if ( rFrm.GetPrev() )
return false;
if ( !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;
}
2000-09-18 23:08:29 +00:00
#define KEEPTAB ( !GetFollow() && !IsFollow() )
void SwTabFrm::MakeAll()
{
if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
return;
if ( HasFollow() )
{
SwTabFrm* pFollow = (SwTabFrm*)GetFollow();
ASSERT( !pFollow->IsJoinLocked() || !pFollow->IsRebuildLastLine(),
"SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" )
if ( pFollow->IsJoinLocked() && pFollow->IsRebuildLastLine() )
return;
}
2001-10-19 09:25:19 +00:00
PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
2000-09-18 23:08:29 +00:00
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 BOOL bOldValidPos = GetValidPosFlag();
2000-09-18 23:08:29 +00:00
//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() )
lcl_RemoveFollowFlowLine( *this );
Join();
}
// The bRemoveFollowFlowLinePending is set if the split attribute of the
// last line is set:
if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() )
{
lcl_RemoveFollowFlowLine( *this );
SetRemoveFollowFlowLinePending( FALSE );
}
2000-09-18 23:08:29 +00:00
if ( bResizeHTMLTable ) //Optimiertes Zusammenspiel mit Grow/Shrink des Inhaltes
{
bResizeHTMLTable = FALSE;
SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
if ( pLayout )
bCalcLowers = pLayout->Resize(
pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
}
BOOL bMakePage = TRUE; //solange TRUE kann eine neue Seite
//angelegt werden (genau einmal)
BOOL bMovedBwd = FALSE; //Wird TRUE wenn der Frame zurueckfliesst
BOOL bMovedFwd = FALSE; //solange FALSE kann der Frm zurueck-
//fliessen (solange, bis er einmal
//vorwaerts ge'moved wurde).
BOOL bSplit = FALSE; //Wird TRUE wenn der Frm gesplittet wurde.
const BOOL bFtnsInDoc = 0 != GetFmt()->GetDoc()->GetFtnIdxs().Count();
2000-09-18 23:08:29 +00:00
BOOL bMoveable;
const BOOL bFly = IsInFly();
SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
const SwBorderAttrs *pAttrs = pAccess->Get();
const BOOL bKeep = IsKeep( *pAttrs );
// All rows should keep together
2000-09-18 23:08:29 +00:00
const BOOL bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue();
// This flag indicates that an error (e.g., oversized heading row)
// occured during the split operation.
bool bSplitError = false;
2000-09-18 23:08:29 +00:00
if ( bDontSplit )
{
while ( GetFollow() && !GetFollow()->IsJoinLocked() )
{
if ( HasFollowFlowLine() )
lcl_RemoveFollowFlowLine( *this );
Join();
}
}
2000-09-18 23:08:29 +00:00
//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, FALSE ) )
bMakePage = FALSE;
bMovedFwd = TRUE;
}
}
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
2000-09-18 23:08:29 +00:00
while ( !bValidPos || !bValidSize || !bValidPrtArea )
{
if ( TRUE == (bMoveable = IsMoveable()) )
if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) )
{
bMovedFwd = TRUE;
bCalcLowers = TRUE;
}
2001-11-16 10:40:30 +00:00
Point aOldPos( (Frm().*fnRect->fnGetPos)() );
MakePos();
2001-11-16 10:40:30 +00:00
if ( aOldPos != (Frm().*fnRect->fnGetPos)() )
{
if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() )
2000-09-18 23:08:29 +00:00
{
SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
if( pLayout )
{
delete pAccess;
bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
2000-09-18 23:08:29 +00:00
pAttrs = pAccess->Get();
}
bValidPrtArea = FALSE;
aNotify.SetLowersComplete( FALSE );
}
SwFrm *pPre;
if ( bKeep || (0 != (pPre = FindPrev()) &&
pPre->GetAttrSet()->GetKeep().GetValue()) )
{
bCalcLowers = TRUE;
}
}
//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 = Lower();
if ( GetTable()->IsHeadlineRepeat() && pFrm )
2000-09-18 23:08:29 +00:00
pFrm = pFrm->GetNext();
if ( pFrm )
2001-11-16 10:40:30 +00:00
n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)();
}
if ( !bValidSize || !bValidPrtArea )
{
const BOOL bOptLower = (Frm().*fnRect->fnGetHeight)() == 0;
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 ( /*!bOptLower &&*/ pLayout &&
((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth ||
(Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) )
2000-09-18 23:08:29 +00:00
{
delete pAccess;
bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrm( *this ), FALSE );
// GetFmt()->GetDoc()->GetDocShell()->IsReadOnly() ? FALSE : TRUE );
pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
pAttrs = pAccess->Get();
}
2001-11-16 10:40:30 +00:00
if ( !bOptLower && aOldPrtPos != (Prt().*fnRect->fnGetPos)() )
2000-09-18 23:08:29 +00:00
aNotify.SetLowersComplete( FALSE );
if ( bOptLower && Lower() )
2000-09-18 23:08:29 +00:00
{
//MA 24. May. 95: Optimierungsversuch!
//Ganz nigel nagel neu das Teil. Damit wir nicht n-fach
//MakeAll'en formatieren wir flugs den Inhalt.
//Das erste Format mussten wir allerdings abwarten, damit
//die Breiten Stimmen!
//MA: Fix, Kein Calc wenn evtl. noch Seitengebunde Flys
//an den Cntnt haengen (siehe frmtool.cxx, ~SwCntntNotify).
SwDoc *pDoc = GetFmt()->GetDoc();
if ( !pDoc->GetSpzFrmFmts()->Count() ||
pDoc->IsLoaded() || pDoc->IsNewDoc() )
{
//MA 28. Nov. 95: Und wieder ein Trick, gleich mal sehen
//ob ein Rueckfluss lohnt.
if ( bMoveable && !GetPrev() )
{
GetLeaf( MAKEPAGE_NONE, FALSE ); //setzt das BackMoveJump
if ( SwFlowFrm::IsMoveBwdJump() )
{
BOOL bDummy;
SwFtnBossFrm *pOldBoss = bFtnsInDoc ?
FindFtnBossFrm( TRUE ) : 0;
const FASTBOOL bOldPrev = GetPrev() != 0;
if ( MoveBwd( bDummy ) )
{
2001-11-16 10:40:30 +00:00
SWREFRESHFN( this )
2000-09-18 23:08:29 +00:00
bMovedBwd = TRUE;
if ( bFtnsInDoc )
MoveLowerFtns( 0, pOldBoss, 0, TRUE );
2001-11-16 10:40:30 +00:00
long nOldTop = (Frm().*fnRect->fnGetTop)();
MakePos();
if( nOldTop != (Frm().*fnRect->fnGetTop)() )
2000-09-18 23:08:29 +00:00
{
SwHTMLTableLayout *pLayout =
GetTable()->GetHTMLTableLayout();
if( pLayout )
{
delete pAccess;
bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrm(
*this ), FALSE );
pAccess= new SwBorderAttrAccess(
SwFrm::GetCache(), this );
pAttrs = pAccess->Get();
}
}
if ( bOldPrev != (0 != GetPrev()) )
{
//Abstand nicht vergessen!
bValidPrtArea = FALSE;
Format( pAttrs );
}
if ( bKeep && KEEPTAB )
{
SwFrm *pNxt = FindNextCnt();
// FindNextCnt geht ggf. in einen Bereich
// hinein, in eine Tabelle allerdings auch
if( pNxt && pNxt->IsInTab() )
pNxt = pNxt->FindTabFrm();
if ( pNxt )
{
pNxt->Calc();
if ( !GetNext() )
bValidPos = FALSE;
}
}
}
}
}
::lcl_FirstTabCalc( this );
bValidSize = bValidPrtArea = FALSE;
Format( pAttrs );
aNotify.SetLowersComplete( TRUE );
}
}
}
//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 ) )
2000-09-18 23:08:29 +00:00
{
//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 = Lower();
if ( GetTable()->IsHeadlineRepeat() && pFrm )
2000-09-18 23:08:29 +00:00
pFrm = pFrm->GetNext();
2001-11-16 10:40:30 +00:00
if(pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight)())
2000-09-18 23:08:29 +00:00
{
SwTabFrm *pMaster = (SwTabFrm*)FindMaster();
BOOL bDummy;
if ( ShouldBwdMoved( pMaster->GetUpper(), FALSE, bDummy ) )
pMaster->InvalidatePos();
}
}
SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( TRUE ) : 0;
BOOL bReformat;
if ( MoveBwd( bReformat ) )
{
2001-11-16 10:40:30 +00:00
SWREFRESHFN( this )
2000-09-18 23:08:29 +00:00
bMovedBwd = TRUE;
aNotify.SetLowersComplete( FALSE );
if ( bFtnsInDoc )
MoveLowerFtns( 0, pOldBoss, 0, TRUE );
if ( bReformat || bKeep )
{
2001-11-16 10:40:30 +00:00
long nOldTop = (Frm().*fnRect->fnGetTop)();
MakePos();
if( nOldTop != (Frm().*fnRect->fnGetTop)() )
2000-09-18 23:08:29 +00:00
{
SwHTMLTableLayout *pLayout =
GetTable()->GetHTMLTableLayout();
if( pLayout )
{
delete pAccess;
bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrm( *this ),
FALSE );
pAccess= new SwBorderAttrAccess(
SwFrm::GetCache(), this );
pAttrs = pAccess->Get();
}
bValidPrtArea = FALSE;
Format( pAttrs );
}
::lcl_Recalc( this, 0, aNotify );
bLowersFormatted = TRUE;
if ( bKeep && KEEPTAB )
{
SwFrm *pNxt = FindNextCnt();
if( pNxt && pNxt->IsInTab() )
pNxt = pNxt->FindTabFrm();
if ( pNxt )
{
pNxt->Calc();
if ( !GetNext() )
bValidPos = 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.
if ( nDistanceToUpperPrtBottom < 0 &&
GetFmt()->GetDoc()->IsBrowseMode() )
{
if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) )
{
// upper is grown --> recalculate <nDistanceToUpperPrtBottom>
nDistanceToUpperPrtBottom =
(Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)());
}
}
if( nDistanceToUpperPrtBottom >= 0 )
/* if( ( bSplit && nDistanceToUpperPrtBottom == 0 ) ||
nDistanceToUpperPrtBottom > 0 )
*/ {
// 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.
2000-09-18 23:08:29 +00:00
if ( !bSplit && GetFollow() )
{
BOOL bDummy;
if ( GetFollow()->ShouldBwdMoved( GetUpper(), FALSE, bDummy ) )
{
SwFrm *pTmp = GetUpper();
2001-12-12 13:44:09 +00:00
SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)();
2001-11-16 10:40:30 +00:00
if ( GetFmt()->GetDoc()->IsBrowseMode() )
nDeadLine += pTmp->Grow( LONG_MAX, TRUE );
2001-12-12 13:44:09 +00:00
if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 )
2001-11-16 10:40:30 +00:00
{
//
// First, we remove an existing follow flow line.
//
if ( HasFollowFlowLine() )
{
lcl_RemoveFollowFlowLine( *this );
// invalidate and rebuild last row
SwFrm* pLastLine = Lower();
while ( pLastLine->GetNext() )
pLastLine = pLastLine->GetNext();
::SwInvalidateAll( pLastLine, LONG_MAX );
SetRebuildLastLine( TRUE );
::lcl_CalcLayout( (SwLayoutFrm*)pLastLine, LONG_MAX );
SetRebuildLastLine( FALSE );
SwFrm *pRow = GetFollow()->Lower();
if ( GetTable()->IsHeadlineRepeat() )
pRow = pRow->GetNext();
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.
//
2001-11-16 10:40:30 +00:00
SwFrm *pRow = GetFollow()->Lower();
if ( GetTable()->IsHeadlineRepeat() )
2001-11-16 10:40:30 +00:00
pRow = pRow->GetNext();
2001-11-16 10:40:30 +00:00
const SwTwips nOld = (Frm().*fnRect->fnGetHeight)();
2000-09-18 23:08:29 +00:00
const BOOL bMoveFtns = bFtnsInDoc && pRow &&
!GetFollow()->IsJoinLocked();
SwFtnBossFrm *pOldBoss;
if ( bMoveFtns )
pOldBoss = pRow->FindFtnBossFrm( TRUE );
//fix(8680): Row kann 0 werden.
if ( !pRow || !pRow->GetNext() )
//Der Follow wird leer und damit ueberfluessig.
Join();
2000-09-18 23:08:29 +00:00
else
{
pRow->Cut();
pRow->Paste( this );
}
//Die Fussnoten verschieben!
if ( pRow && bMoveFtns )
if ( ((SwLayoutFrm*)pRow)->MoveLowerFtns(
0, pOldBoss, FindFtnBossFrm( TRUE ), TRUE ) )
GetUpper()->Calc();
2001-11-16 10:40:30 +00:00
if ( pRow && nOld != (Frm().*fnRect->fnGetHeight)() )
2000-09-18 23:08:29 +00:00
::lcl_Recalc( this, (SwLayoutFrm*)pRow, aNotify );
continue;
}
}
}
else if ( bKeep && KEEPTAB )
{
SwFrm *pNxt = FindNextCnt();
if( pNxt && pNxt->IsInTab() )
pNxt = pNxt->FindTabFrm();
if ( pNxt )
pNxt->Calc();
}
if ( IsValid() )
{
if ( bCalcLowers )
{
::lcl_Recalc( this, 0, aNotify );
bLowersFormatted = TRUE;
bCalcLowers = FALSE;
}
else if ( bONECalcLowers )
{
lcl_CalcLayout( (SwLayoutFrm*)Lower(), LONG_MAX );
bONECalcLowers = 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_Recalc( this, 0, aNotify );
bLowersFormatted = TRUE;
bCalcLowers = FALSE;
}
else if ( bONECalcLowers )
{
lcl_CalcLayout( (SwLayoutFrm*)Lower(), LONG_MAX );
bONECalcLowers = FALSE;
}
continue;
}
if ( bCalcLowers && IsValid() )
{
::lcl_Recalc( this, 0, aNotify );
bLowersFormatted = TRUE;
bCalcLowers = FALSE;
if( !IsValid() )
continue;
}
2000-09-18 23:08:29 +00:00
//Der erste Versuch muss natuerlich das Aufspalten der Tabelle sein.
//Das funktioniert natuerlich nur dann, wenn die Tabelle mehr als eine
//Zeile enthaelt und wenn die Unterkante des Upper unter der ersten
//Zeile liegt.
SwFrm *pIndPrev = GetIndPrev();
if ( !bSplitError && ( !bDontSplit || !pIndPrev ) )
2000-09-18 23:08:29 +00:00
{
// only try to break table if there is at least one non-headline row
if ( !GetTable()->IsHeadlineRepeat() || Lower()->GetNext() )
2000-09-18 23:08:29 +00:00
{
2001-12-12 13:44:09 +00:00
SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
2001-11-16 10:40:30 +00:00
if( IsInSct() )
nDeadLine = (*fnRect->fnYInc)( nDeadLine,
GetUpper()->Grow( LONG_MAX, TRUE ) );
2001-11-16 10:40:30 +00:00
::lcl_CalcLayout( (SwLayoutFrm*)Lower(), nDeadLine );
bLowersFormatted = TRUE;
aNotify.SetLowersComplete( TRUE );
2001-12-12 13:44:09 +00:00
if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 )
2001-11-16 10:40:30 +00:00
continue;
SwTwips nBreakLine = (Frm().*fnRect->fnGetTop)();
2001-11-16 10:40:30 +00:00
nBreakLine = (*fnRect->fnYInc)( nBreakLine,
(this->*fnRect->fnGetTopMargin)() +
( GetTable()->IsHeadlineRepeat() ? (Lower()->Frm().*fnRect->fnGetHeight)() : 0 ) );
2001-11-16 10:40:30 +00:00
if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev )
2000-09-18 23:08:29 +00:00
{
//
// An existing follow flow line has to be removed.
//
if ( HasFollowFlowLine() )
lcl_RemoveFollowFlowLine( *this );
bSplitError = !Split( nDeadLine );
// Caution: The follow now can be empty:
if ( GetFollow() )
{
if ( !GetFollow()->Lower() ||
( GetTable()->IsHeadlineRepeat() && !GetFollow()->Lower()->GetNext() ) )
Join();
}
2000-09-18 23:08:29 +00:00
aNotify.SetLowersComplete( FALSE );
bSplit = TRUE;
//Damit es nicht zu Oszillationen kommt, muss der
//Follow gleich gueltig gemacht werden.
if ( GetFollow() )
{
SWRECTFN( GetFollow() )
2001-10-19 09:25:19 +00:00
static BYTE nStack = 0;
if ( !StackHack::IsLocked() && nStack < 4 )
2000-09-18 23:08:29 +00:00
{
2001-10-19 09:25:19 +00:00
++nStack;
2000-09-18 23:08:29 +00:00
StackHack aHack;
2001-05-18 08:26:14 +00:00
delete pAccess;
2000-09-18 23:08:29 +00:00
GetFollow()->MakeAll();
pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this );
2001-05-18 08:26:14 +00:00
pAttrs = pAccess->Get();
2000-09-18 23:08:29 +00:00
((SwTabFrm*)GetFollow())->SetLowersFormatted(FALSE);
::lcl_CalcLayout((SwLayoutFrm*)GetFollow()->Lower(),
(GetFollow()->GetUpper()->Frm().*fnRect->fnGetBottom)() );
2000-09-18 23:08:29 +00:00
if ( !GetFollow()->GetFollow() )
{
SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext();
2000-09-18 23:08:29 +00:00
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();
}
}
2000-09-18 23:08:29 +00:00
}
2001-10-19 09:25:19 +00:00
--nStack;
2000-09-18 23:08:29 +00:00
}
else if ( GetFollow() == GetNext() )
((SwTabFrm*)GetFollow())->MoveFwd( TRUE, FALSE );
ViewShell *pSh;
if ( 0 != (pSh = GetShell()) )
pSh->Imp()->ResetScroll();
}
// If the split operation results in an empty master
// tab frame, the whole tab frame has to move forward.
if ( !bSplit || ( Lower() && ( !GetTable()->IsHeadlineRepeat() || Lower()->GetNext() ) ) )
continue;
2000-09-18 23:08:29 +00:00
}
}
}
if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() &&
GetUpper()->GetUpper()->GetUpper()->IsSctFrm() &&
( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
bMovedFwd = FALSE;
//Mal sehen ob ich irgenwo Platz finde...
if ( !bMovedFwd && !MoveFwd( bMakePage, FALSE ) )
bMakePage = FALSE;
2001-11-16 10:40:30 +00:00
SWREFRESHFN( this )
2000-09-18 23:08:29 +00:00
bMovedFwd = bCalcLowers = TRUE;
aNotify.SetLowersComplete( 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( FALSE );
}
//Wenn mein direkter Nachbar jetzt gleichzeitig mein Follow ist
//verleibe ich mir das Teil ein.
if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
{
if ( HasFollowFlowLine() )
lcl_RemoveFollowFlowLine( *this );
if ( GetFollow() ) Join();
}
2000-09-18 23:08:29 +00:00
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() )
{
::lcl_Recalc( this, 0, aNotify );
bLowersFormatted = TRUE;
bCalcLowers = FALSE;
}
} //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 = FALSE;
delete pAccess;
UnlockJoin();
if ( bMovedFwd || bMovedBwd || !bOldValidPos )
2000-09-18 23:08:29 +00:00
aNotify.SetInvaKeep();
}
/*************************************************************************
|*
|* SwTabFrm::CalcFlyOffsets()
|*
|* Beschreibung: Berechnet die Offsets, die durch FlyFrames
|* entstehen.
|* Ersterstellung MA/MIB 14. Apr. 99
|* Letzte Aenderung
|*
|*************************************************************************/
BOOL SwTabFrm::CalcFlyOffsets( SwTwips& rUpper,
long& rLeftOffset,
long& rRightOffset ) const
{
BOOL bInvalidatePrtArea = FALSE;
const SwPageFrm *pPage = FindPageFrm();
const SwFlyFrm* pMyFly = FindFlyFrm();
if ( pPage->GetSortedObjs() )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
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 ( USHORT i = 0; i < pPage->GetSortedObjs()->Count(); ++i )
{
SdrObject *pObj = (*pPage->GetSortedObjs())[i];
if ( pObj->ISA(SwVirtFlyDrawObj) )
2001-11-16 10:40:30 +00:00
{
SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm();
const SwRect aFlyRect = pFly->AddSpacesToFrm();
if ( WEIT_WECH != (pFly->Frm().*fnRect->fnGetTop)() &&
pFly->IsFlyAtCntFrm() && aFlyRect.IsOver( aRect ) &&
// OD 25.02.2003 #i9040# - use '<=' instead of '<'
2001-11-16 10:40:30 +00:00
(*fnRect->fnYDiff)(
(pFly->GetAnchor()->Frm().*fnRect->fnGetBottom)(),
(Frm().*fnRect->fnGetTop)() ) <= 0 &&
2001-11-16 10:40:30 +00:00
!IsAnLower( pFly ) && !pFly->IsAnLower( this ) &&
( !pMyFly || pMyFly->IsAnLower( pFly ) ) &&
pPage->GetPhyPageNum() >=
pFly->GetAnchor()->FindPageFrm()->GetPhyPageNum() &&
// anchor should be in same page body/header/footer
( pFly->GetAnchor()->FindFooterOrHeader() ==
FindFooterOrHeader() ) )
2001-11-16 10:40:30 +00:00
{
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 = TRUE;
}
if ( (SURROUND_RIGHT == rSur.GetSurround() ||
SURROUND_PARALLEL == rSur.GetSurround())&&
HORI_LEFT == rHori.GetHoriOrient() )
{
const long nWidth = (*fnRect->fnXDiff)(
(aFlyRect.*fnRect->fnGetRight)(),
(pFly->GetAnchor()->Frm().*fnRect->fnGetLeft)() );
rLeftOffset = Max( rLeftOffset, nWidth );
bInvalidatePrtArea = TRUE;
}
if ( (SURROUND_LEFT == rSur.GetSurround() ||
SURROUND_PARALLEL == rSur.GetSurround())&&
HORI_RIGHT == rHori.GetHoriOrient() )
{
const long nWidth = (*fnRect->fnXDiff)(
(pFly->GetAnchor()->Frm().*fnRect->fnGetRight)(),
(aFlyRect.*fnRect->fnGetLeft)() );
rRightOffset = Max( rRightOffset, nWidth );
bInvalidatePrtArea = TRUE;
}
}
}
}
rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() );
2000-09-18 23:08:29 +00:00
}
return bInvalidatePrtArea;
}
/*************************************************************************
|*
|* SwTabFrm::Format()
|*
|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea
|* Die Fixsize wird hier nicht eingestellt.
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 18. Jun. 97
|*
|*************************************************************************/
void SwTabFrm::Format( const SwBorderAttrs *pAttrs )
{
ASSERT( pAttrs, "TabFrm::Format, pAttrs ist 0." );
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
if ( !bValidSize )
{
long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() -
(Frm().*fnRect->fnGetWidth)();
if( nDiff )
(aFrm.*fnRect->fnAddRight)( nDiff );
}
2000-09-18 23:08:29 +00:00
//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,
2000-09-18 23:08:29 +00:00
nLeftOffset = 0;
if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
2000-09-18 23:08:29 +00:00
bValidPrtArea = FALSE;
long nRightOffset = Max( 0L, nTmpRight );
2000-09-18 23:08:29 +00:00
SwTwips nLower = pAttrs->CalcBottomLine();
if ( !bValidPrtArea )
{ bValidPrtArea = 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.
2001-11-16 10:40:30 +00:00
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();
2000-09-18 23:08:29 +00:00
//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, TRUE );
2000-09-18 23:08:29 +00:00
BOOL bCheckBrowseWidth = FALSE;
// OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
SwTwips nLeftSpacing = 0;
SwTwips nRightSpacing = 0;
2000-09-18 23:08:29 +00:00
switch ( GetFmt()->GetHoriOrient().GetHoriOrient() )
{
case HORI_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 ) );
}
2000-09-18 23:08:29 +00:00
}
break;
case HORI_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 ) );
}
2000-09-18 23:08:29 +00:00
}
break;
case HORI_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;
2000-09-18 23:08:29 +00:00
case HORI_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 = TRUE;
nLeftSpacing = nLeftLine + nLeftOffset;
nRightSpacing = nRightLine + nRightOffset;
2000-09-18 23:08:29 +00:00
break;
case HORI_NONE:
{
//Die Raender werden vom Randattribut bestimmt.
nLeftSpacing = pAttrs->CalcLeft( this );
2000-09-18 23:08:29 +00:00
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 ) );
2000-09-18 23:08:29 +00:00
}
// OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
nRightSpacing = pAttrs->CalcRight( this );
2000-09-18 23:08:29 +00:00
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 ) );
2000-09-18 23:08:29 +00:00
}
// OD 10.03.2003 #i9040# - do not hold wished table width.
/*
2000-09-18 23:08:29 +00:00
if ( !pAttrs->GetLRSpace().GetRight() )
nRight = Max( nRight, nMax - (nWish + nLeft + nRight));
*/
2000-09-18 23:08:29 +00:00
}
break;
case HORI_LEFT_AND_WIDTH:
{
2000-09-18 23:08:29 +00:00
//Linker Rand und die Breite zaehlen (Word-Spezialitaet)
// OD 10.03.2003 #i9040# - no width alignment in online mode.
//bCheckBrowseWidth = TRUE;
nLeftSpacing = pAttrs->CalcLeft( this );
2000-09-18 23:08:29 +00:00
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 ) );
2000-09-18 23:08:29 +00:00
}
// 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 );
}
2000-09-18 23:08:29 +00:00
break;
default:
ASSERT( FALSE, "Ungueltige orientation fuer Table." );
}
2001-11-16 10:40:30 +00:00
(this->*fnRect->fnSetYMargins)( nUpper, nLower );
if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) )
2001-11-16 10:40:30 +00:00
(this->*fnRect->fnSetXMargins)( 0, 0 );
else
(this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing );
2000-09-18 23:08:29 +00:00
ViewShell *pSh;
if ( bCheckBrowseWidth && GetFmt()->GetDoc()->IsBrowseMode() &&
GetUpper()->IsPageBodyFrm() && // nur PageBodyFrms, nicht etwa ColBodyFrms
0 != (pSh = GetShell()) && 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())
const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
long nWidth = pSh->VisArea().Width() - 2 * aBorder.Width();
nWidth -= Prt().Left();
nWidth -= pAttrs->CalcRightLine();
Prt().Width( Min( nWidth, Prt().Width() ) );
}
2001-11-16 10:40:30 +00:00
if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() )
2000-09-18 23:08:29 +00:00
bValidSize = FALSE;
}
if ( !bValidSize )
{
bValidSize = 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)();
2000-09-18 23:08:29 +00:00
pFrm = pFrm->GetNext();
}
//Jetzt noch die Raender addieren
nRemaining += nUpper + nLower;
2001-11-16 10:40:30 +00:00
nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining;
2000-09-18 23:08:29 +00:00
if ( nDiff > 0 )
2001-10-19 09:25:19 +00:00
Shrink( nDiff PHEIGHT );
2000-09-18 23:08:29 +00:00
else if ( nDiff < 0 )
2001-10-19 09:25:19 +00:00
Grow( -nDiff PHEIGHT );
2000-09-18 23:08:29 +00:00
}
}
/*************************************************************************
|*
|* SwTabFrm::GrowFrm()
|*
|* Ersterstellung MA 12. Mar. 93
|* Letzte Aenderung MA 23. Sep. 96
|*
|*************************************************************************/
2001-10-19 09:25:19 +00:00
SwTwips SwTabFrm::GrowFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
{
SWRECTFN( this )
SwTwips nHeight =(Frm().*fnRect->fnGetHeight)();
if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) )
nDist = LONG_MAX - nHeight;
2000-09-18 23:08:29 +00:00
if ( bTst && !IsRestrictTableGrowth() )
return nDist;
if ( GetUpper() )
2000-09-18 23:08:29 +00:00
{
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 )
2000-09-18 23:08:29 +00:00
{
nReal -= (pFrm->Frm().*fnRect->fnGetHeight)();
pFrm = pFrm->GetNext();
}
long nTmp = 0;
if ( nReal < nDist )
{
nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo );
if ( IsRestrictTableGrowth() )
{
nTmp = Min( nDist, nReal + nTmp );
nDist = nTmp < 0 ? 0 : nTmp;
}
2001-10-19 09:25:19 +00:00
}
if ( !bTst )
2001-10-19 09:25:19 +00:00
{
(Frm().*fnRect->fnAddBottom)( nDist );
SwRootFrm *pRootFrm = FindRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm );
}
2000-09-18 23:08:29 +00:00
}
}
2000-09-18 23:08:29 +00:00
if ( !bTst && ( nDist || IsRestrictTableGrowth() ) )
{
2000-09-18 23:08:29 +00:00
SwPageFrm *pPage = FindPageFrm();
if ( GetNext() )
{
GetNext()->_InvalidatePos();
if ( GetNext()->IsCntntFrm() )
GetNext()->InvalidatePage( pPage );
}
_InvalidateAll();
InvalidatePage( pPage );
SetComplete();
const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos();
if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
SetCompletePaint();
}
2000-09-18 23:08:29 +00:00
return nDist;
}
/*************************************************************************
|*
|* SwTabFrm::Modify()
|*
|* Ersterstellung MA 14. Mar. 93
|* Letzte Aenderung MA 06. Dec. 96
|*
|*************************************************************************/
void SwTabFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
{
BYTE nInvFlags = 0;
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( 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 & 0x01 )
// SetCompletePaint();
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( SfxPoolItem *pOld, SfxPoolItem *pNew,
BYTE &rInvFlags,
SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
BOOL bClear = TRUE;
const USHORT nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
switch( nWhich )
{
case RES_TBLHEADLINECHG:
//Es wird getoggelt.
if ( IsFollow() )
{
if ( GetTable()->IsHeadlineRepeat() )
{
bDontCreateObjects = TRUE; //frmtool
SwFrm *pRow = new SwRowFrm( *GetTable()->GetTabLines()[0] );
bDontCreateObjects = FALSE;
pRow->Paste( this, Lower() );
}
else if ( Lower() )
{
SwFrm *pLow = Lower();
pLow->Cut();
delete pLow;
}
}
else if ( !HasFollow() )
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( 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;
2002-06-24 08:37:40 +00:00
case RES_FRAMEDIR :
SetDerivedR2L( sal_False );
CheckDirChange();
break;
2000-09-18 23:08:29 +00:00
case RES_UL_SPACE:
rInvFlags |= 0x1C;
/* kein Break hier */
default:
bClear = FALSE;
}
if ( bClear )
{
if ( pOldSet || pNewSet )
{
if ( pOldSet )
pOldSet->ClearItem( nWhich );
if ( pNewSet )
pNewSet->ClearItem( nWhich );
}
else
SwLayoutFrm::Modify( pOld, pNew );
}
}
/*************************************************************************
|*
|* SwTabFrm::GetInfo()
|*
|* Ersterstellung MA 06. Dec. 96
|* Letzte Aenderung MA 26. Jun. 98
|*
|*************************************************************************/
BOOL SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const
{
if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() )
{
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 FALSE;
}
if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
(!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
{
//Das koennte er sein.
rInfo.SetInfo( pPage, this );
}
}
}
return TRUE;
}
/*************************************************************************
|*
|* SwTabFrm::FindLastCntnt()
|*
|* Ersterstellung MA 13. Apr. 93
|* Letzte Aenderung MA 15. May. 98
|*
|*************************************************************************/
SwCntntFrm *SwTabFrm::FindLastCntnt()
{
SwFrm *pRet = pLower;
2000-09-18 23:08:29 +00:00
while ( pRet && !pRet->IsCntntFrm() )
{
SwFrm *pOld = pRet;
SwFrm *pTmp = pRet; // To skip empty section frames
2000-09-18 23:08:29 +00:00
while ( pRet->GetNext() )
{
2000-09-18 23:08:29 +00:00
pRet = pRet->GetNext();
if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() )
pTmp = pRet;
}
pRet = pTmp;
2000-09-18 23:08:29 +00:00
if ( pRet->GetLower() )
pRet = pRet->GetLower();
if ( pRet == pOld )
{
// Wenn am Ende der letzten Zelle ein spaltiger Bereich steht,
2000-09-18 23:08:29 +00:00
// der eine leere letzte Spalte hat, muessen wir noch die anderen
// Spalten abklappern, dies erledigt SwSectionFrm::FindLastCntnt
if( pRet->IsColBodyFrm() )
{
#ifndef PRODUCT
SwSectionFrm* pSect = pRet->FindSctFrm();
ASSERT( pSect, "Wo kommt denn die Spalte her?")
ASSERT( IsAnLower( pSect ), "Gespaltene Zelle?" );
#endif
return pRet->FindSctFrm()->FindLastCntnt();
}
// pRet may be a cell frame without a lower (cell has been split)
ASSERT( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" )
do
{
if ( ((SwCellFrm*)pRet)->Lower() )
{
pRet = ((SwCellFrm*)pRet)->Lower();
break;
}
pRet = pRet->GetPrev();
}
while( pRet );
2000-09-18 23:08:29 +00:00
}
}
// #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 )
{
2000-09-18 23:08:29 +00:00
while ( pRet->GetNext() )
pRet = pRet->GetNext();
if( pRet->IsSctFrm() )
pRet = ((SwSectionFrm*)pRet)->FindLastCntnt();
}
2000-09-18 23:08:29 +00:00
return (SwCntntFrm*)pRet;
}
/*************************************************************************
|*
|* SwTabFrm::GetLeaf()
|*
|* Ersterstellung MA 19. Mar. 93
|* Letzte Aenderung MA 25. Apr. 95
|*
|*************************************************************************/
SwLayoutFrm *SwTabFrm::GetLeaf( MakePageType eMakePage, 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
|* Ersterstellung MA 10. Jul. 95
|* Letzte Aenderung MA 04. Mar. 97
|*
|*************************************************************************/
BOOL SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, BOOL bHead, BOOL &rReformat )
{
rReformat = 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();
BOOL bMoveAnyway = FALSE;
SwTwips nSpace = 0;
2001-11-16 10:40:30 +00:00
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( FALSE ==
( bMoveAnyway = BwdMoveNecessary( pOldPage, Frm() ) > 1 ) )
{
SwRect aRect( pNewUpper->Prt() );
aRect.Pos() += pNewUpper->Frm().Pos();
const SwFrm *pPrevFrm = pNewUpper->Lower();
while ( pPrevFrm )
{
(aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX->
fnGetBottom)() );
pPrevFrm = pPrevFrm->GetNext();
}
bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1;
nSpace = (aRect.*fnRectX->fnGetHeight)();
if ( GetFmt()->GetDoc()->IsBrowseMode() )
nSpace += pNewUpper->Grow( LONG_MAX, TRUE );
}
}
else if( !bLockBackMove )
bMoveAnyway = TRUE;
}
else if( !bLockBackMove )
bMoveAnyway = TRUE;
if ( bMoveAnyway )
return rReformat = TRUE;
else if ( !bLockBackMove && nSpace > 0 )
{
const BOOL bRepeat = GetTable()->IsHeadlineRepeat();
const SwFrm* pFirstRow = Lower();
SwTwips nTmpHeight = 0;
if ( pFirstRow && bRepeat )
{
if ( !IsFollow() )
nTmpHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)();
pFirstRow = pFirstRow->GetNext();
}
// pFirst 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 = ((SwRowFrm*)pFirstRow)->IsRowSplitAllowed();
const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue();
if ( bDontSplit )
nTmpHeight = (Frm().*fnRect->fnGetHeight)();
else if ( !bSplittable )
nTmpHeight += (pFirstRow->Frm().*fnRect->fnGetHeight)();
else
{
const bool bOldJoinLock = IsJoinLocked();
LockJoin();
nTmpHeight += lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow );
if ( !bOldJoinLock )
UnlockJoin();
}
}
return nTmpHeight < nSpace;
2001-11-16 10:40:30 +00:00
}
2000-09-18 23:08:29 +00:00
}
return FALSE;
}
/*************************************************************************
|*
|* SwTabFrm::Cut()
|*
|* Ersterstellung MA 23. Feb. 94
|* Letzte Aenderung MA 09. Sep. 98
|*
|*************************************************************************/
void SwTabFrm::Cut()
{
ASSERT( 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();
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
2000-09-18 23:08:29 +00:00
Remove();
if ( pUp )
{
ASSERT( !pUp->IsFtnFrm(), "Tabelle in Fussnote." );
2003-03-28 12:51:01 +00:00
SwSectionFrm *pSct = 0;
2000-09-18 23:08:29 +00:00
if( !pUp->Lower() && pUp->IsInSct() &&
!(pSct = pUp->FindSctFrm())->ContainsCntnt() )
{
if ( pUp->GetUpper() )
{
pSct->DelEmpty( FALSE );
pSct->_InvalidateSize();
}
}
2001-11-16 10:40:30 +00:00
else if( (Frm().*fnRect->fnGetHeight)() )
{
// OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
// undo changes of fix for #104992#
2001-10-19 09:25:19 +00:00
pUp->Shrink( Frm().Height() PHEIGHT );
}
2000-09-18 23:08:29 +00:00
}
if ( pPage && !IsFollow() && pPage->GetUpper() )
((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth();
}
/*************************************************************************
|*
|* SwTabFrm::Paste()
|*
|* Ersterstellung MA 23. Feb. 94
|* Letzte Aenderung MA 09. Sep. 98
|*
|*************************************************************************/
void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling )
{
ASSERT( pParent, "Kein Parent fuer Paste." );
ASSERT( pParent->IsLayoutFrm(), "Parent ist CntntFrm." );
ASSERT( pParent != this, "Bin selbst der Parent." );
ASSERT( pSibling != this, "Bin mein eigener Nachbar." );
ASSERT( !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 );
}
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
if( (Frm().*fnRect->fnGetHeight)() )
pParent->Grow( (Frm().*fnRect->fnGetHeight)() );
if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() )
Prepare( PREP_FIXSIZE_CHG );
2000-09-18 23:08:29 +00:00
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() != &GetFmt()->GetDoc()->GetPageDesc(0)) )
CheckPageDescs( pPage, TRUE );
}
}
}
/*************************************************************************
|*
|* SwTabFrm::Prepare()
|*
|* Created AMA 01/10/02
|* Last Change AMA 01/10/02
|*
|*************************************************************************/
void SwTabFrm::Prepare( const PrepareHint eHint, const void *, BOOL )
{
if( PREP_BOSS_CHGD == eHint )
CheckDirChange();
}
2000-09-18 23:08:29 +00:00
/*************************************************************************
|*
|* SwRowFrm::SwRowFrm(), ~SwRowFrm()
|*
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 30. May. 96
|*
|*************************************************************************/
SwRowFrm::SwRowFrm( const SwTableLine &rLine, bool bInsertContent ):
2000-09-18 23:08:29 +00:00
SwLayoutFrm( rLine.GetFrmFmt() ),
pTabLine( &rLine ),
pFollowRow( 0 ),
bIsFollowFlowRow( false )
2000-09-18 23:08:29 +00:00
{
nType = FRMC_ROW;
2000-09-18 23:08:29 +00:00
//Gleich die Boxen erzeugen und einfuegen.
const SwTableBoxes &rBoxes = rLine.GetTabBoxes();
SwFrm *pPrev = 0;
for ( USHORT i = 0; i < rBoxes.Count(); ++i )
{
SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], bInsertContent );
2000-09-18 23:08:29 +00:00
pNew->InsertBehind( this, pPrev );
pPrev = pNew;
}
}
SwRowFrm::~SwRowFrm()
{
SwModify* pMod = GetFmt();
if( pMod )
{
pMod->Remove( this ); // austragen,
if( !pMod->GetDepends() )
delete pMod; // und loeschen
}
}
/*************************************************************************
|*
|* SwRowFrm::RegistFlys()
|*
|* Ersterstellung MA 08. Jul. 93
|* Letzte Aenderung MA 08. Jul. 93
|*
|*************************************************************************/
void SwRowFrm::RegistFlys( SwPageFrm *pPage )
{
::RegistFlys( pPage ? pPage : FindPageFrm(), this );
}
/*************************************************************************
|*
|* SwRowFrm::Modify()
|*
|* Ersterstellung MA 12. Nov. 97
|* Letzte Aenderung MA 12. Nov. 97
|*
|*************************************************************************/
void SwRowFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
{
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, FALSE, &pItem);
if ( !pItem )
pChgSet->GetItemState( RES_ROW_SPLIT, FALSE, &pItem);
}
else if ( RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which() )
2000-09-18 23:08:29 +00:00
pItem = pNew;
if ( pItem )
{
SwTabFrm *pTab = FindTabFrm();
if ( pTab && pTab->IsFollow() &&
(!GetPrev() ||
(pTab->GetTable()->IsHeadlineRepeat() && !GetPrev()->GetPrev())))
{
pTab->FindMaster()->InvalidatePos();
}
}
SwLayoutFrm::Modify( pOld, pNew );
}
/*************************************************************************
|*
|* SwRowFrm::MakeAll()
|*
|* Ersterstellung MA 01. Mar. 94
|* Letzte Aenderung MA 01. Mar. 94
|*
|*************************************************************************/
void SwRowFrm::MakeAll()
{
if ( !GetNext() )
bValidSize = FALSE;
SwLayoutFrm::MakeAll();
}
/*************************************************************************
|*
|* SwRowFrm::Format()
|*
|* Ersterstellung MA 13. Mar. 93
|* Letzte Aenderung MA 20. Jun. 96
|*
|*************************************************************************/
long MA_FASTCALL CalcHeightWidthFlys( const SwFrm *pFrm )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( pFrm )
2000-09-18 23:08:29 +00:00
long nHeight = 0;
const SwFrm* pTmp = pFrm->IsSctFrm() ?
((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm;
while( pTmp )
{
if ( pTmp->GetDrawObjs() )
{
for ( USHORT i = 0; i < pTmp->GetDrawObjs()->Count(); ++i )
{
const SdrObject *pO = (*pTmp->GetDrawObjs())[i];
if ( pO->ISA(SwVirtFlyDrawObj) )
2000-09-18 23:08:29 +00:00
{
const SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pO)->GetFlyFrm();
// OD 30.09.2003 #i18732# - only objects, which follow
// the text flow have to be considered.
const SwFrmFmt* pFrmFmt = static_cast<const SwVirtFlyDrawObj*>(pO)->GetFmt();
const bool bConsiderFly =
!pFly->IsFlyInCntFrm() &&
pFly->Frm().Top() != WEIT_WECH &&
pFrmFmt->GetFollowTextFlow().GetValue();
if ( bConsiderFly )
2000-09-18 23:08:29 +00:00
{
const SwFmtFrmSize &rSz = pFly->GetFmt()->GetFrmSize();
if( !rSz.GetHeightPercent() )
2002-09-19 12:25:35 +00:00
{
const SwTwips nFlyWidth =
(pFly->Frm().*fnRect->fnGetHeight)() +
( bVert ?
pFly->GetCurRelPos().X() :
pFly->GetCurRelPos().Y() );
const SwTwips nFrmDiff =
(*fnRect->fnYDiff)(
(pTmp->Frm().*fnRect->fnGetTop)(),
(pFrm->Frm().*fnRect->fnGetTop)() );
nHeight = Max( nHeight, nFlyWidth + nFrmDiff -
(pFrm->Frm().*fnRect->fnGetHeight)() );
}
2000-09-18 23:08:29 +00:00
}
}
}
}
if( !pFrm->IsSctFrm() )
break;
pTmp = pTmp->FindNextCnt();
if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) )
break;
}
return nHeight;
}
SwTwips MA_FASTCALL lcl_CalcMinRowHeight( SwLayoutFrm *pRow );
SwTwips MA_FASTCALL lcl_CalcMinCellHeight( SwLayoutFrm *pCell,
const SwBorderAttrs *pAttrs = 0 )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( pCell )
2000-09-18 23:08:29 +00:00
SwTwips nHeight = 0;
SwFrm *pLow = pCell->Lower();
if ( pLow )
{
long nFlyAdd = 0;
while ( pLow )
{
if( pLow->IsCntntFrm() || pLow->IsSctFrm() )
{
2001-11-16 10:40:30 +00:00
long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)();
nHeight += nLowHeight;
nFlyAdd = Max( 0L, nFlyAdd - nLowHeight );
2000-09-18 23:08:29 +00:00
nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) );
}
else
nHeight += ::lcl_CalcMinRowHeight( (SwLayoutFrm*)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() )
2000-09-18 23:08:29 +00:00
{
SwTabFrm* pTab = pCell->FindTabFrm();
if ( pAttrs )
nHeight += pAttrs->CalcTop() + pAttrs->CalcBottom();
else
{
SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell );
const SwBorderAttrs &rAttrs = *aAccess.Get();
nHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
}
2000-09-18 23:08:29 +00:00
}
return nHeight;
}
SwTwips MA_FASTCALL lcl_CalcMinRowHeight( SwLayoutFrm *pRow )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( pRow )
const SwFmtFrmSize &rSz = pRow->GetFmt()->GetFrmSize();
2001-10-19 09:25:19 +00:00
if ( pRow->HasFixSize() )
{
ASSERT( ATT_FIX_SIZE == rSz.GetSizeType(), "pRow claims to have fixed size" )
return rSz.GetHeight();
}
2000-09-18 23:08:29 +00:00
SwTwips nHeight = 0;
SwLayoutFrm *pLow = (SwLayoutFrm*)pRow->Lower();
while ( pLow )
{
SwTwips nTmp = ::lcl_CalcMinCellHeight( pLow );
if ( nTmp > nHeight )
nHeight = nTmp;
pLow = (SwLayoutFrm*)pLow->GetNext();
}
if ( rSz.GetSizeType() == ATT_MIN_SIZE )
nHeight = Max( nHeight, rSz.GetHeight() );
return nHeight;
}
void SwRowFrm::Format( const SwBorderAttrs *pAttrs )
{
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
2000-09-18 23:08:29 +00:00
ASSERT( pAttrs, "SwRowFrm::Format ohne Attrs." );
2001-10-19 09:25:19 +00:00
const BOOL bFix = BFIXHEIGHT;
2000-09-18 23:08:29 +00:00
if ( !bValidPrtArea )
{
//RowFrms haben keine Umrandung usw. also entspricht die PrtArea immer
//dem Frm.
bValidPrtArea = TRUE;
aPrt.Left( 0 );
aPrt.Top( 0 );
aPrt.Width ( aFrm.Width() );
aPrt.Height( aFrm.Height() );
}
while ( !bValidSize )
{
bValidSize = TRUE;
2001-10-19 09:25:19 +00:00
#ifndef PRODUCT
if ( HasFixSize() )
{
const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize();
ASSERT( rFrmSize.GetSize().Height() > 0, "Hat ihn" );
}
#endif
2001-11-16 10:40:30 +00:00
const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() - (HasFixSize() ?
2001-10-19 09:25:19 +00:00
pAttrs->GetSize().Height() :
::lcl_CalcMinRowHeight( this ));
2000-09-18 23:08:29 +00:00
if ( nDiff )
{
2001-10-19 09:25:19 +00:00
BFIXHEIGHT = FALSE;
2000-09-18 23:08:29 +00:00
if ( nDiff > 0 )
2001-10-19 09:25:19 +00:00
Shrink( nDiff PHEIGHT, FALSE, TRUE );
2000-09-18 23:08:29 +00:00
else if ( nDiff < 0 )
2001-10-19 09:25:19 +00:00
Grow( -nDiff PHEIGHT );
BFIXHEIGHT = bFix;
2000-09-18 23:08:29 +00:00
}
}
if ( !GetNext() )
{
//Der letzte fuellt den verbleibenden Raum im Upper aus.
2001-11-16 10:40:30 +00:00
SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)();
SwFrm *pSibling = GetUpper()->Lower();
do
{ nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)();
2000-09-18 23:08:29 +00:00
pSibling = pSibling->GetNext();
} while ( pSibling );
if ( nDiff > 0 )
{
2001-10-19 09:25:19 +00:00
BFIXHEIGHT = FALSE;
Grow( nDiff PHEIGHT );
BFIXHEIGHT = bFix;
2000-09-18 23:08:29 +00:00
bValidSize = TRUE;
}
}
}
/*************************************************************************
|*
|* SwRowFrm::AdjustCells()
|*
|* Ersterstellung MA 10. Aug. 93
|* Letzte Aenderung MA 16. Dec. 96
|*
|*************************************************************************/
void SwRowFrm::AdjustCells( const SwTwips nHeight, const BOOL bHeight )
{
SwFrm *pFrm = Lower();
if ( bHeight )
{
SwRootFrm *pRootFrm = 0;
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
while ( pFrm )
{
long nDiff = nHeight - (pFrm->Frm().*fnRect->fnGetHeight)();
if( nDiff )
{
SwRect aOldFrm( pFrm->Frm() );
2001-11-16 10:40:30 +00:00
(pFrm->Frm().*fnRect->fnAddBottom)( nDiff );
if( !pRootFrm )
pRootFrm = FindRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pFrm, aOldFrm );
}
2000-09-18 23:08:29 +00:00
pFrm->_InvalidatePrt();
}
pFrm = pFrm->GetNext();
}
}
else
{ while ( pFrm )
{
pFrm->_InvalidateAll();
pFrm = pFrm->GetNext();
}
}
InvalidatePage();
}
/*************************************************************************
|*
|* SwRowFrm::Cut()
|*
|* Ersterstellung MA 12. Nov. 97
|* Letzte Aenderung MA 12. Nov. 97
|*
|*************************************************************************/
void SwRowFrm::Cut()
{
SwTabFrm *pTab = FindTabFrm();
if ( pTab && pTab->IsFollow() &&
(!GetPrev() ||
(pTab->GetTable()->IsHeadlineRepeat() && !GetPrev()->GetPrev())))
{
pTab->FindMaster()->InvalidatePos();
}
SwLayoutFrm::Cut();
}
/*************************************************************************
|*
|* SwRowFrm::GrowFrm()
|*
|* Ersterstellung MA 15. Mar. 93
|* Letzte Aenderung MA 05. May. 94
|*
|*************************************************************************/
2001-10-19 09:25:19 +00:00
SwTwips SwRowFrm::GrowFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
{
SwTwips nReal = 0;
SwTabFrm* pTab = FindTabFrm();
SWRECTFN( pTab )
bool bRestrictTableGrowth;
bool bHasFollowFlowLine = pTab->HasFollowFlowLine();
if ( GetUpper()->IsTabFrm() )
bRestrictTableGrowth = NULL != IsInSplitTableRow();
else
{
ASSERT( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" )
bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine;
ASSERT( !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( 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( FALSE );
}
nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo);
pTab->SetRestrictTableGrowth( FALSE );
pTab->SetFollowFlowLine( bHasFollowFlowLine );
2001-10-19 09:25:19 +00:00
//Hoehe der Zellen auf den neuesten Stand bringen.
if ( !bTst )
{
SWRECTFN( this )
2001-11-16 10:40:30 +00:00
AdjustCells( (Prt().*fnRect->fnGetHeight)() + nReal, TRUE );
2001-10-19 09:25:19 +00:00
if ( nReal )
SetCompletePaint();
}
2001-10-19 09:25:19 +00:00
return nReal;
}
2001-10-19 09:25:19 +00:00
/*************************************************************************
|*
|* SwRowFrm::ShrinkFrm()
|*
|* Ersterstellung MA 15. Mar. 93
|* Letzte Aenderung MA 20. Jun. 96
|*
|*************************************************************************/
SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, BOOL bTst, BOOL bInfo )
{
SWRECTFN( this )
if( HasFixSize() )
{
2002-09-19 14:31:21 +00:00
AdjustCells( (Prt().*fnRect->fnGetHeight)(), TRUE );
2001-10-19 09:25:19 +00:00
return 0L;
}
//bInfo wird ggf. vom SwRowFrm::Format auf TRUE gesetzt, hier muss dann
//entsprechend reagiert werden
const 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.GetSizeType() == ATT_MIN_SIZE ?
2002-01-22 09:13:33 +00:00
rSz.GetHeight() : 0;
2001-10-19 09:25:19 +00:00
SwLayoutFrm *pCell = (SwLayoutFrm*)Lower();
if( nMinHeight < (Frm().*fnRect->fnGetHeight)() )
{
SwLayoutFrm *pCell = (SwLayoutFrm*)Lower();
while ( pCell )
{
SwTwips nAct = ::lcl_CalcMinCellHeight( pCell );
if ( nAct > nMinHeight )
nMinHeight = nAct;
if ( nMinHeight >= (Frm().*fnRect->fnGetHeight)() )
break;
pCell = (SwLayoutFrm*)pCell->GetNext();
}
}
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 );
if( IsVertical() && !bRev )
Frm().Pos().X() += nReal;
2001-10-19 09:25:19 +00:00
}
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 );
if( IsVertical() && !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() &&
2001-10-19 09:25:19 +00:00
(!GetPrev() ||
(pTab->GetTable()->IsHeadlineRepeat() && !GetPrev()->GetPrev() ) ) )
2001-10-19 09:25:19 +00:00
{
SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() );
pMasterTab->InvalidatePos();
2001-10-19 09:25:19 +00:00
}
}
AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, TRUE );
2001-10-19 09:25:19 +00:00
}
return nReal;
}
/*************************************************************************
|*
|* SwRowFrm::IsRowSplitAllowed()
|*
|*************************************************************************/
bool SwRowFrm::IsRowSplitAllowed() const
{
// Fixed size rows are never allowed to split:
if ( HasFixSize() )
{
const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize();
ASSERT( ATT_FIX_SIZE == rSz.GetSizeType(), "pRow claims to have fixed size" )
return false;
}
// Repeated headlines are never allowed to split:
const SwFrm* pRow = this; // find most upper row frame
while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() )
pRow = pRow->GetUpper();
ASSERT( pRow->GetUpper()->IsTabFrm(), "No tabframe found!" )
const SwTabFrm* pTabFrm = (SwTabFrm*)pRow->GetUpper();
if ( this == pTabFrm->Lower() && pTabFrm->GetTable()->IsHeadlineRepeat() )
return false;
const SwTableLine* pTabLine = GetTabLine();
const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)pTabLine->GetFrmFmt();
const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit();
return 0 != rLP.GetValue();
}
2001-10-19 09:25:19 +00:00
2000-09-18 23:08:29 +00:00
/*************************************************************************
|*
|* SwCellFrm::SwCellFrm(), ~SwCellFrm()
|*
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 30. May. 96
|*
|*************************************************************************/
SwCellFrm::SwCellFrm( const SwTableBox &rBox, bool bInsertContent ) :
2000-09-18 23:08:29 +00:00
SwLayoutFrm( rBox.GetFrmFmt() ),
pTabBox( &rBox )
{
nType = FRMC_CELL;
2000-09-18 23:08:29 +00:00
if ( !bInsertContent )
return;
2000-09-18 23:08:29 +00:00
//Wenn ein StartIdx vorhanden ist, so werden CntntFrms in der Zelle
//angelegt, andernfalls muessen Rows vorhanden sein und diese werden
//angelegt.
if ( rBox.GetSttIdx() )
{
ULONG nIndex = rBox.GetSttIdx();
::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex );
}
else
{ const SwTableLines &rLines = rBox.GetTabLines();
SwFrm *pPrev = 0;
for ( USHORT i = 0; i < rLines.Count(); ++i )
{
SwRowFrm *pNew = new SwRowFrm( *rLines[i], bInsertContent );
2000-09-18 23:08:29 +00:00
pNew->InsertBehind( this, pPrev );
pPrev = pNew;
}
}
}
SwCellFrm::~SwCellFrm()
{
SwModify* pMod = GetFmt();
if( pMod )
{
2002-04-11 13:04:40 +00:00
// At this stage the lower frames aren't destroyed already,
// therfor we have to do a recursive dispose.
SwRootFrm *pRootFrm = FindRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, sal_True );
}
2000-09-18 23:08:29 +00:00
pMod->Remove( this ); // austragen,
if( !pMod->GetDepends() )
delete pMod; // und loeschen
}
}
/*************************************************************************
|*
|* SwCellFrm::Format()
|*
|* Ersterstellung MA 09. Mar. 93
|* Letzte Aenderung MA 29. Jan. 98
|*
|*************************************************************************/
BOOL lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, BOOL bInva )
{
BOOL bRet = FALSE;
SwFrm *pFrm = pLay->Lower();
SwPageFrm* pPg = NULL;
2001-11-16 10:40:30 +00:00
SWRECTFN( pLay )
while ( pFrm )
{
long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)();
if( nFrmTop != lYStart )
{
bRet = 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 ( USHORT i = 0; i < pFrm->GetDrawObjs()->Count(); ++i )
{
SdrObject *pO = (*pFrm->GetDrawObjs())[i];
if ( pO->ISA(SwVirtFlyDrawObj) )
2001-11-16 10:40:30 +00:00
{
SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pO)->GetFlyFrm();
if( WEIT_WECH != pFly->Frm().Top() )
{
(pFly->Frm().*fnRect->fnSubTop)( -lDiff );
(pFly->Frm().*fnRect->fnAddBottom)( lDiff );
}
pFly->GetVirtDrawObj()->_SetRectsDirty();
if ( pFly->IsFlyInCntFrm() )
((SwFlyInCntFrm*)pFly)->AddRefOfst( lDiff );
else
{
if( !pPg )
pPg = pLay->FindPageFrm();
SwPageFrm* pOld = pFly->FindPageFrm();
if( pPg != pOld )
pOld->MoveFly( pFly, pPg );
if( pFly->IsAutoPos() )
((SwFlyAtCntFrm*)pFly)->AddLastCharY( lDiff );
}
if( ::lcl_ArrangeLowers( pFly,
(pFly->*fnRect->fnGetPrtTop)(), bInva ) )
pFly->SetCompletePaint();
}
else
{
// OD 30.06.2003 #108784# - consider 'virtual' drawing
// objects.
if ( pO->ISA(SwDrawVirtObj) )
{
SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(pO);
pDrawVirtObj->SetAnchorPos( pFrm->GetFrmAnchorPos( ::HasWrap( pO ) ) );
pDrawVirtObj->AdjustRelativePosToReference();
}
else
{
pO->SetAnchorPos( pFrm->GetFrmAnchorPos( ::HasWrap( pO ) ) );
// OD 30.06.2003 #108784# - correct relative position
// of 'virtual' drawing objects.
SwDrawContact* pDrawContact =
static_cast<SwDrawContact*>(pO->GetUserCall());
if ( pDrawContact )
{
pDrawContact->CorrectRelativePosOfVirtObjs();
}
}
}
2001-11-16 10:40:30 +00:00
}
}
}
// 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)());
if ( nDistanceToUpperPrtBottom < 0 && pFrm->IsInSplitTableRow() )
pFrm->InvalidatePos();
2001-11-16 10:40:30 +00:00
pFrm = pFrm->GetNext();
}
2000-09-18 23:08:29 +00:00
return bRet;
}
void SwCellFrm::Format( const SwBorderAttrs *pAttrs )
{
ASSERT( pAttrs, "CellFrm::Format, pAttrs ist 0." );
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
if ( !bValidPrtArea )
{
bValidPrtArea = TRUE;
2000-09-18 23:08:29 +00:00
2001-11-16 10:40:30 +00:00
//Position einstellen.
long nLeftSpace = pAttrs->CalcLeft( this );
// OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
long nRightSpace = pAttrs->CalcRight( this );
(this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace );
if ( Lower() )
{
long nTopSpace = pAttrs->CalcTop();
long nBottomSpace = pAttrs->CalcBottom();
(this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace );
}
2001-11-16 10:40:30 +00:00
}
2000-09-18 23:08:29 +00:00
long nRemaining = ::lcl_CalcMinCellHeight( this, pAttrs );
if ( !bValidSize )
{
bValidSize = 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 SwTabFrm *pTab = FindTabFrm();
SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth();
nWidth = pAttrs->GetSize().Width();
ASSERT( nWish, "Tabelle ohne Breite?" );
ASSERT( nWidth <= nWish, "Zelle breiter als Tabelle." );
ASSERT( nWidth > 0, "Box without width" );
2001-11-16 10:40:30 +00:00
long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
if ( nWish != nPrtWidth )
{
// #i12092# use double instead of long,
// otherwise this cut lead to overflows
double nTmpWidth = nWidth;
nTmpWidth *= nPrtWidth;
nTmpWidth /= nWish;
nWidth = (SwTwips)nTmpWidth;
// nWidth *= nPrtWidth;
// nWidth /= nWish;
2001-11-16 10:40:30 +00:00
}
}
else
{
ASSERT( 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 );
2001-11-16 10:40:30 +00:00
(Prt().*fnRect->fnAddRight)( nDiff );
//Jetzt die Hoehe einstellen, sie wird vom Inhalt und den Raendern
//bestimmt.
const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)();
2000-09-18 23:08:29 +00:00
if ( nDiffHeight )
{
if ( nDiffHeight > 0 )
{
//Wieder validieren wenn kein Wachstum stattgefunden hat.
//Invalidiert wird durch AdjustCells von der Row.
2001-10-19 09:25:19 +00:00
if ( !Grow( nDiffHeight PHEIGHT ) )
2000-09-18 23:08:29 +00:00
bValidSize = bValidPrtArea = TRUE;
}
else
{
//Nur dann invalidiert lassen, wenn tatsaechlich
//geshrinkt wurde; das kann abgelehnt werden, weil alle
//nebeneinanderliegenden Zellen gleichgross sein muessen.
2001-10-19 09:25:19 +00:00
if ( !Shrink( -nDiffHeight PHEIGHT ) )
2000-09-18 23:08:29 +00:00
bValidSize = bValidPrtArea = TRUE;
}
}
}
const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient();
if ( !Lower() )
return;
if ( !FindTabFrm()->IsRebuildLastLine() && VERT_NONE != rOri.GetVertOrient() )
2000-09-18 23:08:29 +00:00
{
if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() )
{
//ASSERT fuer HTML-Import!
ASSERT( !this, "VAlign an Zelle ohne Inhalt" );
return;
}
BOOL bVertDir = TRUE;
//Keine Ausrichtung wenn Rahmen mit Umlauf in die Zelle ragen.
SwPageFrm *pPg = FindPageFrm();
if ( pPg->GetSortedObjs() )
{
SwRect aRect( Prt() ); aRect += Frm().Pos();
for ( USHORT i = 0; i < pPg->GetSortedObjs()->Count(); ++i )
{
const SdrObject *pObj = (*pPg->GetSortedObjs())[i];
SwRect aTmp( pObj->GetCurrentBoundRect() );
2000-09-18 23:08:29 +00:00
if ( aTmp.IsOver( aRect ) )
{
SdrObjUserCall *pUserCall;
const SwFmtSurround &rSur = ((SwContact*)
(pUserCall=GetUserCall(pObj)))->GetFmt()->GetSurround();
if ( SURROUND_THROUGHT != rSur.GetSurround() )
{
const SwFrm *pAnch;
if ( pObj->ISA(SwVirtFlyDrawObj) )
2000-09-18 23:08:29 +00:00
{
const SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm();
if ( pFly->IsAnLower( this ) )
continue;
pAnch = pFly->GetAnchor();
}
else
pAnch = ((SwDrawContact*)pUserCall)->GetAnchor();
if ( !IsAnLower( pAnch ) )
{
bVertDir = FALSE;
break;
}
}
}
}
}
2001-11-16 10:40:30 +00:00
long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
if( ( bVertDir && ( nRemaining -= (pAttrs->CalcTop() +
pAttrs->CalcBottom())) < nPrtHeight ) ||
(Lower()->Frm().*fnRect->fnGetTop)() !=
(this->*fnRect->fnGetPrtTop)() )
{
long lTopOfst = 0,
nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining;
2000-09-18 23:08:29 +00:00
if ( nDiff >= 0 )
{
if ( bVertDir )
{
switch ( rOri.GetVertOrient() )
{
case VERT_CENTER: lTopOfst = nDiff / 2; break;
case VERT_BOTTOM: lTopOfst = nDiff; break;
};
}
2001-11-16 10:40:30 +00:00
long nTmp = (*fnRect->fnYInc)(
(this->*fnRect->fnGetPrtTop)(), lTopOfst );
if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) )
2000-09-18 23:08:29 +00:00
SetCompletePaint();
}
}
}
else
{
//Ist noch eine alte Ausrichtung beruecksichtigt worden?
if ( Lower()->IsCntntFrm() )
{
2001-11-16 10:40:30 +00:00
const long lYStart = (this->*fnRect->fnGetPrtTop)();
2000-09-18 23:08:29 +00:00
lcl_ArrangeLowers( this, lYStart, TRUE );
}
}
}
/*************************************************************************
|*
|* SwCellFrm::Modify()
|*
|* Ersterstellung MA 20. Dec. 96
|* Letzte Aenderung MA 20. Dec. 96
|*
|*************************************************************************/
void SwCellFrm::Modify( SfxPoolItem * pOld, SfxPoolItem * pNew )
{
BOOL bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
const SfxPoolItem *pItem = 0;
if( bAttrSetChg )
((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, FALSE, &pItem);
else if ( RES_VERT_ORIENT == pNew->Which() )
pItem = pNew;
if ( pItem )
{
BOOL bInva = TRUE;
if ( VERT_NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() &&
// OD 04.11.2003 #112910#
Lower() && Lower()->IsCntntFrm() )
2000-09-18 23:08:29 +00:00
{
2001-11-16 10:40:30 +00:00
SWRECTFN( this )
const long lYStart = (this->*fnRect->fnGetPrtTop)();
2000-09-18 23:08:29 +00:00
bInva = lcl_ArrangeLowers( this, lYStart, FALSE );
}
if ( bInva )
{
SetCompletePaint();
InvalidatePrt();
}
}
if( (bAttrSetChg &&
SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, FALSE )) ||
RES_PROTECT == pNew->Which() )
{
ViewShell *pSh = GetShell();
if( pSh && pSh->GetLayout()->IsAnyShellAccessible() )
pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this );
}
2000-09-18 23:08:29 +00:00
SwLayoutFrm::Modify( pOld, pNew );
}
bool SwTabFrm::IsLayoutSplitAllowed() const
{
return GetFmt()->GetLayoutSplit().GetValue();
}