blob: 69fe5ee338e878e5b8acd709bbbfe806c609a22e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <hintids.hxx>
#include <tools/bigint.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <editeng/brshitem.hxx>
#include <editeng/keepitem.hxx>
#include <editeng/shaditem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/boxitem.hxx>
#include <sfx2/printer.hxx>
#include <editeng/lspcitem.hxx>
#include <fmtornt.hxx>
#include <fmtanchr.hxx>
#include <fmthdft.hxx>
#include <fmtcntnt.hxx>
#include <fmtfsize.hxx>
#include <fmtsrnd.hxx>
#include <docary.hxx>
#include <lineinfo.hxx>
#include <swmodule.hxx>
#include "pagefrm.hxx"
#include "colfrm.hxx"
#include "doc.hxx"
#include "fesh.hxx"
#include "viewimp.hxx"
#include "viewopt.hxx"
#include "pam.hxx"
#include "dflyobj.hxx"
#include "dcontact.hxx"
#include "frmtool.hxx"
#include "docsh.hxx"
#include "tabfrm.hxx"
#include "rowfrm.hxx"
#include "ftnfrm.hxx"
#include "txtfrm.hxx"
#include "notxtfrm.hxx"
#include "flyfrms.hxx"
#include "layact.hxx"
#include "pagedesc.hxx"
#include "section.hxx"
#include "sectfrm.hxx"
#include "node2lay.hxx"
#include "ndole.hxx"
#include "ndtxt.hxx"
#include "swtable.hxx"
#include "hints.hxx"
#include <layhelp.hxx>
#include <laycache.hxx>
#include <rootfrm.hxx>
#include "mdiexp.hxx"
#include "statstr.hrc"
#include <paratr.hxx>
#include <sortedobjs.hxx>
#include <objectformatter.hxx>
#include <switerator.hxx>
// ftnfrm.cxx:
void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes );
using namespace ::com::sun::star;
sal_Bool bObjsDirect = sal_True;
sal_Bool bDontCreateObjects = sal_False;
sal_Bool bSetCompletePaintOnInvalidate = sal_False;
sal_uInt8 StackHack::nCnt = 0;
sal_Bool StackHack::bLocked = sal_False;
/*************************************************************************/
SwFrmNotify::SwFrmNotify( SwFrm *pF ) :
pFrm( pF ),
aFrm( pF->Frm() ),
aPrt( pF->Prt() ),
bInvaKeep( sal_False ),
bValidSize( pF->GetValidSizeFlag() ),
mbFrmDeleted( false ) // #i49383#
{
if ( pF->IsTxtFrm() )
{
mnFlyAnchorOfst = ((SwTxtFrm*)pF)->GetBaseOfstForFly( sal_True );
mnFlyAnchorOfstNoWrap = ((SwTxtFrm*)pF)->GetBaseOfstForFly( sal_False );
}
else
{
mnFlyAnchorOfst = 0;
mnFlyAnchorOfstNoWrap = 0;
}
bHadFollow = pF->IsCntntFrm() ?
(((SwCntntFrm*)pF)->GetFollow() ? sal_True : sal_False) :
sal_False;
}
/*************************************************************************/
SwFrmNotify::~SwFrmNotify()
{
// #i49383#
if ( mbFrmDeleted )
{
return;
}
SWRECTFN( pFrm )
const sal_Bool bAbsP = POS_DIFF( aFrm, pFrm->Frm() );
const sal_Bool bChgWidth =
(aFrm.*fnRect->fnGetWidth)() != (pFrm->Frm().*fnRect->fnGetWidth)();
const sal_Bool bChgHeight =
(aFrm.*fnRect->fnGetHeight)()!=(pFrm->Frm().*fnRect->fnGetHeight)();
const sal_Bool bChgFlyBasePos = pFrm->IsTxtFrm() &&
( ( mnFlyAnchorOfst != ((SwTxtFrm*)pFrm)->GetBaseOfstForFly( sal_True ) ) ||
( mnFlyAnchorOfstNoWrap != ((SwTxtFrm*)pFrm)->GetBaseOfstForFly( sal_False ) ) );
if ( pFrm->IsFlowFrm() && !pFrm->IsInFtn() )
{
SwFlowFrm *pFlow = SwFlowFrm::CastFlowFrm( pFrm );
if ( !pFlow->IsFollow() )
{
if ( !pFrm->GetIndPrev() )
{
if ( bInvaKeep )
{
SwFrm *pPre = pFrm->FindPrev();
if ( pPre && pPre->IsFlowFrm() )
{
// 1. pPre wants to keep with me:
bool bInvalidPrePos = SwFlowFrm::CastFlowFrm( pPre )->IsKeep( *pPre->GetAttrSet() ) && pPre->GetIndPrev();
// 2. pPre is a table and the last row wants to keep with me:
if ( !bInvalidPrePos && pPre->IsTabFrm() )
{
SwTabFrm* pPreTab = static_cast<SwTabFrm*>(pPre);
if ( pPreTab->GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) )
{
SwRowFrm* pLastRow = static_cast<SwRowFrm*>(pPreTab->GetLastLower());
if ( pLastRow && pLastRow->ShouldRowKeepWithNext() )
bInvalidPrePos = true;
}
}
if ( bInvalidPrePos )
pPre->InvalidatePos();
}
}
}
else if ( !pFlow->HasFollow() )
{
long nOldHeight = (aFrm.*fnRect->fnGetHeight)();
long nNewHeight = (pFrm->Frm().*fnRect->fnGetHeight)();
if( (nOldHeight > nNewHeight) || (!nOldHeight && nNewHeight) )
pFlow->CheckKeep();
}
}
}
if ( bAbsP )
{
pFrm->SetCompletePaint();
SwFrm* pNxt = pFrm->GetIndNext();
// #121888# - skip empty section frames
while ( pNxt &&
pNxt->IsSctFrm() && !static_cast<SwSectionFrm*>(pNxt)->GetSection() )
{
pNxt = pNxt->GetIndNext();
}
if ( pNxt )
pNxt->InvalidatePos();
else
{
// #104100# - correct condition for setting retouche
// flag for vertical layout.
if( pFrm->IsRetoucheFrm() &&
(aFrm.*fnRect->fnTopDist)( (pFrm->Frm().*fnRect->fnGetTop)() ) > 0 )
{
pFrm->SetRetouche();
}
// A fresh follow frame does not have to be invalidated, because
// it is already formatted:
if ( bHadFollow || !pFrm->IsCntntFrm() || !((SwCntntFrm*)pFrm)->GetFollow() )
{
if ( !pFrm->IsTabFrm() || !((SwTabFrm*)pFrm)->GetFollow() )
pFrm->InvalidateNextPos();
}
}
}
//Fuer Hintergrundgrafiken muss bei Groessenaenderungen ein Repaint her.
const sal_Bool bPrtWidth =
(aPrt.*fnRect->fnGetWidth)() != (pFrm->Prt().*fnRect->fnGetWidth)();
const sal_Bool bPrtHeight =
(aPrt.*fnRect->fnGetHeight)()!=(pFrm->Prt().*fnRect->fnGetHeight)();
if ( bPrtWidth || bPrtHeight )
{
const SvxGraphicPosition ePos = pFrm->GetAttrSet()->GetBackground().GetGraphicPos();
if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
pFrm->SetCompletePaint();
}
else
{
// #97597# - consider case that *only* margins between
// frame and printing area has changed. Then, frame has to be repainted,
// in order to force paint of the margin areas.
if ( !bAbsP && (bChgWidth || bChgHeight) )
{
pFrm->SetCompletePaint();
}
}
const sal_Bool bPrtP = POS_DIFF( aPrt, pFrm->Prt() );
if ( bAbsP || bPrtP || bChgWidth || bChgHeight ||
bPrtWidth || bPrtHeight || bChgFlyBasePos )
{
if( pFrm->IsAccessibleFrm() )
{
SwRootFrm *pRootFrm = pFrm->getRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pFrm, aFrm );
}
}
// Notification of anchored objects
if ( pFrm->GetDrawObjs() )
{
const SwSortedObjs &rObjs = *pFrm->GetDrawObjs();
SwPageFrm* pPageFrm = 0;
for ( sal_uInt32 i = 0; i < rObjs.Count(); ++i )
{
// OD 2004-03-31 #i26791# - no general distinction between
// Writer fly frames and drawing objects
bool bNotify = false;
bool bNotifySize = false;
SwAnchoredObject* pObj = rObjs[i];
SwContact* pContact = ::GetUserCall( pObj->GetDrawObj() );
// --> OD 2004-12-08 #115759#
const bool bAnchoredAsChar = pContact->ObjAnchoredAsChar();
if ( !bAnchoredAsChar )
// <--
{
// Notify object, which aren't anchored as-character:
// always notify objects, if frame position has changed
// or if the object is to-page|to-fly anchored.
if ( bAbsP ||
pContact->ObjAnchoredAtPage() ||
pContact->ObjAnchoredAtFly() )
{
bNotify = true;
// assure that to-fly anchored Writer fly frames are
// registered at the correct page frame, if frame
// position has changed.
if ( bAbsP && pContact->ObjAnchoredAtFly() &&
pObj->ISA(SwFlyFrm) )
{
// determine to-fly anchored Writer fly frame
SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj);
// determine page frame of to-fly anchored
// Writer fly frame
SwPageFrm* pFlyPageFrm = pFlyFrm->FindPageFrm();
// determine page frame, if needed.
if ( !pPageFrm )
{
pPageFrm = pFrm->FindPageFrm();
}
if ( pPageFrm != pFlyPageFrm )
{
ASSERT( pFlyPageFrm, "~SwFrmNotify: Fly from Nowhere" );
if( pFlyPageFrm )
pFlyPageFrm->MoveFly( pFlyFrm, pPageFrm );
else
pPageFrm->AppendFlyToPage( pFlyFrm );
}
}
}
// otherwise the objects are notified in dependence to
// its positioning and alignment
else
{
const SwFmtVertOrient& rVert =
pContact->GetFmt()->GetVertOrient();
if ( ( rVert.GetVertOrient() == text::VertOrientation::CENTER ||
rVert.GetVertOrient() == text::VertOrientation::BOTTOM ||
rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
( bChgHeight || bPrtHeight ) )
{
bNotify = true;
}
if ( !bNotify )
{
const SwFmtHoriOrient& rHori =
pContact->GetFmt()->GetHoriOrient();
if ( ( rHori.GetHoriOrient() != text::HoriOrientation::NONE ||
rHori.GetRelationOrient()== text::RelOrientation::PRINT_AREA ||
rHori.GetRelationOrient()== text::RelOrientation::FRAME ) &&
( bChgWidth || bPrtWidth || bChgFlyBasePos ) )
{
bNotify = true;
}
}
}
}
else if ( bPrtWidth )
{
// Notify as-character anchored objects, if printing area
// width has changed.
bNotify = true;
bNotifySize = true;
}
// perform notification via the corresponding invalidations
if ( bNotify )
{
if ( pObj->ISA(SwFlyFrm) )
{
SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj);
if ( bNotifySize )
pFlyFrm->_InvalidateSize();
// --> OD 2004-12-08 #115759# - no invalidation of
// position for as-character anchored objects.
if ( !bAnchoredAsChar )
{
pFlyFrm->_InvalidatePos();
}
// <--
pFlyFrm->_Invalidate();
}
else if ( pObj->ISA(SwAnchoredDrawObject) )
{
// --> OD 2004-12-08 #115759# - no invalidation of
// position for as-character anchored objects.
if ( !bAnchoredAsChar )
{
pObj->InvalidateObjPos();
}
// <--
}
else
{
ASSERT( false,
"<SwCntntNotify::~SwCntntNotify()> - unknown anchored object type. Please inform OD." );
}
}
}
}
}
else if( pFrm->IsTxtFrm() && bValidSize != pFrm->GetValidSizeFlag() )
{
SwRootFrm *pRootFrm = pFrm->getRootFrm();
if( pRootFrm && pRootFrm->IsAnyShellAccessible() &&
pRootFrm->GetCurrShell() )
{
pRootFrm->GetCurrShell()->Imp()->InvalidateAccessibleFrmContent( pFrm );
}
}
// #i9046# Automatic frame width
SwFlyFrm* pFly = 0;
// --> FME 2004-10-21 #i35879# Do not trust the inf flags. pFrm does not
// necessarily have to have an upper!
if ( !pFrm->IsFlyFrm() && 0 != ( pFly = pFrm->ImplFindFlyFrm() ) )
// <--
{
// --> OD 2006-05-08 #i61999#
// no invalidation of columned Writer fly frames, because automatic
// width doesn't make sense for such Writer fly frames.
if ( pFly->Lower() && !pFly->Lower()->IsColumnFrm() )
{
const SwFmtFrmSize &rFrmSz = pFly->GetFmt()->GetFrmSize();
// This could be optimized. Basically the fly frame only has to
// be invalidated, if the first line of pFrm (if pFrm is a content
// frame, for other frame types its the print area) has changed its
// size and pFrm was responsible for the current width of pFly. On
// the other hand, this is only rarely used and re-calculation of
// the fly frame does not cause too much trouble. So we keep it this
// way:
if ( ATT_FIX_SIZE != rFrmSz.GetWidthSizeType() )
{
// --> OD 2005-07-29 #i50668#, #i50998# - invalidation of position
// of as-character anchored fly frames not needed and can cause
// layout loops
if ( !pFly->ISA(SwFlyInCntFrm) )
{
pFly->InvalidatePos();
}
// <--
pFly->InvalidateSize();
}
}
// <--
}
}
/*************************************************************************/
SwLayNotify::SwLayNotify( SwLayoutFrm *pLayFrm ) :
SwFrmNotify( pLayFrm ),
bLowersComplete( sal_False )
{
}
/*************************************************************************/
// OD 2004-05-11 #i28701# - local method to invalidate the position of all
// frames inclusive its floating screen objects, which are lowers of the given
// layout frame
void lcl_InvalidatePosOfLowers( SwLayoutFrm& _rLayoutFrm )
{
if( _rLayoutFrm.IsFlyFrm() && _rLayoutFrm.GetDrawObjs() )
{
_rLayoutFrm.InvalidateObjs( true, false );
}
SwFrm* pLowerFrm = _rLayoutFrm.Lower();
while ( pLowerFrm )
{
pLowerFrm->InvalidatePos();
if ( pLowerFrm->IsTxtFrm() )
{
static_cast<SwTxtFrm*>(pLowerFrm)->Prepare( PREP_POS_CHGD );
}
else if ( pLowerFrm->IsTabFrm() )
{
pLowerFrm->InvalidatePrt();
}
pLowerFrm->InvalidateObjs( true, false );
pLowerFrm = pLowerFrm->GetNext();
};
}
SwLayNotify::~SwLayNotify()
{
// --> OD 2005-07-29 #i49383#
if ( mbFrmDeleted )
{
return;
}
// <--
SwLayoutFrm *pLay = GetLay();
SWRECTFN( pLay )
sal_Bool bNotify = sal_False;
if ( pLay->Prt().SSize() != aPrt.SSize() )
{
if ( !IsLowersComplete() )
{
sal_Bool bInvaPercent;
if ( pLay->IsRowFrm() )
{
bInvaPercent = sal_True;
long nNew = (pLay->Prt().*fnRect->fnGetHeight)();
if( nNew != (aPrt.*fnRect->fnGetHeight)() )
((SwRowFrm*)pLay)->AdjustCells( nNew, sal_True);
if( (pLay->Prt().*fnRect->fnGetWidth)()
!= (aPrt.*fnRect->fnGetWidth)() )
((SwRowFrm*)pLay)->AdjustCells( 0, sal_False );
}
else
{
//Proportionale Anpassung der innenliegenden.
//1. Wenn der Formatierte kein Fly ist
//2. Wenn er keine Spalten enthaelt
//3. Wenn der Fly eine feste Hoehe hat und die Spalten in der
// Hoehe danebenliegen.
//4. niemals bei SectionFrms.
sal_Bool bLow;
if( pLay->IsFlyFrm() )
{
if ( pLay->Lower() )
{
bLow = !pLay->Lower()->IsColumnFrm() ||
(pLay->Lower()->Frm().*fnRect->fnGetHeight)()
!= (pLay->Prt().*fnRect->fnGetHeight)();
}
else
bLow = sal_False;
}
else if( pLay->IsSctFrm() )
{
if ( pLay->Lower() )
{
if( pLay->Lower()->IsColumnFrm() && pLay->Lower()->GetNext() )
bLow = pLay->Lower()->Frm().Height() != pLay->Prt().Height();
else
bLow = pLay->Prt().Width() != aPrt.Width();
}
else
bLow = sal_False;
}
else if( pLay->IsFooterFrm() && !pLay->HasFixSize() )
bLow = pLay->Prt().Width() != aPrt.Width();
else
bLow = sal_True;
bInvaPercent = bLow;
if ( bLow )
{
pLay->ChgLowersProp( aPrt.SSize() );
}
//Wenn die PrtArea gewachsen ist, so ist es moeglich, dass die
//Kette der Untergeordneten einen weiteren Frm aufnehmen kann,
//mithin muss also der 'moeglicherweise passende' Invalidiert werden.
//Das invalidieren lohnt nur, wenn es sich beim mir bzw. meinen
//Uppers um eine Moveable-Section handelt.
//Die PrtArea ist gewachsen, wenn die Breite oder die Hoehe groesser
//geworden ist.
if ( (pLay->Prt().Height() > aPrt.Height() ||
pLay->Prt().Width() > aPrt.Width()) &&
(pLay->IsMoveable() || pLay->IsFlyFrm()) )
{
SwFrm *pTmpFrm = pLay->Lower();
if ( pTmpFrm && pTmpFrm->IsFlowFrm() )
{
while ( pTmpFrm->GetNext() )
pTmpFrm = pTmpFrm->GetNext();
pTmpFrm->InvalidateNextPos();
}
}
}
bNotify = sal_True;
//TEUER!! aber wie macht man es geschickter?
if( bInvaPercent )
pLay->InvaPercentLowers( pLay->Prt().Height() - aPrt.Height() );
}
if ( pLay->IsTabFrm() )
//Damit _nur_ der Shatten bei Groessenaenderungen gemalt wird.
((SwTabFrm*)pLay)->SetComplete();
else
{
const ViewShell *pSh = pLay->getRootFrm()->GetCurrShell();
if( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ||
!(pLay->GetType() & (FRM_BODY | FRM_PAGE)) )
//Damit die untergeordneten sauber retouchiert werden.
//Problembsp: Flys an den Henkeln packen und verkleinern.
//Nicht fuer Body und Page, sonst flackerts beim HTML-Laden.
pLay->SetCompletePaint();
}
}
//Lower benachrichtigen wenn sich die Position veraendert hat.
const sal_Bool bPrtPos = POS_DIFF( aPrt, pLay->Prt() );
const sal_Bool bPos = bPrtPos || POS_DIFF( aFrm, pLay->Frm() );
const sal_Bool bSize = pLay->Frm().SSize() != aFrm.SSize();
if ( bPos && pLay->Lower() && !IsLowersComplete() )
pLay->Lower()->InvalidatePos();
if ( bPrtPos )
pLay->SetCompletePaint();
//Nachfolger benachrichtigen wenn sich die SSize geaendert hat.
if ( bSize )
{
if( pLay->GetNext() )
{
if ( pLay->GetNext()->IsLayoutFrm() )
pLay->GetNext()->_InvalidatePos();
else
pLay->GetNext()->InvalidatePos();
}
else if( pLay->IsSctFrm() )
pLay->InvalidateNextPos();
}
if ( !IsLowersComplete() &&
!(pLay->GetType()&(FRM_FLY|FRM_SECTION) &&
pLay->Lower() && pLay->Lower()->IsColumnFrm()) &&
(bPos || bNotify) && !(pLay->GetType() & 0x1823) ) //Tab, Row, FtnCont, Root, Page
{
// --> OD 2005-03-11 #i44016# - force unlock of position of lower objects.
// --> OD 2005-03-30 #i43913# - no unlock of position of objects,
// if <pLay> is a cell frame, and its table frame resp. its parent table
// frame is locked.
// --> OD 2005-04-15 #i47458# - force unlock of position of lower objects,
// only if position of layout frame has changed.
bool bUnlockPosOfObjs( bPos );
if ( bUnlockPosOfObjs && pLay->IsCellFrm() )
{
SwTabFrm* pTabFrm( pLay->FindTabFrm() );
if ( pTabFrm &&
( pTabFrm->IsJoinLocked() ||
( pTabFrm->IsFollow() &&
pTabFrm->FindMaster()->IsJoinLocked() ) ) )
{
bUnlockPosOfObjs = false;
}
}
// --> OD 2005-05-18 #i49383# - check for footnote frame, if unlock
// of position of lower objects is allowed.
else if ( bUnlockPosOfObjs && pLay->IsFtnFrm() )
{
bUnlockPosOfObjs = static_cast<SwFtnFrm*>(pLay)->IsUnlockPosOfLowerObjs();
}
// <--
// --> OD 2005-07-29 #i51303# - no unlock of object positions for sections
else if ( bUnlockPosOfObjs && pLay->IsSctFrm() )
{
bUnlockPosOfObjs = false;
}
// <--
pLay->NotifyLowerObjs( bUnlockPosOfObjs );
// <--
}
if ( bPos && pLay->IsFtnFrm() && pLay->Lower() )
{
// OD 2004-05-11 #i28701#
::lcl_InvalidatePosOfLowers( *pLay );
}
if( ( bPos || bSize ) && pLay->IsFlyFrm() && ((SwFlyFrm*)pLay)->GetAnchorFrm()
&& ((SwFlyFrm*)pLay)->GetAnchorFrm()->IsFlyFrm() )
((SwFlyFrm*)pLay)->AnchorFrm()->InvalidateSize();
}
/*************************************************************************/
SwFlyNotify::SwFlyNotify( SwFlyFrm *pFlyFrm ) :
SwLayNotify( pFlyFrm ),
// --> OD 2004-11-24 #115759# - keep correct page frame - the page frame
// the Writer fly frame is currently registered at.
pOldPage( pFlyFrm->GetPageFrm() ),
// <--
aFrmAndSpace( pFlyFrm->GetObjRectWithSpaces() )
{
}
/*************************************************************************/
SwFlyNotify::~SwFlyNotify()
{
// --> OD 2005-07-29 #i49383#
if ( mbFrmDeleted )
{
return;
}
// <--
SwFlyFrm *pFly = GetFly();
if ( pFly->IsNotifyBack() )
{
ViewShell *pSh = pFly->getRootFrm()->GetCurrShell();
SwViewImp *pImp = pSh ? pSh->Imp() : 0;
if ( !pImp || !pImp->IsAction() || !pImp->GetLayAction().IsAgain() )
{
//Wenn in der LayAction das IsAgain gesetzt ist kann es sein,
//dass die alte Seite inzwischen vernichtet wurde!
::Notify( pFly, pOldPage, aFrmAndSpace, &aPrt );
// --> OD 2004-10-20 #i35640# - additional notify anchor text frame,
// if Writer fly frame has changed its page
if ( pFly->GetAnchorFrm()->IsTxtFrm() &&
pFly->GetPageFrm() != pOldPage )
{
pFly->AnchorFrm()->Prepare( PREP_FLY_LEAVE );
}
// <--
}
pFly->ResetNotifyBack();
}
//Haben sich Groesse oder Position geaendert, so sollte die View
//das wissen.
SWRECTFN( pFly )
const bool bPosChgd = POS_DIFF( aFrm, pFly->Frm() );
const bool bFrmChgd = pFly->Frm().SSize() != aFrm.SSize();
const bool bPrtChgd = aPrt != pFly->Prt();
if ( bPosChgd || bFrmChgd || bPrtChgd )
{
pFly->NotifyDrawObj();
}
if ( bPosChgd && aFrm.Pos().X() != WEIT_WECH )
{
// OD 2004-05-10 #i28701# - no direct move of lower Writer fly frames.
// reason: New positioning and alignment (e.g. to-paragraph anchored,
// but aligned at page) are introduced.
// <SwLayNotify::~SwLayNotify()> takes care of invalidation of lower
// floating screen objects by calling method <SwLayoutFrm::NotifyLowerObjs()>.
if ( pFly->IsFlyAtCntFrm() )
{
SwFrm *pNxt = pFly->AnchorFrm()->FindNext();
if ( pNxt )
{
pNxt->InvalidatePos();
}
}
// --> OD 2004-11-05 #i26945# - notify anchor.
// Needed for negative positioned Writer fly frames
if ( pFly->GetAnchorFrm()->IsTxtFrm() )
{
pFly->AnchorFrm()->Prepare( PREP_FLY_LEAVE );
}
// <--
}
// OD 2004-05-13 #i28701#
// --> OD 2005-03-21 #i45180# - no adjustment of layout process flags and
// further notifications/invalidations, if format is called by grow/shrink
if ( pFly->ConsiderObjWrapInfluenceOnObjPos() &&
( !pFly->ISA(SwFlyFreeFrm) ||
!static_cast<SwFlyFreeFrm*>(pFly)->IsNoMoveOnCheckClip() ) )
// <--
{
// --> OD 2005-09-05 #i54138# - suppress restart of the layout process
// on changed frame height.
// Note: It doesn't seem to be necessary and can cause layout loops.
if ( bPosChgd )
// <--
{
// indicate a restart of the layout process
pFly->SetRestartLayoutProcess( true );
}
else
{
// lock position
pFly->LockPosition();
if ( !pFly->ConsiderForTextWrap() )
{
// indicate that object has to be considered for text wrap
pFly->SetConsiderForTextWrap( true );
// invalidate 'background' in order to allow its 'background'
// to wrap around it.
pFly->NotifyBackground( pFly->GetPageFrm(),
pFly->GetObjRectWithSpaces(),
PREP_FLY_ARRIVE );
// invalidate position of anchor frame in order to force
// a re-format of the anchor frame, which also causes a
// re-format of the invalid previous frames of the anchor frame.
pFly->AnchorFrm()->InvalidatePos();
}
}
}
}
/*************************************************************************/
SwCntntNotify::SwCntntNotify( SwCntntFrm *pCntntFrm ) :
SwFrmNotify( pCntntFrm ),
// OD 08.01.2004 #i11859#
mbChkHeightOfLastLine( false ),
mnHeightOfLastLine( 0L ),
// OD 2004-02-26 #i25029#
mbInvalidatePrevPrtArea( false ),
mbBordersJoinedWithPrev( false )
{
// OD 08.01.2004 #i11859#
if ( pCntntFrm->IsTxtFrm() )
{
SwTxtFrm* pTxtFrm = static_cast<SwTxtFrm*>(pCntntFrm);
if ( !pTxtFrm->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::OLD_LINE_SPACING) )
{
const SwAttrSet* pSet = pTxtFrm->GetAttrSet();
const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
if ( rSpace.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
{
mbChkHeightOfLastLine = true;
mnHeightOfLastLine = pTxtFrm->GetHeightOfLastLine();
}
}
}
}
/*************************************************************************/
SwCntntNotify::~SwCntntNotify()
{
// --> OD 2005-07-29 #i49383#
if ( mbFrmDeleted )
{
return;
}
// <--
SwCntntFrm *pCnt = GetCnt();
if ( bSetCompletePaintOnInvalidate )
pCnt->SetCompletePaint();
SWRECTFN( pCnt )
if ( pCnt->IsInTab() && ( POS_DIFF( pCnt->Frm(), aFrm ) ||
pCnt->Frm().SSize() != aFrm.SSize()))
{
SwLayoutFrm* pCell = pCnt->GetUpper();
while( !pCell->IsCellFrm() && pCell->GetUpper() )
pCell = pCell->GetUpper();
ASSERT( pCell->IsCellFrm(), "Where's my cell?" );
if ( text::VertOrientation::NONE != pCell->GetFmt()->GetVertOrient().GetVertOrient() )
pCell->InvalidatePrt(); //fuer vertikale Ausrichtung.
}
// OD 2004-02-26 #i25029#
if ( mbInvalidatePrevPrtArea && mbBordersJoinedWithPrev &&
pCnt->IsTxtFrm() &&
!pCnt->IsFollow() && !pCnt->GetIndPrev() )
{
// determine previous frame
SwFrm* pPrevFrm = pCnt->FindPrev();
// skip empty section frames and hidden text frames
{
while ( pPrevFrm &&
( ( pPrevFrm->IsSctFrm() &&
!static_cast<SwSectionFrm*>(pPrevFrm)->GetSection() ) ||
( pPrevFrm->IsTxtFrm() &&
static_cast<SwTxtFrm*>(pPrevFrm)->IsHiddenNow() ) ) )
{
pPrevFrm = pPrevFrm->FindPrev();
}
}
// Invalidate printing area of found previous frame
if ( pPrevFrm )
{
if ( pPrevFrm->IsSctFrm() )
{
if ( pCnt->IsInSct() )
{
// Note: found previous frame is a section frame and
// <pCnt> is also inside a section.
// Thus due to <mbBordersJoinedWithPrev>,
// <pCnt> had joined its borders/shadow with the
// last content of the found section.
// Invalidate printing area of last content in found section.
SwFrm* pLstCntntOfSctFrm =
static_cast<SwSectionFrm*>(pPrevFrm)->FindLastCntnt();
if ( pLstCntntOfSctFrm )
{
pLstCntntOfSctFrm->InvalidatePrt();
}
}
}
else
{
pPrevFrm->InvalidatePrt();
}
}
}
const bool bFirst = (aFrm.*fnRect->fnGetWidth)() == 0;
if ( pCnt->IsNoTxtFrm() )
{
//Aktive PlugIn's oder OLE-Objekte sollten etwas von der Veraenderung
//mitbekommen, damit sie Ihr Window entsprechend verschieben.
ViewShell *pSh = pCnt->getRootFrm()->GetCurrShell();
if ( pSh )
{
SwOLENode *pNd;
if ( 0 != (pNd = pCnt->GetNode()->GetOLENode()) &&
(pNd->GetOLEObj().IsOleRef() ||
pNd->IsOLESizeInvalid()) )
{
// --> OD #i117189#
const bool bNoTxtFrmPrtAreaChanged =
( aPrt.SSize().Width() != 0 &&
aPrt.SSize().Height() != 0 ) &&
aPrt.SSize() != pCnt->Prt().SSize();
// <--
ASSERT( pCnt->IsInFly(), "OLE not in FlyFrm" );
SwFlyFrm *pFly = pCnt->FindFlyFrm();
svt::EmbeddedObjectRef& xObj = pNd->GetOLEObj().GetObject();
SwFEShell *pFESh = 0;
ViewShell *pTmp = pSh;
do
{ if ( pTmp->ISA( SwCrsrShell ) )
{
pFESh = (SwFEShell*)pTmp;
// #108369#: Here used to be the condition if (!bFirst).
// I think this should mean "do not call CalcAndSetScale"
// if the frame is formatted for the first time.
// Unfortunately this is not valid anymore since the
// SwNoTxtFrm already gets a width during CalcLowerPreps.
// Nevertheless, the indention of !bFirst seemed to be
// to assure that the OLE objects have already been notified
// if necessary before calling CalcAndSetScale.
// So I replaced !bFirst by !IsOLESizeInvalid. There is
// one additional problem specific to the word import:
// The layout is calculated _before_ calling PrtOLENotify,
// and the OLE objects are not invalidated during import.
// Therefore I added the condition !IsUpdateExpFld,
// have a look at the occurence of CalcLayout in
// uiview/view.cxx.
if ( !pNd->IsOLESizeInvalid() &&
!pSh->GetDoc()->IsUpdateExpFld() )
pFESh->CalcAndSetScale( xObj,
&pFly->Prt(), &pFly->Frm(),
bNoTxtFrmPrtAreaChanged );
}
pTmp = (ViewShell*)pTmp->GetNext();
} while ( pTmp != pSh );
if ( pFESh && pNd->IsOLESizeInvalid() )
{
pNd->SetOLESizeInvalid( sal_False );
//TODO/LATER: needs OnDocumentPrinterChanged
//xObj->OnDocumentPrinterChanged( pNd->GetDoc()->getPrinter( false ) );
pFESh->CalcAndSetScale( xObj );//Client erzeugen lassen.
}
}
//dito Animierte Grafiken
if ( Frm().HasArea() && ((SwNoTxtFrm*)pCnt)->HasAnimation() )
{
((SwNoTxtFrm*)pCnt)->StopAnimation();
pSh->InvalidateWindows( Frm() );
}
}
}
if ( bFirst )
{
pCnt->SetRetouche(); //fix(13870)
SwDoc *pDoc = pCnt->GetNode()->GetDoc();
if ( pDoc->GetSpzFrmFmts()->Count() &&
pDoc->DoesContainAtPageObjWithContentAnchor() && !pDoc->IsNewDoc() )
{
// If certain import filters for foreign file format import
// AT_PAGE anchored objects, the corresponding page number is
// typically not known. In this case the content position is
// stored at which the anchored object is found in the
// imported document.
// When this content is formatted it is the time at which
// the page is known. Thus, this data can be corrected now.
const SwPageFrm* pPage = 0;
SwNodeIndex *pIdx = 0;
SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts();
for ( sal_uInt16 i = 0; i < pTbl->Count(); ++i )
{
SwFrmFmt *pFmt = (*pTbl)[i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
if ( FLY_AT_PAGE != rAnch.GetAnchorId() ||
rAnch.GetCntntAnchor() == 0 )
{
continue;
}
if ( !pIdx )
{
pIdx = new SwNodeIndex( *pCnt->GetNode() );
}
if ( rAnch.GetCntntAnchor()->nNode == *pIdx )
{
ASSERT( false, "<SwCntntNotify::~SwCntntNotify()> - to page anchored object with content position. Please inform OD." );
if ( !pPage )
{
pPage = pCnt->FindPageFrm();
}
SwFmtAnchor aAnch( rAnch );
aAnch.SetAnchor( 0 );
aAnch.SetPageNum( pPage->GetPhyPageNum() );
pFmt->SetFmtAttr( aAnch );
if ( RES_DRAWFRMFMT != pFmt->Which() )
{
pFmt->MakeFrms();
}
}
}
delete pIdx;
}
}
// OD 12.01.2004 #i11859# - invalidate printing area of following frame,
// if height of last line has changed.
if ( pCnt->IsTxtFrm() && mbChkHeightOfLastLine )
{
if ( mnHeightOfLastLine != static_cast<SwTxtFrm*>(pCnt)->GetHeightOfLastLine() )
{
pCnt->InvalidateNextPrtArea();
}
}
// --> OD 2005-03-07 #i44049#
if ( pCnt->IsTxtFrm() && POS_DIFF( aFrm, pCnt->Frm() ) )
{
pCnt->InvalidateObjs( true );
}
// <--
// --> OD 2005-04-12 #i43255# - move code to invalidate at-character
// anchored objects due to a change of its anchor character from
// method <SwTxtFrm::Format(..)>.
if ( pCnt->IsTxtFrm() )
{
SwTxtFrm* pMasterFrm = pCnt->IsFollow()
? static_cast<SwTxtFrm*>(pCnt)->FindMaster()
: static_cast<SwTxtFrm*>(pCnt);
if ( pMasterFrm && !pMasterFrm->IsFlyLock() &&
pMasterFrm->GetDrawObjs() )
{
SwSortedObjs* pObjs = pMasterFrm->GetDrawObjs();
for ( sal_uInt32 i = 0; i < pObjs->Count(); ++i )
{
SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId()
== FLY_AT_CHAR )
{
pAnchoredObj->CheckCharRectAndTopOfLine( !pMasterFrm->IsEmpty() );
}
}
}
}
// <--
}
/*************************************************************************/
void AppendObjs( const SwSpzFrmFmts *pTbl, sal_uLong nIndex,
SwFrm *pFrm, SwPageFrm *pPage )
{
for ( sal_uInt16 i = 0; i < pTbl->Count(); ++i )
{
SwFrmFmt *pFmt = (SwFrmFmt*)(*pTbl)[i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
if ( rAnch.GetCntntAnchor() &&
(rAnch.GetCntntAnchor()->nNode.GetIndex() == nIndex) )
{
const bool bFlyAtFly = rAnch.GetAnchorId() == FLY_AT_FLY; // LAYER_IMPL
//Wird ein Rahmen oder ein SdrObject beschrieben?
const bool bSdrObj = RES_DRAWFRMFMT == pFmt->Which();
// OD 23.06.2003 #108784# - append also drawing objects anchored
// as character.
const bool bDrawObjInCntnt = bSdrObj &&
(rAnch.GetAnchorId() == FLY_AS_CHAR);
if( bFlyAtFly ||
(rAnch.GetAnchorId() == FLY_AT_PARA) ||
(rAnch.GetAnchorId() == FLY_AT_CHAR) ||
bDrawObjInCntnt )
{
SdrObject* pSdrObj = 0;
if ( bSdrObj && 0 == (pSdrObj = pFmt->FindSdrObject()) )
{
ASSERT( !bSdrObj, "DrawObject not found." );
pFmt->GetDoc()->DelFrmFmt( pFmt );
--i;
continue;
}
if ( pSdrObj )
{
if ( !pSdrObj->GetPage() )
{
pFmt->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
InsertObject(pSdrObj, pSdrObj->GetOrdNumDirect());
}
SwDrawContact* pNew =
static_cast<SwDrawContact*>(GetUserCall( pSdrObj ));
if ( !pNew->GetAnchorFrm() )
{
pFrm->AppendDrawObj( *(pNew->GetAnchoredObj( 0L )) );
}
// OD 19.06.2003 #108784# - add 'virtual' drawing object,
// if necessary. But control objects have to be excluded.
else if ( !::CheckControlLayer( pSdrObj ) &&
pNew->GetAnchorFrm() != pFrm &&
!pNew->GetDrawObjectByAnchorFrm( *pFrm ) )
{
SwDrawVirtObj* pDrawVirtObj = pNew->AddVirtObj();
pFrm->AppendDrawObj( *(pNew->GetAnchoredObj( pDrawVirtObj )) );
// for repaint, use new ActionChanged()
// pDrawVirtObj->SendRepaintBroadcast();
pDrawVirtObj->ActionChanged();
}
}
else
{
SwFlyFrm *pFly;
if( bFlyAtFly )
pFly = new SwFlyLayFrm( (SwFlyFrmFmt*)pFmt, pFrm, pFrm );
else
pFly = new SwFlyAtCntFrm( (SwFlyFrmFmt*)pFmt, pFrm, pFrm );
pFly->Lock();
pFrm->AppendFly( pFly );
pFly->Unlock();
if ( pPage )
::RegistFlys( pPage, pFly );
}
}
}
}
}
bool lcl_ObjConnected( SwFrmFmt *pFmt, const SwFrm* pSib )
{
SwIterator<SwFlyFrm,SwFmt> aIter( *pFmt );
if ( RES_FLYFRMFMT == pFmt->Which() )
{
const SwRootFrm* pRoot = pSib ? pSib->getRootFrm() : 0;
const SwFlyFrm* pTmpFrm;
for( pTmpFrm = aIter.First(); pTmpFrm; pTmpFrm = aIter.Next() )
{
if(! pRoot || pRoot == pTmpFrm->getRootFrm() )
return true;
}
}
else
{
SwDrawContact *pContact = SwIterator<SwDrawContact,SwFmt>::FirstElement(*pFmt);
if ( pContact )
return pContact->GetAnchorFrm() != 0;
}
return false;
}
/** helper method to determine, if a <SwFrmFmt>, which has an object connected,
is located in header or footer.
OD 23.06.2003 #108784#
@author OD
*/
bool lcl_InHeaderOrFooter( SwFrmFmt& _rFmt )
{
bool bRetVal = false;
const SwFmtAnchor& rAnch = _rFmt.GetAnchor();
if (rAnch.GetAnchorId() != FLY_AT_PAGE)
{
bRetVal = _rFmt.GetDoc()->IsInHeaderFooter( rAnch.GetCntntAnchor()->nNode );
}
return bRetVal;
}
void AppendAllObjs( const SwSpzFrmFmts *pTbl, const SwFrm* pSib )
{
//Verbinden aller Objekte, die in der SpzTbl beschrieben sind mit dem
//Layout.
//Wenn sich nix mehr tut hoeren wir auf. Dann koennen noch Formate
//uebrigbleiben, weil wir weder zeichengebunde Rahmen verbinden noch
//Objecte die in zeichengebundenen verankert sind.
SwSpzFrmFmts aCpy( 255, 255 );
aCpy.Insert( pTbl, 0 );
sal_uInt16 nOldCnt = USHRT_MAX;
while ( aCpy.Count() && aCpy.Count() != nOldCnt )
{
nOldCnt = aCpy.Count();
for ( int i = 0; i < int(aCpy.Count()); ++i )
{
SwFrmFmt *pFmt = (SwFrmFmt*)aCpy[ sal_uInt16(i) ];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
sal_Bool bRemove = sal_False;
if ((rAnch.GetAnchorId() == FLY_AT_PAGE) ||
(rAnch.GetAnchorId() == FLY_AS_CHAR))
{
//Seitengebunde sind bereits verankert, zeichengebundene
//will ich hier nicht.
bRemove = sal_True;
}
else if ( sal_False == (bRemove = ::lcl_ObjConnected( pFmt, pSib )) ||
::lcl_InHeaderOrFooter( *pFmt ) )
{
// OD 23.06.2003 #108784# - correction: for objects in header
// or footer create frames, in spite of the fact that an connected
// objects already exists.
//Fuer Flys und DrawObjs nur dann ein MakeFrms rufen wenn noch
//keine abhaengigen Existieren, andernfalls, oder wenn das
//MakeFrms keine abhaengigen erzeugt, entfernen.
pFmt->MakeFrms();
bRemove = ::lcl_ObjConnected( pFmt, pSib );
}
if ( bRemove )
{
aCpy.Remove( sal_uInt16(i) );
--i;
}
}
}
aCpy.Remove( 0, aCpy.Count() );
}
/** local method to set 'working' position for newly inserted frames
OD 12.08.2003 #i17969#
@author OD
*/
void lcl_SetPos( SwFrm& _rNewFrm,
const SwLayoutFrm& _rLayFrm )
{
SWRECTFN( (&_rLayFrm) )
(_rNewFrm.Frm().*fnRect->fnSetPos)( (_rLayFrm.Frm().*fnRect->fnGetPos)() );
// move position by one SwTwip in text flow direction in order to get
// notifications for a new calculated position after its formatting.
if ( bVert )
_rNewFrm.Frm().Pos().X() -= 1;
else
_rNewFrm.Frm().Pos().Y() += 1;
}
void MA_FASTCALL _InsertCnt( SwLayoutFrm *pLay, SwDoc *pDoc,
sal_uLong nIndex, sal_Bool bPages, sal_uLong nEndIndex,
SwFrm *pPrv )
{
pDoc->BlockIdling();
SwRootFrm* pLayout = pLay->getRootFrm();
const sal_Bool bOldCallbackActionEnabled = pLayout ? pLayout->IsCallbackActionEnabled() : sal_False;
if( bOldCallbackActionEnabled )
pLayout->SetCallbackActionEnabled( sal_False );
//Bei der Erzeugung des Layouts wird bPages mit sal_True uebergeben. Dann
//werden schon mal alle x Absaetze neue Seiten angelegt. Bei umbruechen
//und/oder Pagedescriptorwechseln werden gleich die entsprechenden Seiten
//angelegt.
//Vorteil ist, das einerseits schon eine annaehernd realistische Zahl von
//Seiten angelegt wird, vor allem aber gibt es nicht mehr eine schier
//lange Kette von Absaetzen teuer verschoben werden muss, bis sie sich auf
//ertraegliches mass reduziert hat.
//Wir gehen mal davon aus, da? 20 Absaetze auf eine Seite passen
//Damit es in extremen Faellen nicht gar so heftig rechenen wir je nach
//Node noch etwas drauf.
//Wenn in der DocStatistik eine brauchebare Seitenzahl angegeben ist
//(wird beim Schreiben gepflegt), so wird von dieser Seitenanzahl
//ausgegengen.
const sal_Bool bStartPercent = bPages && !nEndIndex;
SwPageFrm *pPage = pLay->FindPageFrm();
const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts();
SwFrm *pFrm = 0;
sal_Bool bBreakAfter = sal_False;
SwActualSection *pActualSection = 0;
SwLayHelper *pPageMaker;
//Wenn das Layout erzeugt wird (bPages == sal_True) steuern wir den Progress
//an. Flys und DrawObjekte werden dann nicht gleich verbunden, dies
//passiert erst am Ende der Funktion.
if ( bPages )
{
// Attention: the SwLayHelper class uses references to the content-,
// page-, layout-frame etc. and may change them!
pPageMaker = new SwLayHelper( pDoc, pFrm, pPrv, pPage, pLay,
pActualSection, bBreakAfter, nIndex, 0 == nEndIndex );
if( bStartPercent )
{
const sal_uLong nPageCount = pPageMaker->CalcPageCount();
if( nPageCount )
bObjsDirect = sal_False;
}
}
else
pPageMaker = NULL;
if( pLay->IsInSct() &&
( pLay->IsSctFrm() || pLay->GetUpper() ) ) // Hierdurch werden Frischlinge
// abgefangen, deren Flags noch nicht ermittelt werden koennen,
// so z.B. beim Einfuegen einer Tabelle
{
SwSectionFrm* pSct = pLay->FindSctFrm();
// Wenn Inhalt in eine Fussnote eingefuegt wird, die in einem spaltigen
// Bereich liegt, so darf der spaltige Bereich nicht aufgebrochen werden.
// Nur wenn im Innern der Fussnote ein Bereich liegt, ist dies ein
// Kandidat fuer pActualSection.
// Gleiches gilt fuer Bereiche in Tabellen, wenn innerhalb einer Tabelle
// eingefuegt wird, duerfen nur Bereiche, die ebenfalls im Innern liegen,
// aufgebrochen werden.
if( ( !pLay->IsInFtn() || pSct->IsInFtn() ) &&
( !pLay->IsInTab() || pSct->IsInTab() ) )
{
pActualSection = new SwActualSection( 0, pSct, 0 );
ASSERT( !pLay->Lower() || !pLay->Lower()->IsColumnFrm(),
"_InsertCnt: Wrong Call" );
}
}
//If a section is "open", the pActualSection points to an SwActualSection.
//If the page breaks, for "open" sections a follow will created.
//For nested sections (which have, however, not a nested layout),
//the SwActualSection class has a member, which points to an upper(section).
//When the "inner" section finishs, the upper will used instead.
while( sal_True )
{
SwNode *pNd = pDoc->GetNodes()[nIndex];
if ( pNd->IsCntntNode() )
{
SwCntntNode* pNode = (SwCntntNode*)pNd;
pFrm = pNode->IsTxtNode() ? new SwTxtFrm( (SwTxtNode*)pNode, pLay ) :
pNode->MakeFrm( pLay );
if( pPageMaker )
pPageMaker->CheckInsert( nIndex );
pFrm->InsertBehind( pLay, pPrv );
// --> OD 2005-12-01 #i27138#
// notify accessibility paragraphs objects about changed
// CONTENT_FLOWS_FROM/_TO relation.
// Relation CONTENT_FLOWS_FROM for next paragraph will change
// and relation CONTENT_FLOWS_TO for previous paragraph will change.
if ( pFrm->IsTxtFrm() )
{
ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
// no notification, if <ViewShell> is in construction
if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{
pViewShell->InvalidateAccessibleParaFlowRelation(
dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
// --> OD 2006-08-28 #i68958#
// The information flags of the text frame are validated
// in methods <FindNextCnt(..)> and <FindPrevCnt(..)>.
// The information flags have to be invalidated, because
// it is possible, that the one of its upper frames
// isn't inserted into the layout.
pFrm->InvalidateInfFlags();
// <--
}
}
// <--
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout
// for setting position at newly inserted frame
lcl_SetPos( *pFrm, *pLay );
pPrv = pFrm;
if ( pTbl->Count() && bObjsDirect && !bDontCreateObjects )
AppendObjs( pTbl, nIndex, pFrm, pPage );
}
else if ( pNd->IsTableNode() )
{ //Sollten wir auf eine Tabelle gestossen sein?
SwTableNode *pTblNode = (SwTableNode*)pNd;
// #108116# loading may produce table structures that GCLines
// needs to clean up. To keep table formulas correct, change
// all table formulas to internal (BOXPTR) representation.
SwTableFmlUpdate aMsgHnt( &pTblNode->GetTable() );
aMsgHnt.eFlags = TBL_BOXPTR;
pDoc->UpdateTblFlds( &aMsgHnt );
pTblNode->GetTable().GCLines();
pFrm = pTblNode->MakeFrm( pLay );
if( pPageMaker )
pPageMaker->CheckInsert( nIndex );
pFrm->InsertBehind( pLay, pPrv );
// --> OD 2005-12-01 #i27138#
// notify accessibility paragraphs objects about changed
// CONTENT_FLOWS_FROM/_TO relation.
// Relation CONTENT_FLOWS_FROM for next paragraph will change
// and relation CONTENT_FLOWS_TO for previous paragraph will change.
{
ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
// no notification, if <ViewShell> is in construction
if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{
pViewShell->InvalidateAccessibleParaFlowRelation(
dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
}
}
// <--
if ( bObjsDirect && pTbl->Count() )
((SwTabFrm*)pFrm)->RegistFlys();
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout
// for setting position at newly inserted frame
lcl_SetPos( *pFrm, *pLay );
pPrv = pFrm;
//Index auf den Endnode der Tabellensection setzen.
nIndex = pTblNode->EndOfSectionIndex();
SwTabFrm* pTmpFrm = (SwTabFrm*)pFrm;
while ( pTmpFrm )
{
pTmpFrm->CheckDirChange();
pTmpFrm = pTmpFrm->IsFollow() ? pTmpFrm->FindMaster() : NULL;
}
}
else if ( pNd->IsSectionNode() )
{
SwSectionNode *pNode = (SwSectionNode*)pNd;
if( pNode->GetSection().CalcHiddenFlag() )
// ist versteckt, ueberspringe den Bereich
nIndex = pNode->EndOfSectionIndex();
else
{
pFrm = pNode->MakeFrm( pLay );
pActualSection = new SwActualSection( pActualSection,
(SwSectionFrm*)pFrm, pNode );
if ( pActualSection->GetUpper() )
{
//Hinter den Upper einsetzen, beim EndNode wird der "Follow"
//des Uppers erzeugt.
SwSectionFrm *pTmp = pActualSection->GetUpper()->GetSectionFrm();
pFrm->InsertBehind( pTmp->GetUpper(), pTmp );
// OD 25.03.2003 #108339# - direct initialization of section
// after insertion in the layout
static_cast<SwSectionFrm*>(pFrm)->Init();
}
else
{
pFrm->InsertBehind( pLay, pPrv );
// OD 25.03.2003 #108339# - direct initialization of section
// after insertion in the layout
static_cast<SwSectionFrm*>(pFrm)->Init();
// --> FME 2004-09-08 #i33963#
// Do not trust the IsInFtn flag. If we are currently
// building up a table, the upper of pPrv may be a cell
// frame, but the cell frame does not have an upper yet.
if( pPrv && 0 != pPrv->ImplFindFtnFrm() )
// <--
{
if( pPrv->IsSctFrm() )
pPrv = ((SwSectionFrm*)pPrv)->ContainsCntnt();
if( pPrv && pPrv->IsTxtFrm() )
((SwTxtFrm*)pPrv)->Prepare( PREP_QUOVADIS, 0, sal_False );
}
}
// --> OD 2005-12-01 #i27138#
// notify accessibility paragraphs objects about changed
// CONTENT_FLOWS_FROM/_TO relation.
// Relation CONTENT_FLOWS_FROM for next paragraph will change
// and relation CONTENT_FLOWS_TO for previous paragraph will change.
{
ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
// no notification, if <ViewShell> is in construction
if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{
pViewShell->InvalidateAccessibleParaFlowRelation(
dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
}
}
// <--
pFrm->CheckDirChange();
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout
// for setting position at newly inserted frame
lcl_SetPos( *pFrm, *pLay );
// OD 20.11.2002 #105405# - no page, no invalidate.
if ( pPage )
{
// OD 18.09.2002 #100522#
// invalidate page in order to force format and paint of
// inserted section frame
pFrm->InvalidatePage( pPage );
// FME 10.11.2003 #112243#
// Invalidate fly content flag:
if ( pFrm->IsInFly() )
pPage->InvalidateFlyCntnt();
// OD 14.11.2002 #104684# - invalidate page content in order to
// force format and paint of section content.
pPage->InvalidateCntnt();
}
pLay = (SwLayoutFrm*)pFrm;
if ( pLay->Lower() && pLay->Lower()->IsLayoutFrm() )
pLay = pLay->GetNextLayoutLeaf();
pPrv = 0;
}
}
else if ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )
{
ASSERT( pActualSection, "Sectionende ohne Anfang?" );
ASSERT( pActualSection->GetSectionNode() == pNd->StartOfSectionNode(),
"Sectionende mit falschen Start Node?" );
//Section schliessen, ggf. die umgebende Section wieder
//aktivieren.
SwActualSection *pTmp = pActualSection->GetUpper();
delete pActualSection;
pLay = pLay->FindSctFrm();
if ( 0 != (pActualSection = pTmp) )
{
//Koennte noch sein, das der letzte SectionFrm leer geblieben
//ist. Dann ist es jetzt an der Zeit ihn zu entfernen.
if ( !pLay->ContainsCntnt() )
{
SwFrm *pTmpFrm = pLay;
pLay = pTmpFrm->GetUpper();
pPrv = pTmpFrm->GetPrev();
pTmpFrm->Remove();
delete pTmpFrm;
}
else
{
pPrv = pLay;
pLay = pLay->GetUpper();
}
// new section frame
pFrm = pActualSection->GetSectionNode()->MakeFrm( pLay );
pFrm->InsertBehind( pLay, pPrv );
static_cast<SwSectionFrm*>(pFrm)->Init();
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout
// for setting position at newly inserted frame
lcl_SetPos( *pFrm, *pLay );
SwSectionFrm* pOuterSectionFrm = pActualSection->GetSectionFrm();
// a follow has to be appended to the new section frame
SwSectionFrm* pFollow = pOuterSectionFrm->GetFollow();
if ( pFollow )
{
pOuterSectionFrm->SetFollow( NULL );
pOuterSectionFrm->InvalidateSize();
((SwSectionFrm*)pFrm)->SetFollow( pFollow );
}
// Wir wollen keine leeren Teile zuruecklassen
if( ! pOuterSectionFrm->IsColLocked() &&
! pOuterSectionFrm->ContainsCntnt() )
{
pOuterSectionFrm->DelEmpty( sal_True );
delete pOuterSectionFrm;
}
pActualSection->SetSectionFrm( (SwSectionFrm*)pFrm );
pLay = (SwLayoutFrm*)pFrm;
if ( pLay->Lower() && pLay->Lower()->IsLayoutFrm() )
pLay = pLay->GetNextLayoutLeaf();
pPrv = 0;
}
else
{
//Nix mehr mit Sections, es geht direkt hinter dem SectionFrame
//weiter.
pPrv = pLay;
pLay = pLay->GetUpper();
}
}
else if( pNd->IsStartNode() &&
SwFlyStartNode == ((SwStartNode*)pNd)->GetStartNodeType() )
{
if ( pTbl->Count() && bObjsDirect && !bDontCreateObjects )
{
SwFlyFrm* pFly = pLay->FindFlyFrm();
if( pFly )
AppendObjs( pTbl, nIndex, pFly, pPage );
}
}
else
// Weder Cntnt noch Tabelle noch Section,
// also muessen wir fertig sein.
break;
++nIndex;
// Der Endnode wird nicht mehr mitgenommen, es muss vom
// Aufrufenden (Section/MakeFrms()) sichergestellt sein, dass das Ende
// des Bereichs vor dem EndIndex liegt!
if ( nEndIndex && nIndex >= nEndIndex )
break;
}
if ( pActualSection )
{
//Kann passieren, dass noch eine leere (Follow-)Section uebrig geblieben ist.
if ( !(pLay = pActualSection->GetSectionFrm())->ContainsCntnt() )
{
pLay->Remove();
delete pLay;
}
delete pActualSection;
}
if ( bPages ) //Jetzt noch die Flys verbinden lassen.
{
if ( !bDontCreateObjects )
AppendAllObjs( pTbl, pLayout );
bObjsDirect = sal_True;
}
if( pPageMaker )
{
pPageMaker->CheckFlyCache( pPage );
delete pPageMaker;
if( pDoc->GetLayoutCache() )
{
#ifdef DBG_UTIL
#if OSL_DEBUG_LEVEL > 1
pDoc->GetLayoutCache()->CompareLayout( *pDoc );
#endif
#endif
pDoc->GetLayoutCache()->ClearImpl();
}
}
pDoc->UnblockIdling();
if( bOldCallbackActionEnabled )
pLayout->SetCallbackActionEnabled( bOldCallbackActionEnabled );
}
void MakeFrms( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
const SwNodeIndex &rEndIdx )
{
bObjsDirect = sal_False;
SwNodeIndex aTmp( rSttIdx );
sal_uLong nEndIdx = rEndIdx.GetIndex();
SwNode* pNd = pDoc->GetNodes().FindPrvNxtFrmNode( aTmp,
pDoc->GetNodes()[ nEndIdx-1 ]);
if ( pNd )
{
sal_Bool bApres = aTmp < rSttIdx;
SwNode2Layout aNode2Layout( *pNd, rSttIdx.GetIndex() );
SwFrm* pFrm;
while( 0 != (pFrm = aNode2Layout.NextFrm()) )
{
SwLayoutFrm *pUpper = pFrm->GetUpper();
SwFtnFrm* pFtnFrm = pUpper->FindFtnFrm();
sal_Bool bOldLock, bOldFtn;
if( pFtnFrm )
{
bOldFtn = pFtnFrm->IsColLocked();
pFtnFrm->ColLock();
}
else
bOldFtn = sal_True;
SwSectionFrm* pSct = pUpper->FindSctFrm();
// Es sind innerhalb von Fussnoten nur die Bereiche interessant,
// die in den Fussnoten liegen, nicht etwa die (spaltigen) Bereiche,
// in denen die Fussnoten(Container) liegen.
// #109767# Table frame is in section, insert section in cell frame.
if( pSct && ((pFtnFrm && !pSct->IsInFtn()) || pUpper->IsCellFrm()) )
pSct = NULL;
if( pSct )
{ // damit der SectionFrm nicht zerstoert wird durch pTmp->MoveFwd()
bOldLock = pSct->IsColLocked();
pSct->ColLock();
}
else
bOldLock = sal_True;
// Wenn pFrm sich nicht bewegen kann, koennen wir auch niemanden
// auf die naechste Seite schieben. Innerhalb eines Rahmens auch
// nicht ( in der 1. Spalte eines Rahmens waere pFrm Moveable()! )
// Auch in spaltigen Bereichen in Tabellen waere pFrm Moveable.
sal_Bool bMoveNext = nEndIdx - rSttIdx.GetIndex() > 120;
sal_Bool bAllowMove = !pFrm->IsInFly() && pFrm->IsMoveable() &&
(!pFrm->IsInTab() || pFrm->IsTabFrm() );
if ( bMoveNext && bAllowMove )
{
SwFrm *pMove = pFrm;
SwFrm *pPrev = pFrm->GetPrev();
SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pMove );
ASSERT( pTmp, "Missing FlowFrm" );
if ( bApres )
{
// Wir wollen, dass der Rest der Seite leer ist, d.h.
// der naechste muss auf die naechste Seite wandern.
// Dieser kann auch in der naechsten Spalte stehen!
ASSERT( !pTmp->HasFollow(), "Follows forbidden" );
pPrev = pFrm;
// Wenn unser umgebender SectionFrm einen Next besitzt,
// so soll dieser ebenfalls gemoved werden!
pMove = pFrm->GetIndNext();
SwColumnFrm* pCol = (SwColumnFrm*)pFrm->FindColFrm();
if( pCol )
pCol = (SwColumnFrm*)pCol->GetNext();
do
{
if( pCol && !pMove )
{ // Bisher haben wir keinen Nachfolger gefunden
// jetzt gucken wir in die naechste Spalte
pMove = pCol->ContainsAny();
if( pCol->GetNext() )
pCol = (SwColumnFrm*)pCol->GetNext();
else if( pCol->IsInSct() )
{ // Wenn es keine naechste Spalte gibt, wir aber
// innerhalb eines spaltigen Bereichs sind,
// koennte es noch ausserhalb des Bereich
// (Seiten-)Spalten geben
pCol = (SwColumnFrm*)pCol->FindSctFrm()->FindColFrm();
if( pCol )
pCol = (SwColumnFrm*)pCol->GetNext();
}
else
pCol = NULL;
}
// Falls hier verschrottete SectionFrms herumgammeln,
// muessen diese uebersprungen werden.
while( pMove && pMove->IsSctFrm() &&
!((SwSectionFrm*)pMove)->GetSection() )
pMove = pMove->GetNext();
} while( !pMove && pCol );
if( pMove )
{
if ( pMove->IsCntntFrm() )
pTmp = (SwCntntFrm*)pMove;
else if ( pMove->IsTabFrm() )
pTmp = (SwTabFrm*)pMove;
else if ( pMove->IsSctFrm() )
{
pMove = ((SwSectionFrm*)pMove)->ContainsAny();
if( pMove )
pTmp = SwFlowFrm::CastFlowFrm( pMove );
else
pTmp = NULL;
}
}
else
pTmp = 0;
}
else
{
ASSERT( !pTmp->IsFollow(), "Follows really forbidden" );
// Bei Bereichen muss natuerlich der Inhalt auf die Reise
// geschickt werden.
if( pMove->IsSctFrm() )
{
while( pMove && pMove->IsSctFrm() &&
!((SwSectionFrm*)pMove)->GetSection() )
pMove = pMove->GetNext();
if( pMove && pMove->IsSctFrm() )
pMove = ((SwSectionFrm*)pMove)->ContainsAny();
if( pMove )
pTmp = SwFlowFrm::CastFlowFrm( pMove );
else
pTmp = NULL;
}
}
if( pTmp )
{
SwFrm* pOldUp = pTmp->GetFrm()->GetUpper();
// MoveFwd==sal_True bedeutet, dass wir auf der gleichen
// Seite geblieben sind, wir wollen aber die Seite wechseln,
// sofern dies moeglich ist
sal_Bool bTmpOldLock = pTmp->IsJoinLocked();
pTmp->LockJoin();
while( pTmp->MoveFwd( sal_True, sal_False, sal_True ) )
{
if( pOldUp == pTmp->GetFrm()->GetUpper() )
break;
pOldUp = pTmp->GetFrm()->GetUpper();
}
if( !bTmpOldLock )
pTmp->UnlockJoin();
}
::_InsertCnt( pUpper, pDoc, rSttIdx.GetIndex(),
pFrm->IsInDocBody(), nEndIdx, pPrev );
}
else
{
sal_Bool bSplit;
SwFrm* pPrv = bApres ? pFrm : pFrm->GetPrev();
// Wenn in einen SectionFrm ein anderer eingefuegt wird,
// muss dieser aufgebrochen werden
if( pSct && rSttIdx.GetNode().IsSectionNode() )
{
bSplit = pSct->SplitSect( pFrm, bApres );
// Wenn pSct nicht aufgespalten werden konnte
if( !bSplit && !bApres )
{
pUpper = pSct->GetUpper();
pPrv = pSct->GetPrev();
}
}
else
bSplit = sal_False;
::_InsertCnt( pUpper, pDoc, rSttIdx.GetIndex(), sal_False,
nEndIdx, pPrv );
// OD 23.06.2003 #108784# - correction: append objects doesn't
// depend on value of <bAllowMove>
if( !bDontCreateObjects )
{
const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts();
if( pTbl->Count() )
AppendAllObjs( pTbl, pUpper );
}
// Wenn nichts eingefuegt wurde, z.B. ein ausgeblendeter Bereich,
// muss das Splitten rueckgaengig gemacht werden
if( bSplit && pSct && pSct->GetNext()
&& pSct->GetNext()->IsSctFrm() )
pSct->MergeNext( (SwSectionFrm*)pSct->GetNext() );
if( pFrm->IsInFly() )
pFrm->FindFlyFrm()->_Invalidate();
if( pFrm->IsInTab() )
pFrm->InvalidateSize();
}
SwPageFrm *pPage = pUpper->FindPageFrm();
SwFrm::CheckPageDescs( pPage, sal_False );
if( !bOldFtn )
pFtnFrm->ColUnlock();
if( !bOldLock )
{
pSct->ColUnlock();
// Zum Beispiel beim Einfuegen von gelinkten Bereichen,
// die wiederum Bereiche enthalten, kann pSct jetzt leer sein
// und damit ruhig zerstoert werden.
if( !pSct->ContainsCntnt() )
{
pSct->DelEmpty( sal_True );
pUpper->getRootFrm()->RemoveFromList( pSct );
delete pSct;
}
}
}
}
bObjsDirect = sal_True;
}
/*************************************************************************/
SwBorderAttrs::SwBorderAttrs( const SwModify *pMod, const SwFrm *pConstructor ) :
SwCacheObj( pMod ),
rAttrSet( pConstructor->IsCntntFrm()
? ((SwCntntFrm*)pConstructor)->GetNode()->GetSwAttrSet()
: ((SwLayoutFrm*)pConstructor)->GetFmt()->GetAttrSet() ),
rUL ( rAttrSet.GetULSpace() ),
// --> OD 2008-12-04 #i96772#
// LRSpaceItem is copied due to the possibility that it is adjusted - see below
rLR ( rAttrSet.GetLRSpace() ),
// <--
rBox ( rAttrSet.GetBox() ),
rShadow ( rAttrSet.GetShadow() ),
aFrmSize( rAttrSet.GetFrmSize().GetSize() )
{
// --> OD 2008-12-02 #i96772#
const SwTxtFrm* pTxtFrm = dynamic_cast<const SwTxtFrm*>(pConstructor);
if ( pTxtFrm )
{
pTxtFrm->GetTxtNode()->ClearLRSpaceItemDueToListLevelIndents( rLR );
}
//Achtung: Die USHORTs fuer die gecache'ten Werte werden absichtlich
//nicht initialisiert!
//Muessen alle einmal berechnet werden:
bTopLine = bBottomLine = bLeftLine = bRightLine =
bTop = bBottom = bLine = sal_True;
bCacheGetLine = bCachedGetTopLine = bCachedGetBottomLine = sal_False;
// OD 21.05.2003 #108789# - init cache status for values <bJoinedWithPrev>
// and <bJoinedWithNext>, which aren't initialized by default.
bCachedJoinedWithPrev = sal_False;
bCachedJoinedWithNext = sal_False;
bBorderDist = 0 != (pConstructor->GetType() & (FRM_CELL));
}
SwBorderAttrs::~SwBorderAttrs()
{
((SwModify*)pOwner)->SetInCache( sal_False );
}
/*************************************************************************
|*
|* SwBorderAttrs::CalcTop(), CalcBottom(), CalcLeft(), CalcRight()
|*
|* Beschreibung Die Calc-Methoden errechnen zusaetzlich zu den
|* von den Attributen vorgegebenen Groessen einen Sicherheitsabstand.
|* der Sicherheitsabstand wird nur einkalkuliert, wenn Umrandung und/oder
|* Schatten im Spiel sind; er soll vermeiden, dass aufgrund der
|* groben physikalischen Gegebenheiten Raender usw. uebermalt werden.
|*
|*************************************************************************/
void SwBorderAttrs::_CalcTop()
{
nTop = CalcTopLine() + rUL.GetUpper();
bTop = sal_False;
}
void SwBorderAttrs::_CalcBottom()
{
nBottom = CalcBottomLine() + rUL.GetLower();
bBottom = sal_False;
}
long SwBorderAttrs::CalcRight( const SwFrm* pCaller ) const
{
long nRight;
// OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
// and right border are painted on the right respectively left.
if ( pCaller->IsCellFrm() && pCaller->IsRightToLeft() )
nRight = CalcLeftLine();
else
nRight = CalcRightLine();
// for paragraphs, "left" is "before text" and "right" is "after text"
if ( pCaller->IsTxtFrm() && pCaller->IsRightToLeft() )
nRight += rLR.GetLeft();
else
nRight += rLR.GetRight();
// --> OD 2008-01-21 #newlistlevelattrs#
// correction: retrieve left margin for numbering in R2L-layout
if ( pCaller->IsTxtFrm() && pCaller->IsRightToLeft() )
{
nRight += ((SwTxtFrm*)pCaller)->GetTxtNode()->GetLeftMarginWithNum();
}
// <--
return nRight;
}
long SwBorderAttrs::CalcLeft( const SwFrm *pCaller ) const
{
long nLeft;
// OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
// and right border are painted on the right respectively left.
if ( pCaller->IsCellFrm() && pCaller->IsRightToLeft() )
nLeft = CalcRightLine();
else
nLeft = CalcLeftLine();
// for paragraphs, "left" is "before text" and "right" is "after text"
if ( pCaller->IsTxtFrm() && pCaller->IsRightToLeft() )
nLeft += rLR.GetRight();
else
nLeft += rLR.GetLeft();
// --> OD 2008-01-21 #newlistlevelattrs#
// correction: do not retrieve left margin for numbering in R2L-layout
// if ( pCaller->IsTxtFrm() )
if ( pCaller->IsTxtFrm() && !pCaller->IsRightToLeft() )
// <--
{
nLeft += ((SwTxtFrm*)pCaller)->GetTxtNode()->GetLeftMarginWithNum();
}
return nLeft;
}
/*************************************************************************
|*
|* SwBorderAttrs::CalcTopLine(), CalcBottomLine(),
|* CalcLeftLine(), CalcRightLine()
|*
|* Beschreibung Berechnung der Groessen fuer Umrandung und Schatten.
|* Es kann auch ohne Linien ein Abstand erwuenscht sein,
|* dieser wird dann nicht vom Attribut sondern hier
|* beruecksichtigt (bBorderDist, z.B. fuer Zellen).
|*
|*************************************************************************/
void SwBorderAttrs::_CalcTopLine()
{
nTopLine = (bBorderDist && !rBox.GetTop())
? rBox.GetDistance (BOX_LINE_TOP)
: rBox.CalcLineSpace(BOX_LINE_TOP);
nTopLine = nTopLine + rShadow.CalcShadowSpace(SHADOW_TOP);
bTopLine = sal_False;
}
void SwBorderAttrs::_CalcBottomLine()
{
nBottomLine = (bBorderDist && !rBox.GetBottom())
? rBox.GetDistance (BOX_LINE_BOTTOM)
: rBox.CalcLineSpace(BOX_LINE_BOTTOM);
nBottomLine = nBottomLine + rShadow.CalcShadowSpace(SHADOW_BOTTOM);
bBottomLine = sal_False;
}
void SwBorderAttrs::_CalcLeftLine()
{
nLeftLine = (bBorderDist && !rBox.GetLeft())
? rBox.GetDistance (BOX_LINE_LEFT)
: rBox.CalcLineSpace(BOX_LINE_LEFT);
nLeftLine = nLeftLine + rShadow.CalcShadowSpace(SHADOW_LEFT);
bLeftLine = sal_False;
}
void SwBorderAttrs::_CalcRightLine()
{
nRightLine = (bBorderDist && !rBox.GetRight())
? rBox.GetDistance (BOX_LINE_RIGHT)
: rBox.CalcLineSpace(BOX_LINE_RIGHT);
nRightLine = nRightLine + rShadow.CalcShadowSpace(SHADOW_RIGHT);
bRightLine = sal_False;
}
/*************************************************************************/
void SwBorderAttrs::_IsLine()
{
bIsLine = rBox.GetTop() || rBox.GetBottom() ||
rBox.GetLeft()|| rBox.GetRight();
bLine = sal_False;
}
/*************************************************************************
|*
|* SwBorderAttrs::CmpLeftRightLine(), IsTopLine(), IsBottomLine()
|*
|* Die Umrandungen benachbarter Absaetze werden nach folgendem
|* Algorithmus zusammengefasst:
|*
|* 1. Die Umrandung oben faellt weg, wenn der Vorgaenger dieselbe
|* Umrandung oben aufweist und 3. Zutrifft.
|* Zusaetzlich muss der Absatz mindestens rechts oder links oder
|* unten eine Umrandung haben.
|* 2. Die Umrandung unten faellt weg, wenn der Nachfolger dieselbe
|* Umrandung untern aufweist und 3. Zustrifft.
|* Zusaetzlich muss der Absatz mindestens rechts oder links oder
|* oben eine Umrandung haben.
|* 3. Die Umrandungen links und rechts vor Vorgaenger bzw. Nachfolger
|* sind identisch.
|*
|*************************************************************************/
inline int CmpLines( const SvxBorderLine *pL1, const SvxBorderLine *pL2 )
{
return ( ((pL1 && pL2) && (*pL1 == *pL2)) || (!pL1 && !pL2) );
}
// OD 21.05.2003 #108789# - change name of 1st parameter - "rAttrs" -> "rCmpAttrs"
// OD 21.05.2003 #108789# - compare <CalcRight()> and <rCmpAttrs.CalcRight()>
// instead of only the right LR-spacing, because R2L-layout has to be
// considered.
sal_Bool SwBorderAttrs::CmpLeftRight( const SwBorderAttrs &rCmpAttrs,
const SwFrm *pCaller,
const SwFrm *pCmp ) const
{
return ( CmpLines( rCmpAttrs.GetBox().GetLeft(), GetBox().GetLeft() ) &&
CmpLines( rCmpAttrs.GetBox().GetRight(),GetBox().GetRight() ) &&
CalcLeft( pCaller ) == rCmpAttrs.CalcLeft( pCmp ) &&
// OD 21.05.2003 #108789# - compare <CalcRight> with <rCmpAttrs.CalcRight>.
CalcRight( pCaller ) == rCmpAttrs.CalcRight( pCmp ) );
}
sal_Bool SwBorderAttrs::_JoinWithCmp( const SwFrm& _rCallerFrm,
const SwFrm& _rCmpFrm ) const
{
sal_Bool bReturnVal = sal_False;
SwBorderAttrAccess aCmpAccess( SwFrm::GetCache(), &_rCmpFrm );
const SwBorderAttrs &rCmpAttrs = *aCmpAccess.Get();
if ( rShadow == rCmpAttrs.GetShadow() &&
CmpLines( rBox.GetTop(), rCmpAttrs.GetBox().GetTop() ) &&
CmpLines( rBox.GetBottom(), rCmpAttrs.GetBox().GetBottom() ) &&
CmpLeftRight( rCmpAttrs, &_rCallerFrm, &_rCmpFrm )
)
{
bReturnVal = sal_True;
}
return bReturnVal;
}
// OD 21.05.2003 #108789# - method to determine, if borders are joined with
// previous frame. Calculated value saved in cached value <bJoinedWithPrev>
// OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrm>
void SwBorderAttrs::_CalcJoinedWithPrev( const SwFrm& _rFrm,
const SwFrm* _pPrevFrm )
{
// set default
bJoinedWithPrev = sal_False;
if ( _rFrm.IsTxtFrm() )
{
// text frame can potentially join with previous text frame, if
// corresponding attribute set is set at previous text frame.
// OD 2004-02-26 #i25029# - If parameter <_pPrevFrm> is set, take this
// one as previous frame.
const SwFrm* pPrevFrm = _pPrevFrm ? _pPrevFrm : _rFrm.GetPrev();
// OD 2004-02-13 #i25029# - skip hidden text frames.
while ( pPrevFrm && pPrevFrm->IsTxtFrm() &&
static_cast<const SwTxtFrm*>(pPrevFrm)->IsHiddenNow() )
{
pPrevFrm = pPrevFrm->GetPrev();
}
if ( pPrevFrm && pPrevFrm->IsTxtFrm() &&
pPrevFrm->GetAttrSet()->GetParaConnectBorder().GetValue()
)
{
bJoinedWithPrev = _JoinWithCmp( _rFrm, *(pPrevFrm) );
}
}
// valid cache status, if demanded
// OD 2004-02-26 #i25029# - Do not validate cache, if parameter <_pPrevFrm>
// is set.
bCachedJoinedWithPrev = bCacheGetLine && !_pPrevFrm;
}
// OD 21.05.2003 #108789# - method to determine, if borders are joined with
// next frame. Calculated value saved in cached value <bJoinedWithNext>
void SwBorderAttrs::_CalcJoinedWithNext( const SwFrm& _rFrm )
{
// set default
bJoinedWithNext = sal_False;
if ( _rFrm.IsTxtFrm() )
{
// text frame can potentially join with next text frame, if
// corresponding attribute set is set at current text frame.
// OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames.
const SwFrm* pNextFrm = _rFrm.GetNext();
while ( pNextFrm && pNextFrm->IsTxtFrm() &&
static_cast<const SwTxtFrm*>(pNextFrm)->IsHiddenNow() )
{
pNextFrm = pNextFrm->GetNext();
}
if ( pNextFrm && pNextFrm->IsTxtFrm() &&
_rFrm.GetAttrSet()->GetParaConnectBorder().GetValue()
)
{
bJoinedWithNext = _JoinWithCmp( _rFrm, *(pNextFrm) );
}
}
// valid cache status, if demanded
bCachedJoinedWithNext = bCacheGetLine;
}
// OD 21.05.2003 #108789# - accessor for cached values <bJoinedWithPrev>
// OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrm>, which is passed to
// method <_CalcJoindWithPrev(..)>.
sal_Bool SwBorderAttrs::JoinedWithPrev( const SwFrm& _rFrm,
const SwFrm* _pPrevFrm ) const
{
if ( !bCachedJoinedWithPrev || _pPrevFrm )
{
// OD 2004-02-26 #i25029# - pass <_pPrevFrm> as 2nd parameter
const_cast<SwBorderAttrs*>(this)->_CalcJoinedWithPrev( _rFrm, _pPrevFrm );
}
return bJoinedWithPrev;
}
sal_Bool SwBorderAttrs::JoinedWithNext( const SwFrm& _rFrm ) const
{
if ( !bCachedJoinedWithNext )
{
const_cast<SwBorderAttrs*>(this)->_CalcJoinedWithNext( _rFrm );
}
return bJoinedWithNext;
}
// OD 2004-02-26 #i25029# - added 2nd parameter <_pPrevFrm>, which is passed to
// method <JoinedWithPrev>
void SwBorderAttrs::_GetTopLine( const SwFrm& _rFrm,
const SwFrm* _pPrevFrm )
{
sal_uInt16 nRet = CalcTopLine();
// OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
// OD 2004-02-26 #i25029# - add 2nd parameter
if ( JoinedWithPrev( _rFrm, _pPrevFrm ) )
{
nRet = 0;
}
bCachedGetTopLine = bCacheGetLine;
nGetTopLine = nRet;
}
void SwBorderAttrs::_GetBottomLine( const SwFrm& _rFrm )
{
sal_uInt16 nRet = CalcBottomLine();
// OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
if ( JoinedWithNext( _rFrm ) )
{
nRet = 0;
}
bCachedGetBottomLine = bCacheGetLine;
nGetBottomLine = nRet;
}
/*************************************************************************/
SwBorderAttrAccess::SwBorderAttrAccess( SwCache &rCach, const SwFrm *pFrm ) :
SwCacheAccess( rCach, (pFrm->IsCntntFrm() ?
(void*)((SwCntntFrm*)pFrm)->GetNode() :
(void*)((SwLayoutFrm*)pFrm)->GetFmt()),
(sal_Bool)(pFrm->IsCntntFrm() ?
((SwModify*)((SwCntntFrm*)pFrm)->GetNode())->IsInCache() :
((SwModify*)((SwLayoutFrm*)pFrm)->GetFmt())->IsInCache()) ),
pConstructor( pFrm )
{
}
/*************************************************************************/
SwCacheObj *SwBorderAttrAccess::NewObj()
{
((SwModify*)pOwner)->SetInCache( sal_True );
return new SwBorderAttrs( (SwModify*)pOwner, pConstructor );
}
SwBorderAttrs *SwBorderAttrAccess::Get()
{
return (SwBorderAttrs*)SwCacheAccess::Get();
}
/*************************************************************************/
SwOrderIter::SwOrderIter( const SwPageFrm *pPg, sal_Bool bFlys ) :
pPage( pPg ),
pCurrent( 0 ),
bFlysOnly( bFlys )
{
}
/*************************************************************************/
const SdrObject *SwOrderIter::Top()
{
pCurrent = 0;
if ( pPage->GetSortedObjs() )
{
sal_uInt32 nTopOrd = 0;
const SwSortedObjs *pObjs = pPage->GetSortedObjs();
if ( pObjs->Count() )
{
(*pObjs)[0]->GetDrawObj()->GetOrdNum(); //Aktualisieren erzwingen!
for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
{
const SdrObject* pObj = (*pObjs)[i]->GetDrawObj();
if ( bFlysOnly && !pObj->ISA(SwVirtFlyDrawObj) )
continue;
sal_uInt32 nTmp = pObj->GetOrdNumDirect();
if ( nTmp >= nTopOrd )
{
nTopOrd = nTmp;
pCurrent = pObj;
}
}
}
}
return pCurrent;
}
/*************************************************************************/
const SdrObject *SwOrderIter::Bottom()
{
pCurrent = 0;
if ( pPage->GetSortedObjs() )
{
sal_uInt32 nBotOrd = USHRT_MAX;
const SwSortedObjs *pObjs = pPage->GetSortedObjs();
if ( pObjs->Count() )
{
(*pObjs)[0]->GetDrawObj()->GetOrdNum(); //Aktualisieren erzwingen!
for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
{
const SdrObject* pObj = (*pObjs)[i]->GetDrawObj();
if ( bFlysOnly && !pObj->ISA(SwVirtFlyDrawObj) )
continue;
sal_uInt32 nTmp = pObj->GetOrdNumDirect();
if ( nTmp < nBotOrd )
{
nBotOrd = nTmp;
pCurrent = pObj;
}
}
}
}
return pCurrent;
}
/*************************************************************************/
const SdrObject *SwOrderIter::Next()
{
const sal_uInt32 nCurOrd = pCurrent ? pCurrent->GetOrdNumDirect() : 0;
pCurrent = 0;
if ( pPage->GetSortedObjs() )
{
sal_uInt32 nOrd = USHRT_MAX;
const SwSortedObjs *pObjs = pPage->GetSortedObjs();
if ( pObjs->Count() )
{
(*pObjs)[0]->GetDrawObj()->GetOrdNum(); //Aktualisieren erzwingen!
for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
{
const SdrObject* pObj = (*pObjs)[i]->GetDrawObj();
if ( bFlysOnly && !pObj->ISA(SwVirtFlyDrawObj) )
continue;
sal_uInt32 nTmp = pObj->GetOrdNumDirect();
if ( nTmp > nCurOrd && nTmp < nOrd )
{
nOrd = nTmp;
pCurrent = pObj;
}
}
}
}
return pCurrent;
}
/*************************************************************************/
const SdrObject *SwOrderIter::Prev()
{
const sal_uInt32 nCurOrd = pCurrent ? pCurrent->GetOrdNumDirect() : 0;
pCurrent = 0;
if ( pPage->GetSortedObjs() )
{
sal_uInt32 nOrd = 0;
const SwSortedObjs *pObjs = pPage->GetSortedObjs();
if ( pObjs->Count() )
{
(*pObjs)[0]->GetDrawObj()->GetOrdNum(); //Aktualisieren erzwingen!
for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
{
const SdrObject* pObj = (*pObjs)[i]->GetDrawObj();
if ( bFlysOnly && !pObj->ISA(SwVirtFlyDrawObj) )
continue;
sal_uInt32 nTmp = pObj->GetOrdNumDirect();
if ( nTmp < nCurOrd && nTmp >= nOrd )
{
nOrd = nTmp;
pCurrent = pObj;
}
}
}
}
return pCurrent;
}
/*************************************************************************/
//Unterstruktur eines LayoutFrms fuer eine Aktion aufheben und wieder
//restaurieren.
//Neuer Algorithmus: Es ist unuetz jeden Nachbarn einzeln zu betrachten und
//die Pointer sauber zu setzen (Upper, Nachbarn, usw.)
//Es reicht vollkommen jeweils eine Einzelkette zu loesen, und mit dem
//Letzen der Einzelkette nachzuschauen ob noch eine weitere Kette
//angeheangt werden muss. Es brauchen nur die Pointer korrigiert werden,
//die zur Verkettung notwendig sind. So koennen Beipspielsweise die Pointer
//auf die Upper auf den alten Uppern stehenbleiben. Korrigiert werden die
//Pointer dann im RestoreCntnt. Zwischenzeitlich ist sowieso jeder Zugriff
//verboten.
//Unterwegs werden die Flys bei der Seite abgemeldet.
// --> OD 2004-11-29 #115759# - 'remove' also drawing object from page and
// at-fly anchored objects from page
void MA_FASTCALL lcl_RemoveObjsFromPage( SwFrm* _pFrm )
{
ASSERT( _pFrm->GetDrawObjs(), "Keine DrawObjs fuer lcl_RemoveFlysFromPage." );
SwSortedObjs &rObjs = *_pFrm->GetDrawObjs();
for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
{
SwAnchoredObject* pObj = rObjs[i];
// --> OD 2004-11-29 #115759# - reset member, at which the anchored
// object orients its vertical position
pObj->ClearVertPosOrientFrm();
// <--
// --> OD 2005-03-03 #i43913#
pObj->ResetLayoutProcessBools();
// <--
// --> OD 2004-11-29 #115759# - remove also lower objects of as-character
// anchored Writer fly frames from page
if ( pObj->ISA(SwFlyFrm) )
{
SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj);
// --> OD 2004-11-29 #115759# - remove also direct lowers of Writer
// fly frame from page
if ( pFlyFrm->GetDrawObjs() )
{
::lcl_RemoveObjsFromPage( pFlyFrm );
}
// <--
SwCntntFrm* pCnt = pFlyFrm->ContainsCntnt();
while ( pCnt )
{
if ( pCnt->GetDrawObjs() )
::lcl_RemoveObjsFromPage( pCnt );
pCnt = pCnt->GetNextCntntFrm();
}
if ( pFlyFrm->IsFlyFreeFrm() )
{
// --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
pFlyFrm->GetPageFrm()->RemoveFlyFromPage( pFlyFrm );
}
}
// <--
// --> OD 2004-11-29 #115759# - remove also drawing objects from page
else if ( pObj->ISA(SwAnchoredDrawObject) )
{
if (pObj->GetFrmFmt().GetAnchor().GetAnchorId() != FLY_AS_CHAR)
{
pObj->GetPageFrm()->RemoveDrawObjFromPage(
*(static_cast<SwAnchoredDrawObject*>(pObj)) );
}
}
// <--
}
}
SwFrm *SaveCntnt( SwLayoutFrm *pLay, SwFrm *pStart )
{
if( pLay->IsSctFrm() && pLay->Lower() && pLay->Lower()->IsColumnFrm() )
lcl_RemoveFtns( (SwColumnFrm*)pLay->Lower(), sal_True, sal_True );
SwFrm *pSav;
if ( 0 == (pSav = pLay->ContainsAny()) )
return 0;
if( pSav->IsInFtn() && !pLay->IsInFtn() )
{
do
pSav = pSav->FindNext();
while( pSav && pSav->IsInFtn() );
if( !pSav || !pLay->IsAnLower( pSav ) )
return NULL;
}
// Tables should be saved as a whole, expection:
// The contents of a section or a cell inside a table should be saved
if ( pSav->IsInTab() && !( ( pLay->IsSctFrm() || pLay->IsCellFrm() ) && pLay->IsInTab() ) )
while ( !pSav->IsTabFrm() )
pSav = pSav->GetUpper();
if( pSav->IsInSct() )
{ // Jetzt wird der oberste Bereich gesucht, der innerhalb von pLay ist.
SwFrm* pSect = pLay->FindSctFrm();
SwFrm *pTmp = pSav;
do
{
pSav = pTmp;
pTmp = pSav->GetUpper() ? pSav->GetUpper()->FindSctFrm() : NULL;
} while ( pTmp != pSect );
}
SwFrm *pFloat = pSav;
if( !pStart )
pStart = pSav;
sal_Bool bGo = pStart == pSav;
do
{
if( bGo )
pFloat->GetUpper()->pLower = 0; //Die Teilkette ausklinken.
//Das Ende der Teilkette suchen, unterwegs die Flys abmelden.
do
{
if( bGo )
{
if ( pFloat->IsCntntFrm() )
{
if ( pFloat->GetDrawObjs() )
::lcl_RemoveObjsFromPage( (SwCntntFrm*)pFloat );
}
else if ( pFloat->IsTabFrm() || pFloat->IsSctFrm() )
{
SwCntntFrm *pCnt = ((SwLayoutFrm*)pFloat)->ContainsCntnt();
if( pCnt )
{
do
{ if ( pCnt->GetDrawObjs() )
::lcl_RemoveObjsFromPage( pCnt );
pCnt = pCnt->GetNextCntntFrm();
} while ( pCnt && ((SwLayoutFrm*)pFloat)->IsAnLower( pCnt ) );
}
}
else {
ASSERT( !pFloat, "Neuer Float-Frame?" );
}
}
if ( pFloat->GetNext() )
{
if( bGo )
pFloat->pUpper = NULL;
pFloat = pFloat->GetNext();
if( !bGo && pFloat == pStart )
{
bGo = sal_True;
pFloat->pPrev->pNext = NULL;
pFloat->pPrev = NULL;
}
}
else
break;
} while ( pFloat );
//Die naechste Teilkette suchen und die Ketten miteinander verbinden.
SwFrm *pTmp = pFloat->FindNext();
if( bGo )
pFloat->pUpper = NULL;
if( !pLay->IsInFtn() )
while( pTmp && pTmp->IsInFtn() )
pTmp = pTmp->FindNext();
if ( !pLay->IsAnLower( pTmp ) )
pTmp = 0;
if ( pTmp && bGo )
{
pFloat->pNext = pTmp; //Die beiden Ketten verbinden.
pFloat->pNext->pPrev = pFloat;
}
pFloat = pTmp;
bGo = bGo || ( pStart == pFloat );
} while ( pFloat );
return bGo ? pStart : NULL;
}
// --> OD 2004-11-29 #115759# - add also drawing objects to page and at-fly
// anchored objects to page
void MA_FASTCALL lcl_AddObjsToPage( SwFrm* _pFrm, SwPageFrm* _pPage )
{
ASSERT( _pFrm->GetDrawObjs(), "Keine DrawObjs fuer lcl_AddFlysToPage." );
SwSortedObjs &rObjs = *_pFrm->GetDrawObjs();
for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
{
SwAnchoredObject* pObj = rObjs[i];
// --> OD 2004-11-29 #115759# - unlock position of anchored object
// in order to get the object's position calculated.
pObj->UnlockPosition();
// <--
// --> OD 2004-11-29 #115759# - add also lower objects of as-character
// anchored Writer fly frames from page
if ( pObj->ISA(SwFlyFrm) )
{
SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj);
if ( pObj->ISA(SwFlyFreeFrm) )
{
_pPage->AppendFlyToPage( pFlyFrm );
}
pFlyFrm->_InvalidatePos();
pFlyFrm->_InvalidateSize();
pFlyFrm->InvalidatePage( _pPage );
// --> OD 2004-11-29 #115759# - add also at-fly anchored objects
// to page
if ( pFlyFrm->GetDrawObjs() )
{
::lcl_AddObjsToPage( pFlyFrm, _pPage );
}
// <--
SwCntntFrm *pCnt = pFlyFrm->ContainsCntnt();
while ( pCnt )
{
if ( pCnt->GetDrawObjs() )
::lcl_AddObjsToPage( pCnt, _pPage );
pCnt = pCnt->GetNextCntntFrm();
}
}
// <--
// --> OD 2004-11-29 #115759# - remove also drawing objects from page
else if ( pObj->ISA(SwAnchoredDrawObject) )
{
if (pObj->GetFrmFmt().GetAnchor().GetAnchorId() != FLY_AS_CHAR)
{
pObj->InvalidateObjPos();
_pPage->AppendDrawObjToPage(
*(static_cast<SwAnchoredDrawObject*>(pObj)) );
}
}
// <--
}
}
void RestoreCntnt( SwFrm *pSav, SwLayoutFrm *pParent, SwFrm *pSibling, bool bGrow )
{
ASSERT( pSav && pParent, "Kein Save oder Parent fuer Restore." );
SWRECTFN( pParent )
//Wenn es bereits FlowFrms unterhalb des neuen Parent gibt, so wird die
//Kette, beginnend mit pSav, hinter dem letzten angehaengt.
//Die Teile werden kurzerhand insertet und geeignet invalidiert.
//Unterwegs werden die Flys der CntntFrms bei der Seite angemeldet.
SwPageFrm *pPage = pParent->FindPageFrm();
if ( pPage )
pPage->InvalidatePage( pPage ); //Invalides Layout anmelden.
//Vorgaenger festellen und die Verbindung herstellen bzw. initialisieren.
pSav->pPrev = pSibling;
SwFrm* pNxt;
if ( pSibling )
{
pNxt = pSibling->pNext;
pSibling->pNext = pSav;
pSibling->_InvalidatePrt();
((SwCntntFrm*)pSibling)->InvalidatePage( pPage );//Invaliden Cntnt anmelden.
if ( ((SwCntntFrm*)pSibling)->GetFollow() )
pSibling->Prepare( PREP_CLEAR, 0, sal_False );
}
else
{ pNxt = pParent->pLower;
pParent->pLower = pSav;
pSav->pUpper = pParent; //Schon mal setzen, sonst ist fuer das
//invalidate der Parent (z.B. ein Fly) nicht klar.
//Invaliden Cntnt anmelden.
if ( pSav->IsCntntFrm() )
((SwCntntFrm*)pSav)->InvalidatePage( pPage );
else
{ // pSav koennte auch ein leerer SectFrm sein
SwCntntFrm* pCnt = pParent->ContainsCntnt();
if( pCnt )
pCnt->InvalidatePage( pPage );
}
}
//Der Parent muss entsprechend gegrow'ed werden.
SwTwips nGrowVal = 0;
SwFrm* pLast;
do
{ pSav->pUpper = pParent;
nGrowVal += (pSav->Frm().*fnRect->fnGetHeight)();
pSav->_InvalidateAll();
//Jetzt die Flys anmelden, fuer TxtFrms gleich geeignet invalidieren.
if ( pSav->IsCntntFrm() )
{
if ( pSav->IsTxtFrm() &&
((SwTxtFrm*)pSav)->GetCacheIdx() != USHRT_MAX )
((SwTxtFrm*)pSav)->Init(); //Ich bin sein Freund.
if ( pPage && pSav->GetDrawObjs() )
::lcl_AddObjsToPage( (SwCntntFrm*)pSav, pPage );
}
else
{ SwCntntFrm *pBlub = ((SwLayoutFrm*)pSav)->ContainsCntnt();
if( pBlub )
{
do
{ if ( pPage && pBlub->GetDrawObjs() )
::lcl_AddObjsToPage( pBlub, pPage );
if( pBlub->IsTxtFrm() && ((SwTxtFrm*)pBlub)->HasFtn() &&
((SwTxtFrm*)pBlub)->GetCacheIdx() != USHRT_MAX )
((SwTxtFrm*)pBlub)->Init(); //Ich bin sein Freund.
pBlub = pBlub->GetNextCntntFrm();
} while ( pBlub && ((SwLayoutFrm*)pSav)->IsAnLower( pBlub ));
}
}
pLast = pSav;
pSav = pSav->GetNext();
} while ( pSav );
if( pNxt )
{
pLast->pNext = pNxt;
pNxt->pPrev = pLast;
}
if ( bGrow )
pParent->Grow( nGrowVal );
}
/*************************************************************************
|*
|* SqRt() Berechnung der Quadratwurzel, damit die math.lib
|* nicht auch noch dazugelinkt werden muss.
|*
|*************************************************************************/
sal_uLong MA_FASTCALL SqRt( BigInt nX )
{
BigInt nErg = 1;
if ( !nX.IsNeg() )
{
BigInt nOldErg = 1;
for ( int i = 0; i <= 5; i++ )
{
nErg = (nOldErg + (nX / nOldErg)) / BigInt(2);
nOldErg = nErg;
}
}
return nErg >= BigInt(SAL_MAX_UINT32) ? ULONG_MAX : (sal_uLong)nErg;
}
/*************************************************************************/
SwPageFrm * MA_FASTCALL InsertNewPage( SwPageDesc &rDesc, SwFrm *pUpper,
sal_Bool bOdd, sal_Bool bInsertEmpty, sal_Bool bFtn,
SwFrm *pSibling )
{
SwPageFrm *pRet;
SwDoc *pDoc = ((SwLayoutFrm*)pUpper)->GetFmt()->GetDoc();
SwFrmFmt *pFmt = bOdd ? rDesc.GetRightFmt() : rDesc.GetLeftFmt();
//Wenn ich kein FrmFmt fuer die Seite gefunden habe, muss ich eben
//eine Leerseite einfuegen.
if ( !pFmt )
{
pFmt = bOdd ? rDesc.GetLeftFmt() : rDesc.GetRightFmt();
ASSERT( pFmt, "Descriptor without any format?!" );
bInsertEmpty = !bInsertEmpty;
}
if( bInsertEmpty )
{
SwPageDesc *pTmpDesc = pSibling && pSibling->GetPrev() ?
((SwPageFrm*)pSibling->GetPrev())->GetPageDesc() : &rDesc;
pRet = new SwPageFrm( pDoc->GetEmptyPageFmt(), pUpper, pTmpDesc );
pRet->Paste( pUpper, pSibling );
pRet->PreparePage( bFtn );
}
pRet = new SwPageFrm( pFmt, pUpper, &rDesc );
pRet->Paste( pUpper, pSibling );
pRet->PreparePage( bFtn );
if ( pRet->GetNext() )
((SwRootFrm*)pRet->GetUpper())->AssertPageFlys( pRet );
return pRet;
}
/*************************************************************************
|*
|* RegistFlys(), Regist() Die beiden folgenden Methoden durchsuchen rekursiv
|* eine Layoutstruktur und melden alle FlyFrms, die einen beliebigen Frm
|* innerhalb der Struktur als Anker haben bei der Seite an.
|*
|*************************************************************************/
void MA_FASTCALL lcl_Regist( SwPageFrm *pPage, const SwFrm *pAnch )
{
SwSortedObjs *pObjs = (SwSortedObjs*)pAnch->GetDrawObjs();
for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i )
{
SwAnchoredObject* pObj = (*pObjs)[i];
if ( pObj->ISA(SwFlyFrm) )
{
SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pObj);
//Ggf. ummelden, nicht anmelden wenn bereits bekannt.
// --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()>
SwPageFrm *pPg = pFly->IsFlyFreeFrm()
? pFly->GetPageFrm() : pFly->FindPageFrm();
if ( pPg != pPage )
{
if ( pPg )
pPg->RemoveFlyFromPage( pFly );
pPage->AppendFlyToPage( pFly );
}
::RegistFlys( pPage, pFly );
}
else
{
// --> OD 2008-04-22 #i87493#
if ( pPage != pObj->GetPageFrm() )
{
// --> OD 2004-07-02 #i28701#
if ( pObj->GetPageFrm() )
pObj->GetPageFrm()->RemoveDrawObjFromPage( *pObj );
pPage->AppendDrawObjToPage( *pObj );
// <--
}
// <--
}
const SwFlyFrm* pFly = pAnch->FindFlyFrm();
if ( pFly &&
pObj->GetDrawObj()->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() &&
pObj->GetDrawObj()->GetPage() )
{
//#i119945# set pFly's OrdNum to pObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
pObj->DrawObj()->GetPage()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(),
pObj->GetDrawObj()->GetOrdNumDirect() );
}
}
}
void RegistFlys( SwPageFrm *pPage, const SwLayoutFrm *pLay )
{
if ( pLay->GetDrawObjs() )
::lcl_Regist( pPage, pLay );
const SwFrm *pFrm = pLay->Lower();
while ( pFrm )
{
if ( pFrm->IsLayoutFrm() )
::RegistFlys( pPage, (const SwLayoutFrm*)pFrm );
else if ( pFrm->GetDrawObjs() )
::lcl_Regist( pPage, pFrm );
pFrm = pFrm->GetNext();
}
}
/*************************************************************************
|*
|* void Notify()
|*
|* Beschreibung Benachrichtigt den Hintergrund je nach der
|* Veraenderung zwischen altem und neuem Rechteckt.
|*
|*************************************************************************/
void Notify( SwFlyFrm *pFly, SwPageFrm *pOld, const SwRect &rOld,
const SwRect* pOldPrt )
{
const SwRect aFrm( pFly->GetObjRectWithSpaces() );
if ( rOld.Pos() != aFrm.Pos() )
{ //Positionsaenderung, alten und neuen Bereich invalidieren
if ( rOld.HasArea() &&
rOld.Left()+pFly->GetFmt()->GetLRSpace().GetLeft() < WEIT_WECH )
{
pFly->NotifyBackground( pOld, rOld, PREP_FLY_LEAVE );
}
pFly->NotifyBackground( pFly->FindPageFrm(), aFrm, PREP_FLY_ARRIVE );
}
else if ( rOld.SSize() != aFrm.SSize() )
{ //Groessenaenderung, den Bereich der Verlassen wurde bzw. jetzt
//ueberdeckt wird invalidieren.
//Der Einfachheit halber wird hier bewusst jeweils ein Twip
//unnoetig invalidiert.
ViewShell *pSh = pFly->getRootFrm()->GetCurrShell();
if( pSh && rOld.HasArea() )
pSh->InvalidateWindows( rOld );
// --> OD 2005-08-19 #i51941# - consider case that fly frame isn't
// registered at the old page <pOld>
SwPageFrm* pPageFrm = pFly->FindPageFrm();
if ( pOld != pPageFrm )
{
pFly->NotifyBackground( pPageFrm, aFrm, PREP_FLY_ARRIVE );
}
// <--
if ( rOld.Left() != aFrm.Left() )
{
SwRect aTmp( rOld );
aTmp.Union( aFrm );
aTmp.Left( Min(aFrm.Left(), rOld.Left()) );
aTmp.Right( Max(aFrm.Left(), rOld.Left()) );
pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
}
SwTwips nOld = rOld.Right();
SwTwips nNew = aFrm.Right();
if ( nOld != nNew )
{
SwRect aTmp( rOld );
aTmp.Union( aFrm );
aTmp.Left( Min(nNew, nOld) );
aTmp.Right( Max(nNew, nOld) );
pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
}
if ( rOld.Top() != aFrm.Top() )
{
SwRect aTmp( rOld );
aTmp.Union( aFrm );
aTmp.Top( Min(aFrm.Top(), rOld.Top()) );
aTmp.Bottom( Max(aFrm.Top(), rOld.Top()) );
pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
}
nOld = rOld.Bottom();
nNew = aFrm.Bottom();
if ( nOld != nNew )
{
SwRect aTmp( rOld );
aTmp.Union( aFrm );
aTmp.Top( Min(nNew, nOld) );
aTmp.Bottom( Max(nNew, nOld) );
pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
}
}
else if ( pOldPrt && *pOldPrt != pFly->Prt() &&
pFly->GetFmt()->GetSurround().IsContour() )
{
// #i24097#
pFly->NotifyBackground( pFly->FindPageFrm(), aFrm, PREP_FLY_ARRIVE );
}
}
/*************************************************************************/
void lcl_CheckFlowBack( SwFrm* pFrm, const SwRect &rRect )
{
SwTwips nBottom = rRect.Bottom();
while( pFrm )
{
if( pFrm->IsLayoutFrm() )
{
if( rRect.IsOver( pFrm->Frm() ) )
lcl_CheckFlowBack( ((SwLayoutFrm*)pFrm)->Lower(), rRect );
}
else if( !pFrm->GetNext() && nBottom > pFrm->Frm().Bottom() )
{
if( pFrm->IsCntntFrm() && ((SwCntntFrm*)pFrm)->HasFollow() )
pFrm->InvalidateSize();
else
pFrm->InvalidateNextPos();
}
pFrm = pFrm->GetNext();
}
}
void MA_FASTCALL lcl_NotifyCntnt( const SdrObject *pThis, SwCntntFrm *pCnt,
const SwRect &rRect, const PrepareHint eHint )
{
if ( pCnt->IsTxtFrm() )
{
SwRect aCntPrt( pCnt->Prt() );
aCntPrt.Pos() += pCnt->Frm().Pos();
if ( eHint == PREP_FLY_ATTR_CHG )
{
// --> OD 2004-10-20 #i35640# - use given rectangle <rRect> instead
// of current bound rectangle
if ( aCntPrt.IsOver( rRect ) )
// <--
pCnt->Prepare( PREP_FLY_ATTR_CHG );
}
// --> OD 2004-11-01 #i23129# - only invalidate, if the text frame
// printing area overlaps with the given rectangle.
else if ( aCntPrt.IsOver( rRect ) )
// <--
pCnt->Prepare( eHint, (void*)&aCntPrt._Intersection( rRect ) );
if ( pCnt->GetDrawObjs() )
{
const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
{
SwAnchoredObject* pObj = rObjs[i];
if ( pObj->ISA(SwFlyFrm) )
{
SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pObj);
if ( pFly->IsFlyInCntFrm() )
{
SwCntntFrm *pCntnt = pFly->ContainsCntnt();
while ( pCntnt )
{
::lcl_NotifyCntnt( pThis, pCntnt, rRect, eHint );
pCntnt = pCntnt->GetNextCntntFrm();
}
}
}
}
}
}
}
void Notify_Background( const SdrObject* pObj,
SwPageFrm* pPage,
const SwRect& rRect,
const PrepareHint eHint,
const sal_Bool bInva )
{
//Wenn der Frm gerade erstmalig sinnvoll positioniert wurde, braucht der
//alte Bereich nicht benachrichtigt werden.
if ( eHint == PREP_FLY_LEAVE && rRect.Top() == WEIT_WECH )
return;
SwLayoutFrm* pArea;
SwFlyFrm *pFlyFrm = 0;
SwFrm* pAnchor;
if( pObj->ISA(SwVirtFlyDrawObj) )
{
pFlyFrm = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm();
pAnchor = pFlyFrm->AnchorFrm();
}
else
{
pFlyFrm = NULL;
pAnchor = const_cast<SwFrm*>(
GetUserCall(pObj)->GetAnchoredObj( pObj )->GetAnchorFrm() );
}
if( PREP_FLY_LEAVE != eHint && pAnchor->IsInFly() )
pArea = pAnchor->FindFlyFrm();
else
pArea = pPage;
SwCntntFrm *pCnt = 0;
if ( pArea )
{
if( PREP_FLY_ARRIVE != eHint )
lcl_CheckFlowBack( pArea, rRect );
//Es reagieren sowieso nur die auf den Anker folgenden auf den Fly, also
//brauchen diese nicht abgeklappert werden.
//Ausnahme sind ist natuerlich das LEAVE, denn der Fly koennte ja von
//"oben" kommen.
// Wenn der Anker auf der vorhergehenden Seite liegt, muss ebenfalls
// die gesamte Seite abgearbeitet werden. (47722)
// OD 2004-05-13 #i28701# - If the wrapping style has to be considered
// on the object positioning, the complete area has to be processed,
// because content frames before the anchor frame also have to consider
// the object for the text wrapping.
// --> OD 2004-08-25 #i3317# - The complete area has always been
// processed.
{
pCnt = pArea->ContainsCntnt();
}
// <--
}
SwFrm *pLastTab = 0;
while ( pCnt && pArea && pArea->IsAnLower( pCnt ) )
{
::lcl_NotifyCntnt( pObj, pCnt, rRect, eHint );
if ( pCnt->IsInTab() )
{
SwLayoutFrm* pCell = pCnt->GetUpper();
// --> OD 2005-01-14 #i40606# - use <GetLastBoundRect()>
// instead of <GetCurrentBoundRect()>, because a recalculation
// of the bounding rectangle isn't intended here.
if ( pCell->IsCellFrm() &&
( pCell->Frm().IsOver( pObj->GetLastBoundRect() ) ||
pCell->Frm().IsOver( rRect ) ) )
// <--
{
const SwFmtVertOrient &rOri = pCell->GetFmt()->GetVertOrient();
if ( text::VertOrientation::NONE != rOri.GetVertOrient() )
pCell->InvalidatePrt();
}
SwTabFrm *pTab = pCnt->FindTabFrm();
if ( pTab != pLastTab )
{
pLastTab = pTab;
// --> OD 2005-01-14 #i40606# - use <GetLastBoundRect()>
// instead of <GetCurrentBoundRect()>, because a recalculation
// of the bounding rectangle isn't intended here.
if ( pTab->Frm().IsOver( pObj->GetLastBoundRect() ) ||
pTab->Frm().IsOver( rRect ) )
// <--
{
if ( !pFlyFrm || !pFlyFrm->IsLowerOf( pTab ) )
pTab->InvalidatePrt();
}
}
}
pCnt = pCnt->GetNextCntntFrm();
}
// #108745# Sorry, but this causes nothing but trouble. I remove these lines
// taking the risk that the footer frame will have a wrong height
// if( pPage->Lower() )
// {
// SwFrm* pFrm = pPage->Lower();
// while( pFrm->GetNext() )
// pFrm = pFrm->GetNext();
// if( pFrm->IsFooterFrm() &&
// ( ( pFrm->Frm().IsOver( pObj->GetBoundRect() ) ||
// pFrm->Frm().IsOver( rRect ) ) ) )
// pFrm->InvalidateSize();
// }
// --> OD 2007-07-24 #128702# - make code robust
if ( pPage && pPage->GetSortedObjs() )
// <--
{
pObj->GetOrdNum();
const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
{
SwAnchoredObject* pAnchoredObj = rObjs[i];
if ( pAnchoredObj->ISA(SwFlyFrm) )
{
if( pAnchoredObj->GetDrawObj() == pObj )
continue;
SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj);
if ( pFly->Frm().Top() == WEIT_WECH )
continue;
if ( !pFlyFrm ||
(!pFly->IsLowerOf( pFlyFrm ) &&
pFly->GetVirtDrawObj()->GetOrdNumDirect() < pObj->GetOrdNumDirect()))
{
pCnt = pFly->ContainsCntnt();
while ( pCnt )
{
::lcl_NotifyCntnt( pObj, pCnt, rRect, eHint );
pCnt = pCnt->GetNextCntntFrm();
}
}
if( pFly->IsFlyLayFrm() )
{
if( pFly->Lower() && pFly->Lower()->IsColumnFrm() &&
pFly->Frm().Bottom() >= rRect.Top() &&
pFly->Frm().Top() <= rRect.Bottom() &&
pFly->Frm().Right() >= rRect.Left() &&
pFly->Frm().Left() <= rRect.Right() )
{
pFly->InvalidateSize();
}
}
//Flys, die ueber mir liegen muessen/mussten evtl.
//ausweichen, wenn sie eine automatische Ausrichtung haben.
//das ist unabhaengig von meinem Attribut, weil dies sich
//gerade geaendert haben kann und eben deshalb
//umformatiert wurde.
else if ( pFly->IsFlyAtCntFrm() &&
pObj->GetOrdNumDirect() <
pFly->GetVirtDrawObj()->GetOrdNumDirect() &&
pFlyFrm && !pFly->IsLowerOf( pFlyFrm ) )
{
const SwFmtHoriOrient &rH = pFly->GetFmt()->GetHoriOrient();
if ( text::HoriOrientation::NONE != rH.GetHoriOrient() &&
text::HoriOrientation::CENTER != rH.GetHoriOrient() &&
( !pFly->IsAutoPos() || text::RelOrientation::CHAR != rH.GetRelationOrient() ) &&
(pFly->Frm().Bottom() >= rRect.Top() &&
pFly->Frm().Top() <= rRect.Bottom()) )
pFly->InvalidatePos();
}
}
}
}
if ( pFlyFrm && pAnchor->GetUpper() && pAnchor->IsInTab() )//MA_FLY_HEIGHT
pAnchor->GetUpper()->InvalidateSize();
// --> OD 2008-01-30 #i82258# - make code robust
ViewShell* pSh = 0;
if ( bInva && pPage &&
0 != (pSh = pPage->getRootFrm()->GetCurrShell()) )
{
pSh->InvalidateWindows( rRect );
}
// <--
}
/*************************************************************************
|*
|* GetVirtualUpper() liefert bei absatzgebundenen Objekten den Upper
|* des Ankers. Falls es sich dabei um verkettete Rahmen oder
|* Fussnoten handelt, wird ggf. der "virtuelle" Upper ermittelt.
|*
|*************************************************************************/
const SwFrm* GetVirtualUpper( const SwFrm* pFrm, const Point& rPos )
{
if( pFrm->IsTxtFrm() )
{
pFrm = pFrm->GetUpper();
if( !pFrm->Frm().IsInside( rPos ) )
{
if( pFrm->IsFtnFrm() )
{
const SwFtnFrm* pTmp = ((SwFtnFrm*)pFrm)->GetFollow();
while( pTmp )
{
if( pTmp->Frm().IsInside( rPos ) )
return pTmp;
pTmp = pTmp->GetFollow();
}
}
else
{
SwFlyFrm* pTmp = (SwFlyFrm*)pFrm->FindFlyFrm();
while( pTmp )
{
if( pTmp->Frm().IsInside( rPos ) )
return pTmp;
pTmp = pTmp->GetNextLink();
}
}
}
}
return pFrm;
}
/*************************************************************************/
sal_Bool Is_Lower_Of( const SwFrm *pCurrFrm, const SdrObject* pObj )
{
Point aPos;
const SwFrm* pFrm;
if( pObj->ISA(SwVirtFlyDrawObj) )
{
const SwFlyFrm* pFly = ( (SwVirtFlyDrawObj*)pObj )->GetFlyFrm();
pFrm = pFly->GetAnchorFrm();
aPos = pFly->Frm().Pos();
}
else
{
pFrm = ( (SwDrawContact*)GetUserCall(pObj) )->GetAnchorFrm(pObj);
aPos = pObj->GetCurrentBoundRect().TopLeft();
}
ASSERT( pFrm, "8-( Fly is lost in Space." );
pFrm = GetVirtualUpper( pFrm, aPos );
do
{ if ( pFrm == pCurrFrm )
return sal_True;
if( pFrm->IsFlyFrm() )
{
aPos = pFrm->Frm().Pos();
pFrm = GetVirtualUpper( ((const SwFlyFrm*)pFrm)->GetAnchorFrm(), aPos );
}
else
pFrm = pFrm->GetUpper();
} while ( pFrm );
return sal_False;
}
const SwFrm *FindKontext( const SwFrm *pFrm, sal_uInt16 nAdditionalKontextTyp )
{
//Liefert die Umgebung des Frm in die kein Fly aus einer anderen
//Umgebung hineinragen kann.
const sal_uInt16 nTyp = FRM_ROOT | FRM_HEADER | FRM_FOOTER | FRM_FTNCONT |
FRM_FTN | FRM_FLY |
FRM_TAB | FRM_ROW | FRM_CELL |
nAdditionalKontextTyp;
do
{ if ( pFrm->GetType() & nTyp )
break;
pFrm = pFrm->GetUpper();
} while( pFrm );
return pFrm;
}
sal_Bool IsFrmInSameKontext( const SwFrm *pInnerFrm, const SwFrm *pFrm )
{
const SwFrm *pKontext = FindKontext( pInnerFrm, 0 );
const sal_uInt16 nTyp = FRM_ROOT | FRM_HEADER | FRM_FOOTER | FRM_FTNCONT |
FRM_FTN | FRM_FLY |
FRM_TAB | FRM_ROW | FRM_CELL;
do
{ if ( pFrm->GetType() & nTyp )
{
if( pFrm == pKontext )
return sal_True;
if( pFrm->IsCellFrm() )
return sal_False;
}
if( pFrm->IsFlyFrm() )
{
Point aPos( pFrm->Frm().Pos() );
pFrm = GetVirtualUpper( ((const SwFlyFrm*)pFrm)->GetAnchorFrm(), aPos );
}
else
pFrm = pFrm->GetUpper();
} while( pFrm );
return sal_False;
}
//---------------------------------
SwTwips MA_FASTCALL lcl_CalcCellRstHeight( SwLayoutFrm *pCell )
{
if ( pCell->Lower()->IsCntntFrm() || pCell->Lower()->IsSctFrm() )
{
SwFrm *pLow = pCell->Lower();
long nHeight = 0, nFlyAdd = 0;
do
{
long nLow = pLow->Frm().Height();
if( pLow->IsTxtFrm() && ((SwTxtFrm*)pLow)->IsUndersized() )
nLow += ((SwTxtFrm*)pLow)->GetParHeight()-pLow->Prt().Height();
else if( pLow->IsSctFrm() && ((SwSectionFrm*)pLow)->IsUndersized() )
nLow += ((SwSectionFrm*)pLow)->Undersize();
nFlyAdd = Max( 0L, nFlyAdd - nLow );
nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) );
nHeight += nLow;
pLow = pLow->GetNext();
} while ( pLow );
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.
SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell );
const SwBorderAttrs &rAttrs = *aAccess.Get();
nHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
return pCell->Frm().Height() - nHeight;
}
else
{
long nRstHeight = 0;
SwFrm *pLow = pCell->Lower();
do
{ nRstHeight += ::CalcRowRstHeight( (SwLayoutFrm*)pLow );
pLow = pLow->GetNext();
} while ( pLow );
return nRstHeight;
}
}
SwTwips MA_FASTCALL CalcRowRstHeight( SwLayoutFrm *pRow )
{
SwTwips nRstHeight = LONG_MAX;
SwLayoutFrm *pLow = (SwLayoutFrm*)pRow->Lower();
while ( pLow )
{
nRstHeight = Min( nRstHeight, ::lcl_CalcCellRstHeight( pLow ) );
pLow = (SwLayoutFrm*)pLow->GetNext();
}
return nRstHeight;
}
const SwFrm* MA_FASTCALL FindPage( const SwRect &rRect, const SwFrm *pPage )
{
if ( !rRect.IsOver( pPage->Frm() ) )
{
const SwRootFrm* pRootFrm = static_cast<const SwRootFrm*>(pPage->GetUpper());
const SwFrm* pTmpPage = pRootFrm ? pRootFrm->GetPageAtPos( rRect.TopLeft(), &rRect.SSize(), true ) : 0;
if ( pTmpPage )
pPage = pTmpPage;
}
return pPage;
}
#include <svl/smplhint.hxx>
class SwFrmHolder : private SfxListener
{
SwFrm* pFrm;
bool bSet;
virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
public:
SwFrmHolder() : pFrm(0), bSet(false) {}
void SetFrm( SwFrm* pHold );
SwFrm* GetFrm() { return pFrm; }
void Reset();
bool IsSet() { return bSet; }
};
void SwFrmHolder::SetFrm( SwFrm* pHold )
{
bSet = true;
pFrm = pHold;
StartListening(*pHold);
}
void SwFrmHolder::Reset()
{
if (pFrm)
EndListening(*pFrm);
bSet = false;
pFrm = 0;
}
void SwFrmHolder::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
if ( rHint.IsA(TYPE(SfxSimpleHint)) )
{
if ( ( (SfxSimpleHint&) rHint ).GetId() == SFX_HINT_DYING && &rBC == pFrm )
pFrm = 0;
}
}
SwFrm* GetFrmOfModify( const SwRootFrm* pLayout, SwModify const& rMod, sal_uInt16 const nFrmType,
const Point* pPoint, const SwPosition *pPos, const sal_Bool bCalcFrm )
{
SwFrm *pMinFrm = 0, *pTmpFrm;
SwFrmHolder aHolder;
SwRect aCalcRect;
bool bClientIterChanged = false;
SwIterator<SwFrm,SwModify> aIter( rMod );
do {
pMinFrm = 0;
aHolder.Reset();
sal_uInt64 nMinDist = 0;
bClientIterChanged = false;
for( pTmpFrm = aIter.First(); pTmpFrm; pTmpFrm = aIter.Next() )
{
if( pTmpFrm->GetType() & nFrmType &&
( !pLayout || pLayout == pTmpFrm->getRootFrm() ) &&
(!pTmpFrm->IsFlowFrm() ||
!SwFlowFrm::CastFlowFrm( pTmpFrm )->IsFollow() ))
{
if( pPoint )
{
// watch for Frm being deleted
if ( pMinFrm )
aHolder.SetFrm( pMinFrm );
else
aHolder.Reset();
if( bCalcFrm )
{
// --> OD 2005-03-04 #b6234250# - format parent Writer
// fly frame, if it isn't been formatted yet.
// Note: The Writer fly frame could be the frame itself.
SwFlyFrm* pFlyFrm( pTmpFrm->FindFlyFrm() );
if ( pFlyFrm &&
pFlyFrm->Frm().Pos().X() == WEIT_WECH &&
pFlyFrm->Frm().Pos().Y() == WEIT_WECH )
{
SwObjectFormatter::FormatObj( *pFlyFrm );
}
// <--
pTmpFrm->Calc();
}
// #127369#
// aIter.IsChanged checks if the current pTmpFrm has been deleted while
// it is the current iterator
// FrmHolder watches for deletion of the current pMinFrm
if( aIter.IsChanged() || ( aHolder.IsSet() && !aHolder.GetFrm() ) )
{
// restart iteration
bClientIterChanged = true;
break;
}
// bei Flys ggfs. ueber den Parent gehen wenn sie selbst
// nocht nicht "formatiert" sind
if( !bCalcFrm && nFrmType & FRM_FLY &&
((SwFlyFrm*)pTmpFrm)->GetAnchorFrm() &&
WEIT_WECH == pTmpFrm->Frm().Pos().X() &&
WEIT_WECH == pTmpFrm->Frm().Pos().Y() )
aCalcRect = ((SwFlyFrm*)pTmpFrm)->GetAnchorFrm()->Frm();
else
aCalcRect = pTmpFrm->Frm();
if ( aCalcRect.IsInside( *pPoint ) )
{
pMinFrm = pTmpFrm;
break;
}
// Point not in rectangle. Compare distances:
const Point aCalcRectCenter = aCalcRect.Center();
const Point aDiff = aCalcRectCenter - *pPoint;
const sal_uInt64 nCurrentDist = aDiff.X() * aDiff.X() + aDiff.Y() * aDiff.Y(); // opt: no sqrt
if ( !pMinFrm || nCurrentDist < nMinDist )
{
pMinFrm = pTmpFrm;
nMinDist = nCurrentDist;
}
}
else
{
// Wenn kein pPoint angegeben ist, dann reichen
// wir irgendeinen raus: den ersten!
pMinFrm = pTmpFrm;
break;
}
}
}
} while( bClientIterChanged );
if( pPos && pMinFrm && pMinFrm->IsTxtFrm() )
return ((SwTxtFrm*)pMinFrm)->GetFrmAtPos( *pPos );
return pMinFrm;
}
sal_Bool IsExtraData( const SwDoc *pDoc )
{
const SwLineNumberInfo &rInf = pDoc->GetLineNumberInfo();
return rInf.IsPaintLineNumbers() ||
rInf.IsCountInFlys() ||
((sal_Int16)SW_MOD()->GetRedlineMarkPos() != text::HoriOrientation::NONE &&
pDoc->GetRedlineTbl().Count());
}
// OD 22.09.2003 #110978#
const SwRect SwPageFrm::PrtWithoutHeaderAndFooter() const
{
SwRect aPrtWithoutHeaderFooter( Prt() );
aPrtWithoutHeaderFooter.Pos() += Frm().Pos();
const SwFrm* pLowerFrm = Lower();
while ( pLowerFrm )
{
// Note: independent on text direction page header and page footer are
// always at top respectively at bottom of the page frame.
if ( pLowerFrm->IsHeaderFrm() )
{
aPrtWithoutHeaderFooter.Top( aPrtWithoutHeaderFooter.Top() +
pLowerFrm->Frm().Height() );
}
if ( pLowerFrm->IsFooterFrm() )
{
aPrtWithoutHeaderFooter.Bottom( aPrtWithoutHeaderFooter.Bottom() -
pLowerFrm->Frm().Height() );
}
pLowerFrm = pLowerFrm->GetNext();
}
return aPrtWithoutHeaderFooter;
}
/** method to determine the spacing values of a frame
OD 2004-03-10 #i28701#
OD 2009-08-28 #i102458#
Add output parameter <obIsLineSpacingProportional>
@author OD
*/
void GetSpacingValuesOfFrm( const SwFrm& rFrm,
SwTwips& onLowerSpacing,
SwTwips& onLineSpacing,
bool& obIsLineSpacingProportional )
{
if ( !rFrm.IsFlowFrm() )
{
onLowerSpacing = 0;
onLineSpacing = 0;
}
else
{
const SvxULSpaceItem& rULSpace = rFrm.GetAttrSet()->GetULSpace();
onLowerSpacing = rULSpace.GetLower();
onLineSpacing = 0;
obIsLineSpacingProportional = false;
if ( rFrm.IsTxtFrm() )
{
onLineSpacing = static_cast<const SwTxtFrm&>(rFrm).GetLineSpace();
obIsLineSpacingProportional =
onLineSpacing != 0 &&
static_cast<const SwTxtFrm&>(rFrm).GetLineSpace( true ) == 0;
}
ASSERT( onLowerSpacing >= 0 && onLineSpacing >= 0,
"<GetSpacingValuesOfFrm(..)> - spacing values aren't positive!" );
}
}
/** method to get the content of the table cell, skipping content from nested tables
*/
const SwCntntFrm* GetCellCntnt( const SwLayoutFrm& rCell )
{
const SwCntntFrm* pCntnt = rCell.ContainsCntnt();
const SwTabFrm* pTab = rCell.FindTabFrm();
while ( pCntnt && rCell.IsAnLower( pCntnt ) )
{
const SwTabFrm* pTmpTab = pCntnt->FindTabFrm();
if ( pTmpTab != pTab )
{
pCntnt = pTmpTab->FindLastCntnt();
if ( pCntnt )
pCntnt = pCntnt->FindNextCnt();
}
else
break;
}
return pCntnt;
}
/** Can be used to check if a frame has been deleted
*/
bool SwDeletionChecker::HasBeenDeleted()
{
if ( !mpFrm || !mpRegIn )
return false;
SwIterator<SwFrm,SwModify> aIter(*mpRegIn);
SwFrm* pLast = aIter.First();
while ( pLast )
{
if ( pLast == mpFrm )
return false;
pLast = aIter.Next();
}
return true;
}