diff options
Diffstat (limited to 'sw/source/core/layout/frmtool.cxx')
-rw-r--r-- | sw/source/core/layout/frmtool.cxx | 3604 |
1 files changed, 3604 insertions, 0 deletions
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx new file mode 100644 index 000000000000..56059a4aaf26 --- /dev/null +++ b/sw/source/core/layout/frmtool.cxx @@ -0,0 +1,3604 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <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 ) + { + OSL_ENSURE( 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 + { + OSL_FAIL( "<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(); + OSL_ENSURE( 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(); + } + } + } + + sal_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()) ) + { + OSL_ENSURE( 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 occurrence of CalcLayout in + // uiview/view.cxx. + if ( !pNd->IsOLESizeInvalid() && + !pSh->GetDoc()->IsUpdateExpFld() ) + pFESh->CalcAndSetScale( xObj, &pFly->Prt(), &pFly->Frm()); + } + 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->IsLoaded() && !pDoc->IsNewDoc() ) + { + //Der Frm wurde wahrscheinlich zum ersten mal formatiert. + //Wenn ein Filter Flys oder Zeichenobjekte einliest und diese + //Seitengebunden sind, hat er ein Problem, weil er i.d.R. die + //Seitennummer nicht kennt. Er weiss lediglich welches der Inhalt + //(CntntNode) an dieser Stelle ist. + //Die Filter stellen dazu das Ankerattribut der Objekte so ein, dass + //sie vom Typ zwar Seitengebunden sind, aber der Index des Ankers + //auf diesen CntntNode zeigt. + //Hier werden diese vorlauefigen Verbindungen aufgeloest. + + const SwPageFrm *pPage = 0; + SwNodeIndex *pIdx = 0; + SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts(); + + for ( sal_uInt16 i = 0; i < pTbl->Count(); ++i ) + { + if ( !pPage ) + pPage = pCnt->FindPageFrm(); + SwFrmFmt *pFmt = (*pTbl)[i]; + const SwFmtAnchor &rAnch = pFmt->GetAnchor(); + + if ((FLY_AT_PAGE != rAnch.GetAnchorId()) && + (FLY_AT_PARA != rAnch.GetAnchorId())) + { + continue; //#60878# nicht etwa zeichengebundene. + } + + if ( rAnch.GetCntntAnchor() ) + { + if ( !pIdx ) + { + pIdx = new SwNodeIndex( *pCnt->GetNode() ); + } + if ( rAnch.GetCntntAnchor()->nNode == *pIdx ) + { + if (FLY_AT_PAGE == rAnch.GetAnchorId()) + { + OSL_FAIL( "<SwCntntNotify::~SwCntntNotify()> - to page anchored object with content position. Please inform OD." ); + 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()) ) + { + OSL_ENSURE( !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 ); + OSL_ENSURE( !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() ) + { + OSL_ENSURE( pActualSection, "Sectionende ohne Anfang?" ); + OSL_ENSURE( 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() ) + { +#if OSL_DEBUG_LEVEL > 1 + pDoc->GetLayoutCache()->CompareLayout( *pDoc ); +#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 ); + OSL_ENSURE( 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! + OSL_ENSURE( !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 + { + OSL_ENSURE( !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=0; + + if (!pCaller->IsTxtFrm() || !((SwTxtFrm*)pCaller)->GetTxtNode()->GetDoc()->get(IDocumentSettingAccess::INVERT_BORDER_SPACING)) { + // 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(); + + // 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=0; + + if (!pCaller->IsTxtFrm() || !((SwTxtFrm*)pCaller)->GetTxtNode()->GetDoc()->get(IDocumentSettingAccess::INVERT_BORDER_SPACING)) { + // 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(); + + + // 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 editeng::SvxBorderLine *pL1, const editeng::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() ) + { + const SwSortedObjs *pObjs = pPage->GetSortedObjs(); + if ( pObjs->Count() ) + { + sal_uInt32 nTopOrd = 0; + (*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() ) + { + const SwSortedObjs *pObjs = pPage->GetSortedObjs(); + if ( pObjs->Count() ) + { + sal_uInt32 nOrd = 0; + (*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 ) +{ + OSL_ENSURE( _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 { + OSL_ENSURE( !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 ) +{ + OSL_ENSURE( _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 ) +{ + OSL_ENSURE( 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(); + OSL_ENSURE( 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() ) + { + pObj->DrawObj()->GetPage()->SetObjectOrdNum( + pObj->GetDrawObj()->GetOrdNumDirect(), + pFly->GetVirtDrawObj()->GetOrdNumDirect() + 1 ); + } + } +} + +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(); + } + OSL_ENSURE( 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; + } + + OSL_ENSURE( 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; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |