diff options
Diffstat (limited to 'sw/source/core/layout')
45 files changed, 61209 insertions, 0 deletions
diff --git a/sw/source/core/layout/anchoreddrawobject.cxx b/sw/source/core/layout/anchoreddrawobject.cxx new file mode 100644 index 000000000000..c00f394c9a83 --- /dev/null +++ b/sw/source/core/layout/anchoreddrawobject.cxx @@ -0,0 +1,900 @@ +/* -*- 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 <anchoreddrawobject.hxx> +#include <svx/svdobj.hxx> +#include <dcontact.hxx> +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <doc.hxx> +#include <tocntntanchoredobjectposition.hxx> +#include <tolayoutanchoredobjectposition.hxx> +#include <frmtool.hxx> +#include <fmtornt.hxx> +// --> #i32795# +#include <txtfrm.hxx> +// <-- +// --> #i32795# +// template class <std::vector> +#include <vector> +// <-- + +// --> #i28749# +#include <com/sun/star/text/PositionLayoutDir.hpp> +// <-- +// --> #i44559# +#include <ndtxt.hxx> +// <-- + +using namespace ::com::sun::star; + +// ============================================================================ +// helper class for correct notification due to the positioning of +// the anchored drawing object +// ============================================================================ +class SwPosNotify +{ + private: + SwAnchoredDrawObject* mpAnchoredDrawObj; + SwRect maOldObjRect; + SwPageFrm* mpOldPageFrm; + + public: + SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj ); + ~SwPosNotify(); + // --> OD 2004-08-12 #i32795# + Point LastObjPos() const; + // <-- +}; + +SwPosNotify::SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj ) : + mpAnchoredDrawObj( _pAnchoredDrawObj ) +{ + maOldObjRect = mpAnchoredDrawObj->GetObjRect(); + // --> #i35640# - determine correct page frame + mpOldPageFrm = mpAnchoredDrawObj->GetPageFrm(); + // <-- +} + +SwPosNotify::~SwPosNotify() +{ + if ( maOldObjRect != mpAnchoredDrawObj->GetObjRect() ) + { + if( maOldObjRect.HasArea() && mpOldPageFrm ) + { + mpAnchoredDrawObj->NotifyBackground( mpOldPageFrm, maOldObjRect, + PREP_FLY_LEAVE ); + } + SwRect aNewObjRect( mpAnchoredDrawObj->GetObjRect() ); + if( aNewObjRect.HasArea() ) + { + // --> #i35640# - determine correct page frame + SwPageFrm* pNewPageFrm = mpAnchoredDrawObj->GetPageFrm(); + // <-- + if( pNewPageFrm ) + mpAnchoredDrawObj->NotifyBackground( pNewPageFrm, aNewObjRect, + PREP_FLY_ARRIVE ); + } + + ::ClrContourCache( mpAnchoredDrawObj->GetDrawObj() ); + + // --> #i35640# - additional notify anchor text frame + // Needed for negative positioned drawing objects + // --> #i43255# - refine condition to avoid unneeded + // invalidations: anchored object had to be on the page of its anchor + // text frame. + if ( mpAnchoredDrawObj->GetAnchorFrm()->IsTxtFrm() && + mpOldPageFrm == mpAnchoredDrawObj->GetAnchorFrm()->FindPageFrm() ) + { + mpAnchoredDrawObj->AnchorFrm()->Prepare( PREP_FLY_LEAVE ); + } + // <-- + + // indicate a restart of the layout process + mpAnchoredDrawObj->SetRestartLayoutProcess( true ); + } + else + { + // lock position + mpAnchoredDrawObj->LockPosition(); + + if ( !mpAnchoredDrawObj->ConsiderForTextWrap() ) + { + // indicate that object has to be considered for text wrap + mpAnchoredDrawObj->SetConsiderForTextWrap( true ); + // invalidate 'background' in order to allow its 'background' + // to wrap around it. + mpAnchoredDrawObj->NotifyBackground( mpAnchoredDrawObj->GetPageFrm(), + mpAnchoredDrawObj->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. + mpAnchoredDrawObj->AnchorFrm()->InvalidatePos(); + } + } +} + +// --> #i32795# +Point SwPosNotify::LastObjPos() const +{ + return maOldObjRect.Pos(); +} +//<-- + +// ============================================================================ +// #i32795# +// helper class for oscillation control on object positioning +// ============================================================================ +class SwObjPosOscillationControl +{ + private: + sal_uInt8 mnPosStackSize; + + const SwAnchoredDrawObject* mpAnchoredDrawObj; + + std::vector<Point*> maObjPositions; + + public: + SwObjPosOscillationControl( const SwAnchoredDrawObject& _rAnchoredDrawObj ); + ~SwObjPosOscillationControl(); + + bool OscillationDetected(); +}; + +SwObjPosOscillationControl::SwObjPosOscillationControl( + const SwAnchoredDrawObject& _rAnchoredDrawObj ) + : mnPosStackSize( 20 ), + mpAnchoredDrawObj( &_rAnchoredDrawObj ) +{ +} + +SwObjPosOscillationControl::~SwObjPosOscillationControl() +{ + while ( !maObjPositions.empty() ) + { + Point* pPos = maObjPositions.back(); + delete pPos; + + maObjPositions.pop_back(); + } +} + +bool SwObjPosOscillationControl::OscillationDetected() +{ + bool bOscillationDetected = false; + + if ( maObjPositions.size() == mnPosStackSize ) + { + // position stack is full -> oscillation + bOscillationDetected = true; + } + else + { + Point* pNewObjPos = new Point( mpAnchoredDrawObj->GetObjRect().Pos() ); + for ( std::vector<Point*>::iterator aObjPosIter = maObjPositions.begin(); + aObjPosIter != maObjPositions.end(); + ++aObjPosIter ) + { + if ( *(pNewObjPos) == *(*aObjPosIter) ) + { + // position already occurred -> oscillation + bOscillationDetected = true; + delete pNewObjPos; + break; + } + } + if ( !bOscillationDetected ) + { + maObjPositions.push_back( pNewObjPos ); + } + } + + return bOscillationDetected; +} + +// ============================================================================ +// implementation of class <SwAnchoredDrawObject> +// ============================================================================ +TYPEINIT1(SwAnchoredDrawObject,SwAnchoredObject); + +SwAnchoredDrawObject::SwAnchoredDrawObject() : + SwAnchoredObject(), + mbValidPos( false ), + // --> #i34748# + mpLastObjRect( 0L ), + // <-- + mbNotYetAttachedToAnchorFrame( true ), + // --> #i28749# + mbNotYetPositioned( true ), + // <-- + // --> #i62875# + mbCaptureAfterLayoutDirChange( false ) + // <-- +{ +} + +SwAnchoredDrawObject::~SwAnchoredDrawObject() +{ + // --> follow-up of #i34748# + delete mpLastObjRect; + // <-- +} + +// --> #i62875# +void SwAnchoredDrawObject::UpdateLayoutDir() +{ + SwFrmFmt::tLayoutDir nOldLayoutDir( GetFrmFmt().GetLayoutDir() ); + + SwAnchoredObject::UpdateLayoutDir(); + + if ( !NotYetPositioned() && + GetFrmFmt().GetLayoutDir() != nOldLayoutDir && + GetFrmFmt().GetDoc()->get(IDocumentSettingAccess::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE) && + !IsOutsidePage() ) + { + mbCaptureAfterLayoutDirChange = true; + } +} +// <-- + +// --> #i62875# +bool SwAnchoredDrawObject::IsOutsidePage() const +{ + bool bOutsidePage( false ); + + if ( !NotYetPositioned() && GetPageFrm() ) + { + SwRect aTmpRect( GetObjRect() ); + bOutsidePage = + ( aTmpRect.Intersection( GetPageFrm()->Frm() ) != GetObjRect() ); + } + + return bOutsidePage; +} +// <-- + +// ============================================================================= +// #i26791# - implementation of pure virtual method declared in +// base class <SwAnchoredObject> +// ============================================================================= +void SwAnchoredDrawObject::MakeObjPos() +{ + if ( IsPositioningInProgress() ) + { + // nothind to do - positioning already in progress + return; + } + + if ( mbValidPos ) + { + // nothing to do - position is valid + return; + } + + // --> #i28749# - anchored drawing object has to be attached + // to anchor frame + if ( mbNotYetAttachedToAnchorFrame ) + { + OSL_FAIL( "<SwAnchoredDrawObject::MakeObjPos() - drawing object not yet attached to anchor frame -> no positioning" ); + return; + } + + SwDrawContact* pDrawContact = + static_cast<SwDrawContact*>(::GetUserCall( GetDrawObj() )); + + // --> #i28749# - if anchored drawing object hasn't been yet + // positioned, convert its positioning attributes, if its positioning + // attributes are given in horizontal left-to-right layout. + // --> #i36010# - Note: horizontal left-to-right layout is made + // the default layout direction for <SwDrawFrmFmt> instances. Thus, it has + // to be adjusted manually, if no adjustment of the positioning attributes + // have to be performed here. + // --> #i35635# - additionally move drawing object to the visible layer. + if ( mbNotYetPositioned ) + { + // --> #i35635# + pDrawContact->MoveObjToVisibleLayer( DrawObj() ); + // <-- + // --> perform conversion of positioning + // attributes only for 'master' drawing objects + // --> #i44334#, #i44681# - check, if positioning + // attributes already have been set. + if ( !GetDrawObj()->ISA(SwDrawVirtObj) && + !static_cast<SwDrawFrmFmt&>(GetFrmFmt()).IsPosAttrSet() ) + { + _SetPositioningAttr(); + } + // <-- + // --> + // - reset internal flag after all needed actions are performed to + // avoid callbacks from drawing layer + mbNotYetPositioned = false; + // <-- + } + // <-- + + // indicate that positioning is in progress + { + SwObjPositioningInProgress aObjPosInProgress( *this ); + + // determine relative position of drawing object and set it + switch ( pDrawContact->GetAnchorId() ) + { + case FLY_AS_CHAR: + { + // indicate that position will be valid after positioning is performed + mbValidPos = true; + // nothing to do, because as-character anchored objects are positioned + // during the format of its anchor frame - see <SwFlyCntPortion::SetBase(..)> + } + break; + case FLY_AT_PARA: + case FLY_AT_CHAR: + { + // --> #i32795# - move intrinsic positioning to + // helper method <_MakeObjPosAnchoredAtPara()> + _MakeObjPosAnchoredAtPara(); + } + break; + case FLY_AT_PAGE: + case FLY_AT_FLY: + { + // --> #i32795# - move intrinsic positioning to + // helper method <_MakeObjPosAnchoredAtLayout()> + _MakeObjPosAnchoredAtLayout(); + } + break; + default: + { + OSL_FAIL( "<SwAnchoredDrawObject::MakeObjPos()> - unknown anchor type - please inform OD." ); + } + } + + // keep, current object rectangle + // --> #i34748# - use new method <SetLastObjRect(..)> + SetLastObjRect( GetObjRect().SVRect() ); + // <-- + + // Assure for 'master' drawing object, that it's registered at the correct page. + // Perform check not for as-character anchored drawing objects and only if + // the anchor frame is valid. + if ( !GetDrawObj()->ISA(SwDrawVirtObj) && + !pDrawContact->ObjAnchoredAsChar() && + GetAnchorFrm()->IsValid() ) + { + pDrawContact->ChkPage(); + } + } + + // --> #i62875# + if ( mbCaptureAfterLayoutDirChange && + GetPageFrm() ) + { + SwRect aPageRect( GetPageFrm()->Frm() ); + SwRect aObjRect( GetObjRect() ); + if ( aObjRect.Right() >= aPageRect.Right() + 10 ) + { + Size aSize( aPageRect.Right() - aObjRect.Right(), 0 ); + DrawObj()->Move( aSize ); + aObjRect = GetObjRect(); + } + + if ( aObjRect.Left() + 10 <= aPageRect.Left() ) + { + Size aSize( aPageRect.Left() - aObjRect.Left(), 0 ); + DrawObj()->Move( aSize ); + } + + mbCaptureAfterLayoutDirChange = false; + } + // <-- +} + +/** method for the intrinsic positioning of a at-paragraph|at-character + anchored drawing object + + #i32795# - helper method for method <MakeObjPos> + + @author OD +*/ +void SwAnchoredDrawObject::_MakeObjPosAnchoredAtPara() +{ + // --> #i32795# - adopt positioning algorithm from Writer + // fly frames, which are anchored at paragraph|at character + + // Determine, if anchor frame can/has to be formatted. + // If yes, after each object positioning the anchor frame is formatted. + // If after the anchor frame format the object position isn't valid, the + // object is positioned again. + // --> #i43255# - refine condition: anchor frame format not + // allowed, if another anchored object, has to be consider its wrap influence + // --> #i50356# - format anchor frame containing the anchor + // position. E.g., for at-character anchored object this can be the follow + // frame of the anchor frame, which contains the anchor character. + const bool bFormatAnchor = + !static_cast<const SwTxtFrm*>( GetAnchorFrmContainingAnchPos() )->IsAnyJoinLocked() && + !ConsiderObjWrapInfluenceOnObjPos() && + !ConsiderObjWrapInfluenceOfOtherObjs(); + // <-- + + if ( bFormatAnchor ) + { + // --> #i50356# + GetAnchorFrmContainingAnchPos()->Calc(); + // <-- + } + + bool bOscillationDetected = false; + SwObjPosOscillationControl aObjPosOscCtrl( *this ); + // --> #i3317# - boolean, to apply temporarly the + // 'straightforward positioning process' for the frame due to its + // overlapping with a previous column. + bool bConsiderWrapInfluenceDueToOverlapPrevCol( false ); + // <-- + do { + // indicate that position will be valid after positioning is performed + mbValidPos = true; + + // --> #i35640# - correct scope for <SwPosNotify> instance + { + // create instance of <SwPosNotify> for correct notification + SwPosNotify aPosNotify( this ); + + // determine and set position + objectpositioning::SwToCntntAnchoredObjectPosition + aObjPositioning( *DrawObj() ); + aObjPositioning.CalcPosition(); + + // get further needed results of the positioning algorithm + SetVertPosOrientFrm ( aObjPositioning.GetVertPosOrientFrm() ); + _SetDrawObjAnchor(); + + // check for object position oscillation, if position has changed. + if ( GetObjRect().Pos() != aPosNotify.LastObjPos() ) + { + bOscillationDetected = aObjPosOscCtrl.OscillationDetected(); + } + } + // <-- + // format anchor frame, if requested. + // Note: the format of the anchor frame can cause the object position + // to be invalid. + if ( bFormatAnchor ) + { + // --> #i50356# + GetAnchorFrmContainingAnchPos()->Calc(); + // <-- + } + + // --> #i3317# + if ( !ConsiderObjWrapInfluenceOnObjPos() && + OverlapsPrevColumn() ) + { + bConsiderWrapInfluenceDueToOverlapPrevCol = true; + } + // <-- + } while ( !mbValidPos && !bOscillationDetected && + !bConsiderWrapInfluenceDueToOverlapPrevCol ); + + // --> #i3317# - consider a detected oscillation and overlapping + // with previous column. + // temporarly consider the anchored objects wrapping style influence + if ( bOscillationDetected || bConsiderWrapInfluenceDueToOverlapPrevCol ) + { + SetTmpConsiderWrapInfluence( true ); + SetRestartLayoutProcess( true ); + } + // <-- +} + +/** method for the intrinsic positioning of a at-page|at-frame anchored + drawing object + + #i32795# - helper method for method <MakeObjPos> + + @author OD +*/ +void SwAnchoredDrawObject::_MakeObjPosAnchoredAtLayout() +{ + // indicate that position will be valid after positioning is performed + mbValidPos = true; + + // create instance of <SwPosNotify> for correct notification + SwPosNotify aPosNotify( this ); + + // determine position + objectpositioning::SwToLayoutAnchoredObjectPosition + aObjPositioning( *DrawObj() ); + aObjPositioning.CalcPosition(); + + // set position + + // --> #i31698# + // --> #i34995# - setting anchor position needed for filters, + // especially for the xml-filter to the OpenOffice.org file format + { + const Point aNewAnchorPos = + GetAnchorFrm()->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) ); + DrawObj()->SetAnchorPos( aNewAnchorPos ); + // --> #i70122# - missing invalidation + InvalidateObjRectWithSpaces(); + // <-- + } + // <-- + SetCurrRelPos( aObjPositioning.GetRelPos() ); + const SwFrm* pAnchorFrm = GetAnchorFrm(); + SWRECTFN( pAnchorFrm ); + const Point aAnchPos( (pAnchorFrm->Frm().*fnRect->fnGetPos)() ); + SetObjLeft( aAnchPos.X() + GetCurrRelPos().X() ); + SetObjTop( aAnchPos.Y() + GetCurrRelPos().Y() ); + // <-- +} + +void SwAnchoredDrawObject::_SetDrawObjAnchor() +{ + // new anchor position + // --> #i31698# - + Point aNewAnchorPos = + GetAnchorFrm()->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) ); + Point aCurrAnchorPos = GetDrawObj()->GetAnchorPos(); + if ( aNewAnchorPos != aCurrAnchorPos ) + { + // determine movement to be applied after setting the new anchor position + Size aMove( aCurrAnchorPos.X() - aNewAnchorPos.X(), + aCurrAnchorPos.Y() - aNewAnchorPos.Y() ); + // set new anchor position + DrawObj()->SetAnchorPos( aNewAnchorPos ); + // correct object position, caused by setting new anchor position + DrawObj()->Move( aMove ); + // --> #i70122# - missing invalidation + InvalidateObjRectWithSpaces(); + // <-- + } +} + +/** method to invalidate the given page frame + + #i28701# + + @author OD +*/ +void SwAnchoredDrawObject::_InvalidatePage( SwPageFrm* _pPageFrm ) +{ + if ( _pPageFrm && !_pPageFrm->GetFmt()->GetDoc()->IsInDtor() ) + { + if ( _pPageFrm->GetUpper() ) + { + // --> #i35007# - correct invalidation for as-character + // anchored objects. + if ( GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR ) + { + _pPageFrm->InvalidateFlyInCnt(); + } + else + { + _pPageFrm->InvalidateFlyLayout(); + } + // <-- + + SwRootFrm* pRootFrm = static_cast<SwRootFrm*>(_pPageFrm->GetUpper()); + pRootFrm->DisallowTurbo(); + if ( pRootFrm->GetTurbo() ) + { + const SwCntntFrm* pTmpFrm = pRootFrm->GetTurbo(); + pRootFrm->ResetTurbo(); + pTmpFrm->InvalidatePage(); + } + pRootFrm->SetIdleFlags(); + } + } +} + +void SwAnchoredDrawObject::InvalidateObjPos() +{ + // --> #i28701# - check, if invalidation is allowed + if ( mbValidPos && + InvalidationOfPosAllowed() ) + { + mbValidPos = false; + // --> #i68520# + InvalidateObjRectWithSpaces(); + // <-- + + // --> #i44339# - check, if anchor frame exists. + if ( GetAnchorFrm() ) + { + // --> #118547# - notify anchor frame of as-character + // anchored object, because its positioned by the format of its anchor frame. + // --> #i44559# - assure, that text hint is already + // existing in the text frame + if ( GetAnchorFrm()->ISA(SwTxtFrm) && + (GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) ) + { + SwTxtFrm* pAnchorTxtFrm( static_cast<SwTxtFrm*>(AnchorFrm()) ); + if ( pAnchorTxtFrm->GetTxtNode()->GetpSwpHints() && + pAnchorTxtFrm->CalcFlyPos( &GetFrmFmt() ) != STRING_LEN ) + { + AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, &GetFrmFmt() ); + } + } + // <-- + + SwPageFrm* pPageFrm = AnchorFrm()->FindPageFrm(); + _InvalidatePage( pPageFrm ); + + // --> #i32270# - also invalidate page frame, at which the + // drawing object is registered at. + SwPageFrm* pPageFrmRegisteredAt = GetPageFrm(); + if ( pPageFrmRegisteredAt && + pPageFrmRegisteredAt != pPageFrm ) + { + _InvalidatePage( pPageFrmRegisteredAt ); + } + // <-- + // --> #i33751#, #i34060# - method <GetPageFrmOfAnchor()> + // is replaced by method <FindPageFrmOfAnchor()>. It's return value + // have to be checked. + SwPageFrm* pPageFrmOfAnchor = FindPageFrmOfAnchor(); + if ( pPageFrmOfAnchor && + pPageFrmOfAnchor != pPageFrm && + pPageFrmOfAnchor != pPageFrmRegisteredAt ) + // <-- + { + _InvalidatePage( pPageFrmOfAnchor ); + } + } + // <-- + } +} + +SwFrmFmt& SwAnchoredDrawObject::GetFrmFmt() +{ + OSL_ENSURE( static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt(), + "<SwAnchoredDrawObject::GetFrmFmt()> - missing frame format -> crash." ); + return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt()); +} +const SwFrmFmt& SwAnchoredDrawObject::GetFrmFmt() const +{ + OSL_ENSURE( static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt(), + "<SwAnchoredDrawObject::GetFrmFmt()> - missing frame format -> crash." ); + return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFmt()); +} + +const SwRect SwAnchoredDrawObject::GetObjRect() const +{ + // use geometry of drawing object + //return GetDrawObj()->GetCurrentBoundRect(); + return GetDrawObj()->GetSnapRect(); +} + +// --> #i70122# +const SwRect SwAnchoredDrawObject::GetObjBoundRect() const +{ + return GetDrawObj()->GetCurrentBoundRect(); +} +// <-- + +// --> #i68520# +bool SwAnchoredDrawObject::_SetObjTop( const SwTwips _nTop ) +{ + SwTwips nDiff = _nTop - GetObjRect().Top(); + DrawObj()->Move( Size( 0, nDiff ) ); + + return nDiff != 0; +} +bool SwAnchoredDrawObject::_SetObjLeft( const SwTwips _nLeft ) +{ + SwTwips nDiff = _nLeft - GetObjRect().Left(); + DrawObj()->Move( Size( nDiff, 0 ) ); + + return nDiff != 0; +} +// <-- + +/** adjust positioning and alignment attributes for new anchor frame + + #i33313# - add second optional parameter <_pNewObjRect> + + @author OD +*/ +void SwAnchoredDrawObject::AdjustPositioningAttr( const SwFrm* _pNewAnchorFrm, + const SwRect* _pNewObjRect ) +{ + SwTwips nHoriRelPos = 0; + SwTwips nVertRelPos = 0; + const Point aAnchorPos = _pNewAnchorFrm->GetFrmAnchorPos( ::HasWrap( GetDrawObj() ) ); + // --> #i33313# + const SwRect aObjRect( _pNewObjRect ? *_pNewObjRect : GetObjRect() ); + // <-- + const bool bVert = _pNewAnchorFrm->IsVertical(); + const bool bR2L = _pNewAnchorFrm->IsRightToLeft(); + if ( bVert ) + { + nHoriRelPos = aObjRect.Top() - aAnchorPos.Y(); + nVertRelPos = aAnchorPos.X() - aObjRect.Right(); + } + else if ( bR2L ) + { + nHoriRelPos = aAnchorPos.X() - aObjRect.Right(); + nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); + } + else + { + nHoriRelPos = aObjRect.Left() - aAnchorPos.X(); + nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); + } + + GetFrmFmt().SetFmtAttr( SwFmtHoriOrient( nHoriRelPos, text::HoriOrientation::NONE, text::RelOrientation::FRAME ) ); + GetFrmFmt().SetFmtAttr( SwFmtVertOrient( nVertRelPos, text::VertOrientation::NONE, text::RelOrientation::FRAME ) ); +} + +// --> #i34748# - change return type +const Rectangle* SwAnchoredDrawObject::GetLastObjRect() const +{ + return mpLastObjRect; +} +// <-- + +// --> #i34748# - change return type. +// If member <mpLastObjRect> is NULL, create one. +void SwAnchoredDrawObject::SetLastObjRect( const Rectangle& _rNewLastRect ) +{ + if ( !mpLastObjRect ) + { + mpLastObjRect = new Rectangle; + } + *(mpLastObjRect) = _rNewLastRect; +} +// <-- + +void SwAnchoredDrawObject::ObjectAttachedToAnchorFrame() +{ + // --> #i31698# + SwAnchoredObject::ObjectAttachedToAnchorFrame(); + // <-- + + if ( mbNotYetAttachedToAnchorFrame ) + { + mbNotYetAttachedToAnchorFrame = false; + } +} + +/** method to set positioning attributes + + #i35798# + During load the positioning attributes aren't set. + Thus, the positioning attributes are set by the current object geometry. + This method is also used for the conversion for drawing objects + (not anchored as-character) imported from OpenOffice.org file format + once and directly before the first positioning. + + @author OD +*/ +void SwAnchoredDrawObject::_SetPositioningAttr() +{ + SwDrawContact* pDrawContact = + static_cast<SwDrawContact*>(GetUserCall( GetDrawObj() )); + + if ( !pDrawContact->ObjAnchoredAsChar() ) + { + SwRect aObjRect( GetObjRect() ); + + SwTwips nHoriPos = aObjRect.Left(); + SwTwips nVertPos = aObjRect.Top(); + // --> #i44334#, #i44681# + // perform conversion only if position is in horizontal-left-to-right-layout. + if ( GetFrmFmt().GetPositionLayoutDir() == + text::PositionLayoutDir::PositionInHoriL2R ) + { + SwFrmFmt::tLayoutDir eLayoutDir = GetFrmFmt().GetLayoutDir(); + switch ( eLayoutDir ) + { + case SwFrmFmt::HORI_L2R: + { + // nothing to do + } + break; + case SwFrmFmt::HORI_R2L: + { + nHoriPos = -aObjRect.Left() - aObjRect.Width(); + } + break; + case SwFrmFmt::VERT_R2L: + { + nHoriPos = aObjRect.Top(); + nVertPos = -aObjRect.Left() - aObjRect.Width(); + } + break; + default: + { + OSL_FAIL( "<SwAnchoredDrawObject::_SetPositioningAttr()> - unsupported layout direction" ); + } + } + } + // <-- + + // --> #i71182# + // only change position - do not lose other attributes + SwFmtHoriOrient aHori( GetFrmFmt().GetHoriOrient() ); + aHori.SetPos( nHoriPos ); + GetFrmFmt().SetFmtAttr( aHori ); + + SwFmtVertOrient aVert( GetFrmFmt().GetVertOrient() ); + + aVert.SetPos( nVertPos ); + GetFrmFmt().SetFmtAttr( aVert ); + // <-- + + // --> #i36010# - set layout direction of the position + GetFrmFmt().SetPositionLayoutDir( + text::PositionLayoutDir::PositionInLayoutDirOfAnchor ); + // <-- + } + // --> #i65798# - also for as-character anchored objects + // --> #i45952# - indicate that position + // attributes are set now. + static_cast<SwDrawFrmFmt&>(GetFrmFmt()).PosAttrSet(); + // <-- +} + +void SwAnchoredDrawObject::NotifyBackground( SwPageFrm* _pPageFrm, + const SwRect& _rRect, + PrepareHint _eHint ) +{ + ::Notify_Background( GetDrawObj(), _pPageFrm, _rRect, _eHint, sal_True ); +} + +/** method to assure that anchored object is registered at the correct + page frame + + #i28701# + + @author OD +*/ +void SwAnchoredDrawObject::RegisterAtCorrectPage() +{ + SwPageFrm* pPageFrm( 0L ); + if ( GetVertPosOrientFrm() ) + { + pPageFrm = const_cast<SwPageFrm*>(GetVertPosOrientFrm()->FindPageFrm()); + } + if ( pPageFrm && GetPageFrm() != pPageFrm ) + { + if ( GetPageFrm() ) + GetPageFrm()->RemoveDrawObjFromPage( *this ); + pPageFrm->AppendDrawObjToPage( *this ); + } +} + +// ============================================================================= + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/anchoredobject.cxx b/sw/source/core/layout/anchoredobject.cxx new file mode 100644 index 000000000000..d33b6e009753 --- /dev/null +++ b/sw/source/core/layout/anchoredobject.cxx @@ -0,0 +1,1062 @@ +/* -*- 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 <anchoredobject.hxx> +#include <pam.hxx> +#include <frame.hxx> +#include <txtfrm.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +// --> #i28701# +#include <doc.hxx> +#include <fmtsrnd.hxx> +#include <svx/svdobj.hxx> +#include <dcontact.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <sortedobjs.hxx> +#include <pagefrm.hxx> +// <-- +#include <frmatr.hxx> +// --> #i3317# +#include <colfrm.hxx> +// <-- +// --> #i35911# +#include <layouter.hxx> + + +using namespace ::com::sun::star; + + +// <-- +// ============================================================================ +// --> #i28701# - +// implementation of helper class <SwObjPositioningInProgress> +// ============================================================================ +SwObjPositioningInProgress::SwObjPositioningInProgress( SdrObject& _rSdrObj ) : + mpAnchoredObj( 0L ), + // --> #i52904# + mbOldObjPositioningInProgress( false ) + // <-- +{ + mpAnchoredObj = ::GetUserCall( &_rSdrObj )->GetAnchoredObj( &_rSdrObj ); + // --> #i52904# + mbOldObjPositioningInProgress = mpAnchoredObj->IsPositioningInProgress(); + // <-- + mpAnchoredObj->SetPositioningInProgress( true ); +} +SwObjPositioningInProgress::SwObjPositioningInProgress( SwAnchoredObject& _rAnchoredObj ) : + mpAnchoredObj( &_rAnchoredObj ), + // --> #i52904# + mbOldObjPositioningInProgress( false ) + // <-- +{ + // --> #i52904# + mbOldObjPositioningInProgress = mpAnchoredObj->IsPositioningInProgress(); + // <-- + mpAnchoredObj->SetPositioningInProgress( true ); +} + +SwObjPositioningInProgress::~SwObjPositioningInProgress() +{ + if ( mpAnchoredObj ) + { + // --> #i52904# + mpAnchoredObj->SetPositioningInProgress( mbOldObjPositioningInProgress ); + // <-- + } +} + +// ============================================================================ + +TYPEINIT0(SwAnchoredObject); + +SwAnchoredObject::SwAnchoredObject() : + mpDrawObj( 0L ), + mpAnchorFrm( 0L ), + // --> #i28701# + mpPageFrm( 0L ), + // <-- + maRelPos(), + maLastCharRect(), + mnLastTopOfLine( 0L ), + mpVertPosOrientFrm( 0L ), + // --> #i28701# + mbPositioningInProgress( false ), + mbConsiderForTextWrap( false ), + mbPositionLocked( false ), + // --> #i40147# + mbKeepPositionLockedForSection( false ), + // <-- + mbRestartLayoutProcess( false ), + // <-- + // --> #i35911# + mbClearedEnvironment( false ), + // <-- + // --> #i3317# + mbTmpConsiderWrapInfluence( false ), + // <-- + // --> #i68520# + maObjRectWithSpaces(), + mbObjRectWithSpacesValid( false ), + maLastObjRect() + // <-- +{ +} + +SwAnchoredObject::~SwAnchoredObject() +{ +} + +// ============================================================================= +// accessors for member <mpDrawObj> +// ============================================================================= +void SwAnchoredObject::SetDrawObj( SdrObject& _rDrawObj ) +{ + mpDrawObj = &_rDrawObj; +} + +const SdrObject* SwAnchoredObject::GetDrawObj() const +{ + return mpDrawObj; +} + +SdrObject* SwAnchoredObject::DrawObj() +{ + return mpDrawObj; +} + +// ============================================================================= +// accessors for member <mpAnchorFrm> +// ============================================================================= +const SwFrm* SwAnchoredObject::GetAnchorFrm() const +{ + return mpAnchorFrm; +} + +SwFrm* SwAnchoredObject::AnchorFrm() +{ + return mpAnchorFrm; +} + +void SwAnchoredObject::ChgAnchorFrm( SwFrm* _pNewAnchorFrm ) +{ + mpAnchorFrm = _pNewAnchorFrm; + + if ( mpAnchorFrm ) + { + ObjectAttachedToAnchorFrame(); + } +} + +/** determine anchor frame containing the anchor position + + #i26945# + the anchor frame, which is determined, is <mpAnchorFrm> + for an at-page, at-frame or at-paragraph anchored object + and the anchor character frame for an at-character and as-character + anchored object. + + @author OD +*/ +SwFrm* SwAnchoredObject::GetAnchorFrmContainingAnchPos() +{ + SwFrm* pAnchorFrmContainingAnchPos = FindAnchorCharFrm(); + if ( !pAnchorFrmContainingAnchPos ) + { + pAnchorFrmContainingAnchPos = AnchorFrm(); + } + + return pAnchorFrmContainingAnchPos; +} + +// ============================================================================= +// #i28701# accessors for member <mpPageFrm> +// ============================================================================= +SwPageFrm* SwAnchoredObject::GetPageFrm() +{ + return mpPageFrm; +} + +const SwPageFrm* SwAnchoredObject::GetPageFrm() const +{ + return mpPageFrm; +} + +void SwAnchoredObject::SetPageFrm( SwPageFrm* _pNewPageFrm ) +{ + if ( mpPageFrm != _pNewPageFrm ) + { + // clear member, which denotes the layout frame at which the vertical + // position is oriented at, if it doesn't fit to the new page frame. + if ( GetVertPosOrientFrm() && + ( !_pNewPageFrm || + _pNewPageFrm != GetVertPosOrientFrm()->FindPageFrm() ) ) + { + ClearVertPosOrientFrm(); + } + + // assign new page frame + mpPageFrm = _pNewPageFrm; + } +} + +// ============================================================================= +// accessors for member <maLastCharRect> +// ============================================================================= +const SwRect& SwAnchoredObject::GetLastCharRect() const +{ + return maLastCharRect; +} + +SwTwips SwAnchoredObject::GetRelCharX( const SwFrm* pFrm ) const +{ + return maLastCharRect.Left() - pFrm->Frm().Left(); +} + +SwTwips SwAnchoredObject::GetRelCharY( const SwFrm* pFrm ) const +{ + return maLastCharRect.Bottom() - pFrm->Frm().Top(); +} + +void SwAnchoredObject::AddLastCharY( long nDiff ) +{ + maLastCharRect.Pos().Y() += nDiff; +} + +void SwAnchoredObject::ResetLastCharRectHeight() +{ + maLastCharRect.Height( 0 ); +} +// ============================================================================= +// accessors for member <mpVertPosOrientFrm> +// ============================================================================= +void SwAnchoredObject::SetVertPosOrientFrm( const SwLayoutFrm& _rVertPosOrientFrm ) +{ + mpVertPosOrientFrm = &_rVertPosOrientFrm; + + // --> OD 2004-07-02 #i28701# - take over functionality of deleted method + // <SwFlyAtCntFrm::AssertPage()>: assure for at-paragraph and at-character + // an anchored object, that it is registered at the correct page frame + RegisterAtCorrectPage(); +} + +// ============================================================================= +// accessors for member <mnLastTopOfLine> +// ============================================================================= +SwTwips SwAnchoredObject::GetLastTopOfLine() const +{ + return mnLastTopOfLine; +} + +// #i28701# - follow-up of #i22341# +void SwAnchoredObject::AddLastTopOfLineY( SwTwips _nDiff ) +{ + mnLastTopOfLine += _nDiff; +} + +/** check anchor character rectangle and top of line + + #i26791 + For to-character anchored Writer fly frames the members <maLastCharRect> + and <maLastTopOfLine> are updated. These are checked for change and + depending on the applied positioning, it's decided, if the Writer fly + frame has to be invalidated. + + add parameter <_bCheckForParaPorInf>, default value <true> + + @author OD +*/ +void SwAnchoredObject::CheckCharRectAndTopOfLine( + const bool _bCheckForParaPorInf ) +{ + if ( GetAnchorFrm() && + GetAnchorFrm()->IsTxtFrm() ) + { + const SwFmtAnchor& rAnch = GetFrmFmt().GetAnchor(); + if ( (rAnch.GetAnchorId() == FLY_AT_CHAR) && + rAnch.GetCntntAnchor() ) + { + // --> if requested, assure that anchor frame, + // which contains the anchor character, has a paragraph portion information. + // The paragraph portion information is needed to determine the + // anchor character rectangle respectively the top of the line. + // Thus, a format of this frame is avoided to determine the + // paragraph portion information. + // --> #i26945# - use new method <FindAnchorCharFrm()> + const SwTxtFrm& aAnchorCharFrm = *(FindAnchorCharFrm()); + // <-- + if ( !_bCheckForParaPorInf || aAnchorCharFrm.HasPara() ) + { + _CheckCharRect( rAnch, aAnchorCharFrm ); + _CheckTopOfLine( rAnch, aAnchorCharFrm ); + } + // <-- + } + } +} + +/** check anchor character rectangle + + #i22341# + helper method for method <CheckCharRectAndTopOfLine()> + For to-character anchored Writer fly frames the member <maLastCharRect> + is updated. This is checked for change and depending on the applied + positioning, it's decided, if the Writer fly frame has to be invalidated. + + improvement - add second parameter <_rAnchorCharFrm> + + @author OD +*/ +void SwAnchoredObject::_CheckCharRect( const SwFmtAnchor& _rAnch, + const SwTxtFrm& _rAnchorCharFrm ) +{ + // determine rectangle of anchor character. If not exist, abort operation + SwRect aCharRect; + if ( !_rAnchorCharFrm.GetAutoPos( aCharRect, *_rAnch.GetCntntAnchor() ) ) + { + return; + } + // check, if anchor character rectangle has changed + if ( aCharRect != maLastCharRect ) + { + // check positioning and alignment for invalidation of position + { + SWRECTFN( (&_rAnchorCharFrm) ); + // determine positioning and alignment + SwFmtVertOrient aVert( GetFrmFmt().GetVertOrient() ); + SwFmtHoriOrient aHori( GetFrmFmt().GetHoriOrient() ); + // check for anchor character rectangle changes for certain + // positionings and alignments + // add condition to invalidate position, + // if vertical aligned at frame/page area and vertical position + // of anchor character has changed. + const sal_Int16 eVertRelOrient = aVert.GetRelationOrient(); + if ( ( aHori.GetRelationOrient() == text::RelOrientation::CHAR && + (aCharRect.*fnRect->fnGetLeft)() != + (maLastCharRect.*fnRect->fnGetLeft)() ) || + ( eVertRelOrient == text::RelOrientation::CHAR && + ( (aCharRect.*fnRect->fnGetTop)() != + (maLastCharRect.*fnRect->fnGetTop)() || + (aCharRect.*fnRect->fnGetHeight)() != + (maLastCharRect.*fnRect->fnGetHeight)() ) ) || + ( ( ( eVertRelOrient == text::RelOrientation::FRAME ) || + ( eVertRelOrient == text::RelOrientation::PRINT_AREA ) || + ( eVertRelOrient == text::RelOrientation::PAGE_FRAME ) || + ( eVertRelOrient == text::RelOrientation::PAGE_PRINT_AREA ) ) && + ( (aCharRect.*fnRect->fnGetTop)() != + (maLastCharRect.*fnRect->fnGetTop)() ) ) ) + { + // --> #i26945#, #i35911# - unlock position of + // anchored object, if it isn't registered at the page, + // where its anchor character frame is on. + if ( GetPageFrm() != _rAnchorCharFrm.FindPageFrm() ) + { + UnlockPosition(); + } + // <-- + InvalidateObjPos(); + } + } + // keep new anchor character rectangle + maLastCharRect = aCharRect; + } +} + +/** check top of line + + #i22341# + helper method for method <CheckCharRectAndTopOfLine()> + For to-character anchored Writer fly frames the member <mnLastTopOfLine> + is updated. This is checked for change and depending on the applied + positioning, it's decided, if the Writer fly frame has to be invalidated. + + improvement - add second parameter <_rAnchorCharFrm> + + @author OD +*/ +void SwAnchoredObject::_CheckTopOfLine( const SwFmtAnchor& _rAnch, + const SwTxtFrm& _rAnchorCharFrm ) +{ + SwTwips nTopOfLine = 0L; + if ( _rAnchorCharFrm.GetTopOfLine( nTopOfLine, *_rAnch.GetCntntAnchor() ) ) + { + if ( nTopOfLine != mnLastTopOfLine ) + { + // check alignment for invalidation of position + if ( GetFrmFmt().GetVertOrient().GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + // --> #i26945#, #i35911# - unlock position of + // anchored object, if it isn't registered at the page, + // where its anchor character frame is on. + if ( GetPageFrm() != _rAnchorCharFrm.FindPageFrm() ) + { + UnlockPosition(); + } + // <-- + InvalidateObjPos(); + } + // keep new top of line value + mnLastTopOfLine = nTopOfLine; + } + } +} + +void SwAnchoredObject::ClearCharRectAndTopOfLine() +{ + maLastCharRect.Clear(); + mnLastTopOfLine = 0; +} + +const Point SwAnchoredObject::GetCurrRelPos() const +{ + return maRelPos; +} +void SwAnchoredObject::SetCurrRelPos( Point _aRelPos ) +{ + maRelPos = _aRelPos; +} + +void SwAnchoredObject::ObjectAttachedToAnchorFrame() +{ + // default behaviour: + // update layout direction, the anchored object is assigned to + UpdateLayoutDir(); +} + +/** method update layout direction the layout direction, the anchored + object is in + + #i31698# + method has typically to be called, if the anchored object gets its + anchor frame assigned. + + @author OD +*/ +void SwAnchoredObject::UpdateLayoutDir() +{ + SwFrmFmt::tLayoutDir nLayoutDir = SwFrmFmt::HORI_L2R; + const SwFrm* pAnchorFrm = GetAnchorFrm(); + if ( pAnchorFrm ) + { + const bool bVert = pAnchorFrm->IsVertical(); + const bool bR2L = pAnchorFrm->IsRightToLeft(); + if ( bVert ) + { + nLayoutDir = SwFrmFmt::VERT_R2L; + } + else if ( bR2L ) + { + nLayoutDir = SwFrmFmt::HORI_R2L; + } + } + GetFrmFmt().SetLayoutDir( nLayoutDir ); +} + +/** method to perform necessary invalidations for the positioning of + objects, for whose the wrapping style influence has to be considered + on the object positioning. + + #i28701# + + @author OD +*/ +void SwAnchoredObject::InvalidateObjPosForConsiderWrapInfluence( + const bool _bNotifyBackgrd ) +{ + if ( ConsiderObjWrapInfluenceOnObjPos() ) + { + // indicate that object has not to be considered for text wrap + SetConsiderForTextWrap( false ); + // unlock position + UnlockPosition(); + // invalidate position + InvalidateObjPos(); + // invalidate 'background', if requested + if ( _bNotifyBackgrd ) + { + NotifyBackground( GetPageFrm(), GetObjRectWithSpaces(), PREP_FLY_LEAVE ); + } + } +} + +/** method to determine, if wrapping style influence of the anchored + object has to be considered on the object positioning + + #i28701# + Note: result of this method also decides, if the booleans for the + layout process are of relevance. + + @author OD +*/ +bool SwAnchoredObject::ConsiderObjWrapInfluenceOnObjPos() const +{ + bool bRet( false ); + + const SwFrmFmt& rObjFmt = GetFrmFmt(); + + // --> #i3317# - add condition <IsTmpConsiderWrapInfluence()> + // --> #i55204# + // - correction: wrapping style influence has been considered, if condition + // <IsTmpConsiderWrapInfluence()> is hold, regardless of its anchor type + // or its wrapping style. + if ( IsTmpConsiderWrapInfluence() ) + { + bRet = true; + } + else if ( rObjFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + // <-- + { + const SwFmtAnchor& rAnchor = rObjFmt.GetAnchor(); + if ( ((rAnchor.GetAnchorId() == FLY_AT_CHAR) || + (rAnchor.GetAnchorId() == FLY_AT_PARA)) && + rObjFmt.GetSurround().GetSurround() != SURROUND_THROUGHT ) + { + // --> #i34520# - text also wraps around anchored + // objects in the layer Hell - see the text formatting. + // Thus, it hasn't to be checked here. + bRet = true; + // <-- + } + } + + return bRet; +} + +/** method to determine, if other anchored objects, also attached at + to the anchor frame, have to consider its wrap influence. + + // --> #i43255# + + @author OD +*/ +bool SwAnchoredObject::ConsiderObjWrapInfluenceOfOtherObjs() const +{ + bool bRet( false ); + + const SwSortedObjs* pObjs = GetAnchorFrm()->GetDrawObjs(); + if ( pObjs->Count() > 1 ) + { + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj != this && + pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() ) + { + bRet = true; + break; + } + } + } + + return bRet; +} + +// ============================================================================= +// --> #i28701# - accessors to booleans for layout process +// ============================================================================= +bool SwAnchoredObject::ConsiderForTextWrap() const +{ + if ( ConsiderObjWrapInfluenceOnObjPos() ) + return mbConsiderForTextWrap; + else + return true; +} + +void SwAnchoredObject::SetConsiderForTextWrap( const bool _bConsiderForTextWrap ) +{ + mbConsiderForTextWrap = _bConsiderForTextWrap; +} + +bool SwAnchoredObject::PositionLocked() const +{ + if ( ConsiderObjWrapInfluenceOnObjPos() ) + return mbPositionLocked; + else + return false; +} + +bool SwAnchoredObject::RestartLayoutProcess() const +{ + if ( ConsiderObjWrapInfluenceOnObjPos() ) + return mbRestartLayoutProcess; + else + return false; +} + +void SwAnchoredObject::SetRestartLayoutProcess( const bool _bRestartLayoutProcess ) +{ + mbRestartLayoutProcess = _bRestartLayoutProcess; +} + +// --> #i35911# +bool SwAnchoredObject::ClearedEnvironment() const +{ + if ( ConsiderObjWrapInfluenceOnObjPos() ) + return mbClearedEnvironment; + else + return false; +} +void SwAnchoredObject::SetClearedEnvironment( const bool _bClearedEnvironment ) +{ + mbClearedEnvironment = _bClearedEnvironment; +} +// <-- + +/** method to determine, if due to anchored object size and wrapping + style, its layout environment is cleared. + + #i35911# + + @author OD +*/ +bool SwAnchoredObject::HasClearedEnvironment() const +{ + bool bHasClearedEnvironment( false ); + + // --> #i43913# - layout frame, vertical position is orient at, has to be set. + OSL_ENSURE( GetVertPosOrientFrm(), + "<SwAnchoredObject::HasClearedEnvironment()> - layout frame missing, at which the vertical position is oriented at." ); + if ( GetVertPosOrientFrm() && + GetAnchorFrm()->IsTxtFrm() && + !static_cast<const SwTxtFrm*>(GetAnchorFrm())->IsFollow() && + static_cast<const SwTxtFrm*>(GetAnchorFrm())->FindPageFrm()->GetPhyPageNum() >= + GetPageFrm()->GetPhyPageNum() ) + // <-- + { + const SwFrm* pTmpFrm = GetVertPosOrientFrm()->Lower(); + while ( pTmpFrm && pTmpFrm->IsLayoutFrm() && !pTmpFrm->IsTabFrm() ) + { + pTmpFrm = static_cast<const SwLayoutFrm*>(pTmpFrm)->Lower(); + } + if ( !pTmpFrm ) + { + bHasClearedEnvironment = true; + } + else if ( pTmpFrm->IsTxtFrm() && !pTmpFrm->GetNext() ) + { + const SwTxtFrm* pTmpTxtFrm = static_cast<const SwTxtFrm*>(pTmpFrm); + if ( pTmpTxtFrm->IsUndersized() || + ( pTmpTxtFrm->GetFollow() && + pTmpTxtFrm->GetFollow()->GetOfst() == 0 ) ) + { + bHasClearedEnvironment = true; + } + } + } + + return bHasClearedEnvironment; +} + +/** method to add spacing to object area + + #i28701# + #i68520# - return constant reference and use cache + + @author OD +*/ +const SwRect& SwAnchoredObject::GetObjRectWithSpaces() const +{ + if ( mbObjRectWithSpacesValid && + maLastObjRect != GetObjRect() ) + { + OSL_FAIL( "<SwAnchoredObject::GetObjRectWithSpaces> - cache for object rectangle inclusive spaces marked as valid, but it couldn't be. Missing invalidation of cache. Please inform OD." ); + InvalidateObjRectWithSpaces(); + } + if ( !mbObjRectWithSpacesValid ) + { + // --> #i70122# - correction: + // use bounding rectangle of anchored objects. +// maObjRectWithSpaces = GetObjRect(); + maObjRectWithSpaces = GetObjBoundRect(); + // <-- + const SwFrmFmt& rFmt = GetFrmFmt(); + const SvxULSpaceItem& rUL = rFmt.GetULSpace(); + const SvxLRSpaceItem& rLR = rFmt.GetLRSpace(); + { + maObjRectWithSpaces.Top ( Max( maObjRectWithSpaces.Top() - long(rUL.GetUpper()), 0L )); + maObjRectWithSpaces.Left( Max( maObjRectWithSpaces.Left()- long(rLR.GetLeft()), 0L )); + maObjRectWithSpaces.SSize().Height() += rUL.GetLower(); + maObjRectWithSpaces.SSize().Width() += rLR.GetRight(); + } + + mbObjRectWithSpacesValid = true; + maLastObjRect = GetObjRect(); + } + + return maObjRectWithSpaces; +} + +// --> #i68520# +void SwAnchoredObject::SetObjTop( const SwTwips _nTop) +{ + const bool bTopChanged( _SetObjTop( _nTop ) ); + if ( bTopChanged ) + { + mbObjRectWithSpacesValid = false; + } +} + +void SwAnchoredObject::SetObjLeft( const SwTwips _nLeft) +{ + const bool bLeftChanged( _SetObjLeft( _nLeft ) ); + if ( bLeftChanged ) + { + mbObjRectWithSpacesValid = false; + } +} +// <-- + +/** method to update anchored object in the <SwSortedObjs> lists + + #i28701# + If document compatibility option 'Consider wrapping style influence + on object positioning' is ON, additionally all anchored objects + at the anchor frame and all following anchored objects on the page + frame are invalidated. + + @author OD +*/ +void SwAnchoredObject::UpdateObjInSortedList() +{ + if ( GetAnchorFrm() ) + { + if ( GetFrmFmt().getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + // invalidate position of all anchored objects at anchor frame + if ( GetAnchorFrm()->GetDrawObjs() ) + { + const SwSortedObjs* pObjs = GetAnchorFrm()->GetDrawObjs(); + // determine start index + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() ) + pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence( true ); + else + pAnchoredObj->InvalidateObjPos(); + } + } + // invalidate all following anchored objects on the page frame + if ( GetPageFrm() && GetPageFrm()->GetSortedObjs() ) + { + const SwSortedObjs* pObjs = GetPageFrm()->GetSortedObjs(); + // determine start index + sal_uInt32 i = pObjs->ListPosOf( *this ) + 1; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() ) + pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence( true ); + else + pAnchoredObj->InvalidateObjPos(); + } + } + } + // update its position in the sorted object list of its anchor frame + AnchorFrm()->GetDrawObjs()->Update( *this ); + // update its position in the sorted object list of its page frame + // note: as-character anchored object aren't registered at a page frame + if ( GetFrmFmt().GetAnchor().GetAnchorId() != FLY_AS_CHAR ) + { + GetPageFrm()->GetSortedObjs()->Update( *this ); + } + } +} + +/** method to determine, if invalidation of position is allowed + + #i28701# + + @author OD +*/ +bool SwAnchoredObject::InvalidationOfPosAllowed() const +{ + // --> Check, if page frame layout is in progress, + // isn't needed, because of anchored object, whose are moved forward. + return !PositionLocked(); + // <-- +} + +/** method to determine the page frame, on which the 'anchor' of + the given anchored object is. + + #i28701# + #i33751#, #i34060# + Adjust meaning of method and thus its name: If the anchored object + or its anchor isn't correctly inserted in the layout, no page frame + can be found. Thus, the return type changed to be a pointer and can + be NULL. + + @author OD +*/ +SwPageFrm* SwAnchoredObject::FindPageFrmOfAnchor() +{ + SwPageFrm* pRetPageFrm = 0L; + + // --> #i44339# - check, if anchor frame exists. + if ( mpAnchorFrm ) + { + // --> #i26945# - use new method <GetAnchorFrmContainingAnchPos()> + pRetPageFrm = GetAnchorFrmContainingAnchPos()->FindPageFrm(); + // <-- + } + + return pRetPageFrm; +} + +/** get frame, which contains the anchor character, if the object + is anchored at-character or as-character. + + #i26945# + + @author OD + + @return SwTxtFrm* + text frame containing the anchor character. It's NULL, if the object + isn't anchored at-character resp. as-character. +*/ +SwTxtFrm* SwAnchoredObject::FindAnchorCharFrm() +{ + SwTxtFrm* pAnchorCharFrm( 0L ); + + // --> #i44339# - check, if anchor frame exists. + if ( mpAnchorFrm ) + { + const SwFmtAnchor& rAnch = GetFrmFmt().GetAnchor(); + if ((rAnch.GetAnchorId() == FLY_AT_CHAR) || + (rAnch.GetAnchorId() == FLY_AS_CHAR)) + { + pAnchorCharFrm = &(static_cast<SwTxtFrm*>(AnchorFrm())-> + GetFrmAtOfst( rAnch.GetCntntAnchor()->nContent.GetIndex() )); + } + } + // <-- + + return pAnchorCharFrm; +} + +/** method to determine, if a format on the anchored object is possible + + #i28701# + A format is possible, if anchored object is in an invisible layer. + Note: method is virtual to refine the conditions for the sub-classes. + + @author OD +*/ +bool SwAnchoredObject::IsFormatPossible() const +{ + return GetFrmFmt().GetDoc()->IsVisibleLayerId( GetDrawObj()->GetLayer() ); +} + +// --> #i3317# +void SwAnchoredObject::SetTmpConsiderWrapInfluence( const bool _bTmpConsiderWrapInfluence ) +{ + mbTmpConsiderWrapInfluence = _bTmpConsiderWrapInfluence; + // --> #i35911# + if ( mbTmpConsiderWrapInfluence ) + { + SwLayouter::InsertObjForTmpConsiderWrapInfluence( *(GetFrmFmt().GetDoc()), + *this ); + } + // <-- +} + +bool SwAnchoredObject::IsTmpConsiderWrapInfluence() const +{ + return mbTmpConsiderWrapInfluence; +} +// <-- + +void SwAnchoredObject::SetTmpConsiderWrapInfluenceOfOtherObjs( const bool bTmpConsiderWrapInfluence ) +{ + const SwSortedObjs* pObjs = GetAnchorFrm()->GetDrawObjs(); + if ( pObjs->Count() > 1 ) + { + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj != this ) + { + pAnchoredObj->SetTmpConsiderWrapInfluence( bTmpConsiderWrapInfluence ); + } + } + } +} + +/** method to determine, if the anchored object is overlapping with a + previous column + + #i3317# + overlapping with a previous column means, that the object overlaps + with a column, which is a previous one of the column its anchor + frame is in. + Only applied for at-paragraph and at-character anchored objects. + + @author OD +*/ +bool SwAnchoredObject::OverlapsPrevColumn() const +{ + bool bOverlapsPrevColumn( false ); + + if ( mpAnchorFrm && mpAnchorFrm->IsTxtFrm() ) + { + const SwFrm* pColFrm = mpAnchorFrm->FindColFrm(); + if ( pColFrm && pColFrm->GetPrev() ) + { + const SwFrm* pTmpColFrm = pColFrm->GetPrev(); + SwRect aChkRect; + while ( pTmpColFrm ) + { + aChkRect.Union( pTmpColFrm->Frm() ); + pTmpColFrm = pTmpColFrm->GetPrev(); + } + bOverlapsPrevColumn = GetObjRect().IsOver( aChkRect ); + } + } + + return bOverlapsPrevColumn; +} + +/** method to determine position of anchored object relative to + anchor frame + + #i30669# + Usage: Needed layout information for WW8 export + + @author OD +*/ +Point SwAnchoredObject::GetRelPosToAnchorFrm() const +{ + Point aRelPos; + + OSL_ENSURE( GetAnchorFrm(), + "<SwAnchoredObject::GetRelPosToAnchorFrm()> - missing anchor frame." ); + aRelPos = GetObjRect().Pos(); + aRelPos -= GetAnchorFrm()->Frm().Pos(); + + return aRelPos; +} + +/** method to determine position of anchored object relative to + page frame + + #i30669# + Usage: Needed layout information for WW8 export + #i33818# - add parameters <_bFollowTextFlow> and + <_obRelToTableCell> + If <_bFollowTextFlow> is set and object is anchored inside table, + the position relative to the table cell is determined. Output + parameter <_obRelToTableCell> reflects this situation + + @author OD +*/ +Point SwAnchoredObject::GetRelPosToPageFrm( const bool _bFollowTextFlow, + bool& _obRelToTableCell ) const +{ + Point aRelPos; + _obRelToTableCell = false; + + OSL_ENSURE( GetAnchorFrm(), + "<SwAnchoredObject::GetRelPosToPageFrm()> - missing anchor frame." ); + OSL_ENSURE( GetAnchorFrm()->FindPageFrm(), + "<SwAnchoredObject::GetRelPosToPageFrm()> - missing page frame." ); + + aRelPos = GetObjRect().Pos(); + // --> #i33818# - search for cell frame, if object has to + // follow the text flow. + const SwFrm* pFrm( 0L ); + if ( _bFollowTextFlow && !GetAnchorFrm()->IsPageFrm() ) + { + pFrm = GetAnchorFrm()->GetUpper(); + while ( !pFrm->IsCellFrm() && !pFrm->IsPageFrm() ) + { + pFrm = pFrm->GetUpper(); + } + } + else + { + pFrm = GetAnchorFrm()->FindPageFrm(); + } + if ( pFrm->IsCellFrm() ) + { + aRelPos -= ( pFrm->Frm().Pos() + pFrm->Prt().Pos() ); + _obRelToTableCell = true; + } + else + { + aRelPos -= pFrm->Frm().Pos(); + } + // <-- + + return aRelPos; +} + +/** method to determine position of anchored object relative to + anchor character + + #i30669# + Usage: Needed layout information for WW8 export + + @author OD +*/ +Point SwAnchoredObject::GetRelPosToChar() const +{ + Point aRelPos; + + aRelPos = GetObjRect().Pos(); + aRelPos -= GetLastCharRect().Pos(); + + return aRelPos; +} + +/** method to determine position of anchored object relative to + top of line + + #i30669# + Usage: Needed layout information for WW8 export + + @author OD +*/ +Point SwAnchoredObject::GetRelPosToLine() const +{ + Point aRelPos; + + aRelPos = GetObjRect().Pos(); + aRelPos.Y() -= GetLastTopOfLine(); + + return aRelPos; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx new file mode 100644 index 000000000000..5d3c7924531e --- /dev/null +++ b/sw/source/core/layout/atrfrm.cxx @@ -0,0 +1,3299 @@ +/* -*- 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 <com/sun/star/text/RelOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/HorizontalAdjust.hpp> +#include <com/sun/star/text/DocumentStatistic.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/HoriOrientationFormat.hpp> +#include <com/sun/star/text/NotePrintMode.hpp> +#include <com/sun/star/text/SizeType.hpp> +#include <com/sun/star/text/VertOrientationFormat.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/text/XTextFrame.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/text/InvalidTextContentException.hpp> +#include <com/sun/star/container/XIndexContainer.hpp> +#include <com/sun/star/text/TextGridMode.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <svtools/unoimap.hxx> +#include <svtools/unoevent.hxx> +#include <basic/sbxvar.hxx> +#include <svtools/imap.hxx> +#include <svtools/imapobj.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> +#include <unosett.hxx> +#include <unostyle.hxx> +#include <fmtclds.hxx> +#include <fmtornt.hxx> +#include <fmthdft.hxx> +#include <fmtpdsc.hxx> +#include <fmtcntnt.hxx> +#include <fmtfsize.hxx> +#include <fmtfordr.hxx> +#include <fmtsrnd.hxx> +#include <fmtanchr.hxx> +#include <fmtlsplt.hxx> +#include <fmtrowsplt.hxx> +#include <fmtftntx.hxx> +#include <fmteiro.hxx> +#include <fmturl.hxx> +#include <fmtcnct.hxx> +#include <node.hxx> +#include <section.hxx> +#include <fmtline.hxx> +#include <tgrditem.hxx> +#include <hfspacingitem.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <crsrsh.hxx> +#include <pam.hxx> +#include <dflyobj.hxx> +#include <dcontact.hxx> +#include <flyfrm.hxx> +#include <frmtool.hxx> +#include <flyfrms.hxx> +#include <pagedesc.hxx> +#include <grfatr.hxx> +#include <ndnotxt.hxx> +#include <docary.hxx> +#include <node2lay.hxx> +#include <fmtclbl.hxx> +#include <swunohelper.hxx> +#include <unoframe.hxx> +#include <unotextbodyhf.hxx> +#include <SwStyleNameMapper.hxx> +#include <editeng/brshitem.hxx> +#include <svtools/grfmgr.hxx> +#include <cmdid.h> +#include <unomid.h> +#include <comcore.hrc> +#include <svx/svdundo.hxx> // #111827# +#include <sortedobjs.hxx> +#include <HandleAnchorNodeChg.hxx> +#include <svl/cjkoptions.hxx> +#include <switerator.hxx> +#include <pagedeschint.hxx> + +using namespace ::com::sun::star; +using ::rtl::OUString; + +SV_IMPL_PTRARR(SwColumns,SwColumn*) + +TYPEINIT1(SwFmtVertOrient, SfxPoolItem); +TYPEINIT1(SwFmtHoriOrient, SfxPoolItem); +TYPEINIT2(SwFmtHeader, SfxPoolItem, SwClient ); +TYPEINIT2(SwFmtFooter, SfxPoolItem, SwClient ); +TYPEINIT2(SwFmtPageDesc, SfxPoolItem, SwClient ); +TYPEINIT1_AUTOFACTORY(SwFmtLineNumber, SfxPoolItem); + +/* -------------------------------------------------- + * Umwandlung fuer QueryValue + * --------------------------------------------------*/ +sal_Int16 lcl_RelToINT(sal_Int16 eRelation) +{ + sal_Int16 nRet = text::RelOrientation::FRAME; + switch(eRelation) + { + case text::RelOrientation::PRINT_AREA: nRet = text::RelOrientation::PRINT_AREA; break; + case text::RelOrientation::CHAR: nRet = text::RelOrientation::CHAR; break; + case text::RelOrientation::PAGE_LEFT: nRet = text::RelOrientation::PAGE_LEFT; break; + case text::RelOrientation::PAGE_RIGHT: nRet = text::RelOrientation::PAGE_RIGHT; break; + case text::RelOrientation::FRAME_LEFT: nRet = text::RelOrientation::FRAME_LEFT; break; + case text::RelOrientation::FRAME_RIGHT: nRet = text::RelOrientation::FRAME_RIGHT; break; + case text::RelOrientation::PAGE_FRAME: nRet = text::RelOrientation::PAGE_FRAME; break; + case text::RelOrientation::PAGE_PRINT_AREA: nRet = text::RelOrientation::PAGE_PRINT_AREA; break; + // OD 13.11.2003 #i22341# + case text::RelOrientation::TEXT_LINE: nRet = text::RelOrientation::TEXT_LINE; break; + default: break; + } + return nRet; +} + +sal_Int16 lcl_IntToRelation(const uno::Any& rVal) +{ + sal_Int16 eRet = text::RelOrientation::FRAME; + sal_Int16 nVal = 0; + rVal >>= nVal; + switch(nVal) + { + case text::RelOrientation::PRINT_AREA: eRet = text::RelOrientation::PRINT_AREA ; break; + case text::RelOrientation::CHAR: eRet = text::RelOrientation::CHAR ; break; + case text::RelOrientation::PAGE_LEFT: eRet = text::RelOrientation::PAGE_LEFT ; break; + case text::RelOrientation::PAGE_RIGHT: eRet = text::RelOrientation::PAGE_RIGHT ; break; + case text::RelOrientation::FRAME_LEFT: eRet = text::RelOrientation::FRAME_LEFT ; break; + case text::RelOrientation::FRAME_RIGHT: eRet = text::RelOrientation::FRAME_RIGHT ; break; + case text::RelOrientation::PAGE_FRAME: eRet = text::RelOrientation::PAGE_FRAME ; break; + case text::RelOrientation::PAGE_PRINT_AREA: eRet = text::RelOrientation::PAGE_PRINT_AREA ; break; + // OD 13.11.2003 #i22341# + case text::RelOrientation::TEXT_LINE: eRet = text::RelOrientation::TEXT_LINE; break; + } + return eRet; +} + +void DelHFFormat( SwClient *pToRemove, SwFrmFmt *pFmt ) +{ + //Wenn der Client der letzte ist der das Format benutzt, so muss dieses + //vernichtet werden. Zuvor muss jedoch ggf. die Inhaltssection vernichtet + //werden. + SwDoc* pDoc = pFmt->GetDoc(); + pFmt->Remove( pToRemove ); + if( pDoc->IsInDtor() ) + { + delete pFmt; + return; + } + + //Nur noch Frms angemeldet? + sal_Bool bDel = sal_True; + { + // Klammer, weil im DTOR SwClientIter das Flag bTreeChg zurueck + // gesetzt wird. Unguenstig, wenn das Format vorher zerstoert wird. + SwClientIter aIter( *pFmt ); // TODO + SwClient *pLast = aIter.GoStart(); + if( pLast ) + do { + bDel = pLast->IsA( TYPE(SwFrm) ) + || SwXHeadFootText::IsXHeadFootText(pLast); + } while( bDel && 0 != ( pLast = aIter++ )); + } + + if ( bDel ) + { + //Wenn in einem der Nodes noch ein Crsr angemeldet ist, muss das + //ParkCrsr einer (beliebigen) Shell gerufen werden. + SwFmtCntnt& rCnt = (SwFmtCntnt&)pFmt->GetCntnt(); + if ( rCnt.GetCntntIdx() ) + { + SwNode *pNode = 0; + { + // --> OD 2008-10-07 #i92993# + // Begin with start node of page header/footer to assure that + // complete content is checked for cursors and the complete content + // is deleted on below made method call <pDoc->DeleteSection(pNode)> +// SwNodeIndex aIdx( *rCnt.GetCntntIdx(), 1 ); + SwNodeIndex aIdx( *rCnt.GetCntntIdx(), 0 ); + // <-- + //Wenn in einem der Nodes noch ein Crsr angemeldet ist, muss das + //ParkCrsr einer (beliebigen) Shell gerufen werden. + pNode = & aIdx.GetNode(); + sal_uInt32 nEnd = pNode->EndOfSectionIndex(); + while ( aIdx < nEnd ) + { + if ( pNode->IsCntntNode() && + ((SwCntntNode*)pNode)->GetDepends() ) + { + SwCrsrShell *pShell = SwIterator<SwCrsrShell,SwCntntNode>::FirstElement( *(SwCntntNode*)pNode ); + if( pShell ) + { + pShell->ParkCrsr( aIdx ); + aIdx = nEnd-1; + } + } + aIdx++; + pNode = & aIdx.GetNode(); + } + } + rCnt.SetNewCntntIdx( (const SwNodeIndex*)0 ); + + // beim Loeschen von Header/Footer-Formaten IMMER das Undo + // abschalten! (Bug 31069) + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + OSL_ENSURE( pNode, "Ein grosses Problem." ); + pDoc->DeleteSection( pNode ); + } + delete pFmt; + } +} + +// class SwFmtFrmSize +// Implementierung teilweise inline im hxx + +SwFmtFrmSize::SwFmtFrmSize( SwFrmSize eSize, SwTwips nWidth, SwTwips nHeight ) + : SfxPoolItem( RES_FRM_SIZE ), + aSize( nWidth, nHeight ), + eFrmHeightType( eSize ), + eFrmWidthType( ATT_FIX_SIZE ) +{ + nWidthPercent = nHeightPercent = 0; +} + +SwFmtFrmSize& SwFmtFrmSize::operator=( const SwFmtFrmSize& rCpy ) +{ + aSize = rCpy.GetSize(); + eFrmHeightType = rCpy.GetHeightSizeType(); + eFrmWidthType = rCpy.GetWidthSizeType(); + nHeightPercent = rCpy.GetHeightPercent(); + nWidthPercent = rCpy.GetWidthPercent(); + return *this; +} + +int SwFmtFrmSize::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return( eFrmHeightType == ((SwFmtFrmSize&)rAttr).eFrmHeightType && + eFrmWidthType == ((SwFmtFrmSize&)rAttr).eFrmWidthType && + aSize == ((SwFmtFrmSize&)rAttr).GetSize()&& + nWidthPercent == ((SwFmtFrmSize&)rAttr).GetWidthPercent() && + nHeightPercent == ((SwFmtFrmSize&)rAttr).GetHeightPercent() ); +} + +SfxPoolItem* SwFmtFrmSize::Clone( SfxItemPool* ) const +{ + return new SwFmtFrmSize( *this ); +} + +bool SwFmtFrmSize::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case MID_FRMSIZE_SIZE: + { + awt::Size aTmp; + aTmp.Height = TWIP_TO_MM100(aSize.Height()); + aTmp.Width = TWIP_TO_MM100(aSize.Width()); + rVal.setValue(&aTmp, ::getCppuType((const awt::Size*)0)); + } + break; + case MID_FRMSIZE_REL_HEIGHT: + rVal <<= (sal_Int16)(GetHeightPercent() != 0xFF ? GetHeightPercent() : 0); + break; + case MID_FRMSIZE_REL_WIDTH: + rVal <<= (sal_Int16)(GetWidthPercent() != 0xFF ? GetWidthPercent() : 0); + break; + case MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH: + { + sal_Bool bTmp = 0xFF == GetHeightPercent(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT: + { + sal_Bool bTmp = 0xFF == GetWidthPercent(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_FRMSIZE_WIDTH : + rVal <<= (sal_Int32)TWIP_TO_MM100(aSize.Width()); + break; + case MID_FRMSIZE_HEIGHT: + // #95848# returned size should never be zero. + // (there was a bug that allowed for setting height to 0. + // Thus there some documents existing with that not allowed + // attribut value which may cause problems on import.) + rVal <<= (sal_Int32)TWIP_TO_MM100(aSize.Height() < MINLAY ? MINLAY : aSize.Height() ); + break; + case MID_FRMSIZE_SIZE_TYPE: + rVal <<= (sal_Int16)GetHeightSizeType(); + break; + case MID_FRMSIZE_IS_AUTO_HEIGHT: + { + sal_Bool bTmp = ATT_FIX_SIZE != GetHeightSizeType(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_FRMSIZE_WIDTH_TYPE: + rVal <<= (sal_Int16)GetWidthSizeType(); + break; + } + return true; +} + +bool SwFmtFrmSize::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + sal_Bool bConvert = 0 != (nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_FRMSIZE_SIZE: + { + awt::Size aVal; + if(!(rVal >>= aVal)) + bRet = false; + else + { + Size aTmp(aVal.Width, aVal.Height); + if(bConvert) + { + aTmp.Height() = MM100_TO_TWIP(aTmp.Height()); + aTmp.Width() = MM100_TO_TWIP(aTmp.Width()); + } + if(aTmp.Height() && aTmp.Width()) + aSize = aTmp; + else + bRet = false; + } + } + break; + case MID_FRMSIZE_REL_HEIGHT: + { + sal_Int16 nSet = 0; + rVal >>= nSet; + if(nSet >= 0 && nSet <= 0xfe) + SetHeightPercent((sal_uInt8)nSet); + else + bRet = false; + } + break; + case MID_FRMSIZE_REL_WIDTH: + { + sal_Int16 nSet = 0; + rVal >>= nSet; + if(nSet >= 0 && nSet <= 0xfe) + SetWidthPercent((sal_uInt8)nSet); + else + bRet = false; + } + break; + case MID_FRMSIZE_IS_SYNC_HEIGHT_TO_WIDTH: + { + sal_Bool bSet = *(sal_Bool*)rVal.getValue(); + if(bSet) + SetHeightPercent(0xff); + else if( 0xff == GetHeightPercent() ) + SetHeightPercent( 0 ); + } + break; + case MID_FRMSIZE_IS_SYNC_WIDTH_TO_HEIGHT: + { + sal_Bool bSet = *(sal_Bool*)rVal.getValue(); + if(bSet) + SetWidthPercent(0xff); + else if( 0xff == GetWidthPercent() ) + SetWidthPercent(0); + } + break; + case MID_FRMSIZE_WIDTH : + { + sal_Int32 nWd = 0; + if(rVal >>= nWd) + { + if(bConvert) + nWd = MM100_TO_TWIP(nWd); + if(nWd < MINLAY) + nWd = MINLAY; + aSize.Width() = nWd; + } + else + bRet = sal_False; + } + break; + case MID_FRMSIZE_HEIGHT: + { + sal_Int32 nHg = 0; + if(rVal >>= nHg) + { + if(bConvert) + nHg = MM100_TO_TWIP(nHg); + if(nHg < MINLAY) + nHg = MINLAY; + aSize.Height() = nHg; + } + else + bRet = false; + } + break; + case MID_FRMSIZE_SIZE_TYPE: + { + sal_Int16 nType = 0; + if((rVal >>= nType) && nType >= 0 && nType <= ATT_MIN_SIZE ) + { + SetHeightSizeType((SwFrmSize)nType); + } + else + bRet = false; + } + break; + case MID_FRMSIZE_IS_AUTO_HEIGHT: + { + sal_Bool bSet = *(sal_Bool*)rVal.getValue(); + SetHeightSizeType(bSet ? ATT_VAR_SIZE : ATT_FIX_SIZE); + } + break; + case MID_FRMSIZE_WIDTH_TYPE: + { + sal_Int16 nType = 0; + if((rVal >>= nType) && nType >= 0 && nType <= ATT_MIN_SIZE ) + { + SetWidthSizeType((SwFrmSize)nType); + } + else + bRet = false; + } + break; + default: + bRet = false; + } + return bRet; +} + +// class SwFmtFillOrder +// Implementierung teilweise inline im hxx + +SwFmtFillOrder::SwFmtFillOrder( SwFillOrder nFO ) + : SfxEnumItem( RES_FILL_ORDER, sal_uInt16(nFO) ) +{} + +SfxPoolItem* SwFmtFillOrder::Clone( SfxItemPool* ) const +{ + return new SwFmtFillOrder( GetFillOrder() ); +} + +sal_uInt16 SwFmtFillOrder::GetValueCount() const +{ + return SW_FILL_ORDER_END - SW_FILL_ORDER_BEGIN; +} + +// class SwFmtHeader +// Implementierung teilweise inline im hxx + +SwFmtHeader::SwFmtHeader( SwFrmFmt *pHeaderFmt ) + : SfxPoolItem( RES_HEADER ), + SwClient( pHeaderFmt ), + bActive( pHeaderFmt ? sal_True : sal_False ) +{ +} + +SwFmtHeader::SwFmtHeader( const SwFmtHeader &rCpy ) + : SfxPoolItem( RES_HEADER ), + SwClient( (SwModify*)rCpy.GetRegisteredIn() ), + bActive( rCpy.IsActive() ) +{ +} + +SwFmtHeader::SwFmtHeader( sal_Bool bOn ) + : SfxPoolItem( RES_HEADER ), + SwClient( 0 ), + bActive( bOn ) +{ +} + + SwFmtHeader::~SwFmtHeader() +{ + if ( GetHeaderFmt() ) + DelHFFormat( this, GetHeaderFmt() ); +} + +int SwFmtHeader::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( GetRegisteredIn() == ((SwFmtHeader&)rAttr).GetRegisteredIn() && + bActive == ((SwFmtHeader&)rAttr).IsActive() ); +} + +SfxPoolItem* SwFmtHeader::Clone( SfxItemPool* ) const +{ + return new SwFmtHeader( *this ); +} + +void SwFmtHeader::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add(this); +} + +// class SwFmtFooter +// Implementierung teilweise inline im hxx + +SwFmtFooter::SwFmtFooter( SwFrmFmt *pFooterFmt ) + : SfxPoolItem( RES_FOOTER ), + SwClient( pFooterFmt ), + bActive( pFooterFmt ? sal_True : sal_False ) +{ +} + +SwFmtFooter::SwFmtFooter( const SwFmtFooter &rCpy ) + : SfxPoolItem( RES_FOOTER ), + SwClient( (SwModify*)rCpy.GetRegisteredIn() ), + bActive( rCpy.IsActive() ) +{ +} + +SwFmtFooter::SwFmtFooter( sal_Bool bOn ) + : SfxPoolItem( RES_FOOTER ), + SwClient( 0 ), + bActive( bOn ) +{ +} + + SwFmtFooter::~SwFmtFooter() +{ + if ( GetFooterFmt() ) + DelHFFormat( this, GetFooterFmt() ); +} + +void SwFmtFooter::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add(this); +} + +int SwFmtFooter::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( GetRegisteredIn() == ((SwFmtFooter&)rAttr).GetRegisteredIn() && + bActive == ((SwFmtFooter&)rAttr).IsActive() ); +} + +SfxPoolItem* SwFmtFooter::Clone( SfxItemPool* ) const +{ + return new SwFmtFooter( *this ); +} + +// class SwFmtCntnt +// Implementierung teilweise inline im hxx + +SwFmtCntnt::SwFmtCntnt( const SwFmtCntnt &rCpy ) + : SfxPoolItem( RES_CNTNT ) +{ + pStartNode = rCpy.GetCntntIdx() ? + new SwNodeIndex( *rCpy.GetCntntIdx() ) : 0; +} + +SwFmtCntnt::SwFmtCntnt( const SwStartNode *pStartNd ) + : SfxPoolItem( RES_CNTNT ) +{ + pStartNode = pStartNd ? new SwNodeIndex( *pStartNd ) : 0; +} + + SwFmtCntnt::~SwFmtCntnt() +{ + delete pStartNode; +} + +void SwFmtCntnt::SetNewCntntIdx( const SwNodeIndex *pIdx ) +{ + delete pStartNode; + pStartNode = pIdx ? new SwNodeIndex( *pIdx ) : 0; +} + +int SwFmtCntnt::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + if( (long)pStartNode ^ (long)((SwFmtCntnt&)rAttr).pStartNode ) + return 0; + if( pStartNode ) + return ( *pStartNode == *((SwFmtCntnt&)rAttr).GetCntntIdx() ); + return 1; +} + +SfxPoolItem* SwFmtCntnt::Clone( SfxItemPool* ) const +{ + return new SwFmtCntnt( *this ); +} + +// class SwFmtPageDesc +// Implementierung teilweise inline im hxx + +SwFmtPageDesc::SwFmtPageDesc( const SwFmtPageDesc &rCpy ) + : SfxPoolItem( RES_PAGEDESC ), + SwClient( (SwPageDesc*)rCpy.GetPageDesc() ), + nNumOffset( rCpy.nNumOffset ), + nDescNameIdx( rCpy.nDescNameIdx ), + pDefinedIn( 0 ) +{ +} + +SwFmtPageDesc::SwFmtPageDesc( const SwPageDesc *pDesc ) + : SfxPoolItem( RES_PAGEDESC ), + SwClient( (SwPageDesc*)pDesc ), + nNumOffset( 0 ), + nDescNameIdx( 0xFFFF ), // IDX_NO_VALUE + pDefinedIn( 0 ) +{ +} + + SwFmtPageDesc::~SwFmtPageDesc() {} + +bool SwFmtPageDesc::KnowsPageDesc() const +{ + return (GetRegisteredIn() != 0); +} + +int SwFmtPageDesc::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( pDefinedIn == ((SwFmtPageDesc&)rAttr).pDefinedIn ) && + ( nNumOffset == ((SwFmtPageDesc&)rAttr).nNumOffset ) && + ( GetPageDesc() == ((SwFmtPageDesc&)rAttr).GetPageDesc() ); +} + +SfxPoolItem* SwFmtPageDesc::Clone( SfxItemPool* ) const +{ + return new SwFmtPageDesc( *this ); +} + +void SwFmtPageDesc::SwClientNotify( const SwModify&, const SfxHint& rHint ) +{ + const SwPageDescHint* pHint = dynamic_cast<const SwPageDescHint*>(&rHint); + if ( pHint ) + { + // mba: shouldn't that be broadcasted also? + SwFmtPageDesc aDfltDesc( pHint->GetPageDesc() ); + SwPageDesc* pDesc = pHint->GetPageDesc(); + const SwModify* pMod = GetDefinedIn(); + if ( pMod ) + { + if( pMod->ISA( SwCntntNode ) ) + ((SwCntntNode*)pMod)->SetAttr( aDfltDesc ); + else if( pMod->ISA( SwFmt )) + ((SwFmt*)pMod)->SetFmtAttr( aDfltDesc ); + else + { + OSL_FAIL( "What kind of SwModify is this?" ); + RegisterToPageDesc( *pDesc ); + } + } + else + // there could be an Undo-copy + RegisterToPageDesc( *pDesc ); + } +} + +void SwFmtPageDesc::RegisterToPageDesc( SwPageDesc& rDesc ) +{ + rDesc.Add( this ); +} + +void SwFmtPageDesc::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + if( !pDefinedIn ) + return; + + const sal_uInt16 nWhichId = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhichId ) + { + case RES_OBJECTDYING: + //Der Pagedesc, bei dem ich angemeldet bin stirbt, ich trage + //mich also bei meinem Format aus. + //Dabei werden ich Deletet!!! + if( IS_TYPE( SwFmt, pDefinedIn )) +#if OSL_DEBUG_LEVEL > 1 + { + sal_Bool bDel = ((SwFmt*)pDefinedIn)->ResetFmtAttr( RES_PAGEDESC ); + OSL_ENSURE( bDel, ";-) FmtPageDesc nicht zerstoert." ); + } +#else + ((SwFmt*)pDefinedIn)->ResetFmtAttr( RES_PAGEDESC ); +#endif + else if( IS_TYPE( SwCntntNode, pDefinedIn )) +#if OSL_DEBUG_LEVEL > 1 + { + sal_Bool bDel = ((SwCntntNode*)pDefinedIn)->ResetAttr( RES_PAGEDESC ); + OSL_ENSURE( bDel, ";-) FmtPageDesc nicht zerstoert." ); + } +#else + ((SwCntntNode*)pDefinedIn)->ResetAttr( RES_PAGEDESC ); +#endif + break; + + default: + /* do nothing */; + } +} + +bool SwFmtPageDesc::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_PAGEDESC_PAGENUMOFFSET: + rVal <<= (sal_Int16)GetNumOffset(); + break; + + case MID_PAGEDESC_PAGEDESCNAME: + { + const SwPageDesc* pDesc = GetPageDesc(); + if( pDesc ) + { + String aString; + SwStyleNameMapper::FillProgName(pDesc->GetName(), aString, nsSwGetPoolIdFromName::GET_POOLID_PAGEDESC, sal_True ); + rVal <<= OUString( aString ); + } + else + rVal.clear(); + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtPageDesc::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch ( nMemberId ) + { + case MID_PAGEDESC_PAGENUMOFFSET: + { + sal_Int16 nOffset = 0; + if(rVal >>= nOffset) + SetNumOffset( nOffset ); + else + bRet = false; + } + break; + + case MID_PAGEDESC_PAGEDESCNAME: + /* geht nicht, weil das Attribut eigentlich nicht den Namen + * sondern einen Pointer auf den PageDesc braucht (ist Client davon). + * Der Pointer waere aber ueber den Namen nur vom Dokument zu erfragen. + */ + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + + +// class SwFmtCol +// Implementierung teilweise inline im hxx + +SwColumn::SwColumn() : + nWish ( 0 ), + nUpper( 0 ), + nLower( 0 ), + nLeft ( 0 ), + nRight( 0 ) +{ +} + +sal_Bool SwColumn::operator==( const SwColumn &rCmp ) +{ + return (nWish == rCmp.GetWishWidth() && + GetLeft() == rCmp.GetLeft() && + GetRight() == rCmp.GetRight() && + GetUpper() == rCmp.GetUpper() && + GetLower() == rCmp.GetLower()) ? sal_True : sal_False; +} + +SwFmtCol::SwFmtCol( const SwFmtCol& rCpy ) + : SfxPoolItem( RES_COL ), + eLineStyle( rCpy.eLineStyle ), + nLineWidth( rCpy.nLineWidth), + aLineColor( rCpy.aLineColor), + nLineHeight( rCpy.GetLineHeight() ), + eAdj( rCpy.GetLineAdj() ), + aColumns( (sal_Int8)rCpy.GetNumCols(), 1 ), + nWidth( rCpy.GetWishWidth() ), + bOrtho( rCpy.IsOrtho() ) +{ + for ( sal_uInt16 i = 0; i < rCpy.GetNumCols(); ++i ) + { + SwColumn *pCol = new SwColumn( *rCpy.GetColumns()[i] ); + aColumns.Insert( pCol, aColumns.Count() ); + } +} + +SwFmtCol::~SwFmtCol() {} + +SwFmtCol& SwFmtCol::operator=( const SwFmtCol& rCpy ) +{ + eLineStyle = rCpy.eLineStyle; + nLineWidth = rCpy.nLineWidth; + aLineColor = rCpy.aLineColor; + nLineHeight = rCpy.GetLineHeight(); + eAdj = rCpy.GetLineAdj(); + nWidth = rCpy.GetWishWidth(); + bOrtho = rCpy.IsOrtho(); + + if ( aColumns.Count() ) + aColumns.DeleteAndDestroy( 0, aColumns.Count() ); + for ( sal_uInt16 i = 0; i < rCpy.GetNumCols(); ++i ) + { + SwColumn *pCol = new SwColumn( *rCpy.GetColumns()[i] ); + aColumns.Insert( pCol, aColumns.Count() ); + } + return *this; +} + +SwFmtCol::SwFmtCol() + : SfxPoolItem( RES_COL ), + eLineStyle( editeng::NO_STYLE ), + nLineWidth(0), + nLineHeight( 100 ), + eAdj( COLADJ_NONE ), + nWidth( USHRT_MAX ), + bOrtho( sal_True ) +{ +} + +int SwFmtCol::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + const SwFmtCol &rCmp = (const SwFmtCol&)rAttr; + if( !(eLineStyle == rCmp.eLineStyle && + nLineWidth == rCmp.nLineWidth && + aLineColor == rCmp.aLineColor && + nLineHeight == rCmp.GetLineHeight() && + eAdj == rCmp.GetLineAdj() && + nWidth == rCmp.GetWishWidth() && + bOrtho == rCmp.IsOrtho() && + aColumns.Count() == rCmp.GetNumCols()) ) + return 0; + + for ( sal_uInt16 i = 0; i < aColumns.Count(); ++i ) + if ( !(*aColumns[i] == *rCmp.GetColumns()[i]) ) + return 0; + + return 1; +} + +SfxPoolItem* SwFmtCol::Clone( SfxItemPool* ) const +{ + return new SwFmtCol( *this ); +} + +sal_uInt16 SwFmtCol::GetGutterWidth( sal_Bool bMin ) const +{ + sal_uInt16 nRet = 0; + if ( aColumns.Count() == 2 ) + nRet = aColumns[0]->GetRight() + aColumns[1]->GetLeft(); + else if ( aColumns.Count() > 2 ) + { + sal_Bool bSet = sal_False; + for ( sal_uInt16 i = 1; i < aColumns.Count()-1; ++i ) + { + const sal_uInt16 nTmp = aColumns[i]->GetRight() + aColumns[i+1]->GetLeft(); + if ( bSet ) + { + if ( nTmp != nRet ) + { + if ( !bMin ) + return USHRT_MAX; + if ( nRet > nTmp ) + nRet = nTmp; + } + } + else + { bSet = sal_True; + nRet = nTmp; + } + } + } + return nRet; +} + +void SwFmtCol::SetGutterWidth( sal_uInt16 nNew, sal_uInt16 nAct ) +{ + if ( bOrtho ) + Calc( nNew, nAct ); + else + { + sal_uInt16 nHalf = nNew / 2; + for ( sal_uInt16 i = 0; i < aColumns.Count(); ++i ) + { SwColumn *pCol = aColumns[i]; + pCol->SetLeft ( nHalf ); + pCol->SetRight( nHalf ); + if ( i == 0 ) + pCol->SetLeft( 0 ); + else if ( i == (aColumns.Count() - 1) ) + pCol->SetRight( 0 ); + } + } +} + +void SwFmtCol::Init( sal_uInt16 nNumCols, sal_uInt16 nGutterWidth, sal_uInt16 nAct ) +{ + //Loeschen scheint hier auf den erste Blick vielleicht etwas zu heftig; + //anderfalls muessten allerdings alle Werte der verbleibenden SwColumn's + //initialisiert werden. + if ( aColumns.Count() ) + aColumns.DeleteAndDestroy( 0, aColumns.Count() ); + for ( sal_uInt16 i = 0; i < nNumCols; ++i ) + { SwColumn *pCol = new SwColumn; + aColumns.Insert( pCol, i ); + } + bOrtho = sal_True; + nWidth = USHRT_MAX; + if( nNumCols ) + Calc( nGutterWidth, nAct ); +} + +void SwFmtCol::SetOrtho( sal_Bool bNew, sal_uInt16 nGutterWidth, sal_uInt16 nAct ) +{ + bOrtho = bNew; + if ( bNew && aColumns.Count() ) + Calc( nGutterWidth, nAct ); +} + +sal_uInt16 SwFmtCol::CalcColWidth( sal_uInt16 nCol, sal_uInt16 nAct ) const +{ + OSL_ENSURE( nCol < aColumns.Count(), ":-( ColumnsArr ueberindiziert." ); + if ( nWidth != nAct ) + { + long nW = aColumns[nCol]->GetWishWidth(); + nW *= nAct; + nW /= nWidth; + return sal_uInt16(nW); + } + else + return aColumns[nCol]->GetWishWidth(); +} + +sal_uInt16 SwFmtCol::CalcPrtColWidth( sal_uInt16 nCol, sal_uInt16 nAct ) const +{ + OSL_ENSURE( nCol < aColumns.Count(), ":-( ColumnsArr ueberindiziert." ); + sal_uInt16 nRet = CalcColWidth( nCol, nAct ); + SwColumn *pCol = aColumns[nCol]; + nRet = nRet - pCol->GetLeft(); + nRet = nRet - pCol->GetRight(); + return nRet; +} + +void SwFmtCol::Calc( sal_uInt16 nGutterWidth, sal_uInt16 nAct ) +{ + if(!GetNumCols()) + return; + //Erstmal die Spalten mit der Aktuellen Breite einstellen, dann die + //Wunschbreite der Spalten anhand der Gesamtwunschbreite hochrechnen. + + const sal_uInt16 nGutterHalf = nGutterWidth ? nGutterWidth / 2 : 0; + + //Breite der PrtAreas ist Gesamtbreite - Zwischenraeume / Anzahl + const sal_uInt16 nPrtWidth = + (nAct - ((GetNumCols()-1) * nGutterWidth)) / GetNumCols(); + sal_uInt16 nAvail = nAct; + + //Die erste Spalte ist PrtBreite + (Zwischenraumbreite/2) + const sal_uInt16 nLeftWidth = nPrtWidth + nGutterHalf; + SwColumn *pCol = aColumns[0]; + pCol->SetWishWidth( nLeftWidth ); + pCol->SetRight( nGutterHalf ); + pCol->SetLeft ( 0 ); + nAvail = nAvail - nLeftWidth; + + //Spalte 2 bis n-1 ist PrtBreite + Zwischenraumbreite + const sal_uInt16 nMidWidth = nPrtWidth + nGutterWidth; + sal_uInt16 i; + + for ( i = 1; i < GetNumCols()-1; ++i ) + { + pCol = aColumns[i]; + pCol->SetWishWidth( nMidWidth ); + pCol->SetLeft ( nGutterHalf ); + pCol->SetRight( nGutterHalf ); + nAvail = nAvail - nMidWidth; + } + + //Die Letzte Spalte entspricht wieder der ersten, um Rundungsfehler + //auszugleichen wird der letzten Spalte alles zugeschlagen was die + //anderen nicht verbraucht haben. + pCol = aColumns[aColumns.Count()-1]; + pCol->SetWishWidth( nAvail ); + pCol->SetLeft ( nGutterHalf ); + pCol->SetRight( 0 ); + + //Umrechnen der aktuellen Breiten in Wunschbreiten. + for ( i = 0; i < aColumns.Count(); ++i ) + { + pCol = aColumns[i]; + long nTmp = pCol->GetWishWidth(); + nTmp *= GetWishWidth(); + nTmp /= nAct; + pCol->SetWishWidth( sal_uInt16(nTmp) ); + } +} + +bool SwFmtCol::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + if(MID_COLUMN_SEPARATOR_LINE == nMemberId) + { + OSL_FAIL("not implemented"); + } + else + { + uno::Reference< text::XTextColumns > xCols = new SwXTextColumns(*this); + rVal.setValue(&xCols, ::getCppuType((uno::Reference< text::XTextColumns>*)0)); + } + return true; +} + +bool SwFmtCol::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = false; + if(MID_COLUMN_SEPARATOR_LINE == nMemberId) + { + OSL_FAIL("not implemented"); + } + else + { + uno::Reference< text::XTextColumns > xCols; + rVal >>= xCols; + if(xCols.is()) + { + uno::Sequence<text::TextColumn> aSetColumns = xCols->getColumns(); + const text::TextColumn* pArray = aSetColumns.getConstArray(); + aColumns.DeleteAndDestroy(0, aColumns.Count()); + //max. Count ist hier 64K - das kann das Array aber nicht + sal_uInt16 nCount = Min( (sal_uInt16)aSetColumns.getLength(), + (sal_uInt16) 0x3fff ); + sal_uInt16 nWidthSum = 0; + // #101224# one column is no column + // + if(nCount > 1) + for(sal_uInt16 i = 0; i < nCount; i++) + { + SwColumn* pCol = new SwColumn; + pCol->SetWishWidth( static_cast<sal_uInt16>(pArray[i].Width) ); + nWidthSum = static_cast<sal_uInt16>(nWidthSum + pArray[i].Width); + pCol->SetLeft ( static_cast<sal_uInt16>(MM100_TO_TWIP(pArray[i].LeftMargin)) ); + pCol->SetRight( static_cast<sal_uInt16>(MM100_TO_TWIP(pArray[i].RightMargin)) ); + aColumns.Insert(pCol, i); + } + bRet = true; + nWidth = nWidthSum; + bOrtho = sal_False; + + uno::Reference<lang::XUnoTunnel> xNumTunnel(xCols, uno::UNO_QUERY); + SwXTextColumns* pSwColums = 0; + if(xNumTunnel.is()) + { + pSwColums = reinterpret_cast< SwXTextColumns * >( + sal::static_int_cast< sal_IntPtr >( + xNumTunnel->getSomething( SwXTextColumns::getUnoTunnelId() ))); + } + if(pSwColums) + { + bOrtho = pSwColums->IsAutomaticWidth(); + nLineWidth = pSwColums->GetSepLineWidth(); + aLineColor.SetColor(pSwColums->GetSepLineColor()); + nLineHeight = pSwColums->GetSepLineHeightRelative(); + switch ( pSwColums->GetSepLineStyle() ) + { + default: + case 0: eLineStyle = editeng::NO_STYLE; break; + case 1: eLineStyle = editeng::SOLID; break; + case 2: eLineStyle = editeng::DOTTED; break; + case 3: eLineStyle = editeng::DASHED; break; + } + if(!pSwColums->GetSepLineIsOn()) + eAdj = COLADJ_NONE; + else switch(pSwColums->GetSepLineVertAlign()) + { + case 0: eAdj = COLADJ_TOP; break; //VerticalAlignment_TOP + case 1: eAdj = COLADJ_CENTER;break; //VerticalAlignment_MIDDLE + case 2: eAdj = COLADJ_BOTTOM;break; //VerticalAlignment_BOTTOM + default: OSL_ENSURE( !this, "unknown alignment" ); break; + } + } + } + } + return bRet; +} + + +// class SwFmtSurround +// Implementierung teilweise inline im hxx + +SwFmtSurround::SwFmtSurround( SwSurround eFly ) : + SfxEnumItem( RES_SURROUND, sal_uInt16( eFly ) ) +{ + bAnchorOnly = bContour = bOutside = sal_False; +} + +SwFmtSurround::SwFmtSurround( const SwFmtSurround &rCpy ) : + SfxEnumItem( RES_SURROUND, rCpy.GetValue() ) +{ + bAnchorOnly = rCpy.bAnchorOnly; + bContour = rCpy.bContour; + bOutside = rCpy.bOutside; +} + +int SwFmtSurround::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( GetValue() == ((SwFmtSurround&)rAttr).GetValue() && + bAnchorOnly== ((SwFmtSurround&)rAttr).bAnchorOnly && + bContour== ((SwFmtSurround&)rAttr).bContour && + bOutside== ((SwFmtSurround&)rAttr).bOutside ); +} + +SfxPoolItem* SwFmtSurround::Clone( SfxItemPool* ) const +{ + return new SwFmtSurround( *this ); +} + +sal_uInt16 SwFmtSurround::GetValueCount() const +{ + return SURROUND_END - SURROUND_BEGIN; +} + + +bool SwFmtSurround::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_SURROUND_SURROUNDTYPE: + rVal <<= (text::WrapTextMode)GetSurround(); + break; + case MID_SURROUND_ANCHORONLY: + { + sal_Bool bTmp = IsAnchorOnly(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_SURROUND_CONTOUR: + { + sal_Bool bTmp = IsContour(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_SURROUND_CONTOUROUTSIDE: + { + sal_Bool bTmp = IsOutside(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtSurround::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_SURROUND_SURROUNDTYPE: + { + sal_Int32 eVal = SWUnoHelper::GetEnumAsInt32( rVal ); + if( eVal >= 0 && eVal < (sal_Int16)SURROUND_END ) + SetValue( static_cast<sal_uInt16>(eVal) ); + else { + //exception + ; + } + } + break; + + case MID_SURROUND_ANCHORONLY: + SetAnchorOnly( *(sal_Bool*)rVal.getValue() ); + break; + case MID_SURROUND_CONTOUR: + SetContour( *(sal_Bool*)rVal.getValue() ); + break; + case MID_SURROUND_CONTOUROUTSIDE: + SetOutside( *(sal_Bool*)rVal.getValue() ); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +// class SwFmtVertOrient +// Implementierung teilweise inline im hxx + +SwFmtVertOrient::SwFmtVertOrient( SwTwips nY, sal_Int16 eVert, + sal_Int16 eRel ) + : SfxPoolItem( RES_VERT_ORIENT ), + nYPos( nY ), + eOrient( eVert ), + eRelation( eRel ) +{} + +int SwFmtVertOrient::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( nYPos == ((SwFmtVertOrient&)rAttr).nYPos && + eOrient == ((SwFmtVertOrient&)rAttr).eOrient && + eRelation == ((SwFmtVertOrient&)rAttr).eRelation ); +} + +SfxPoolItem* SwFmtVertOrient::Clone( SfxItemPool* ) const +{ + return new SwFmtVertOrient( nYPos, eOrient, eRelation ); +} + +bool SwFmtVertOrient::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_VERTORIENT_ORIENT: + { + sal_Int16 nRet = text::VertOrientation::NONE; + switch( eOrient ) + { + case text::VertOrientation::TOP : nRet = text::VertOrientation::TOP ;break; + case text::VertOrientation::CENTER : nRet = text::VertOrientation::CENTER ;break; + case text::VertOrientation::BOTTOM : nRet = text::VertOrientation::BOTTOM ;break; + case text::VertOrientation::CHAR_TOP : nRet = text::VertOrientation::CHAR_TOP ;break; + case text::VertOrientation::CHAR_CENTER: nRet = text::VertOrientation::CHAR_CENTER;break; + case text::VertOrientation::CHAR_BOTTOM: nRet = text::VertOrientation::CHAR_BOTTOM;break; + case text::VertOrientation::LINE_TOP : nRet = text::VertOrientation::LINE_TOP ;break; + case text::VertOrientation::LINE_CENTER: nRet = text::VertOrientation::LINE_CENTER;break; + case text::VertOrientation::LINE_BOTTOM: nRet = text::VertOrientation::LINE_BOTTOM;break; + default: break; + } + rVal <<= nRet; + } + break; + case MID_VERTORIENT_RELATION: + rVal <<= lcl_RelToINT(eRelation); + break; + case MID_VERTORIENT_POSITION: + rVal <<= (sal_Int32)TWIP_TO_MM100(GetPos()); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtVertOrient::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + sal_Bool bConvert = 0 != (nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_VERTORIENT_ORIENT: + { + sal_uInt16 nVal = 0; + rVal >>= nVal; + switch( nVal ) + { + case text::VertOrientation::NONE: eOrient = text::VertOrientation::NONE; break; + case text::VertOrientation::TOP : eOrient = text::VertOrientation::TOP; break; + case text::VertOrientation::CENTER : eOrient = text::VertOrientation::CENTER; break; + case text::VertOrientation::BOTTOM : eOrient = text::VertOrientation::BOTTOM; break; + case text::VertOrientation::CHAR_TOP : eOrient = text::VertOrientation::CHAR_TOP; break; + case text::VertOrientation::CHAR_CENTER: eOrient = text::VertOrientation::CHAR_CENTER;break; + case text::VertOrientation::CHAR_BOTTOM: eOrient = text::VertOrientation::CHAR_BOTTOM;break; + case text::VertOrientation::LINE_TOP : eOrient = text::VertOrientation::LINE_TOP; break; + case text::VertOrientation::LINE_CENTER: eOrient = text::VertOrientation::LINE_CENTER;break; + case text::VertOrientation::LINE_BOTTOM: eOrient = text::VertOrientation::LINE_BOTTOM;break; + } + } + break; + case MID_VERTORIENT_RELATION: + { + eRelation = lcl_IntToRelation(rVal); + } + break; + case MID_VERTORIENT_POSITION: + { + sal_Int32 nVal = 0; + rVal >>= nVal; + if(bConvert) + nVal = MM100_TO_TWIP(nVal); + SetPos( nVal ); + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + + + +// class SwFmtHoriOrient +// Implementierung teilweise inline im hxx + +SwFmtHoriOrient::SwFmtHoriOrient( SwTwips nX, sal_Int16 eHori, + sal_Int16 eRel, sal_Bool bPos ) + : SfxPoolItem( RES_HORI_ORIENT ), + nXPos( nX ), + eOrient( eHori ), + eRelation( eRel ), + bPosToggle( bPos ) +{} + +int SwFmtHoriOrient::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return ( nXPos == ((SwFmtHoriOrient&)rAttr).nXPos && + eOrient == ((SwFmtHoriOrient&)rAttr).eOrient && + eRelation == ((SwFmtHoriOrient&)rAttr).eRelation && + bPosToggle == ((SwFmtHoriOrient&)rAttr).bPosToggle ); +} + +SfxPoolItem* SwFmtHoriOrient::Clone( SfxItemPool* ) const +{ + return new SwFmtHoriOrient( nXPos, eOrient, eRelation, bPosToggle ); +} + +bool SwFmtHoriOrient::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_HORIORIENT_ORIENT: + { + sal_Int16 nRet = text::HoriOrientation::NONE; + switch( eOrient ) + { + case text::HoriOrientation::RIGHT: nRet = text::HoriOrientation::RIGHT; break; + case text::HoriOrientation::CENTER : nRet = text::HoriOrientation::CENTER; break; + case text::HoriOrientation::LEFT : nRet = text::HoriOrientation::LEFT; break; + case text::HoriOrientation::INSIDE : nRet = text::HoriOrientation::INSIDE; break; + case text::HoriOrientation::OUTSIDE: nRet = text::HoriOrientation::OUTSIDE; break; + case text::HoriOrientation::FULL: nRet = text::HoriOrientation::FULL; break; + case text::HoriOrientation::LEFT_AND_WIDTH : + nRet = text::HoriOrientation::LEFT_AND_WIDTH; + break; + default: + break; + + } + rVal <<= nRet; + } + break; + case MID_HORIORIENT_RELATION: + rVal <<= lcl_RelToINT(eRelation); + break; + case MID_HORIORIENT_POSITION: + rVal <<= (sal_Int32)TWIP_TO_MM100(GetPos()); + break; + case MID_HORIORIENT_PAGETOGGLE: + { + sal_Bool bTmp = IsPosToggle(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtHoriOrient::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + sal_Bool bConvert = 0 != (nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_HORIORIENT_ORIENT: + { + sal_Int16 nVal = 0; + rVal >>= nVal; + switch( nVal ) + { + case text::HoriOrientation::NONE: eOrient = text::HoriOrientation::NONE ; break; + case text::HoriOrientation::RIGHT: eOrient = text::HoriOrientation::RIGHT; break; + case text::HoriOrientation::CENTER : eOrient = text::HoriOrientation::CENTER; break; + case text::HoriOrientation::LEFT : eOrient = text::HoriOrientation::LEFT; break; + case text::HoriOrientation::INSIDE : eOrient = text::HoriOrientation::INSIDE; break; + case text::HoriOrientation::OUTSIDE: eOrient = text::HoriOrientation::OUTSIDE; break; + case text::HoriOrientation::FULL: eOrient = text::HoriOrientation::FULL; break; + case text::HoriOrientation::LEFT_AND_WIDTH: + eOrient = text::HoriOrientation::LEFT_AND_WIDTH; + break; + } + } + break; + case MID_HORIORIENT_RELATION: + { + eRelation = lcl_IntToRelation(rVal); + } + break; + case MID_HORIORIENT_POSITION: + { + sal_Int32 nVal = 0; + if(!(rVal >>= nVal)) + bRet = false; + if(bConvert) + nVal = MM100_TO_TWIP(nVal); + SetPos( nVal ); + } + break; + case MID_HORIORIENT_PAGETOGGLE: + SetPosToggle( *(sal_Bool*)rVal.getValue()); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + + + +// class SwFmtAnchor +// Implementierung teilweise inline im hxx + +SwFmtAnchor::SwFmtAnchor( RndStdIds nRnd, sal_uInt16 nPage ) + : SfxPoolItem( RES_ANCHOR ), + pCntntAnchor( 0 ), + nAnchorId( nRnd ), + nPageNum( nPage ), + // OD 2004-05-05 #i28701# - get always new increased order number + mnOrder( ++mnOrderCounter ) +{} + +SwFmtAnchor::SwFmtAnchor( const SwFmtAnchor &rCpy ) + : SfxPoolItem( RES_ANCHOR ), + nAnchorId( rCpy.GetAnchorId() ), + nPageNum( rCpy.GetPageNum() ), + // OD 2004-05-05 #i28701# - get always new increased order number + mnOrder( ++mnOrderCounter ) +{ + pCntntAnchor = rCpy.GetCntntAnchor() ? + new SwPosition( *rCpy.GetCntntAnchor() ) : 0; +} + + SwFmtAnchor::~SwFmtAnchor() +{ + delete pCntntAnchor; +} + +void SwFmtAnchor::SetAnchor( const SwPosition *pPos ) +{ + if ( pCntntAnchor ) + delete pCntntAnchor; + pCntntAnchor = pPos ? new SwPosition( *pPos ) : 0; + //AM Absatz gebundene Flys sollten nie in den Absatz hineinzeigen. + if (pCntntAnchor && + ((FLY_AT_PARA == nAnchorId) || (FLY_AT_FLY == nAnchorId))) + { + pCntntAnchor->nContent.Assign( 0, 0 ); + } +} + +SwFmtAnchor& SwFmtAnchor::operator=(const SwFmtAnchor& rAnchor) +{ + nAnchorId = rAnchor.GetAnchorId(); + nPageNum = rAnchor.GetPageNum(); + // OD 2004-05-05 #i28701# - get always new increased order number + mnOrder = ++mnOrderCounter; + + delete pCntntAnchor; + pCntntAnchor = rAnchor.pCntntAnchor ? + new SwPosition(*(rAnchor.pCntntAnchor)) : 0; + return *this; +} + +int SwFmtAnchor::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + // OD 2004-05-05 #i28701# - Note: <mnOrder> hasn't to be considered. + return ( nAnchorId == ((SwFmtAnchor&)rAttr).GetAnchorId() && + nPageNum == ((SwFmtAnchor&)rAttr).GetPageNum() && + //Anker vergleichen. Entweder zeigen beide auf das gleiche + //Attribut bzw. sind 0 oder die SwPosition* sind beide + //gueltig und die SwPositions sind gleich. + (pCntntAnchor == ((SwFmtAnchor&)rAttr).GetCntntAnchor() || + (pCntntAnchor && ((SwFmtAnchor&)rAttr).GetCntntAnchor() && + *pCntntAnchor == *((SwFmtAnchor&)rAttr).GetCntntAnchor()))); +} + +SfxPoolItem* SwFmtAnchor::Clone( SfxItemPool* ) const +{ + return new SwFmtAnchor( *this ); +} + +// OD 2004-05-05 #i28701# +sal_uInt32 SwFmtAnchor::mnOrderCounter = 0; + +// OD 2004-05-05 #i28701# +sal_uInt32 SwFmtAnchor::GetOrder() const +{ + return mnOrder; +} + +bool SwFmtAnchor::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_ANCHOR_ANCHORTYPE: + + text::TextContentAnchorType eRet; + switch (GetAnchorId()) + { + case FLY_AT_CHAR: + eRet = text::TextContentAnchorType_AT_CHARACTER; + break; + case FLY_AT_PAGE: + eRet = text::TextContentAnchorType_AT_PAGE; + break; + case FLY_AT_FLY: + eRet = text::TextContentAnchorType_AT_FRAME; + break; + case FLY_AS_CHAR: + eRet = text::TextContentAnchorType_AS_CHARACTER; + break; + //case FLY_AT_PARA: + default: + eRet = text::TextContentAnchorType_AT_PARAGRAPH; + } + rVal <<= eRet; + break; + case MID_ANCHOR_PAGENUM: + rVal <<= (sal_Int16)GetPageNum(); + break; + case MID_ANCHOR_ANCHORFRAME: + { + if(pCntntAnchor && FLY_AT_FLY == nAnchorId) + { + SwFrmFmt* pFmt = pCntntAnchor->nNode.GetNode().GetFlyFmt(); + if(pFmt) + { + uno::Reference<container::XNamed> xNamed = SwXFrames::GetObject( *pFmt, FLYCNTTYPE_FRM ); + uno::Reference<text::XTextFrame> xRet(xNamed, uno::UNO_QUERY); + rVal <<= xRet; + } + } + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtAnchor::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_ANCHOR_ANCHORTYPE: + { + RndStdIds eAnchor; + switch( SWUnoHelper::GetEnumAsInt32( rVal ) ) + { + case text::TextContentAnchorType_AS_CHARACTER: + eAnchor = FLY_AS_CHAR; + break; + case text::TextContentAnchorType_AT_PAGE: + eAnchor = FLY_AT_PAGE; + if( GetPageNum() > 0 && pCntntAnchor ) + { + // If the anchor type is page and a valid page number + // has been set, the content position isn't required + // any longer. + delete pCntntAnchor; + pCntntAnchor = 0; + } + break; + case text::TextContentAnchorType_AT_FRAME: + eAnchor = FLY_AT_FLY; + break; + case text::TextContentAnchorType_AT_CHARACTER: + eAnchor = FLY_AT_CHAR; + break; + //case text::TextContentAnchorType_AT_PARAGRAPH: + default: + eAnchor = FLY_AT_PARA; + break; + } + SetType( eAnchor ); + } + break; + case MID_ANCHOR_PAGENUM: + { + sal_Int16 nVal = 0; + if((rVal >>= nVal) && nVal > 0) + { + SetPageNum( nVal ); + if ((FLY_AT_PAGE == GetAnchorId()) && pCntntAnchor) + { + // If the anchor type is page and a valid page number + // is set, the content paoition has to be deleted to not + // confuse the layout (frmtool.cxx). However, if the + // anchor type is not page, any content position will + // be kept. + delete pCntntAnchor; + pCntntAnchor = 0; + } + } + else + bRet = false; + } + break; + case MID_ANCHOR_ANCHORFRAME: + //no break here!; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +// class SwFmtURL +// Implementierung teilweise inline im hxx + +SwFmtURL::SwFmtURL() : + SfxPoolItem( RES_URL ), + pMap( 0 ), + bIsServerMap( sal_False ) +{ +} + +SwFmtURL::SwFmtURL( const SwFmtURL &rURL) : + SfxPoolItem( RES_URL ), + sTargetFrameName( rURL.GetTargetFrameName() ), + sURL( rURL.GetURL() ), + sName( rURL.GetName() ), + bIsServerMap( rURL.IsServerMap() ) +{ + pMap = rURL.GetMap() ? new ImageMap( *rURL.GetMap() ) : 0; +} + +SwFmtURL::~SwFmtURL() +{ + if ( pMap ) + delete pMap; +} + +int SwFmtURL::operator==( const SfxPoolItem &rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + const SwFmtURL &rCmp = (SwFmtURL&)rAttr; + sal_Bool bRet = bIsServerMap == rCmp.IsServerMap() && + sURL == rCmp.GetURL() && + sTargetFrameName == rCmp.GetTargetFrameName() && + sName == rCmp.GetName(); + if ( bRet ) + { + if ( pMap && rCmp.GetMap() ) + bRet = *pMap == *rCmp.GetMap(); + else + bRet = pMap == rCmp.GetMap(); + } + return bRet; +} + +SfxPoolItem* SwFmtURL::Clone( SfxItemPool* ) const +{ + return new SwFmtURL( *this ); +} + +void SwFmtURL::SetURL( const XubString &rURL, sal_Bool bServerMap ) +{ + sURL = rURL; + bIsServerMap = bServerMap; +} + +void SwFmtURL::SetMap( const ImageMap *pM ) +{ + if ( pMap ) + delete pMap; + pMap = pM ? new ImageMap( *pM ) : 0; +} +extern const SvEventDescription* lcl_GetSupportedMacroItems(); + +bool SwFmtURL::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_URL_URL: + { + OUString sRet = GetURL(); + rVal <<= sRet; + } + break; + case MID_URL_TARGET: + { + OUString sRet = GetTargetFrameName(); + rVal <<= sRet; + } + break; + case MID_URL_HYPERLINKNAME: + rVal <<= OUString( GetName() ); + break; + case MID_URL_CLIENTMAP: + { + uno::Reference< uno::XInterface > xInt; + if(pMap) + { + xInt = SvUnoImageMap_createInstance( *pMap, lcl_GetSupportedMacroItems() ); + } + else + { + ImageMap aEmptyMap; + xInt = SvUnoImageMap_createInstance( aEmptyMap, lcl_GetSupportedMacroItems() ); + } + uno::Reference< container::XIndexContainer > xCont(xInt, uno::UNO_QUERY); + rVal <<= xCont; + } + break; + case MID_URL_SERVERMAP: + { + sal_Bool bTmp = IsServerMap(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtURL::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_URL_URL: + { + OUString sTmp; + rVal >>= sTmp; + SetURL( sTmp, bIsServerMap ); + } + break; + case MID_URL_TARGET: + { + OUString sTmp; + rVal >>= sTmp; + SetTargetFrameName( sTmp ); + } + break; + case MID_URL_HYPERLINKNAME: + { + OUString sTmp; + rVal >>= sTmp; + SetName( sTmp ); + } + break; + case MID_URL_CLIENTMAP: + { + uno::Reference<container::XIndexContainer> xCont; + if(!rVal.hasValue()) + DELETEZ(pMap); + else if(rVal >>= xCont) + { + if(!pMap) + pMap = new ImageMap; + bRet = SvUnoImageMap_fillImageMap( xCont, *pMap ); + } + else + bRet = false; + } + break; + case MID_URL_SERVERMAP: + bIsServerMap = *(sal_Bool*)rVal.getValue(); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + + +// class SwNoReadOnly + +SfxPoolItem* SwFmtEditInReadonly::Clone( SfxItemPool* ) const +{ + return new SwFmtEditInReadonly( Which(), GetValue() ); +} + +// class SwFmtLayoutSplit + +SfxPoolItem* SwFmtLayoutSplit::Clone( SfxItemPool* ) const +{ + return new SwFmtLayoutSplit( GetValue() ); +} + +// class SwFmtRowSplit + +SfxPoolItem* SwFmtRowSplit::Clone( SfxItemPool* ) const +{ + return new SwFmtRowSplit( GetValue() ); +} + + +// class SwFmtNoBalancedColumns + +SfxPoolItem* SwFmtNoBalancedColumns::Clone( SfxItemPool* ) const +{ + return new SwFmtNoBalancedColumns( GetValue() ); +} + +// class SwFmtFtnEndAtTxtEnd + +sal_uInt16 SwFmtFtnEndAtTxtEnd::GetValueCount() const +{ + return sal_uInt16( FTNEND_ATTXTEND_END ); +} + +SwFmtFtnEndAtTxtEnd& SwFmtFtnEndAtTxtEnd::operator=( + const SwFmtFtnEndAtTxtEnd& rAttr ) +{ + SfxEnumItem::SetValue( rAttr.GetValue() ); + aFmt = rAttr.aFmt; + nOffset = rAttr.nOffset; + sPrefix = rAttr.sPrefix; + sSuffix = rAttr.sSuffix; + return *this; +} + +int SwFmtFtnEndAtTxtEnd::operator==( const SfxPoolItem& rItem ) const +{ + const SwFmtFtnEndAtTxtEnd& rAttr = (SwFmtFtnEndAtTxtEnd&)rItem; + return SfxEnumItem::operator==( rAttr ) && + aFmt.GetNumberingType() == rAttr.aFmt.GetNumberingType() && + nOffset == rAttr.nOffset && + sPrefix == rAttr.sPrefix && + sSuffix == rAttr.sSuffix; +} + +bool SwFmtFtnEndAtTxtEnd::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_COLLECT : + { + sal_Bool bVal = GetValue() >= FTNEND_ATTXTEND; + rVal.setValue(&bVal, ::getBooleanCppuType()); + } + break; + case MID_RESTART_NUM : + { + sal_Bool bVal = GetValue() >= FTNEND_ATTXTEND_OWNNUMSEQ; + rVal.setValue(&bVal, ::getBooleanCppuType()); + } + break; + case MID_NUM_START_AT: rVal <<= (sal_Int16) nOffset; break; + case MID_OWN_NUM : + { + sal_Bool bVal = GetValue() >= FTNEND_ATTXTEND_OWNNUMANDFMT; + rVal.setValue(&bVal, ::getBooleanCppuType()); + } + break; + case MID_NUM_TYPE : rVal <<= aFmt.GetNumberingType(); break; + case MID_PREFIX : rVal <<= OUString(sPrefix); break; + case MID_SUFFIX : rVal <<= OUString(sSuffix); break; + default: return sal_False; + } + return true; +} + +bool SwFmtFtnEndAtTxtEnd::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + bool bRet = true; + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_COLLECT : + { + sal_Bool bVal = *(sal_Bool*)rVal.getValue(); + if(!bVal && GetValue() >= FTNEND_ATTXTEND) + SetValue(FTNEND_ATPGORDOCEND); + else if(bVal && GetValue() < FTNEND_ATTXTEND) + SetValue(FTNEND_ATTXTEND); + } + break; + case MID_RESTART_NUM : + { + sal_Bool bVal = *(sal_Bool*)rVal.getValue(); + if(!bVal && GetValue() >= FTNEND_ATTXTEND_OWNNUMSEQ) + SetValue(FTNEND_ATTXTEND); + else if(bVal && GetValue() < FTNEND_ATTXTEND_OWNNUMSEQ) + SetValue(FTNEND_ATTXTEND_OWNNUMSEQ); + } + break; + case MID_NUM_START_AT: + { + sal_Int16 nVal = 0; + rVal >>= nVal; + if(nVal >= 0) + nOffset = nVal; + else + bRet = false; + } + break; + case MID_OWN_NUM : + { + sal_Bool bVal = *(sal_Bool*)rVal.getValue(); + if(!bVal && GetValue() >= FTNEND_ATTXTEND_OWNNUMANDFMT) + SetValue(FTNEND_ATTXTEND_OWNNUMSEQ); + else if(bVal && GetValue() < FTNEND_ATTXTEND_OWNNUMANDFMT) + SetValue(FTNEND_ATTXTEND_OWNNUMANDFMT); + } + break; + case MID_NUM_TYPE : + { + sal_Int16 nVal = 0; + rVal >>= nVal; + if(nVal >= 0 && + (nVal <= SVX_NUM_ARABIC || + SVX_NUM_CHARS_UPPER_LETTER_N == nVal || + SVX_NUM_CHARS_LOWER_LETTER_N == nVal )) + aFmt.SetNumberingType(nVal); + else + bRet = false; + } + break; + case MID_PREFIX : + { + OUString sVal; rVal >>= sVal; + sPrefix = sVal; + } + break; + case MID_SUFFIX : + { + OUString sVal; rVal >>= sVal; + sSuffix = sVal; + } + break; + default: bRet = false; + } + return bRet; +} + + +// class SwFmtFtnAtTxtEnd + +SfxPoolItem* SwFmtFtnAtTxtEnd::Clone( SfxItemPool* ) const +{ + SwFmtFtnAtTxtEnd* pNew = new SwFmtFtnAtTxtEnd; + *pNew = *this; + return pNew; +} + +// class SwFmtEndAtTxtEnd + +SfxPoolItem* SwFmtEndAtTxtEnd::Clone( SfxItemPool* ) const +{ + SwFmtEndAtTxtEnd* pNew = new SwFmtEndAtTxtEnd; + *pNew = *this; + return pNew; +} + +//class SwFmtChain + + +int SwFmtChain::operator==( const SfxPoolItem &rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + + return GetPrev() == ((SwFmtChain&)rAttr).GetPrev() && + GetNext() == ((SwFmtChain&)rAttr).GetNext(); +} + +SwFmtChain::SwFmtChain( const SwFmtChain &rCpy ) : + SfxPoolItem( RES_CHAIN ) +{ + SetPrev( rCpy.GetPrev() ); + SetNext( rCpy.GetNext() ); +} + +SfxPoolItem* SwFmtChain::Clone( SfxItemPool* ) const +{ + SwFmtChain *pRet = new SwFmtChain; + pRet->SetPrev( GetPrev() ); + pRet->SetNext( GetNext() ); + return pRet; +} + +void SwFmtChain::SetPrev( SwFlyFrmFmt *pFmt ) +{ + if ( pFmt ) + pFmt->Add( &aPrev ); + else if ( aPrev.GetRegisteredIn() ) + ((SwModify*)aPrev.GetRegisteredIn())->Remove( &aPrev ); +} + +void SwFmtChain::SetNext( SwFlyFrmFmt *pFmt ) +{ + if ( pFmt ) + pFmt->Add( &aNext ); + else if ( aNext.GetRegisteredIn() ) + ((SwModify*)aNext.GetRegisteredIn())->Remove( &aNext ); +} + +bool SwFmtChain::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + XubString aRet; + switch ( nMemberId ) + { + case MID_CHAIN_PREVNAME: + if ( GetPrev() ) + aRet = GetPrev()->GetName(); + break; + case MID_CHAIN_NEXTNAME: + if ( GetNext() ) + aRet = GetNext()->GetName(); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + rVal <<= OUString(aRet); + return bRet; +} + + + + +//class SwFmtLineNumber + +SwFmtLineNumber::SwFmtLineNumber() : + SfxPoolItem( RES_LINENUMBER ) +{ + nStartValue = 0; + bCountLines = sal_True; +} + +SwFmtLineNumber::~SwFmtLineNumber() +{ +} + +int SwFmtLineNumber::operator==( const SfxPoolItem &rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + + return nStartValue == ((SwFmtLineNumber&)rAttr).GetStartValue() && + bCountLines == ((SwFmtLineNumber&)rAttr).IsCount(); +} + +SfxPoolItem* SwFmtLineNumber::Clone( SfxItemPool* ) const +{ + return new SwFmtLineNumber( *this ); +} + +bool SwFmtLineNumber::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_LINENUMBER_COUNT: + { + sal_Bool bTmp = IsCount(); + rVal.setValue(&bTmp, ::getBooleanCppuType()); + } + break; + case MID_LINENUMBER_STARTVALUE: + rVal <<= (sal_Int32)GetStartValue(); + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +bool SwFmtLineNumber::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + // hier wird immer konvertiert! + nMemberId &= ~CONVERT_TWIPS; + bool bRet = true; + switch ( nMemberId ) + { + case MID_LINENUMBER_COUNT: + SetCountLines( *(sal_Bool*)rVal.getValue() ); + break; + case MID_LINENUMBER_STARTVALUE: + { + sal_Int32 nVal = 0; + if(rVal >>= nVal) + SetStartValue( nVal ); + else + bRet = false; + } + break; + default: + OSL_ENSURE( !this, "unknown MemberId" ); + bRet = false; + } + return bRet; +} + +/************************************************************************* + * class SwTextGridItem + *************************************************************************/ + +SwTextGridItem::SwTextGridItem() + : SfxPoolItem( RES_TEXTGRID ), aColor( COL_LIGHTGRAY ), nLines( 20 ), + nBaseHeight( 400 ), nRubyHeight( 200 ), eGridType( GRID_NONE ), + bRubyTextBelow( 0 ), bPrintGrid( 1 ), bDisplayGrid( 1 ), + nBaseWidth(400), bSnapToChars( 1 ), bSquaredMode(1) +{ +} + +SwTextGridItem::~SwTextGridItem() +{ +} + +int SwTextGridItem::operator==( const SfxPoolItem& rAttr ) const +{ + OSL_ENSURE( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" ); + return eGridType == ((SwTextGridItem&)rAttr).GetGridType() && + nLines == ((SwTextGridItem&)rAttr).GetLines() && + nBaseHeight == ((SwTextGridItem&)rAttr).GetBaseHeight() && + nRubyHeight == ((SwTextGridItem&)rAttr).GetRubyHeight() && + bRubyTextBelow == ((SwTextGridItem&)rAttr).GetRubyTextBelow() && + bDisplayGrid == ((SwTextGridItem&)rAttr).GetDisplayGrid() && + bPrintGrid == ((SwTextGridItem&)rAttr).GetPrintGrid() && + aColor == ((SwTextGridItem&)rAttr).GetColor() && + nBaseWidth == ((SwTextGridItem&)rAttr).GetBaseWidth() && + bSnapToChars == ((SwTextGridItem&)rAttr).GetSnapToChars() && + bSquaredMode == ((SwTextGridItem&)rAttr).GetSquaredMode(); +} + +SfxPoolItem* SwTextGridItem::Clone( SfxItemPool* ) const +{ + return new SwTextGridItem( *this ); +} + +SwTextGridItem& SwTextGridItem::operator=( const SwTextGridItem& rCpy ) +{ + aColor = rCpy.GetColor(); + nLines = rCpy.GetLines(); + nBaseHeight = rCpy.GetBaseHeight(); + nRubyHeight = rCpy.GetRubyHeight(); + eGridType = rCpy.GetGridType(); + bRubyTextBelow = rCpy.GetRubyTextBelow(); + bPrintGrid = rCpy.GetPrintGrid(); + bDisplayGrid = rCpy.GetDisplayGrid(); + nBaseWidth = rCpy.GetBaseWidth(); + bSnapToChars = rCpy.GetSnapToChars(); + bSquaredMode = rCpy.GetSquaredMode(); + + return *this; +} + +bool SwTextGridItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const +{ + bool bRet = true; + + switch( nMemberId & ~CONVERT_TWIPS ) + { + case MID_GRID_COLOR: + rVal <<= GetColor().GetColor(); + break; + case MID_GRID_LINES: + rVal <<= GetLines(); + break; + case MID_GRID_RUBY_BELOW: + rVal.setValue( &bRubyTextBelow, ::getBooleanCppuType() ); + break; + case MID_GRID_PRINT: + rVal.setValue( &bPrintGrid, ::getBooleanCppuType() ); + break; + case MID_GRID_DISPLAY: + rVal.setValue( &bDisplayGrid, ::getBooleanCppuType() ); + break; + case MID_GRID_BASEHEIGHT: + DBG_ASSERT( (nMemberId & CONVERT_TWIPS) != 0, + "This value needs TWIPS-MM100 conversion" ); + rVal <<= (sal_Int32) TWIP_TO_MM100_UNSIGNED(nBaseHeight); + break; + case MID_GRID_BASEWIDTH: + DBG_ASSERT( (nMemberId & CONVERT_TWIPS) != 0, + "This value needs TWIPS-MM100 conversion" ); + rVal <<= (sal_Int32) TWIP_TO_MM100_UNSIGNED(nBaseWidth); + break; + case MID_GRID_RUBYHEIGHT: + DBG_ASSERT( (nMemberId & CONVERT_TWIPS) != 0, + "This value needs TWIPS-MM100 conversion" ); + rVal <<= (sal_Int32)TWIP_TO_MM100_UNSIGNED(nRubyHeight); + break; + case MID_GRID_TYPE: + switch( GetGridType() ) + { + case GRID_NONE: + rVal <<= text::TextGridMode::NONE; + break; + case GRID_LINES_ONLY: + rVal <<= text::TextGridMode::LINES; + break; + case GRID_LINES_CHARS: + rVal <<= text::TextGridMode::LINES_AND_CHARS; + break; + default: + OSL_FAIL("unknown SwTextGrid value"); + bRet = false; + break; + } + break; + case MID_GRID_SNAPTOCHARS: + rVal.setValue( &bSnapToChars, ::getBooleanCppuType() ); + break; + case MID_GRID_STANDARD_MODE: + { + sal_Bool bStandardMode = !bSquaredMode; + rVal.setValue( &bStandardMode, ::getBooleanCppuType() ); + } + break; + default: + OSL_FAIL("Unknown SwTextGridItem member"); + bRet = false; + break; + } + + return bRet; +} + +bool SwTextGridItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) +{ + bool bRet = true; + switch( nMemberId & ~CONVERT_TWIPS ) + { + case MID_GRID_COLOR: + { + sal_Int32 nTmp = 0; + bRet = (rVal >>= nTmp); + if( bRet ) + SetColor( Color(nTmp) ); + } + break; + case MID_GRID_LINES: + { + sal_Int16 nTmp = 0; + bRet = (rVal >>= nTmp); + if( bRet && (nTmp >= 0) ) + SetLines( (sal_uInt16)nTmp ); + else + bRet = false; + } + break; + case MID_GRID_RUBY_BELOW: + SetRubyTextBelow( *(sal_Bool*)rVal.getValue() ); + break; + case MID_GRID_PRINT: + SetPrintGrid( *(sal_Bool*)rVal.getValue() ); + break; + case MID_GRID_DISPLAY: + SetDisplayGrid( *(sal_Bool*)rVal.getValue() ); + break; + case MID_GRID_BASEHEIGHT: + case MID_GRID_BASEWIDTH: + case MID_GRID_RUBYHEIGHT: + { + DBG_ASSERT( (nMemberId & CONVERT_TWIPS) != 0, + "This value needs TWIPS-MM100 conversion" ); + sal_Int32 nTmp = 0; + bRet = (rVal >>= nTmp); + nTmp = MM100_TO_TWIP( nTmp ); + if( bRet && (nTmp >= 0) && ( nTmp <= USHRT_MAX) ) + if( (nMemberId & ~CONVERT_TWIPS) == MID_GRID_BASEHEIGHT ) + SetBaseHeight( (sal_uInt16)nTmp ); + else if( (nMemberId & ~CONVERT_TWIPS) == MID_GRID_BASEWIDTH ) + SetBaseWidth( (sal_uInt16)nTmp ); + else + SetRubyHeight( (sal_uInt16)nTmp ); + else + bRet = false; + } + break; + case MID_GRID_TYPE: + { + sal_Int16 nTmp = 0; + bRet = (rVal >>= nTmp); + if( bRet ) + { + switch( nTmp ) + { + case text::TextGridMode::NONE: + SetGridType( GRID_NONE ); + break; + case text::TextGridMode::LINES: + SetGridType( GRID_LINES_ONLY ); + break; + case text::TextGridMode::LINES_AND_CHARS: + SetGridType( GRID_LINES_CHARS ); + break; + default: + bRet = false; + break; + } + } + break; + } + case MID_GRID_SNAPTOCHARS: + SetSnapToChars( *(sal_Bool*)rVal.getValue() ); + break; + case MID_GRID_STANDARD_MODE: + { + sal_Bool bStandard = *(sal_Bool*)rVal.getValue(); + SetSquaredMode( !bStandard ); + break; + } + default: + OSL_FAIL("Unknown SwTextGridItem member"); + bRet = false; + } + + return bRet; +} + +void SwTextGridItem::SwitchPaperMode(sal_Bool bNew) +{ + if( bNew == bSquaredMode ) + { + //same paper mode, not switch + return; + } + + // use default value when grid is disable + if( eGridType == GRID_NONE ) + { + bSquaredMode = bNew; + Init(); + return; + } + + if( bSquaredMode ) + { + //switch from "squared mode" to "standard mode" + nBaseWidth = nBaseHeight; + nBaseHeight = nBaseHeight + nRubyHeight; + nRubyHeight = 0; + } + else + { + //switch from "standard mode" to "squared mode" + nRubyHeight = nBaseHeight/3; + nBaseHeight = nBaseHeight - nRubyHeight; + nBaseWidth = nBaseHeight; + } + bSquaredMode = !bSquaredMode; +} + +void SwTextGridItem::Init() +{ + if( bSquaredMode ) + { + nLines = 20; + nBaseHeight = 400; + nRubyHeight = 200; + eGridType = GRID_NONE; + bRubyTextBelow = 0; + bPrintGrid = 1; + bDisplayGrid = 1; + bSnapToChars = 1; + nBaseWidth = 400; + } + else + { + nLines = 44; + nBaseHeight = 312; + nRubyHeight = 0; + eGridType = GRID_NONE; + bRubyTextBelow = 0; + bPrintGrid = 1; + bDisplayGrid = 1; + nBaseWidth = 210; + bSnapToChars = 1; + + //default grid type is line only in CJK env + //disable this function due to type area change + //if grid type change. + //if(SvtCJKOptions().IsAsianTypographyEnabled()) + //{ + // bDisplayGrid = 0; + // eGridType = GRID_LINES_ONLY; + //} + } +} +// class SwHeaderAndFooterEatSpacingItem + +SfxPoolItem* SwHeaderAndFooterEatSpacingItem::Clone( SfxItemPool* ) const +{ + return new SwHeaderAndFooterEatSpacingItem( Which(), GetValue() ); +} + + +// class SwFrmFmt +// Implementierung teilweise inline im hxx + +TYPEINIT1( SwFrmFmt, SwFmt ); +IMPL_FIXEDMEMPOOL_NEWDEL_DLL( SwFrmFmt, 20, 20 ) + +void SwFrmFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + SwFmtHeader *pH = 0; + SwFmtFooter *pF = 0; + + sal_uInt16 nWhich = pNew ? pNew->Which() : 0; + + if( RES_ATTRSET_CHG == nWhich ) + { + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( + RES_HEADER, sal_False, (const SfxPoolItem**)&pH ); + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( + RES_FOOTER, sal_False, (const SfxPoolItem**)&pF ); + } + else if( RES_HEADER == nWhich ) + pH = (SwFmtHeader*)pNew; + else if( RES_FOOTER == nWhich ) + pF = (SwFmtFooter*)pNew; + + if( pH && pH->IsActive() && !pH->GetHeaderFmt() ) + { //Hat er keinen, mach ich ihm einen + SwFrmFmt *pFmt = GetDoc()->MakeLayoutFmt( RND_STD_HEADER, 0 ); + pH->RegisterToFormat( *pFmt ); + } + + if( pF && pF->IsActive() && !pF->GetFooterFmt() ) + { //Hat er keinen, mach ich ihm einen + SwFrmFmt *pFmt = GetDoc()->MakeLayoutFmt( RND_STD_FOOTER, 0 ); + pF->RegisterToFormat( *pFmt ); + } + + // MIB 24.3.98: Modify der Basisklasse muss immer gerufen werden, z.B. + // wegen RESET_FMTWRITTEN. +// if ( GetDepends() ) + SwFmt::Modify( pOld, pNew ); + + if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which())) + { // invalidate cached uno object + SetXObject(uno::Reference<uno::XInterface>(0)); + } +} + +void SwFrmFmt::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add( this ); +} + +//Vernichtet alle Frms, die in aDepend angemeldet sind. + +void SwFrmFmt::DelFrms() +{ + SwIterator<SwFrm,SwFmt> aIter( *this ); + SwFrm * pLast = aIter.First(); + if( pLast ) + do { + pLast->Cut(); + delete pLast; + } while( 0 != ( pLast = aIter.Next() )); +} + +void SwFrmFmt::MakeFrms() +{ + OSL_ENSURE( !this, "Sorry not implemented." ); +} + + + +SwRect SwFrmFmt::FindLayoutRect( const sal_Bool bPrtArea, const Point* pPoint, + const sal_Bool bCalcFrm ) const +{ + SwRect aRet; + SwFrm *pFrm = 0; + if( ISA( SwSectionFmt ) ) + { + // dann den frame::Frame per Node2Layout besorgen + SwSectionNode* pSectNd = ((SwSectionFmt*)this)->GetSectionNode(); + if( pSectNd ) + { + SwNode2Layout aTmp( *pSectNd, pSectNd->GetIndex() - 1 ); + pFrm = aTmp.NextFrm(); + + if( pFrm && !pFrm->KnowsFormat(*this) ) + { + // die Section hat keinen eigenen frame::Frame, also falls + // jemand die tatsaechliche Groe?e braucht, so muss das + // noch implementier werden, in dem sich vom Ende noch + // der entsprechende frame::Frame besorgt wird. + // PROBLEM: was passiert bei SectionFrames, die auf unter- + // schiedlichen Seiten stehen?? + if( bPrtArea ) + aRet = pFrm->Prt(); + else + { + aRet = pFrm->Frm(); + --aRet.Pos().Y(); + } + pFrm = 0; // das Rect ist ja jetzt fertig + } + } + } + else + { + sal_uInt16 nFrmType = RES_FLYFRMFMT == Which() ? FRM_FLY : USHRT_MAX; + pFrm = ::GetFrmOfModify( 0, *(SwModify*)this, nFrmType, pPoint, + 0, bCalcFrm ); + } + + if( pFrm ) + { + if( bPrtArea ) + aRet = pFrm->Prt(); + else + aRet = pFrm->Frm(); + } + return aRet; +} + +SwContact* SwFrmFmt::FindContactObj() +{ + return SwIterator<SwContact,SwFmt>::FirstElement( *this ); +} + +SdrObject* SwFrmFmt::FindSdrObject() +{ + // --> OD 2005-01-06 #i30669# - use method <FindContactObj()> instead of + // duplicated code. + SwContact* pFoundContact = FindContactObj(); + return pFoundContact ? pFoundContact->GetMaster() : 0; + // <-- +} + +SdrObject* SwFrmFmt::FindRealSdrObject() +{ + if( RES_FLYFRMFMT == Which() ) + { + Point aNullPt; + SwFlyFrm* pFly = (SwFlyFrm*)::GetFrmOfModify( 0, *this, FRM_FLY, + &aNullPt, 0, sal_False ); + return pFly ? pFly->GetVirtDrawObj() : 0; + } + return FindSdrObject(); +} + + +sal_Bool SwFrmFmt::IsLowerOf( const SwFrmFmt& rFmt ) const +{ + //Auch eine Verkettung von Innen nach aussen oder von aussen + //nach innen ist nicht zulaessig. + SwFlyFrm *pSFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement(*this); + if( pSFly ) + { + SwFlyFrm *pAskFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement(rFmt); + if( pAskFly ) + return pSFly->IsLowerOf( pAskFly ); + } + + // dann mal ueber die Node-Positionen versuchen + const SwFmtAnchor* pAnchor = &rFmt.GetAnchor(); + if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && pAnchor->GetCntntAnchor()) + { + const SwSpzFrmFmts& rFmts = *GetDoc()->GetSpzFrmFmts(); + const SwNode* pFlyNd = pAnchor->GetCntntAnchor()->nNode.GetNode(). + FindFlyStartNode(); + while( pFlyNd ) + { + // dann ueber den Anker nach oben "hangeln" + sal_uInt16 n; + for( n = 0; n < rFmts.Count(); ++n ) + { + const SwFrmFmt* pFmt = rFmts[ n ]; + const SwNodeIndex* pIdx = pFmt->GetCntnt().GetCntntIdx(); + if( pIdx && pFlyNd == &pIdx->GetNode() ) + { + if( pFmt == this ) + return sal_True; + + pAnchor = &pFmt->GetAnchor(); + if ((FLY_AT_PAGE == pAnchor->GetAnchorId()) || + !pAnchor->GetCntntAnchor() ) + { + return sal_False; + } + + pFlyNd = pAnchor->GetCntntAnchor()->nNode.GetNode(). + FindFlyStartNode(); + break; + } + } + if( n >= rFmts.Count() ) + { + OSL_ENSURE( !this, "Fly-Section aber kein Format gefunden" ); + return sal_False; + } + } + } + return sal_False; +} + +// --> OD 2004-07-27 #i31698# +SwFrmFmt::tLayoutDir SwFrmFmt::GetLayoutDir() const +{ + return SwFrmFmt::HORI_L2R; +} + +void SwFrmFmt::SetLayoutDir( const SwFrmFmt::tLayoutDir ) +{ + // empty body, because default implementation does nothing +} +// <-- + +// --> OD 2004-08-06 #i28749# +sal_Int16 SwFrmFmt::GetPositionLayoutDir() const +{ + return text::PositionLayoutDir::PositionInLayoutDirOfAnchor; +} +void SwFrmFmt::SetPositionLayoutDir( const sal_Int16 ) +{ + // empty body, because default implementation does nothing +} +// <-- +String SwFrmFmt::GetDescription() const +{ + return SW_RES(STR_FRAME); +} + +// class SwFlyFrmFmt +// Implementierung teilweise inline im hxx + +TYPEINIT1( SwFlyFrmFmt, SwFrmFmt ); +IMPL_FIXEDMEMPOOL_NEWDEL( SwFlyFrmFmt, 10, 10 ) + +SwFlyFrmFmt::~SwFlyFrmFmt() +{ + SwIterator<SwFlyFrm,SwFmt> aIter( *this ); + SwFlyFrm * pLast = aIter.First(); + if( pLast ) + do { + delete pLast; + } while( 0 != ( pLast = aIter.Next() )); + + SwIterator<SwFlyDrawContact,SwFmt> a2ndIter( *this ); + SwFlyDrawContact* pC = a2ndIter.First(); + if( pC ) + do { + delete pC; + + } while( 0 != ( pC = a2ndIter.Next() )); +} + +//Erzeugen der Frms wenn das Format einen Absatzgebundenen Rahmen beschreibt. +//MA: 14. Feb. 94, Erzeugen der Frms auch fuer Seitengebundene Rahmen. + +void SwFlyFrmFmt::MakeFrms() +{ + // gibts ueberhaupt ein Layout ?? + if( !GetDoc()->GetCurrentViewShell() ) + return; //swmod 071108//swmod 071225 + + SwModify *pModify = 0; + // OD 24.07.2003 #111032# - create local copy of anchor attribute for possible changes. + SwFmtAnchor aAnchorAttr( GetAnchor() ); + switch( aAnchorAttr.GetAnchorId() ) + { + case FLY_AS_CHAR: + case FLY_AT_PARA: + case FLY_AT_CHAR: + if( aAnchorAttr.GetCntntAnchor() ) + { + pModify = aAnchorAttr.GetCntntAnchor()->nNode.GetNode().GetCntntNode(); + } + break; + + case FLY_AT_FLY: + if( aAnchorAttr.GetCntntAnchor() ) + { + //Erst einmal ueber den Inhalt suchen, weil konstant schnell. Kann + //Bei verketteten Rahmen aber auch schief gehen, weil dann evtl. + //niemals ein frame::Frame zu dem Inhalt existiert. Dann muss leider noch + //die Suche vom StartNode zum FrameFormat sein. + SwNodeIndex aIdx( aAnchorAttr.GetCntntAnchor()->nNode ); + SwCntntNode *pCNd = GetDoc()->GetNodes().GoNext( &aIdx ); + // --> OD 2009-12-28 #i105535# + if ( pCNd == 0 ) + { + pCNd = aAnchorAttr.GetCntntAnchor()->nNode.GetNode().GetCntntNode(); + } + if ( pCNd ) + // <-- + { + if( SwIterator<SwFrm,SwCntntNode>::FirstElement( *pCNd ) ) + { + pModify = pCNd; + } + } + // --> OD 2009-12-28 #i105535# + if ( pModify == 0 ) + // <-- + { + const SwNodeIndex &rIdx = aAnchorAttr.GetCntntAnchor()->nNode; + SwSpzFrmFmts& rFmts = *GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 i = 0; i < rFmts.Count(); ++i ) + { + SwFrmFmt* pFlyFmt = rFmts[i]; + if( pFlyFmt->GetCntnt().GetCntntIdx() && + rIdx == *pFlyFmt->GetCntnt().GetCntntIdx() ) + { + pModify = pFlyFmt; + break; + } + } + } + } + break; + + case FLY_AT_PAGE: + { + sal_uInt16 nPgNum = aAnchorAttr.GetPageNum(); + SwPageFrm *pPage = (SwPageFrm*)GetDoc()->GetCurrentLayout()->Lower(); //swmod 080218 + if( !nPgNum && aAnchorAttr.GetCntntAnchor() ) + { + SwCntntNode *pCNd = + aAnchorAttr.GetCntntAnchor()->nNode.GetNode().GetCntntNode(); + SwIterator<SwFrm,SwCntntNode> aIter( *pCNd ); + for (SwFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) + { + pPage = pFrm->FindPageFrm(); + if( pPage ) + { + nPgNum = pPage->GetPhyPageNum(); + // OD 24.07.2003 #111032# - update anchor attribute + aAnchorAttr.SetPageNum( nPgNum ); + aAnchorAttr.SetAnchor( 0 ); + SetFmtAttr( aAnchorAttr ); + } + break; + } + } + while ( pPage ) + { + if ( pPage->GetPhyPageNum() == nPgNum ) + { + // --> OD 2005-06-09 #i50432# - adjust synopsis of <PlaceFly(..)> + pPage->PlaceFly( 0, this ); + // <-- + break; + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + } + break; + default: + break; + } + + if( pModify ) + { + SwIterator<SwFrm,SwModify> aIter( *pModify ); + for( SwFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) + { + sal_Bool bAdd = !pFrm->IsCntntFrm() || + !((SwCntntFrm*)pFrm)->IsFollow(); + + if ( FLY_AT_FLY == aAnchorAttr.GetAnchorId() && !pFrm->IsFlyFrm() ) + { + // --> OD 2009-12-28 #i105535# + // fallback to anchor type at-paragraph, if no fly frame is found. +// pFrm = pFrm->FindFlyFrm(); + SwFrm* pFlyFrm = pFrm->FindFlyFrm(); + if ( pFlyFrm ) + { + pFrm = pFlyFrm; + } + else + { + aAnchorAttr.SetType( FLY_AT_PARA ); + SetFmtAttr( aAnchorAttr ); + MakeFrms(); + return; + } + // <-- + } + + if( pFrm->GetDrawObjs() ) + { + // --> OD 2004-07-01 #i28701# - new type <SwSortedObjs> + SwSortedObjs &rObjs = *pFrm->GetDrawObjs(); + for( sal_uInt16 i = 0; i < rObjs.Count(); ++i) + { + // --> OD 2004-07-01 #i28701# - consider changed type of + // <SwSortedObjs> entries. + SwAnchoredObject* pObj = rObjs[i]; + if( pObj->ISA(SwFlyFrm) && + (&pObj->GetFrmFmt()) == this ) + { + bAdd = sal_False; + break; + } + } + } + + if( bAdd ) + { + SwFlyFrm *pFly = 0; + switch( aAnchorAttr.GetAnchorId() ) + { + case FLY_AT_FLY: + pFly = new SwFlyLayFrm( this, pFrm, pFrm ); + break; + + case FLY_AT_PARA: + case FLY_AT_CHAR: + pFly = new SwFlyAtCntFrm( this, pFrm, pFrm ); + break; + + case FLY_AS_CHAR: + pFly = new SwFlyInCntFrm( this, pFrm, pFrm ); + break; + default: + OSL_ENSURE( !this, "Neuer Ankertyp" ); + break; + } + pFrm->AppendFly( pFly ); + SwPageFrm *pPage = pFly->FindPageFrm(); + if( pPage ) + ::RegistFlys( pPage, pFly ); + } + } + } +} + +SwFlyFrm* SwFlyFrmFmt::GetFrm( const Point* pPoint, const sal_Bool bCalcFrm ) const +{ + return (SwFlyFrm*)::GetFrmOfModify( 0, *(SwModify*)this, FRM_FLY, + pPoint, 0, bCalcFrm ); +} + +SwAnchoredObject* SwFlyFrmFmt::GetAnchoredObj( const Point* pPoint, const sal_Bool bCalcFrm ) const +{ + SwFlyFrm* pFlyFrm( GetFrm( pPoint, bCalcFrm ) ); + if ( pFlyFrm ) + { + return dynamic_cast<SwAnchoredObject*>(pFlyFrm); + } + else + { + return 0L; + } +} + + +sal_Bool SwFlyFrmFmt::GetInfo( SfxPoolItem& rInfo ) const +{ + switch( rInfo.Which() ) + { + case RES_CONTENT_VISIBLE: + { + ((SwPtrMsgPoolItem&)rInfo).pObject = SwIterator<SwFrm,SwFmt>::FirstElement( *this ); + } + return sal_False; + + default: + return SwFrmFmt::GetInfo( rInfo ); + } + return sal_True; +} + +// --> OD 2009-07-14 #i73249# +void SwFlyFrmFmt::SetObjTitle( const String& rTitle, bool bBroadcast ) +{ + SdrObject* pMasterObject = FindSdrObject(); + OSL_ENSURE( pMasterObject, + "<SwNoTxtNode::SetObjTitle(..)> - missing <SdrObject> instance" ); + if ( !pMasterObject ) + { + return; + } + + if( bBroadcast ) + { + SwStringMsgPoolItem aOld( RES_TITLE_CHANGED, pMasterObject->GetTitle() ); + SwStringMsgPoolItem aNew( RES_TITLE_CHANGED, rTitle ); + pMasterObject->SetTitle( rTitle ); + ModifyNotification( &aOld, &aNew ); + } + else + { + pMasterObject->SetTitle( rTitle ); + } +} + +const String SwFlyFrmFmt::GetObjTitle() const +{ + const SdrObject* pMasterObject = FindSdrObject(); + OSL_ENSURE( pMasterObject, + "<SwFlyFrmFmt::GetObjTitle(..)> - missing <SdrObject> instance" ); + if ( !pMasterObject ) + { + return aEmptyStr; + } + + return pMasterObject->GetTitle(); +} + +void SwFlyFrmFmt::SetObjDescription( const String& rDescription, bool bBroadcast ) +{ + SdrObject* pMasterObject = FindSdrObject(); + OSL_ENSURE( pMasterObject, + "<SwFlyFrmFmt::SetDescription(..)> - missing <SdrObject> instance" ); + if ( !pMasterObject ) + { + return; + } + + if( bBroadcast ) + { + SwStringMsgPoolItem aOld( RES_DESCRIPTION_CHANGED, pMasterObject->GetDescription() ); + SwStringMsgPoolItem aNew( RES_DESCRIPTION_CHANGED, rDescription ); + pMasterObject->SetDescription( rDescription ); + ModifyNotification( &aOld, &aNew ); + } + else + { + pMasterObject->SetDescription( rDescription ); + } +} + +const String SwFlyFrmFmt::GetObjDescription() const +{ + const SdrObject* pMasterObject = FindSdrObject(); + OSL_ENSURE( pMasterObject, + "<SwNoTxtNode::GetDescription(..)> - missing <SdrObject> instance" ); + if ( !pMasterObject ) + { + return aEmptyStr; + } + + return pMasterObject->GetDescription(); +} +// <-- + +/** SwFlyFrmFmt::IsBackgroundTransparent - for #99657# + + OD 22.08.2002 - overloading virtual method and its default implementation, + because format of fly frame provides transparent backgrounds. + Method determines, if background of fly frame is transparent. + + @author OD + + @return true, if background color is transparent, but not "no fill" + or the transparency of a existing background graphic is set. +*/ +sal_Bool SwFlyFrmFmt::IsBackgroundTransparent() const +{ + sal_Bool bReturn = sal_False; + + /// NOTE: If background color is "no fill"/"auto fill" (COL_TRANSPARENT) + /// and there is no background graphic, it "inherites" the background + /// from its anchor. + if ( (GetBackground().GetColor().GetTransparency() != 0) && + (GetBackground().GetColor() != COL_TRANSPARENT) + ) + { + bReturn = sal_True; + } + else + { + const GraphicObject *pTmpGrf = + static_cast<const GraphicObject*>(GetBackground().GetGraphicObject()); + if ( (pTmpGrf) && + (pTmpGrf->GetAttr().GetTransparency() != 0) + ) + { + bReturn = sal_True; + } + } + + return bReturn; +} + +/** SwFlyFrmFmt::IsBackgroundBrushInherited - for #103898# + + OD 08.10.2002 - method to determine, if the brush for drawing the + background is "inherited" from its parent/grandparent. + This is the case, if no background graphic is set and the background + color is "no fill"/"auto fill" + NOTE: condition is "copied" from method <SwFrm::GetBackgroundBrush(..). + + @author OD + + @return true, if background brush is "inherited" from parent/grandparent +*/ +sal_Bool SwFlyFrmFmt::IsBackgroundBrushInherited() const +{ + sal_Bool bReturn = sal_False; + + if ( (GetBackground().GetColor() == COL_TRANSPARENT) && + !(GetBackground().GetGraphicObject()) ) + { + bReturn = sal_True; + } + + return bReturn; +} + +// --> OD 2006-02-28 #125892# +SwHandleAnchorNodeChg::SwHandleAnchorNodeChg( SwFlyFrmFmt& _rFlyFrmFmt, + const SwFmtAnchor& _rNewAnchorFmt, + SwFlyFrm* _pKeepThisFlyFrm ) + : mrFlyFrmFmt( _rFlyFrmFmt ), + mbAnchorNodeChanged( false ) +{ + const RndStdIds nNewAnchorType( _rNewAnchorFmt.GetAnchorId() ); + if ( ((nNewAnchorType == FLY_AT_PARA) || + (nNewAnchorType == FLY_AT_CHAR)) && + _rNewAnchorFmt.GetCntntAnchor() && + _rNewAnchorFmt.GetCntntAnchor()->nNode.GetNode().GetCntntNode() ) + { + const SwFmtAnchor& aOldAnchorFmt( _rFlyFrmFmt.GetAnchor() ); + if ( aOldAnchorFmt.GetAnchorId() == nNewAnchorType && + aOldAnchorFmt.GetCntntAnchor() && + aOldAnchorFmt.GetCntntAnchor()->nNode.GetNode().GetCntntNode() && + aOldAnchorFmt.GetCntntAnchor()->nNode != + _rNewAnchorFmt.GetCntntAnchor()->nNode ) + { + // determine 'old' number of anchor frames + sal_uInt32 nOldNumOfAnchFrm( 0L ); + SwIterator<SwFrm,SwCntntNode> aOldIter( *(aOldAnchorFmt.GetCntntAnchor()->nNode.GetNode().GetCntntNode()) ); + for( SwFrm* pOld = aOldIter.First(); pOld; pOld = aOldIter.Next() ) + { + ++nOldNumOfAnchFrm; + } + // determine 'new' number of anchor frames + sal_uInt32 nNewNumOfAnchFrm( 0L ); + SwIterator<SwFrm,SwCntntNode> aNewIter( *(_rNewAnchorFmt.GetCntntAnchor()->nNode.GetNode().GetCntntNode()) ); + for( SwFrm* pNew = aNewIter.First(); pNew; pNew = aNewIter.Next() ) + { + ++nNewNumOfAnchFrm; + } + if ( nOldNumOfAnchFrm != nNewNumOfAnchFrm ) + { + // delete existing fly frames except <_pKeepThisFlyFrm> + SwIterator<SwFrm,SwFmt> aIter( mrFlyFrmFmt ); + SwFrm* pFrm = aIter.First(); + if ( pFrm ) + { + do { + if ( pFrm != _pKeepThisFlyFrm ) + { + pFrm->Cut(); + delete pFrm; + } + } while( 0 != ( pFrm = aIter.Next() )); + } + // indicate, that re-creation of fly frames necessary + mbAnchorNodeChanged = true; + } + } + } +} + +SwHandleAnchorNodeChg::~SwHandleAnchorNodeChg() +{ + if ( mbAnchorNodeChanged ) + { + mrFlyFrmFmt.MakeFrms(); + } +} +// <-- +// class SwDrawFrmFmt +// Implementierung teilweise inline im hxx + +TYPEINIT1( SwDrawFrmFmt, SwFrmFmt ); +IMPL_FIXEDMEMPOOL_NEWDEL( SwDrawFrmFmt, 10, 10 ) + +SwDrawFrmFmt::~SwDrawFrmFmt() +{ + SwContact *pContact = FindContactObj(); + delete pContact; +} + +void SwDrawFrmFmt::MakeFrms() +{ + SwDrawContact *pContact = (SwDrawContact*)FindContactObj(); + if ( pContact ) + pContact->ConnectToLayout(); +} + +void SwDrawFrmFmt::DelFrms() +{ + SwDrawContact *pContact = (SwDrawContact *)FindContactObj(); + if ( pContact ) //fuer den Reader und andere Unabwaegbarkeiten. + pContact->DisconnectFromLayout(); +} + +// --> OD 2004-07-27 #i31698# +SwFrmFmt::tLayoutDir SwDrawFrmFmt::GetLayoutDir() const +{ + return meLayoutDir; +} + +void SwDrawFrmFmt::SetLayoutDir( const SwFrmFmt::tLayoutDir _eLayoutDir ) +{ + meLayoutDir = _eLayoutDir; +} +// <-- + +// --> OD 2004-08-06 #i28749# +sal_Int16 SwDrawFrmFmt::GetPositionLayoutDir() const +{ + return mnPositionLayoutDir; +} +void SwDrawFrmFmt::SetPositionLayoutDir( const sal_Int16 _nPositionLayoutDir ) +{ + switch ( _nPositionLayoutDir ) + { + case text::PositionLayoutDir::PositionInHoriL2R: + case text::PositionLayoutDir::PositionInLayoutDirOfAnchor: + { + mnPositionLayoutDir = _nPositionLayoutDir; + } + break; + default: + { + OSL_FAIL( "<SwDrawFrmFmt::SetPositionLayoutDir(..)> - invalid attribute value." ); + } + } +} +// <-- + +String SwDrawFrmFmt::GetDescription() const +{ + String aResult; + const SdrObject * pSdrObj = FindSdrObject(); + + if (pSdrObj) + { + if (pSdrObj != pSdrObjCached) + { + SdrObject * pSdrObjCopy = pSdrObj->Clone(); + SdrUndoNewObj * pSdrUndo = new SdrUndoNewObj(*pSdrObjCopy); + sSdrObjCachedComment = pSdrUndo->GetComment(); + + delete pSdrUndo; + + pSdrObjCached = pSdrObj; + } + + aResult = sSdrObjCachedComment; + } + else + aResult = SW_RES(STR_GRAPHIC); + + return aResult; +} + +IMapObject* SwFrmFmt::GetIMapObject( const Point& rPoint, + const SwFlyFrm *pFly ) const +{ + const SwFmtURL &rURL = GetURL(); + if( !rURL.GetMap() ) + return 0; + + if( !pFly ) + { + pFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement( *this ); + if( !pFly ) + return 0; + } + + //Orignialgroesse fuer OLE und Grafik ist die TwipSize, + //ansonsten die Groesse vom FrmFmt des Fly. + const SwFrm *pRef; + SwNoTxtNode *pNd = 0; + Size aOrigSz; + if( pFly->Lower() && pFly->Lower()->IsNoTxtFrm() ) + { + pRef = pFly->Lower(); + pNd = ((SwCntntFrm*)pRef)->GetNode()->GetNoTxtNode(); + aOrigSz = pNd->GetTwipSize(); + } + else + { + pRef = pFly; + aOrigSz = pFly->GetFmt()->GetFrmSize().GetSize(); + } + + if( aOrigSz.Width() != 0 && aOrigSz.Height() != 0 ) + { + Point aPos( rPoint ); + Size aActSz ( pRef == pFly ? pFly->Frm().SSize() : pRef->Prt().SSize() ); + const MapMode aSrc ( MAP_TWIP ); + const MapMode aDest( MAP_100TH_MM ); + aOrigSz = OutputDevice::LogicToLogic( aOrigSz, aSrc, aDest ); + aActSz = OutputDevice::LogicToLogic( aActSz, aSrc, aDest ); + aPos -= pRef->Frm().Pos(); + aPos -= pRef->Prt().Pos(); + aPos = OutputDevice::LogicToLogic( aPos, aSrc, aDest ); + sal_uInt32 nFlags = 0; + if ( pFly != pRef && pNd->IsGrfNode() ) + { + const sal_uInt16 nMirror = pNd->GetSwAttrSet(). + GetMirrorGrf().GetValue(); + if ( RES_MIRROR_GRAPH_BOTH == nMirror ) + nFlags = IMAP_MIRROR_HORZ | IMAP_MIRROR_VERT; + else if ( RES_MIRROR_GRAPH_VERT == nMirror ) + nFlags = IMAP_MIRROR_VERT; + else if ( RES_MIRROR_GRAPH_HOR == nMirror ) + nFlags = IMAP_MIRROR_HORZ; + + } + return ((ImageMap*)rURL.GetMap())->GetHitIMapObject( aOrigSz, + aActSz, aPos, nFlags ); + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx new file mode 100644 index 000000000000..e3bcf56ee9c4 --- /dev/null +++ b/sw/source/core/layout/calcmove.cxx @@ -0,0 +1,2116 @@ +/* -*- 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 "rootfrm.hxx" +#include "pagefrm.hxx" +#include "cntfrm.hxx" +#include "viewsh.hxx" +#include "doc.hxx" +#include "viewimp.hxx" +#include "viewopt.hxx" +#include "swtypes.hxx" +#include "dflyobj.hxx" +#include "dcontact.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "txtftn.hxx" +#include "fmtftn.hxx" +#include <editeng/ulspitem.hxx> +#include <editeng/keepitem.hxx> + +#include <vcl/outdev.hxx> +#include <fmtfsize.hxx> +#include <fmtanchr.hxx> +#include <fmtclbl.hxx> + +#include "tabfrm.hxx" +#include "ftnfrm.hxx" +#include "txtfrm.hxx" +#include "pagedesc.hxx" +#include "ftninfo.hxx" +#include "sectfrm.hxx" +#include "dbg_lay.hxx" + +// --> OD 2004-06-23 #i28701# +#include <sortedobjs.hxx> +#include <layouter.hxx> +// --> OD 2004-11-01 #i36347# +#include <flyfrms.hxx> +// <-- + +#include <ndtxt.hxx> + +//------------------------------------------------------------------------ +// Move-Methoden +//------------------------------------------------------------------------ + +/************************************************************************* +|* +|* SwCntntFrm::ShouldBwdMoved() +|* +|* Beschreibung Returnwert sagt, ob der Frm verschoben werden sollte. +|* +|*************************************************************************/ + + +sal_Bool SwCntntFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, sal_Bool, sal_Bool & ) +{ + if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove())) + { + //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv. + //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen + //moechte die FixSize die gleiche ist, die der Frm selbst hat. + //In diesem Fall kann einfach geprueft werden, ob der Frm genug + //Platz fuer seine VarSize findet, ist dies nicht der Fall kann + //gleich auf das Verschieben verzichtet werden. + //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst + //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise + //aufspalten kann. + //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind + //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn + //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt + //etwas Platz zur Verfuegung steht). + + //Die FixSize der Umgebungen in denen Cntnts herumlungern ist immer + //Die Breite. + + //Wenn mehr als ein Blatt zurueckgegangen wurde (z.B. ueberspringen + //von Leerseiten), so muss in jedemfall gemoved werden - sonst wuerde, + //falls der Frm nicht in das Blatt passt, nicht mehr auf die + //dazwischenliegenden Blaetter geachtet werden. + sal_uInt8 nMoveAnyway = 0; + SwPageFrm * const pNewPage = pNewUpper->FindPageFrm(); + SwPageFrm *pOldPage = FindPageFrm(); + + if ( SwFlowFrm::IsMoveBwdJump() ) + return sal_True; + + if( IsInFtn() && IsInSct() ) + { + SwFtnFrm* pFtn = FindFtnFrm(); + SwSectionFrm* pMySect = pFtn->FindSctFrm(); + if( pMySect && pMySect->IsFtnLock() ) + { + SwSectionFrm *pSect = pNewUpper->FindSctFrm(); + while( pSect && pSect->IsInFtn() ) + pSect = pSect->GetUpper()->FindSctFrm(); + OSL_ENSURE( pSect, "Escaping footnote" ); + if( pSect != pMySect ) + return sal_False; + } + } + SWRECTFN( this ) + SWRECTFNX( pNewUpper ) + if( Abs( (pNewUpper->Prt().*fnRectX->fnGetWidth)() - + (GetUpper()->Prt().*fnRect->fnGetWidth)() ) > 1 ) + nMoveAnyway = 2; // Damit kommt nur noch ein _WouldFit mit Umhaengen in Frage + + // OD 2004-05-26 #i25904# - do *not* move backward, + // if <nMoveAnyway> equals 3 and no space is left in new upper. + nMoveAnyway |= BwdMoveNecessary( pOldPage, Frm() ); + { + const IDocumentSettingAccess* pIDSA = pNewPage->GetFmt()->getIDocumentSettingAccess(); + SwTwips nSpace = 0; + SwRect aRect( pNewUpper->Prt() ); + aRect.Pos() += pNewUpper->Frm().Pos(); + const SwFrm *pPrevFrm = pNewUpper->Lower(); + while ( pPrevFrm ) + { + SwTwips nNewTop = (pPrevFrm->Frm().*fnRectX->fnGetBottom)(); + // OD 2004-03-01 #106629#: + // consider lower spacing of last frame in a table cell + { + // check, if last frame is inside table and if it includes + // its lower spacing. + if ( !pPrevFrm->GetNext() && pPrevFrm->IsInTab() && + pIDSA->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) ) + { + const SwFrm* pLastFrm = pPrevFrm; + // if last frame is a section, take its last content + if ( pPrevFrm->IsSctFrm() ) + { + pLastFrm = static_cast<const SwSectionFrm*>(pPrevFrm)->FindLastCntnt(); + if ( pLastFrm && + pLastFrm->FindTabFrm() != pPrevFrm->FindTabFrm() ) + { + pLastFrm = pLastFrm->FindTabFrm(); + } + } + + if ( pLastFrm ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pLastFrm ); + const SwBorderAttrs& rAttrs = *aAccess.Get(); + nNewTop -= rAttrs.GetULSpace().GetLower(); + } + } + } + (aRect.*fnRectX->fnSetTop)( nNewTop ); + + pPrevFrm = pPrevFrm->GetNext(); + } + + nMoveAnyway |= BwdMoveNecessary( pNewPage, aRect); + + //determine space left in new upper frame + nSpace = (aRect.*fnRectX->fnGetHeight)(); + const ViewShell *pSh = pNewUpper->getRootFrm()->GetCurrShell(); + if ( IsInFtn() || + (pSh && pSh->GetViewOptions()->getBrowseMode()) || + pNewUpper->IsCellFrm() || + ( pNewUpper->IsInSct() && ( pNewUpper->IsSctFrm() || + ( pNewUpper->IsColBodyFrm() && + !pNewUpper->GetUpper()->GetPrev() && + !pNewUpper->GetUpper()->GetNext() ) ) ) ) + nSpace += pNewUpper->Grow( LONG_MAX, sal_True ); + + if ( nMoveAnyway < 3 ) + { + if ( nSpace ) + { + //Keine Beruecksichtigung der Fussnoten die an dem Absatz + //kleben, denn dies wuerde extrem unuebersichtlichen Code + //beduerfen (wg. Beruecksichtung der Breiten und vor allem + //der Flys, die ja wieder Einfluss auf die Fussnoten nehmen...). + + // _WouldFit kann bei gleicher Breite und _nur_ selbst verankerten Flys + // befragt werden. + // _WouldFit kann auch gefragt werden, wenn _nur_ fremdverankerte Flys vorliegen, + // dabei ist sogar die Breite egal, da ein TestFormat in der neuen Umgebung + // vorgenommen wird. + // --> OD 2007-11-26 #b6614158# + const sal_uInt8 nBwdMoveNecessaryResult = + BwdMoveNecessary( pNewPage, aRect); + const bool bObjsInNewUpper( nBwdMoveNecessaryResult == 2 || + nBwdMoveNecessaryResult == 3 ); + + return _WouldFit( nSpace, pNewUpper, nMoveAnyway == 2, + bObjsInNewUpper ); + // <-- + } + //Bei einem spaltigen Bereichsfrischling kann _WouldFit kein + //brauchbares Ergebnis liefern, also muessen wir wirklich + //zurueckfliessen + else if( pNewUpper->IsInSct() && pNewUpper->IsColBodyFrm() && + !(pNewUpper->Prt().*fnRectX->fnGetWidth)() && + ( pNewUpper->GetUpper()->GetPrev() || + pNewUpper->GetUpper()->GetNext() ) ) + return sal_True; + else + return sal_False; // Kein Platz, dann ist es sinnlos, zurueckzufliessen + } + else + { + // OD 2004-05-26 #i25904# - check for space left in new upper + if ( nSpace ) + return sal_True; + else + return sal_False; + } + } + } + return sal_False; +} + +//------------------------------------------------------------------------ +// Calc-Methoden +//------------------------------------------------------------------------ + +/************************************************************************* +|* +|* SwFrm::Prepare() +|* +|* Beschreibung Bereitet den Frm auf die 'Formatierung' (MakeAll()) +|* vor. Diese Methode dient dazu auf dem Stack Platz einzusparen, +|* denn zur Positionsberechnung des Frm muss sichergestellt sein, dass +|* die Position von Upper und Prev gueltig sind, mithin also ein +|* rekursiver Aufruf (Schleife waere relativ teuer, da selten notwendig). +|* Jeder Aufruf von MakeAll verbraucht aber ca. 500Byte Stack - +|* das Ende ist leicht abzusehen. _Prepare benoetigt nur wenig Stack, +|* deshalb solle der Rekursive Aufruf hier kein Problem sein. +|* Ein weiterer Vorteil ist, das eines schoenen Tages das _Prepare und +|* damit die Formatierung von Vorgaengern umgangen werden kann. +|* So kann evtl. mal 'schnell' an's Dokumentende gesprungen werden. +|* +|*************************************************************************/ +//Zwei kleine Freundschaften werden hier zu einem Geheimbund. +inline void PrepareLock( SwFlowFrm *pTab ) +{ + pTab->LockJoin(); +} +inline void PrepareUnlock( SwFlowFrm *pTab ) +{ + pTab->UnlockJoin(); + +} + +// hopefully, one day this function simply will return 'false' +bool lcl_IsCalcUpperAllowed( const SwFrm& rFrm ) +{ + return !rFrm.GetUpper()->IsSctFrm() && + !rFrm.GetUpper()->IsFooterFrm() && + // --> OD 2004-11-02 #i23129#, #i36347# - no format of upper Writer fly frame + !rFrm.GetUpper()->IsFlyFrm() && + // <-- + !( rFrm.GetUpper()->IsTabFrm() && rFrm.GetUpper()->GetUpper()->IsInTab() ) && + !( rFrm.IsTabFrm() && rFrm.GetUpper()->IsInTab() ); +} + +void SwFrm::PrepareMake() +{ + StackHack aHack; + if ( GetUpper() ) + { + if ( lcl_IsCalcUpperAllowed( *this ) ) + GetUpper()->Calc(); + OSL_ENSURE( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." ); + if ( !GetUpper() ) + return; + + const sal_Bool bCnt = IsCntntFrm(); + const sal_Bool bTab = IsTabFrm(); + sal_Bool bNoSect = IsInSct(); + sal_Bool bOldTabLock = sal_False, bFoll = sal_False; + SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL; + + if ( bTab ) + { + pThis = (SwTabFrm*)this; + bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked(); + ::PrepareLock( (SwTabFrm*)this ); + bFoll = pThis->IsFollow(); + } + else if( IsSctFrm() ) + { + pThis = (SwSectionFrm*)this; + bFoll = pThis->IsFollow(); + bNoSect = sal_False; + } + else if ( bCnt && sal_True == (bFoll = pThis->IsFollow()) && + GetPrev() ) + { + //Wenn der Master gereade ein CalcFollow ruft braucht die Kette + //nicht durchlaufen werden. Das spart Zeit und vermeidet Probleme. + if ( ((SwTxtFrm*)((SwTxtFrm*)this)->FindMaster())->IsLocked() ) + { + MakeAll(); + return; + } + } + + // --> OD 2005-03-04 #i44049# - no format of previous frame, if current + // frame is a table frame and its previous frame wants to keep with it. + const bool bFormatPrev = !bTab || + !GetPrev() || + !GetPrev()->GetAttrSet()->GetKeep().GetValue(); + if ( bFormatPrev ) + { + SwFrm *pFrm = GetUpper()->Lower(); + while ( pFrm != this ) + { + OSL_ENSURE( pFrm, ":-( Layoutgeruest wackelig (this not found)." ); + if ( !pFrm ) + return; //Oioioioi ... + + if ( !pFrm->IsValid() ) + { + //Ein kleiner Eingriff der hoffentlich etwas zur Verbesserung + //der Stabilitaet beitraegt: + //Wenn ich Follow _und_ Nachbar eines Frms vor mir bin, + //so wuerde dieser mich beim Formatieren deleten; wie jeder + //leicht sehen kann waere dies eine etwas unuebersichtliche + //Situation die es zu vermeiden gilt. + if ( bFoll && pFrm->IsFlowFrm() && + (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) ) + break; + + //MA: 24. Mar. 94, Calc wuerde doch nur wieder in ein _Prepare laufen und so + //die ganze Kette nocheinmal abhuenern. + // pFrm->Calc(); + pFrm->MakeAll(); + if( IsSctFrm() && !((SwSectionFrm*)this)->GetSection() ) + break; + } + //Die Kette kann bei CntntFrms waehrend des durchlaufens + //aufgebrochen werden, deshalb muss der Nachfolger etwas + //umstaendlich ermittelt werden. However, irgendwann _muss_ + //ich wieder bei mir selbst ankommen. + pFrm = pFrm->FindNext(); + + //Wenn wir in einem SectionFrm gestartet sind, koennen wir durch die + //MakeAll-Aufrufe in einen Section-Follow gewandert sein. + //FindNext liefert allerdings den SectionFrm, nicht seinen Inhalt. + // => wir finden uns selbst nicht mehr! + if( bNoSect && pFrm && pFrm->IsSctFrm() ) + { + SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pCnt ) + pFrm = pCnt; + } + } + OSL_ENSURE( GetUpper(), "Layoutgeruest wackelig (Upper wech II)." ); + if ( !GetUpper() ) + return; + + if ( lcl_IsCalcUpperAllowed( *this ) ) + GetUpper()->Calc(); + + OSL_ENSURE( GetUpper(), "Layoutgeruest wackelig (Upper wech III)." ); + } + + if ( bTab && !bOldTabLock ) + ::PrepareUnlock( (SwTabFrm*)this ); + } + MakeAll(); +} + +void SwFrm::OptPrepareMake() +{ + // --> OD 2004-11-02 #i23129#, #i36347# - no format of upper Writer fly frame + if ( GetUpper() && !GetUpper()->IsFooterFrm() && + !GetUpper()->IsFlyFrm() ) + // <-- + { + GetUpper()->Calc(); + OSL_ENSURE( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." ); + if ( !GetUpper() ) + return; + } + if ( GetPrev() && !GetPrev()->IsValid() ) + PrepareMake(); + else + { + StackHack aHack; + MakeAll(); + } +} + + + +void SwFrm::PrepareCrsr() +{ + StackHack aHack; + if( GetUpper() && !GetUpper()->IsSctFrm() ) + { + GetUpper()->PrepareCrsr(); + GetUpper()->Calc(); + + OSL_ENSURE( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." ); + if ( !GetUpper() ) + return; + + const sal_Bool bCnt = IsCntntFrm(); + const sal_Bool bTab = IsTabFrm(); + sal_Bool bNoSect = IsInSct(); + + sal_Bool bOldTabLock = sal_False, bFoll; + SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL; + + if ( bTab ) + { + bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked(); + ::PrepareLock( (SwTabFrm*)this ); + pThis = (SwTabFrm*)this; + } + else if( IsSctFrm() ) + { + pThis = (SwSectionFrm*)this; + bNoSect = sal_False; + } + bFoll = pThis && pThis->IsFollow(); + + SwFrm *pFrm = GetUpper()->Lower(); + while ( pFrm != this ) + { + OSL_ENSURE( pFrm, ":-( Layoutgeruest wackelig (this not found)." ); + if ( !pFrm ) + return; //Oioioioi ... + + if ( !pFrm->IsValid() ) + { + //Ein kleiner Eingriff der hoffentlich etwas zur Verbesserung + //der Stabilitaet beitraegt: + //Wenn ich Follow _und_ Nachbar eines Frms vor mir bin, + //so wuerde dieser mich beim Formatieren deleten; wie jeder + //leicht sehen kann waere dies eine etwas unuebersichtliche + //Situation die es zu vermeiden gilt. + if ( bFoll && pFrm->IsFlowFrm() && + (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) ) + break; + + pFrm->MakeAll(); + } + //Die Kette kann bei CntntFrms waehrend des durchlaufens + //aufgebrochen werden, deshalb muss der Nachfolger etwas + //umstaendlich ermittelt werden. However, irgendwann _muss_ + //ich wieder bei mir selbst ankommen. + pFrm = pFrm->FindNext(); + if( bNoSect && pFrm && pFrm->IsSctFrm() ) + { + SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pCnt ) + pFrm = pCnt; + } + } + OSL_ENSURE( GetUpper(), "Layoutgeruest wackelig (Upper wech II)." ); + if ( !GetUpper() ) + return; + + GetUpper()->Calc(); + + OSL_ENSURE( GetUpper(), "Layoutgeruest wackelig (Upper wech III)." ); + + if ( bTab && !bOldTabLock ) + ::PrepareUnlock( (SwTabFrm*)this ); + } + Calc(); +} + +/************************************************************************* +|* +|* SwFrm::MakePos() +|* +|*************************************************************************/ + +// Hier wird GetPrev() zurueckgegeben, allerdings werden +// dabei leere SectionFrms ueberlesen +SwFrm* lcl_Prev( SwFrm* pFrm, sal_Bool bSectPrv = sal_True ) +{ + SwFrm* pRet = pFrm->GetPrev(); + if( !pRet && pFrm->GetUpper() && pFrm->GetUpper()->IsSctFrm() && + bSectPrv && !pFrm->IsColumnFrm() ) + pRet = pFrm->GetUpper()->GetPrev(); + while( pRet && pRet->IsSctFrm() && + !((SwSectionFrm*)pRet)->GetSection() ) + pRet = pRet->GetPrev(); + return pRet; +} + +SwFrm* lcl_NotHiddenPrev( SwFrm* pFrm ) +{ + SwFrm *pRet = pFrm; + do + { + pRet = lcl_Prev( pRet ); + } while ( pRet && pRet->IsTxtFrm() && ((SwTxtFrm*)pRet)->IsHiddenNow() ); + return pRet; +} + +void SwFrm::MakePos() +{ + if ( !bValidPos ) + { + bValidPos = sal_True; + sal_Bool bUseUpper = sal_False; + SwFrm* pPrv = lcl_Prev( this ); + if ( pPrv && + ( !pPrv->IsCntntFrm() || + ( ((SwCntntFrm*)pPrv)->GetFollow() != this ) ) + ) + { + if ( !StackHack::IsLocked() && + ( !IsInSct() || IsSctFrm() ) && + !pPrv->IsSctFrm() && + !pPrv->GetAttrSet()->GetKeep().GetValue() + ) + { + pPrv->Calc(); //hierbei kann der Prev verschwinden! + } + else if ( pPrv->Frm().Top() == 0 ) + { + bUseUpper = sal_True; + } + } + + pPrv = lcl_Prev( this, sal_False ); + sal_uInt16 nMyType = GetType(); + SWRECTFN( ( IsCellFrm() && GetUpper() ? GetUpper() : this ) ) + if ( !bUseUpper && pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + if( FRM_NEIGHBOUR & nMyType ) + { + sal_Bool bR2L = IsRightToLeft(); + if( bR2L ) + (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() - + (aFrm.*fnRect->fnGetWidth)() ); + else + (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() + + (pPrv->Frm().*fnRect->fnGetWidth)() ); + + // cells may now leave their uppers + if( bVert && FRM_CELL & nMyType && !bReverse ) + aFrm.Pos().X() -= aFrm.Width() -pPrv->Frm().Width(); + } + else if( bVert && FRM_NOTE_VERT & nMyType ) + { + if( bReverse ) + aFrm.Pos().X() += pPrv->Frm().Width(); + else + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( bVertL2R ) + aFrm.Pos().X() += pPrv->Frm().Width(); + else + aFrm.Pos().X() -= aFrm.Width(); + } + } + else + aFrm.Pos().Y() += pPrv->Frm().Height(); + } + else if ( GetUpper() ) + { + // OD 15.10.2002 #103517# - add safeguard for <SwFooterFrm::Calc()> + // If parent frame is a footer frame and its <ColLocked()>, then + // do *not* calculate it. + // NOTE: Footer frame is <ColLocked()> during its + // <FormatSize(..)>, which is called from <Format(..)>, which + // is called from <MakeAll()>, which is called from <Calc()>. + // --> OD 2005-11-17 #i56850# + // - no format of upper Writer fly frame, which is anchored + // at-paragraph or at-character. + if ( !GetUpper()->IsTabFrm() && + !( IsTabFrm() && GetUpper()->IsInTab() ) && + !GetUpper()->IsSctFrm() && + !dynamic_cast<SwFlyAtCntFrm*>(GetUpper()) && + !( GetUpper()->IsFooterFrm() && + GetUpper()->IsColLocked() ) + ) + { + GetUpper()->Calc(); + } + // <-- + pPrv = lcl_Prev( this, sal_False ); + if ( !bUseUpper && pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + if( FRM_NEIGHBOUR & nMyType ) + { + sal_Bool bR2L = IsRightToLeft(); + if( bR2L ) + (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() - + (aFrm.*fnRect->fnGetWidth)() ); + else + (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() + + (pPrv->Frm().*fnRect->fnGetWidth)() ); + + // cells may now leave their uppers + if( bVert && FRM_CELL & nMyType && !bReverse ) + aFrm.Pos().X() -= aFrm.Width() -pPrv->Frm().Width(); + } + else if( bVert && FRM_NOTE_VERT & nMyType ) + { + if( bReverse ) + aFrm.Pos().X() += pPrv->Frm().Width(); + else + aFrm.Pos().X() -= aFrm.Width(); + } + else + aFrm.Pos().Y() += pPrv->Frm().Height(); + } + else + { + aFrm.Pos( GetUpper()->Frm().Pos() ); + aFrm.Pos() += GetUpper()->Prt().Pos(); + if( FRM_NEIGHBOUR & nMyType && IsRightToLeft() ) + { + if( bVert ) + aFrm.Pos().Y() += GetUpper()->Prt().Height() + - aFrm.Height(); + else + aFrm.Pos().X() += GetUpper()->Prt().Width() + - aFrm.Width(); + } + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + else if( bVert && !bVertL2R && FRM_NOTE_VERT & nMyType && !bReverse ) + aFrm.Pos().X() -= aFrm.Width() - GetUpper()->Prt().Width(); + } + } + else + aFrm.Pos().X() = aFrm.Pos().Y() = 0; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsBodyFrm() && bVert && !bVertL2R && !bReverse && GetUpper() ) + aFrm.Pos().X() += GetUpper()->Prt().Width() - aFrm.Width(); + bValidPos = sal_True; + } +} + +/************************************************************************* +|* +|* SwPageFrm::MakeAll() +|* +|*************************************************************************/ +// --> OD 2004-07-01 #i28701# - new type <SwSortedObjs> +void lcl_CheckObjects( SwSortedObjs* pSortedObjs, SwFrm* pFrm, long& rBot ) +{ + //Und dann kann es natuerlich noch Absatzgebundene + //Rahmen geben, die unterhalb ihres Absatzes stehen. + long nMax = 0; + for ( sal_uInt16 i = 0; i < pSortedObjs->Count(); ++i ) + { + // --> OD 2004-07-01 #i28701# - consider changed type of <SwSortedObjs> + // entries. + SwAnchoredObject* pObj = (*pSortedObjs)[i]; + long nTmp = 0; + if ( pObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pObj); + if( pFly->Frm().Top() != WEIT_WECH && + ( pFrm->IsPageFrm() ? pFly->IsFlyLayFrm() : + ( pFly->IsFlyAtCntFrm() && + ( pFrm->IsBodyFrm() ? pFly->GetAnchorFrm()->IsInDocBody() : + pFly->GetAnchorFrm()->IsInFtn() ) ) ) ) + { + nTmp = pFly->Frm().Bottom(); + } + } + else + nTmp = pObj->GetObjRect().Bottom(); + nMax = Max( nTmp, nMax ); + // <-- + } + ++nMax; //Unterkante vs. Hoehe! + rBot = Max( rBot, nMax ); +} + +void SwPageFrm::MakeAll() +{ + PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) + + const SwRect aOldRect( Frm() ); //Anpassung der Root-Groesse + const SwLayNotify aNotify( this ); //uebernimmt im DTor die Benachrichtigung + SwBorderAttrAccess *pAccess = 0; + const SwBorderAttrs*pAttrs = 0; + + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + if ( !bValidPos ) + { + // PAGES01 + bValidPos = sal_True; // positioning of the pages is taken care of by the root frame + } + + if ( !bValidSize || !bValidPrtArea ) + { + if ( IsEmptyPage() ) + { + Frm().Width( 0 ); Prt().Width( 0 ); + Frm().Height( 0 ); Prt().Height( 0 ); + Prt().Left( 0 ); Prt().Top( 0 ); + bValidSize = bValidPrtArea = sal_True; + } + else + { + if ( !pAccess ) + { + pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + //Bei der BrowseView gelten feste Einstellungen. + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() ); + const long nTop = pAttrs->CalcTopLine() + aBorder.Height(); + const long nBottom = pAttrs->CalcBottomLine()+ aBorder.Height(); + + long nWidth = GetUpper() ? ((SwRootFrm*)GetUpper())->GetBrowseWidth() : 0; + if ( nWidth < pSh->GetBrowseWidth() ) + nWidth = pSh->GetBrowseWidth(); + nWidth += + 2 * aBorder.Width(); +/* + long nWidth = GetUpper() ? ((SwRootFrm*)GetUpper())->GetBrowseWidth() + 2 * aBorder.Width() : 0; + if ( nWidth < pSh->VisArea().Width() ) + nWidth = pSh->VisArea().Width(); */ + + nWidth = Max( nWidth, 2L * aBorder.Width() + 4L*MM50 ); + Frm().Width( nWidth ); + + SwLayoutFrm *pBody = FindBodyCont(); + if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + { + //Fuer Spalten gilt eine feste Hoehe + Frm().Height( pAttrs->GetSize().Height() ); + } + else + { + //Fuer Seiten ohne Spalten bestimmt der Inhalt die + //Groesse. + long nBot = Frm().Top() + nTop; + SwFrm *pFrm = Lower(); + while ( pFrm ) + { + long nTmp = 0; + SwFrm *pCnt = ((SwLayoutFrm*)pFrm)->ContainsAny(); + while ( pCnt && (pCnt->GetUpper() == pFrm || + ((SwLayoutFrm*)pFrm)->IsAnLower( pCnt ))) + { + nTmp += pCnt->Frm().Height(); + if( pCnt->IsTxtFrm() && + ((SwTxtFrm*)pCnt)->IsUndersized() ) + nTmp += ((SwTxtFrm*)pCnt)->GetParHeight() + - pCnt->Prt().Height(); + else if( pCnt->IsSctFrm() && + ((SwSectionFrm*)pCnt)->IsUndersized() ) + nTmp += ((SwSectionFrm*)pCnt)->Undersize(); + pCnt = pCnt->FindNext(); + } + // OD 29.10.2002 #97265# - consider invalid body frame properties + if ( pFrm->IsBodyFrm() && + ( !pFrm->GetValidSizeFlag() || + !pFrm->GetValidPrtAreaFlag() ) && + ( pFrm->Frm().Height() < pFrm->Prt().Height() ) + ) + { + nTmp = Min( nTmp, pFrm->Frm().Height() ); + } + else + { + // OD 30.10.2002 #97265# - assert invalid lower property + OSL_ENSURE( !(pFrm->Frm().Height() < pFrm->Prt().Height()), + "SwPageFrm::MakeAll(): Lower with frame height < printing height" ); + nTmp += pFrm->Frm().Height() - pFrm->Prt().Height(); + } + if ( !pFrm->IsBodyFrm() ) + nTmp = Min( nTmp, pFrm->Frm().Height() ); + nBot += nTmp; + // Hier werden die absatzgebundenen Objekte ueberprueft, + // ob sie ueber den Body/FtnCont hinausragen. + if( pSortedObjs && !pFrm->IsHeaderFrm() && + !pFrm->IsFooterFrm() ) + lcl_CheckObjects( pSortedObjs, pFrm, nBot ); + pFrm = pFrm->GetNext(); + } + nBot += nBottom; + //Und die Seitengebundenen + if ( pSortedObjs ) + lcl_CheckObjects( pSortedObjs, this, nBot ); + nBot -= Frm().Top(); + // --> OD 2004-11-10 #i35143# - If second page frame + // exists, the first page doesn't have to fulfill the + // visible area. + if ( !GetPrev() && !GetNext() ) + // <-- + { + nBot = Max( nBot, pSh->VisArea().Height() ); + } + // --> OD 2004-11-10 #i35143# - Assure, that the page + // doesn't exceed the defined browse height. + Frm().Height( Min( nBot, BROWSE_HEIGHT ) ); + // <-- + } + Prt().Left ( pAttrs->CalcLeftLine() + aBorder.Width() ); + Prt().Top ( nTop ); + Prt().Width( Frm().Width() - ( Prt().Left() + + pAttrs->CalcRightLine() + aBorder.Width() ) ); + Prt().Height( Frm().Height() - (nTop + nBottom) ); + bValidSize = bValidPrtArea = sal_True; + } + else + { //FixSize einstellen, bei Seiten nicht vom Upper sondern vom + //Attribut vorgegeben. + Frm().SSize( pAttrs->GetSize() ); + Format( pAttrs ); + } + } + } + } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) + delete pAccess; + + // PAGES01 + if ( Frm() != aOldRect && GetUpper() ) + static_cast<SwRootFrm*>(GetUpper())->CheckViewLayout( 0, 0 ); + +#if OSL_DEBUG_LEVEL > 1 + //Der Upper (Root) muss mindestens so breit + //sein, dass er die breiteste Seite aufnehmen kann. + if ( GetUpper() ) + { + OSL_ENSURE( GetUpper()->Prt().Width() >= aFrm.Width(), "Rootsize" ); + } +#endif +} + +/************************************************************************* +|* +|* SwLayoutFrm::MakeAll() +|* +|*************************************************************************/ + + +void SwLayoutFrm::MakeAll() +{ + PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) + + //uebernimmt im DTor die Benachrichtigung + const SwLayNotify aNotify( this ); + sal_Bool bVert = IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = ( IsNeighbourFrm() == bVert )? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert ); + + SwBorderAttrAccess *pAccess = 0; + const SwBorderAttrs*pAttrs = 0; + + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + if ( !bValidPos ) + MakePos(); + + if ( GetUpper() ) + { + // NEW TABLES + if ( IsLeaveUpperAllowed() ) + { + if ( !bValidSize ) + bValidPrtArea = sal_False; + } + else + { + if ( !bValidSize ) + { + //FixSize einstellen, die VarSize wird von Format() nach + //Berechnung der PrtArea eingestellt. + bValidPrtArea = sal_False; + + SwTwips nPrtWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + if( bVert && ( IsBodyFrm() || IsFtnContFrm() ) ) + { + SwFrm* pNxt = GetPrev(); + while( pNxt && !pNxt->IsHeaderFrm() ) + pNxt = pNxt->GetPrev(); + if( pNxt ) + nPrtWidth -= pNxt->Frm().Height(); + pNxt = GetNext(); + while( pNxt && !pNxt->IsFooterFrm() ) + pNxt = pNxt->GetNext(); + if( pNxt ) + nPrtWidth -= pNxt->Frm().Height(); + } + + const long nDiff = nPrtWidth - (Frm().*fnRect->fnGetWidth)(); + + if( IsNeighbourFrm() && IsRightToLeft() ) + (Frm().*fnRect->fnSubLeft)( nDiff ); + else + (Frm().*fnRect->fnAddRight)( nDiff ); + } + else + { + // Don't leave your upper + const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if( (Frm().*fnRect->fnOverStep)( nDeadLine ) ) + bValidSize = sal_False; + } + } + } + if ( !bValidSize || !bValidPrtArea ) + { + if ( !pAccess ) + { + pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + Format( pAttrs ); + } + } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) + if ( pAccess ) + delete pAccess; +} + +/************************************************************************* +|* +|* SwCntntFrm::MakePrtArea() +|* +|*************************************************************************/ +bool SwTxtNode::IsCollapse() const +{ + if ( GetDoc()->get( IDocumentSettingAccess::COLLAPSE_EMPTY_CELL_PARA ) && GetTxt().Len()==0 ) { + sal_uLong nIdx=GetIndex(); + const SwEndNode *pNdBefore=GetNodes()[nIdx-1]->GetEndNode(); + const SwEndNode *pNdAfter=GetNodes()[nIdx+1]->GetEndNode(); + + // The paragraph is collapsed only if the NdAfter is the end of a cell + bool bInTable = this->FindTableNode( ) != NULL; + + SwSortedObjs* pObjs = this->getLayoutFrm( GetDoc()->GetCurrentLayout() )->GetDrawObjs( ); + sal_uInt32 nObjs = ( pObjs != NULL ) ? pObjs->Count( ) : 0; + + if ( pNdBefore!=NULL && pNdAfter!=NULL && nObjs == 0 && bInTable ) { + return true; + } else { + return false; + } + } else + return false; +} + +bool SwFrm::IsCollapse() const +{ + if (IsTxtFrm()) { + const SwTxtFrm *pTxtFrm=(SwTxtFrm*)this; + const SwTxtNode *pTxtNode=pTxtFrm->GetTxtNode(); + if (pTxtNode && pTxtNode->IsCollapse()) { + return true; + } else { + return false; + } + } else { + return false; + } +} + +sal_Bool SwCntntFrm::MakePrtArea( const SwBorderAttrs &rAttrs ) +{ + sal_Bool bSizeChgd = sal_False; + + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + + SWRECTFN( this ) + const sal_Bool bTxtFrm = IsTxtFrm(); + SwTwips nUpper = 0; + if ( bTxtFrm && ((SwTxtFrm*)this)->IsHiddenNow() ) + { + if ( ((SwTxtFrm*)this)->HasFollow() ) + ((SwTxtFrm*)this)->JoinFrm(); + + if( (Prt().*fnRect->fnGetHeight)() ) + ((SwTxtFrm*)this)->HideHidden(); + Prt().Pos().X() = Prt().Pos().Y() = 0; + (Prt().*fnRect->fnSetWidth)( (Frm().*fnRect->fnGetWidth)() ); + (Prt().*fnRect->fnSetHeight)( 0 ); + nUpper = -( (Frm().*fnRect->fnGetHeight)() ); + } + else + { + //Vereinfachung: CntntFrms sind immer in der Hoehe Variabel! + + //An der FixSize gibt der umgebende Frame die Groesse vor, die + //Raender werden einfach abgezogen. + const long nLeft = rAttrs.CalcLeft( this ); + const long nRight = ((SwBorderAttrs&)rAttrs).CalcRight( this ); + (this->*fnRect->fnSetXMargins)( nLeft, nRight ); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + SwTwips nWidthArea; + if( pSh && 0!=(nWidthArea=(pSh->VisArea().*fnRect->fnGetWidth)()) && + GetUpper()->IsPageBodyFrm() && // nicht dagegen bei BodyFrms in Columns + pSh->GetViewOptions()->getBrowseMode() ) + { + //Nicht ueber die Kante des sichbaren Bereiches hinausragen. + //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite" + //geben kann (RootFrm::ImplCalcBrowseWidth()) + long nMinWidth = 0; + + for (sal_uInt16 i = 0; GetDrawObjs() && i < GetDrawObjs()->Count();++i) + { + // --> OD 2004-07-01 #i28701# - consider changed type of + // <SwSortedObjs> entries + SwAnchoredObject* pObj = (*GetDrawObjs())[i]; + const SwFrmFmt& rFmt = pObj->GetFrmFmt(); + const sal_Bool bFly = pObj->ISA(SwFlyFrm); + if ((bFly && (WEIT_WECH == pObj->GetObjRect().Width())) + || rFmt.GetFrmSize().GetWidthPercent()) + { + continue; + } + + if ( FLY_AS_CHAR == rFmt.GetAnchor().GetAnchorId() ) + { + nMinWidth = Max( nMinWidth, + bFly ? rFmt.GetFrmSize().GetWidth() + : pObj->GetObjRect().Width() ); + } + // <-- + } + + const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() ); + long nWidth = nWidthArea - 2 * ( IsVertical() ? aBorder.Height() : aBorder.Width() ); + nWidth -= (Prt().*fnRect->fnGetLeft)(); + nWidth -= rAttrs.CalcRightLine(); + nWidth = Max( nMinWidth, nWidth ); + (Prt().*fnRect->fnSetWidth)( Min( nWidth, + (Prt().*fnRect->fnGetWidth)() ) ); + } + + if ( (Prt().*fnRect->fnGetWidth)() <= MINLAY ) + { + //Die PrtArea sollte schon wenigstens MINLAY breit sein, passend + //zu den Minimalwerten des UI + (Prt().*fnRect->fnSetWidth)( Min( long(MINLAY), + (Frm().*fnRect->fnGetWidth)() ) ); + SwTwips nTmp = (Frm().*fnRect->fnGetWidth)() - + (Prt().*fnRect->fnGetWidth)(); + if( (Prt().*fnRect->fnGetLeft)() > nTmp ) + (Prt().*fnRect->fnSetLeft)( nTmp ); + } + + //Fuer die VarSize gelten folgende Regeln: + //1. Der erste einer Kette hat keinen Rand nach oben + //2. Nach unten gibt es nie einen Rand + //3. Der Rand nach oben ist das Maximum aus dem Abstand des + // Prev nach unten und dem eigenen Abstand nach oben. + //Die drei Regeln werden auf die Berechnung der Freiraeume, die von + //UL- bzw. LRSpace vorgegeben werden, angewand. Es gibt in alle + //Richtungen jedoch ggf. trotzdem einen Abstand; dieser wird durch + //Umrandung und/oder Schatten vorgegeben. + //4. Der Abstand fuer TextFrms entspricht mindestens dem Durchschuss + + nUpper = CalcUpperSpace( &rAttrs, NULL ); + + SwTwips nLower = CalcLowerSpace( &rAttrs ); + if (IsCollapse()) { + nUpper=0; + nLower=0; + } +// // in balanced columned section frames we do not want the +// // common border +// sal_Bool bCommonBorder = sal_True; +// if ( IsInSct() && GetUpper()->IsColBodyFrm() ) +// { +// const SwSectionFrm* pSct = FindSctFrm(); +// bCommonBorder = pSct->GetFmt()->GetBalancedColumns().GetValue(); +// } +// SwTwips nLower = bCommonBorder ? +// rAttrs.GetBottomLine( this ) : +// rAttrs.CalcBottomLine(); + + (Prt().*fnRect->fnSetPosY)( (!bVert || bReverse) ? nUpper : nLower); + nUpper += nLower; + nUpper -= (Frm().*fnRect->fnGetHeight)() - + (Prt().*fnRect->fnGetHeight)(); + } + //Wenn Unterschiede zwischen Alter und neuer Groesse, + //Grow() oder Shrink() rufen + if ( nUpper ) + { + if ( nUpper > 0 ) + GrowFrm( nUpper ); + else + ShrinkFrm( -nUpper ); + bSizeChgd = sal_True; + } + } + return bSizeChgd; +} + +/************************************************************************* +|* +|* SwCntntFrm::MakeAll() +|* +|*************************************************************************/ + +#define STOP_FLY_FORMAT 10 +// --> OD 2006-09-25 #b6448963# - loop prevention +const int cnStopFormat = 15; +// <-- + +inline void ValidateSz( SwFrm *pFrm ) +{ + if ( pFrm ) + { + pFrm->bValidSize = sal_True; + pFrm->bValidPrtArea = sal_True; + } +} + +void SwCntntFrm::MakeAll() +{ + OSL_ENSURE( GetUpper(), "keinen Upper?" ); + OSL_ENSURE( IsTxtFrm(), "MakeAll(), NoTxt" ); + + if ( !IsFollow() && StackHack::IsLocked() ) + return; + + if ( IsJoinLocked() ) + return; + + OSL_ENSURE( !((SwTxtFrm*)this)->IsSwapped(), "Calculation of a swapped frame" ); + + StackHack aHack; + + if ( ((SwTxtFrm*)this)->IsLocked() ) + { + OSL_FAIL( "Format fuer gelockten TxtFrm." ); + return; + } + + LockJoin(); + long nFormatCount = 0; + // --> OD 2006-09-25 #b6448963# - loop prevention + int nConsequetiveFormatsWithoutChange = 0; + // <-- + PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) + +#if OSL_DEBUG_LEVEL > 1 + const SwDoc *pDoc = GetAttrSet()->GetDoc(); + if( pDoc ) + { + static sal_Bool bWarn = sal_False; + if( pDoc->InXMLExport() ) + { + OSL_ENSURE( bWarn, "Formatting during XML-export!" ); + bWarn = sal_True; + } + else + bWarn = sal_False; + } +#endif + + //uebernimmt im DTor die Benachrichtigung + SwCntntNotify *pNotify = new SwCntntNotify( this ); + + sal_Bool bMakePage = sal_True; //solange sal_True kann eine neue Seite + //angelegt werden (genau einmal) + sal_Bool bMovedBwd = sal_False; //Wird sal_True wenn der Frame zurueckfliesst + sal_Bool bMovedFwd = sal_False; //solange sal_False kann der Frm zurueck- + //fliessen (solange, bis er einmal + //vorwaerts ge'moved wurde). + sal_Bool bFormatted = sal_False; //Fuer die Witwen und Waisen Regelung + //wird der letzte CntntFrm einer Kette + //u.U. zum Formatieren angeregt, dies + //braucht nur einmal zu passieren. + //Immer wenn der Frm gemoved wird muss + //das Flag zurueckgesetzt werden. + sal_Bool bMustFit = sal_False; //Wenn einmal die Notbremse gezogen wurde, + //werden keine anderen Prepares mehr + //abgesetzt. + sal_Bool bFitPromise = sal_False; //Wenn ein Absatz nicht passte, mit WouldFit + //aber verspricht, dass er sich passend + //einstellt wird dieses Flag gesetzt. + //Wenn er dann sein Versprechen nicht haelt, + //kann kontrolliert verfahren werden. + sal_Bool bMoveable; + const sal_Bool bFly = IsInFly(); + const sal_Bool bTab = IsInTab(); + const sal_Bool bFtn = IsInFtn(); + const sal_Bool bSct = IsInSct(); + Point aOldFrmPos; //Damit bei Turnarounds jew. mit der + Point aOldPrtPos; //letzten Pos verglichen und geprueft + //werden kann, ob ein Prepare sinnvoll ist. + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + // OD 2004-02-26 #i25029# + if ( !IsFollow() && rAttrs.JoinedWithPrev( *(this) ) ) + { + pNotify->SetBordersJoinedWithPrev(); + } + + const sal_Bool bKeep = IsKeep( rAttrs.GetAttrSet() ); + + SwSaveFtnHeight *pSaveFtn = 0; + if ( bFtn ) + { + SwFtnFrm *pFtn = FindFtnFrm(); + SwSectionFrm* pSct = pFtn->FindSctFrm(); + if ( !((SwTxtFrm*)pFtn->GetRef())->IsLocked() ) + { + SwFtnBossFrm* pBoss = pFtn->GetRef()->FindFtnBossFrm( + pFtn->GetAttr()->GetFtn().IsEndNote() ); + if( !pSct || pSct->IsColLocked() || !pSct->Growable() ) + pSaveFtn = new SwSaveFtnHeight( pBoss, + ((SwTxtFrm*)pFtn->GetRef())->GetFtnLine( pFtn->GetAttr() ) ); + } + } + + // --> OD 2008-08-12 #b6732519# + if ( GetUpper()->IsSctFrm() && + HasFollow() && + GetFollow()->GetFrm() == GetNext() ) + { + dynamic_cast<SwTxtFrm*>(this)->JoinFrm(); + } + // <-- + + // --> OD 2004-06-23 #i28701# - move master forward, if it has to move, + // because of its object positioning. + if ( !static_cast<SwTxtFrm*>(this)->IsFollow() ) + { + sal_uInt32 nToPageNum = 0L; + const bool bMoveFwdByObjPos = SwLayouter::FrmMovedFwdByObjPos( + *(GetAttrSet()->GetDoc()), + *(static_cast<SwTxtFrm*>(this)), + nToPageNum ); + // --> OD 2006-01-27 #i58182# + // Also move a paragraph forward, which is the first one inside a table cell. + if ( bMoveFwdByObjPos && + FindPageFrm()->GetPhyPageNum() < nToPageNum && + ( lcl_Prev( this ) || + GetUpper()->IsCellFrm() || + ( GetUpper()->IsSctFrm() && + GetUpper()->GetUpper()->IsCellFrm() ) ) && + IsMoveable() ) + { + bMovedFwd = sal_True; + MoveFwd( bMakePage, sal_False ); + } + // <-- + } + // <-- + + //Wenn ein Follow neben seinem Master steht und nicht passt, kann er + //gleich verschoben werden. + if ( lcl_Prev( this ) && ((SwTxtFrm*)this)->IsFollow() && IsMoveable() ) + { + bMovedFwd = sal_True; + // OD 2004-03-02 #106629# - If follow frame is in table, it's master + // will be the last in the current table cell. Thus, invalidate the + // printing area of the master, + if ( IsInTab() ) + { + lcl_Prev( this )->InvalidatePrt(); + } + MoveFwd( bMakePage, sal_False ); + } + + // OD 08.11.2002 #104840# - check footnote content for forward move. + // If a content of a footnote is on a prior page/column as its invalid + // reference, it can be moved forward. + if ( bFtn && !bValidPos ) + { + SwFtnFrm* pFtn = FindFtnFrm(); + SwCntntFrm* pRefCnt = pFtn ? pFtn->GetRef() : 0; + if ( pRefCnt && !pRefCnt->IsValid() ) + { + SwFtnBossFrm* pFtnBossOfFtn = pFtn->FindFtnBossFrm(); + SwFtnBossFrm* pFtnBossOfRef = pRefCnt->FindFtnBossFrm(); + //<loop of movefwd until condition held or no move> + if ( pFtnBossOfFtn && pFtnBossOfRef && + pFtnBossOfFtn != pFtnBossOfRef && + pFtnBossOfFtn->IsBefore( pFtnBossOfRef ) ) + { + bMovedFwd = sal_True; + MoveFwd( bMakePage, sal_False ); + } + } + } + + SWRECTFN( this ) + + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + // --> OD 2006-09-25 #b6448963# - loop prevention + SwRect aOldFrm_StopFormat( Frm() ); + SwRect aOldPrt_StopFormat( Prt() ); + // <-- + if ( sal_True == (bMoveable = IsMoveable()) ) + { + SwFrm *pPre = GetIndPrev(); + if ( CheckMoveFwd( bMakePage, bKeep, bMovedBwd ) ) + { + SWREFRESHFN( this ) + bMovedFwd = sal_True; + if ( bMovedBwd ) + { + //Beim zurueckfliessen wurde der Upper angeregt sich + //vollstaendig zu Painten, dass koennen wir uns jetzt + //nach dem hin und her fliessen sparen. + GetUpper()->ResetCompletePaint(); + //Der Vorgaenger wurde Invalidiert, das ist jetzt auch obsolete. + OSL_ENSURE( pPre, "missing old Prev" ); + if( !pPre->IsSctFrm() ) + ::ValidateSz( pPre ); + } + bMoveable = IsMoveable(); + } + } + + aOldFrmPos = (Frm().*fnRect->fnGetPos)(); + aOldPrtPos = (Prt().*fnRect->fnGetPos)(); + + if ( !bValidPos ) + MakePos(); + + //FixSize einstellen, die VarSize wird von Format() justiert. + if ( !bValidSize ) + { + // --> OD 2006-01-03 #125452# + // invalidate printing area flag, if the following conditions are hold: + // - current frame width is 0. + // - current printing area width is 0. + // - frame width is adjusted to a value greater than 0. + // - printing area flag is sal_True. + // Thus, it's assured that the printing area is adjusted, if the + // frame area width changes its width from 0 to something greater + // than 0. + // Note: A text frame can be in such a situation, if the format is + // triggered by method call <SwCrsrShell::SetCrsr()> after + // loading the document. + const SwTwips nNewFrmWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + if ( bValidPrtArea && nNewFrmWidth > 0 && + (Frm().*fnRect->fnGetWidth)() == 0 && + (Prt().*fnRect->fnGetWidth)() == 0 ) + { + bValidPrtArea = sal_False; + } + + (Frm().*fnRect->fnSetWidth)( nNewFrmWidth ); + // <-- + } + if ( !bValidPrtArea ) + { + const long nOldW = (Prt().*fnRect->fnGetWidth)(); + // --> OD 2004-09-28 #i34730# - keep current frame height + const SwTwips nOldH = (Frm().*fnRect->fnGetHeight)(); + // <-- + MakePrtArea( rAttrs ); + if ( nOldW != (Prt().*fnRect->fnGetWidth)() ) + Prepare( PREP_FIXSIZE_CHG ); + // --> OD 2004-09-28 #i34730# - check, if frame height has changed. + // If yes, send a PREP_ADJUST_FRM and invalidate the size flag to + // force a format. The format will check in its method + // <SwTxtFrm::CalcPreps()>, if the already formatted lines still + // fit and if not, performs necessary actions. + // --> OD 2005-01-10 #i40150# - no check, if frame is undersized. + if ( bValidSize && !IsUndersized() && + nOldH != (Frm().*fnRect->fnGetHeight)() ) + { + // --> OD 2004-11-25 #115759# - no PREP_ADJUST_FRM and size + // invalidation, if height decreases only by the additional + // lower space as last content of a table cell and an existing + // follow containing one line exists. + const SwTwips nHDiff = nOldH - (Frm().*fnRect->fnGetHeight)(); + const bool bNoPrepAdjustFrm = + nHDiff > 0 && IsInTab() && GetFollow() && + ( 1 == static_cast<SwTxtFrm*>(GetFollow())->GetLineCount( STRING_LEN ) || (static_cast<SwTxtFrm*>(GetFollow())->Frm().*fnRect->fnGetWidth)() < 0 ) && + GetFollow()->CalcAddLowerSpaceAsLastInTableCell() == nHDiff; + if ( !bNoPrepAdjustFrm ) + { + Prepare( PREP_ADJUST_FRM ); + bValidSize = sal_False; + } + // <-- + } + // <-- + } + + //Damit die Witwen- und Waisen-Regelung eine Change bekommt muss der + //CntntFrm benachrichtigt werden. + //Kriterium: + //- Er muss Moveable sein (sonst mach das Spalten keinen Sinn.) + //- Er muss mit der Unterkante der PrtArea des Upper ueberlappen. + if ( !bMustFit ) + { + sal_Bool bWidow = sal_True; + const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if ( bMoveable && !bFormatted && ( GetFollow() || + ( (Frm().*fnRect->fnOverStep)( nDeadLine ) ) ) ) + { + Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False ); + bValidSize = bWidow = sal_False; + } + if( (Frm().*fnRect->fnGetPos)() != aOldFrmPos || + (Prt().*fnRect->fnGetPos)() != aOldPrtPos ) + { + // In diesem Prepare erfolgt ggf. ein _InvalidateSize(). + // bValidSize wird sal_False und das Format() wird gerufen. + Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ); + if ( bWidow && GetFollow() ) + { Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False ); + bValidSize = sal_False; + } + } + } + if ( !bValidSize ) + { + bValidSize = bFormatted = sal_True; + ++nFormatCount; + if( nFormatCount > STOP_FLY_FORMAT ) + SetFlyLock( sal_True ); + // --> OD 2006-09-25 #b6448963# - loop prevention + // No format any longer, if <cnStopFormat> consequetive formats + // without change occur. + if ( nConsequetiveFormatsWithoutChange <= cnStopFormat ) + { + Format(); + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OSL_FAIL( "debug assertion: <SwCntntFrm::MakeAll()> - format of text frame suppressed by fix b6448963" ); + } +#endif + // <-- + } + + //Wenn ich der erste einer Kette bin koennte ich mal sehen ob + //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll). + //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts + //geflossen sein. + sal_Bool bDummy; + if ( !lcl_Prev( this ) && + !bMovedFwd && + ( bMoveable || ( bFly && !bTab ) ) && + ( !bFtn || !GetUpper()->FindFtnFrm()->GetPrev() ) + && MoveBwd( bDummy ) ) + { + SWREFRESHFN( this ) + bMovedBwd = sal_True; + bFormatted = sal_False; + if ( bKeep && bMoveable ) + { + if( CheckMoveFwd( bMakePage, sal_False, bMovedBwd ) ) + { + bMovedFwd = sal_True; + bMoveable = IsMoveable(); + SWREFRESHFN( this ) + } + Point aOldPos = (Frm().*fnRect->fnGetPos)(); + MakePos(); + if( aOldPos != (Frm().*fnRect->fnGetPos)() ) + { + Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ); + if ( !bValidSize ) + { + (Frm().*fnRect->fnSetWidth)( (GetUpper()-> + Prt().*fnRect->fnGetWidth)() ); + if ( !bValidPrtArea ) + { + const long nOldW = (Prt().*fnRect->fnGetWidth)(); + MakePrtArea( rAttrs ); + if( nOldW != (Prt().*fnRect->fnGetWidth)() ) + Prepare( PREP_FIXSIZE_CHG, 0, sal_False ); + } + if( GetFollow() ) + Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False ); + bValidSize = bFormatted = sal_True; + Format(); + } + } + SwFrm *pNxt = HasFollow() ? NULL : FindNext(); + while( pNxt && pNxt->IsSctFrm() ) + { // Leere Bereiche auslassen, in die anderen hinein + if( ((SwSectionFrm*)pNxt)->GetSection() ) + { + SwFrm* pTmp = ((SwSectionFrm*)pNxt)->ContainsAny(); + if( pTmp ) + { + pNxt = pTmp; + break; + } + } + pNxt = pNxt->FindNext(); + } + if ( pNxt ) + { + pNxt->Calc(); + if( bValidPos && !GetIndNext() ) + { + SwSectionFrm *pSct = FindSctFrm(); + if( pSct && !pSct->GetValidSizeFlag() ) + { + SwSectionFrm* pNxtSct = pNxt->FindSctFrm(); + if( pNxtSct && pSct->IsAnFollow( pNxtSct ) ) + bValidPos = sal_False; + } + else + bValidPos = sal_False; + } + } + } + } + + //Der TxtFrm Validiert sich bei Fussnoten ggf. selbst, dass kann leicht + //dazu fuehren, dass seine Position obwohl unrichtig valide ist. + if ( bValidPos ) + { + // --> OD 2006-01-23 #i59341# + // Workaround for inadequate layout algorithm: + // suppress invalidation and calculation of position, if paragraph + // has formatted itself at least STOP_FLY_FORMAT times and + // has anchored objects. + // Thus, the anchored objects get the possibility to format itself + // and this probably solve the layout loop. + if ( bFtn && + nFormatCount <= STOP_FLY_FORMAT && + !GetDrawObjs() ) + // <-- + { + bValidPos = sal_False; + MakePos(); + aOldFrmPos = (Frm().*fnRect->fnGetPos)(); + aOldPrtPos = (Prt().*fnRect->fnGetPos)(); + } + } + + // --> OD 2006-09-25 #b6448963# - loop prevention + { + if ( aOldFrm_StopFormat == Frm() && + aOldPrt_StopFormat == Prt() ) + { + ++nConsequetiveFormatsWithoutChange; + } + else + { + nConsequetiveFormatsWithoutChange = 0; + } + } + // <-- + + //Wieder ein Wert ungueltig? - dann nochmal das ganze... + if ( !bValidPos || !bValidSize || !bValidPrtArea ) + continue; + + //Fertig? + // Achtung, wg. Hoehe==0, ist es besser statt Bottom() Top()+Height() zu nehmen + // (kommt bei Undersized TxtFrms an der Unterkante eines spaltigen Bereichs vor) + const long nPrtBottom = (GetUpper()->*fnRect->fnGetPrtBottom)(); + const long nBottomDist = (Frm().*fnRect->fnBottomDist)( nPrtBottom ); + if( nBottomDist >= 0 ) + { + if ( bKeep && bMoveable ) + { + //Wir sorgen dafuer, dass der Nachfolger gleich mit formatiert + //wird. Dadurch halten wir das Heft in der Hand, bis wirklich + //(fast) alles stabil ist. So vermeiden wir Endlosschleifen, + //die durch staendig wiederholte Versuche entstehen. + //Das bMoveFwdInvalid ist fuer #38407# notwendig. War urspruenglich + //in flowfrm.cxx rev 1.38 behoben, das unterbrach aber obiges + //Schema und spielte lieber Tuerme von Hanoi (#43669#). + SwFrm *pNxt = HasFollow() ? NULL : FindNext(); + // Bei Bereichen nehmen wir lieber den Inhalt, denn nur + // dieser kann ggf. die Seite wechseln + while( pNxt && pNxt->IsSctFrm() ) + { + if( ((SwSectionFrm*)pNxt)->GetSection() ) + { + pNxt = ((SwSectionFrm*)pNxt)->ContainsAny(); + break; + } + pNxt = pNxt->FindNext(); + } + if ( pNxt ) + { + const sal_Bool bMoveFwdInvalid = 0 != GetIndNext(); + const sal_Bool bNxtNew = + ( 0 == (pNxt->Prt().*fnRect->fnGetHeight)() ) && + (!pNxt->IsTxtFrm() ||!((SwTxtFrm*)pNxt)->IsHiddenNow()); + + pNxt->Calc(); + + if ( !bMovedBwd && + ((bMoveFwdInvalid && !GetIndNext()) || + bNxtNew) ) + { + if( bMovedFwd ) + pNotify->SetInvaKeep(); + bMovedFwd = sal_False; + } + } + } + continue; + } + + //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt + //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen + + //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe + //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man + //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und + //zwar mit aller Kraft. + if ( !bMoveable || IsUndersized() ) + { + if( !bMoveable && IsInTab() ) + { + long nDiff = -(Frm().*fnRect->fnBottomDist)( + (GetUpper()->*fnRect->fnGetPrtBottom)() ); + long nReal = GetUpper()->Grow( nDiff ); + if( nReal ) + continue; + } + break; + } + + //Wenn ich nun ueberhaupt ganz und garnicht in meinen Upper passe + //so kann die Situation vielleicht doch noch durch Aufbrechen + //aufgeklart werden. Diese Situation tritt bei einem frisch + //erzeugten Follow auf, der zwar auf die Folgeseite geschoben wurde + //aber selbst noch zu gross fuer diese ist; also wiederum + //aufgespalten werden muss. + //Wenn ich nicht passe und nicht Spaltbar (WouldFit()) bin, so schicke + //ich meinem TxtFrmanteil die Nachricht, dass eben falls moeglich + //trotz des Attributes 'nicht aufspalten' aufgespalten werden muss. + sal_Bool bMoveOrFit = sal_False; + sal_Bool bDontMoveMe = !GetIndPrev(); + if( bDontMoveMe && IsInSct() ) + { + SwFtnBossFrm* pBoss = FindFtnBossFrm(); + bDontMoveMe = !pBoss->IsInSct() || + ( !pBoss->Lower()->GetNext() && !pBoss->GetPrev() ); + } + + // Finally, we are able to split table rows. Therefore, bDontMoveMe + // can be set to sal_False: + if( bDontMoveMe && IsInTab() && + 0 != const_cast<SwCntntFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) ) + bDontMoveMe = sal_False; + + if ( bDontMoveMe && (Frm().*fnRect->fnGetHeight)() > + (GetUpper()->Prt().*fnRect->fnGetHeight)() ) + { + if ( !bFitPromise ) + { + SwTwips nTmp = (GetUpper()->Prt().*fnRect->fnGetHeight)() - + (Prt().*fnRect->fnGetTop)(); + sal_Bool bSplit = !IsFwdMoveAllowed(); + if ( nTmp > 0 && WouldFit( nTmp, bSplit, sal_False ) ) + { + Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False ); + bValidSize = sal_False; + bFitPromise = sal_True; + continue; + } + /* -------------------------------------------------- + * Frueher wurde in Rahmen und Bereichen niemals versucht, + * durch bMoveOrFit den TxtFrm unter Verzicht auf seine + * Attribute (Widows,Keep) doch noch passend zu bekommen. + * Dies haette zumindest bei spaltigen Rahmen versucht + * werden muessen, spaetestens bei verketteten Rahmen und + * in Bereichen muss es versucht werden. + * Ausnahme: Wenn wir im FormatWidthCols stehen, duerfen die + * Attribute nicht ausser Acht gelassen werden. + * --------------------------------------------------*/ + else if ( !bFtn && bMoveable && + ( !bFly || !FindFlyFrm()->IsColLocked() ) && + ( !bSct || !FindSctFrm()->IsColLocked() ) ) + bMoveOrFit = sal_True; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OSL_FAIL( "+TxtFrm hat WouldFit-Versprechen nicht eingehalten." ); + } +#endif + } + + //Mal sehen ob ich irgenwo Platz finde... + //Benachbarte Fussnoten werden in _MoveFtnCntFwd 'vorgeschoben' + SwFrm *pPre = GetIndPrev(); + SwFrm *pOldUp = GetUpper(); + +/* MA 13. Oct. 98: Was soll das denn sein!? + * AMA 14. Dec 98: Wenn ein spaltiger Bereich keinen Platz mehr fuer seinen ersten ContentFrm + * bietet, so soll dieser nicht nur in die naechste Spalte, sondern ggf. bis zur naechsten + * Seite wandern und dort einen Section-Follow erzeugen. + */ + if( IsInSct() && bMovedFwd && bMakePage && pOldUp->IsColBodyFrm() && + pOldUp->GetUpper()->GetUpper()->IsSctFrm() && + ( pPre || pOldUp->GetUpper()->GetPrev() ) && + ((SwSectionFrm*)pOldUp->GetUpper()->GetUpper())->MoveAllowed(this) ) + bMovedFwd = sal_False; + + const sal_Bool bCheckForGrownBody = pOldUp->IsBodyFrm(); + const long nOldBodyHeight = (pOldUp->Frm().*fnRect->fnGetHeight)(); + + if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) ) + bMakePage = sal_False; + SWREFRESHFN( this ) + + // If MoveFwd moves the paragraph to the next page, a following + // paragraph, which contains footnotes can can cause the old upper + // frame to grow. In this case we explicitely allow a new check + // for MoveBwd. Robust: We also check the bMovedBwd flag again. + // If pOldUp was a footnote frame, it has been deleted inside MoveFwd. + // Therefore we only check for growing body frames. + if ( bCheckForGrownBody && ! bMovedBwd && pOldUp != GetUpper() && + (pOldUp->Frm().*fnRect->fnGetHeight)() > nOldBodyHeight ) + bMovedFwd = sal_False; + else + bMovedFwd = sal_True; + + bFormatted = sal_False; + if ( bMoveOrFit && GetUpper() == pOldUp ) + { + // FME 2007-08-30 #i81146# new loop control + if ( nConsequetiveFormatsWithoutChange <= cnStopFormat ) + { + Prepare( PREP_MUST_FIT, 0, sal_False ); + bValidSize = sal_False; + bMustFit = sal_True; + continue; + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl in SwCntntFrm::MakeAll" ); +#endif + } + if ( bMovedBwd && GetUpper() ) + { //Unuetz gewordene Invalidierungen zuruecknehmen. + GetUpper()->ResetCompletePaint(); + if( pPre && !pPre->IsSctFrm() ) + ::ValidateSz( pPre ); + } + + } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) + + + // NEW: Looping Louie (Light). Should not be applied in balanced sections. + // Should only be applied if there is no better solution! + LOOPING_LOUIE_LIGHT( bMovedFwd && bMovedBwd && !IsInBalancedSection() && + ( + + // --> FME 2005-01-26 #118572# + ( bFtn && !FindFtnFrm()->GetRef()->IsInSct() ) || + // <-- + + // --> FME 2005-01-27 #i33887# + ( IsInSct() && bKeep ) + // <-- + + // ... add your conditions here ... + + ), + static_cast<SwTxtFrm&>(*this) ); + + + if ( pSaveFtn ) + delete pSaveFtn; + + UnlockJoin(); + if ( bMovedFwd || bMovedBwd ) + pNotify->SetInvaKeep(); + // OD 2004-02-26 #i25029# + if ( bMovedFwd ) + { + pNotify->SetInvalidatePrevPrtArea(); + } + delete pNotify; + SetFlyLock( sal_False ); +} + +/************************************************************************* +|* +|* SwCntntFrm::_WouldFit() +|* +|*************************************************************************/ + + + + +void MakeNxt( SwFrm *pFrm, SwFrm *pNxt ) +{ + //fix(25455): Validieren, sonst kommt es zu einer Rekursion. + //Der erste Versuch, der Abbruch mit pFrm = 0 wenn !Valid, + //fuehrt leider zu dem Problem, dass das Keep dann u.U. nicht mehr + //korrekt beachtet wird (27417) + const sal_Bool bOldPos = pFrm->GetValidPosFlag(); + const sal_Bool bOldSz = pFrm->GetValidSizeFlag(); + const sal_Bool bOldPrt = pFrm->GetValidPrtAreaFlag(); + pFrm->bValidPos = pFrm->bValidPrtArea = pFrm->bValidSize = sal_True; + + //fix(29272): Nicht MakeAll rufen, dort wird evtl. pFrm wieder invalidert + //und kommt rekursiv wieder herein. + if ( pNxt->IsCntntFrm() ) + { + SwCntntNotify aNotify( (SwCntntFrm*)pNxt ); + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + if ( !pNxt->GetValidSizeFlag() ) + { + if( pNxt->IsVertical() ) + pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() ); + else + pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() ); + } + ((SwCntntFrm*)pNxt)->MakePrtArea( rAttrs ); + pNxt->Format( &rAttrs ); + } + else + { + SwLayNotify aNotify( (SwLayoutFrm*)pNxt ); + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + if ( !pNxt->GetValidSizeFlag() ) + { + if( pNxt->IsVertical() ) + pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() ); + else + pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() ); + } + pNxt->Format( &rAttrs ); + } + + pFrm->bValidPos = bOldPos; + pFrm->bValidSize = bOldSz; + pFrm->bValidPrtArea = bOldPrt; +} + +// Diese Routine ueberprueft, ob zwischen dem FtnBoss von pFrm und dem +// von pNxt keine anderen FtnBosse liegen + +sal_Bool lcl_IsNextFtnBoss( const SwFrm *pFrm, const SwFrm* pNxt ) +{ + OSL_ENSURE( pFrm && pNxt, "lcl_IsNextFtnBoss: No Frames?" ); + pFrm = pFrm->FindFtnBossFrm(); + pNxt = pNxt->FindFtnBossFrm(); + // Falls pFrm eine letzte Spalte ist, wird stattdessen die Seite genommen + while( pFrm && pFrm->IsColumnFrm() && !pFrm->GetNext() ) + pFrm = pFrm->GetUpper()->FindFtnBossFrm(); + // Falls pNxt eine erste Spalte ist, wird stattdessen die Seite genommen + while( pNxt && pNxt->IsColumnFrm() && !pNxt->GetPrev() ) + pNxt = pNxt->GetUpper()->FindFtnBossFrm(); + // So, jetzt muessen pFrm und pNxt entweder zwei benachbarte Seiten oder Spalten sein. + return ( pFrm && pNxt && pFrm->GetNext() == pNxt ); +} + +// --> OD 2007-11-26 #b6614158# +sal_Bool SwCntntFrm::_WouldFit( SwTwips nSpace, + SwLayoutFrm *pNewUpper, + sal_Bool bTstMove, + const bool bObjsInNewUpper ) +// <-- +{ + //Damit die Fussnote sich ihren Platz sorgsam waehlt, muss + //sie in jedem Fall gemoved werden, wenn zwischen dem + //neuen Upper und ihrer aktuellen Seite/Spalte mindestens eine + //Seite/Spalte liegt. + SwFtnFrm* pFtnFrm = 0; + if ( IsInFtn() ) + { + if( !lcl_IsNextFtnBoss( pNewUpper, this ) ) + return sal_True; + pFtnFrm = FindFtnFrm(); + } + + sal_Bool bRet; + sal_Bool bSplit = !pNewUpper->Lower(); + SwCntntFrm *pFrm = this; + const SwFrm *pTmpPrev = pNewUpper->Lower(); + if( pTmpPrev && pTmpPrev->IsFtnFrm() ) + pTmpPrev = ((SwFtnFrm*)pTmpPrev)->Lower(); + while ( pTmpPrev && pTmpPrev->GetNext() ) + pTmpPrev = pTmpPrev->GetNext(); + do + { + // --> FME 2005-03-31 #b6236853# #i46181# + SwTwips nSecondCheck = 0; + SwTwips nOldSpace = nSpace; + sal_Bool bOldSplit = bSplit; + // <-- + + if ( bTstMove || IsInFly() || ( IsInSct() && + ( pFrm->GetUpper()->IsColBodyFrm() || ( pFtnFrm && + pFtnFrm->GetUpper()->GetUpper()->IsColumnFrm() ) ) ) ) + { + //Jetzt wirds ein bischen hinterlistig; empfindliche Gemueter sollten + //lieber wegsehen. Wenn ein Flys Spalten enthaelt so sind die Cntnts + //moveable, mit Ausnahme der in der letzten Spalte (siehe + //SwFrm::IsMoveable()). Zurueckfliessen duerfen sie aber natuerlich. + //Das WouldFit() liefert leider nur dann einen vernueftigen Wert, wenn + //der Frm moveable ist. Um dem WouldFit() einen Moveable Frm + //vorzugaukeln haenge ich ihn einfach solange um. + // Auch bei spaltigen Bereichen muss umgehaengt werden, damit + // SwSectionFrm::Growable() den richtigen Wert liefert. + // Innerhalb von Fussnoten muss ggf. sogar der SwFtnFrm umgehaengt werden, + // falls es dort keinen SwFtnFrm gibt. + SwFrm* pTmpFrm = pFrm->IsInFtn() && !pNewUpper->FindFtnFrm() ? + (SwFrm*)pFrm->FindFtnFrm() : pFrm; + SwLayoutFrm *pUp = pTmpFrm->GetUpper(); + SwFrm *pOldNext = pTmpFrm->GetNext(); + pTmpFrm->Remove(); + pTmpFrm->InsertBefore( pNewUpper, 0 ); + if ( pFrm->IsTxtFrm() && + ( bTstMove || + ((SwTxtFrm*)pFrm)->HasFollow() || + ( !((SwTxtFrm*)pFrm)->HasPara() && + !((SwTxtFrm*)pFrm)->IsEmpty() + ) + ) + ) + { + bTstMove = sal_True; + bRet = ((SwTxtFrm*)pFrm)->TestFormat( pTmpPrev, nSpace, bSplit ); + } + else + bRet = pFrm->WouldFit( nSpace, bSplit, sal_False ); + + pTmpFrm->Remove(); + pTmpFrm->InsertBefore( pUp, pOldNext ); + } + else + { + bRet = pFrm->WouldFit( nSpace, bSplit, sal_False ); + nSecondCheck = !bSplit ? 1 : 0; + } + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + //Bitter aber wahr: Der Abstand muss auch noch mit einkalkuliert werden. + //Bei TestFormatierung ist dies bereits geschehen. + if ( bRet && !bTstMove ) + { + SwTwips nUpper; + + if ( pTmpPrev ) + { + nUpper = CalcUpperSpace( NULL, pTmpPrev ); + + // in balanced columned section frames we do not want the + // common border + sal_Bool bCommonBorder = sal_True; + if ( pFrm->IsInSct() && pFrm->GetUpper()->IsColBodyFrm() ) + { + const SwSectionFrm* pSct = pFrm->FindSctFrm(); + bCommonBorder = pSct->GetFmt()->GetBalancedColumns().GetValue(); + } + + // --> FME 2005-03-31 #b6236853# #i46181# + nSecondCheck = ( 1 == nSecondCheck && + pFrm == this && + IsTxtFrm() && + bCommonBorder && + !static_cast<const SwTxtFrm*>(this)->IsEmpty() ) ? + nUpper : + 0; + // <-- + + nUpper += bCommonBorder ? + rAttrs.GetBottomLine( *(pFrm) ) : + rAttrs.CalcBottomLine(); + + } + else + { + // --> FME 2005-03-31 #b6236853# #i46181# + nSecondCheck = 0; + // <-- + + if( pFrm->IsVertical() ) + nUpper = pFrm->Frm().Width() - pFrm->Prt().Width(); + else + nUpper = pFrm->Frm().Height() - pFrm->Prt().Height(); + } + + nSpace -= nUpper; + + if ( nSpace < 0 ) + { + bRet = sal_False; + + // --> FME 2005-03-31 #b6236853# #i46181# + if ( nSecondCheck > 0 ) + { + // The following code is indented to solve a (rare) problem + // causing some frames not to move backward: + // SwTxtFrm::WouldFit() claims that the whole paragraph + // fits into the given space and subtracts the height of + // all lines from nSpace. nSpace - nUpper is not a valid + // indicator if the frame should be allowed to move backward. + // We do a second check with the original remaining space + // reduced by the required upper space: + nOldSpace -= nSecondCheck; + const bool bSecondRet = nOldSpace >= 0 && pFrm->WouldFit( nOldSpace, bOldSplit, sal_False ); + if ( bSecondRet && bOldSplit && nOldSpace >= 0 ) + { + bRet = sal_True; + bSplit = sal_True; + } + } + // <-- + } + } + + // OD 2004-03-01 #106629# - also consider lower spacing in table cells + if ( bRet && IsInTab() && + pNewUpper->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) ) + { + nSpace -= rAttrs.GetULSpace().GetLower(); + if ( nSpace < 0 ) + { + bRet = sal_False; + } + } + + if ( bRet && !bSplit && pFrm->IsKeep( rAttrs.GetAttrSet() ) ) + { + if( bTstMove ) + { + while( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->HasFollow() ) + { + pFrm = ((SwTxtFrm*)pFrm)->GetFollow(); + } + // OD 11.04.2003 #108824# - If last follow frame of <this> text + // frame isn't valid, a formatting of the next content frame + // doesn't makes sense. Thus, return sal_True. + if ( IsAnFollow( pFrm ) && !pFrm->IsValid() ) + { + OSL_FAIL( "Only a warning for task 108824:/n<SwCntntFrm::_WouldFit(..) - follow not valid!" ); + return sal_True; + } + } + SwFrm *pNxt; + if( 0 != (pNxt = pFrm->FindNext()) && pNxt->IsCntntFrm() && + ( !pFtnFrm || ( pNxt->IsInFtn() && + pNxt->FindFtnFrm()->GetAttr() == pFtnFrm->GetAttr() ) ) ) + { + // ProbeFormatierung vertraegt keine absatz- oder gar zeichengebundene Objekte + // --> OD 2007-11-26 #b6614158# + // current solution for the test formatting doesn't work, if + // objects are present in the remaining area of the new upper + if ( bTstMove && + ( pNxt->GetDrawObjs() || bObjsInNewUpper ) ) + { + return sal_True; + } + // <-- + + if ( !pNxt->IsValid() ) + MakeNxt( pFrm, pNxt ); + + //Kleiner Trick: Wenn der naechste einen Vorgaenger hat, so hat + //er den Absatzabstand bereits berechnet. Er braucht dann nicht + //teuer kalkuliert werden. + if( lcl_NotHiddenPrev( pNxt ) ) + pTmpPrev = 0; + else + { + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow() ) + pTmpPrev = lcl_NotHiddenPrev( pFrm ); + else + pTmpPrev = pFrm; + } + pFrm = (SwCntntFrm*)pNxt; + } + else + pFrm = 0; + } + else + pFrm = 0; + + } while ( bRet && pFrm ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/colfrm.cxx b/sw/source/core/layout/colfrm.cxx new file mode 100644 index 000000000000..5e9aa78fdb59 --- /dev/null +++ b/sw/source/core/layout/colfrm.cxx @@ -0,0 +1,478 @@ +/* -*- 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 "cntfrm.hxx" +#include "doc.hxx" + +#include "hintids.hxx" +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <fmtclds.hxx> +#include <fmtfordr.hxx> +#include <frmfmt.hxx> +#include <node.hxx> +#include "frmtool.hxx" +#include "colfrm.hxx" +#include "pagefrm.hxx" +#include "bodyfrm.hxx" // ColumnFrms jetzt mit BodyFrm +#include "rootfrm.hxx" // wg. RemoveFtns +#include "sectfrm.hxx" // wg. FtnAtEnd-Flag +#include "switerator.hxx" + +// ftnfrm.cxx: +void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes ); + + +/************************************************************************* +|* +|* SwColumnFrm::SwColumnFrm() +|* +|*************************************************************************/ +SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ): + SwFtnBossFrm( pFmt, pSib ) +{ + nType = FRMC_COLUMN; + SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib ); + pColBody->InsertBehind( this, 0 ); // ColumnFrms jetzt mit BodyFrm + SetMaxFtnHeight( LONG_MAX ); +} + +SwColumnFrm::~SwColumnFrm() +{ + SwFrmFmt *pFmt = GetFmt(); + SwDoc *pDoc; + if ( !(pDoc = pFmt->GetDoc())->IsInDtor() && pFmt->IsLastDepend() ) + { + //Ich bin der einzige, weg mit dem Format. + //Vorher ummelden, damit die Basisklasse noch klarkommt. + pDoc->GetDfltFrmFmt()->Add( this ); + pDoc->DelFrmFmt( pFmt ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::ChgColumns() +|* +|*************************************************************************/ + +void MA_FASTCALL lcl_RemoveColumns( SwLayoutFrm *pCont, sal_uInt16 nCnt ) +{ + OSL_ENSURE( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(), + "Keine Spalten zu entfernen." ); + + SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower(); + ::lcl_RemoveFtns( pColumn, sal_True, sal_True ); + while ( pColumn->GetNext() ) + { + OSL_ENSURE( pColumn->GetNext()->IsColumnFrm(), + "Nachbar von ColFrm kein ColFrm." ); + pColumn = (SwColumnFrm*)pColumn->GetNext(); + } + for ( sal_uInt16 i = 0; i < nCnt; ++i ) + { + SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev(); + pColumn->Cut(); + delete pColumn; //Format wird ggf. im DTor mit vernichtet. + pColumn = pTmp; + } +} + +SwLayoutFrm * MA_FASTCALL lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount ) +{ + SwFrm *pCol = pLay->Lower(); + if ( pLay->IsPageFrm() ) + pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower(); + + if ( pCol && pCol->IsColumnFrm() ) + { + SwFrm *pTmp = pCol; + sal_uInt16 i; + for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i ) + /* do nothing */; + return i == nCount ? (SwLayoutFrm*)pCol : 0; + } + return 0; +} + + +static sal_Bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount ) +{ + SwDoc *pDoc = pCont->GetFmt()->GetDoc(); + const sal_Bool bMod = pDoc->IsModified(); + + //Format sollen soweit moeglich geshared werden. Wenn es also schon einen + //Nachbarn mit den selben Spalteneinstellungen gibt, so koennen die + //Spalten an die selben Formate gehaengt werden. + //Der Nachbar kann ueber das Format gesucht werden, wer der Owner des Attributes + //ist, ist allerdings vom Frametyp abhaengig. + SwLayoutFrm *pAttrOwner = pCont; + if ( pCont->IsBodyFrm() ) + pAttrOwner = pCont->FindPageFrm(); + SwLayoutFrm *pNeighbourCol = 0; + SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() ); + SwLayoutFrm *pNeighbour = aIter.First(); + + sal_uInt16 nAdd = 0; + SwFrm *pCol = pCont->Lower(); + if ( pCol && pCol->IsColumnFrm() ) + for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd ) + /* do nothing */; + while ( pNeighbour ) + { + if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) && + pNeighbourCol != pCont ) + break; + pNeighbourCol = 0; + pNeighbour = aIter.Next(); + } + + sal_Bool bRet; + SwTwips nMax = pCont->IsPageBodyFrm() ? + pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX; + if ( pNeighbourCol ) + { + bRet = sal_False; + SwFrm *pTmp = pCont->Lower(); + while ( pTmp ) + { + pTmp = pTmp->GetNext(); + pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); + } + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont ); + pTmpCol->SetMaxFtnHeight( nMax ); + pTmpCol->InsertBefore( pCont, NULL ); + pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); + } + } + else + { + bRet = sal_True; + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyStr, pDoc->GetDfltFrmFmt()); + SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont ); + pTmp->SetMaxFtnHeight( nMax ); + pTmp->Paste( pCont ); + } + } + + if ( !bMod ) + pDoc->ResetModified(); + return bRet; +} + +/*-------------------------------------------------- + * ChgColumns() adds or removes columns from a layoutframe. + * Normally, a layoutframe with a column attribut of 1 or 0 columns contains + * no columnframe. However, a sectionframe with "footnotes at the end" needs + * a columnframe. If the bChgFtn-flag is set, the columnframe will be inserted + * or remove, if necessary. + * --------------------------------------------------*/ + +void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew, + const sal_Bool bChgFtn ) +{ + if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn ) + return; + // --> OD 2009-08-12 #i97379# + // If current lower is a no text frame, then columns are not allowed + if ( Lower() && Lower()->IsNoTxtFrm() && + rNew.GetNumCols() > 1 ) + { + return; + } + // <-- + + sal_uInt16 nNewNum, nOldNum = 1; + if( Lower() && Lower()->IsColumnFrm() ) + { + SwFrm* pCol = Lower(); + while( 0 != (pCol=pCol->GetNext()) ) + ++nOldNum; + } + nNewNum = rNew.GetNumCols(); + if( !nNewNum ) + ++nNewNum; + sal_Bool bAtEnd; + if( IsSctFrm() ) + bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd(); + else + bAtEnd = sal_False; + + //Einstellung der Spaltenbreiten ist nur bei neuen Formaten notwendig. + sal_Bool bAdjustAttributes = nOldNum != rOld.GetNumCols(); + + //Wenn die Spaltenanzahl unterschiedlich ist, wird der Inhalt + //gesichert und restored. + SwFrm *pSave = 0; + if( nOldNum != nNewNum || bChgFtn ) + { + SwDoc *pDoc = GetFmt()->GetDoc(); + OSL_ENSURE( pDoc, "FrmFmt gibt kein Dokument her." ); + // SaveCntnt wuerde auch den Inhalt der Fussnotencontainer aufsaugen + // und im normalen Textfluss unterbringen. + if( IsPageBodyFrm() ) + pDoc->GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), sal_True, sal_False ); //swmod 080218 + pSave = ::SaveCntnt( this ); + + //Wenn Spalten existieren, jetzt aber eine Spaltenanzahl von + //0 oder eins gewuenscht ist, so werden die Spalten einfach vernichtet. + if ( nNewNum == 1 && !bAtEnd ) + { + ::lcl_RemoveColumns( this, nOldNum ); + if ( IsBodyFrm() ) + SetFrmFmt( pDoc->GetDfltFrmFmt() ); + else + GetFmt()->SetFmtAttr( SwFmtFillOrder() ); + if ( pSave ) + ::RestoreCntnt( pSave, this, 0, true ); + return; + } + if ( nOldNum == 1 ) + { + if ( IsBodyFrm() ) + SetFrmFmt( pDoc->GetColumnContFmt() ); + else + GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) ); + if( !Lower() || !Lower()->IsColumnFrm() ) + --nOldNum; + } + if ( nOldNum > nNewNum ) + { + ::lcl_RemoveColumns( this, nOldNum - nNewNum ); + bAdjustAttributes = sal_True; + } + else if( nOldNum < nNewNum ) + { + sal_uInt16 nAdd = nNewNum - nOldNum; + bAdjustAttributes = lcl_AddColumns( this, nAdd ); + } + } + + if ( !bAdjustAttributes ) + { + if ( rOld.GetLineWidth() != rNew.GetLineWidth() || + rOld.GetWishWidth() != rNew.GetWishWidth() || + rOld.IsOrtho() != rNew.IsOrtho() ) + bAdjustAttributes = sal_True; + else + { + sal_uInt16 nCount = Min( rNew.GetColumns().Count(), rOld.GetColumns().Count() ); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + if ( !(*rOld.GetColumns()[i] == *rNew.GetColumns()[i]) ) + { + bAdjustAttributes = sal_True; + break; + } + } + } + + //Sodele, jetzt koennen die Spalten bequem eingestellt werden. + AdjustColumns( &rNew, bAdjustAttributes ); + + //Erst jetzt den Inhalt restaurieren. Ein frueheres Restaurieren wuerde + //unnuetzte Aktionen beim Einstellen zur Folge haben. + if ( pSave ) + { + OSL_ENSURE( Lower() && Lower()->IsLayoutFrm() && + ((SwLayoutFrm*)Lower())->Lower() && + ((SwLayoutFrm*)Lower())->Lower()->IsLayoutFrm(), + "Gesucht: Spaltenbody (Tod oder Lebend)." ); // ColumnFrms jetzt mit BodyFrm + ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::AdjustColumns() +|* +|*************************************************************************/ + +void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, sal_Bool bAdjustAttributes ) +{ + if( !Lower()->GetNext() ) + { + Lower()->ChgSize( Prt().SSize() ); + return; + } + + const sal_Bool bVert = IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + + //Ist ein Pointer da, oder sollen wir die Attribute einstellen, + //so stellen wir auf jeden Fall die Spaltenbreiten ein. Andernfalls + //checken wir, ob eine Einstellung notwendig ist. + if ( !pAttr ) + { + pAttr = &GetFmt()->GetCol(); + if ( !bAdjustAttributes ) + { + long nAvail = (Prt().*fnRect->fnGetWidth)(); + for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower(); + pCol; + pCol = (SwLayoutFrm*)pCol->GetNext() ) + nAvail -= (pCol->Frm().*fnRect->fnGetWidth)(); + if ( !nAvail ) + return; + } + } + + //Sodele, jetzt koennen die Spalten bequem eingestellt werden. + //Die Breiten werden mitgezaehlt, damit wir dem letzten den Rest geben + //koennen. + SwTwips nAvail = (Prt().*fnRect->fnGetWidth)(); + const sal_Bool bLine = pAttr->GetLineAdj() != COLADJ_NONE; + const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0; + + const sal_Bool bR2L = IsRightToLeft(); + SwFrm *pCol = bR2L ? GetLastLower() : Lower(); + + // --> FME 2004-07-16 #i27399# + // bOrtho means we have to adjust the column frames manually. Otherwise + // we may use the values returned by CalcColWidth: + const sal_Bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0; + long nGutter = 0; + // <-- + + for ( sal_uInt16 i = 0; i < pAttr->GetNumCols(); ++i ) + { + if( !bOrtho ) + { + const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ? + nAvail : + pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) ); + + const Size aColSz = bVert ? + Size( Prt().Width(), nWidth ) : + Size( nWidth, Prt().Height() ); + + pCol->ChgSize( aColSz ); + + // Hierdurch werden die ColumnBodyFrms von Seitenspalten angepasst und + // ihr bFixHeight-Flag wird gesetzt, damit sie nicht schrumpfen/wachsen. + // Bei Rahmenspalten hingegen soll das Flag _nicht_ gesetzt werden, + // da BodyFrms in Rahmenspalten durchaus wachsen/schrumpfen duerfen. + if( IsBodyFrm() ) + ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); + + nAvail -= nWidth; + } + + if ( bOrtho || bAdjustAttributes ) + { + const SwColumn *pC = pAttr->GetColumns()[i]; + const SwAttrSet* pSet = pCol->GetAttrSet(); + SvxLRSpaceItem aLR( pSet->GetLRSpace() ); + + //Damit die Trennlinien Platz finden, muessen sie hier + //Beruecksichtigung finden. Ueberall wo zwei Spalten aufeinanderstossen + //wird jeweils rechts bzw. links ein Sicherheitsabstand von 20 plus + //der halben Penbreite einkalkuliert. + const sal_uInt16 nLeft = pC->GetLeft(); + const sal_uInt16 nRight = pC->GetRight(); + + aLR.SetLeft ( nLeft ); + aLR.SetRight( nRight ); + + if ( bLine ) + { + if ( i == 0 ) + { + aLR.SetRight( Max( nRight, nMin ) ); + } + else if ( i == pAttr->GetNumCols() - 1 ) + { + aLR.SetLeft ( Max( nLeft, nMin ) ); + } + else + { + aLR.SetLeft ( Max( nLeft, nMin ) ); + aLR.SetRight( Max( nRight, nMin ) ); + } + } + + if ( bAdjustAttributes ) + { + SvxULSpaceItem aUL( pSet->GetULSpace() ); + aUL.SetUpper( pC->GetUpper()); + aUL.SetLower( pC->GetLower()); + + ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR ); + ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL ); + } + + nGutter += aLR.GetLeft() + aLR.GetRight(); + } + + pCol = bR2L ? pCol->GetPrev() : pCol->GetNext(); + } + + if( bOrtho ) + { + long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols(); + pCol = Lower(); + for( sal_uInt16 i = 0; i < pAttr->GetNumCols(); pCol = pCol->GetNext(), ++i ) + { + SwTwips nWidth; + if ( i == pAttr->GetNumCols() - 1 ) + nWidth = nAvail; + else + { + SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() ); + nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight(); + } + if( nWidth < 0 ) + nWidth = 0; + + const Size aColSz = bVert ? + Size( Prt().Width(), nWidth ) : + Size( nWidth, Prt().Height() ); + + pCol->ChgSize( aColSz ); + + if( IsBodyFrm() ) + ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); + + nAvail -= nWidth; + } + } +} + + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/dbg_lay.cxx b/sw/source/core/layout/dbg_lay.cxx new file mode 100644 index 000000000000..8f70b6925a0a --- /dev/null +++ b/sw/source/core/layout/dbg_lay.cxx @@ -0,0 +1,868 @@ +/* -*- 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" + +#if OSL_DEBUG_LEVEL > 1 + +/* + * Und hier die Beschreibung: + * + * Durch die PROTOCOL-Makros wird es ermoeglicht, Ereignisse im Frame-Methoden zu protokollieren. + * In protokollwuerdigen Stellen in Frame-Methoden muss entweder ein PROTOCOL(...) oder bei Methoden, + * bei denen auch das Verlassen der Methode mitprotokolliert werden soll, ein PROTOCOL_ENTER(...)-Makro + * stehen. + * Die Parameter der PROTOCOL-Makros sind + * 1. Ein Pointer auf einen SwFrm, also meist "this" oder "rThis" + * 2. Die Funktionsgruppe z.B. PROT_MAKEALL, hierueber wird (inline) entschieden, ob dies + * zur Zeit protokolliert werden soll oder nicht. + * 3. Die Aktion, im Normalfall 0, aber z.B. ein ACT_START bewirkt eine Einrueckung in der + * Ausgabedatei, ein ACT_END nimmt dies wieder zurueck. Auf diese Art wird z.B. durch + * PROTOCOL_ENTER am Anfang einer Methode eingerueckt und beim Verlassen wieder zurueck. + * 4. Der vierte Parameter ist ein void-Pointer, damit man irgendetwas uebergeben kann, + * was in das Protokoll einfliessen kann, typesches Beispiel bei PROT_GROW muss man + * einen Pointer auf den Wert, um den gegrowt werden soll, uebergeben. + * + * + * Das Protokoll ist die Datei "dbg_lay.out" im aktuellen (BIN-)Verzeichnis. + * Es enthaelt Zeilen mit FrmId, Funktionsgruppe sowie weiteren Infos. + * + * Was genau protokolliert wird, kann auf folgende Arten eingestellt werden: + * 1. Die statische Variable SwProtokoll::nRecord enthaelt die Funktionsgruppen, + * die aufgezeichnet werden sollen. + * Ein Wert von z.B. PROT_GROW bewirkt, das Aufrufe von SwFrm::Grow dokumentiert werden, + * PROT_MAKEALL protokolliert Aufrufe von xxx::MakeAll. + * Die PROT_XY-Werte koennen oderiert werden. + * Default ist Null, es wird keine Methode aufgezeichnet. + * 2. In der SwImplProtocol-Klasse gibt es einen Filter fuer Frame-Typen, + * nur die Methodenaufrufe von Frame-Typen, die dort gesetzt sind, werden protokolliert. + * Der Member nTypes kann auf Werte wie FRM_PAGE, FRM_SECTION gesetzt und oderiert werden. + * Default ist 0xFFFF, d.h. alle Frame-Typen. + * 3. In der SwImplProtocol-Klasse gibt es einen ArrayPointer auf FrmIds, die zu ueberwachen sind. + * Ist der Pointer Null, so werden alle Frames protokolliert, ansonsten nur Frames, + * die in dem Array vermerkt sind. + * + * Eine Aufzeichnung in Gang zu setzen, erfordert entweder Codemanipulation, z.B. in + * SwProtocol::Init() einen anderen Default fuer nRecord setzen oder Debuggermanipulation. + * Im Debugger gibt verschiedene, sich anbietende Stellen: + * 1. In SwProtocol::Init() einen Breakpoint setzen und dort nRecord manipulieren, ggf. + * FrmIds eintragen, dann beginnt die Aufzeichnung bereits beim Programmstart. + * 2. Waehrend des Programmlaufs einen Breakpoint vor irgendein PROTOCOL oder PROTOCOL_ENTER- + * Makro setzen, dann am SwProtocol::nRecord das unterste Bit setzen (PROT_INIT). Dies + * bewirkt, dass die Funktionsgruppe des folgenden Makros aktiviert und in Zukunft + * protokolliert wird. + * 3. Spezialfall von 2.: Wenn man 2. in der Methode SwRootFrm::Paint(..) anwendet, werden + * die Aufzeichnungseinstellung aus der Datei "dbg_lay.ini" ausgelesen! + * In dieser INI-Datei kann es Kommentarzeilen geben, diese beginnen mit '#', dann + * sind die Sektionen "[frmid]", "[frmtype]" und "[record]" relevant. + * Nach [frmid] koennen die FrameIds der zu protokollierenden Frames folgen. Gibt es + * dort keine Eintraege, werden alle Frames aufgezeichnet. + * Nach [frmtype] koennen FrameTypen folgen, die aufgezeichnet werden sollen, da der + * Default hier allerdings USHRT_MAX ist, werden sowieso alle aufgezeichnet. Man kann + * allerdings auch Typen entfernen, in dem man ein '!' vor den Wert setzt, z.B. + * !0xC000 nimmt die SwCntntFrms aus der Aufzeichnung heraus. + * Nach [record] folgen die Funktionsgruppen, die aufgezeichnet werden sollen, Default + * ist hier 0, also keine. Auch hier kann man mit einem vorgestellten '!' Funktionen + * wieder entfernen. + * Hier mal ein Beispiel fuer eine INI-Datei: + * ------------------------------------------ + * #Funktionen: Alle, ausser PRTAREA + * [record] 0xFFFFFFE !0x200 + * [frmid] + * #folgende FrmIds: + * 1 2 12 13 14 15 + * #keine Layoutframes ausser ColumnFrms + * [frmtype] !0x3FFF 0x4 + * ------------------------------------------ + * + * Wenn die Aufzeichnung erstmal laeuft, kann man in SwImplProtocol::_Record(...) mittels + * Debugger vielfaeltige Manipulationen vornehmen, z.B. bezueglich FrameTypen oder FrmIds. + * + * --------------------------------------------------*/ + +#if !defined(OSL_DEBUG_LEVEL) || OSL_DEBUG_LEVEL <= 1 +#error Who broken the makefiles? +#endif + + + +#include "dbg_lay.hxx" +#include <tools/stream.hxx> + +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_USHORTS +#define _SVSTDARR_USHORTSSORT +#include <svl/svstdarr.hxx> +#endif + +#include <stdio.h> + +#include "frame.hxx" +#include "layfrm.hxx" +#include "flyfrm.hxx" +#include "txtfrm.hxx" +#include "ndtxt.hxx" +#include "dflyobj.hxx" +#include <fntcache.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + +sal_uLong SwProtocol::nRecord = 0; +SwImplProtocol* SwProtocol::pImpl = NULL; + +sal_uLong lcl_GetFrameId( const SwFrm* pFrm ) +{ +#if OSL_DEBUG_LEVEL > 1 + static sal_Bool bFrameId = sal_False; + if( bFrameId ) + return pFrm->GetFrmId(); +#endif + if( pFrm && pFrm->IsTxtFrm() ) + return ((SwTxtFrm*)pFrm)->GetTxtNode()->GetIndex(); + return 0; +} + +class SwImplProtocol +{ + SvFileStream *pStream; // Ausgabestream + SvUShortsSort *pFrmIds; // welche FrmIds sollen aufgezeichnet werden ( NULL == alle ) + std::vector<long> aVars; // Variables + ByteString aLayer; // Einrueckung der Ausgabe (" " pro Start/End) + sal_uInt16 nTypes; // welche Typen sollen aufgezeichnet werden + sal_uInt16 nLineCount; // Ausgegebene Zeilen + sal_uInt16 nMaxLines; // Maximal auszugebende Zeilen + sal_uInt8 nInitFile; // Bereich (FrmId,FrmType,Record) beim Einlesen der INI-Datei + sal_uInt8 nTestMode; // Special fuer Testformatierung, es wird ggf. nur + // innerhalb einer Testformatierung aufgezeichnet. + void _Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ); + sal_Bool NewStream(); + void CheckLine( ByteString& rLine ); + void SectFunc( ByteString &rOut, const SwFrm* pFrm, sal_uLong nAct, void* pParam ); +public: + SwImplProtocol(); + ~SwImplProtocol(); + // Aufzeichnen + void Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) + { if( pStream ) _Record( pFrm, nFunction, nAct, pParam ); } + sal_Bool InsertFrm( sal_uInt16 nFrmId ); // FrmId aufnehmen zum Aufzeichnen + sal_Bool DeleteFrm( sal_uInt16 nFrmId ); // FrmId entfernen, diesen nicht mehr Aufzeichnen + void FileInit(); // Auslesen der INI-Datei + void ChkStream() { if( !pStream ) NewStream(); } + void SnapShot( const SwFrm* pFrm, sal_uLong nFlags ); + void GetVar( const sal_uInt16 nNo, long& rVar ) + { if( nNo < aVars.size() ) rVar = aVars[ nNo ]; } +}; + +/* -------------------------------------------------- + * Durch das PROTOCOL_ENTER-Makro wird ein SwEnterLeave-Objekt erzeugt, + * wenn die aktuelle Funktion aufgezeichnet werden soll, wird ein + * SwImplEnterLeave-Objekt angelegt. Der Witz dabei ist, das der Ctor + * des Impl-Objekt am Anfang der Funktion und automatisch der Dtor beim + * Verlassen der Funktion gerufen wird. In der Basis-Implementierung ruft + * der Ctor lediglich ein PROTOCOL(..) mit ACT_START und im Dtor ein + * PROTOCOL(..) mit ACT_END. + * Es lassen sich Ableitungen der Klasse bilden, um z.B. beim Verlassen + * einer Funktion Groessenaenderungen des Frames zu dokumentieren u.v.a.m. + * Dazu braucht dann nur noch in SwEnterLeave::Ctor(...) die gewuenschte + * SwImplEnterLeave-Klasse angelegt zu werden. + * + * --------------------------------------------------*/ + +class SwImplEnterLeave +{ +protected: + const SwFrm* pFrm; // Der Frame, + sal_uLong nFunction, nAction; // die Funktion, ggf. die Aktion + void* pParam; // und weitere Parameter +public: + SwImplEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) + : pFrm( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {} + virtual void Enter(); // Ausgabe beim Eintritt + virtual void Leave(); // Ausgabe beim Verlassen +}; + +class SwSizeEnterLeave : public SwImplEnterLeave +{ + long nFrmHeight; +public: + SwSizeEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) + : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmHeight( pF->Frm().Height() ) {} + virtual void Leave(); // Ausgabe der Groessenaenderung +}; + +class SwUpperEnterLeave : public SwImplEnterLeave +{ + sal_uInt16 nFrmId; +public: + SwUpperEnterLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) + : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrmId( 0 ) {} + virtual void Enter(); // Ausgabe + virtual void Leave(); // Ausgabe der FrmId des Uppers +}; + +class SwFrmChangesLeave : public SwImplEnterLeave +{ + SwRect aFrm; +public: + SwFrmChangesLeave( const SwFrm* pF, sal_uLong nFunct, sal_uLong nAct, void* pPar ) + : SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrm( pF->Frm() ) {} + virtual void Enter(); // keine Ausgabe + virtual void Leave(); // Ausgabe bei Aenderung der Frm-Area +}; + +void SwProtocol::Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) +{ + if( Start() ) + { // Hier landen wir, wenn im Debugger SwProtocol::nRecord mit PROT_INIT(0x1) oderiert wurde + sal_Bool bFinit = sal_False; // Dies bietet im Debugger die Moeglichkeit, + if( bFinit ) // die Aufzeichnung dieser Action zu beenden + { + nRecord &= ~nFunction; // Diese Funktion nicht mehr aufzeichnen + nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen + return; + } + nRecord |= nFunction; // Aufzeichnung dieser Funktion freischalten + nRecord &= ~PROT_INIT; // PROT_INIT stets zuruecksetzen + if( pImpl ) + pImpl->ChkStream(); + } + if( !pImpl ) // Impl-Object anlegen, wenn noetig + pImpl = new SwImplProtocol(); + pImpl->Record( pFrm, nFunction, nAct, pParam ); // ...und Aufzeichnen +} + +// Die folgende Funktion wird beim Anziehen der Writer-DLL durch TxtInit(..) aufgerufen +// und ermoeglicht dem Debuggenden Funktionen und/oder FrmIds freizuschalten + +void SwProtocol::Init() +{ + nRecord = 0; + XubString aName( "dbg_lay.go", RTL_TEXTENCODING_MS_1252 ); + SvFileStream aStream( aName, STREAM_READ ); + if( aStream.IsOpen() ) + { + pImpl = new SwImplProtocol(); + pImpl->FileInit(); + } + aStream.Close(); +} + +// Ende der Aufzeichnung + +void SwProtocol::Stop() +{ + if( pImpl ) + { + delete pImpl; + pImpl = NULL; + if( pFntCache ) + pFntCache->Flush(); + } + nRecord = 0; +} + +// Creates a more or less detailed snapshot of the layout structur + +void SwProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags ) +{ + if( pImpl ) + pImpl->SnapShot( pFrm, nFlags ); +} + +void SwProtocol::GetVar( const sal_uInt16 nNo, long& rVar ) +{ + if( pImpl ) + pImpl->GetVar( nNo, rVar ); +} + +SwImplProtocol::SwImplProtocol() + : pStream( NULL ), pFrmIds( NULL ), nTypes( 0xffff ), + nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 ) +{ + NewStream(); +} + +sal_Bool SwImplProtocol::NewStream() +{ + XubString aName( "dbg_lay.out", RTL_TEXTENCODING_MS_1252 ); + nLineCount = 0; + pStream = new SvFileStream( aName, STREAM_WRITE | STREAM_TRUNC ); + if( pStream->GetError() ) + { + delete pStream; + pStream = NULL; + } + return 0 != pStream; +} + +SwImplProtocol::~SwImplProtocol() +{ + if( pStream ) + { + pStream->Close(); + delete pStream; + } + delete pFrmIds; + aVars.clear(); +} + +/* -------------------------------------------------- + * SwImplProtocol::CheckLine analysiert eine Zeile der INI-Datei + * --------------------------------------------------*/ + +void SwImplProtocol::CheckLine( ByteString& rLine ) +{ + rLine = rLine.ToLowerAscii(); // Gross/Kleinschreibung ist einerlei + while( STRING_LEN > rLine.SearchAndReplace( '\t', ' ' ) ) + ; //nothing // Tabs werden durch Blanks ersetzt + if( '#' == rLine.GetChar(0) ) // Kommentarzeilen beginnen mit '#' + return; + if( '[' == rLine.GetChar(0) ) // Bereiche: FrmIds, Typen oder Funktionen + { + ByteString aTmp = rLine.GetToken( 0, ']' ); + if( "[frmid" == aTmp ) // Bereich FrmIds + { + nInitFile = 1; + delete pFrmIds; + pFrmIds = NULL; // Default: Alle Frames aufzeichnen + } + else if( "[frmtype" == aTmp )// Bereich Typen + { + nInitFile = 2; + nTypes = USHRT_MAX; // Default: Alle FrmaeTypen aufzeichnen + } + else if( "[record" == aTmp )// Bereich Funktionen + { + nInitFile = 3; + SwProtocol::SetRecord( 0 );// Default: Keine Funktion wird aufgezeichnet + } + else if( "[test" == aTmp )// Bereich Funktionen + { + nInitFile = 4; // Default: + nTestMode = 0; // Ausserhalb der Testformatierung wird aufgezeichnet + } + else if( "[max" == aTmp )// maximale Zeilenzahl + { + nInitFile = 5; // Default: + nMaxLines = USHRT_MAX; + } + else if( "[var" == aTmp )// variables + { + nInitFile = 6; + } + else + nInitFile = 0; // Nanu: Unbekannter Bereich? + rLine.Erase( 0, aTmp.Len() + 1 ); + } + sal_uInt16 nToks = rLine.GetTokenCount( ' ' ); // Blanks (oder Tabs) sind die Trenner + for( sal_uInt16 i=0; i < nToks; ++i ) + { + ByteString aTok = rLine.GetToken( i, ' ' ); + sal_Bool bNo = sal_False; + if( '!' == aTok.GetChar(0) ) + { + bNo = sal_True; // Diese(n) Funktion/Typ entfernen + aTok.Erase( 0, 1 ); + } + if( aTok.Len() ) + { + sal_uLong nVal; + sscanf( aTok.GetBuffer(), "%li", &nVal ); + switch ( nInitFile ) + { + case 1: InsertFrm( sal_uInt16( nVal ) ); // FrmId aufnehmen + break; + case 2: { + sal_uInt16 nNew = (sal_uInt16)nVal; + if( bNo ) + nTypes &= ~nNew; // Typ entfernen + else + nTypes |= nNew; // Typ aufnehmen + } + break; + case 3: { + sal_uLong nOld = SwProtocol::Record(); + if( bNo ) + nOld &= ~nVal; // Funktion entfernen + else + nOld |= nVal; // Funktion aufnehmen + SwProtocol::SetRecord( nOld ); + } + break; + case 4: { + sal_uInt8 nNew = (sal_uInt8)nVal; + if( bNo ) + nTestMode &= ~nNew; // TestMode zuruecksetzen + else + nTestMode |= nNew; // TestMode setzen + } + break; + case 5: nMaxLines = (sal_uInt16)nVal; + break; + case 6: aVars.push_back( (long)nVal ); + break; + } + } + } +} + +/* -------------------------------------------------- + * SwImplProtocol::FileInit() liest die Datei "dbg_lay.ini" + * im aktuellen Verzeichnis und wertet sie aus. + * --------------------------------------------------*/ +void SwImplProtocol::FileInit() +{ + XubString aName( "dbg_lay.ini", RTL_TEXTENCODING_MS_1252 ); + SvFileStream aStream( aName, STREAM_READ ); + if( aStream.IsOpen() ) + { + ByteString aLine; + nInitFile = 0; + while( !aStream.IsEof() ) + { + sal_Char c; + aStream >> c; + if( '\n' == c || '\r' == c ) // Zeilenende + { + aLine.EraseLeadingChars(); + aLine.EraseTrailingChars(); + if( aLine.Len() ) + CheckLine( aLine ); // Zeile auswerten + aLine.Erase(); + } + else + aLine += c; + } + if( aLine.Len() ) + CheckLine( aLine ); // letzte Zeile auswerten + } + aStream.Close(); +} + +/* -------------------------------------------------- + * lcl_Start sorgt fuer Einrueckung um zwei Blanks bei ACT_START + * und nimmt diese bei ACT_END wieder zurueck. + * --------------------------------------------------*/ +void lcl_Start( ByteString& rOut, ByteString& rLay, sal_uLong nAction ) +{ + if( nAction == ACT_START ) + { + rLay += " "; + rOut += " On"; + } + else if( nAction == ACT_END ) + { + if( rLay.Len() > 1 ) + { + rLay.Erase( rLay.Len() - 2 ); + rOut.Erase( 0, 2 ); + } + rOut += " Off"; + } +} + +/* -------------------------------------------------- + * lcl_Flags gibt das ValidSize-, ValidPos- und ValidPrtArea-Flag ("Sz","Ps","PA") + * des Frames aus, "+" fuer valid, "-" fuer invalid. + * --------------------------------------------------*/ + +void lcl_Flags( ByteString& rOut, const SwFrm* pFrm ) +{ + rOut += " Sz"; + rOut += pFrm->GetValidSizeFlag() ? '+' : '-'; + rOut += " Ps"; + rOut += pFrm->GetValidPosFlag() ? '+' : '-'; + rOut += " PA"; + rOut += pFrm->GetValidPrtAreaFlag() ? '+' : '-'; +} + +/* -------------------------------------------------- + * lcl_FrameType gibt den Typ des Frames in Klartext aus. + * --------------------------------------------------*/ + +void lcl_FrameType( ByteString& rOut, const SwFrm* pFrm ) +{ + if( pFrm->IsTxtFrm() ) + rOut += "Txt "; + else if( pFrm->IsLayoutFrm() ) + { + if( pFrm->IsPageFrm() ) + rOut += "Page "; + else if( pFrm->IsColumnFrm() ) + rOut += "Col "; + else if( pFrm->IsBodyFrm() ) + { + if( pFrm->GetUpper() && pFrm->IsColBodyFrm() ) + rOut += "(Col)"; + rOut += "Body "; + } + else if( pFrm->IsRootFrm() ) + rOut += "Root "; + else if( pFrm->IsCellFrm() ) + rOut += "Cell "; + else if( pFrm->IsTabFrm() ) + rOut += "Tab "; + else if( pFrm->IsRowFrm() ) + rOut += "Row "; + else if( pFrm->IsSctFrm() ) + rOut += "Sect "; + else if( pFrm->IsHeaderFrm() ) + rOut += "Header "; + else if( pFrm->IsFooterFrm() ) + rOut += "Footer "; + else if( pFrm->IsFtnFrm() ) + rOut += "Ftn "; + else if( pFrm->IsFtnContFrm() ) + rOut += "FtnCont "; + else if( pFrm->IsFlyFrm() ) + rOut += "Fly "; + else + rOut += "Layout "; + } + else if( pFrm->IsNoTxtFrm() ) + rOut += "NoTxt "; + else + rOut += "Not impl. "; +} + +/* -------------------------------------------------- + * SwImplProtocol::Record(..) wird nur gerufen, wenn das PROTOCOL-Makro + * feststellt, dass die Funktion aufgezeichnet werden soll ( SwProtocol::nRecord ). + * In dieser Methode werden noch die beiden weiteren Einschraenkungen ueberprueft, + * ob die FrmId und der FrameType zu den aufzuzeichnenden gehoeren. + * --------------------------------------------------*/ + +void SwImplProtocol::_Record( const SwFrm* pFrm, sal_uLong nFunction, sal_uLong nAct, void* pParam ) +{ + sal_uInt16 nSpecial = 0; + if( nSpecial ) // Debugger-Manipulationsmoeglichkeit + { + sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrm )); + switch ( nSpecial ) + { + case 1: InsertFrm( nId ); break; + case 2: DeleteFrm( nId ); break; + case 3: delete pFrmIds; pFrmIds = NULL; break; + case 4: delete pStream; pStream = NULL; break; + } + return; + } + if( !pStream && !NewStream() ) + return; // Immer noch kein Stream + + if( pFrmIds && !pFrmIds->Seek_Entry( sal_uInt16(lcl_GetFrameId( pFrm )) ) ) + return; // gehoert nicht zu den gewuenschten FrmIds + + if( !(pFrm->GetType() & nTypes) ) + return; // Der Typ ist unerwuenscht + + if( 1 == nTestMode && nFunction != PROT_TESTFORMAT ) + return; // Wir sollen nur innerhalb einer Testformatierung aufzeichnen + sal_Bool bTmp = sal_False; + ByteString aOut = aLayer; + aOut += ByteString::CreateFromInt64( lcl_GetFrameId( pFrm ) ); + aOut += ' '; + lcl_FrameType( aOut, pFrm ); // dann den FrameType + switch ( nFunction ) // und die Funktion + { + case PROT_SNAPSHOT: lcl_Flags( aOut, pFrm ); + break; + case PROT_MAKEALL: aOut += "MakeAll"; + lcl_Start( aOut, aLayer, nAct ); + if( nAct == ACT_START ) + lcl_Flags( aOut, pFrm ); + break; + case PROT_MOVE_FWD: bTmp = sal_True; // NoBreak + case PROT_MOVE_BWD: aOut += ( nFunction == bTmp ) ? "Fwd" : "Bwd"; + lcl_Start( aOut, aLayer, nAct ); + if( pParam ) + { + aOut += ' '; + aOut += ByteString::CreateFromInt32( *((sal_uInt16*)pParam) ); + } + break; + case PROT_GROW_TST: if( ACT_START != nAct ) + return; + aOut += "TestGrow"; + break; + case PROT_SHRINK_TST: if( ACT_START != nAct ) + return; + aOut += "TestShrink"; + break; + case PROT_ADJUSTN : + case PROT_SHRINK: bTmp = sal_True; // NoBreak + case PROT_GROW: aOut += !bTmp ? "Grow" : + ( nFunction == PROT_SHRINK ? "Shrink" : "AdjustNgbhd" ); + lcl_Start( aOut, aLayer, nAct ); + if( pParam ) + { + aOut += ' '; + aOut += ByteString::CreateFromInt64( *((long*)pParam) ); + } + break; + case PROT_POS: break; + case PROT_PRTAREA: aOut += "PrtArea"; + lcl_Start( aOut, aLayer, nAct ); + break; + case PROT_SIZE: aOut += "Size"; + lcl_Start( aOut, aLayer, nAct ); + aOut += ' '; + aOut += ByteString::CreateFromInt64( pFrm->Frm().Height() ); + break; + case PROT_LEAF: aOut += "Prev/NextLeaf"; + lcl_Start( aOut, aLayer, nAct ); + aOut += ' '; + if( pParam ) + { + aOut += ' '; + aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); + } + break; + case PROT_FILE_INIT: FileInit(); + aOut = "Initialize"; + break; + case PROT_SECTION: SectFunc( aOut, pFrm, nAct, pParam ); + break; + case PROT_CUT: bTmp = sal_True; // NoBreak + case PROT_PASTE: aOut += bTmp ? "Cut from " : "Paste to "; + aOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); + break; + case PROT_TESTFORMAT: aOut += "Test"; + lcl_Start( aOut, aLayer, nAct ); + if( ACT_START == nAct ) + nTestMode |= 2; + else + nTestMode &= ~2; + break; + case PROT_FRMCHANGES: + { + SwRect& rFrm = *((SwRect*)pParam); + if( pFrm->Frm().Pos() != rFrm.Pos() ) + { + aOut += "PosChg: ("; + aOut += ByteString::CreateFromInt64(rFrm.Left()); + aOut += ", "; + aOut += ByteString::CreateFromInt64(rFrm.Top()); + aOut += ") ("; + aOut += ByteString::CreateFromInt64(pFrm->Frm().Left()); + aOut += ", "; + aOut += ByteString::CreateFromInt64(pFrm->Frm().Top()); + aOut += ") "; + } + if( pFrm->Frm().Height() != rFrm.Height() ) + { + aOut += "Height: "; + aOut += ByteString::CreateFromInt64(rFrm.Height()); + aOut += " -> "; + aOut += ByteString::CreateFromInt64(pFrm->Frm().Height()); + aOut += " "; + } + if( pFrm->Frm().Width() != rFrm.Width() ) + { + aOut += "Width: "; + aOut += ByteString::CreateFromInt64(rFrm.Width()); + aOut += " -> "; + aOut += ByteString::CreateFromInt64(pFrm->Frm().Width()); + aOut += " "; + } + break; + } + } + *pStream << aOut.GetBuffer() << endl; // Ausgabe + pStream->Flush(); // Gleich auf die Platte, damit man mitlesen kann + if( ++nLineCount >= nMaxLines ) // Maximale Ausgabe erreicht? + SwProtocol::SetRecord( 0 ); // => Ende der Aufzeichnung +} + +/* -------------------------------------------------- + * SwImplProtocol::SectFunc(...) wird von SwImplProtocol::_Record(..) gerufen, + * hier werden die Ausgaben rund um SectionFrms abgehandelt. + * --------------------------------------------------*/ + +void SwImplProtocol::SectFunc( ByteString &rOut, const SwFrm* , sal_uLong nAct, void* pParam ) +{ + sal_Bool bTmp = sal_False; + switch( nAct ) + { + case ACT_MERGE: rOut += "Merge Section "; + rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); + break; + case ACT_CREATE_MASTER: bTmp = sal_True; // NoBreak + case ACT_CREATE_FOLLOW: rOut += "Create Section "; + rOut += bTmp ? "Master to " : "Follow from "; + rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); + break; + case ACT_DEL_MASTER: bTmp = sal_True; // NoBreak + case ACT_DEL_FOLLOW: rOut += "Delete Section "; + rOut += bTmp ? "Master to " : "Follow from "; + rOut += ByteString::CreateFromInt64( lcl_GetFrameId( (SwFrm*)pParam ) ); + break; + } +} + +/* -------------------------------------------------- + * SwImplProtocol::InsertFrm(..) nimmt eine neue FrmId zum Aufzeichnen auf, + * wenn pFrmIds==NULL, werden alle aufgezeichnet, sobald durch InsertFrm(..) + * pFrmIds angelegt wird, werden nur noch die enthaltenen FrmIds aufgezeichnet. + * --------------------------------------------------*/ + +sal_Bool SwImplProtocol::InsertFrm( sal_uInt16 nId ) +{ + if( !pFrmIds ) + pFrmIds = new SvUShortsSort(5,5); + if( pFrmIds->Seek_Entry( nId ) ) + return sal_False; + pFrmIds->Insert( nId ); + return sal_True; +} + +/* -------------------------------------------------- + * SwImplProtocol::DeleteFrm(..) entfernt eine FrmId aus dem pFrmIds-Array, + * so dass diese Frame nicht mehr aufgezeichnet wird. + * --------------------------------------------------*/ +sal_Bool SwImplProtocol::DeleteFrm( sal_uInt16 nId ) +{ + sal_uInt16 nPos; + if( !pFrmIds || !pFrmIds->Seek_Entry( nId, &nPos ) ) + return sal_False; + pFrmIds->Remove( nPos ); + return sal_True; +} + +/*-------------------------------------------------- + * SwProtocol::SnapShot(..) + * creates a snapshot of the given frame and its content. + * --------------------------------------------------*/ +void SwImplProtocol::SnapShot( const SwFrm* pFrm, sal_uLong nFlags ) +{ + while( pFrm ) + { + _Record( pFrm, PROT_SNAPSHOT, 0, 0); + if( pFrm->GetDrawObjs() && nFlags & SNAP_FLYFRAMES ) + { + aLayer += "[ "; + const SwSortedObjs &rObjs = *pFrm->GetDrawObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pObj = rObjs[i]; + if ( pObj->ISA(SwFlyFrm) ) + SnapShot( static_cast<SwFlyFrm*>(pObj), nFlags ); + } + if( aLayer.Len() > 1 ) + aLayer.Erase( aLayer.Len() - 2 ); + } + if( pFrm->IsLayoutFrm() && nFlags & SNAP_LOWER && + ( !pFrm->IsTabFrm() || nFlags & SNAP_TABLECONT ) ) + { + aLayer += " "; + SnapShot( ((SwLayoutFrm*)pFrm)->Lower(), nFlags ); + if( aLayer.Len() > 1 ) + aLayer.Erase( aLayer.Len() - 2 ); + } + pFrm = pFrm->GetNext(); + } +} + +/* -------------------------------------------------- + * SwEnterLeave::Ctor(..) wird vom eigentlichen (inline-)Kontruktor gerufen, + * wenn die Funktion aufgezeichnet werden soll. + * Die Aufgabe ist es abhaengig von der Funktion das richtige SwImplEnterLeave-Objekt + * zu erzeugen, alles weitere geschieht dann in dessen Ctor/Dtor. + * --------------------------------------------------*/ +void SwEnterLeave::Ctor( const SwFrm* pFrm, sal_uLong nFunc, sal_uLong nAct, void* pPar ) +{ + switch( nFunc ) + { + case PROT_ADJUSTN : + case PROT_GROW: + case PROT_SHRINK : pImpl = new SwSizeEnterLeave( pFrm, nFunc, nAct, pPar ); break; + case PROT_MOVE_FWD: + case PROT_MOVE_BWD : pImpl = new SwUpperEnterLeave( pFrm, nFunc, nAct, pPar ); break; + case PROT_FRMCHANGES : pImpl = new SwFrmChangesLeave( pFrm, nFunc, nAct, pPar ); break; + default: pImpl = new SwImplEnterLeave( pFrm, nFunc, nAct, pPar ); break; + } + pImpl->Enter(); +} + +/* -------------------------------------------------- + * SwEnterLeave::Dtor() ruft lediglich den Destruktor des SwImplEnterLeave-Objekts, + * ist nur deshalb nicht inline, damit die SwImplEnterLeave-Definition nicht + * im dbg_lay.hxx zu stehen braucht. + * --------------------------------------------------*/ + +void SwEnterLeave::Dtor() +{ + if( pImpl ) + { + pImpl->Leave(); + delete pImpl; + } +} + +void SwImplEnterLeave::Enter() +{ + SwProtocol::Record( pFrm, nFunction, ACT_START, pParam ); +} + +void SwImplEnterLeave::Leave() +{ + SwProtocol::Record( pFrm, nFunction, ACT_END, pParam ); +} + +void SwSizeEnterLeave::Leave() +{ + nFrmHeight = pFrm->Frm().Height() - nFrmHeight; + SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmHeight ); +} + +void SwUpperEnterLeave::Enter() +{ + nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0; + SwProtocol::Record( pFrm, nFunction, ACT_START, &nFrmId ); +} + +void SwUpperEnterLeave::Leave() +{ + nFrmId = pFrm->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrm->GetUpper() )) : 0; + SwProtocol::Record( pFrm, nFunction, ACT_END, &nFrmId ); +} + +void SwFrmChangesLeave::Enter() +{ +} + +void SwFrmChangesLeave::Leave() +{ + if( pFrm->Frm() != aFrm ) + SwProtocol::Record( pFrm, PROT_FRMCHANGES, 0, &aFrm ); +} + +#endif // DBG_UTIL + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx new file mode 100644 index 000000000000..16bc348b6a42 --- /dev/null +++ b/sw/source/core/layout/findfrm.cxx @@ -0,0 +1,1793 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "node.hxx" +#include "doc.hxx" +#include "frmtool.hxx" +#include "flyfrm.hxx" +#include <frmfmt.hxx> +#include <cellfrm.hxx> +#include <rowfrm.hxx> +#include <swtable.hxx> + +#include "tabfrm.hxx" +#include "sectfrm.hxx" +#include "flyfrms.hxx" +#include "ftnfrm.hxx" +#include "txtftn.hxx" +#include "fmtftn.hxx" +#include <txtfrm.hxx> // SwTxtFrm +#include <switerator.hxx> + +/************************************************************************* +|* +|* FindBodyCont, FindLastBodyCntnt() +|* +|* Beschreibung Sucht den ersten/letzten CntntFrm im BodyText unterhalb +|* der Seite. +|* +|*************************************************************************/ +SwLayoutFrm *SwFtnBossFrm::FindBodyCont() +{ + SwFrm *pLay = Lower(); + while ( pLay && !pLay->IsBodyFrm() ) + pLay = pLay->GetNext(); + return (SwLayoutFrm*)pLay; +} + +SwCntntFrm *SwPageFrm::FindLastBodyCntnt() +{ + SwCntntFrm *pRet = FindFirstBodyCntnt(); + SwCntntFrm *pNxt = pRet; + while ( pNxt && pNxt->IsInDocBody() && IsAnLower( pNxt ) ) + { pRet = pNxt; + pNxt = pNxt->FindNextCnt(); + } + return pRet; +} + +/************************************************************************* +|* +|* SwLayoutFrm::ContainsCntnt +|* +|* Beschreibung Prueft, ob der Frame irgendwo in seiner +|* untergeordneten Struktur einen oder mehrere CntntFrm's enthaelt; +|* Falls ja wird der erste gefundene CntntFrm zurueckgegeben. +|* +|*************************************************************************/ + +const SwCntntFrm *SwLayoutFrm::ContainsCntnt() const +{ + //LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat + //solange die weiteren Blatter abklappern bis Inhalt gefunden oder der + //this verlassen wird. + //Sections: Cntnt neben Sections wuerde so nicht gefunden (leere Section + //direct neben CntntFrm), deshalb muss fuer diese Aufwendiger rekursiv gesucht + //werden. + + const SwLayoutFrm *pLayLeaf = this; + do + { + while ( (!pLayLeaf->IsSctFrm() || pLayLeaf == this ) && + pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() ) + pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower(); + + if( pLayLeaf->IsSctFrm() && pLayLeaf != this ) + { + const SwCntntFrm *pCnt = pLayLeaf->ContainsCntnt(); + if( pCnt ) + return pCnt; + if( pLayLeaf->GetNext() ) + { + if( pLayLeaf->GetNext()->IsLayoutFrm() ) + { + pLayLeaf = (SwLayoutFrm*)pLayLeaf->GetNext(); + continue; + } + else + return (SwCntntFrm*)pLayLeaf->GetNext(); + } + } + else if ( pLayLeaf->Lower() ) + return (SwCntntFrm*)pLayLeaf->Lower(); + + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + if( !IsAnLower( pLayLeaf) ) + return 0; + } while( pLayLeaf ); + return 0; +} + +/************************************************************************* +|* +|* SwLayoutFrm::FirstCell +|* +|* Beschreibung ruft zunaechst ContainsAny auf, um in die innerste Zelle +|* hineinzukommen. Dort hangelt es sich wieder hoch zum +|* ersten SwCellFrm, seit es SectionFrms gibt, reicht kein +|* ContainsCntnt()->GetUpper() mehr... +|* +|*************************************************************************/ + +const SwCellFrm *SwLayoutFrm::FirstCell() const +{ + const SwFrm* pCnt = ContainsAny(); + while( pCnt && !pCnt->IsCellFrm() ) + pCnt = pCnt->GetUpper(); + return (const SwCellFrm*)pCnt; +} + +/************************************************************************* +|* +|* SwLayoutFrm::ContainsAny +|* +|* Beschreibung wie ContainsCntnt, nur dass nicht nur CntntFrms, sondern auch +|* Bereiche und Tabellen zurueckgegeben werden. +|* +|*************************************************************************/ + +// --> OD 2006-02-01 #130797# +// New parameter <_bInvestigateFtnForSections> controls investigation of +// content of footnotes for sections. +const SwFrm *SwLayoutFrm::ContainsAny( const bool _bInvestigateFtnForSections ) const +{ + //LayoutBlatt nach unten hin suchen und wenn dieses keinen Inhalt hat + //solange die weiteren Blatter abklappern bis Inhalt gefunden oder der + //this verlassen wird. + // Oder bis wir einen SectionFrm oder TabFrm gefunden haben + + const SwLayoutFrm *pLayLeaf = this; + // --> OD 2006-02-01 #130797# + const bool bNoFtn = IsSctFrm() && !_bInvestigateFtnForSections; + // <-- + do + { + while ( ( (!pLayLeaf->IsSctFrm() && !pLayLeaf->IsTabFrm()) + || pLayLeaf == this ) && + pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrm() ) + pLayLeaf = (SwLayoutFrm*)pLayLeaf->Lower(); + + if( ( pLayLeaf->IsTabFrm() || pLayLeaf->IsSctFrm() ) + && pLayLeaf != this ) + { + // Wir liefern jetzt auch "geloeschte" SectionFrms zurueck, + // damit diese beim SaveCntnt und RestoreCntnt mitgepflegt werden. + return pLayLeaf; + } + else if ( pLayLeaf->Lower() ) + return (SwCntntFrm*)pLayLeaf->Lower(); + + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + if( bNoFtn && pLayLeaf && pLayLeaf->IsInFtn() ) + { + do + { + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + } while( pLayLeaf && pLayLeaf->IsInFtn() ); + } + if( !IsAnLower( pLayLeaf) ) + return 0; + } while( pLayLeaf ); + return 0; +} + + +/************************************************************************* +|* +|* SwFrm::GetLower() +|* +|*************************************************************************/ +const SwFrm* SwFrm::GetLower() const +{ + return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0; +} + +SwFrm* SwFrm::GetLower() +{ + return IsLayoutFrm() ? ((SwLayoutFrm*)this)->Lower() : 0; +} + +/************************************************************************* +|* +|* SwLayoutFrm::IsAnLower() +|* +|*************************************************************************/ +sal_Bool SwLayoutFrm::IsAnLower( const SwFrm *pAssumed ) const +{ + const SwFrm *pUp = pAssumed; + while ( pUp ) + { + if ( pUp == this ) + return sal_True; + if ( pUp->IsFlyFrm() ) + pUp = ((SwFlyFrm*)pUp)->GetAnchorFrm(); + else + pUp = pUp->GetUpper(); + } + return sal_False; +} + +/** method to check relative position of layout frame to + a given layout frame. + + OD 08.11.2002 - refactoring of pseudo-local method <lcl_Apres(..)> in + <txtftn.cxx> for #104840#. + + @param _aCheckRefLayFrm + constant reference of an instance of class <SwLayoutFrm> which + is used as the reference for the relative position check. + + @author OD + + @return true, if <this> is positioned before the layout frame <p> +*/ +bool SwLayoutFrm::IsBefore( const SwLayoutFrm* _pCheckRefLayFrm ) const +{ + OSL_ENSURE( !IsRootFrm() , "<IsBefore> called at a <SwRootFrm>."); + OSL_ENSURE( !_pCheckRefLayFrm->IsRootFrm() , "<IsBefore> called with a <SwRootFrm>."); + + bool bReturn; + + // check, if on different pages + const SwPageFrm *pMyPage = FindPageFrm(); + const SwPageFrm *pCheckRefPage = _pCheckRefLayFrm->FindPageFrm(); + if( pMyPage != pCheckRefPage ) + { + // being on different page as check reference + bReturn = pMyPage->GetPhyPageNum() < pCheckRefPage->GetPhyPageNum(); + } + else + { + // being on same page as check reference + // --> search my supreme parent <pUp>, which doesn't contain check reference. + const SwLayoutFrm* pUp = this; + while ( pUp->GetUpper() && + !pUp->GetUpper()->IsAnLower( _pCheckRefLayFrm ) + ) + pUp = pUp->GetUpper(); + if( !pUp->GetUpper() ) + { + // can occur, if <this> is a fly frm + bReturn = false; + } + else + { + // travel through the next's of <pUp> and check if one of these + // contain the check reference. + SwLayoutFrm* pUpNext = (SwLayoutFrm*)pUp->GetNext(); + while ( pUpNext && + !pUpNext->IsAnLower( _pCheckRefLayFrm ) ) + { + pUpNext = (SwLayoutFrm*)pUpNext->GetNext(); + } + bReturn = pUpNext != 0; + } + } + + return bReturn; +} + +// +// Local helper functions for GetNextLayoutLeaf +// + +const SwFrm* lcl_FindLayoutFrame( const SwFrm* pFrm, bool bNext ) +{ + const SwFrm* pRet = 0; + if ( pFrm->IsFlyFrm() ) + pRet = bNext ? ((SwFlyFrm*)pFrm)->GetNextLink() : ((SwFlyFrm*)pFrm)->GetPrevLink(); + else + pRet = bNext ? pFrm->GetNext() : pFrm->GetPrev(); + + return pRet; +} + +const SwFrm* lcl_GetLower( const SwFrm* pFrm, bool bFwd ) +{ + if ( !pFrm->IsLayoutFrm() ) + return 0; + + return bFwd ? + static_cast<const SwLayoutFrm*>(pFrm)->Lower() : + static_cast<const SwLayoutFrm*>(pFrm)->GetLastLower(); +} + +/************************************************************************* +|* +|* SwFrm::ImplGetNextLayoutLeaf +|* +|* Finds the next layout leaf. This is a layout frame, which does not + * have a lower which is a LayoutFrame. That means, pLower can be 0 or a + * content frame. + * + * However, pLower may be a TabFrm + * +|*************************************************************************/ + +const SwLayoutFrm *SwFrm::ImplGetNextLayoutLeaf( bool bFwd ) const +{ + const SwFrm *pFrm = this; + const SwLayoutFrm *pLayoutFrm = 0; + const SwFrm *p = 0; + bool bGoingUp = !bFwd; // false for forward, true for backward + do { + + bool bGoingFwdOrBwd = false, bGoingDown = false; + + bGoingDown = ( !bGoingUp && ( 0 != (p = lcl_GetLower( pFrm, bFwd ) ) ) ); + if ( !bGoingDown ) + { + // I cannot go down, because either I'm currently going up or + // because the is no lower. + // I'll try to go forward: + bGoingFwdOrBwd = (0 != (p = lcl_FindLayoutFrame( pFrm, bFwd ) ) ); + if ( !bGoingFwdOrBwd ) + { + // I cannot go forward, because there is no next frame. + // I'll try to go up: + bGoingUp = (0 != (p = pFrm->GetUpper() ) ); + if ( !bGoingUp ) + { + // I cannot go up, because there is no upper frame. + return 0; + } + } + } + + // If I could not go down or forward, I'll have to go up + bGoingUp = !bGoingFwdOrBwd && !bGoingDown; + + pFrm = p; + p = lcl_GetLower( pFrm, true ); + + } while( ( p && !p->IsFlowFrm() ) || + pFrm == this || + 0 == ( pLayoutFrm = pFrm->IsLayoutFrm() ? (SwLayoutFrm*)pFrm : 0 ) || + pLayoutFrm->IsAnLower( this ) ); + + return pLayoutFrm; +} + + + +/************************************************************************* +|* +|* SwFrm::ImplGetNextCntntFrm( bool ) +|* +|* Rueckwaertswandern im Baum: Den untergeordneten Frm greifen, +|* wenn es einen gibt und nicht gerade zuvor um eine Ebene +|* aufgestiegen wurde (das wuerde zu einem endlosen Auf und Ab +|* fuehren!). Damit wird sichergestellt, dass beim +|* Rueckwaertswandern alle Unterbaeume durchsucht werden. Wenn +|* abgestiegen wurde, wird zuerst an das Ende der Kette gegangen, +|* weil im weiteren ja vom letzten Frm innerhalb eines anderen +|* Frms rueckwaerts gegangen wird. +|* Vorwaetzwander funktioniert analog. +|* +|*************************************************************************/ + +// Achtung: Fixes in ImplGetNextCntntFrm() muessen moeglicherweise auch in +// die weiter oben stehende Methode lcl_NextFrm(..) eingepflegt werden +const SwCntntFrm* SwCntntFrm::ImplGetNextCntntFrm( bool bFwd ) const +{ + const SwFrm *pFrm = this; + // #100926# + SwCntntFrm *pCntntFrm = 0; + sal_Bool bGoingUp = sal_False; + do { + const SwFrm *p = 0; + sal_Bool bGoingFwdOrBwd = sal_False, bGoingDown = sal_False; + + bGoingDown = ( !bGoingUp && ( 0 != ( p = lcl_GetLower( pFrm, true ) ) ) ); + if ( !bGoingDown ) + { + bGoingFwdOrBwd = ( 0 != ( p = lcl_FindLayoutFrame( pFrm, bFwd ) ) ); + if ( !bGoingFwdOrBwd ) + { + bGoingUp = ( 0 != ( p = pFrm->GetUpper() ) ); + if ( !bGoingUp ) + { + return 0; + } + } + } + + bGoingUp = !(bGoingFwdOrBwd || bGoingDown); + + if ( !bFwd ) + { + if( bGoingDown && p ) + while ( p->GetNext() ) + p = p->GetNext(); + } + + pFrm = p; + } while ( 0 == (pCntntFrm = (pFrm->IsCntntFrm() ? (SwCntntFrm*)pFrm:0) )); + + return pCntntFrm; +} + + + + +/************************************************************************* +|* +|* SwFrm::FindRootFrm(), FindTabFrm(), FindFtnFrm(), FindFlyFrm(), +|* FindPageFrm(), FindColFrm() +|* +|*************************************************************************/ +SwPageFrm* SwFrm::FindPageFrm() +{ + SwFrm *pRet = this; + while ( pRet && !pRet->IsPageFrm() ) + { + if ( pRet->GetUpper() ) + pRet = pRet->GetUpper(); + else if ( pRet->IsFlyFrm() ) + { + // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()> + if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() ) + pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm(); + else + pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm(); + } + else + return 0; + } + return (SwPageFrm*)pRet; +} + +SwFtnBossFrm* SwFrm::FindFtnBossFrm( sal_Bool bFootnotes ) +{ + SwFrm *pRet = this; + // Innerhalb einer Tabelle gibt es keine Fussnotenbosse, auch spaltige + // Bereiche enthalten dort keine Fussnotentexte + if( pRet->IsInTab() ) + pRet = pRet->FindTabFrm(); + while ( pRet && !pRet->IsFtnBossFrm() ) + { + if ( pRet->GetUpper() ) + pRet = pRet->GetUpper(); + else if ( pRet->IsFlyFrm() ) + { + // --> OD 2004-06-30 #i28701# - use new method <GetPageFrm()> + if ( static_cast<SwFlyFrm*>(pRet)->GetPageFrm() ) + pRet = static_cast<SwFlyFrm*>(pRet)->GetPageFrm(); + else + pRet = static_cast<SwFlyFrm*>(pRet)->AnchorFrm(); + } + else + return 0; + } + if( bFootnotes && pRet && pRet->IsColumnFrm() && + !pRet->GetNext() && !pRet->GetPrev() ) + { + SwSectionFrm* pSct = pRet->FindSctFrm(); + OSL_ENSURE( pSct, "FindFtnBossFrm: Single column outside section?" ); + if( !pSct->IsFtnAtEnd() ) + return pSct->FindFtnBossFrm( sal_True ); + } + return (SwFtnBossFrm*)pRet; +} + +SwTabFrm* SwFrm::ImplFindTabFrm() +{ + SwFrm *pRet = this; + while ( !pRet->IsTabFrm() ) + { + pRet = pRet->GetUpper(); + if ( !pRet ) + return 0; + } + return (SwTabFrm*)pRet; +} + +SwSectionFrm* SwFrm::ImplFindSctFrm() +{ + SwFrm *pRet = this; + while ( !pRet->IsSctFrm() ) + { + pRet = pRet->GetUpper(); + if ( !pRet ) + return 0; + } + return (SwSectionFrm*)pRet; +} + +SwFtnFrm *SwFrm::ImplFindFtnFrm() +{ + SwFrm *pRet = this; + while ( !pRet->IsFtnFrm() ) + { + pRet = pRet->GetUpper(); + if ( !pRet ) + return 0; + } + return (SwFtnFrm*)pRet; +} + +SwFlyFrm *SwFrm::ImplFindFlyFrm() +{ + const SwFrm *pRet = this; + do + { + if ( pRet->IsFlyFrm() ) + return (SwFlyFrm*)pRet; + else + pRet = pRet->GetUpper(); + } while ( pRet ); + return 0; +} + +SwFrm *SwFrm::FindColFrm() +{ + SwFrm *pFrm = this; + do + { pFrm = pFrm->GetUpper(); + } while ( pFrm && !pFrm->IsColumnFrm() ); + return pFrm; +} + +SwRowFrm *SwFrm::FindRowFrm() +{ + SwFrm *pFrm = this; + do + { pFrm = pFrm->GetUpper(); + } while ( pFrm && !pFrm->IsRowFrm() ); + return dynamic_cast< SwRowFrm* >( pFrm ); +} + +SwFrm* SwFrm::FindFooterOrHeader() +{ + SwFrm* pRet = this; + do + { if ( pRet->GetType() & 0x0018 ) //Header und Footer + return pRet; + else if ( pRet->GetUpper() ) + pRet = pRet->GetUpper(); + else if ( pRet->IsFlyFrm() ) + pRet = ((SwFlyFrm*)pRet)->AnchorFrm(); + else + return 0; + } while ( pRet ); + return pRet; +} + +const SwFtnFrm* SwFtnContFrm::FindFootNote() const +{ + const SwFtnFrm* pRet = (SwFtnFrm*)Lower(); + if( pRet && !pRet->GetAttr()->GetFtn().IsEndNote() ) + return pRet; + return NULL; +} + +const SwPageFrm* SwRootFrm::GetPageAtPos( const Point& rPt, const Size* pSize, bool bExtend ) const +{ + const SwPageFrm* pRet = 0; + + SwRect aRect; + if ( pSize ) + { + aRect.Pos() = rPt; + aRect.SSize() = *pSize; + } + + const SwFrm* pPage = Lower(); + + if ( !bExtend ) + { + if( !Frm().IsInside( rPt ) ) + return 0; + + // skip pages above point: + while( pPage && rPt.Y() > pPage->Frm().Bottom() ) + pPage = pPage->GetNext(); + } + + OSL_ENSURE( GetPageNum() <= maPageRects.size(), "number of pages differes from page rect array size" ); + sal_uInt16 nPageIdx = 0; + + while ( pPage && !pRet ) + { + const SwRect& rBoundRect = bExtend ? maPageRects[ nPageIdx++ ] : pPage->Frm(); + + if ( (!pSize && rBoundRect.IsInside(rPt)) || + (pSize && rBoundRect.IsOver(aRect)) ) + { + pRet = static_cast<const SwPageFrm*>(pPage); + } + + pPage = pPage->GetNext(); + } + + return pRet; +} + +/************************************************************************* +|* +|* SwFrmFrm::GetAttrSet() +|* +|*************************************************************************/ +const SwAttrSet* SwFrm::GetAttrSet() const +{ + if ( IsCntntFrm() ) + return &((const SwCntntFrm*)this)->GetNode()->GetSwAttrSet(); + else + return &((const SwLayoutFrm*)this)->GetFmt()->GetAttrSet(); +} + +/************************************************************************* +|* +|* SwFrm::_FindNext(), _FindPrev(), InvalidateNextPos() +|* _FindNextCnt() geht in Tabellen und Bereiche hineinund liefert +|* nur SwCntntFrms. +|* +|* Beschreibung Invalidiert die Position des Naechsten Frames. +|* Dies ist der direkte Nachfolger, oder bei CntntFrm's der naechste +|* CntntFrm der im gleichen Fluss liegt wie ich: +|* - Body, +|* - Fussnoten, +|* - Bei Kopf-/Fussbereichen ist die Benachrichtigung nur innerhalb des +|* Bereiches weiterzuleiten. +|* - dito fuer Flys. +|* - Cntnts in Tabs halten sich ausschliesslich innerhalb ihrer Zelle +|* auf. +|* - Tabellen verhalten sich prinzipiell analog zu den Cntnts +|* - Bereiche ebenfalls +|* +|*************************************************************************/ + +// Diese Hilfsfunktion ist ein Aequivalent zur ImplGetNextCntntFrm()-Methode, +// sie liefert allerdings neben ContentFrames auch TabFrms und SectionFrms. +SwFrm* lcl_NextFrm( SwFrm* pFrm ) +{ + SwFrm *pRet = 0; + sal_Bool bGoingUp = sal_False; + do { + SwFrm *p = 0; + + sal_Bool bGoingFwd = sal_False; + sal_Bool bGoingDown = (!bGoingUp && ( 0 != (p = pFrm->IsLayoutFrm() ? ((SwLayoutFrm*)pFrm)->Lower() : 0))); + + if( !bGoingDown ) + { + bGoingFwd = (0 != (p = ( pFrm->IsFlyFrm() ? ((SwFlyFrm*)pFrm)->GetNextLink() : pFrm->GetNext()))); + if ( !bGoingFwd ) + { + bGoingUp = (0 != (p = pFrm->GetUpper())); + if ( !bGoingUp ) + { + return 0; + } + } + } + bGoingUp = !(bGoingFwd || bGoingDown); + pFrm = p; + } while ( 0 == (pRet = ( ( pFrm->IsCntntFrm() || ( !bGoingUp && + ( pFrm->IsTabFrm() || pFrm->IsSctFrm() ) ) )? pFrm : 0 ) ) ); + return pRet; +} + +SwFrm *SwFrm::_FindNext() +{ + sal_Bool bIgnoreTab = sal_False; + SwFrm *pThis = this; + + if ( IsTabFrm() ) + { + //Der letzte Cntnt der Tabelle wird + //gegriffen und dessen Nachfolger geliefert. Um die Spezialbeh. + //Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt. + if ( ((SwTabFrm*)this)->GetFollow() ) + return ((SwTabFrm*)this)->GetFollow(); + + pThis = ((SwTabFrm*)this)->FindLastCntnt(); + if ( !pThis ) + pThis = this; + bIgnoreTab = sal_True; + } + else if ( IsSctFrm() ) + { + //Der letzte Cntnt des Bereichs wird gegriffen und dessen Nachfolger + // geliefert. + if ( ((SwSectionFrm*)this)->GetFollow() ) + return ((SwSectionFrm*)this)->GetFollow(); + + pThis = ((SwSectionFrm*)this)->FindLastCntnt(); + if ( !pThis ) + pThis = this; + } + else if ( IsCntntFrm() ) + { + if( ((SwCntntFrm*)this)->GetFollow() ) + return ((SwCntntFrm*)this)->GetFollow(); + } + else if ( IsRowFrm() ) + { + SwFrm* pMyUpper = GetUpper(); + if ( pMyUpper->IsTabFrm() && ((SwTabFrm*)pMyUpper)->GetFollow() ) + return ((SwTabFrm*)pMyUpper)->GetFollow()->GetLower(); + else return NULL; + } + else + return NULL; + + SwFrm* pRet = NULL; + const sal_Bool bFtn = pThis->IsInFtn(); + if ( !bIgnoreTab && pThis->IsInTab() ) + { + SwLayoutFrm *pUp = pThis->GetUpper(); + while ( !pUp->IsCellFrm() ) + pUp = pUp->GetUpper(); + OSL_ENSURE( pUp, "Cntnt in Tabelle aber nicht in Zelle." ); + SwFrm* pNxt = ((SwCellFrm*)pUp)->GetFollowCell(); + if ( pNxt ) + pNxt = ((SwCellFrm*)pNxt)->ContainsCntnt(); + if ( !pNxt ) + { + pNxt = lcl_NextFrm( pThis ); + if ( pUp->IsAnLower( pNxt ) ) + pRet = pNxt; + } + else + pRet = pNxt; + } + else + { + const sal_Bool bBody = pThis->IsInDocBody(); + SwFrm *pNxtCnt = lcl_NextFrm( pThis ); + if ( pNxtCnt ) + { + if ( bBody || bFtn ) + { + while ( pNxtCnt ) + { + // OD 02.04.2003 #108446# - check for endnote, only if found + // next content isn't contained in a section, that collect its + // endnotes at its end. + bool bEndn = IsInSct() && !IsSctFrm() && + ( !pNxtCnt->IsInSct() || + !pNxtCnt->FindSctFrm()->IsEndnAtEnd() + ); + if ( ( bBody && pNxtCnt->IsInDocBody() ) || + ( pNxtCnt->IsInFtn() && + ( bFtn || + ( bEndn && pNxtCnt->FindFtnFrm()->GetAttr()->GetFtn().IsEndNote() ) + ) + ) + ) + { + pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm() + : (SwFrm*)pNxtCnt; + break; + } + pNxtCnt = lcl_NextFrm( pNxtCnt ); + } + } + else if ( pThis->IsInFly() ) + { + pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm() + : (SwFrm*)pNxtCnt; + } + else //Fuss-/oder Kopfbereich + { + const SwFrm *pUp = pThis->GetUpper(); + const SwFrm *pCntUp = pNxtCnt->GetUpper(); + while ( pUp && pUp->GetUpper() && + !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() ) + pUp = pUp->GetUpper(); + while ( pCntUp && pCntUp->GetUpper() && + !pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() ) + pCntUp = pCntUp->GetUpper(); + if ( pCntUp == pUp ) + { + pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrm() + : (SwFrm*)pNxtCnt; + } + } + } + } + if( pRet && pRet->IsInSct() ) + { + SwSectionFrm* pSct = pRet->FindSctFrm(); + //Fussnoten in spaltigen Rahmen duerfen nicht den Bereich + //liefern, der die Fussnoten umfasst + if( !pSct->IsAnLower( this ) && + (!bFtn || pSct->IsInFtn() ) ) + return pSct; + } + return pRet; +} + +// --> OD 2005-12-01 #i27138# - add parameter <_bInSameFtn> +SwCntntFrm *SwFrm::_FindNextCnt( const bool _bInSameFtn ) +{ + SwFrm *pThis = this; + + if ( IsTabFrm() ) + { + if ( ((SwTabFrm*)this)->GetFollow() ) + { + pThis = ((SwTabFrm*)this)->GetFollow()->ContainsCntnt(); + if( pThis ) + return (SwCntntFrm*)pThis; + } + pThis = ((SwTabFrm*)this)->FindLastCntnt(); + if ( !pThis ) + return 0; + } + else if ( IsSctFrm() ) + { + if ( ((SwSectionFrm*)this)->GetFollow() ) + { + pThis = ((SwSectionFrm*)this)->GetFollow()->ContainsCntnt(); + if( pThis ) + return (SwCntntFrm*)pThis; + } + pThis = ((SwSectionFrm*)this)->FindLastCntnt(); + if ( !pThis ) + return 0; + } + else if ( IsCntntFrm() && ((SwCntntFrm*)this)->GetFollow() ) + return ((SwCntntFrm*)this)->GetFollow(); + + if ( pThis->IsCntntFrm() ) + { + const sal_Bool bBody = pThis->IsInDocBody(); + const sal_Bool bFtn = pThis->IsInFtn(); + SwCntntFrm *pNxtCnt = ((SwCntntFrm*)pThis)->GetNextCntntFrm(); + if ( pNxtCnt ) + { + // --> OD 2005-12-01 #i27138# + if ( bBody || ( bFtn && !_bInSameFtn ) ) + // <-- + { + // handling for environments 'footnotes' and 'document body frames': + while ( pNxtCnt ) + { + if ( (bBody && pNxtCnt->IsInDocBody()) || + (bFtn && pNxtCnt->IsInFtn()) ) + return pNxtCnt; + pNxtCnt = pNxtCnt->GetNextCntntFrm(); + } + } + // --> OD 2005-12-01 #i27138# + else if ( bFtn && _bInSameFtn ) + { + // handling for environments 'each footnote': + // Assure that found next content frame belongs to the same footnotes + const SwFtnFrm* pFtnFrmOfNext( pNxtCnt->FindFtnFrm() ); + const SwFtnFrm* pFtnFrmOfCurr( pThis->FindFtnFrm() ); + OSL_ENSURE( pFtnFrmOfCurr, + "<SwFrm::_FindNextCnt() - unknown layout situation: current frame has to have an upper footnote frame." ); + if ( pFtnFrmOfNext == pFtnFrmOfCurr ) + { + return pNxtCnt; + } + else if ( pFtnFrmOfCurr->GetFollow() ) + { + // next content frame has to be the first content frame + // in the follow footnote, which contains a content frame. + SwFtnFrm* pFollowFtnFrmOfCurr( + const_cast<SwFtnFrm*>(pFtnFrmOfCurr) ); + pNxtCnt = 0L; + do { + pFollowFtnFrmOfCurr = pFollowFtnFrmOfCurr->GetFollow(); + pNxtCnt = pFollowFtnFrmOfCurr->ContainsCntnt(); + } while ( !pNxtCnt && pFollowFtnFrmOfCurr->GetFollow() ); + return pNxtCnt; + } + else + { + // current content frame is the last content frame in the + // footnote - no next content frame exists. + return 0L; + } + } + // <-- + else if ( pThis->IsInFly() ) + // handling for environments 'unlinked fly frame' and + // 'group of linked fly frames': + return pNxtCnt; + else + { + // handling for environments 'page header' and 'page footer': + const SwFrm *pUp = pThis->GetUpper(); + const SwFrm *pCntUp = pNxtCnt->GetUpper(); + while ( pUp && pUp->GetUpper() && + !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() ) + pUp = pUp->GetUpper(); + while ( pCntUp && pCntUp->GetUpper() && + !pCntUp->IsHeaderFrm() && !pCntUp->IsFooterFrm() ) + pCntUp = pCntUp->GetUpper(); + if ( pCntUp == pUp ) + return pNxtCnt; + } + } + } + return 0; +} + +/** method to determine previous content frame in the same environment + for a flow frame (content frame, table frame, section frame) + + OD 2005-11-30 #i27138# + + @author OD +*/ +SwCntntFrm* SwFrm::_FindPrevCnt( const bool _bInSameFtn ) +{ + if ( !IsFlowFrm() ) + { + // nothing to do, if current frame isn't a flow frame. + return 0L; + } + + SwCntntFrm* pPrevCntntFrm( 0L ); + + // Because method <SwCntntFrm::GetPrevCntntFrm()> is used to travel + // through the layout, a content frame, at which the travel starts, is needed. + SwCntntFrm* pCurrCntntFrm = dynamic_cast<SwCntntFrm*>(this); + + // perform shortcut, if current frame is a follow, and + // determine <pCurrCntntFrm>, if current frame is a table or section frame + if ( pCurrCntntFrm && pCurrCntntFrm->IsFollow() ) + { + // previous content frame is its master content frame + pPrevCntntFrm = pCurrCntntFrm->FindMaster(); + } + else if ( IsTabFrm() ) + { + SwTabFrm* pTabFrm( static_cast<SwTabFrm*>(this) ); + if ( pTabFrm->IsFollow() ) + { + // previous content frame is the last content of its master table frame + pPrevCntntFrm = pTabFrm->FindMaster()->FindLastCntnt(); + } + else + { + // start content frame for the search is the first content frame of + // the table frame. + pCurrCntntFrm = pTabFrm->ContainsCntnt(); + } + } + else if ( IsSctFrm() ) + { + SwSectionFrm* pSectFrm( static_cast<SwSectionFrm*>(this) ); + if ( pSectFrm->IsFollow() ) + { + // previous content frame is the last content of its master section frame + pPrevCntntFrm = pSectFrm->FindMaster()->FindLastCntnt(); + } + else + { + // start content frame for the search is the first content frame of + // the section frame. + pCurrCntntFrm = pSectFrm->ContainsCntnt(); + } + } + + // search for next content frame, depending on the environment, in which + // the current frame is in. + if ( !pPrevCntntFrm && pCurrCntntFrm ) + { + pPrevCntntFrm = pCurrCntntFrm->GetPrevCntntFrm(); + if ( pPrevCntntFrm ) + { + if ( pCurrCntntFrm->IsInFly() ) + { + // handling for environments 'unlinked fly frame' and + // 'group of linked fly frames': + // Nothing to do, <pPrevCntntFrm> is the one + } + else + { + const bool bInDocBody = pCurrCntntFrm->IsInDocBody(); + const bool bInFtn = pCurrCntntFrm->IsInFtn(); + if ( bInDocBody || ( bInFtn && !_bInSameFtn ) ) + { + // handling for environments 'footnotes' and 'document body frames': + // Assure that found previous frame is also in one of these + // environments. Otherwise, travel further + while ( pPrevCntntFrm ) + { + if ( ( bInDocBody && pPrevCntntFrm->IsInDocBody() ) || + ( bInFtn && pPrevCntntFrm->IsInFtn() ) ) + { + break; + } + pPrevCntntFrm = pPrevCntntFrm->GetPrevCntntFrm(); + } + } + else if ( bInFtn && _bInSameFtn ) + { + // handling for environments 'each footnote': + // Assure that found next content frame belongs to the same footnotes + const SwFtnFrm* pFtnFrmOfPrev( pPrevCntntFrm->FindFtnFrm() ); + const SwFtnFrm* pFtnFrmOfCurr( pCurrCntntFrm->FindFtnFrm() ); + if ( pFtnFrmOfPrev != pFtnFrmOfCurr ) + { + if ( pFtnFrmOfCurr->GetMaster() ) + { + SwFtnFrm* pMasterFtnFrmOfCurr( + const_cast<SwFtnFrm*>(pFtnFrmOfCurr) ); + pPrevCntntFrm = 0L; + // --> OD 2007-07-05 #146872# + // correct wrong loop-condition + do { + pMasterFtnFrmOfCurr = pMasterFtnFrmOfCurr->GetMaster(); + pPrevCntntFrm = pMasterFtnFrmOfCurr->FindLastCntnt(); + } while ( !pPrevCntntFrm && + pMasterFtnFrmOfCurr->GetMaster() ); + // <-- + } + else + { + // current content frame is the first content in the + // footnote - no previous content exists. + pPrevCntntFrm = 0L;; + } + } + } + else + { + // handling for environments 'page header' and 'page footer': + // Assure that found previous frame is also in the same + // page header respectively page footer as <pCurrCntntFrm> + // Note: At this point its clear, that <pCurrCntntFrm> has + // to be inside a page header or page footer and that + // neither <pCurrCntntFrm> nor <pPrevCntntFrm> are + // inside a fly frame. + // Thus, method <FindFooterOrHeader()> can be used. + OSL_ENSURE( pCurrCntntFrm->FindFooterOrHeader(), + "<SwFrm::_FindPrevCnt()> - unknown layout situation: current frame should be in page header or page footer" ); + OSL_ENSURE( !pPrevCntntFrm->IsInFly(), + "<SwFrm::_FindPrevCnt()> - unknown layout situation: found previous frame should *not* be inside a fly frame." ); + if ( pPrevCntntFrm->FindFooterOrHeader() != + pCurrCntntFrm->FindFooterOrHeader() ) + { + pPrevCntntFrm = 0L; + } + } + } + } + } + + return pPrevCntntFrm; +} + +SwFrm *SwFrm::_FindPrev() +{ + sal_Bool bIgnoreTab = sal_False; + SwFrm *pThis = this; + + if ( IsTabFrm() ) + { + //Der erste Cntnt der Tabelle wird + //gegriffen und dessen Vorgaenger geliefert. Um die Spezialbeh. + //Fuer Tabellen (s.u.) auszuschalten wird bIgnoreTab gesetzt. + if ( ((SwTabFrm*)this)->IsFollow() ) + return ((SwTabFrm*)this)->FindMaster(); + else + pThis = ((SwTabFrm*)this)->ContainsCntnt(); + bIgnoreTab = sal_True; + } + + if ( pThis && pThis->IsCntntFrm() ) + { + SwCntntFrm *pPrvCnt = ((SwCntntFrm*)pThis)->GetPrevCntntFrm(); + if( !pPrvCnt ) + return 0; + if ( !bIgnoreTab && pThis->IsInTab() ) + { + SwLayoutFrm *pUp = pThis->GetUpper(); + while ( !pUp->IsCellFrm() ) + pUp = pUp->GetUpper(); + OSL_ENSURE( pUp, "Cntnt in Tabelle aber nicht in Zelle." ); + if ( pUp->IsAnLower( pPrvCnt ) ) + return pPrvCnt; + } + else + { + SwFrm* pRet; + const sal_Bool bBody = pThis->IsInDocBody(); + const sal_Bool bFtn = bBody ? sal_False : pThis->IsInFtn(); + if ( bBody || bFtn ) + { + while ( pPrvCnt ) + { + if ( (bBody && pPrvCnt->IsInDocBody()) || + (bFtn && pPrvCnt->IsInFtn()) ) + { + pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm() + : (SwFrm*)pPrvCnt; + return pRet; + } + pPrvCnt = pPrvCnt->GetPrevCntntFrm(); + } + } + else if ( pThis->IsInFly() ) + { + pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm() + : (SwFrm*)pPrvCnt; + return pRet; + } + else //Fuss-/oder Kopfbereich oder Fly + { + const SwFrm *pUp = pThis->GetUpper(); + const SwFrm *pCntUp = pPrvCnt->GetUpper(); + while ( pUp && pUp->GetUpper() && + !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() ) + pUp = pUp->GetUpper(); + while ( pCntUp && pCntUp->GetUpper() ) + pCntUp = pCntUp->GetUpper(); + if ( pCntUp == pUp ) + { + pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrm() + : (SwFrm*)pPrvCnt; + return pRet; + } + } + } + } + return 0; +} + +void SwFrm::ImplInvalidateNextPos( sal_Bool bNoFtn ) +{ + SwFrm *pFrm; + if ( 0 != (pFrm = _FindNext()) ) + { + if( pFrm->IsSctFrm() ) + { + while( pFrm && pFrm->IsSctFrm() ) + { + if( ((SwSectionFrm*)pFrm)->GetSection() ) + { + SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pTmp ) + pTmp->InvalidatePos(); + else if( !bNoFtn ) + ((SwSectionFrm*)pFrm)->InvalidateFtnPos(); + if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm ) + pFrm->InvalidatePos(); + return; + } + pFrm = pFrm->FindNext(); + } + if( pFrm ) + { + if ( pFrm->IsSctFrm()) + { // Damit der Inhalt eines Bereichs die Chance erhaelt, + // die Seite zu wechseln, muss er ebenfalls invalidiert werden. + SwFrm* pTmp = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pTmp ) + pTmp->InvalidatePos(); + if( !IsInSct() || FindSctFrm()->GetFollow() != pFrm ) + pFrm->InvalidatePos(); + } + else + pFrm->InvalidatePos(); + } + } + else + pFrm->InvalidatePos(); + } +} + +/** method to invalidate printing area of next frame + + OD 09.01.2004 #i11859# + + @author OD + + FME 2004-04-19 #i27145# Moved function from SwTxtFrm to SwFrm +*/ +void SwFrm::InvalidateNextPrtArea() +{ + // determine next frame + SwFrm* pNextFrm = FindNext(); + // skip empty section frames and hidden text frames + { + while ( pNextFrm && + ( ( pNextFrm->IsSctFrm() && + !static_cast<SwSectionFrm*>(pNextFrm)->GetSection() ) || + ( pNextFrm->IsTxtFrm() && + static_cast<SwTxtFrm*>(pNextFrm)->IsHiddenNow() ) ) ) + { + pNextFrm = pNextFrm->FindNext(); + } + } + + // Invalidate printing area of found next frame + if ( pNextFrm ) + { + if ( pNextFrm->IsSctFrm() ) + { + // Invalidate printing area of found section frame, if + // (1) this text frame isn't in a section OR + // (2) found section frame isn't a follow of the section frame this + // text frame is in. + if ( !IsInSct() || FindSctFrm()->GetFollow() != pNextFrm ) + { + pNextFrm->InvalidatePrt(); + } + + // Invalidate printing area of first content in found section. + SwFrm* pFstCntntOfSctFrm = + static_cast<SwSectionFrm*>(pNextFrm)->ContainsAny(); + if ( pFstCntntOfSctFrm ) + { + pFstCntntOfSctFrm->InvalidatePrt(); + } + } + else + { + pNextFrm->InvalidatePrt(); + } + } +} + +/************************************************************************* +|* +|* lcl_IsInColSect() +|* liefert nur sal_True, wenn der Frame _direkt_ in einem spaltigen Bereich steht, +|* nicht etwa, wenn er in einer Tabelle steht, die in einem spaltigen Bereich ist. +|* +|*************************************************************************/ + +sal_Bool lcl_IsInColSct( const SwFrm *pUp ) +{ + sal_Bool bRet = sal_False; + while( pUp ) + { + if( pUp->IsColumnFrm() ) + bRet = sal_True; + else if( pUp->IsSctFrm() ) + return bRet; + else if( pUp->IsTabFrm() ) + return sal_False; + pUp = pUp->GetUpper(); + } + return sal_False; +} + +/************************************************************************* +|* +|* SwFrm::IsMoveable(); +|* +|*************************************************************************/ +/** determine, if frame is moveable in given environment + + OD 08.08.2003 #110978# + method replaced 'old' method <sal_Bool IsMoveable() const>. + Determines, if frame is moveable in given environment. if no environment + is given (parameter _pLayoutFrm == 0L), the movability in the actual + environment (<this->GetUpper()) is checked. + + @author OD +*/ + +bool SwFrm::IsMoveable( const SwLayoutFrm* _pLayoutFrm ) const +{ + bool bRetVal = false; + + if ( !_pLayoutFrm ) + { + _pLayoutFrm = GetUpper(); + } + + if ( _pLayoutFrm && IsFlowFrm() ) + { + if ( _pLayoutFrm->IsInSct() && lcl_IsInColSct( _pLayoutFrm ) ) + { + bRetVal = true; + } + else if ( _pLayoutFrm->IsInFly() || + _pLayoutFrm->IsInDocBody() || + _pLayoutFrm->IsInFtn() ) + { + if ( _pLayoutFrm->IsInTab() && !IsTabFrm() && + ( !IsCntntFrm() || !const_cast<SwFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) ) ) + { + bRetVal = false; + } + else + { + if ( _pLayoutFrm->IsInFly() ) + { + // if fly frame has a follow (next linked fly frame), + // frame is moveable. + if ( const_cast<SwLayoutFrm*>(_pLayoutFrm)->FindFlyFrm()->GetNextLink() ) + { + bRetVal = true; + } + else + { + // if environment is columned, frame is moveable, if + // it isn't in last column. + // search for column frame + const SwFrm* pCol = _pLayoutFrm; + while ( pCol && !pCol->IsColumnFrm() ) + { + pCol = pCol->GetUpper(); + } + // frame is moveable, if found column frame isn't last one. + if ( pCol && pCol->GetNext() ) + { + bRetVal = true; + } + } + } + else + { + bRetVal = true; + } + } + } + } + + return bRetVal; +} + +/************************************************************************* +|* +|* SwFrm::SetInfFlags(); +|* +|*************************************************************************/ +void SwFrm::SetInfFlags() +{ + if ( !IsFlyFrm() && !GetUpper() ) //noch nicht gepastet, keine Informationen + return; //lieferbar + + bInfInvalid = bInfBody = bInfTab = bInfFly = bInfFtn = bInfSct = sal_False; + + SwFrm *pFrm = this; + if( IsFtnContFrm() ) + bInfFtn = sal_True; + do + { // bInfBody wird nur am Seitenbody, nicht im ColumnBody gesetzt + if ( pFrm->IsBodyFrm() && !bInfFtn && pFrm->GetUpper() + && pFrm->GetUpper()->IsPageFrm() ) + bInfBody = sal_True; + else if ( pFrm->IsTabFrm() || pFrm->IsCellFrm() ) + { + bInfTab = sal_True; + } + else if ( pFrm->IsFlyFrm() ) + bInfFly = sal_True; + else if ( pFrm->IsSctFrm() ) + bInfSct = sal_True; + else if ( pFrm->IsFtnFrm() ) + bInfFtn = sal_True; + + pFrm = pFrm->GetUpper(); + + } while ( pFrm && !pFrm->IsPageFrm() ); //Oberhalb der Seite kommt nix +} + +/*-----------------22.8.2001 14:30------------------ + * SwFrm::SetDirFlags( sal_Bool ) + * actualizes the vertical or the righttoleft-flags. + * If the property is derived, it's from the upper or (for fly frames) from + * the anchor. Otherwise we've to call a virtual method to check the property. + * --------------------------------------------------*/ + +void SwFrm::SetDirFlags( sal_Bool bVert ) +{ + if( bVert ) + { + // OD 2004-01-21 #114969# - if derived, valid vertical flag only if + // vertical flag of upper/anchor is valid. + if( bDerivedVert ) + { + const SwFrm* pAsk = IsFlyFrm() ? + ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper(); + + OSL_ENSURE( pAsk != this, "Autsch! Stack overflow is about to happen" ); + + if( pAsk ) + { + bVertical = pAsk->IsVertical() ? 1 : 0; + bReverse = pAsk->IsReverse() ? 1 : 0; + + bVertLR = pAsk->IsVertLR() ? 1 : 0; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( !pAsk->bInvalidVert ) + bInvalidVert = sal_False; + } + } + else + CheckDirection( bVert ); + } + else + { + sal_Bool bInv = 0; + if( !bDerivedR2L ) // CheckDirection is able to set bDerivedR2L! + CheckDirection( bVert ); + if( bDerivedR2L ) + { + const SwFrm* pAsk = IsFlyFrm() ? + ((SwFlyFrm*)this)->GetAnchorFrm() : GetUpper(); + + OSL_ENSURE( pAsk != this, "Autsch! Stack overflow is about to happen" ); + + if( pAsk ) + bRightToLeft = pAsk->IsRightToLeft() ? 1 : 0; + if( !pAsk || pAsk->bInvalidR2L ) + bInv = bInvalidR2L; + } + bInvalidR2L = bInv; + } +} + +SwLayoutFrm* SwFrm::GetNextCellLeaf( MakePageType ) +{ + SwFrm* pTmpFrm = this; + while ( !pTmpFrm->IsCellFrm() ) + pTmpFrm = pTmpFrm->GetUpper(); + + OSL_ENSURE( pTmpFrm, "SwFrm::GetNextCellLeaf() without cell" ); + return ((SwCellFrm*)pTmpFrm)->GetFollowCell(); +} + +SwLayoutFrm* SwFrm::GetPrevCellLeaf( MakePageType ) +{ + SwFrm* pTmpFrm = this; + while ( !pTmpFrm->IsCellFrm() ) + pTmpFrm = pTmpFrm->GetUpper(); + + OSL_ENSURE( pTmpFrm, "SwFrm::GetNextPreviousLeaf() without cell" ); + return ((SwCellFrm*)pTmpFrm)->GetPreviousCell(); +} + +SwCellFrm* lcl_FindCorrespondingCellFrm( const SwRowFrm& rOrigRow, + const SwCellFrm& rOrigCell, + const SwRowFrm& rCorrRow, + bool bInFollow ) +{ + SwCellFrm* pRet = NULL; + SwCellFrm* pCell = (SwCellFrm*)rOrigRow.Lower(); + SwCellFrm* pCorrCell = (SwCellFrm*)rCorrRow.Lower(); + + while ( pCell != &rOrigCell && !pCell->IsAnLower( &rOrigCell ) ) + { + pCell = (SwCellFrm*)pCell->GetNext(); + pCorrCell = (SwCellFrm*)pCorrCell->GetNext(); + } + + OSL_ENSURE( pCell && pCorrCell, "lcl_FindCorrespondingCellFrm does not work" ); + + if ( pCell != &rOrigCell ) + { + // rOrigCell must be a lower of pCell. We need to recurse into the rows: + OSL_ENSURE( pCell->Lower() && pCell->Lower()->IsRowFrm(), + "lcl_FindCorrespondingCellFrm does not work" ); + + SwRowFrm* pRow = (SwRowFrm*)pCell->Lower(); + while ( !pRow->IsAnLower( &rOrigCell ) ) + pRow = (SwRowFrm*)pRow->GetNext(); + + SwRowFrm* pCorrRow = 0; + if ( bInFollow ) + pCorrRow = pRow->GetFollowRow(); + else + { + SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pCorrCell->GetLastLower()); + + if ( pTmpRow && pTmpRow->GetFollowRow() == pRow ) + pCorrRow = pTmpRow; + } + + if ( pCorrRow ) + pRet = lcl_FindCorrespondingCellFrm( *pRow, rOrigCell, *pCorrRow, bInFollow ); + } + else + pRet = pCorrCell; + + return pRet; +} + +// VERSION OF GetFollowCell() that assumes that we always have a follow flow line: +SwCellFrm* SwCellFrm::GetFollowCell() const +{ + SwCellFrm* pRet = NULL; + + // NEW TABLES + // Covered cells do not have follow cells! + const long nRowSpan = GetLayoutRowSpan(); + if ( nRowSpan < 1 ) + return NULL; + + // find most upper row frame + const SwFrm* pRow = GetUpper(); + while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) + pRow = pRow->GetUpper(); + + if ( !pRow ) + return NULL; + + const SwTabFrm* pTabFrm = static_cast<const SwTabFrm*>( pRow->GetUpper() ); + if ( !pRow || !pTabFrm->GetFollow() || !pTabFrm->HasFollowFlowLine() ) + return NULL; + + const SwCellFrm* pThisCell = this; + + // Get last cell of the current table frame that belongs to the rowspan: + if ( nRowSpan > 1 ) + { + // optimization: Will end of row span be in last row or exceed row? + long nMax = 0; + while ( pRow->GetNext() && ++nMax < nRowSpan ) + pRow = pRow->GetNext(); + + if ( !pRow->GetNext() ) + { + pThisCell = &pThisCell->FindStartEndOfRowSpanCell( false, true ); + pRow = pThisCell->GetUpper(); + } + } + + const SwRowFrm* pFollowRow = NULL; + if ( !pRow->GetNext() && + NULL != ( pFollowRow = pRow->IsInSplitTableRow() ) && + ( !pFollowRow->IsRowSpanLine() || nRowSpan > 1 ) ) + pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *pThisCell, *pFollowRow, true ); + + return pRet; +} + +// VERSION OF GetPreviousCell() THAT ASSUMES THAT WE ALWAYS HAVE A FFL +SwCellFrm* SwCellFrm::GetPreviousCell() const +{ + SwCellFrm* pRet = NULL; + + // NEW TABLES + // Covered cells do not have previous cells! + if ( GetLayoutRowSpan() < 1 ) + return NULL; + + // find most upper row frame + const SwFrm* pRow = GetUpper(); + while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) + pRow = pRow->GetUpper(); + + OSL_ENSURE( pRow->GetUpper() && pRow->GetUpper()->IsTabFrm(), "GetPreviousCell without Table" ); + + SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper(); + + if ( pTab->IsFollow() ) + { + const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow(); + const bool bIsInFirstLine = ( pTmp == pRow ); + + if ( bIsInFirstLine ) + { + SwTabFrm *pMaster = (SwTabFrm*)pTab->FindMaster(); + if ( pMaster && pMaster->HasFollowFlowLine() ) + { + SwRowFrm* pMasterRow = static_cast<SwRowFrm*>(pMaster->GetLastLower()); + if ( pMasterRow ) + pRet = lcl_FindCorrespondingCellFrm( *((SwRowFrm*)pRow), *this, *pMasterRow, false ); + if ( pRet && pRet->GetTabBox()->getRowSpan() < 1 ) + pRet = &const_cast<SwCellFrm&>(pRet->FindStartEndOfRowSpanCell( true, true )); + } + } + } + + return pRet; +} + +// --> NEW TABLES +const SwCellFrm& SwCellFrm::FindStartEndOfRowSpanCell( bool bStart, bool bCurrentTableOnly ) const +{ + const SwCellFrm* pRet = 0; + + const SwTabFrm* pTableFrm = dynamic_cast<const SwTabFrm*>(GetUpper()->GetUpper()); + + if ( !bStart && pTableFrm->IsFollow() && pTableFrm->IsInHeadline( *this ) ) + return *this; + + OSL_ENSURE( pTableFrm && + ( (bStart && GetTabBox()->getRowSpan() < 1) || + (!bStart && GetLayoutRowSpan() > 1) ), + "SwCellFrm::FindStartRowSpanCell: No rowspan, no table, no cookies" ); + + if ( pTableFrm ) + { + const SwTable* pTable = pTableFrm->GetTable(); + + sal_uInt16 nMax = USHRT_MAX; + if ( bCurrentTableOnly ) + { + const SwFrm* pCurrentRow = GetUpper(); + const bool bDoNotEnterHeadline = bStart && pTableFrm->IsFollow() && + !pTableFrm->IsInHeadline( *pCurrentRow ); + + // check how many rows we are allowed to go up or down until we reach the end of + // the current table frame: + nMax = 0; + while ( bStart ? pCurrentRow->GetPrev() : pCurrentRow->GetNext() ) + { + if ( bStart ) + { + // do not enter a repeated headline: + if ( bDoNotEnterHeadline && pTableFrm->IsFollow() && + pTableFrm->IsInHeadline( *pCurrentRow->GetPrev() ) ) + break; + + pCurrentRow = pCurrentRow->GetPrev(); + } + else + pCurrentRow = pCurrentRow->GetNext(); + + ++nMax; + } + } + + // By passing the nMax value for Find*OfRowSpan (in case of bCurrentTableOnly + // is set) we assure that we find a rMasterBox that has a SwCellFrm in + // the current table frame: + const SwTableBox& rMasterBox = bStart ? + GetTabBox()->FindStartOfRowSpan( *pTable, nMax ) : + GetTabBox()->FindEndOfRowSpan( *pTable, nMax ); + + SwIterator<SwCellFrm,SwFmt> aIter( *rMasterBox.GetFrmFmt() ); + + for ( SwCellFrm* pMasterCell = aIter.First(); pMasterCell; pMasterCell = aIter.Next() ) + { + if ( pMasterCell->GetTabBox() == &rMasterBox ) + { + const SwTabFrm* pMasterTable = static_cast<const SwTabFrm*>(pMasterCell->GetUpper()->GetUpper()); + + if ( bCurrentTableOnly ) + { + if ( pMasterTable == pTableFrm ) + { + pRet = pMasterCell; + break; + } + } + else + { + if ( pMasterTable == pTableFrm || + ( (bStart && pMasterTable->IsAnFollow(pTableFrm)) || + (!bStart && pTableFrm->IsAnFollow(pMasterTable)) ) ) + { + pRet = pMasterCell; + break; + } + } + } + } + } + + OSL_ENSURE( pRet, "SwCellFrm::FindStartRowSpanCell: No result" ); + + return *pRet; +} +// <-- NEW TABLES + +const SwRowFrm* SwFrm::IsInSplitTableRow() const +{ + OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" ); + + const SwFrm* pRow = this; + + // find most upper row frame + while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) ) + pRow = pRow->GetUpper(); + + if ( !pRow ) return NULL; + + OSL_ENSURE( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" ); + + const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper(); + // --> OD 2006-06-28 #b6443897# + // If most upper row frame is a headline row, the current frame + // can't be in a splitted table row. Thus, add corresponding condition. + if ( pRow->GetNext() || + pTab->GetTable()->IsHeadline( + *(static_cast<const SwRowFrm*>(pRow)->GetTabLine()) ) || + !pTab->HasFollowFlowLine() || + !pTab->GetFollow() ) + return NULL; + // <-- + + // skip headline + const SwRowFrm* pFollowRow = pTab->GetFollow()->GetFirstNonHeadlineRow(); + + OSL_ENSURE( pFollowRow, "SwFrm::IsInSplitTableRow() does not work" ); + + return pFollowRow; +} + +const SwRowFrm* SwFrm::IsInFollowFlowRow() const +{ + OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" ); + + // find most upper row frame + const SwFrm* pRow = this; + while( pRow && ( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() ) ) + pRow = pRow->GetUpper(); + + if ( !pRow ) return NULL; + + OSL_ENSURE( pRow->GetUpper()->IsTabFrm(), "Confusion in table layout" ); + + const SwTabFrm* pTab = (SwTabFrm*)pRow->GetUpper(); + + const SwTabFrm* pMaster = pTab->IsFollow() ? pTab->FindMaster() : 0; + + if ( !pMaster || !pMaster->HasFollowFlowLine() ) + return NULL; + + const SwFrm* pTmp = pTab->GetFirstNonHeadlineRow(); + const bool bIsInFirstLine = ( pTmp == pRow ); + + if ( !bIsInFirstLine ) + return NULL; + + const SwRowFrm* pMasterRow = static_cast<const SwRowFrm*>(pMaster->GetLastLower()); + return pMasterRow; +} + +bool SwFrm::IsInBalancedSection() const +{ + bool bRet = false; + + if ( IsInSct() ) + { + const SwSectionFrm* pSectionFrm = FindSctFrm(); + if ( pSectionFrm ) + bRet = pSectionFrm->IsBalancedSection(); + } + return bRet; +} + +/* + * SwLayoutFrm::GetLastLower() + */ +const SwFrm* SwLayoutFrm::GetLastLower() const +{ + const SwFrm* pRet = Lower(); + if ( !pRet ) + return 0; + while ( pRet->GetNext() ) + pRet = pRet->GetNext(); + return pRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx new file mode 100644 index 000000000000..59fac2138f1d --- /dev/null +++ b/sw/source/core/layout/flowfrm.cxx @@ -0,0 +1,2672 @@ +/* -*- 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 "pam.hxx" +#include "swtable.hxx" +#include "frame.hxx" +#include "rootfrm.hxx" +#include "pagefrm.hxx" +#include "flyfrm.hxx" +#include "viewsh.hxx" +#include "doc.hxx" +#include "viewimp.hxx" +#include "viewopt.hxx" +#include "dflyobj.hxx" +#include "frmtool.hxx" +#include "dcontact.hxx" +#include <editeng/brkitem.hxx> +#include <editeng/keepitem.hxx> +#include <fmtsrnd.hxx> +#include <fmtanchr.hxx> +#include <fmtpdsc.hxx> +#include <editeng/ulspitem.hxx> +#include <tgrditem.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <editeng/pgrditem.hxx> +#include <paratr.hxx> +#include "ftnfrm.hxx" +#include "txtfrm.hxx" +#include "tabfrm.hxx" +#include "pagedesc.hxx" +#include "layact.hxx" +#include "fmtornt.hxx" +#include "flyfrms.hxx" +#include "sectfrm.hxx" +#include "section.hxx" +#include "dbg_lay.hxx" +#include "lineinfo.hxx" +#include <fmtclbl.hxx> +#include <sortedobjs.hxx> +#include <layouter.hxx> +#include <fmtfollowtextflow.hxx> +#include <switerator.hxx> + +sal_Bool SwFlowFrm::bMoveBwdJump = sal_False; + + +/************************************************************************* +|* +|* SwFlowFrm::SwFlowFrm() +|* +|*************************************************************************/ + + +SwFlowFrm::SwFlowFrm( SwFrm &rFrm ) : + rThis( rFrm ), + pFollow( 0 ) +{ + bLockJoin = bIsFollow = bCntntLock = bOwnFtnNum = + bFtnLock = bFlyLock = sal_False; +} + + +/************************************************************************* +|* +|* SwFlowFrm::IsFollowLocked() +|* return sal_True if any follow has the JoinLocked flag +|* +|*************************************************************************/ + +sal_Bool SwFlowFrm::HasLockedFollow() const +{ + const SwFlowFrm* pFrm = GetFollow(); + while( pFrm ) + { + if( pFrm->IsJoinLocked() ) + return sal_True; + pFrm = pFrm->GetFollow(); + } + return sal_False; +} + +/************************************************************************* +|* +|* SwFlowFrm::IsKeepFwdMoveAllowed() +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::IsKeepFwdMoveAllowed() +{ + //Wenn der Vorgaenger das KeepAttribut traegt und auch dessen + //Vorgaenger usw. bis zum ersten der Kette und fuer diesen das + //IsFwdMoveAllowed ein sal_False liefert, so ist das Moven eben nicht erlaubt. + SwFrm *pFrm = &rThis; + if ( !pFrm->IsInFtn() ) + do + { if ( pFrm->GetAttrSet()->GetKeep().GetValue() ) + pFrm = pFrm->GetIndPrev(); + else + return sal_True; + } while ( pFrm ); + + //Siehe IsFwdMoveAllowed() + sal_Bool bRet = sal_False; + if ( pFrm && pFrm->GetIndPrev() ) + bRet = sal_True; + return bRet; +} + +/************************************************************************* +|* +|* SwFlowFrm::CheckKeep() +|* +|*************************************************************************/ + + +void SwFlowFrm::CheckKeep() +{ + //Den 'letzten' Vorgaenger mit KeepAttribut anstossen, denn + //die ganze Truppe koennte zuruckrutschen. + SwFrm *pPre = rThis.GetIndPrev(); + if( pPre->IsSctFrm() ) + { + SwFrm *pLast = ((SwSectionFrm*)pPre)->FindLastCntnt(); + if( pLast && pLast->FindSctFrm() == pPre ) + pPre = pLast; + else + return; + } + SwFrm* pTmp; + sal_Bool bKeep; + while ( sal_True == (bKeep = pPre->GetAttrSet()->GetKeep().GetValue()) && + 0 != ( pTmp = pPre->GetIndPrev() ) ) + { + if( pTmp->IsSctFrm() ) + { + SwFrm *pLast = ((SwSectionFrm*)pTmp)->FindLastCntnt(); + if( pLast && pLast->FindSctFrm() == pTmp ) + pTmp = pLast; + else + break; + } + pPre = pTmp; + } + if ( bKeep ) + pPre->InvalidatePos(); +} + +/************************************************************************* +|* +|* SwFlowFrm::IsKeep() +|* +|*************************************************************************/ + +sal_Bool SwFlowFrm::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKeep ) const +{ + // 1. The keep attribute is ignored inside footnotes + // 2. For compatibility reasons, the keep attribute is + // ignored for frames inside table cells + // 3. If bBreakCheck is set to true, this function only checks + // if there are any break after attributes set at rAttrs + // or break before attributes set for the next content (or next table) + sal_Bool bKeep = bCheckIfLastRowShouldKeep || + ( !rThis.IsInFtn() && + ( !rThis.IsInTab() || rThis.IsTabFrm() ) && + rAttrs.GetKeep().GetValue() ); + + OSL_ENSURE( !bCheckIfLastRowShouldKeep || rThis.IsTabFrm(), + "IsKeep with bCheckIfLastRowShouldKeep should only be used for tabfrms" ); + + // Ignore keep attribute if there are break situations: + if ( bKeep ) + { + switch ( rAttrs.GetBreak().GetBreak() ) + { + case SVX_BREAK_COLUMN_AFTER: + case SVX_BREAK_COLUMN_BOTH: + case SVX_BREAK_PAGE_AFTER: + case SVX_BREAK_PAGE_BOTH: + { + bKeep = sal_False; + } + default: break; + } + if ( bKeep ) + { + SwFrm *pNxt; + if( 0 != (pNxt = rThis.FindNextCnt()) && + (!pFollow || pNxt != pFollow->GetFrm())) + { + // --> FME 2006-05-15 #135914# + // The last row of a table only keeps with the next content + // it they are in the same section: + if ( bCheckIfLastRowShouldKeep ) + { + const SwSection* pThisSection = 0; + const SwSection* pNextSection = 0; + const SwSectionFrm* pThisSectionFrm = rThis.FindSctFrm(); + const SwSectionFrm* pNextSectionFrm = pNxt->FindSctFrm(); + + if ( pThisSectionFrm ) + pThisSection = pThisSectionFrm->GetSection(); + + if ( pNextSectionFrm ) + pNextSection = pNextSectionFrm->GetSection(); + + if ( pThisSection != pNextSection ) + bKeep = sal_False; + } + // <-- + + if ( bKeep ) + { + const SwAttrSet* pSet = NULL; + + if ( pNxt->IsInTab() ) + { + SwTabFrm* pTab = pNxt->FindTabFrm(); + if ( ! rThis.IsInTab() || rThis.FindTabFrm() != pTab ) + pSet = &pTab->GetFmt()->GetAttrSet(); + } + + if ( ! pSet ) + pSet = pNxt->GetAttrSet(); + + OSL_ENSURE( pSet, "No AttrSet to check keep attribute" ); + + if ( pSet->GetPageDesc().GetPageDesc() ) + bKeep = sal_False; + else switch ( pSet->GetBreak().GetBreak() ) + { + case SVX_BREAK_COLUMN_BEFORE: + case SVX_BREAK_COLUMN_BOTH: + case SVX_BREAK_PAGE_BEFORE: + case SVX_BREAK_PAGE_BOTH: + bKeep = sal_False; + default: break; + } + } + } + } + } + return bKeep; +} + +/************************************************************************* +|* +|* SwFlowFrm::BwdMoveNecessary() +|* +|*************************************************************************/ + + +sal_uInt8 SwFlowFrm::BwdMoveNecessary( const SwPageFrm *pPage, const SwRect &rRect ) +{ + // Der return-Wert entscheidet mit, + // ob auf Zurueckgeflossen werden muss, (3) + // ob das gute alte WouldFit gerufen werden kann (0, 1) + // oder ob ein Umhaengen und eine Probeformatierung sinnvoll ist (2) + // dabei bedeutet Bit 1, dass Objekte an mir selbst verankert sind + // und Bit 2, dass ich anderen Objekten ausweichen muss. + + //Wenn ein SurroundObj, dass einen Umfluss wuenscht mit dem Rect ueberlappt + //ist der Fluss notwendig (weil die Verhaeltnisse nicht geschaetzt werden + //koennen), es kann allerdings ggf. eine TestFormatierung stattfinden. + //Wenn das SurroundObj ein Fly ist und ich selbst ein Lower bin oder der Fly + //Lower von mir ist, so spielt er keine Rolle. + //Wenn das SurroundObj in einem zeichengebunden Fly verankert ist, und ich + //selbst nicht Lower dieses Zeichengebundenen Flys bin, so spielt der Fly + //keine Rolle. + //#32639# Wenn das Objekt bei mir verankert ist kann ich es + //vernachlaessigen, weil es hoechstwahrscheinlich (!?) mitfliesst, + //eine TestFormatierung ist dann allerdings nicht erlaubt! + sal_uInt8 nRet = 0; + SwFlowFrm *pTmp = this; + do + { // Wenn an uns oder einem Follow Objekte haengen, so + // kann keine ProbeFormatierung stattfinden, da absatzgebundene + // nicht richtig beruecksichtigt wuerden und zeichengebundene sollten + // gar nicht zur Probe formatiert werden. + if( pTmp->GetFrm()->GetDrawObjs() ) + nRet = 1; + pTmp = pTmp->GetFollow(); + } while ( !nRet && pTmp ); + if ( pPage->GetSortedObjs() ) + { + // --> OD 2004-07-01 #i28701# - new type <SwSortedObjs> + const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + sal_uLong nIndex = ULONG_MAX; + for ( sal_uInt16 i = 0; nRet < 3 && i < rObjs.Count(); ++i ) + { + // --> OD 2004-07-01 #i28701# - consider changed type of + // <SwSortedObjs> entries. + SwAnchoredObject* pObj = rObjs[i]; + const SwFrmFmt& rFmt = pObj->GetFrmFmt(); + const SwRect aRect( pObj->GetObjRect() ); + if ( aRect.IsOver( rRect ) && + rFmt.GetSurround().GetSurround() != SURROUND_THROUGHT ) + { + if( rThis.IsLayoutFrm() && //Fly Lower von This? + Is_Lower_Of( &rThis, pObj->GetDrawObj() ) ) + continue; + if( pObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pObj); + if ( pFly->IsAnLower( &rThis ) )//This Lower vom Fly? + continue; + } + + const SwFrm* pAnchor = pObj->GetAnchorFrm(); + if ( pAnchor == &rThis ) + { + nRet |= 1; + continue; + } + + //Nicht wenn das Objekt im Textfluss hinter mir verankert ist, + //denn dann weiche ich ihm nicht aus. + if ( ::IsFrmInSameKontext( pAnchor, &rThis ) ) + { + if ( rFmt.GetAnchor().GetAnchorId() == FLY_AT_PARA ) + { + // Den Index des anderen erhalten wir immer ueber das Ankerattr. + sal_uLong nTmpIndex = rFmt.GetAnchor().GetCntntAnchor()->nNode.GetIndex(); + // Jetzt wird noch ueberprueft, ob der aktuelle Absatz vor dem + // Anker des verdraengenden Objekts im Text steht, dann wird + // nicht ausgewichen. + // Der Index wird moeglichst ueber einen SwFmtAnchor ermittelt, + // da sonst recht teuer. + if( ULONG_MAX == nIndex ) + { + const SwNode *pNode; + if ( rThis.IsCntntFrm() ) + pNode = ((SwCntntFrm&)rThis).GetNode(); + else if( rThis.IsSctFrm() ) + pNode = ((SwSectionFmt*)((SwSectionFrm&)rThis). + GetFmt())->GetSectionNode(); + else + { + OSL_ENSURE( rThis.IsTabFrm(), "new FowFrm?" ); + pNode = ((SwTabFrm&)rThis).GetTable()-> + GetTabSortBoxes()[0]->GetSttNd()->FindTableNode(); + } + nIndex = pNode->GetIndex(); + } + if( nIndex < nTmpIndex ) + continue; + } + } + else + continue; + + nRet |= 2; + } + } + } + return nRet; +} + +/************************************************************************* +|* +|* SwFlowFrm::CutTree(), PasteTree(), MoveSubTree() +|* +|* Beschreibung Eine Spezialisierte Form des Cut() und Paste(), die +|* eine ganze Kette umhaengt (naehmlich this und folgende). Dabei werden +|* nur minimale Operationen und Benachrichtigungen ausgefuehrt. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFlowFrm::CutTree( SwFrm *pStart ) +{ + //Der Start und alle Nachbarn werden ausgeschnitten, sie werden aneinander- + //gereiht und ein Henkel auf den ersten wird zurueckgeliefert. + //Zurueckbleibende werden geeignet invalidiert. + + SwLayoutFrm *pLay = pStart->GetUpper(); + if ( pLay->IsInFtn() ) + pLay = pLay->FindFtnFrm(); + + // --> OD 2006-05-08 #i58846# + // <pPrepare( PREP_QUOVADIS )> only for frames in footnotes + if( pStart->IsInFtn() ) + { + SwFrm* pTmp = pStart->GetIndPrev(); + if( pTmp ) + pTmp->Prepare( PREP_QUOVADIS ); + } + // <-- + + //Nur fix auschneiden und zwar so, dass klare Verhaeltnisse bei den + //Verlassenen herrschen. Die Pointer der ausgeschnittenen Kette zeigen + //noch wer weiss wo hin. + if ( pStart == pStart->GetUpper()->Lower() ) + pStart->GetUpper()->pLower = 0; + if ( pStart->GetPrev() ) + { + pStart->GetPrev()->pNext = 0; + pStart->pPrev = 0; + } + + if ( pLay->IsFtnFrm() ) + { + if ( !pLay->Lower() && !pLay->IsColLocked() && + !((SwFtnFrm*)pLay)->IsBackMoveLocked() ) + { + pLay->Cut(); + delete pLay; + } + else + { + sal_Bool bUnlock = !((SwFtnFrm*)pLay)->IsBackMoveLocked(); + ((SwFtnFrm*)pLay)->LockBackMove(); + pLay->InvalidateSize(); + pLay->Calc(); + SwCntntFrm *pCnt = pLay->ContainsCntnt(); + while ( pCnt && pLay->IsAnLower( pCnt ) ) + { + //Kann sein, dass der CntFrm gelockt ist, wir wollen hier nicht + //in eine endlose Seitenwanderung hineinlaufen und rufen das + //Calc garnicht erst! + OSL_ENSURE( pCnt->IsTxtFrm(), "Die Graphic ist gelandet." ); + if ( ((SwTxtFrm*)pCnt)->IsLocked() || + ((SwTxtFrm*)pCnt)->GetFollow() == pStart ) + break; + pCnt->Calc(); + pCnt = pCnt->GetNextCntntFrm(); + } + if( bUnlock ) + ((SwFtnFrm*)pLay)->UnlockBackMove(); + } + pLay = 0; + } + return pLay; +} + + + +sal_Bool SwFlowFrm::PasteTree( SwFrm *pStart, SwLayoutFrm *pParent, SwFrm *pSibling, + SwFrm *pOldParent ) +{ + //returnt sal_True wenn in der Kette ein LayoutFrm steht. + sal_Bool bRet = sal_False; + + //Die mit pStart beginnende Kette wird vor den Sibling unter den Parent + //gehaengt. Fuer geeignete Invalidierung wird ebenfalls gesorgt. + + //Ich bekomme eine fertige Kette. Der Anfang der Kette muss verpointert + //werden, dann alle Upper fuer die Kette und schliesslich dass Ende. + //Unterwegs werden alle geeignet invalidiert. + if ( pSibling ) + { + if ( 0 != (pStart->pPrev = pSibling->GetPrev()) ) + pStart->GetPrev()->pNext = pStart; + else + pParent->pLower = pStart; + pSibling->_InvalidatePos(); + pSibling->_InvalidatePrt(); + } + else + { + if ( 0 == (pStart->pPrev = pParent->Lower()) ) + pParent->pLower = pStart; + else + //Modified for #i100782#,04/03/2009 + //If the pParent has more than 1 child nodes, former design will + //ignore them directly without any collection work. It will make some + //dangling pointers. This lead the crash... + //The new design will find the last child of pParent in loop way, and + //add the pStart after the last child. + // pParent->Lower()->pNext = pStart; + { + SwFrm* pTemp = pParent->pLower; + while (pTemp) + { + if (pTemp->pNext) + pTemp = pTemp->pNext; + else + { + pStart->pPrev = pTemp; + pTemp->pNext = pStart; + break; + } + } + } + //End modification for #i100782#,04/03/2009 + + // #i27145# + if ( pParent->IsSctFrm() ) + { + // We have no sibling because pParent is a section frame and + // has just been created to contain some content. The printing + // area of the frame behind pParent has to be invalidated, so + // that the correct distance between pParent and the next frame + // can be calculated. + pParent->InvalidateNextPrtArea(); + } + } + SwFrm *pFloat = pStart; + SwFrm *pLst = 0; + SWRECTFN( pParent ) + SwTwips nGrowVal = 0; + do + { pFloat->pUpper = pParent; + pFloat->_InvalidateAll(); + pFloat->CheckDirChange(); + + //Ich bin Freund des TxtFrm und darf deshalb so einiges. Das mit + //dem CacheIdx scheint etwas riskant! + if ( pFloat->IsTxtFrm() ) + { + if ( ((SwTxtFrm*)pFloat)->GetCacheIdx() != USHRT_MAX ) + ((SwTxtFrm*)pFloat)->Init(); //Ich bin sein Freund. + } + else + bRet = sal_True; + + nGrowVal += (pFloat->Frm().*fnRect->fnGetHeight)(); + if ( pFloat->GetNext() ) + pFloat = pFloat->GetNext(); + else + { + pLst = pFloat; + pFloat = 0; + } + } while ( pFloat ); + + if ( pSibling ) + { + pLst->pNext = pSibling; + pSibling->pPrev = pLst; + if( pSibling->IsInFtn() ) + { + if( pSibling->IsSctFrm() ) + pSibling = ((SwSectionFrm*)pSibling)->ContainsAny(); + if( pSibling ) + pSibling->Prepare( PREP_ERGOSUM ); + } + } + if ( nGrowVal ) + { + if ( pOldParent && pOldParent->IsBodyFrm() ) //Fuer variable Seitenhoehe beim Browsen + pOldParent->Shrink( nGrowVal ); + pParent->Grow( nGrowVal ); + } + + if ( pParent->IsFtnFrm() ) + ((SwFtnFrm*)pParent)->InvalidateNxtFtnCnts( pParent->FindPageFrm() ); + return bRet; +} + + + +void SwFlowFrm::MoveSubTree( SwLayoutFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent, "Kein Parent uebergeben." ); + OSL_ENSURE( rThis.GetUpper(), "Wo kommen wir denn her?" ); + + //Sparsamer benachrichtigen wenn eine Action laeuft. + ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + const SwViewImp *pImp = pSh ? pSh->Imp() : 0; + const sal_Bool bComplete = pImp && pImp->IsAction() && pImp->GetLayAction().IsComplete(); + + if ( !bComplete ) + { + SwFrm *pPre = rThis.GetIndPrev(); + if ( pPre ) + { + pPre->SetRetouche(); + // --> OD 2004-11-23 #115759# - follow-up of #i26250# + // invalidate printing area of previous frame, if it's in a table + if ( pPre->GetUpper()->IsInTab() ) + { + pPre->_InvalidatePrt(); + } + // <-- + pPre->InvalidatePage(); + } + else + { rThis.GetUpper()->SetCompletePaint(); + rThis.GetUpper()->InvalidatePage(); + } + } + + SwPageFrm *pOldPage = rThis.FindPageFrm(); + + SwLayoutFrm *pOldParent = CutTree( &rThis ); + const sal_Bool bInvaLay = PasteTree( &rThis, pParent, pSibling, pOldParent ); + + // Wenn durch das Cut&Paste ein leerer SectionFrm entstanden ist, sollte + // dieser automatisch verschwinden. + SwSectionFrm *pSct; + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + if ( pOldParent && !pOldParent->Lower() && + ( pOldParent->IsInSct() && + !(pSct = pOldParent->FindSctFrm())->ContainsCntnt() && + !pSct->ContainsAny( true ) ) ) + // <-- + { + pSct->DelEmpty( sal_False ); + } + + // In einem spaltigen Bereich rufen wir lieber kein Calc "von unten" + if( !rThis.IsInSct() && + ( !rThis.IsInTab() || ( rThis.IsTabFrm() && !rThis.GetUpper()->IsInTab() ) ) ) + rThis.GetUpper()->Calc(); + else if( rThis.GetUpper()->IsSctFrm() ) + { + SwSectionFrm* pTmpSct = (SwSectionFrm*)rThis.GetUpper(); + sal_Bool bOld = pTmpSct->IsCntntLocked(); + pTmpSct->SetCntntLock( sal_True ); + pTmpSct->Calc(); + if( !bOld ) + pTmpSct->SetCntntLock( sal_False ); + } + SwPageFrm *pPage = rThis.FindPageFrm(); + + if ( pOldPage != pPage ) + { + rThis.InvalidatePage( pPage ); + if ( rThis.IsLayoutFrm() ) + { + SwCntntFrm *pCnt = ((SwLayoutFrm*)&rThis)->ContainsCntnt(); + if ( pCnt ) + pCnt->InvalidatePage( pPage ); + } + else if ( pSh && pSh->GetDoc()->GetLineNumberInfo().IsRestartEachPage() + && pPage->FindFirstBodyCntnt() == &rThis ) + { + rThis._InvalidateLineNum(); + } + } + if ( bInvaLay || (pSibling && pSibling->IsLayoutFrm()) ) + rThis.GetUpper()->InvalidatePage( pPage ); +} + +/************************************************************************* +|* +|* SwFlowFrm::IsAnFollow() +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::IsAnFollow( const SwFlowFrm *pAssumed ) const +{ + const SwFlowFrm *pFoll = this; + do + { if ( pAssumed == pFoll ) + return sal_True; + pFoll = pFoll->GetFollow(); + } while ( pFoll ); + return sal_False; +} + + +/************************************************************************* +|* +|* SwFlowFrm::FindMaster() +|* +|*************************************************************************/ + +SwTxtFrm* SwCntntFrm::FindMaster() const +{ + OSL_ENSURE( IsFollow(), "SwCntntFrm::FindMaster(): !IsFollow" ); + + const SwCntntFrm* pCnt = GetPrevCntntFrm(); + + while ( pCnt ) + { + if ( pCnt->HasFollow() && pCnt->GetFollow() == this ) + { + OSL_ENSURE( pCnt->IsTxtFrm(), "NoTxtFrm with follow found" ); + return (SwTxtFrm*)pCnt; + } + pCnt = pCnt->GetPrevCntntFrm(); + } + + OSL_FAIL( "Follow ist lost in Space." ); + return 0; +} + +SwSectionFrm* SwSectionFrm::FindMaster() const +{ + OSL_ENSURE( IsFollow(), "SwSectionFrm::FindMaster(): !IsFollow" ); + + SwIterator<SwSectionFrm,SwFmt> aIter( *pSection->GetFmt() ); + SwSectionFrm* pSect = aIter.First(); + while ( pSect ) + { + if( pSect->GetFollow() == this ) + return pSect; + pSect = aIter.Next(); + } + + OSL_FAIL( "Follow ist lost in Space." ); + return 0; +} + +SwTabFrm* SwTabFrm::FindMaster( bool bFirstMaster ) const +{ + OSL_ENSURE( IsFollow(), "SwTabFrm::FindMaster(): !IsFollow" ); + + SwIterator<SwTabFrm,SwFmt> aIter( *GetTable()->GetFrmFmt() ); + SwTabFrm* pTab = aIter.First(); + while ( pTab ) + { + if ( bFirstMaster ) + { + // + // Optimization. This makes code like this obsolete: + // while ( pTab->IsFollow() ) + // pTab = pTab->FindMaster(); + // + if ( !pTab->IsFollow() ) + { + SwTabFrm* pNxt = pTab; + while ( pNxt ) + { + if ( pNxt->GetFollow() == this ) + return pTab; + pNxt = pNxt->GetFollow(); + } + } + } + else + { + if ( pTab->GetFollow() == this ) + return pTab; + } + + pTab = aIter.Next(); + } + + OSL_FAIL( "Follow ist lost in Space." ); + return 0; +} + +/************************************************************************* +|* +|* SwFrm::GetLeaf() +|* +|* Beschreibung Liefert das naechste/vorhergehende LayoutBlatt, +|* das _nicht_ unterhalb von this liegt (oder gar this selbst ist). +|* Ausserdem muss dieses LayoutBlatt im gleichen Textfluss wie +|* pAnch Ausgangsfrm liegen (Body, Ftn) +|* +|*************************************************************************/ + + +const SwLayoutFrm *SwFrm::GetLeaf( MakePageType eMakePage, sal_Bool bFwd, + const SwFrm *pAnch ) const +{ + //Ohne Fluss kein genuss... + if ( !(IsInDocBody() || IsInFtn() || IsInFly()) ) + return 0; + + const SwFrm *pLeaf = this; + sal_Bool bFound = sal_False; + + do + { pLeaf = ((SwFrm*)pLeaf)->GetLeaf( eMakePage, bFwd ); + + if ( pLeaf && + (!IsLayoutFrm() || !((SwLayoutFrm*)this)->IsAnLower( pLeaf ))) + { + if ( pAnch->IsInDocBody() == pLeaf->IsInDocBody() && + pAnch->IsInFtn() == pLeaf->IsInFtn() ) + { + bFound = sal_True; + } + } + } while ( !bFound && pLeaf ); + + return (const SwLayoutFrm*)pLeaf; +} + +/************************************************************************* +|* +|* SwFrm::GetLeaf() +|* +|* Beschreibung Ruft Get[Next|Prev]Leaf +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetLeaf( MakePageType eMakePage, sal_Bool bFwd ) +{ + if ( IsInFtn() ) + return bFwd ? GetNextFtnLeaf( eMakePage ) : GetPrevFtnLeaf( eMakePage ); + + // --> OD 2005-08-16 #i53323# + // A frame could be inside a table AND inside a section. + // Thus, it has to be determined, which is the first parent. + bool bInTab( IsInTab() ); + bool bInSct( IsInSct() ); + if ( bInTab && bInSct ) + { + const SwFrm* pUpperFrm( GetUpper() ); + while ( pUpperFrm ) + { + if ( pUpperFrm->IsTabFrm() ) + { + // the table is the first. + bInSct = false; + break; + } + else if ( pUpperFrm->IsSctFrm() ) + { + // the section is the first. + bInTab = false; + break; + } + + pUpperFrm = pUpperFrm->GetUpper(); + } + } + + if ( bInTab && ( !IsTabFrm() || GetUpper()->IsCellFrm() ) ) // TABLE IN TABLE + return bFwd ? GetNextCellLeaf( eMakePage ) : GetPrevCellLeaf( eMakePage ); + + if ( bInSct ) + return bFwd ? GetNextSctLeaf( eMakePage ) : GetPrevSctLeaf( eMakePage ); + // <-- + + return bFwd ? GetNextLeaf( eMakePage ) : GetPrevLeaf( eMakePage ); +} + + + +sal_Bool SwFrm::WrongPageDesc( SwPageFrm* pNew ) +{ + //Jetzt wirds leider etwas kompliziert: + //Ich bringe ich evtl. selbst + //einen Pagedesc mit; der der Folgeseite muss dann damit + //uebereinstimmen. + //Anderfalls muss ich mir etwas genauer ansehen wo der + //Folgepagedesc herkam. + //Wenn die Folgeseite selbst schon sagt, dass ihr + //Pagedesc nicht stimmt so kann ich das Teil bedenkenlos + //auswechseln. + //Wenn die Seite meint, dass ihr Pagedesc stimmt, so heisst + //das leider noch immer nicht, dass ich damit etwas anfangen + //kann: Wenn der erste BodyCntnt einen PageDesc oder einen + //PageBreak wuenscht, so muss ich ebenfalls eine neue + //Seite einfuegen; es sein denn die gewuenschte Seite ist + //die richtige. + //Wenn ich einen neue Seite eingefuegt habe, so fangen die + //Probleme leider erst an, denn wahrscheinlich wird die dann + //folgende Seite verkehrt gewesen und ausgewechselt worden + //sein. Das hat zur Folge, dass ich zwar eine neue (und + //jetzt richtige) Seite habe, die Bedingungen zum auswechseln + //aber leider noch immer stimmen. + //Ausweg: Vorlaeufiger Versuch, nur einmal eine neue Seite + //einsetzen (Leerseiten werden noetigenfalls bereits von + //InsertPage() eingefuegt. + const SwFmtPageDesc &rFmtDesc = GetAttrSet()->GetPageDesc(); + + //Mein Pagedesc zaehlt nicht, wenn ich ein Follow bin! + SwPageDesc *pDesc = 0; + sal_uInt16 nTmp = 0; + SwFlowFrm *pFlow = SwFlowFrm::CastFlowFrm( this ); + if ( !pFlow || !pFlow->IsFollow() ) + { + pDesc = (SwPageDesc*)rFmtDesc.GetPageDesc(); + if( pDesc ) + { + if( !pDesc->GetRightFmt() ) + nTmp = 2; + else if( !pDesc->GetLeftFmt() ) + nTmp = 1; + else if( rFmtDesc.GetNumOffset() ) + nTmp = rFmtDesc.GetNumOffset(); + } + } + + //Bringt der Cntnt einen Pagedesc mit oder muss zaehlt die + //virtuelle Seitennummer des neuen Layoutleafs? + // Bei Follows zaehlt der PageDesc nicht + const sal_Bool bOdd = nTmp ? ( nTmp % 2 ? sal_True : sal_False ) + : pNew->OnRightPage(); + if ( !pDesc ) + pDesc = pNew->FindPageDesc(); + const SwFlowFrm *pNewFlow = pNew->FindFirstBodyCntnt(); + // Haben wir uns selbst gefunden? + if( pNewFlow == pFlow ) + pNewFlow = NULL; + if ( pNewFlow && pNewFlow->GetFrm()->IsInTab() ) + pNewFlow = pNewFlow->GetFrm()->FindTabFrm(); + const SwPageDesc *pNewDesc= ( pNewFlow && !pNewFlow->IsFollow() ) + ? pNewFlow->GetFrm()->GetAttrSet()->GetPageDesc().GetPageDesc():0; + + return ( pNew->GetPageDesc() != pDesc || // own desc ? + pNew->GetFmt() != (bOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt()) || + ( pNewDesc && pNewDesc == pDesc ) ); +} + + +/************************************************************************* +|* +|* SwFrm::GetNextLeaf() +|* +|* Beschreibung Liefert das naechste LayoutBlatt in den das +|* Frame gemoved werden kann. +|* +|*************************************************************************/ + +SwLayoutFrm *SwFrm::GetNextLeaf( MakePageType eMakePage ) +{ + OSL_ENSURE( !IsInFtn(), "GetNextLeaf(), don't call me for Ftn." ); + OSL_ENSURE( !IsInSct(), "GetNextLeaf(), don't call me for Sections." ); + + const sal_Bool bBody = IsInDocBody(); //Wenn ich aus dem DocBody komme + //Will ich auch im Body landen. + + // Bei Flys macht es keinen Sinn, Seiten einzufuegen, wir wollen lediglich + // die Verkettung absuchen. + if( IsInFly() ) + eMakePage = MAKEPAGE_NONE; + + //Bei Tabellen gleich den grossen Sprung wagen, ein einfaches GetNext... + //wuerde die erste Zellen und in der Folge alle weiteren Zellen nacheinander + //abklappern.... + SwLayoutFrm *pLayLeaf = 0; + if ( IsTabFrm() ) + { + SwCntntFrm* pTmp = ((SwTabFrm*)this)->FindLastCntnt(); + if ( pTmp ) + pLayLeaf = pTmp->GetUpper(); + } + if ( !pLayLeaf ) + pLayLeaf = GetNextLayoutLeaf(); + + SwLayoutFrm *pOldLayLeaf = 0; //Damit bei neu erzeugten Seiten + //nicht wieder vom Anfang gesucht + //wird. + sal_Bool bNewPg = sal_False; //nur einmal eine neue Seite einfuegen. + + while ( sal_True ) + { + if ( pLayLeaf ) + { + //Es gibt noch einen weiteren LayoutFrm, mal sehen, + //ob er bereit ist mich aufzunehmen. + //Dazu braucht er nur von der gleichen Art wie mein Ausgangspunkt + //sein (DocBody bzw. Footnote.) + if ( pLayLeaf->FindPageFrm()->IsFtnPage() ) + { //Wenn ich bei den Endnotenseiten angelangt bin hat sichs. + pLayLeaf = 0; + continue; + } + if ( (bBody && !pLayLeaf->IsInDocBody()) || pLayLeaf->IsInTab() + || pLayLeaf->IsInSct() ) + { + //Er will mich nicht; neuer Versuch, neues Glueck + pOldLayLeaf = pLayLeaf; + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + continue; + } + //Er will mich, also ist er der gesuchte und ich bin fertig. + //Bei einem Seitenwechsel kann es allerdings noch sein, dass + //Der Seitentyp nicht der gewuenschte ist, in diesem Fall muessen + //wir eine Seite des richtigen Typs einfuegen. + + if( !IsFlowFrm() && ( eMakePage == MAKEPAGE_NONE || + eMakePage==MAKEPAGE_APPEND || eMakePage==MAKEPAGE_NOSECTION ) ) + return pLayLeaf; + + SwPageFrm *pNew = pLayLeaf->FindPageFrm(); + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + // #111704# The pagedesc check does not make sense for frames in fly frames + if ( pNew != FindPageFrm() && !bNewPg && !IsInFly() && + // --> FME 2005-05-10 #i46683# + // Do not consider page descriptions in browse mode (since + // MoveBwd ignored them) + !(pSh && pSh->GetViewOptions()->getBrowseMode() ) ) + // <-- + { + if( WrongPageDesc( pNew ) ) + { + SwFtnContFrm *pCont = pNew->FindFtnCont(); + if( pCont ) + { + // Falls die Referenz der ersten Fussnote dieser Seite + // vor der Seite liegt, fuegen wir lieber keine neue Seite + // ein (Bug #55620#) + SwFtnFrm *pFtn = (SwFtnFrm*)pCont->Lower(); + if( pFtn && pFtn->GetRef() ) + { + const sal_uInt16 nRefNum = pNew->GetPhyPageNum(); + if( pFtn->GetRef()->GetPhyPageNum() < nRefNum ) + break; + } + } + //Erwischt, die folgende Seite ist verkehrt, also + //muss eine neue eingefuegt werden. + if ( eMakePage == MAKEPAGE_INSERT ) + { + bNewPg = sal_True; + + SwPageFrm *pPg = pOldLayLeaf ? + pOldLayLeaf->FindPageFrm() : 0; + if ( pPg && pPg->IsEmptyPage() ) + //Nicht hinter, sondern vor der EmptyPage einfuegen. + pPg = (SwPageFrm*)pPg->GetPrev(); + + if ( !pPg || pPg == pNew ) + pPg = FindPageFrm(); + + InsertPage( pPg, sal_False ); + pLayLeaf = GetNextLayoutLeaf(); + pOldLayLeaf = 0; + continue; + } + else + pLayLeaf = 0; + } + } + break; + } + else + { + //Es gibt keinen passenden weiteren LayoutFrm, also muss eine + //neue Seite her. + if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) + { + InsertPage( + pOldLayLeaf ? pOldLayLeaf->FindPageFrm() : FindPageFrm(), + sal_False ); + + //und nochmal das ganze + pLayLeaf = pOldLayLeaf ? pOldLayLeaf : GetNextLayoutLeaf(); + } + else + break; + } + } + return pLayLeaf; +} + +/************************************************************************* +|* +|* SwFrm::GetPrevLeaf() +|* +|* Beschreibung Liefert das vorhergehende LayoutBlatt in das der +|* Frame gemoved werden kann. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetPrevLeaf( MakePageType ) +{ + OSL_ENSURE( !IsInFtn(), "GetPrevLeaf(), don't call me for Ftn." ); + + const sal_Bool bBody = IsInDocBody(); //Wenn ich aus dem DocBody komme + //will ich auch im Body landen. + const sal_Bool bFly = IsInFly(); + + SwLayoutFrm *pLayLeaf = GetPrevLayoutLeaf(); + SwLayoutFrm *pPrevLeaf = 0; + + while ( pLayLeaf ) + { + if ( pLayLeaf->IsInTab() || //In Tabellen geht's niemals hinein. + pLayLeaf->IsInSct() ) //In Bereiche natuerlich auch nicht! + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + else if ( bBody && pLayLeaf->IsInDocBody() ) + { + if ( pLayLeaf->Lower() ) + break; + pPrevLeaf = pLayLeaf; + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + if ( pLayLeaf ) + SwFlowFrm::SetMoveBwdJump( sal_True ); + } + else if ( bFly ) + break; //Cntnts in Flys sollte jedes Layout-Blatt recht sein. + else + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + } + return pLayLeaf ? pLayLeaf : pPrevLeaf; +} + +/************************************************************************* +|* +|* SwFlowFrm::IsPrevObjMove() +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::IsPrevObjMove() const +{ + //sal_True der FlowFrm soll auf einen Rahmen des Vorgaengers Ruecksicht nehmen + // und fuer diesen ggf. Umbrechen. + + //!!!!!!!!!!!Hack!!!!!!!!!!! + const ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + return sal_False; + + SwFrm *pPre = rThis.FindPrev(); + + if ( pPre && pPre->GetDrawObjs() ) + { + OSL_ENSURE( SwFlowFrm::CastFlowFrm( pPre ), "new flowfrm?" ); + if( SwFlowFrm::CastFlowFrm( pPre )->IsAnFollow( this ) ) + return sal_False; + SwLayoutFrm* pPreUp = pPre->GetUpper(); + // Wenn der Upper ein SectionFrm oder die Spalte eines SectionFrms ist, + // duerfen wir aus diesem durchaus heraushaengen, + // es muss stattdessen der Upper des SectionFrms beruecksichtigt werden. + if( pPreUp->IsInSct() ) + { + if( pPreUp->IsSctFrm() ) + pPreUp = pPreUp->GetUpper(); + else if( pPreUp->IsColBodyFrm() && + pPreUp->GetUpper()->GetUpper()->IsSctFrm() ) + pPreUp = pPreUp->GetUpper()->GetUpper()->GetUpper(); + } + // --> OD 2004-10-15 #i26945# - re-factoring: + // use <GetVertPosOrientFrm()> to determine, if object has followed the + // text flow to the next layout frame + for ( sal_uInt16 i = 0; i < pPre->GetDrawObjs()->Count(); ++i ) + { + // --> OD 2004-07-01 #i28701# - consider changed type of + // <SwSortedObjs> entries. + const SwAnchoredObject* pObj = (*pPre->GetDrawObjs())[i]; + // OD 2004-01-20 #110582# - do not consider hidden objects + // --> OD 2004-10-15 #i26945# - do not consider object, which + // doesn't follow the text flow. + if ( pObj->GetFrmFmt().GetDoc()->IsVisibleLayerId( + pObj->GetDrawObj()->GetLayer() ) && + pObj->GetFrmFmt().GetFollowTextFlow().GetValue() ) + // <-- + { + const SwLayoutFrm* pVertPosOrientFrm = pObj->GetVertPosOrientFrm(); + if ( pVertPosOrientFrm && + pPreUp != pVertPosOrientFrm && + !pPreUp->IsAnLower( pVertPosOrientFrm ) ) + { + return sal_True; + } + } + } + // <-- + } + return sal_False; +} + +/************************************************************************* +|* +|* sal_Bool SwFlowFrm::IsPageBreak() +|* +|* Beschreibung Wenn vor dem Frm ein harter Seitenumbruch steht UND +|* es einen Vorgaenger auf der gleichen Seite gibt, wird sal_True +|* zurueckgeliefert (es muss ein PageBreak erzeugt werden) sal_False sonst. +|* Wenn in bAct sal_True uebergeben wird, gibt die Funktion dann sal_True +|* zurueck, wenn ein PageBreak besteht. +|* Fuer Follows wird der harte Seitenumbruch natuerlich nicht +|* ausgewertet. +|* Der Seitenumbruch steht im eigenen FrmFmt (BEFORE) oder im FrmFmt +|* des Vorgaengers (AFTER). Wenn es keinen Vorgaenger auf der Seite +|* gibt ist jede weitere Ueberlegung ueberfluessig. +|* Ein Seitenumbruch (oder der Bedarf) liegt auch dann vor, wenn +|* im FrmFmt ein PageDesc angegeben wird. +|* Die Implementierung arbeitet zuaechst nur auf CntntFrms! +|* -->Fuer LayoutFrms ist die Definition des Vorgaengers unklar. +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::IsPageBreak( sal_Bool bAct ) const +{ + if ( !IsFollow() && rThis.IsInDocBody() && + ( !rThis.IsInTab() || ( rThis.IsTabFrm() && !rThis.GetUpper()->IsInTab() ) ) ) // i66968 + { + const ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + return sal_False; + const SwAttrSet *pSet = rThis.GetAttrSet(); + + //Vorgaenger ermitteln + const SwFrm *pPrev = rThis.FindPrev(); + while ( pPrev && ( !pPrev->IsInDocBody() || + ( pPrev->IsTxtFrm() && ((SwTxtFrm*)pPrev)->IsHiddenNow() ) ) ) + pPrev = pPrev->FindPrev(); + + if ( pPrev ) + { + OSL_ENSURE( pPrev->IsInDocBody(), "IsPageBreak: Not in DocBody?" ); + if ( bAct ) + { if ( rThis.FindPageFrm() == pPrev->FindPageFrm() ) + return sal_False; + } + else + { if ( rThis.FindPageFrm() != pPrev->FindPageFrm() ) + return sal_False; + } + + const SvxBreak eBreak = pSet->GetBreak().GetBreak(); + if ( eBreak == SVX_BREAK_PAGE_BEFORE || eBreak == SVX_BREAK_PAGE_BOTH ) + return sal_True; + else + { + const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak(); + if ( ePrB == SVX_BREAK_PAGE_AFTER || + ePrB == SVX_BREAK_PAGE_BOTH || + pSet->GetPageDesc().GetPageDesc() ) + return sal_True; + } + } + } + return sal_False; +} + +/************************************************************************* +|* +|* sal_Bool SwFlowFrm::IsColBreak() +|* +|* Beschreibung Wenn vor dem Frm ein harter Spaltenumbruch steht UND +|* es einen Vorgaenger in der gleichen Spalte gibt, wird sal_True +|* zurueckgeliefert (es muss ein PageBreak erzeugt werden) sal_False sonst. +|* Wenn in bAct sal_True uebergeben wird, gibt die Funktion dann sal_True +|* zurueck, wenn ein ColBreak besteht. +|* Fuer Follows wird der harte Spaltenumbruch natuerlich nicht +|* ausgewertet. +|* Der Spaltenumbruch steht im eigenen FrmFmt (BEFORE) oder im FrmFmt +|* des Vorgaengers (AFTER). Wenn es keinen Vorgaenger in der Spalte +|* gibt ist jede weitere Ueberlegung ueberfluessig. +|* Die Implementierung arbeitet zuaechst nur auf CntntFrms! +|* -->Fuer LayoutFrms ist die Definition des Vorgaengers unklar. +|* +|*************************************************************************/ + +sal_Bool SwFlowFrm::IsColBreak( sal_Bool bAct ) const +{ + if ( !IsFollow() && (rThis.IsMoveable() || bAct) ) + { + const SwFrm *pCol = rThis.FindColFrm(); + if ( pCol ) + { + //Vorgaenger ermitteln + const SwFrm *pPrev = rThis.FindPrev(); + while( pPrev && ( ( !pPrev->IsInDocBody() && !rThis.IsInFly() ) || + ( pPrev->IsTxtFrm() && ((SwTxtFrm*)pPrev)->IsHiddenNow() ) ) ) + pPrev = pPrev->FindPrev(); + + if ( pPrev ) + { + if ( bAct ) + { if ( pCol == pPrev->FindColFrm() ) + return sal_False; + } + else + { if ( pCol != pPrev->FindColFrm() ) + return sal_False; + } + + const SvxBreak eBreak = rThis.GetAttrSet()->GetBreak().GetBreak(); + if ( eBreak == SVX_BREAK_COLUMN_BEFORE || + eBreak == SVX_BREAK_COLUMN_BOTH ) + return sal_True; + else + { + const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak(); + if ( ePrB == SVX_BREAK_COLUMN_AFTER || + ePrB == SVX_BREAK_COLUMN_BOTH ) + return sal_True; + } + } + } + } + return sal_False; +} + +sal_Bool SwFlowFrm::HasParaSpaceAtPages( sal_Bool bSct ) const +{ + if( rThis.IsInSct() ) + { + const SwFrm* pTmp = rThis.GetUpper(); + while( pTmp ) + { + if( pTmp->IsCellFrm() || pTmp->IsFlyFrm() || + pTmp->IsFooterFrm() || pTmp->IsHeaderFrm() || + ( pTmp->IsFtnFrm() && !((SwFtnFrm*)pTmp)->GetMaster() ) ) + return sal_True; + if( pTmp->IsPageFrm() ) + return ( pTmp->GetPrev() && !IsPageBreak(sal_True) ) ? sal_False : sal_True; + if( pTmp->IsColumnFrm() && pTmp->GetPrev() ) + return IsColBreak( sal_True ); + if( pTmp->IsSctFrm() && ( !bSct || pTmp->GetPrev() ) ) + return sal_False; + pTmp = pTmp->GetUpper(); + } + OSL_FAIL( "HasParaSpaceAtPages: Where's my page?" ); + return sal_False; + } + if( !rThis.IsInDocBody() || ( rThis.IsInTab() && !rThis.IsTabFrm()) || + IsPageBreak( sal_True ) || ( rThis.FindColFrm() && IsColBreak( sal_True ) ) ) + return sal_True; + const SwFrm* pTmp = rThis.FindColFrm(); + if( pTmp ) + { + if( pTmp->GetPrev() ) + return sal_False; + } + else + pTmp = &rThis; + pTmp = pTmp->FindPageFrm(); + return pTmp && !pTmp->GetPrev(); +} + +/** helper method to determine previous frame for calculation of the + upper space + + OD 2004-03-10 #i11860# + + @author OD +*/ +const SwFrm* SwFlowFrm::_GetPrevFrmForUpperSpaceCalc( const SwFrm* _pProposedPrevFrm ) const +{ + const SwFrm* pPrevFrm = _pProposedPrevFrm + ? _pProposedPrevFrm + : rThis.GetPrev(); + + // Skip hidden paragraphs and empty sections + while ( pPrevFrm && + ( ( pPrevFrm->IsTxtFrm() && + static_cast<const SwTxtFrm*>(pPrevFrm)->IsHiddenNow() ) || + ( pPrevFrm->IsSctFrm() && + !static_cast<const SwSectionFrm*>(pPrevFrm)->GetSection() ) ) ) + { + pPrevFrm = pPrevFrm->GetPrev(); + } + + // Special case: no direct previous frame is found but frame is in footnote + // Search for a previous frame in previous footnote, + // if frame isn't in a section, which is also in the footnote + if ( !pPrevFrm && rThis.IsInFtn() && + ( rThis.IsSctFrm() || + !rThis.IsInSct() || !rThis.FindSctFrm()->IsInFtn() ) ) + { + const SwFtnFrm* pPrevFtnFrm = + static_cast<const SwFtnFrm*>(rThis.FindFtnFrm()->GetPrev()); + if ( pPrevFtnFrm ) + { + pPrevFrm = pPrevFtnFrm->GetLastLower(); + + // Skip hidden paragraphs and empty sections + while ( pPrevFrm && + ( ( pPrevFrm->IsTxtFrm() && + static_cast<const SwTxtFrm*>(pPrevFrm)->IsHiddenNow() ) || + ( pPrevFrm->IsSctFrm() && + !static_cast<const SwSectionFrm*>(pPrevFrm)->GetSection() ) ) ) + { + pPrevFrm = pPrevFrm->GetPrev(); + } + } + } + // Special case: found previous frame is a section + // Search for the last content in the section + if( pPrevFrm && pPrevFrm->IsSctFrm() ) + { + const SwSectionFrm* pPrevSectFrm = + static_cast<const SwSectionFrm*>(pPrevFrm); + pPrevFrm = pPrevSectFrm->FindLastCntnt(); + // If the last content is in a table _inside_ the section, + // take the table herself. + // OD 2004-02-18 #106629# - correction: + // Check directly, if table is inside table, instead of indirectly + // by checking, if section isn't inside a table + if ( pPrevFrm && pPrevFrm->IsInTab() ) + { + const SwTabFrm* pTableFrm = pPrevFrm->FindTabFrm(); + if ( pPrevSectFrm->IsAnLower( pTableFrm ) ) + { + pPrevFrm = pTableFrm; + } + } + // OD 2004-02-18 #106629# correction: skip hidden text frames + while ( pPrevFrm && + pPrevFrm->IsTxtFrm() && + static_cast<const SwTxtFrm*>(pPrevFrm)->IsHiddenNow() ) + { + pPrevFrm = pPrevFrm->GetPrev(); + } + } + + return pPrevFrm; +} + +// OD 2004-03-12 #i11860# - add 3rd parameter <_bConsiderGrid> +SwTwips SwFlowFrm::CalcUpperSpace( const SwBorderAttrs *pAttrs, + const SwFrm* pPr, + const bool _bConsiderGrid ) const +{ + // OD 2004-03-10 #i11860# - use new method <GetPrevFrmForUpperSpaceCalc(..)> + const SwFrm* pPrevFrm = _GetPrevFrmForUpperSpaceCalc( pPr ); + + SwBorderAttrAccess *pAccess; + SwFrm* pOwn; + if( !pAttrs ) + { + if( rThis.IsSctFrm() ) + { + SwSectionFrm* pFoll = &((SwSectionFrm&)rThis); + do + pOwn = pFoll->ContainsAny(); + while( !pOwn && 0 != ( pFoll = pFoll->GetFollow() ) ); + if( !pOwn ) + return 0; + } + else + pOwn = &rThis; + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), pOwn ); + pAttrs = pAccess->Get(); + } + else + { + pAccess = NULL; + pOwn = &rThis; + } + SwTwips nUpper = 0; + // OD 06.01.2004 #i11859# + { + const IDocumentSettingAccess* pIDSA = rThis.GetUpper()->GetFmt()->getIDocumentSettingAccess(); + const bool bUseFormerLineSpacing = pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING); + if( pPrevFrm ) + { + // OD 2004-03-10 #i11860# - use new method to determine needed spacing + // values of found previous frame and use these values. + SwTwips nPrevLowerSpace = 0; + SwTwips nPrevLineSpacing = 0; + // --> OD 2009-08-28 #i102458# + bool bPrevLineSpacingPorportional = false; + GetSpacingValuesOfFrm( (*pPrevFrm), + nPrevLowerSpace, nPrevLineSpacing, + bPrevLineSpacingPorportional ); + // <-- + if( pIDSA->get(IDocumentSettingAccess::PARA_SPACE_MAX) ) + { + nUpper = nPrevLowerSpace + pAttrs->GetULSpace().GetUpper(); + SwTwips nAdd = nPrevLineSpacing; + // OD 07.01.2004 #i11859# - consideration of the line spacing + // for the upper spacing of a text frame + if ( bUseFormerLineSpacing ) + { + // former consideration + if ( pOwn->IsTxtFrm() ) + { + nAdd = Max( nAdd, static_cast<SwTxtFrm&>(rThis).GetLineSpace() ); + } + nUpper += nAdd; + } + else + { + // new consideration: + // Only the proportional line spacing of the previous + // text frame is considered for the upper spacing and + // the line spacing values are add up instead of + // building its maximum. + if ( pOwn->IsTxtFrm() ) + { + // --> OD 2009-08-28 #i102458# + // Correction: + // A proportional line spacing of the previous text frame + // is added up to a own leading line spacing. + // Otherwise, the maximum of the leading line spacing + // of the previous text frame and the own leading line + // spacing is built. + if ( bPrevLineSpacingPorportional ) + { + nAdd += static_cast<SwTxtFrm&>(rThis).GetLineSpace( true ); + } + else + { + nAdd = Max( nAdd, static_cast<SwTxtFrm&>(rThis).GetLineSpace( true ) ); + } + // <-- + } + nUpper += nAdd; + } + } + else + { + nUpper = Max( static_cast<long>(nPrevLowerSpace), + static_cast<long>(pAttrs->GetULSpace().GetUpper()) ); + // OD 07.01.2004 #i11859# - consideration of the line spacing + // for the upper spacing of a text frame + if ( bUseFormerLineSpacing ) + { + // former consideration + if ( pOwn->IsTxtFrm() ) + nUpper = Max( nUpper, ((SwTxtFrm*)pOwn)->GetLineSpace() ); + if ( nPrevLineSpacing != 0 ) + { + nUpper = Max( nUpper, nPrevLineSpacing ); + } + } + else + { + // new consideration: + // Only the proportional line spacing of the previous + // text frame is considered for the upper spacing and + // the line spacing values are add up and added to + // the paragraph spacing instead of building the + // maximum of the line spacings and the paragraph spacing. + SwTwips nAdd = nPrevLineSpacing; + if ( pOwn->IsTxtFrm() ) + { + // --> OD 2009-08-28 #i102458# + // Correction: + // A proportional line spacing of the previous text frame + // is added up to a own leading line spacing. + // Otherwise, the maximum of the leading line spacing + // of the previous text frame and the own leading line + // spacing is built. + if ( bPrevLineSpacingPorportional ) + { + nAdd += static_cast<SwTxtFrm&>(rThis).GetLineSpace( true ); + } + else + { + nAdd = Max( nAdd, static_cast<SwTxtFrm&>(rThis).GetLineSpace( true ) ); + } + // <-- + } + nUpper += nAdd; + } + } + } + else if ( pIDSA->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES) && + CastFlowFrm( pOwn )->HasParaSpaceAtPages( rThis.IsSctFrm() ) ) + { + nUpper = pAttrs->GetULSpace().GetUpper(); + } + } + + // OD 2004-02-26 #i25029# - pass previous frame <pPrevFrm> + // to method <GetTopLine(..)>, if parameter <pPr> is set. + // Note: parameter <pPr> is set, if method is called from <SwTxtFrm::WouldFit(..)> + nUpper += pAttrs->GetTopLine( rThis, (pPr ? pPrevFrm : 0L) ); + + // OD 2004-03-12 #i11860# - consider value of new parameter <_bConsiderGrid> + // and use new method <GetUpperSpaceAmountConsideredForPageGrid(..)> + + //consider grid in square page mode + if ( _bConsiderGrid && rThis.GetUpper()->GetFmt()->GetDoc()->IsSquaredPageMode() ) + { + nUpper += _GetUpperSpaceAmountConsideredForPageGrid( nUpper ); + } + + delete pAccess; + return nUpper; +} + +/** method to detemine the upper space amount, which is considered for + the page grid + + OD 2004-03-12 #i11860# + Precondition: Position of frame is valid. + + @author OD +*/ +SwTwips SwFlowFrm::_GetUpperSpaceAmountConsideredForPageGrid( + const SwTwips _nUpperSpaceWithoutGrid ) const +{ + SwTwips nUpperSpaceAmountConsideredForPageGrid = 0; + + if ( rThis.IsInDocBody() && rThis.GetAttrSet()->GetParaGrid().GetValue() ) + { + const SwPageFrm* pPageFrm = rThis.FindPageFrm(); + GETGRID( pPageFrm ) + if( pGrid ) + { + const SwFrm* pBodyFrm = pPageFrm->FindBodyCont(); + if ( pBodyFrm ) + { + const long nGridLineHeight = + pGrid->GetBaseHeight() + pGrid->GetRubyHeight(); + + SWRECTFN( (&rThis) ) + const SwTwips nBodyPrtTop = (pBodyFrm->*fnRect->fnGetPrtTop)(); + const SwTwips nProposedPrtTop = + (*fnRect->fnYInc)( (rThis.Frm().*fnRect->fnGetTop)(), + _nUpperSpaceWithoutGrid ); + + const SwTwips nSpaceAbovePrtTop = + (*fnRect->fnYDiff)( nProposedPrtTop, nBodyPrtTop ); + const SwTwips nSpaceOfCompleteLinesAbove = + nGridLineHeight * ( nSpaceAbovePrtTop / nGridLineHeight ); + SwTwips nNewPrtTop = + (*fnRect->fnYInc)( nBodyPrtTop, nSpaceOfCompleteLinesAbove ); + if ( (*fnRect->fnYDiff)( nProposedPrtTop, nNewPrtTop ) > 0 ) + { + nNewPrtTop = (*fnRect->fnYInc)( nNewPrtTop, nGridLineHeight ); + } + + const SwTwips nNewUpperSpace = + (*fnRect->fnYDiff)( nNewPrtTop, + (rThis.Frm().*fnRect->fnGetTop)() ); + + nUpperSpaceAmountConsideredForPageGrid = + nNewUpperSpace - _nUpperSpaceWithoutGrid; + + OSL_ENSURE( nUpperSpaceAmountConsideredForPageGrid >= 0, + "<SwFlowFrm::GetUpperSpaceAmountConsideredForPageGrid(..)> - negative space considered for page grid!" ); + } + } + } + return nUpperSpaceAmountConsideredForPageGrid; +} + +/** method to determent the upper space amount, which is considered for + the previous frame + + OD 2004-03-11 #i11860# + + @author OD +*/ +SwTwips SwFlowFrm::_GetUpperSpaceAmountConsideredForPrevFrm() const +{ + SwTwips nUpperSpaceAmountOfPrevFrm = 0; + + const SwFrm* pPrevFrm = _GetPrevFrmForUpperSpaceCalc(); + if ( pPrevFrm ) + { + SwTwips nPrevLowerSpace = 0; + SwTwips nPrevLineSpacing = 0; + // --> OD 2009-08-28 #i102458# + bool bDummy = false; + GetSpacingValuesOfFrm( (*pPrevFrm), nPrevLowerSpace, nPrevLineSpacing, bDummy ); + // <-- + if ( nPrevLowerSpace > 0 || nPrevLineSpacing > 0 ) + { + const IDocumentSettingAccess* pIDSA = rThis.GetUpper()->GetFmt()->getIDocumentSettingAccess(); + if ( pIDSA->get(IDocumentSettingAccess::PARA_SPACE_MAX) || + !pIDSA->get(IDocumentSettingAccess::OLD_LINE_SPACING) ) + { + nUpperSpaceAmountOfPrevFrm = nPrevLowerSpace + nPrevLineSpacing; + } + else + { + nUpperSpaceAmountOfPrevFrm = Max( nPrevLowerSpace, nPrevLineSpacing ); + } + } + } + + return nUpperSpaceAmountOfPrevFrm; +} + +/** method to determine the upper space amount, which is considered for + the previous frame and the page grid, if option 'Use former object + positioning' is OFF + + OD 2004-03-18 #i11860# + + @author OD +*/ +SwTwips SwFlowFrm::GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() const +{ + SwTwips nUpperSpaceAmountConsideredForPrevFrmAndPageGrid = 0; + + if ( !rThis.GetUpper()->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) ) + { + nUpperSpaceAmountConsideredForPrevFrmAndPageGrid = + _GetUpperSpaceAmountConsideredForPrevFrm() + + _GetUpperSpaceAmountConsideredForPageGrid( CalcUpperSpace( 0L, 0L, false ) ); + } + + return nUpperSpaceAmountConsideredForPrevFrmAndPageGrid; +} + +/** calculation of lower space + + OD 2004-03-02 #106629# + + @author OD +*/ +SwTwips SwFlowFrm::CalcLowerSpace( const SwBorderAttrs* _pAttrs ) const +{ + SwTwips nLowerSpace = 0; + + SwBorderAttrAccess* pAttrAccess = 0L; + if ( !_pAttrs ) + { + pAttrAccess = new SwBorderAttrAccess( SwFrm::GetCache(), &rThis ); + _pAttrs = pAttrAccess->Get(); + } + + sal_Bool bCommonBorder = sal_True; + if ( rThis.IsInSct() && rThis.GetUpper()->IsColBodyFrm() ) + { + const SwSectionFrm* pSectFrm = rThis.FindSctFrm(); + bCommonBorder = pSectFrm->GetFmt()->GetBalancedColumns().GetValue(); + } + nLowerSpace = bCommonBorder ? + _pAttrs->GetBottomLine( rThis ) : + _pAttrs->CalcBottomLine(); + + // --> OD 2004-07-16 #i26250# + // - correct consideration of table frames + // - use new method <CalcAddLowerSpaceAsLastInTableCell(..)> + if ( ( ( rThis.IsTabFrm() && rThis.GetUpper()->IsInTab() ) || + // --> OD 2004-11-16 #115759# - no lower spacing, if frame has a follow + ( rThis.IsInTab() && !GetFollow() ) ) && + // <-- + !rThis.GetIndNext() ) + { + nLowerSpace += CalcAddLowerSpaceAsLastInTableCell( _pAttrs ); + } + // <-- + + delete pAttrAccess; + + return nLowerSpace; +} + +/** calculation of the additional space to be considered, if flow frame + is the last inside a table cell + + OD 2004-07-16 #i26250# + + @author OD +*/ +SwTwips SwFlowFrm::CalcAddLowerSpaceAsLastInTableCell( + const SwBorderAttrs* _pAttrs ) const +{ + SwTwips nAdditionalLowerSpace = 0; + + if ( rThis.GetUpper()->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) ) + { + const SwFrm* pFrm = &rThis; + if ( pFrm->IsSctFrm() ) + { + const SwSectionFrm* pSectFrm = static_cast<const SwSectionFrm*>(pFrm); + pFrm = pSectFrm->FindLastCntnt(); + if ( pFrm && pFrm->IsInTab() ) + { + const SwTabFrm* pTableFrm = pFrm->FindTabFrm(); + if ( pSectFrm->IsAnLower( pTableFrm ) ) + { + pFrm = pTableFrm; + } + } + } + + SwBorderAttrAccess* pAttrAccess = 0L; + if ( !_pAttrs || pFrm != &rThis ) + { + pAttrAccess = new SwBorderAttrAccess( SwFrm::GetCache(), pFrm ); + _pAttrs = pAttrAccess->Get(); + } + + nAdditionalLowerSpace += _pAttrs->GetULSpace().GetLower(); + + delete pAttrAccess; + } + + return nAdditionalLowerSpace; +} + +/************************************************************************* +|* +|* sal_Bool SwFlowFrm::CheckMoveFwd() +|* +|* Beschreibung Moved den Frm vorwaerts wenn es durch die aktuellen +|* Bedingungen und Attribute notwendig erscheint. +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::CheckMoveFwd( sal_Bool &rbMakePage, sal_Bool bKeep, sal_Bool ) +{ + const SwFrm* pNxt = rThis.GetIndNext(); + + if ( bKeep && //!bMovedBwd && + ( !pNxt || ( pNxt->IsTxtFrm() && ((SwTxtFrm*)pNxt)->IsEmptyMaster() ) ) && + ( 0 != (pNxt = rThis.FindNext()) ) && IsKeepFwdMoveAllowed() ) + { + if( pNxt->IsSctFrm() ) + { // Nicht auf leere SectionFrms hereinfallen + const SwFrm* pTmp = NULL; + while( pNxt && pNxt->IsSctFrm() && + ( !((SwSectionFrm*)pNxt)->GetSection() || + 0 == ( pTmp = ((SwSectionFrm*)pNxt)->ContainsAny() ) ) ) + { + pNxt = pNxt->FindNext(); + pTmp = NULL; + } + if( pTmp ) + pNxt = pTmp; // the content of the next notempty sectionfrm + } + if( pNxt && pNxt->GetValidPosFlag() ) + { + sal_Bool bMove = sal_False; + const SwSectionFrm *pSct = rThis.FindSctFrm(); + if( pSct && !pSct->GetValidSizeFlag() ) + { + const SwSectionFrm* pNxtSct = pNxt->FindSctFrm(); + if( pNxtSct && pSct->IsAnFollow( pNxtSct ) ) + bMove = sal_True; + } + else + bMove = sal_True; + if( bMove ) + { + //Keep together with the following frame + MoveFwd( rbMakePage, sal_False ); + return sal_True; + } + } + } + + sal_Bool bMovedFwd = sal_False; + + if ( rThis.GetIndPrev() ) + { + if ( IsPrevObjMove() ) //Auf Objekte des Prev Ruecksicht nehmen? + { + bMovedFwd = sal_True; + if ( !MoveFwd( rbMakePage, sal_False ) ) + rbMakePage = sal_False; + } + else + { + if ( IsPageBreak( sal_False ) ) + { + while ( MoveFwd( rbMakePage, sal_True ) ) + /* do nothing */; + rbMakePage = sal_False; + bMovedFwd = sal_True; + } + else if ( IsColBreak ( sal_False ) ) + { + const SwPageFrm *pPage = rThis.FindPageFrm(); + SwFrm *pCol = rThis.FindColFrm(); + do + { MoveFwd( rbMakePage, sal_False ); + SwFrm *pTmp = rThis.FindColFrm(); + if( pTmp != pCol ) + { + bMovedFwd = sal_True; + pCol = pTmp; + } + else + break; + } while ( IsColBreak( sal_False ) ); + if ( pPage != rThis.FindPageFrm() ) + rbMakePage = sal_False; + } + } + } + return bMovedFwd; +} + +/************************************************************************* +|* +|* sal_Bool SwFlowFrm::MoveFwd() +|* +|* Beschreibung Returnwert sagt, ob der Frm die Seite gewechselt hat. +|* +|*************************************************************************/ + + +sal_Bool SwFlowFrm::MoveFwd( sal_Bool bMakePage, sal_Bool bPageBreak, sal_Bool bMoveAlways ) +{ +//!!!!MoveFtnCntFwd muss ggf. mitgepflegt werden. + SwFtnBossFrm *pOldBoss = rThis.FindFtnBossFrm(); + if ( rThis.IsInFtn() ) + return ((SwCntntFrm&)rThis).MoveFtnCntFwd( bMakePage, pOldBoss ); + + if( !IsFwdMoveAllowed() && !bMoveAlways ) + { + sal_Bool bNoFwd = sal_True; + if( rThis.IsInSct() ) + { + SwFtnBossFrm* pBoss = rThis.FindFtnBossFrm(); + bNoFwd = !pBoss->IsInSct() || ( !pBoss->Lower()->GetNext() && + !pBoss->GetPrev() ); + } + + // Allow the MoveFwd even if we do not have an IndPrev in these cases: + if ( rThis.IsInTab() && + ( !rThis.IsTabFrm() || + ( rThis.GetUpper()->IsInTab() && + rThis.GetUpper()->FindTabFrm()->IsFwdMoveAllowed() ) ) && + 0 != const_cast<SwFrm&>(rThis).GetNextCellLeaf( MAKEPAGE_NONE ) ) + { + bNoFwd = sal_False; + } + + if( bNoFwd ) + { + //Fuer PageBreak ist das Moven erlaubt, wenn der Frm nicht + //bereits der erste der Seite ist. + if ( !bPageBreak ) + return sal_False; + + const SwFrm *pCol = rThis.FindColFrm(); + if ( !pCol || !pCol->GetPrev() ) + return sal_False; + } + } + + sal_Bool bSamePage = sal_True; + SwLayoutFrm *pNewUpper = + rThis.GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, sal_True ); + + if ( pNewUpper ) + { + PROTOCOL_ENTER( &rThis, PROT_MOVE_FWD, 0, 0 ); + SwPageFrm *pOldPage = pOldBoss->FindPageFrm(); + //Wir moven uns und alle direkten Nachfolger vor den ersten + //CntntFrm unterhalb des neuen Uppers. + + // Wenn unser NewUpper in einem SectionFrm liegt, muessen wir + // verhindern, dass sich dieser im Calc selbst zerstoert + SwSectionFrm* pSect = pNewUpper->FindSctFrm(); + sal_Bool bUnlock = sal_False; + if( pSect ) + { + // Wenn wir nur innerhalb unseres SectionFrms die Spalte wechseln, + // rufen wir lieber kein Calc, sonst wird noch der SectionFrm + // formatiert, der wiederum uns ruft etc. + if( pSect != rThis.FindSctFrm() ) + { + bUnlock = !pSect->IsColLocked(); + pSect->ColLock(); + pNewUpper->Calc(); + if( bUnlock ) + pSect->ColUnlock(); + } + } + // Do not calculate split cell frames. + else if ( !pNewUpper->IsCellFrm() || ((SwLayoutFrm*)pNewUpper)->Lower() ) + pNewUpper->Calc(); + + SwFtnBossFrm *pNewBoss = pNewUpper->FindFtnBossFrm(); + sal_Bool bBossChg = pNewBoss != pOldBoss; + pNewBoss = pNewBoss->FindFtnBossFrm( sal_True ); + pOldBoss = pOldBoss->FindFtnBossFrm( sal_True ); + SwPageFrm* pNewPage = pOldPage; + + // First, we move the footnotes. + sal_Bool bFtnMoved = sal_False; + + // --> FME 2004-07-15 #i26831# + // If pSect has just been created, the printing area of pSect has + // been calculated based on the first content of its follow. + // In this case we prefer to call a SimpleFormat for this new + // section after we inserted the contents. Otherwise the section + // frame will invalidate its lowers, if its printing area changes + // in SwSectionFrm::Format, which can cause loops. + const bool bForceSimpleFormat = pSect && pSect->HasFollow() && + !pSect->ContainsAny(); + // <-- + + if ( pNewBoss != pOldBoss ) + { + pNewPage = pNewBoss->FindPageFrm(); + bSamePage = pNewPage == pOldPage; + //Damit die Fussnoten nicht auf dumme Gedanken kommen + //setzen wir hier die Deadline. + SWRECTFN( pOldBoss ) + SwSaveFtnHeight aHeight( pOldBoss, + (pOldBoss->Frm().*fnRect->fnGetBottom)() ); + SwCntntFrm* pStart = rThis.IsCntntFrm() ? + (SwCntntFrm*)&rThis : ((SwLayoutFrm&)rThis).ContainsCntnt(); + OSL_ENSURE( pStart || ( rThis.IsTabFrm() && !((SwTabFrm&)rThis).Lower() ), + "MoveFwd: Missing Content" ); + SwLayoutFrm* pBody = pStart ? ( pStart->IsTxtFrm() ? + (SwLayoutFrm*)((SwTxtFrm*)pStart)->FindBodyFrm() : 0 ) : 0; + if( pBody ) + bFtnMoved = pBody->MoveLowerFtns( pStart, pOldBoss, pNewBoss, + sal_False); + } + // Bei SectionFrms ist es moeglich, dass wir selbst durch pNewUpper->Calc() + // bewegt wurden, z. B. in den pNewUpper. + // MoveSubTree bzw. PasteTree ist auf so etwas nicht vorbereitet. + if( pNewUpper != rThis.GetUpper() ) + { + // --> FME 2004-04-19 #i27145# + SwSectionFrm* pOldSct = 0; + if ( rThis.GetUpper()->IsSctFrm() ) + { + pOldSct = static_cast<SwSectionFrm*>(rThis.GetUpper()); + } + // <-- + + MoveSubTree( pNewUpper, pNewUpper->Lower() ); + + // --> FME 2004-04-19 #i27145# + if ( pOldSct && pOldSct->GetSection() ) + { + // Prevent loops by setting the new height at + // the section frame if footnotes have been moved. + // Otherwise the call of SwLayNotify::~SwLayNotify() for + // the (invalid) section frame will invalidate the first + // lower of its follow, because it grows due to the removed + // footnotes. + // Note: If pOldSct has become empty during MoveSubTree, it + // has already been scheduled for removal. No SimpleFormat + // for these. + pOldSct->SimpleFormat(); + } + // <-- + + // --> FME 2004-07-15 #i26831# + if ( bForceSimpleFormat ) + { + pSect->SimpleFormat(); + } + // <-- + + if ( bFtnMoved && !bSamePage ) + { + pOldPage->UpdateFtnNum(); + pNewPage->UpdateFtnNum(); + } + + if( bBossChg ) + { + rThis.Prepare( PREP_BOSS_CHGD, 0, sal_False ); + if( !bSamePage ) + { + ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + if ( pSh && !pSh->Imp()->IsUpdateExpFlds() ) + pSh->GetDoc()->SetNewFldLst(true); //Wird von CalcLayout() hinterher erledigt! + + pNewPage->InvalidateSpelling(); + pNewPage->InvalidateSmartTags(); // SMARTTAGS + pNewPage->InvalidateAutoCompleteWords(); + pNewPage->InvalidateWordCount(); + } + } + } + // OD 30.10.2002 #97265# - no <CheckPageDesc(..)> in online layout + const ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + + if ( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ) + { + // --> OD 2009-12-31 #i106452# + // check page description not only in situation with sections. + if ( !bSamePage && + ( rThis.GetAttrSet()->GetPageDesc().GetPageDesc() || + pOldPage->GetPageDesc()->GetFollow() != pNewPage->GetPageDesc() ) ) + { + SwFrm::CheckPageDescs( pNewPage, sal_False ); + } + // <-- + } + } + return bSamePage; +} + + +/************************************************************************* +|* +|* sal_Bool SwFlowFrm::MoveBwd() +|* +|* Beschreibung Returnwert sagt, ob der Frm die Seite wechseln soll. +|* Sollte von abgeleiteten Klassen gerufen werden. +|* Das moven selbst muessen die abgeleiteten uebernehmen. +|* +|*************************************************************************/ + +sal_Bool SwFlowFrm::MoveBwd( sal_Bool &rbReformat ) +{ + SwFlowFrm::SetMoveBwdJump( sal_False ); + + SwFtnFrm* pFtn = rThis.FindFtnFrm(); + if ( pFtn && pFtn->IsBackMoveLocked() ) + return sal_False; + + // --> OD 2004-11-29 #115759# - text frames, which are directly inside + // tables aren't allowed to move backward. + if ( rThis.IsTxtFrm() && rThis.IsInTab() ) + { + const SwLayoutFrm* pUpperFrm = rThis.GetUpper(); + while ( pUpperFrm ) + { + if ( pUpperFrm->IsTabFrm() ) + { + return sal_False; + } + else if ( pUpperFrm->IsColumnFrm() && pUpperFrm->IsInSct() ) + { + break; + } + pUpperFrm = pUpperFrm->GetUpper(); + } + } + // <-- + + SwFtnBossFrm * pOldBoss = rThis.FindFtnBossFrm(); + SwPageFrm * const pOldPage = pOldBoss->FindPageFrm(); + SwLayoutFrm *pNewUpper = 0; + sal_Bool bCheckPageDescs = sal_False; + bool bCheckPageDescOfNextPage = false; + + if ( pFtn ) + { + //Wenn die Fussnote bereits auf der gleichen Seite/Spalte wie die Referenz + //steht, ist nix mit zurueckfliessen. Die breaks brauche fuer die + //Fussnoten nicht geprueft zu werden. + + // --> FME 2004-11-15 #i37084# FindLastCntnt does not necessarily + // have to have a result != 0 + SwFrm* pRef = 0; + const bool bEndnote = pFtn->GetAttr()->GetFtn().IsEndNote(); + if( bEndnote && pFtn->IsInSct() ) + { + SwSectionFrm* pSect = pFtn->FindSctFrm(); + if( pSect->IsEndnAtEnd() ) + pRef = pSect->FindLastCntnt( FINDMODE_LASTCNT ); + } + if( !pRef ) + pRef = pFtn->GetRef(); + // <-- + + OSL_ENSURE( pRef, "MoveBwd: Endnote for an empty section?" ); + + if( !bEndnote ) + pOldBoss = pOldBoss->FindFtnBossFrm( sal_True ); + SwFtnBossFrm *pRefBoss = pRef->FindFtnBossFrm( !bEndnote ); + if ( pOldBoss != pRefBoss && + // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)> + ( !bEndnote || + pRefBoss->IsBefore( pOldBoss ) ) + ) + pNewUpper = rThis.GetLeaf( MAKEPAGE_FTN, sal_False ); + } + else if ( IsPageBreak( sal_True ) ) //PageBreak zu beachten? + { + //Wenn auf der vorhergehenden Seite kein Frm im Body steht, + //so ist das Zurueckfliessen trotz Pagebreak sinnvoll + //(sonst: leere Seite). + //Natuerlich muessen Leereseiten geflissentlich uebersehen werden! + const SwFrm *pFlow = &rThis; + do + { + pFlow = pFlow->FindPrev(); + } while ( pFlow && + ( pFlow->FindPageFrm() == pOldPage || + !pFlow->IsInDocBody() ) ); + if ( pFlow ) + { + long nDiff = pOldPage->GetPhyPageNum() - pFlow->GetPhyPageNum(); + if ( nDiff > 1 ) + { + if ( ((SwPageFrm*)pOldPage->GetPrev())->IsEmptyPage() ) + nDiff -= 1; + if ( nDiff > 1 ) + { + pNewUpper = rThis.GetLeaf( MAKEPAGE_NONE, sal_False ); + // --> OD 2006-05-08 #i53139# + // Now <pNewUpper> is a previous layout frame, which contains + // content. But the new upper layout frame has to be the next one. + // Thus, hack for issue i14206 no longer needed, but fix for issue 114442 + // --> OD 2006-05-17 #136024# - correct fix for i53139: + // Check for wrong page description before using next new upper. + // --> OD 2006-06-06 #i66051# - further correction of fix for i53139 + // Check for correct type of new next upper layout frame + // --> OD 2006-06-08 #136538# - another correction of fix for i53139 + // Assumption, that in all cases <pNewUpper> is a previous + // layout frame, which contains content, is wrong. + // --> OD 2006-07-05 #136538# - another correction of fix for i53139 + // Beside type check, check also, if proposed new next upper + // frame is inside the same frame types. + // --> OD 2007-01-10 #i73194# - and yet another correction + // of fix for i53139: + // Assure that the new next upper layout frame doesn't + // equal the current one. + // E.g.: content is on page 3, on page 2 is only a 'ghost' + // section and on page 1 is normal content. Method <FindPrev(..)> + // will find the last content of page 1, but <GetLeaf(..)> + // returns new upper on page 2. + if ( pNewUpper->Lower() ) + { + SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NONE, sal_True ); + if ( pNewNextUpper && + pNewNextUpper != rThis.GetUpper() && + pNewNextUpper->GetType() == pNewUpper->GetType() && + pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() && + pNewNextUpper->IsInFtn() == pNewUpper->IsInFtn() && + pNewNextUpper->IsInTab() == pNewUpper->IsInTab() && + pNewNextUpper->IsInSct() == pNewUpper->IsInSct() && + !rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) ) + { + pNewUpper = pNewNextUpper; + bCheckPageDescOfNextPage = true; + } + } + // <-- + + bCheckPageDescs = sal_True; + } + } + } + } + else if ( IsColBreak( sal_True ) ) + { + //Wenn in der vorhergehenden Spalte kein CntntFrm steht, so ist + //das Zurueckfliessen trotz ColumnBreak sinnvoll + //(sonst: leere Spalte). + if( rThis.IsInSct() ) + { + pNewUpper = rThis.GetLeaf( MAKEPAGE_NONE, sal_False ); + if( pNewUpper && !SwFlowFrm::IsMoveBwdJump() && + ( pNewUpper->ContainsCntnt() || + ( ( !pNewUpper->IsColBodyFrm() || + !pNewUpper->GetUpper()->GetPrev() ) && + !pNewUpper->FindSctFrm()->GetPrev() ) ) ) + { + pNewUpper = 0; + } + // --> OD 2006-05-08 #i53139# + // --> OD 2006-09-11 #i69409# - check <pNewUpper> + // --> OD 2006-11-02 #i71065# - check <SwFlowFrm::IsMoveBwdJump()> + else if ( pNewUpper && !SwFlowFrm::IsMoveBwdJump() ) + // <-- + { + // Now <pNewUpper> is a previous layout frame, which + // contains content. But the new upper layout frame + // has to be the next one. + // --> OD 2006-05-17 #136024# - correct fix for i53139 + // Check for wrong page description before using next new upper. + // --> OD 2006-06-06 #i66051# - further correction of fix for i53139 + // Check for correct type of new next upper layout frame + // --> OD 2006-07-05 #136538# - another correction of fix for i53139 + // Beside type check, check also, if proposed new next upper + // frame is inside the same frame types. + SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NOSECTION, sal_True ); + if ( pNewNextUpper && + pNewNextUpper->GetType() == pNewUpper->GetType() && + pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() && + pNewNextUpper->IsInFtn() == pNewUpper->IsInFtn() && + pNewNextUpper->IsInTab() == pNewUpper->IsInTab() && + pNewNextUpper->IsInSct() == pNewUpper->IsInSct() && + !rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) ) + { + pNewUpper = pNewNextUpper; + } + } + // <-- + } + else + { + const SwFrm *pCol = rThis.FindColFrm(); + sal_Bool bGoOn = sal_True; + sal_Bool bJump = sal_False; + do + { + if ( pCol->GetPrev() ) + pCol = pCol->GetPrev(); + else + { + bGoOn = sal_False; + pCol = rThis.GetLeaf( MAKEPAGE_NONE, sal_False ); + } + if ( pCol ) + { + // ColumnFrms jetzt mit BodyFrm + SwLayoutFrm* pColBody = pCol->IsColumnFrm() ? + (SwLayoutFrm*)((SwLayoutFrm*)pCol)->Lower() : + (SwLayoutFrm*)pCol; + if ( pColBody->ContainsCntnt() ) + { + bGoOn = sal_False; // Hier gibt's Inhalt, wir akzeptieren diese + // nur, wenn GetLeaf() das MoveBwdJump-Flag gesetzt hat. + if( SwFlowFrm::IsMoveBwdJump() ) + { + pNewUpper = pColBody; + // --> OD 2006-05-08 #i53139# + // Now <pNewUpper> is a previous layout frame, which + // contains content. But the new upper layout frame + // has to be the next one. + // --> OD 2006-05-17 #136024# - correct fix for i53139 + // Check for wrong page description before using next new upper. + // --> OD 2006-06-06 #i66051# - further correction of fix for i53139 + // Check for correct type of new next upper layout frame + // --> OD 2006-07-05 #136538# - another correction of fix for i53139 + // Beside type check, check also, if proposed new next upper + // frame is inside the same frame types. + // --> OD 2006-11-02 #i71065# + // Check that the proposed new next upper layout + // frame isn't the current one. + SwLayoutFrm* pNewNextUpper = pNewUpper->GetLeaf( MAKEPAGE_NONE, sal_True ); + if ( pNewNextUpper && + pNewNextUpper != rThis.GetUpper() && + pNewNextUpper->GetType() == pNewUpper->GetType() && + pNewNextUpper->IsInDocBody() == pNewUpper->IsInDocBody() && + pNewNextUpper->IsInFtn() == pNewUpper->IsInFtn() && + pNewNextUpper->IsInTab() == pNewUpper->IsInTab() && + pNewNextUpper->IsInSct() == pNewUpper->IsInSct() && + !rThis.WrongPageDesc( pNewNextUpper->FindPageFrm() ) ) + { + pNewUpper = pNewNextUpper; + } + // <-- + } + } + else + { + if( pNewUpper ) // Wir hatten schon eine leere Spalte, haben + bJump = sal_True; // also eine uebersprungen + pNewUpper = pColBody; // Diese leere Spalte kommt in Frage, + // trotzdem weitersuchen + } + } + } while( bGoOn ); + if( bJump ) + SwFlowFrm::SetMoveBwdJump( sal_True ); + } + } + else //Keine Breaks also kann ich zurueckfliessen + pNewUpper = rThis.GetLeaf( MAKEPAGE_NONE, sal_False ); + + // --> OD 2004-06-23 #i27801# - no move backward of 'master' text frame, + // if - due to its object positioning - it isn't allowed to be on the new page frame + // --> OD 2005-03-07 #i44049# - add another condition for not moving backward: + // If one of its objects has restarted the layout process, moving backward + // isn't sensible either. + // --> OD 2005-04-19 #i47697# - refine condition made for issue i44049: + // - allow move backward as long as the anchored object is only temporarily + // positions considering its wrapping style. + if ( pNewUpper && + rThis.IsTxtFrm() && !IsFollow() ) + { + sal_uInt32 nToPageNum( 0L ); + const bool bMoveFwdByObjPos = SwLayouter::FrmMovedFwdByObjPos( + *(pOldPage->GetFmt()->GetDoc()), + static_cast<SwTxtFrm&>(rThis), + nToPageNum ); + if ( bMoveFwdByObjPos && + pNewUpper->FindPageFrm()->GetPhyPageNum() < nToPageNum ) + { + pNewUpper = 0; + } + // --> OD 2005-03-07 #i44049# - check, if one of its anchored objects + // has restarted the layout process. + else if ( rThis.GetDrawObjs() ) + { + sal_uInt32 i = 0; + for ( ; i < rThis.GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*rThis.GetDrawObjs())[i]; + // --> OD 2005-04-19 #i47697# - refine condition - see above + if ( pAnchoredObj->RestartLayoutProcess() && + !pAnchoredObj->IsTmpConsiderWrapInfluence() ) + // <-- + { + pNewUpper = 0; + break; + } + } + } + // <-- + } + // <-- + + //Fuer Follows ist das zurueckfliessen nur dann erlaubt wenn in der + //neuen Umgebung kein Nachbar existiert (denn dieses waere der Master). + //(6677)Wenn allerdings leere Blaetter uebersprungen wurden wird doch gemoved. + if ( pNewUpper && IsFollow() && pNewUpper->Lower() ) + { + // --> OD 2007-09-05 #i79774#, #b6596954# + // neglect empty sections in proposed new upper frame + bool bProposedNewUpperContainsOnlyEmptySections( true ); + { + const SwFrm* pLower( pNewUpper->Lower() ); + while ( pLower ) + { + if ( pLower->IsSctFrm() && + !dynamic_cast<const SwSectionFrm*>(pLower)->GetSection() ) + { + pLower = pLower->GetNext(); + continue; + } + else + { + bProposedNewUpperContainsOnlyEmptySections = false; + break; + } + } + } + if ( !bProposedNewUpperContainsOnlyEmptySections ) + { + if ( SwFlowFrm::IsMoveBwdJump() ) + { + //Nicht hinter den Master sondern in das naechstfolgende leere + //Blatt moven. + SwFrm *pFrm = pNewUpper->Lower(); + while ( pFrm->GetNext() ) + pFrm = pFrm->GetNext(); + pNewUpper = pFrm->GetLeaf( MAKEPAGE_INSERT, sal_True ); + if( pNewUpper == rThis.GetUpper() ) //Landen wir wieder an der gleichen Stelle? + pNewUpper = NULL; //dann eruebrigt sich das Moven + } + else + pNewUpper = 0; + } + // <-- + } + if ( pNewUpper && !ShouldBwdMoved( pNewUpper, sal_True, rbReformat ) ) + { + if( !pNewUpper->Lower() ) + { + if( pNewUpper->IsFtnContFrm() ) + { + pNewUpper->Cut(); + delete pNewUpper; + } + else + { + SwSectionFrm* pSectFrm = pNewUpper->FindSctFrm(); + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + if ( pSectFrm && !pSectFrm->IsColLocked() && + !pSectFrm->ContainsCntnt() && !pSectFrm->ContainsAny( true ) ) + // <-- + { + pSectFrm->DelEmpty( sal_True ); + delete pSectFrm; + rThis.bValidPos = sal_True; + } + } + } + pNewUpper = 0; + } + + // OD 2004-05-26 #i21478# - don't move backward, if flow frame wants to + // keep with next frame and next frame is locked. + // --> OD 2004-12-08 #i38232# - If next frame is a table, do *not* check, + // if it's locked. + if ( pNewUpper && !IsFollow() && + rThis.GetAttrSet()->GetKeep().GetValue() && rThis.GetIndNext() ) + { + SwFrm* pIndNext = rThis.GetIndNext(); + // --> OD 2004-12-08 #i38232# + if ( !pIndNext->IsTabFrm() ) + { + // get first content of section, while empty sections are skipped + while ( pIndNext && pIndNext->IsSctFrm() ) + { + if( static_cast<SwSectionFrm*>(pIndNext)->GetSection() ) + { + SwFrm* pTmp = static_cast<SwSectionFrm*>(pIndNext)->ContainsAny(); + if ( pTmp ) + { + pIndNext = pTmp; + break; + } + } + pIndNext = pIndNext->GetIndNext(); + } + OSL_ENSURE( !pIndNext || pIndNext->ISA(SwTxtFrm), + "<SwFlowFrm::MovedBwd(..)> - incorrect next found." ); + if ( pIndNext && pIndNext->IsFlowFrm() && + SwFlowFrm::CastFlowFrm(pIndNext)->IsJoinLocked() ) + { + pNewUpper = 0L; + } + } + // <-- + } + + // --> OD 2006-05-10 #i65250# + // layout loop control for flowing content again and again moving + // backward under the same layout condition. + if ( pNewUpper && !IsFollow() && + pNewUpper != rThis.GetUpper() && + SwLayouter::MoveBwdSuppressed( *(pOldPage->GetFmt()->GetDoc()), + *this, *pNewUpper ) ) + { + SwLayoutFrm* pNextNewUpper = pNewUpper->GetLeaf( + ( !rThis.IsSctFrm() && rThis.IsInSct() ) + ? MAKEPAGE_NOSECTION + : MAKEPAGE_NONE, + sal_True ); + // --> OD 2007-01-10 #i73194# - make code robust + OSL_ENSURE( pNextNewUpper, "<SwFlowFrm::MoveBwd(..)> - missing next new upper" ); + if ( pNextNewUpper && + ( pNextNewUpper == rThis.GetUpper() || + pNextNewUpper->GetType() != rThis.GetUpper()->GetType() ) ) + // <-- + { + pNewUpper = 0L; +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "<SwFlowFrm::MoveBwd(..)> - layout loop control for layout action <Move Backward> applied!" ); +#endif + } + } + // <-- + + OSL_ENSURE( pNewUpper != rThis.GetUpper(), + "<SwFlowFrm::MoveBwd(..)> - moving backward to the current upper frame!? -> Please inform OD." ); + if ( pNewUpper ) + { + PROTOCOL_ENTER( &rThis, PROT_MOVE_BWD, 0, 0 ); + if ( pNewUpper->IsFtnContFrm() ) + { + //Kann sein, dass ich einen Container bekam. + SwFtnFrm *pOld = rThis.FindFtnFrm(); + SwFtnFrm *pNew = new SwFtnFrm( pOld->GetFmt(), pOld, + pOld->GetRef(), pOld->GetAttr() ); + if ( pOld->GetMaster() ) + { + pNew->SetMaster( pOld->GetMaster() ); + pOld->GetMaster()->SetFollow( pNew ); + } + pNew->SetFollow( pOld ); + pOld->SetMaster( pNew ); + pNew->Paste( pNewUpper ); + pNewUpper = pNew; + } + if( pNewUpper->IsFtnFrm() && rThis.IsInSct() ) + { + SwSectionFrm* pSct = rThis.FindSctFrm(); + //Wenn wir in einem Bereich in einer Fussnote stecken, muss im + //neuen Upper ggf. ein SwSectionFrm angelegt werden + if( pSct->IsInFtn() ) + { + SwFrm* pTmp = pNewUpper->Lower(); + if( pTmp ) + { + while( pTmp->GetNext() ) + pTmp = pTmp->GetNext(); + if( !pTmp->IsSctFrm() || + ((SwSectionFrm*)pTmp)->GetFollow() != pSct ) + pTmp = NULL; + } + if( pTmp ) + pNewUpper = (SwSectionFrm*)pTmp; + else + { + pSct = new SwSectionFrm( *pSct, sal_True ); + pSct->Paste( pNewUpper ); + pSct->Init(); + pNewUpper = pSct; + pSct->SimpleFormat(); + } + } + } + sal_Bool bUnlock = sal_False; + sal_Bool bFollow = sal_False; + //Section locken, sonst kann sie bei Fluss des einzigen Cntnt etwa + //von zweiter in die erste Spalte zerstoert werden. + SwSectionFrm* pSect = pNewUpper->FindSctFrm(); + if( pSect ) + { + bUnlock = !pSect->IsColLocked(); + pSect->ColLock(); + bFollow = pSect->HasFollow(); + } + pNewUpper->Calc(); + rThis.Cut(); + // --> OD 2005-02-23 #b6229852# + // optimization: format section, if its size is invalidated and if it's + // the new parent of moved backward frame. + bool bFormatSect( false ); + // <-- + if( bUnlock ) + { + pSect->ColUnlock(); + if( pSect->HasFollow() != bFollow ) + { + pSect->InvalidateSize(); + // --> OD 2005-02-23 #b6229852# - optimization + if ( pSect == pNewUpper ) + bFormatSect = true; + // <-- + } + } + + rThis.Paste( pNewUpper ); + // --> OD 2005-02-23 #b6229852# - optimization + if ( bFormatSect ) + pSect->Calc(); + // <-- + + SwPageFrm *pNewPage = rThis.FindPageFrm(); + if( pNewPage != pOldPage ) + { + rThis.Prepare( PREP_BOSS_CHGD, (const void*)pOldPage, sal_False ); + ViewShell *pSh = rThis.getRootFrm()->GetCurrShell(); + if ( pSh && !pSh->Imp()->IsUpdateExpFlds() ) + pSh->GetDoc()->SetNewFldLst(true); //Wird von CalcLayout() hinterher eledigt! + + pNewPage->InvalidateSpelling(); + pNewPage->InvalidateSmartTags(); // SMARTTAGS + pNewPage->InvalidateAutoCompleteWords(); + pNewPage->InvalidateWordCount(); + + // OD 30.10.2002 #97265# - no <CheckPageDesc(..)> in online layout + if ( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ) + { + if ( bCheckPageDescs && pNewPage->GetNext() ) + { + SwPageFrm* pStartPage = bCheckPageDescOfNextPage ? + pNewPage : + (SwPageFrm*)pNewPage->GetNext(); + SwFrm::CheckPageDescs( pStartPage, sal_False); + } + else if ( rThis.GetAttrSet()->GetPageDesc().GetPageDesc() ) + { + //Erste Seite wird etwa durch Ausblenden eines Bereiches leer + SwFrm::CheckPageDescs( (SwPageFrm*)pNewPage, sal_False); + } + } + } + } + return pNewUpper != 0; +} + +/************************************************************************* +|* +|* SwFlowFrm::CastFlowFrm +|* +|*************************************************************************/ + +SwFlowFrm *SwFlowFrm::CastFlowFrm( SwFrm *pFrm ) +{ + if ( pFrm->IsCntntFrm() ) + return (SwCntntFrm*)pFrm; + if ( pFrm->IsTabFrm() ) + return (SwTabFrm*)pFrm; + if ( pFrm->IsSctFrm() ) + return (SwSectionFrm*)pFrm; + return 0; +} + +const SwFlowFrm *SwFlowFrm::CastFlowFrm( const SwFrm *pFrm ) +{ + if ( pFrm->IsCntntFrm() ) + return (SwCntntFrm*)pFrm; + if ( pFrm->IsTabFrm() ) + return (SwTabFrm*)pFrm; + if ( pFrm->IsSctFrm() ) + return (SwSectionFrm*)pFrm; + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx new file mode 100644 index 000000000000..5b265942d561 --- /dev/null +++ b/sw/source/core/layout/fly.cxx @@ -0,0 +1,2882 @@ +/* -*- 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 <svl/itemiter.hxx> +#include <svtools/imap.hxx> +#include <vcl/graph.hxx> +#include <tools/poly.hxx> +#include <svx/contdlg.hxx> +#include <editeng/protitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/keepitem.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fmtcntnt.hxx> +#include <fmturl.hxx> +#include <fmtsrnd.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fmtcnct.hxx> +#include <layhelp.hxx> +#include <ndtxt.hxx> +#include <svx/svdogrp.hxx> +#include <ndgrf.hxx> +#include <tolayoutanchoredobjectposition.hxx> +#include <fmtfollowtextflow.hxx> +#include <sortedobjs.hxx> +#include <objectformatter.hxx> +#include <anchoredobject.hxx> +#include <ndole.hxx> +#include <swtable.hxx> +#include <svx/svdpage.hxx> +#include "doc.hxx" +#include "viewsh.hxx" +#include "layouter.hxx" +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "pam.hxx" +#include "frmatr.hxx" +#include "viewimp.hxx" +#include "viewopt.hxx" +#include "dcontact.hxx" +#include "dflyobj.hxx" +#include "dview.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "frmfmt.hxx" +#include "hints.hxx" +#include "swregion.hxx" +#include "tabfrm.hxx" +#include "txtfrm.hxx" +#include "ndnotxt.hxx" +#include "notxtfrm.hxx" // GetGrfArea +#include "flyfrms.hxx" +#include "ndindex.hxx" // GetGrfArea +#include "sectfrm.hxx" +#include <vcl/svapp.hxx> +#include <vcl/salbtype.hxx> // FRound +#include "switerator.hxx" + +using namespace ::com::sun::star; + + +// OD 2004-03-23 #i26791 +TYPEINIT2(SwFlyFrm,SwLayoutFrm,SwAnchoredObject); + +/************************************************************************* +|* +|* SwFlyFrm::SwFlyFrm() +|* +|*************************************************************************/ + +SwFlyFrm::SwFlyFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) : + SwLayoutFrm( pFmt, pSib ), + // OD 2004-03-22 #i26791# + SwAnchoredObject(), + // OD 2004-05-27 #i26791# - moved to <SwAnchoredObject> +// aRelPos(), + pPrevLink( 0 ), + pNextLink( 0 ), + bInCnt( sal_False ), + bAtCnt( sal_False ), + bLayout( sal_False ), + bAutoPosition( sal_False ), + bNoShrink( sal_False ), + bLockDeleteContent( sal_False ) +{ + nType = FRMC_FLY; + + bInvalid = bNotifyBack = sal_True; + bLocked = bMinHeight = + bHeightClipped = bWidthClipped = bFormatHeightOnly = sal_False; + + //Grosseneinstellung, Fixe groesse ist immer die Breite + const SwFmtFrmSize &rFrmSize = pFmt->GetFrmSize(); + sal_Bool bVert = sal_False; + sal_uInt16 nDir = + ((SvxFrameDirectionItem&)pFmt->GetFmtAttr( RES_FRAMEDIR )).GetValue(); + if( FRMDIR_ENVIRONMENT == nDir ) + { + bDerivedVert = 1; + bDerivedR2L = 1; + if( pAnch && pAnch->IsVertical() ) + bVert = sal_True; + } + else + { + bInvalidVert = 0; + bDerivedVert = 0; + bDerivedR2L = 0; + if( FRMDIR_HORI_LEFT_TOP == nDir || FRMDIR_HORI_RIGHT_TOP == nDir ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + bVertLR = 0; + bVertical = 0; + } + else + { + const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + bVertLR = 0; + bVertical = 0; + } + else + { + bVertical = 1; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( FRMDIR_VERT_TOP_LEFT == nDir ) + bVertLR = 1; + else + bVertLR = 0; + } + } + + bVert = bVertical; + bInvalidR2L = 0; + if( FRMDIR_HORI_RIGHT_TOP == nDir ) + bRightToLeft = 1; + else + bRightToLeft = 0; + } + + Frm().Width( rFrmSize.GetWidth() ); + Frm().Height( rFrmSize.GetHeightSizeType() == ATT_VAR_SIZE ? MINFLY : rFrmSize.GetHeight() ); + + //Hoehe Fix oder Variabel oder was? + if ( rFrmSize.GetHeightSizeType() == ATT_MIN_SIZE ) + bMinHeight = sal_True; + else if ( rFrmSize.GetHeightSizeType() == ATT_FIX_SIZE ) + bFixSize = sal_True; + + // OD 2004-02-12 #110582#-2 - insert columns, if necessary + InsertColumns(); + + //Erst das Init, dann den Inhalt, denn zum Inhalt koennen widerum + //Objekte/Rahmen gehoeren die dann angemeldet werden. + InitDrawObj( sal_False ); + + // OD 2004-01-19 #110582# + Chain( pAnch ); + + // OD 2004-01-19 #110582# + InsertCnt(); + + //Und erstmal in den Wald stellen die Kiste, damit bei neuen Dokument nicht + //unnoetig viel formatiert wird. + Frm().Pos().X() = Frm().Pos().Y() = WEIT_WECH; +} + +// OD 2004-01-19 #110582# +void SwFlyFrm::Chain( SwFrm* _pAnch ) +{ + // Connect to chain neighboors. + // No problem, if a neighboor doesn't exist - the construction of the + // neighboor will make the connection + const SwFmtChain& rChain = GetFmt()->GetChain(); + if ( rChain.GetPrev() || rChain.GetNext() ) + { + if ( rChain.GetNext() ) + { + SwFlyFrm* pFollow = FindChainNeighbour( *rChain.GetNext(), _pAnch ); + if ( pFollow ) + { + OSL_ENSURE( !pFollow->GetPrevLink(), "wrong chain detected" ); + if ( !pFollow->GetPrevLink() ) + SwFlyFrm::ChainFrames( this, pFollow ); + } + } + if ( rChain.GetPrev() ) + { + SwFlyFrm *pMaster = FindChainNeighbour( *rChain.GetPrev(), _pAnch ); + if ( pMaster ) + { + OSL_ENSURE( !pMaster->GetNextLink(), "wrong chain detected" ); + if ( !pMaster->GetNextLink() ) + SwFlyFrm::ChainFrames( pMaster, this ); + } + } + } +} + +// OD 2004-01-19 #110582# +void SwFlyFrm::InsertCnt() +{ + if ( !GetPrevLink() ) + { + const SwFmtCntnt& rCntnt = GetFmt()->GetCntnt(); + OSL_ENSURE( rCntnt.GetCntntIdx(), ":-( no content prepared." ); + sal_uLong nIndex = rCntnt.GetCntntIdx()->GetIndex(); + // Lower() bedeutet SwColumnFrm, eingefuegt werden muss der Inhalt dann in den (Column)BodyFrm + ::_InsertCnt( Lower() ? (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower() : (SwLayoutFrm*)this, + GetFmt()->GetDoc(), nIndex ); + + //NoTxt haben immer eine FixHeight. + if ( Lower() && Lower()->IsNoTxtFrm() ) + { + bFixSize = sal_True; + bMinHeight = sal_False; + } + } +} + + // OD 2004-02-12 #110582#-2 + void SwFlyFrm::InsertColumns() + { + // --> OD 2009-08-12 #i97379# + // Check, if column are allowed. + // Columns are not allowed for fly frames, which represent graphics or embedded objects. + const SwFmtCntnt& rCntnt = GetFmt()->GetCntnt(); + OSL_ENSURE( rCntnt.GetCntntIdx(), "<SwFlyFrm::InsertColumns()> - no content prepared." ); + SwNodeIndex aFirstCntnt( *(rCntnt.GetCntntIdx()), 1 ); + if ( aFirstCntnt.GetNode().IsNoTxtNode() ) + { + return; + } + // <-- + + const SwFmtCol &rCol = GetFmt()->GetCol(); + if ( rCol.GetNumCols() > 1 ) + { + //PrtArea ersteinmal so gross wie der Frm, damit die Spalten + //vernuenftig eingesetzt werden koennen; das schaukelt sich dann + //schon zurecht. + Prt().Width( Frm().Width() ); + Prt().Height( Frm().Height() ); + const SwFmtCol aOld; //ChgColumns() verlaesst sich darauf, dass auch ein + //Old-Wert hereingereicht wird. + ChgColumns( aOld, rCol ); + } + } + +/************************************************************************* +|* +|* SwFlyFrm::~SwFlyFrm() +|* +|*************************************************************************/ + +SwFlyFrm::~SwFlyFrm() +{ + // Accessible objects for fly frames will be destroyed in this destructor. + // For frames bound as char or frames that don't have an anchor we have + // to do that ourselves. For any other frame the call RemoveFly at the + // anchor will do that. + if( IsAccessibleFrm() && GetFmt() && (IsFlyInCntFrm() || !GetAnchorFrm()) ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell *pVSh = pRootFrm->GetCurrShell(); + if( pVSh && pVSh->Imp() ) + { + // Lowers aren't disposed already, so we have to do a recursive + // dispose + pVSh->Imp()->DisposeAccessibleFrm( this, sal_True ); + } + } + } + + if( GetFmt() && !GetFmt()->GetDoc()->IsInDtor() ) + { + // OD 2004-01-19 #110582# + Unchain(); + + // OD 2004-01-19 #110582# + DeleteCnt(); + + //Tschuess sagen. + if ( GetAnchorFrm() ) + AnchorFrm()->RemoveFly( this ); + } + + FinitDrawObj(); +} + +const IDocumentDrawModelAccess* SwFlyFrm::getIDocumentDrawModelAccess() +{ + return GetFmt()->getIDocumentDrawModelAccess(); +} + +// OD 2004-01-19 #110582# +void SwFlyFrm::Unchain() +{ + if ( GetPrevLink() ) + UnchainFrames( GetPrevLink(), this ); + if ( GetNextLink() ) + UnchainFrames( this, GetNextLink() ); +} + +// OD 2004-01-19 #110582# +void SwFlyFrm::DeleteCnt() +{ + // #110582#-2 + if ( IsLockDeleteContent() ) + return; + + SwFrm* pFrm = pLower; + while ( pFrm ) + { + while ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->Count() ) + { + SwAnchoredObject *pAnchoredObj = (*pFrm->GetDrawObjs())[0]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + delete pAnchoredObj; + else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) + { + // OD 23.06.2003 #108784# - consider 'virtual' drawing objects + SdrObject* pObj = pAnchoredObj->DrawObj(); + if ( pObj->ISA(SwDrawVirtObj) ) + { + SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(pObj); + pDrawVirtObj->RemoveFromWriterLayout(); + pDrawVirtObj->RemoveFromDrawingPage(); + } + else + { + SwDrawContact* pContact = + static_cast<SwDrawContact*>(::GetUserCall( pObj )); + if ( pContact ) + { + pContact->DisconnectFromLayout(); + } + } + } + } + + pFrm->Remove(); + delete pFrm; + pFrm = pLower; + } + + InvalidatePage(); +} + +/************************************************************************* +|* +|* SwFlyFrm::InitDrawObj() +|* +|*************************************************************************/ + +sal_uInt32 SwFlyFrm::_GetOrdNumForNewRef( const SwFlyDrawContact* pContact ) +{ + sal_uInt32 nOrdNum( 0L ); + + // search for another Writer fly frame registered at same frame format + SwIterator<SwFlyFrm,SwFmt> aIter( *pContact->GetFmt() ); + const SwFlyFrm* pFlyFrm( 0L ); + for ( pFlyFrm = aIter.First(); pFlyFrm; pFlyFrm = aIter.Next() ) + { + if ( pFlyFrm != this ) + { + break; + } + } + + if ( pFlyFrm ) + { + // another Writer fly frame found. Take its order number + nOrdNum = pFlyFrm->GetVirtDrawObj()->GetOrdNum(); + } + else + { + // no other Writer fly frame found. Take order number of 'master' object + // --> OD 2004-11-11 #i35748# - use method <GetOrdNumDirect()> instead + // of method <GetOrdNum()> to avoid a recalculation of the order number, + // which isn't intended. + nOrdNum = pContact->GetMaster()->GetOrdNumDirect(); + // <-- + } + + return nOrdNum; +} + +SwVirtFlyDrawObj* SwFlyFrm::CreateNewRef( SwFlyDrawContact *pContact ) +{ + SwVirtFlyDrawObj *pDrawObj = new SwVirtFlyDrawObj( *pContact->GetMaster(), this ); + pDrawObj->SetModel( pContact->GetMaster()->GetModel() ); + pDrawObj->SetUserCall( pContact ); + + //Der Reader erzeugt die Master und setzt diese, um die Z-Order zu + //transportieren, in die Page ein. Beim erzeugen der ersten Referenz werden + //die Master aus der Liste entfernt und fuehren von da an ein + //Schattendasein. + SdrPage* pPg( 0L ); + if ( 0 != ( pPg = pContact->GetMaster()->GetPage() ) ) + { + const sal_uInt32 nOrdNum = pContact->GetMaster()->GetOrdNum(); + pPg->ReplaceObject( pDrawObj, nOrdNum ); + } + // --> OD 2004-08-16 #i27030# - insert new <SwVirtFlyDrawObj> instance + // into drawing page with correct order number + else + { + pContact->GetFmt()->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage( 0 )-> + InsertObject( pDrawObj, _GetOrdNumForNewRef( pContact ) ); + } + // <-- + // --> OD 2004-12-13 #i38889# - assure, that new <SwVirtFlyDrawObj> instance + // is in a visible layer. + pContact->MoveObjToVisibleLayer( pDrawObj ); + // <-- + return pDrawObj; +} + + + +void SwFlyFrm::InitDrawObj( sal_Bool bNotify ) +{ + //ContactObject aus dem Format suchen. Wenn bereits eines existiert, so + //braucht nur eine neue Ref erzeugt werden, anderfalls ist es jetzt an + //der Zeit das Contact zu erzeugen. + + IDocumentDrawModelAccess* pIDDMA = GetFmt()->getIDocumentDrawModelAccess(); + SwFlyDrawContact *pContact = SwIterator<SwFlyDrawContact,SwFmt>::FirstElement( *GetFmt() ); + if ( !pContact ) + { + // --> OD 2005-08-08 #i52858# - method name changed + pContact = new SwFlyDrawContact( (SwFlyFrmFmt*)GetFmt(), + pIDDMA->GetOrCreateDrawModel() ); + // <-- + } + OSL_ENSURE( pContact, "InitDrawObj failed" ); + // OD 2004-03-22 #i26791# + SetDrawObj( *(CreateNewRef( pContact )) ); + + //Den richtigen Layer setzen. + // OD 2004-01-19 #110582# + SdrLayerID nHeavenId = pIDDMA->GetHeavenId(); + SdrLayerID nHellId = pIDDMA->GetHellId(); + // OD 2004-03-22 #i26791# + GetVirtDrawObj()->SetLayer( GetFmt()->GetOpaque().GetValue() + ? nHeavenId + : nHellId ); + if ( bNotify ) + NotifyDrawObj(); +} + +/************************************************************************* +|* +|* SwFlyFrm::FinitDrawObj() +|* +|*************************************************************************/ + +void SwFlyFrm::FinitDrawObj() +{ + if ( !GetVirtDrawObj() ) + return; + + //Bei den SdrPageViews abmelden falls das Objekt dort noch selektiert ist. + if ( !GetFmt()->GetDoc()->IsInDtor() ) + { + ViewShell *p1St = getRootFrm()->GetCurrShell(); + if ( p1St ) + { + ViewShell *pSh = p1St; + do + { //z.Zt. kann das Drawing nur ein Unmark auf alles, weil das + //Objekt bereits Removed wurde. + if( pSh->HasDrawView() ) + pSh->Imp()->GetDrawView()->UnmarkAll(); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != p1St ); + } + } + + //VirtObject mit in das Grab nehmen. Wenn das letzte VirObject + //zerstoert wird, mussen das DrawObject und DrawContact ebenfalls + //zerstoert werden. + SwFlyDrawContact *pMyContact = 0; + if ( GetFmt() ) + { + bool bContinue = true; + SwIterator<SwFrm,SwFmt> aFrmIter( *GetFmt() ); + for ( SwFrm* pFrm = aFrmIter.First(); pFrm; pFrm = aFrmIter.Next() ) + if ( pFrm != this ) + { + // don't delete Contact if there is still a Frm + bContinue = false; + break; + } + + if ( bContinue ) + // no Frm left, find Contact object to destroy + pMyContact = SwIterator<SwFlyDrawContact,SwFmt>::FirstElement( *GetFmt() ); + } + + // OD, OS 2004-03-31 #116203# - clear user call of Writer fly frame 'master' + // <SdrObject> to assure, that a <SwXFrame::dispose()> doesn't delete the + // Writer fly frame again. + if ( pMyContact ) + { + pMyContact->GetMaster()->SetUserCall( 0 ); + } + GetVirtDrawObj()->SetUserCall( 0 ); //Ruft sonst Delete des ContactObj + delete GetVirtDrawObj(); //Meldet sich selbst beim Master ab. + if ( pMyContact ) + delete pMyContact; //zerstoert den Master selbst. +} + +/************************************************************************* +|* +|* SwFlyFrm::ChainFrames() +|* +|*************************************************************************/ + +void SwFlyFrm::ChainFrames( SwFlyFrm *pMaster, SwFlyFrm *pFollow ) +{ + OSL_ENSURE( pMaster && pFollow, "uncomplete chain" ); + OSL_ENSURE( !pMaster->GetNextLink(), "link can not be changed" ); + OSL_ENSURE( !pFollow->GetPrevLink(), "link can not be changed" ); + + pMaster->pNextLink = pFollow; + pFollow->pPrevLink = pMaster; + + if ( pMaster->ContainsCntnt() ) + { + //Damit ggf. ein Textfluss zustande kommt muss invalidiert werden. + SwFrm *pInva = pMaster->FindLastLower(); + SWRECTFN( pMaster ) + const long nBottom = (pMaster->*fnRect->fnGetPrtBottom)(); + while ( pInva ) + { + if( (pInva->Frm().*fnRect->fnBottomDist)( nBottom ) <= 0 ) + { + pInva->InvalidateSize(); + pInva->Prepare( PREP_CLEAR ); + pInva = pInva->FindPrev(); + } + else + pInva = 0; + } + } + + if ( pFollow->ContainsCntnt() ) + { + //Es gibt nur noch den Inhalt des Masters, der Inhalt vom Follow + //hat keine Frames mehr (sollte immer nur genau ein leerer TxtNode sein). + SwFrm *pFrm = pFollow->ContainsCntnt(); + OSL_ENSURE( !pFrm->IsTabFrm() && !pFrm->FindNext(), "follow in chain contains content" ); + pFrm->Cut(); + delete pFrm; + } + + // invalidate accessible relation set (accessibility wrapper) + ViewShell* pSh = pMaster->getRootFrm()->GetCurrShell(); + if( pSh ) + { + SwRootFrm* pLayout = pMaster->getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow ); + } +} + +void SwFlyFrm::UnchainFrames( SwFlyFrm *pMaster, SwFlyFrm *pFollow ) +{ + pMaster->pNextLink = 0; + pFollow->pPrevLink = 0; + + if ( pFollow->ContainsCntnt() ) + { + //Der Master saugt den Inhalt vom Follow auf + SwLayoutFrm *pUpper = pMaster; + if ( pUpper->Lower()->IsColumnFrm() ) + { + pUpper = static_cast<SwLayoutFrm*>(pUpper->GetLastLower()); + pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower()); // der (Column)BodyFrm + OSL_ENSURE( pUpper && pUpper->IsColBodyFrm(), "Missing ColumnBody" ); + } + SwFlyFrm *pFoll = pFollow; + while ( pFoll ) + { + SwFrm *pTmp = ::SaveCntnt( pFoll ); + if ( pTmp ) + ::RestoreCntnt( pTmp, pUpper, pMaster->FindLastLower(), true ); + pFoll->SetCompletePaint(); + pFoll->InvalidateSize(); + pFoll = pFoll->GetNextLink(); + } + } + + //Der Follow muss mit seinem eigenen Inhalt versorgt werden. + const SwFmtCntnt &rCntnt = pFollow->GetFmt()->GetCntnt(); + OSL_ENSURE( rCntnt.GetCntntIdx(), ":-( Kein Inhalt vorbereitet." ); + sal_uLong nIndex = rCntnt.GetCntntIdx()->GetIndex(); + // Lower() bedeutet SwColumnFrm, dieser beinhaltet wieder einen SwBodyFrm + ::_InsertCnt( pFollow->Lower() ? (SwLayoutFrm*)((SwLayoutFrm*)pFollow->Lower())->Lower() + : (SwLayoutFrm*)pFollow, + pFollow->GetFmt()->GetDoc(), ++nIndex ); + + // invalidate accessible relation set (accessibility wrapper) + ViewShell* pSh = pMaster->getRootFrm()->GetCurrShell(); + if( pSh ) + { + SwRootFrm* pLayout = pMaster->getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow ); +} +} + +/************************************************************************* +|* +|* SwFlyFrm::FindChainNeighbour() +|* +|*************************************************************************/ + +SwFlyFrm *SwFlyFrm::FindChainNeighbour( SwFrmFmt &rChain, SwFrm *pAnch ) +{ + //Wir suchen denjenigen Fly, der in dem selben Bereich steht. + //Bereiche koennen zunaechst nur Kopf-/Fusszeilen oder Flys sein. + + if ( !pAnch ) //Wenn ein Anchor uebergeben Wurde zaehlt dieser: Ctor! + pAnch = AnchorFrm(); + + SwLayoutFrm *pLay; + if ( pAnch->IsInFly() ) + pLay = pAnch->FindFlyFrm(); + else + { + //FindFooterOrHeader taugt hier nicht, weil evtl. noch keine Verbindung + //zum Anker besteht. + pLay = pAnch->GetUpper(); + while ( pLay && !(pLay->GetType() & (FRM_HEADER|FRM_FOOTER)) ) + pLay = pLay->GetUpper(); + } + + SwIterator<SwFlyFrm,SwFmt> aIter( rChain ); + SwFlyFrm *pFly = aIter.First(); + if ( pLay ) + { + while ( pFly ) + { + if ( pFly->GetAnchorFrm() ) + { + if ( pFly->GetAnchorFrm()->IsInFly() ) + { + if ( pFly->AnchorFrm()->FindFlyFrm() == pLay ) + break; + } + else if ( pLay == pFly->FindFooterOrHeader() ) + break; + } + pFly = aIter.Next(); + } + } + else if ( pFly ) + { + OSL_ENSURE( !aIter.Next(), "chain with more than one inkarnation" ); + } + return pFly; +} + + +/************************************************************************* +|* +|* SwFlyFrm::FindLastLower() +|* +|*************************************************************************/ + +SwFrm *SwFlyFrm::FindLastLower() +{ + SwFrm *pRet = ContainsAny(); + if ( pRet && pRet->IsInTab() ) + pRet = pRet->FindTabFrm(); + SwFrm *pNxt = pRet; + while ( pNxt && IsAnLower( pNxt ) ) + { pRet = pNxt; + pNxt = pNxt->FindNext(); + } + return pRet; +} + + +/************************************************************************* +|* +|* SwFlyFrm::FrmSizeChg() +|* +|*************************************************************************/ + +sal_Bool SwFlyFrm::FrmSizeChg( const SwFmtFrmSize &rFrmSize ) +{ + sal_Bool bRet = sal_False; + SwTwips nDiffHeight = Frm().Height(); + if ( rFrmSize.GetHeightSizeType() == ATT_VAR_SIZE ) + bFixSize = bMinHeight = sal_False; + else + { + if ( rFrmSize.GetHeightSizeType() == ATT_FIX_SIZE ) + { + bFixSize = sal_True; + bMinHeight = sal_False; + } + else if ( rFrmSize.GetHeightSizeType() == ATT_MIN_SIZE ) + { + bFixSize = sal_False; + bMinHeight = sal_True; + } + nDiffHeight -= rFrmSize.GetHeight(); + } + //Wenn der Fly Spalten enthaehlt muessen der Fly und + //die Spalten schon einmal auf die Wunschwerte gebracht + //werden, sonst haben wir ein kleines Problem. + if ( Lower() ) + { + if ( Lower()->IsColumnFrm() ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + const Size aOldSz( Prt().SSize() ); + const SwTwips nDiffWidth = Frm().Width() - rFrmSize.GetWidth(); + aFrm.Height( aFrm.Height() - nDiffHeight ); + aFrm.Width ( aFrm.Width() - nDiffWidth ); + // --> OD 2006-08-16 #i68520# + InvalidateObjRectWithSpaces(); + // <-- + aPrt.Height( aPrt.Height() - nDiffHeight ); + aPrt.Width ( aPrt.Width() - nDiffWidth ); + ChgLowersProp( aOldSz ); + ::Notify( this, FindPageFrm(), aOld ); + bValidPos = sal_False; + bRet = sal_True; + } + else if ( Lower()->IsNoTxtFrm() ) + { + bFixSize = sal_True; + bMinHeight = sal_False; + } + } + return bRet; +} + +/************************************************************************* +|* +|* SwFlyFrm::Modify() +|* +|*************************************************************************/ + +void SwFlyFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + + if( pNew && RES_ATTRSET_CHG == pNew->Which() ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + _Invalidate(); + if ( nInvFlags & 0x01 ) + { + _InvalidatePos(); + // --> OD 2006-08-16 #i68520# + InvalidateObjRectWithSpaces(); + // <-- + } + if ( nInvFlags & 0x02 ) + { + _InvalidateSize(); + // --> OD 2006-08-16 #i68520# + InvalidateObjRectWithSpaces(); + // <-- + } + if ( nInvFlags & 0x04 ) + _InvalidatePrt(); + if ( nInvFlags & 0x08 ) + SetNotifyBack(); + if ( nInvFlags & 0x10 ) + SetCompletePaint(); + if ( ( nInvFlags & 0x40 ) && Lower() && Lower()->IsNoTxtFrm() ) + ClrContourCache( GetVirtDrawObj() ); + SwRootFrm *pRoot; + if ( nInvFlags & 0x20 && 0 != (pRoot = getRootFrm()) ) + pRoot->InvalidateBrowseWidth(); + // --> OD 2004-06-28 #i28701# + if ( nInvFlags & 0x80 ) + { + // update sorted object lists, the Writer fly frame is registered at. + UpdateObjInSortedList(); + } + // <-- + } + + // --> OD 2005-07-18 #i51474# - reset flags for the layout process + ResetLayoutProcessBools(); + // <-- +} + +void SwFlyFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + ViewShell *pSh = getRootFrm()->GetCurrShell(); + switch( nWhich ) + { + case RES_VERT_ORIENT: + case RES_HORI_ORIENT: + // OD 22.09.2003 #i18732# - consider new option 'follow text flow' + case RES_FOLLOW_TEXT_FLOW: + { + //Achtung! _immer_ Aktion in ChgRePos() mitpflegen. + rInvFlags |= 0x09; + } + break; + // OD 2004-07-01 #i28701# - consider new option 'wrap influence on position' + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + rInvFlags |= 0x89; + } + break; + case RES_SURROUND: + { + // OD 2004-05-13 #i28701# - invalidate position on change of + // wrapping style. + //rInvFlags |= 0x40; + rInvFlags |= 0x41; + //Der Hintergrund muss benachrichtigt und Invalidiert werden. + const SwRect aTmp( GetObjRectWithSpaces() ); + NotifyBackground( FindPageFrm(), aTmp, PREP_FLY_ATTR_CHG ); + + // Durch eine Umlaufaenderung von rahmengebundenen Rahmen kann eine + // vertikale Ausrichtung aktiviert/deaktiviert werden => MakeFlyPos + if( FLY_AT_FLY == GetFmt()->GetAnchor().GetAnchorId() ) + rInvFlags |= 0x09; + + //Ggf. die Kontur am Node loeschen. + if ( Lower() && Lower()->IsNoTxtFrm() && + !GetFmt()->GetSurround().IsContour() ) + { + SwNoTxtNode *pNd = (SwNoTxtNode*)((SwCntntFrm*)Lower())->GetNode(); + if ( pNd->HasContour() ) + pNd->SetContour( 0 ); + } + // --> OD 2004-06-28 #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + } + break; + + case RES_PROTECT: + { + const SvxProtectItem *pP = (SvxProtectItem*)pNew; + GetVirtDrawObj()->SetMoveProtect( pP->IsPosProtected() ); + GetVirtDrawObj()->SetResizeProtect( pP->IsSizeProtected() ); + if( pSh ) + { + SwRootFrm* pLayout = getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this ); + } + break; + } + + case RES_COL: + { + ChgColumns( *(const SwFmtCol*)pOld, *(const SwFmtCol*)pNew ); + const SwFmtFrmSize &rNew = GetFmt()->GetFrmSize(); + if ( FrmSizeChg( rNew ) ) + NotifyDrawObj(); + rInvFlags |= 0x1A; + break; + } + + case RES_FRM_SIZE: + case RES_FMT_CHG: + { + const SwFmtFrmSize &rNew = GetFmt()->GetFrmSize(); + if ( FrmSizeChg( rNew ) ) + NotifyDrawObj(); + rInvFlags |= 0x7F; + if ( RES_FMT_CHG == nWhich ) + { + SwRect aNew( GetObjRectWithSpaces() ); + SwRect aOld( aFrm ); + const SvxULSpaceItem &rUL = ((SwFmtChg*)pOld)->pChangedFmt->GetULSpace(); + aOld.Top( Max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); + aOld.SSize().Height()+= rUL.GetLower(); + const SvxLRSpaceItem &rLR = ((SwFmtChg*)pOld)->pChangedFmt->GetLRSpace(); + aOld.Left ( Max( aOld.Left() - long(rLR.GetLeft()), 0L ) ); + aOld.SSize().Width() += rLR.GetRight(); + aNew.Union( aOld ); + NotifyBackground( FindPageFrm(), aNew, PREP_CLEAR ); + + //Dummer Fall. Bei der Zusweisung einer Vorlage k?nnen wir uns + //nicht auf das alte Spaltenattribut verlassen. Da diese + //wenigstens anzahlgemass fuer ChgColumns vorliegen muessen, + //bleibt uns nur einen temporaeres Attribut zu basteln. + SwFmtCol aCol; + if ( Lower() && Lower()->IsColumnFrm() ) + { + sal_uInt16 nCol = 0; + SwFrm *pTmp = Lower(); + do + { ++nCol; + pTmp = pTmp->GetNext(); + } while ( pTmp ); + aCol.Init( nCol, 0, 1000 ); + } + ChgColumns( aCol, GetFmt()->GetCol() ); + } + + SwFmtURL aURL( GetFmt()->GetURL() ); + if ( aURL.GetMap() ) + { + const SwFmtFrmSize &rOld = nWhich == RES_FRM_SIZE ? + *(SwFmtFrmSize*)pNew : + ((SwFmtChg*)pOld)->pChangedFmt->GetFrmSize(); + //#35091# Kann beim Laden von Vorlagen mal 0 sein + if ( rOld.GetWidth() && rOld.GetHeight() ) + { + + Fraction aScaleX( rOld.GetWidth(), rNew.GetWidth() ); + Fraction aScaleY( rOld.GetHeight(), rOld.GetHeight() ); + aURL.GetMap()->Scale( aScaleX, aScaleY ); + SwFrmFmt *pFmt = GetFmt(); + pFmt->LockModify(); + pFmt->SetFmtAttr( aURL ); + pFmt->UnlockModify(); + } + } + const SvxProtectItem &rP = GetFmt()->GetProtect(); + GetVirtDrawObj()->SetMoveProtect( rP.IsPosProtected() ); + GetVirtDrawObj()->SetResizeProtect( rP.IsSizeProtected() ); + + if ( pSh ) + pSh->InvalidateWindows( Frm() ); + const IDocumentDrawModelAccess* pIDDMA = GetFmt()->getIDocumentDrawModelAccess(); + const sal_uInt8 nId = GetFmt()->GetOpaque().GetValue() ? + pIDDMA->GetHeavenId() : + pIDDMA->GetHellId(); + GetVirtDrawObj()->SetLayer( nId ); + + if ( Lower() ) + { + //Ggf. die Kontur am Node loeschen. + if( Lower()->IsNoTxtFrm() && + !GetFmt()->GetSurround().IsContour() ) + { + SwNoTxtNode *pNd = (SwNoTxtNode*)((SwCntntFrm*)Lower())->GetNode(); + if ( pNd->HasContour() ) + pNd->SetContour( 0 ); + } + else if( !Lower()->IsColumnFrm() ) + { + SwFrm* pFrm = GetLastLower(); + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() ) + pFrm->Prepare( PREP_ADJUST_FRM ); + } + } + + // --> OD 2004-06-28 #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + + break; + } + case RES_UL_SPACE: + case RES_LR_SPACE: + { + rInvFlags |= 0x41; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + getRootFrm()->InvalidateBrowseWidth(); + SwRect aNew( GetObjRectWithSpaces() ); + SwRect aOld( aFrm ); + if ( RES_UL_SPACE == nWhich ) + { + const SvxULSpaceItem &rUL = *(SvxULSpaceItem*)pNew; + aOld.Top( Max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); + aOld.SSize().Height()+= rUL.GetLower(); + } + else + { + const SvxLRSpaceItem &rLR = *(SvxLRSpaceItem*)pNew; + aOld.Left ( Max( aOld.Left() - long(rLR.GetLeft()), 0L ) ); + aOld.SSize().Width() += rLR.GetRight(); + } + aNew.Union( aOld ); + NotifyBackground( FindPageFrm(), aNew, PREP_CLEAR ); + } + break; + + case RES_BOX: + case RES_SHADOW: + rInvFlags |= 0x17; + break; + + case RES_FRAMEDIR : + SetDerivedVert( sal_False ); + SetDerivedR2L( sal_False ); + CheckDirChange(); + break; + + case RES_OPAQUE: + { + if ( pSh ) + pSh->InvalidateWindows( Frm() ); + + const IDocumentDrawModelAccess* pIDDMA = GetFmt()->getIDocumentDrawModelAccess(); + const sal_uInt8 nId = ((SvxOpaqueItem*)pNew)->GetValue() ? + pIDDMA->GetHeavenId() : + pIDDMA->GetHellId(); + GetVirtDrawObj()->SetLayer( nId ); + if( pSh ) + { + SwRootFrm* pLayout = getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + { + pSh->Imp()->DisposeAccessibleFrm( this ); + pSh->Imp()->AddAccessibleFrm( this ); + } + } + // --> OD 2004-06-28 #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + } + break; + + case RES_URL: + //Das Interface arbeitet bei Textrahmen auf der Rahmengroesse, + //die Map muss sich aber auf die FrmSize beziehen + if ( (!Lower() || !Lower()->IsNoTxtFrm()) && + ((SwFmtURL*)pNew)->GetMap() && ((SwFmtURL*)pOld)->GetMap() ) + { + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + if ( rSz.GetHeight() != Frm().Height() || + rSz.GetWidth() != Frm().Width() ) + { + SwFmtURL aURL( GetFmt()->GetURL() ); + Fraction aScaleX( Frm().Width(), rSz.GetWidth() ); + Fraction aScaleY( Frm().Height(), rSz.GetHeight() ); + aURL.GetMap()->Scale( aScaleX, aScaleY ); + SwFrmFmt *pFmt = GetFmt(); + pFmt->LockModify(); + pFmt->SetFmtAttr( aURL ); + pFmt->UnlockModify(); + } + } + /* Keine Invalidierung notwendig */ + break; + + case RES_CHAIN: + { + SwFmtChain *pChain = (SwFmtChain*)pNew; + if ( pChain->GetNext() ) + { + SwFlyFrm *pFollow = FindChainNeighbour( *pChain->GetNext() ); + if ( GetNextLink() && pFollow != GetNextLink() ) + SwFlyFrm::UnchainFrames( this, GetNextLink()); + if ( pFollow ) + { + if ( pFollow->GetPrevLink() && + pFollow->GetPrevLink() != this ) + SwFlyFrm::UnchainFrames( pFollow->GetPrevLink(), + pFollow ); + if ( !GetNextLink() ) + SwFlyFrm::ChainFrames( this, pFollow ); + } + } + else if ( GetNextLink() ) + SwFlyFrm::UnchainFrames( this, GetNextLink() ); + if ( pChain->GetPrev() ) + { + SwFlyFrm *pMaster = FindChainNeighbour( *pChain->GetPrev() ); + if ( GetPrevLink() && pMaster != GetPrevLink() ) + SwFlyFrm::UnchainFrames( GetPrevLink(), this ); + if ( pMaster ) + { + if ( pMaster->GetNextLink() && + pMaster->GetNextLink() != this ) + SwFlyFrm::UnchainFrames( pMaster, + pMaster->GetNextLink() ); + if ( !GetPrevLink() ) + SwFlyFrm::ChainFrames( pMaster, this ); + } + } + else if ( GetPrevLink() ) + SwFlyFrm::UnchainFrames( GetPrevLink(), this ); + } + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrm::Modify( pOld, pNew ); + } +} + +/************************************************************************* +|* +|* SwFlyFrm::GetInfo() +|* +|* Beschreibung erfragt Informationen +|* +*************************************************************************/ + + // erfrage vom Modify Informationen +sal_Bool SwFlyFrm::GetInfo( SfxPoolItem & rInfo ) const +{ + if( RES_AUTOFMT_DOCNODE == rInfo.Which() ) + return sal_False; // es gibt einen FlyFrm also wird er benutzt + return sal_True; // weiter suchen +} + +/************************************************************************* +|* +|* SwFlyFrm::_Invalidate() +|* +|*************************************************************************/ + +void SwFlyFrm::_Invalidate( SwPageFrm *pPage ) +{ + InvalidatePage( pPage ); + bNotifyBack = bInvalid = sal_True; + + SwFlyFrm *pFrm; + if ( GetAnchorFrm() && 0 != (pFrm = AnchorFrm()->FindFlyFrm()) ) + { + //Gaanz dumm: Wenn der Fly innerhalb eines Fly gebunden ist, der + //Spalten enthaehlt, sollte das Format von diesem ausgehen. + if ( !pFrm->IsLocked() && !pFrm->IsColLocked() && + pFrm->Lower() && pFrm->Lower()->IsColumnFrm() ) + pFrm->InvalidateSize(); + } + + // --> OD 2008-01-21 #i85216# + // if vertical position is oriented at a layout frame inside a ghost section, + // assure that the position is invalidated and that the information about + // the vertical position oriented frame is cleared + if ( GetVertPosOrientFrm() && GetVertPosOrientFrm()->IsLayoutFrm() ) + { + const SwSectionFrm* pSectFrm( GetVertPosOrientFrm()->FindSctFrm() ); + if ( pSectFrm && pSectFrm->GetSection() == 0 ) + { + InvalidatePos(); + ClearVertPosOrientFrm(); + } + } + // <-- +} + +/************************************************************************* +|* +|* SwFlyFrm::ChgRelPos() +|* +|* Beschreibung Aenderung der relativen Position, die Position wird +|* damit automatisch Fix, das Attribut wird entprechend angepasst. +|* +|*************************************************************************/ + +void SwFlyFrm::ChgRelPos( const Point &rNewPos ) +{ + if ( GetCurrRelPos() != rNewPos ) + { + SwFrmFmt *pFmt = GetFmt(); + const bool bVert = GetAnchorFrm()->IsVertical(); + const SwTwips nNewY = bVert ? rNewPos.X() : rNewPos.Y(); + SwTwips nTmpY = nNewY == LONG_MAX ? 0 : nNewY; + if( bVert ) + nTmpY = -nTmpY; + SfxItemSet aSet( pFmt->GetDoc()->GetAttrPool(), + RES_VERT_ORIENT, RES_HORI_ORIENT); + + SwFmtVertOrient aVert( pFmt->GetVertOrient() ); + SwTxtFrm *pAutoFrm = NULL; + // --> OD 2004-11-12 #i34948# - handle also at-page and at-fly anchored + // Writer fly frames + const RndStdIds eAnchorType = GetFrmFmt().GetAnchor().GetAnchorId(); + if ( eAnchorType == FLY_AT_PAGE ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); + } + else if ( eAnchorType == FLY_AT_FLY ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::FRAME ); + } + // <-- + else if ( IsFlyAtCntFrm() || text::VertOrientation::NONE != aVert.GetVertOrient() ) + { + if( text::RelOrientation::CHAR == aVert.GetRelationOrient() && IsAutoPos() ) + { + if( LONG_MAX != nNewY ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + xub_StrLen nOfs = + pFmt->GetAnchor().GetCntntAnchor()->nContent.GetIndex(); + OSL_ENSURE( GetAnchorFrm()->IsTxtFrm(), "TxtFrm expected" ); + pAutoFrm = (SwTxtFrm*)GetAnchorFrm(); + while( pAutoFrm->GetFollow() && + pAutoFrm->GetFollow()->GetOfst() <= nOfs ) + { + if( pAutoFrm == GetAnchorFrm() ) + nTmpY += pAutoFrm->GetRelPos().Y(); + nTmpY -= pAutoFrm->GetUpper()->Prt().Height(); + pAutoFrm = pAutoFrm->GetFollow(); + } + nTmpY = ((SwFlyAtCntFrm*)this)->GetRelCharY(pAutoFrm)-nTmpY; + } + else + aVert.SetVertOrient( text::VertOrientation::CHAR_BOTTOM ); + } + else + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::FRAME ); + } + } + aVert.SetPos( nTmpY ); + aSet.Put( aVert ); + + //Fuer Flys im Cnt ist die horizontale Ausrichtung uninteressant, + //den sie ist stets 0. + if ( !IsFlyInCntFrm() ) + { + const SwTwips nNewX = bVert ? rNewPos.Y() : rNewPos.X(); + SwTwips nTmpX = nNewX == LONG_MAX ? 0 : nNewX; + SwFmtHoriOrient aHori( pFmt->GetHoriOrient() ); + // --> OD 2004-11-12 #i34948# - handle also at-page and at-fly anchored + // Writer fly frames + if ( eAnchorType == FLY_AT_PAGE ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); + aHori.SetPosToggle( sal_False ); + } + else if ( eAnchorType == FLY_AT_FLY ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + aHori.SetRelationOrient( text::RelOrientation::FRAME ); + aHori.SetPosToggle( sal_False ); + } + // <-- + else if ( IsFlyAtCntFrm() || text::HoriOrientation::NONE != aHori.GetHoriOrient() ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + if( text::RelOrientation::CHAR == aHori.GetRelationOrient() && IsAutoPos() ) + { + if( LONG_MAX != nNewX ) + { + if( !pAutoFrm ) + { + xub_StrLen nOfs = pFmt->GetAnchor().GetCntntAnchor() + ->nContent.GetIndex(); + OSL_ENSURE( GetAnchorFrm()->IsTxtFrm(), "TxtFrm expected"); + pAutoFrm = (SwTxtFrm*)GetAnchorFrm(); + while( pAutoFrm->GetFollow() && + pAutoFrm->GetFollow()->GetOfst() <= nOfs ) + pAutoFrm = pAutoFrm->GetFollow(); + } + nTmpX -= ((SwFlyAtCntFrm*)this)->GetRelCharX(pAutoFrm); + } + } + else + aHori.SetRelationOrient( text::RelOrientation::FRAME ); + aHori.SetPosToggle( sal_False ); + } + aHori.SetPos( nTmpX ); + aSet.Put( aHori ); + } + SetCurrRelPos( rNewPos ); + pFmt->GetDoc()->SetAttr( aSet, *pFmt ); + } +} +/************************************************************************* +|* +|* SwFlyFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea. +|* Die Fixsize wird hier nicht eingestellt. +|* +|*************************************************************************/ + +void SwFlyFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "FlyFrm::Format, pAttrs ist 0." ); + + ColLock(); + + if ( !bValidSize ) + { + if ( Frm().Top() == WEIT_WECH && Frm().Left() == WEIT_WECH ) + { + //Sicherheitsschaltung wegnehmen (siehe SwFrm::CTor) + Frm().Pos().X() = Frm().Pos().Y() = 0; + // --> OD 2006-08-16 #i68520# + InvalidateObjRectWithSpaces(); + // <-- + } + + //Breite der Spalten pruefen und ggf. einstellen. + if ( Lower() && Lower()->IsColumnFrm() ) + AdjustColumns( 0, sal_False ); + + bValidSize = sal_True; + + const SwTwips nUL = pAttrs->CalcTopLine() + pAttrs->CalcBottomLine(); + const SwTwips nLR = pAttrs->CalcLeftLine() + pAttrs->CalcRightLine(); + const SwFmtFrmSize &rFrmSz = GetFmt()->GetFrmSize(); + Size aRelSize( CalcRel( rFrmSz ) ); + + OSL_ENSURE( pAttrs->GetSize().Height() != 0 || rFrmSz.GetHeightPercent(), "Hoehe des RahmenAttr ist 0." ); + OSL_ENSURE( pAttrs->GetSize().Width() != 0 || rFrmSz.GetWidthPercent(), "Breite des RahmenAttr ist 0." ); + + SWRECTFN( this ) + if( !HasFixSize() ) + { + SwTwips nRemaining = 0; + + long nMinHeight = 0; + if( IsMinHeight() ) + nMinHeight = bVert ? aRelSize.Width() : aRelSize.Height(); + + if ( Lower() ) + { + if ( Lower()->IsColumnFrm() ) + { + FormatWidthCols( *pAttrs, nUL, nMinHeight ); + nRemaining = (Lower()->Frm().*fnRect->fnGetHeight)(); + } + else + { + SwFrm *pFrm = Lower(); + while ( pFrm ) + { + nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() ) + // Dieser TxtFrm waere gern ein bisschen groesser + nRemaining += ((SwTxtFrm*)pFrm)->GetParHeight() + - (pFrm->Prt().*fnRect->fnGetHeight)(); + else if( pFrm->IsSctFrm() && ((SwSectionFrm*)pFrm)->IsUndersized() ) + nRemaining += ((SwSectionFrm*)pFrm)->Undersize(); + pFrm = pFrm->GetNext(); + } + // --> OD 2006-02-09 #130878# + // Do not keep old height, if content has no height. + // The old height could be wrong due to wrong layout cache + // and isn't corrected in the further formatting, because + // the fly frame doesn't become invalid anymore. +// if( !nRemaining ) +// nRemaining = nOldHeight - nUL; + // <-- + } + if ( GetDrawObjs() ) + { + sal_uInt32 nCnt = GetDrawObjs()->Count(); + SwTwips nTop = (Frm().*fnRect->fnGetTop)(); + SwTwips nBorder = (Frm().*fnRect->fnGetHeight)() - + (Prt().*fnRect->fnGetHeight)(); + for ( sal_uInt16 i = 0; i < nCnt; ++i ) + { + SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + // OD 06.11.2003 #i22305# - consider + // only Writer fly frames, which follow the text flow. + if ( pFly->IsFlyLayFrm() && + pFly->Frm().Top() != WEIT_WECH && + pFly->GetFmt()->GetFollowTextFlow().GetValue() ) + { + SwTwips nDist = -(pFly->Frm().*fnRect-> + fnBottomDist)( nTop ); + if( nDist > nBorder + nRemaining ) + nRemaining = nDist - nBorder; + } + } + } + } + } + + if( IsMinHeight() && (nRemaining + nUL) < nMinHeight ) + nRemaining = nMinHeight - nUL; + //Weil das Grow/Shrink der Flys die Groessen nicht direkt + //einstellt, sondern indirekt per Invalidate ein Format + //ausloesst, muessen die Groessen hier direkt eingestellt + //werden. Benachrichtung laeuft bereits mit. + //Weil bereits haeufiger 0en per Attribut hereinkamen wehre + //ich mich ab sofort dagegen. + if ( nRemaining < MINFLY ) + nRemaining = MINFLY; + (Prt().*fnRect->fnSetHeight)( nRemaining ); + nRemaining -= (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnAddBottom)( nRemaining + nUL ); + // --> OD 2006-08-16 #i68520# + if ( nRemaining + nUL != 0 ) + { + InvalidateObjRectWithSpaces(); + } + // <-- + bValidSize = sal_True; + } + else + { + bValidSize = sal_True; //Fixe Frms formatieren sich nicht. + //Flys stellen ihre Groesse anhand des Attr ein. + SwTwips nNewSize = bVert ? aRelSize.Width() : aRelSize.Height(); + nNewSize -= nUL; + if( nNewSize < MINFLY ) + nNewSize = MINFLY; + (Prt().*fnRect->fnSetHeight)( nNewSize ); + nNewSize += nUL - (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnAddBottom)( nNewSize ); + // --> OD 2006-08-16 #i68520# + if ( nNewSize != 0 ) + { + InvalidateObjRectWithSpaces(); + } + // <-- + } + + if ( !bFormatHeightOnly ) + { + OSL_ENSURE( aRelSize == CalcRel( rFrmSz ), "SwFlyFrm::Format CalcRel problem" ); + SwTwips nNewSize = bVert ? aRelSize.Height() : aRelSize.Width(); + + if ( rFrmSz.GetWidthSizeType() != ATT_FIX_SIZE ) + { + // #i9046# Autowidth for fly frames + const SwTwips nAutoWidth = CalcAutoWidth(); + if ( nAutoWidth ) + { + if( ATT_MIN_SIZE == rFrmSz.GetWidthSizeType() ) + nNewSize = Max( nNewSize - nLR, nAutoWidth ); + else + nNewSize = nAutoWidth; + } + } + else + nNewSize -= nLR; + + if( nNewSize < MINFLY ) + nNewSize = MINFLY; + (Prt().*fnRect->fnSetWidth)( nNewSize ); + nNewSize += nLR - (Frm().*fnRect->fnGetWidth)(); + (Frm().*fnRect->fnAddRight)( nNewSize ); + // --> OD 2006-08-16 #i68520# + if ( nNewSize != 0 ) + { + InvalidateObjRectWithSpaces(); + } + // <-- + } + } + ColUnlock(); +} + +// OD 14.03.2003 #i11760# - change parameter <bNoColl>: type <bool>; +// default value = false. +// OD 14.03.2003 #i11760# - add new parameter <bNoCalcFollow> with +// default value = false. +// OD 11.04.2003 #108824# - new parameter <bNoCalcFollow> was used by method +// <FormatWidthCols(..)> to avoid follow formatting +// for text frames. But, unformatted follows causes +// problems in method <SwCntntFrm::_WouldFit(..)>, +// which assumes that the follows are formatted. +// Thus, <bNoCalcFollow> no longer used by <FormatWidthCols(..)>. +//void CalcCntnt( SwLayoutFrm *pLay, sal_Bool bNoColl ) +void CalcCntnt( SwLayoutFrm *pLay, + bool bNoColl, + bool bNoCalcFollow ) +{ + SwSectionFrm* pSect; + sal_Bool bCollect = sal_False; + if( pLay->IsSctFrm() ) + { + pSect = (SwSectionFrm*)pLay; + if( pSect->IsEndnAtEnd() && !bNoColl ) + { + bCollect = sal_True; + SwLayouter::CollectEndnotes( pLay->GetFmt()->GetDoc(), pSect ); + } + pSect->CalcFtnCntnt(); + } + else + pSect = NULL; + SwFrm *pFrm = pLay->ContainsAny(); + if ( !pFrm ) + { + if( pSect ) + { + if( pSect->HasFollow() ) + pFrm = pSect->GetFollow()->ContainsAny(); + if( !pFrm ) + { + if( pSect->IsEndnAtEnd() ) + { + if( bCollect ) + pLay->GetFmt()->GetDoc()->GetLayouter()-> + InsertEndnotes( pSect ); + sal_Bool bLock = pSect->IsFtnLock(); + pSect->SetFtnLock( sal_True ); + pSect->CalcFtnCntnt(); + pSect->CalcFtnCntnt(); + pSect->SetFtnLock( bLock ); + } + return; + } + pFrm->_InvalidatePos(); + } + else + return; + } + pFrm->InvalidatePage(); + + do + { + // local variables to avoid loops caused by anchored object positioning + SwAnchoredObject* pAgainObj1 = 0; + SwAnchoredObject* pAgainObj2 = 0; + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns = 0; + const sal_uInt16 nLoopControlMax = 20; + const SwFrm* pLoopControlCond = 0; + + SwFrm* pLast; + do + { + pLast = pFrm; + if( pFrm->IsVertical() ? + ( pFrm->GetUpper()->Prt().Height() != pFrm->Frm().Height() ) + : ( pFrm->GetUpper()->Prt().Width() != pFrm->Frm().Width() ) ) + { + pFrm->Prepare( PREP_FIXSIZE_CHG ); + pFrm->_InvalidateSize(); + } + + if ( pFrm->IsTabFrm() ) + { + ((SwTabFrm*)pFrm)->bCalcLowers = sal_True; + // OD 26.08.2003 #i18103# - lock move backward of follow table, + // if no section content is formatted or follow table belongs + // to the section, which content is formatted. + if ( ((SwTabFrm*)pFrm)->IsFollow() && + ( !pSect || pSect == pFrm->FindSctFrm() ) ) + { + ((SwTabFrm*)pFrm)->bLockBackMove = sal_True; + } + } + + // OD 14.03.2003 #i11760# - forbid format of follow, if requested. + if ( bNoCalcFollow && pFrm->IsTxtFrm() ) + static_cast<SwTxtFrm*>(pFrm)->ForbidFollowFormat(); + + pFrm->Calc(); + + // OD 14.03.2003 #i11760# - reset control flag for follow format. + if ( pFrm->IsTxtFrm() ) + { + static_cast<SwTxtFrm*>(pFrm)->AllowFollowFormat(); + } + + // #111937# The keep-attribute can cause the position + // of the prev to be invalid: + // OD 2004-03-15 #116560# - Do not consider invalid previous frame + // due to its keep-attribute, if current frame is a follow or is locked. + // --> OD 2005-03-08 #i44049# - do not consider invalid previous + // frame due to its keep-attribute, if it can't move forward. + // --> OD 2006-01-27 #i57765# - do not consider invalid previous + // frame, if current frame has a column/page break before attribute. + SwFrm* pTmpPrev = pFrm->FindPrev(); + SwFlowFrm* pTmpPrevFlowFrm = pTmpPrev && pTmpPrev->IsFlowFrm() ? SwFlowFrm::CastFlowFrm(pTmpPrev) : 0; + SwFlowFrm* pTmpFlowFrm = pFrm->IsFlowFrm() ? SwFlowFrm::CastFlowFrm(pFrm) : 0; + + bool bPrevInvalid = pTmpPrevFlowFrm && pTmpFlowFrm && + !pTmpFlowFrm->IsFollow() && + !StackHack::IsLocked() && // #i76382# + !pTmpFlowFrm->IsJoinLocked() && + !pTmpPrev->GetValidPosFlag() && + pLay->IsAnLower( pTmpPrev ) && + pTmpPrevFlowFrm->IsKeep( *pTmpPrev->GetAttrSet() ) && + pTmpPrevFlowFrm->IsKeepFwdMoveAllowed(); + // <-- + + // format floating screen objects anchored to the frame. + bool bRestartLayoutProcess = false; + if ( !bPrevInvalid && pFrm->GetDrawObjs() && pLay->IsAnLower( pFrm ) ) + { + bool bAgain = false; + SwPageFrm* pPageFrm = pFrm->FindPageFrm(); + sal_uInt32 nCnt = pFrm->GetDrawObjs()->Count(); + for ( sal_uInt16 i = 0; i < nCnt; ++i ) + { + // --> OD 2004-07-01 #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + // determine, if anchored object has to be formatted. + if ( pAnchoredObj->PositionLocked() ) + { + continue; + } + + // format anchored object + if ( pAnchoredObj->IsFormatPossible() ) + { + // --> OD 2005-05-17 #i43737# - no invalidation of + // anchored object needed - causes loops for as-character + // anchored objects. + //pAnchoredObj->InvalidateObjPos(); + // <-- + SwRect aRect( pAnchoredObj->GetObjRect() ); + if ( !SwObjectFormatter::FormatObj( *pAnchoredObj, pFrm, pPageFrm ) ) + { + bRestartLayoutProcess = true; + break; + } + // --> OD 2004-08-25 #i3317# - restart layout process, + // if the position of the anchored object is locked now. + if ( pAnchoredObj->PositionLocked() ) + { + bRestartLayoutProcess = true; + break; + } + // <-- + + if ( aRect != pAnchoredObj->GetObjRect() ) + { + bAgain = true; + if ( pAgainObj2 == pAnchoredObj ) + { + OSL_FAIL( "::CalcCntnt(..) - loop detected, perform attribute changes to avoid the loop" ); + //Oszillation unterbinden. + SwFrmFmt& rFmt = pAnchoredObj->GetFrmFmt(); + SwFmtSurround aAttr( rFmt.GetSurround() ); + if( SURROUND_THROUGHT != aAttr.GetSurround() ) + { + // Bei autopositionierten hilft manchmal nur + // noch, auf Durchlauf zu schalten + if ((rFmt.GetAnchor().GetAnchorId() == + FLY_AT_CHAR) && + (SURROUND_PARALLEL == + aAttr.GetSurround())) + { + aAttr.SetSurround( SURROUND_THROUGHT ); + } + else + { + aAttr.SetSurround( SURROUND_PARALLEL ); + } + rFmt.LockModify(); + rFmt.SetFmtAttr( aAttr ); + rFmt.UnlockModify(); + } + } + else + { + if ( pAgainObj1 == pAnchoredObj ) + pAgainObj2 = pAnchoredObj; + pAgainObj1 = pAnchoredObj; + } + } + + if ( !pFrm->GetDrawObjs() ) + break; + if ( pFrm->GetDrawObjs()->Count() < nCnt ) + { + --i; + --nCnt; + } + } + } + + // --> OD 2004-06-11 #i28701# - restart layout process, if + // requested by floating screen object formatting + if ( bRestartLayoutProcess ) + { + pFrm = pLay->ContainsAny(); + pAgainObj1 = 0L; + pAgainObj2 = 0L; + continue; + } + + // OD 2004-05-17 #i28701# - format anchor frame after its objects + // are formatted, if the wrapping style influence has to be considered. + if ( pLay->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + pFrm->Calc(); + } + // <-- + + if ( bAgain ) + { + pFrm = pLay->ContainsCntnt(); + if ( pFrm && pFrm->IsInTab() ) + pFrm = pFrm->FindTabFrm(); + if( pFrm && pFrm->IsInSct() ) + { + SwSectionFrm* pTmp = pFrm->FindSctFrm(); + if( pTmp != pLay && pLay->IsAnLower( pTmp ) ) + pFrm = pTmp; + } + + if ( pFrm == pLoopControlCond ) + ++nLoopControlRuns; + else + { + nLoopControlRuns = 0; + pLoopControlCond = pFrm; + } + + if ( nLoopControlRuns < nLoopControlMax ) + continue; + +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl in CalcCntnt" ); +#endif + } + } + if ( pFrm->IsTabFrm() ) + { + if ( ((SwTabFrm*)pFrm)->IsFollow() ) + ((SwTabFrm*)pFrm)->bLockBackMove = sal_False; + } + + pFrm = bPrevInvalid ? pTmpPrev : pFrm->FindNext(); + if( !bPrevInvalid && pFrm && pFrm->IsSctFrm() && pSect ) + { + // Es koennen hier leere SectionFrms herumspuken + while( pFrm && pFrm->IsSctFrm() && !((SwSectionFrm*)pFrm)->GetSection() ) + pFrm = pFrm->FindNext(); + // Wenn FindNext den Follow des urspruenglichen Bereichs liefert, + // wollen wir mit dessen Inhalt weitermachen, solange dieser + // zurueckfliesst. + if( pFrm && pFrm->IsSctFrm() && ( pFrm == pSect->GetFollow() || + ((SwSectionFrm*)pFrm)->IsAnFollow( pSect ) ) ) + { + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pFrm ) + pFrm->_InvalidatePos(); + } + } + // Im pLay bleiben, Ausnahme, bei SectionFrms mit Follow wird der erste + // CntntFrm des Follows anformatiert, damit er die Chance erhaelt, in + // pLay zu landen. Solange diese Frames in pLay landen, geht's weiter. + } while ( pFrm && + ( pLay->IsAnLower( pFrm ) || + ( pSect && + ( ( pSect->HasFollow() && + ( pLay->IsAnLower( pLast ) || + ( pLast->IsInSct() && + pLast->FindSctFrm()->IsAnFollow(pSect) ) ) && + pSect->GetFollow()->IsAnLower( pFrm ) ) || + ( pFrm->IsInSct() && + pFrm->FindSctFrm()->IsAnFollow( pSect ) ) ) ) ) ); + if( pSect ) + { + if( bCollect ) + { + pLay->GetFmt()->GetDoc()->GetLayouter()->InsertEndnotes(pSect); + pSect->CalcFtnCntnt(); + } + if( pSect->HasFollow() ) + { + SwSectionFrm* pNxt = pSect->GetFollow(); + while( pNxt && !pNxt->ContainsCntnt() ) + pNxt = pNxt->GetFollow(); + if( pNxt ) + pNxt->CalcFtnCntnt(); + } + if( bCollect ) + { + pFrm = pLay->ContainsAny(); + bCollect = sal_False; + if( pFrm ) + continue; + } + } + break; + } + while( sal_True ); +} + +/************************************************************************* +|* +|* SwFlyFrm::MakeFlyPos() +|* +|*************************************************************************/ +// OD 2004-03-23 #i26791# +//void SwFlyFrm::MakeFlyPos() +void SwFlyFrm::MakeObjPos() +{ + if ( !bValidPos ) + { + bValidPos = sal_True; + + // OD 29.10.2003 #113049# - use new class to position object + GetAnchorFrm()->Calc(); + objectpositioning::SwToLayoutAnchoredObjectPosition + aObjPositioning( *GetVirtDrawObj() ); + aObjPositioning.CalcPosition(); + + // --> OD 2006-10-05 #i58280# + // update relative position + SetCurrRelPos( aObjPositioning.GetRelPos() ); + // <-- + + SWRECTFN( GetAnchorFrm() ); + aFrm.Pos( aObjPositioning.GetRelPos() ); + aFrm.Pos() += (GetAnchorFrm()->Frm().*fnRect->fnGetPos)(); + // --> OD 2006-09-11 #i69335# + InvalidateObjRectWithSpaces(); + // <-- + } +} + +/************************************************************************* +|* +|* SwFlyFrm::MakePrtArea() +|* +|*************************************************************************/ +void SwFlyFrm::MakePrtArea( const SwBorderAttrs &rAttrs ) +{ + + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + + // OD 31.07.2003 #110978# - consider vertical layout + SWRECTFN( this ) + (this->*fnRect->fnSetXMargins)( rAttrs.CalcLeftLine(), + rAttrs.CalcRightLine() ); + (this->*fnRect->fnSetYMargins)( rAttrs.CalcTopLine(), + rAttrs.CalcBottomLine() ); + } +} + +/************************************************************************* +|* +|* SwFlyFrm::_Grow(), _Shrink() +|* +|*************************************************************************/ + +SwTwips SwFlyFrm::_Grow( SwTwips nDist, sal_Bool bTst ) +{ + SWRECTFN( this ) + if ( Lower() && !IsColLocked() && !HasFixSize() ) + { + SwTwips nSize = (Frm().*fnRect->fnGetHeight)(); + if( nSize > 0 && nDist > ( LONG_MAX - nSize ) ) + nDist = LONG_MAX - nSize; + + if ( nDist <= 0L ) + return 0L; + + if ( Lower()->IsColumnFrm() ) + { //Bei Spaltigkeit ubernimmt das Format die Kontrolle ueber + //das Wachstum (wg. des Ausgleichs). + if ( !bTst ) + { + // --> OD 2004-06-09 #i28701# - unlock position of Writer fly frame + UnlockPosition(); + _InvalidatePos(); + InvalidateSize(); + } + return 0L; + } + + if ( !bTst ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + _InvalidateSize(); + const sal_Bool bOldLock = bLocked; + Unlock(); + if ( IsFlyFreeFrm() ) + { + // --> OD 2004-11-12 #i37068# - no format of position here + // and prevent move in method <CheckClip(..)>. + // This is needed to prevent layout loop caused by nested + // Writer fly frames - inner Writer fly frames format its + // anchor, which grows/shrinks the outer Writer fly frame. + // Note: position will be invalidated below. + bValidPos = sal_True; + // --> OD 2005-10-10 #i55416# + // Suppress format of width for autowidth frame, because the + // format of the width would call <SwTxtFrm::CalcFitToContent()> + // for the lower frame, which initiated this grow. + const sal_Bool bOldFormatHeightOnly = bFormatHeightOnly; + const SwFmtFrmSize& rFrmSz = GetFmt()->GetFrmSize(); + if ( rFrmSz.GetWidthSizeType() != ATT_FIX_SIZE ) + { + bFormatHeightOnly = sal_True; + } + // <-- + static_cast<SwFlyFreeFrm*>(this)->SetNoMoveOnCheckClip( true ); + ((SwFlyFreeFrm*)this)->SwFlyFreeFrm::MakeAll(); + static_cast<SwFlyFreeFrm*>(this)->SetNoMoveOnCheckClip( false ); + // --> OD 2005-10-10 #i55416# + if ( rFrmSz.GetWidthSizeType() != ATT_FIX_SIZE ) + { + bFormatHeightOnly = bOldFormatHeightOnly; + } + // <-- + // <-- + } + else + MakeAll(); + _InvalidateSize(); + InvalidatePos(); + if ( bOldLock ) + Lock(); + const SwRect aNew( GetObjRectWithSpaces() ); + if ( aOld != aNew ) + ::Notify( this, FindPageFrm(), aOld ); + return (aNew.*fnRect->fnGetHeight)()-(aOld.*fnRect->fnGetHeight)(); + } + return nDist; + } + return 0L; +} + +SwTwips SwFlyFrm::_Shrink( SwTwips nDist, sal_Bool bTst ) +{ + if( Lower() && !IsColLocked() && !HasFixSize() && !IsNoShrink() ) + { + SWRECTFN( this ) + SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); + if ( nDist > nHeight ) + nDist = nHeight; + + SwTwips nVal = nDist; + if ( IsMinHeight() ) + { + const SwFmtFrmSize& rFmtSize = GetFmt()->GetFrmSize(); + SwTwips nFmtHeight = bVert ? rFmtSize.GetWidth() : rFmtSize.GetHeight(); + + nVal = Min( nDist, nHeight - nFmtHeight ); + } + + if ( nVal <= 0L ) + return 0L; + + if ( Lower()->IsColumnFrm() ) + { //Bei Spaltigkeit ubernimmt das Format die Kontrolle ueber + //das Wachstum (wg. des Ausgleichs). + if ( !bTst ) + { + SwRect aOld( GetObjRectWithSpaces() ); + (Frm().*fnRect->fnSetHeight)( nHeight - nVal ); + // --> OD 2006-08-16 #i68520# + if ( nHeight - nVal != 0 ) + { + InvalidateObjRectWithSpaces(); + } + // <-- + nHeight = (Prt().*fnRect->fnGetHeight)(); + (Prt().*fnRect->fnSetHeight)( nHeight - nVal ); + _InvalidatePos(); + InvalidateSize(); + ::Notify( this, FindPageFrm(), aOld ); + NotifyDrawObj(); + if ( GetAnchorFrm()->IsInFly() ) + AnchorFrm()->FindFlyFrm()->Shrink( nDist, bTst ); + } + return 0L; + } + + if ( !bTst ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + _InvalidateSize(); + const sal_Bool bOldLocked = bLocked; + Unlock(); + if ( IsFlyFreeFrm() ) + { + // --> OD 2004-11-12 #i37068# - no format of position here + // and prevent move in method <CheckClip(..)>. + // This is needed to prevent layout loop caused by nested + // Writer fly frames - inner Writer fly frames format its + // anchor, which grows/shrinks the outer Writer fly frame. + // Note: position will be invalidated below. + bValidPos = sal_True; + // --> OD 2005-10-10 #i55416# + // Suppress format of width for autowidth frame, because the + // format of the width would call <SwTxtFrm::CalcFitToContent()> + // for the lower frame, which initiated this shrink. + const sal_Bool bOldFormatHeightOnly = bFormatHeightOnly; + const SwFmtFrmSize& rFrmSz = GetFmt()->GetFrmSize(); + if ( rFrmSz.GetWidthSizeType() != ATT_FIX_SIZE ) + { + bFormatHeightOnly = sal_True; + } + // <-- + static_cast<SwFlyFreeFrm*>(this)->SetNoMoveOnCheckClip( true ); + ((SwFlyFreeFrm*)this)->SwFlyFreeFrm::MakeAll(); + static_cast<SwFlyFreeFrm*>(this)->SetNoMoveOnCheckClip( false ); + // --> OD 2005-10-10 #i55416# + if ( rFrmSz.GetWidthSizeType() != ATT_FIX_SIZE ) + { + bFormatHeightOnly = bOldFormatHeightOnly; + } + // <-- + // <-- + } + else + MakeAll(); + _InvalidateSize(); + InvalidatePos(); + if ( bOldLocked ) + Lock(); + const SwRect aNew( GetObjRectWithSpaces() ); + if ( aOld != aNew ) + { + ::Notify( this, FindPageFrm(), aOld ); + if ( GetAnchorFrm()->IsInFly() ) + AnchorFrm()->FindFlyFrm()->Shrink( nDist, bTst ); + } + return (aOld.*fnRect->fnGetHeight)() - + (aNew.*fnRect->fnGetHeight)(); + } + return nVal; + } + return 0L; +} + +/************************************************************************* +|* +|* SwFlyFrm::ChgSize() +|* +|*************************************************************************/ + +Size SwFlyFrm::ChgSize( const Size& aNewSize ) +{ + // --> OD 2006-01-19 #i53298# + // If the fly frame anchored at-paragraph or at-character contains an OLE + // object, assure that the new size fits into the current clipping area + // of the fly frame + Size aAdjustedNewSize( aNewSize ); + { + if ( dynamic_cast<SwFlyAtCntFrm*>(this) && + Lower() && dynamic_cast<SwNoTxtFrm*>(Lower()) && + static_cast<SwNoTxtFrm*>(Lower())->GetNode()->GetOLENode() ) + { + SwRect aClipRect; + ::CalcClipRect( GetVirtDrawObj(), aClipRect, sal_False ); + if ( aAdjustedNewSize.Width() > aClipRect.Width() ) + { + aAdjustedNewSize.setWidth( aClipRect.Width() ); + } + if ( aAdjustedNewSize.Height() > aClipRect.Height() ) + { + aAdjustedNewSize.setWidth( aClipRect.Height() ); + } + } + } + // <-- + if ( aAdjustedNewSize != Frm().SSize() ) + { + SwFrmFmt *pFmt = GetFmt(); + SwFmtFrmSize aSz( pFmt->GetFrmSize() ); + aSz.SetWidth( aAdjustedNewSize.Width() ); + // --> OD 2006-01-19 #i53298# - no tolerance any more. + // If it reveals that the tolerance is still needed, then suppress a + // <SetAttr> call, if <aSz> equals the current <SwFmtFrmSize> attribute. +// if ( Abs(aAdjustedNewSize.Height() - aSz.GetHeight()) > 1 ) + aSz.SetHeight( aAdjustedNewSize.Height() ); + // <-- + // uebers Doc fuers Undo! + pFmt->GetDoc()->SetAttr( aSz, *pFmt ); + return aSz.GetSize(); + } + else + return Frm().SSize(); +} + +/************************************************************************* +|* +|* SwFlyFrm::IsLowerOf() +|* +|*************************************************************************/ + +sal_Bool SwFlyFrm::IsLowerOf( const SwLayoutFrm* pUpperFrm ) const +{ + OSL_ENSURE( GetAnchorFrm(), "8-( Fly is lost in Space." ); + const SwFrm* pFrm = GetAnchorFrm(); + do + { + if ( pFrm == pUpperFrm ) + return sal_True; + pFrm = pFrm->IsFlyFrm() + ? ((const SwFlyFrm*)pFrm)->GetAnchorFrm() + : pFrm->GetUpper(); + } while ( pFrm ); + return sal_False; +} + +/************************************************************************* +|* +|* SwFlyFrm::Cut() +|* +|*************************************************************************/ + +void SwFlyFrm::Cut() +{ +} + +/************************************************************************* +|* +|* SwFrm::AppendFly(), RemoveFly() +|* +|*************************************************************************/ + +void SwFrm::AppendFly( SwFlyFrm *pNew ) +{ + if ( !pDrawObjs ) + pDrawObjs = new SwSortedObjs(); + pDrawObjs->Insert( *pNew ); + pNew->ChgAnchorFrm( this ); + + //Bei der Seite anmelden; kann sein, dass noch keine da ist - die + //Anmeldung wird dann in SwPageFrm::PreparePage durch gefuehrt. + SwPageFrm *pPage = FindPageFrm(); + if ( pPage ) + { + if ( pNew->IsFlyAtCntFrm() && pNew->Frm().Top() == WEIT_WECH ) + { + //Versuch die Seitenformatierung von neuen Dokumenten etwas + //guenstiger zu gestalten. + //Wir haengen die Flys erstenmal nach hinten damit sie bei heftigem + //Fluss der Anker nicht unoetig oft formatiert werden. + //Damit man noch brauchbar an das Ende des Dokumentes springen + //kann werden die Flys nicht ganz an das Ende gehaengt. + SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); + if( !SwLayHelper::CheckPageFlyCache( pPage, pNew ) ) + { + SwPageFrm *pTmp = pRoot->GetLastPage(); + if ( pTmp->GetPhyPageNum() > 30 ) + { + for ( sal_uInt16 i = 0; i < 10; ++i ) + { + pTmp = (SwPageFrm*)pTmp->GetPrev(); + if( pTmp->GetPhyPageNum() <= pPage->GetPhyPageNum() ) + break; // damit wir nicht vor unserem Anker landen + } + if ( pTmp->IsEmptyPage() ) + pTmp = (SwPageFrm*)pTmp->GetPrev(); + pPage = pTmp; + } + } + pPage->AppendFlyToPage( pNew ); + } + else + pPage->AppendFlyToPage( pNew ); + } +} + +void SwFrm::RemoveFly( SwFlyFrm *pToRemove ) +{ + //Bei der Seite Abmelden - kann schon passiert sein weil die Seite + //bereits destruiert wurde. + SwPageFrm *pPage = pToRemove->FindPageFrm(); + if ( pPage && pPage->GetSortedObjs() ) + { + pPage->RemoveFlyFromPage( pToRemove ); + } + // --> OD 2008-05-19 #i73201# + else + { + if ( pToRemove->IsAccessibleFrm() && + pToRemove->GetFmt() && + !pToRemove->IsFlyInCntFrm() ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell *pVSh = pRootFrm->GetCurrShell(); + if( pVSh && pVSh->Imp() ) + { + pVSh->Imp()->DisposeAccessibleFrm( pToRemove ); + } + } + } + } + // <-- + + pDrawObjs->Remove( *pToRemove ); + if ( !pDrawObjs->Count() ) + DELETEZ( pDrawObjs ); + + pToRemove->ChgAnchorFrm( 0 ); + + if ( !pToRemove->IsFlyInCntFrm() && GetUpper() && IsInTab() )//MA_FLY_HEIGHT + GetUpper()->InvalidateSize(); +} + +/************************************************************************* +|* +|* SwFrm::AppendDrawObj(), RemoveDrawObj() +|* +|* --> OD 2004-07-06 #i28701# - new methods +|* +|*************************************************************************/ +void SwFrm::AppendDrawObj( SwAnchoredObject& _rNewObj ) +{ + if ( !_rNewObj.ISA(SwAnchoredDrawObject) ) + { + OSL_FAIL( "SwFrm::AppendDrawObj(..) - anchored object of unexcepted type -> object not appended" ); + return; + } + + if ( !_rNewObj.GetDrawObj()->ISA(SwDrawVirtObj) && + _rNewObj.GetAnchorFrm() && _rNewObj.GetAnchorFrm() != this ) + { + // perform disconnect from layout, if 'master' drawing object is appended + // to a new frame. + static_cast<SwDrawContact*>(::GetUserCall( _rNewObj.GetDrawObj() ))-> + DisconnectFromLayout( false ); + } + + if ( _rNewObj.GetAnchorFrm() != this ) + { + if ( !pDrawObjs ) + pDrawObjs = new SwSortedObjs(); + pDrawObjs->Insert( _rNewObj ); + _rNewObj.ChgAnchorFrm( this ); + } + + // --> OD 2010-09-14 #i113730# + // Assure the control objects and group objects containing controls are on the control layer + if ( ::CheckControlLayer( _rNewObj.DrawObj() ) ) + { + const IDocumentDrawModelAccess* pIDDMA = getIDocumentDrawModelAccess(); + const SdrLayerID aCurrentLayer(_rNewObj.DrawObj()->GetLayer()); + const SdrLayerID aControlLayerID(pIDDMA->GetControlsId()); + const SdrLayerID aInvisibleControlLayerID(pIDDMA->GetInvisibleControlsId()); + + if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID) + { + if ( aCurrentLayer == pIDDMA->GetInvisibleHellId() || + aCurrentLayer == pIDDMA->GetInvisibleHeavenId() ) + { + _rNewObj.DrawObj()->SetLayer(aInvisibleControlLayerID); + } + else + { + _rNewObj.DrawObj()->SetLayer(aControlLayerID); + } + } + } + // <-- + + // no direct positioning needed, but invalidate the drawing object position + _rNewObj.InvalidateObjPos(); + + // register at page frame + SwPageFrm* pPage = FindPageFrm(); + if ( pPage ) + { + pPage->AppendDrawObjToPage( _rNewObj ); + } + + // Notify accessible layout. + ViewShell* pSh = getRootFrm()->GetCurrShell(); + if( pSh ) + { + SwRootFrm* pLayout = getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->AddAccessibleObj( _rNewObj.GetDrawObj() ); + } +} + +void SwFrm::RemoveDrawObj( SwAnchoredObject& _rToRemoveObj ) +{ + // Notify accessible layout. + ViewShell* pSh = getRootFrm()->GetCurrShell(); + if( pSh ) + { + SwRootFrm* pLayout = getRootFrm(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->DisposeAccessibleObj( _rToRemoveObj.GetDrawObj() ); + } + + // deregister from page frame + SwPageFrm* pPage = _rToRemoveObj.GetPageFrm(); + if ( pPage && pPage->GetSortedObjs() ) + pPage->RemoveDrawObjFromPage( _rToRemoveObj ); + + pDrawObjs->Remove( _rToRemoveObj ); + if ( !pDrawObjs->Count() ) + DELETEZ( pDrawObjs ); + + _rToRemoveObj.ChgAnchorFrm( 0 ); +} + +/************************************************************************* +|* +|* SwFrm::InvalidateObjs() +|* +|*************************************************************************/ +// --> OD 2004-07-01 #i28701# - change purpose of method and adjust its name +void SwFrm::InvalidateObjs( const bool _bInvaPosOnly, + const bool _bNoInvaOfAsCharAnchoredObjs ) +{ + if ( GetDrawObjs() ) + { + // --> OD 2004-10-08 #i26945# - determine page the frame is on, + // in order to check, if anchored object is registered at the same + // page. + const SwPageFrm* pPageFrm = FindPageFrm(); + // <-- + // --> OD 2004-07-01 #i28701# - re-factoring + sal_uInt32 i = 0; + for ( ; i < GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i]; + if ( _bNoInvaOfAsCharAnchoredObjs && + (pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() + == FLY_AS_CHAR) ) + { + continue; + } + // --> OD 2004-10-08 #i26945# - no invalidation, if anchored object + // isn't registered at the same page and instead is registered at + // the page, where its anchor character text frame is on. + if ( pAnchoredObj->GetPageFrm() && + pAnchoredObj->GetPageFrm() != pPageFrm ) + { + SwTxtFrm* pAnchorCharFrm = pAnchoredObj->FindAnchorCharFrm(); + if ( pAnchorCharFrm && + pAnchoredObj->GetPageFrm() == pAnchorCharFrm->FindPageFrm() ) + { + continue; + } + // --> OD 2004-11-24 #115759# - unlock its position, if anchored + // object isn't registered at the page, where its anchor + // character text frame is on, respectively if it has no + // anchor character text frame. + else + { + pAnchoredObj->UnlockPosition(); + } + // <-- + } + // <-- + // --> OD 2005-07-18 #i51474# - reset flag, that anchored object + // has cleared environment, and unlock its position, if the anchored + // object is registered at the same page as the anchor frame is on. + if ( pAnchoredObj->ClearedEnvironment() && + pAnchoredObj->GetPageFrm() && + pAnchoredObj->GetPageFrm() == pPageFrm ) + { + pAnchoredObj->UnlockPosition(); + pAnchoredObj->SetClearedEnvironment( false ); + } + // <-- + // distinguish between writer fly frames and drawing objects + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + pFly->_Invalidate(); + pFly->_InvalidatePos(); + if ( !_bInvaPosOnly ) + pFly->_InvalidateSize(); + } + else + { + pAnchoredObj->InvalidateObjPos(); + } // end of distinction between writer fly frames and drawing objects + + } // end of loop on objects, which are connected to the frame + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::NotifyLowerObjs() +|* +|*************************************************************************/ +// --> OD 2004-07-01 #i28701# - change purpose of method and its name +// --> OD 2004-10-08 #i26945# - correct check, if anchored object is a lower +// of the layout frame. E.g., anchor character text frame can be a follow text +// frame. +// --> OD 2005-03-11 #i44016# - add parameter <_bUnlockPosOfObjs> to +// force an unlockposition call for the lower objects. +void SwLayoutFrm::NotifyLowerObjs( const bool _bUnlockPosOfObjs ) +{ + // invalidate lower floating screen objects + SwPageFrm* pPageFrm = FindPageFrm(); + if ( pPageFrm && pPageFrm->GetSortedObjs() ) + { + SwSortedObjs& rObjs = *(pPageFrm->GetSortedObjs()); + for ( sal_uInt32 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pObj = rObjs[i]; + // --> OD 2004-10-08 #i26945# - check, if anchored object is a lower + // of the layout frame is changed to check, if its anchor frame + // is a lower of the layout frame. + // determine the anchor frame - usually it's the anchor frame, + // for at-character/as-character anchored objects the anchor character + // text frame is taken. + const SwFrm* pAnchorFrm = pObj->GetAnchorFrmContainingAnchPos(); + // <-- + if ( pObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pObj); + + if ( pFly->Frm().Left() == WEIT_WECH ) + continue; + + if ( pFly->IsAnLower( this ) ) + continue; + + // --> OD 2004-10-08 #i26945# - use <pAnchorFrm> to check, if + // fly frame is lower of layout frame resp. if fly frame is + // at a different page registered as its anchor frame is on. + const bool bLow = IsAnLower( pAnchorFrm ); + if ( bLow || pAnchorFrm->FindPageFrm() != pPageFrm ) + // <-- + { + pFly->_Invalidate( pPageFrm ); + if ( !bLow || pFly->IsFlyAtCntFrm() ) + { + // --> OD 2005-03-11 #i44016# + if ( _bUnlockPosOfObjs ) + { + pFly->UnlockPosition(); + } + // <-- + pFly->_InvalidatePos(); + } + else + pFly->_InvalidatePrt(); + } + } + else + { + OSL_ENSURE( pObj->ISA(SwAnchoredDrawObject), + "<SwLayoutFrm::NotifyFlys() - anchored object of unexcepted type" ); + // --> OD 2004-10-08 #i26945# - use <pAnchorFrm> to check, if + // fly frame is lower of layout frame resp. if fly frame is + // at a different page registered as its anchor frame is on. + if ( IsAnLower( pAnchorFrm ) || + pAnchorFrm->FindPageFrm() != pPageFrm ) + // <-- + { + // --> OD 2005-03-11 #i44016# + if ( _bUnlockPosOfObjs ) + { + pObj->UnlockPosition(); + } + // <-- + pObj->InvalidateObjPos(); + } + } + } + } +} + +/************************************************************************* +|* +|* SwFlyFrm::NotifyDrawObj() +|* +|*************************************************************************/ + +void SwFlyFrm::NotifyDrawObj() +{ + SwVirtFlyDrawObj* pObj = GetVirtDrawObj(); + pObj->SetRect(); + pObj->SetRectsDirty(); + pObj->SetChanged(); + pObj->BroadcastObjectChange(); + if ( GetFmt()->GetSurround().IsContour() ) + ClrContourCache( pObj ); +} + +/************************************************************************* +|* +|* SwFlyFrm::CalcRel() +|* +|*************************************************************************/ + +Size SwFlyFrm::CalcRel( const SwFmtFrmSize &rSz ) const +{ + Size aRet( rSz.GetSize() ); + + const SwFrm *pRel = IsFlyLayFrm() ? GetAnchorFrm() : GetAnchorFrm()->GetUpper(); + if( pRel ) // LAYER_IMPL + { + long nRelWidth = LONG_MAX, nRelHeight = LONG_MAX; + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( ( pRel->IsBodyFrm() || pRel->IsPageFrm() ) && + pSh && pSh->GetViewOptions()->getBrowseMode() && + pSh->VisArea().HasArea() ) + { + nRelWidth = pSh->GetBrowseWidth(); + nRelHeight = pSh->VisArea().Height(); + Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() ); + long nDiff = nRelWidth - pRel->Prt().Width(); + if ( nDiff > 0 ) + nRelWidth -= nDiff; + nRelHeight -= 2*aBorder.Height(); + nDiff = nRelHeight - pRel->Prt().Height(); + if ( nDiff > 0 ) + nRelHeight -= nDiff; + } + nRelWidth = Min( nRelWidth, pRel->Prt().Width() ); + nRelHeight = Min( nRelHeight, pRel->Prt().Height() ); + if( !pRel->IsPageFrm() ) + { + const SwPageFrm* pPage = FindPageFrm(); + if( pPage ) + { + nRelWidth = Min( nRelWidth, pPage->Prt().Width() ); + nRelHeight = Min( nRelHeight, pPage->Prt().Height() ); + } + } + + if ( rSz.GetWidthPercent() && rSz.GetWidthPercent() != 0xFF ) + aRet.Width() = nRelWidth * rSz.GetWidthPercent() / 100; + if ( rSz.GetHeightPercent() && rSz.GetHeightPercent() != 0xFF ) + aRet.Height() = nRelHeight * rSz.GetHeightPercent() / 100; + + if ( rSz.GetWidthPercent() == 0xFF ) + { + aRet.Width() *= aRet.Height(); + aRet.Width() /= rSz.GetHeight(); + } + else if ( rSz.GetHeightPercent() == 0xFF ) + { + aRet.Height() *= aRet.Width(); + aRet.Height() /= rSz.GetWidth(); + } + } + return aRet; +} + +/************************************************************************* +|* +|* SwFlyFrm::CalcAutoWidth() +|* +|*************************************************************************/ + +SwTwips lcl_CalcAutoWidth( const SwLayoutFrm& rFrm ) +{ + SwTwips nRet = 0; + SwTwips nMin = 0; + const SwFrm* pFrm = rFrm.Lower(); + + // No autowidth defined for columned frames + if ( !pFrm || pFrm->IsColumnFrm() ) + return nRet; + + while ( pFrm ) + { + if ( pFrm->IsSctFrm() ) + { + nMin = lcl_CalcAutoWidth( *(SwSectionFrm*)pFrm ); + } + if ( pFrm->IsTxtFrm() ) + { + nMin = ((SwTxtFrm*)pFrm)->CalcFitToContent(); + const SvxLRSpaceItem &rSpace = + ((SwTxtFrm*)pFrm)->GetTxtNode()->GetSwAttrSet().GetLRSpace(); + nMin += rSpace.GetRight() + rSpace.GetTxtLeft() + rSpace.GetTxtFirstLineOfst(); + } + else if ( pFrm->IsTabFrm() ) + { + const SwFmtFrmSize& rTblFmtSz = ((SwTabFrm*)pFrm)->GetTable()->GetFrmFmt()->GetFrmSize(); + if ( USHRT_MAX == rTblFmtSz.GetSize().Width() || + text::HoriOrientation::NONE == ((SwTabFrm*)pFrm)->GetFmt()->GetHoriOrient().GetHoriOrient() ) + { + const SwPageFrm* pPage = rFrm.FindPageFrm(); + // auto width table + nMin = pFrm->GetUpper()->IsVertical() ? + pPage->Prt().Height() : + pPage->Prt().Width(); + } + else + { + nMin = rTblFmtSz.GetSize().Width(); + } + } + + if ( nMin > nRet ) + nRet = nMin; + + pFrm = pFrm->GetNext(); + } + + return nRet; +} + +SwTwips SwFlyFrm::CalcAutoWidth() const +{ + return lcl_CalcAutoWidth( *this ); +} + +/************************************************************************* +|* +|* SwFlyFrm::GetContour() +|* +|*************************************************************************/ +/// OD 16.04.2003 #i13147# - If called for paint and the <SwNoTxtFrm> contains +/// a graphic, load of intrinsic graphic has to be avoided. +sal_Bool SwFlyFrm::GetContour( PolyPolygon& rContour, + const sal_Bool _bForPaint ) const +{ + sal_Bool bRet = sal_False; + if( GetFmt()->GetSurround().IsContour() && Lower() && + Lower()->IsNoTxtFrm() ) + { + SwNoTxtNode *pNd = (SwNoTxtNode*)((SwCntntFrm*)Lower())->GetNode(); + // OD 16.04.2003 #i13147# - determine <GraphicObject> instead of <Graphic> + // in order to avoid load of graphic, if <SwNoTxtNode> contains a graphic + // node and method is called for paint. + const GraphicObject* pGrfObj = NULL; + sal_Bool bGrfObjCreated = sal_False; + const SwGrfNode* pGrfNd = pNd->GetGrfNode(); + if ( pGrfNd && _bForPaint ) + { + pGrfObj = &(pGrfNd->GetGrfObj()); + } + else + { + pGrfObj = new GraphicObject( pNd->GetGraphic() ); + bGrfObjCreated = sal_True; + } + OSL_ENSURE( pGrfObj, "SwFlyFrm::GetContour() - No Graphic/GraphicObject found at <SwNoTxtNode>." ); + if ( pGrfObj && pGrfObj->GetType() != GRAPHIC_NONE ) + { + if( !pNd->HasContour() ) + { + // OD 16.04.2003 #i13147# - no <CreateContour> for a graphic + // during paint. Thus, return (value of <bRet> should be <sal_False>). + if ( pGrfNd && _bForPaint ) + { + OSL_FAIL( "SwFlyFrm::GetContour() - No Contour found at <SwNoTxtNode> during paint." ); + return bRet; + } + pNd->CreateContour(); + } + pNd->GetContour( rContour ); + //Der Node haelt das Polygon passend zur Originalgroesse der Grafik + //hier muss die Skalierung einkalkuliert werden. + SwRect aClip; + SwRect aOrig; + Lower()->Calc(); + ((SwNoTxtFrm*)Lower())->GetGrfArea( aClip, &aOrig, sal_False ); + // OD 16.04.2003 #i13147# - copy method code <SvxContourDlg::ScaleContour(..)> + // in order to avoid that graphic has to be loaded for contour scale. + //SvxContourDlg::ScaleContour( rContour, aGrf, MAP_TWIP, aOrig.SSize() ); + { + OutputDevice* pOutDev = Application::GetDefaultDevice(); + const MapMode aDispMap( MAP_TWIP ); + const MapMode aGrfMap( pGrfObj->GetPrefMapMode() ); + const Size aGrfSize( pGrfObj->GetPrefSize() ); + Size aOrgSize; + Point aNewPoint; + sal_Bool bPixelMap = aGrfMap.GetMapUnit() == MAP_PIXEL; + + if ( bPixelMap ) + aOrgSize = pOutDev->PixelToLogic( aGrfSize, aDispMap ); + else + aOrgSize = pOutDev->LogicToLogic( aGrfSize, aGrfMap, aDispMap ); + + if ( aOrgSize.Width() && aOrgSize.Height() ) + { + double fScaleX = (double) aOrig.Width() / aOrgSize.Width(); + double fScaleY = (double) aOrig.Height() / aOrgSize.Height(); + + for ( sal_uInt16 j = 0, nPolyCount = rContour.Count(); j < nPolyCount; j++ ) + { + Polygon& rPoly = rContour[ j ]; + + for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ ) + { + if ( bPixelMap ) + aNewPoint = pOutDev->PixelToLogic( rPoly[ i ], aDispMap ); + else + aNewPoint = pOutDev->LogicToLogic( rPoly[ i ], aGrfMap, aDispMap ); + + rPoly[ i ] = Point( FRound( aNewPoint.X() * fScaleX ), FRound( aNewPoint.Y() * fScaleY ) ); + } + } + } + } + // OD 17.04.2003 #i13147# - destroy created <GraphicObject>. + if ( bGrfObjCreated ) + { + delete pGrfObj; + } + rContour.Move( aOrig.Left(), aOrig.Top() ); + if( !aClip.Width() ) + aClip.Width( 1 ); + if( !aClip.Height() ) + aClip.Height( 1 ); + rContour.Clip( aClip.SVRect() ); + rContour.Optimize(POLY_OPTIMIZE_CLOSE); + bRet = sal_True; + } + } + return bRet; +} + +// OD 2004-03-25 #i26791# +const SwVirtFlyDrawObj* SwFlyFrm::GetVirtDrawObj() const +{ + return static_cast<const SwVirtFlyDrawObj*>(GetDrawObj()); +} +SwVirtFlyDrawObj* SwFlyFrm::GetVirtDrawObj() +{ + return static_cast<SwVirtFlyDrawObj*>(DrawObj()); +} + +// ============================================================================= +// OD 2004-03-24 #i26791# - implementation of pure virtual method declared in +// base class <SwAnchoredObject> +// ============================================================================= +void SwFlyFrm::InvalidateObjPos() +{ + InvalidatePos(); + // --> OD 2006-08-10 #i68520# + InvalidateObjRectWithSpaces(); + // <-- +} + +SwFrmFmt& SwFlyFrm::GetFrmFmt() +{ + OSL_ENSURE( GetFmt(), + "<SwFlyFrm::GetFrmFmt()> - missing frame format -> crash." ); + return *GetFmt(); +} +const SwFrmFmt& SwFlyFrm::GetFrmFmt() const +{ + OSL_ENSURE( GetFmt(), + "<SwFlyFrm::GetFrmFmt()> - missing frame format -> crash." ); + return *GetFmt(); +} + +const SwRect SwFlyFrm::GetObjRect() const +{ + return Frm(); +} + +// --> OD 2006-10-05 #i70122# +// for Writer fly frames the bounding rectangle equals the object rectangles +const SwRect SwFlyFrm::GetObjBoundRect() const +{ + return GetObjRect(); +} +// <-- + +// --> OD 2006-08-10 #i68520# +bool SwFlyFrm::_SetObjTop( const SwTwips _nTop ) +{ + const bool bChanged( Frm().Pos().Y() != _nTop ); + + Frm().Pos().Y() = _nTop; + + return bChanged; +} +bool SwFlyFrm::_SetObjLeft( const SwTwips _nLeft ) +{ + const bool bChanged( Frm().Pos().X() != _nLeft ); + + Frm().Pos().X() = _nLeft; + + return bChanged; +} +// <-- + +/** method to assure that anchored object is registered at the correct + page frame + + OD 2004-07-02 #i28701# + + @author OD +*/ +void SwFlyFrm::RegisterAtCorrectPage() +{ + // default behaviour is to do nothing. +} + +/** method to determine, if a <MakeAll()> on the Writer fly frame is possible + + OD 2004-05-11 #i28701# + + @author OD +*/ +bool SwFlyFrm::IsFormatPossible() const +{ + return SwAnchoredObject::IsFormatPossible() && + !IsLocked() && !IsColLocked(); +} + +void SwFlyFrm::GetAnchoredObjects( std::list<SwAnchoredObject*>& aList, const SwFmt& rFmt ) +{ + SwIterator<SwFlyFrm,SwFmt> aIter( rFmt ); + for( SwFlyFrm* pFlyFrm = aIter.First(); pFlyFrm; pFlyFrm = aIter.Next() ) + aList.push_back( pFlyFrm ); +} + +const SwFlyFrmFmt * SwFlyFrm::GetFmt() const +{ + return static_cast< const SwFlyFrmFmt * >( GetDep() ); +} + +SwFlyFrmFmt * SwFlyFrm::GetFmt() +{ + return static_cast< SwFlyFrmFmt * >( GetDep() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx new file mode 100644 index 000000000000..7db5677f7403 --- /dev/null +++ b/sw/source/core/layout/flycnt.cxx @@ -0,0 +1,1541 @@ +/* -*- 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 <tools/bigint.hxx> +#include "pagefrm.hxx" +#include "cntfrm.hxx" +#include "flyfrm.hxx" +#include "txtfrm.hxx" +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include "viewsh.hxx" +#include "viewimp.hxx" +#include "pam.hxx" +#include "frmfmt.hxx" +#include "frmtool.hxx" +#include "dflyobj.hxx" +#include "hints.hxx" +#include "ndtxt.hxx" +#include "swundo.hxx" +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> + +#include "tabfrm.hxx" +#include "flyfrms.hxx" +#include "crstate.hxx" +#include "sectfrm.hxx" + +#include <tocntntanchoredobjectposition.hxx> +#include <dcontact.hxx> +#include <sortedobjs.hxx> +#include <layouter.hxx> +#include <objectformattertxtfrm.hxx> +#include <HandleAnchorNodeChg.hxx> + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwFlyAtCntFrm::SwFlyAtCntFrm() +|* +|*************************************************************************/ + +SwFlyAtCntFrm::SwFlyAtCntFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) : + SwFlyFreeFrm( pFmt, pSib, pAnch ) +{ + bAtCnt = sal_True; + bAutoPosition = (FLY_AT_CHAR == pFmt->GetAnchor().GetAnchorId()); +} + +// #i28701# +TYPEINIT1(SwFlyAtCntFrm,SwFlyFreeFrm); +/************************************************************************* +|* +|* SwFlyAtCntFrm::Modify() +|* +|*************************************************************************/ + +void SwFlyAtCntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + sal_uInt16 nWhich = pNew ? pNew->Which() : 0; + const SwFmtAnchor *pAnch = 0; + + if( RES_ATTRSET_CHG == nWhich && SFX_ITEM_SET == + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_ANCHOR, sal_False, + (const SfxPoolItem**)&pAnch )) + ; // Beim GetItemState wird der AnkerPointer gesetzt ! + + else if( RES_ANCHOR == nWhich ) + { + //Ankerwechsel, ich haenge mich selbst um. + //Es darf sich nicht um einen Wechsel des Ankertyps handeln, + //dies ist nur ueber die SwFEShell moeglich. + pAnch = (const SwFmtAnchor*)pNew; + } + + if( pAnch ) + { + OSL_ENSURE( pAnch->GetAnchorId() == GetFmt()->GetAnchor().GetAnchorId(), + "Unzulaessiger Wechsel des Ankertyps." ); + + //Abmelden, neuen Anker besorgen und 'dranhaengen. + SwRect aOld( GetObjRectWithSpaces() ); + SwPageFrm *pOldPage = FindPageFrm(); + const SwFrm *pOldAnchor = GetAnchorFrm(); + SwCntntFrm *pCntnt = (SwCntntFrm*)GetAnchorFrm(); + AnchorFrm()->RemoveFly( this ); + + const sal_Bool bBodyFtn = (pCntnt->IsInDocBody() || pCntnt->IsInFtn()); + + //Den neuen Anker anhand des NodeIdx suchen, am alten und + //neuen NodeIdx kann auch erkannt werden, in welche Richtung + //gesucht werden muss. + const SwNodeIndex aNewIdx( pAnch->GetCntntAnchor()->nNode ); + SwNodeIndex aOldIdx( *pCntnt->GetNode() ); + + //fix: Umstellung, ehemals wurde in der do-while-Schleife nach vorn bzw. + //nach hinten gesucht; je nachdem wie welcher Index kleiner war. + //Das kann aber u.U. zu einer Endlosschleife fuehren. Damit + //wenigstens die Schleife unterbunden wird suchen wir nur in eine + //Richtung. Wenn der neue Anker nicht gefunden wird koennen wir uns + //immer noch vom Node einen Frame besorgen. Die Change, dass dies dann + //der richtige ist, ist gut. + const bool bNext = aOldIdx < aNewIdx; + // consider the case that at found anchor frame candidate already a + // fly frame of the given fly format is registered. + // consider, that <pCntnt> is the already + // the new anchor frame. + bool bFound( aOldIdx == aNewIdx ); + while ( pCntnt && !bFound ) + { + do + { + if ( bNext ) + pCntnt = pCntnt->GetNextCntntFrm(); + else + pCntnt = pCntnt->GetPrevCntntFrm(); + } while ( pCntnt && + !( bBodyFtn == ( pCntnt->IsInDocBody() || + pCntnt->IsInFtn() ) ) ); + if ( pCntnt ) + aOldIdx = *pCntnt->GetNode(); + + // check, if at found anchor frame candidate already a fly frame + // of the given fly frame format is registered. + bFound = aOldIdx == aNewIdx; + if ( bFound && pCntnt->GetDrawObjs() ) + { + SwFrmFmt* pMyFlyFrmFmt( &GetFrmFmt() ); + SwSortedObjs &rObjs = *pCntnt->GetDrawObjs(); + for( sal_uInt16 i = 0; i < rObjs.Count(); ++i) + { + SwFlyFrm* pFlyFrm = dynamic_cast<SwFlyFrm*>(rObjs[i]); + if ( pFlyFrm && + &(pFlyFrm->GetFrmFmt()) == pMyFlyFrmFmt ) + { + bFound = false; + break; + } + } + } + } + if ( !pCntnt ) + { + SwCntntNode *pNode = aNewIdx.GetNode().GetCntntNode(); + pCntnt = pNode->getLayoutFrm( getRootFrm(), &pOldAnchor->Frm().Pos(), 0, sal_False ); + OSL_ENSURE( pCntnt, "Neuen Anker nicht gefunden" ); + } + //Flys haengen niemals an einem Follow sondern immer am + //Master, den suchen wir uns jetzt. + SwCntntFrm* pFlow = pCntnt; + while ( pFlow->IsFollow() ) + pFlow = pFlow->FindMaster(); + pCntnt = pFlow; + + //und schwupp angehaengt das teil... + pCntnt->AppendFly( this ); + if ( pOldPage && pOldPage != FindPageFrm() ) + NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE ); + + //Fix(3495) + _InvalidatePos(); + InvalidatePage(); + SetNotifyBack(); + // #i28701# - reset member <maLastCharRect> and + // <mnLastTopOfLine> for to-character anchored objects. + ClearCharRectAndTopOfLine(); + } + else + SwFlyFrm::Modify( pOld, pNew ); +} + +/************************************************************************* +|* +|* SwFlyAtCntFrm::MakeAll() +|* +|* Beschreibung Bei einem Absatzgebunden Fly kann es durchaus sein, +|* das der Anker auf die Veraenderung des Flys reagiert. Auf diese +|* Reaktion hat der Fly natuerlich auch wieder zu reagieren. +|* Leider kann dies zu Oszillationen fuehren z.b. Der Fly will nach +|* unten, dadurch kann der Inhalt nach oben, der TxtFrm wird kleiner, +|* der Fly muss wieder hoeher woduch der Text wieder nach unten +|* verdraengt wird... +|* Um derartige Oszillationen zu vermeiden, wird ein kleiner Positions- +|* stack aufgebaut. Wenn der Fly ein Position erreicht, die er bereits +|* einmal einnahm, so brechen wir den Vorgang ab. Um keine Risiken +|* einzugehen, wird der Positionsstack so aufgebaut, dass er fuenf +|* Positionen zurueckblickt. +|* Wenn der Stack ueberlaeuft, wird ebenfalls abgebrochen. +|* Der Abbruch fuer dazu, dass der Fly am Ende eine unguenste Position +|* einnimmt. Damit es nicht durch einen wiederholten Aufruf von +|* Aussen zu einer 'grossen Oszillation' kommen kann wird im Abbruch- +|* fall das Attribut des Rahmens auf automatische Ausrichtung oben +|* eingestellt. +|* +|*************************************************************************/ +//Wir brauchen ein Paar Hilfsklassen zur Kontrolle der Ozillation und ein paar +//Funktionen um die Uebersicht zu gewaehrleisten. +// #i3317# - re-factoring of the position stack +class SwOszControl +{ + static const SwFlyFrm *pStk1; + static const SwFlyFrm *pStk2; + static const SwFlyFrm *pStk3; + static const SwFlyFrm *pStk4; + static const SwFlyFrm *pStk5; + + const SwFlyFrm *pFly; + // #i3317# + sal_uInt8 mnPosStackSize; + std::vector<Point*> maObjPositions; + +public: + SwOszControl( const SwFlyFrm *pFrm ); + ~SwOszControl(); + bool ChkOsz(); + static sal_Bool IsInProgress( const SwFlyFrm *pFly ); +}; +const SwFlyFrm *SwOszControl::pStk1 = 0; +const SwFlyFrm *SwOszControl::pStk2 = 0; +const SwFlyFrm *SwOszControl::pStk3 = 0; +const SwFlyFrm *SwOszControl::pStk4 = 0; +const SwFlyFrm *SwOszControl::pStk5 = 0; + +SwOszControl::SwOszControl( const SwFlyFrm *pFrm ) + : pFly( pFrm ), + // #i3317# + mnPosStackSize( 20 ) +{ + if ( !SwOszControl::pStk1 ) + SwOszControl::pStk1 = pFly; + else if ( !SwOszControl::pStk2 ) + SwOszControl::pStk2 = pFly; + else if ( !SwOszControl::pStk3 ) + SwOszControl::pStk3 = pFly; + else if ( !SwOszControl::pStk4 ) + SwOszControl::pStk4 = pFly; + else if ( !SwOszControl::pStk5 ) + SwOszControl::pStk5 = pFly; +} + +SwOszControl::~SwOszControl() +{ + if ( SwOszControl::pStk1 == pFly ) + SwOszControl::pStk1 = 0; + else if ( SwOszControl::pStk2 == pFly ) + SwOszControl::pStk2 = 0; + else if ( SwOszControl::pStk3 == pFly ) + SwOszControl::pStk3 = 0; + else if ( SwOszControl::pStk4 == pFly ) + SwOszControl::pStk4 = 0; + else if ( SwOszControl::pStk5 == pFly ) + SwOszControl::pStk5 = 0; + // #i3317# + while ( !maObjPositions.empty() ) + { + Point* pPos = maObjPositions.back(); + delete pPos; + + maObjPositions.pop_back(); + } +} + +sal_Bool SwOszControl::IsInProgress( const SwFlyFrm *pFly ) +{ + if ( SwOszControl::pStk1 && !pFly->IsLowerOf( SwOszControl::pStk1 ) ) + return sal_True; + if ( SwOszControl::pStk2 && !pFly->IsLowerOf( SwOszControl::pStk2 ) ) + return sal_True; + if ( SwOszControl::pStk3 && !pFly->IsLowerOf( SwOszControl::pStk3 ) ) + return sal_True; + if ( SwOszControl::pStk4 && !pFly->IsLowerOf( SwOszControl::pStk4 ) ) + return sal_True; + if ( SwOszControl::pStk5 && !pFly->IsLowerOf( SwOszControl::pStk5 ) ) + return sal_True; + return sal_False; +} + +bool SwOszControl::ChkOsz() +{ + bool bOscillationDetected = false; + + if ( maObjPositions.size() == mnPosStackSize ) + { + // position stack is full -> oscillation + bOscillationDetected = true; + } + else + { + Point* pNewObjPos = new Point( pFly->GetObjRect().Pos() ); + for ( std::vector<Point*>::iterator aObjPosIter = maObjPositions.begin(); + aObjPosIter != maObjPositions.end(); + ++aObjPosIter ) + { + if ( *(pNewObjPos) == *(*aObjPosIter) ) + { + // position already occurred -> oscillation + bOscillationDetected = true; + delete pNewObjPos; + break; + } + } + if ( !bOscillationDetected ) + { + maObjPositions.push_back( pNewObjPos ); + } + } + + return bOscillationDetected; +} + +void SwFlyAtCntFrm::MakeAll() +{ + if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ) + { + return; + } + + if ( !SwOszControl::IsInProgress( this ) && !IsLocked() && !IsColLocked() ) + { + // #i28701# - use new method <GetPageFrm()> + if( !GetPageFrm() && GetAnchorFrm() && GetAnchorFrm()->IsInFly() ) + { + SwFlyFrm* pFly = AnchorFrm()->FindFlyFrm(); + SwPageFrm *pTmpPage = pFly ? pFly->FindPageFrm() : NULL; + if( pTmpPage ) + pTmpPage->AppendFlyToPage( this ); + } + // #i28701# - use new method <GetPageFrm()> + if( GetPageFrm() ) + { + bSetCompletePaintOnInvalidate = sal_True; + { + SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt(); + const SwFmtFrmSize &rFrmSz = GetFmt()->GetFrmSize(); + if( rFrmSz.GetHeightPercent() != 0xFF && + rFrmSz.GetHeightPercent() >= 100 ) + { + pFmt->LockModify(); + SwFmtSurround aMain( pFmt->GetSurround() ); + if ( aMain.GetSurround() == SURROUND_NONE ) + { + aMain.SetSurround( SURROUND_THROUGHT ); + pFmt->SetFmtAttr( aMain ); + } + pFmt->UnlockModify(); + } + } + + SwOszControl aOszCntrl( this ); + + // #i43255# + // #i50356# - format the anchor frame, which + // contains the anchor position. E.g., for at-character anchored + // object this can be the follow frame of the anchor frame. + const bool bFormatAnchor = + !static_cast<const SwTxtFrm*>( GetAnchorFrmContainingAnchPos() )->IsAnyJoinLocked() && + !ConsiderObjWrapInfluenceOnObjPos() && + !ConsiderObjWrapInfluenceOfOtherObjs(); + + const SwFrm* pFooter = GetAnchorFrm()->FindFooterOrHeader(); + if( pFooter && !pFooter->IsFooterFrm() ) + pFooter = NULL; + bool bOsz = false; + sal_Bool bExtra = Lower() && Lower()->IsColumnFrm(); + // #i3317# - boolean, to apply temporarly the + // 'straightforward positioning process' for the frame due to its + // overlapping with a previous column. + bool bConsiderWrapInfluenceDueToOverlapPrevCol( false ); + // #i35911# - boolean, to apply temporarly the + // 'straightforward positioning process' for the frame due to fact + // that it causes the complete content of its layout environment + // to move forward. + // #i40444# - extend usage of this boolean: + // apply temporarly the 'straightforward positioning process' for + // the frame due to the fact that the frame clears the area for + // the anchor frame, thus it has to move forward. + bool bConsiderWrapInfluenceDueToMovedFwdAnchor( false ); + do { + SWRECTFN( this ) + Point aOldPos( (Frm().*fnRect->fnGetPos)() ); + SwFlyFreeFrm::MakeAll(); + const bool bPosChgDueToOwnFormat = + aOldPos != (Frm().*fnRect->fnGetPos)(); + // #i3317# + if ( !ConsiderObjWrapInfluenceOnObjPos() && + OverlapsPrevColumn() ) + { + bConsiderWrapInfluenceDueToOverlapPrevCol = true; + } + // #i28701# - no format of anchor frame, if + // wrapping style influence is considered on object positioning + if ( bFormatAnchor ) + { + SwTxtFrm* pAnchPosAnchorFrm = + dynamic_cast<SwTxtFrm*>(GetAnchorFrmContainingAnchPos()); + OSL_ENSURE( pAnchPosAnchorFrm, + "<SwFlyAtCntFrm::MakeAll()> - anchor frame of wrong type -> crash" ); + // #i58182# - For the usage of new method + // <SwObjectFormatterTxtFrm::CheckMovedFwdCondition(..)> + // to check move forward of anchor frame due to the object + // positioning it's needed to know, if the object is anchored + // at the master frame before the anchor frame is formatted. + const bool bAnchoredAtMaster( !pAnchPosAnchorFrm->IsFollow() ); + + // #i56300# + // perform complete format of anchor text frame and its + // previous frames, which have become invalid due to the + // fly frame format. + SwObjectFormatterTxtFrm::FormatAnchorFrmAndItsPrevs( *pAnchPosAnchorFrm ); + // #i35911# + // #i40444# + // #i58182# - usage of new method + // <SwObjectFormatterTxtFrm::CheckMovedFwdCondition(..)> + sal_uInt32 nToPageNum( 0L ); + bool bDummy( false ); + if ( SwObjectFormatterTxtFrm::CheckMovedFwdCondition( + *this, GetPageFrm()->GetPhyPageNum(), + bAnchoredAtMaster, nToPageNum, bDummy ) ) + { + bConsiderWrapInfluenceDueToMovedFwdAnchor = true; + // mark anchor text frame + // directly, that it is moved forward by object positioning. + SwTxtFrm* pAnchorTxtFrm( static_cast<SwTxtFrm*>(AnchorFrm()) ); + bool bInsert( true ); + sal_uInt32 nAnchorFrmToPageNum( 0L ); + const SwDoc& rDoc = *(GetFrmFmt().GetDoc()); + if ( SwLayouter::FrmMovedFwdByObjPos( + rDoc, *pAnchorTxtFrm, nAnchorFrmToPageNum ) ) + { + if ( nAnchorFrmToPageNum < nToPageNum ) + SwLayouter::RemoveMovedFwdFrm( rDoc, *pAnchorTxtFrm ); + else + bInsert = false; + } + if ( bInsert ) + { + SwLayouter::InsertMovedFwdFrm( rDoc, *pAnchorTxtFrm, + nToPageNum ); + } + } + } + + if ( aOldPos != (Frm().*fnRect->fnGetPos)() || + ( !GetValidPosFlag() && + ( pFooter || bPosChgDueToOwnFormat ) ) ) + { + bOsz = aOszCntrl.ChkOsz(); + + // special loop prevention for dedicated document: + if ( bOsz && + HasFixSize() && IsClipped() && + GetAnchorFrm()->GetUpper()->IsCellFrm() ) + { + SwFrmFmt* pFmt = GetFmt(); + const SwFmtFrmSize& rFrmSz = pFmt->GetFrmSize(); + if ( rFrmSz.GetWidthPercent() && + rFrmSz.GetHeightPercent() == 0xFF ) + { + SwFmtSurround aSurround( pFmt->GetSurround() ); + if ( aSurround.GetSurround() == SURROUND_NONE ) + { + pFmt->LockModify(); + aSurround.SetSurround( SURROUND_THROUGHT ); + pFmt->SetFmtAttr( aSurround ); + pFmt->UnlockModify(); + bOsz = false; +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "<SwFlyAtCntFrm::MakeAll()> - special loop prevention for dedicated document of b6403541 applied" ); +#endif + } + } + } + } + + if ( bExtra && Lower() && !Lower()->GetValidPosFlag() ) + { + // Wenn ein mehrspaltiger Rahmen wg. Positionswechsel ungueltige + // Spalten hinterlaesst, so drehen wir lieber hier eine weitere + // Runde und formatieren unseren Inhalt via FormatWidthCols nochmal. + _InvalidateSize(); + bExtra = sal_False; // Sicherhaltshalber gibt es nur eine Ehrenrunde. + } + } while ( !IsValid() && !bOsz && + // #i3317# + !bConsiderWrapInfluenceDueToOverlapPrevCol && + // #i40444# + !bConsiderWrapInfluenceDueToMovedFwdAnchor && + GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ); + + // #i3317# - instead of attribute change apply + // temporarly the 'straightforward positioning process'. + // #i80924# + // handle special case during splitting of table rows + if ( bConsiderWrapInfluenceDueToMovedFwdAnchor && + GetAnchorFrm()->IsInTab() && + GetAnchorFrm()->IsInFollowFlowRow() ) + { + const SwFrm* pCellFrm = GetAnchorFrm(); + while ( pCellFrm && !pCellFrm->IsCellFrm() ) + { + pCellFrm = pCellFrm->GetUpper(); + } + if ( pCellFrm ) + { + SWRECTFN( pCellFrm ) + if ( (pCellFrm->Frm().*fnRect->fnGetTop)() == 0 && + (pCellFrm->Frm().*fnRect->fnGetHeight)() == 0 ) + { + bConsiderWrapInfluenceDueToMovedFwdAnchor = false; + } + } + } + if ( bOsz || bConsiderWrapInfluenceDueToOverlapPrevCol || + // #i40444# + bConsiderWrapInfluenceDueToMovedFwdAnchor ) + { + SetTmpConsiderWrapInfluence( true ); + SetRestartLayoutProcess( true ); + SetTmpConsiderWrapInfluenceOfOtherObjs( true ); + } + bSetCompletePaintOnInvalidate = sal_False; + } + } +} + +/** method to determine, if a <MakeAll()> on the Writer fly frame is possible + + #i28701# +*/ +bool SwFlyAtCntFrm::IsFormatPossible() const +{ + return SwFlyFreeFrm::IsFormatPossible() && + !SwOszControl::IsInProgress( this ); +} + +/************************************************************************* +|* +|* FindAnchor() und Hilfsfunktionen. +|* +|* Beschreibung: Sucht ausgehend von pOldAnch einen Anker fuer +|* Absatzgebundene Objekte. +|* Wird beim Draggen von Absatzgebundenen Objekten zur Ankeranzeige sowie +|* fuer Ankerwechsel benoetigt. +|* +|*************************************************************************/ + +class SwDistance +{ +public: + SwTwips nMain, nSub; + SwDistance() { nMain = nSub = 0; } + SwDistance& operator=( const SwDistance &rTwo ) + { nMain = rTwo.nMain; nSub = rTwo.nSub; return *this; } + sal_Bool operator<( const SwDistance& rTwo ) + { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && nSub && + rTwo.nSub && nSub < rTwo.nSub ); } + sal_Bool operator<=( const SwDistance& rTwo ) + { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && ( !nSub || + !rTwo.nSub || nSub <= rTwo.nSub ) ); } +}; + +const SwFrm * MA_FASTCALL lcl_CalcDownDist( SwDistance &rRet, + const Point &rPt, + const SwCntntFrm *pCnt ) +{ + rRet.nSub = 0; + //Wenn der Point direkt innerhalb des Cnt steht ist die Sache klar und + //der Cntnt hat automatisch eine Entfernung von 0 + if ( pCnt->Frm().IsInside( rPt ) ) + { + rRet.nMain = 0; + return pCnt; + } + else + { + const SwLayoutFrm *pUp = pCnt->IsInTab() ? pCnt->FindTabFrm()->GetUpper() : pCnt->GetUpper(); + // einspaltige Bereiche muessen zu ihrem Upper durchschalten + while( pUp->IsSctFrm() ) + pUp = pUp->GetUpper(); + const bool bVert = pUp->IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + const bool bVertL2R = pUp->IsVertLR(); + + //Dem Textflus folgen. + // #i70582# + // --> OD 2009-03-05 - adopted for Support for Classical Mongolian Script + const SwTwips nTopForObjPos = + bVert + ? ( bVertL2R + ? ( pCnt->Frm().Left() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) + : ( pCnt->Frm().Left() + + pCnt->Frm().Width() - + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) ) + : ( pCnt->Frm().Top() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ); + if ( pUp->Frm().IsInside( rPt ) ) + { + // <rPt> point is inside environment of given content frame + // #i70582# + if( bVert ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( bVertL2R ) + rRet.nMain = rPt.X() - nTopForObjPos; + else + rRet.nMain = nTopForObjPos - rPt.X(); + } + else + rRet.nMain = rPt.Y() - nTopForObjPos; + return pCnt; + } + else if ( rPt.Y() <= pUp->Frm().Top() ) + { + // <rPt> point is above environment of given content frame + // correct for vertical layout? + rRet.nMain = LONG_MAX; + } + else if( rPt.X() < pUp->Frm().Left() && + rPt.Y() <= ( bVert ? pUp->Frm().Top() : pUp->Frm().Bottom() ) ) + { + // <rPt> point is left of environment of given content frame + // seems not to be correct for vertical layout!? + const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, sal_False, pCnt ); + if( !pLay || + (bVert && (pLay->Frm().Top() + pLay->Prt().Bottom()) <rPt.Y())|| + (!bVert && (pLay->Frm().Left() + pLay->Prt().Right())<rPt.X()) ) + { + // <rPt> point is in left border of environment + // #i70582# + if( bVert ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( bVertL2R ) + rRet.nMain = rPt.X() - nTopForObjPos; + else + rRet.nMain = nTopForObjPos - rPt.X(); + } + else + rRet.nMain = rPt.Y() - nTopForObjPos; + return pCnt; + } + else + rRet.nMain = LONG_MAX; + } + else + { + // Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + rRet.nMain = bVert + ? ( bVertL2R + ? ( (pUp->Frm().Left() + pUp->Prt().Right()) - nTopForObjPos ) + : ( nTopForObjPos - (pUp->Frm().Left() + pUp->Prt().Left() ) ) ) + : ( (pUp->Frm().Top() + pUp->Prt().Bottom()) - nTopForObjPos ); + + const SwFrm *pPre = pCnt; + const SwFrm *pLay = pUp->GetLeaf( MAKEPAGE_NONE, sal_True, pCnt ); + SwTwips nFrmTop = 0; + SwTwips nPrtHeight = 0; + sal_Bool bSct = sal_False; + const SwSectionFrm *pSect = pUp->FindSctFrm(); + if( pSect ) + { + rRet.nSub = rRet.nMain; + rRet.nMain = 0; + } + if( pSect && !pSect->IsAnLower( pLay ) ) + { + bSct = sal_False; + const SwSectionFrm* pNxtSect = pLay ? pLay->FindSctFrm() : 0; + if( pSect->IsAnFollow( pNxtSect ) ) + { + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + nFrmTop = pLay->Frm().Left(); + else + nFrmTop = pLay->Frm().Left() + pLay->Frm().Width(); + nPrtHeight = pLay->Prt().Width(); + } + else + { + nFrmTop = pLay->Frm().Top(); + nPrtHeight = pLay->Prt().Height(); + } + pSect = pNxtSect; + } + else + { + pLay = pSect->GetUpper(); + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + { + nFrmTop = pSect->Frm().Right(); + nPrtHeight = pLay->Frm().Left() + pLay->Prt().Left() + + pLay->Prt().Width() - pSect->Frm().Left() + - pSect->Frm().Width(); + } + else + { + nFrmTop = pSect->Frm().Left(); + nPrtHeight = pSect->Frm().Left() - pLay->Frm().Left() + - pLay->Prt().Left(); + } + } + else + { + nFrmTop = pSect->Frm().Bottom(); + nPrtHeight = pLay->Frm().Top() + pLay->Prt().Top() + + pLay->Prt().Height() - pSect->Frm().Top() + - pSect->Frm().Height(); + } + pSect = 0; + } + } + else if( pLay ) + { + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + { + nFrmTop = pLay->Frm().Left(); + nPrtHeight = pLay->Prt().Width(); + } + else + { + nFrmTop = pLay->Frm().Left() + pLay->Frm().Width(); + nPrtHeight = pLay->Prt().Width(); + } + } + else + { + nFrmTop = pLay->Frm().Top(); + nPrtHeight = pLay->Prt().Height(); + } + bSct = 0 != pSect; + } + while ( pLay && !pLay->Frm().IsInside( rPt ) && + ( pLay->Frm().Top() <= rPt.Y() || pLay->IsInFly() || + ( pLay->IsInSct() && + pLay->FindSctFrm()->GetUpper()->Frm().Top() <= rPt.Y())) ) + { + if ( pLay->IsFtnContFrm() ) + { + if ( !((SwLayoutFrm*)pLay)->Lower() ) + { + SwFrm *pDel = (SwFrm*)pLay; + pDel->Cut(); + delete pDel; + return pPre; + } + return 0; + } + else + { + if( bSct || pSect ) + rRet.nSub += nPrtHeight; + else + rRet.nMain += nPrtHeight; + pPre = pLay; + pLay = pLay->GetLeaf( MAKEPAGE_NONE, sal_True, pCnt ); + if( pSect && !pSect->IsAnLower( pLay ) ) + { // If we're leaving a SwSectionFrm, the next Leaf-Frm + // is the part of the upper below the SectionFrm. + const SwSectionFrm* pNxtSect = pLay ? + pLay->FindSctFrm() : NULL; + bSct = sal_False; + if( pSect->IsAnFollow( pNxtSect ) ) + { + pSect = pNxtSect; + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + { + nFrmTop = pLay->Frm().Left(); + nPrtHeight = pLay->Prt().Width(); + } + else + { + nFrmTop = pLay->Frm().Left() + pLay->Frm().Width(); + nPrtHeight = pLay->Prt().Width(); + } + } + else + { + nFrmTop = pLay->Frm().Top(); + nPrtHeight = pLay->Prt().Height(); + } + } + else + { + pLay = pSect->GetUpper(); + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + { + nFrmTop = pSect->Frm().Right(); + nPrtHeight = pLay->Frm().Left()+pLay->Prt().Left() + + pLay->Prt().Width() - pSect->Frm().Left() + - pSect->Frm().Width(); + } + else + { + nFrmTop = pSect->Frm().Left(); + nPrtHeight = pSect->Frm().Left() - + pLay->Frm().Left() - pLay->Prt().Left(); + } + } + else + { + nFrmTop = pSect->Frm().Bottom(); + nPrtHeight = pLay->Frm().Top()+pLay->Prt().Top() + + pLay->Prt().Height() - pSect->Frm().Top() + - pSect->Frm().Height(); + } + pSect = 0; + } + } + else if( pLay ) + { + if( pLay->IsVertical() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( pLay->IsVertLR() ) + { + nFrmTop = pLay->Frm().Left(); + nPrtHeight = pLay->Prt().Width(); + } + else + { + nFrmTop = pLay->Frm().Left() + pLay->Frm().Width(); + nPrtHeight = pLay->Prt().Width(); + } + } + else + { + nFrmTop = pLay->Frm().Top(); + nPrtHeight = pLay->Prt().Height(); + } + bSct = 0 != pSect; + } + } + } + if ( pLay ) + { + if ( pLay->Frm().IsInside( rPt ) ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwTwips nDiff = pLay->IsVertical() ? ( pLay->IsVertLR() ? ( rPt.X() - nFrmTop ) : ( nFrmTop - rPt.X() ) ) + : ( rPt.Y() - nFrmTop ); + if( bSct || pSect ) + rRet.nSub += nDiff; + else + rRet.nMain += nDiff; + } + if ( pLay->IsFtnContFrm() && !((SwLayoutFrm*)pLay)->Lower() ) + { + SwFrm *pDel = (SwFrm*)pLay; + pDel->Cut(); + delete pDel; + return 0; + } + return pLay; + } + else + rRet.nMain = LONG_MAX; + } + } + return 0; +} + +sal_uLong MA_FASTCALL lcl_FindCntDiff( const Point &rPt, const SwLayoutFrm *pLay, + const SwCntntFrm *& rpCnt, + const sal_Bool bBody, const sal_Bool bFtn ) +{ + //Sucht unterhalb von pLay den dichtesten Cnt zum Point. Der Bezugspunkt + //der Cntnts ist immer die linke obere Ecke. + //Der Cnt soll moeglichst ueber dem Point liegen. + +#if OSL_DEBUG_LEVEL > 1 + Point arPoint( rPt ); +#endif + + rpCnt = 0; + sal_uLong nDistance = ULONG_MAX; + sal_uLong nNearest = ULONG_MAX; + const SwCntntFrm *pCnt = pLay->ContainsCntnt(); + + while ( pCnt && (bBody != pCnt->IsInDocBody() || bFtn != pCnt->IsInFtn())) + { + pCnt = pCnt->GetNextCntntFrm(); + if ( !pLay->IsAnLower( pCnt ) ) + pCnt = 0; + } + const SwCntntFrm *pNearest = pCnt; + if ( pCnt ) + { + do + { + //Jetzt die Entfernung zwischen den beiden Punkten berechnen. + //'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2 + sal_uInt32 dX = Max( pCnt->Frm().Left(), rPt.X() ) - + Min( pCnt->Frm().Left(), rPt.X() ), + dY = Max( pCnt->Frm().Top(), rPt.Y() ) - + Min( pCnt->Frm().Top(), rPt.Y() ); + BigInt dX1( dX ), dY1( dY ); + dX1 *= dX1; dY1 *= dY1; + const sal_uLong nDiff = ::SqRt( dX1 + dY1 ); + if ( pCnt->Frm().Top() <= rPt.Y() ) + { + if ( nDiff < nDistance ) + { //Der ist dichter dran + nDistance = nNearest = nDiff; + rpCnt = pNearest = pCnt; + } + } + else if ( nDiff < nNearest ) + { + nNearest = nDiff; + pNearest = pCnt; + } + pCnt = pCnt->GetNextCntntFrm(); + while ( pCnt && + (bBody != pCnt->IsInDocBody() || bFtn != pCnt->IsInFtn())) + pCnt = pCnt->GetNextCntntFrm(); + + } while ( pCnt && pLay->IsAnLower( pCnt ) ); + } + if ( nDistance == ULONG_MAX ) + { rpCnt = pNearest; + return nNearest; + } + return nDistance; +} + +const SwCntntFrm * MA_FASTCALL lcl_FindCnt( const Point &rPt, const SwCntntFrm *pCnt, + const sal_Bool bBody, const sal_Bool bFtn ) +{ + //Sucht ausgehen von pCnt denjenigen CntntFrm, dessen linke obere + //Ecke am dichtesten am Point liegt. + //Liefert _immer_ einen CntntFrm zurueck. + + //Zunaechst wird versucht den dichtesten Cntnt innerhalt derjenigen + //Seite zu suchen innerhalb derer der Cntnt steht. + //Ausgehend von der Seite muessen die Seiten in beide + //Richtungen beruecksichtigt werden. + //Falls moeglich wird ein Cntnt geliefert, dessen Y-Position ueber der + //des Point sitzt. + const SwCntntFrm *pRet, *pNew; + const SwLayoutFrm *pLay = pCnt->FindPageFrm(); + sal_uLong nDist; + + nDist = ::lcl_FindCntDiff( rPt, pLay, pNew, bBody, bFtn ); + if ( pNew ) + pRet = pNew; + else + { pRet = pCnt; + nDist = ULONG_MAX; + } + const SwCntntFrm *pNearest = pRet; + sal_uLong nNearest = nDist; + + if ( pLay ) + { + const SwLayoutFrm *pPge = pLay; + sal_uLong nOldNew = ULONG_MAX; + for ( sal_uInt16 i = 0; pPge->GetPrev() && (i < 3); ++i ) + { + pPge = (SwLayoutFrm*)pPge->GetPrev(); + const sal_uLong nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFtn ); + if ( nNew < nDist ) + { + if ( pNew->Frm().Top() <= rPt.Y() ) + { + pRet = pNearest = pNew; + nDist = nNearest = nNew; + } + else if ( nNew < nNearest ) + { + pNearest = pNew; + nNearest = nNew; + } + } + else if ( nOldNew != ULONG_MAX && nNew > nOldNew ) + break; + else + nOldNew = nNew; + + } + pPge = pLay; + nOldNew = ULONG_MAX; + for ( sal_uInt16 j = 0; pPge->GetNext() && (j < 3); ++j ) + { + pPge = (SwLayoutFrm*)pPge->GetNext(); + const sal_uLong nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFtn ); + if ( nNew < nDist ) + { + if ( pNew->Frm().Top() <= rPt.Y() ) + { + pRet = pNearest = pNew; + nDist = nNearest = nNew; + } + else if ( nNew < nNearest ) + { + pNearest = pNew; + nNearest = nNew; + } + } + else if ( nOldNew != ULONG_MAX && nNew > nOldNew ) + break; + else + nOldNew = nNew; + } + } + if ( (pRet->Frm().Top() > rPt.Y()) ) + return pNearest; + else + return pRet; +} + +void lcl_PointToPrt( Point &rPoint, const SwFrm *pFrm ) +{ + SwRect aTmp( pFrm->Prt() ); + aTmp += pFrm->Frm().Pos(); + if ( rPoint.X() < aTmp.Left() ) + rPoint.X() = aTmp.Left(); + else if ( rPoint.X() > aTmp.Right() ) + rPoint.X() = aTmp.Right(); + if ( rPoint.Y() < aTmp.Top() ) + rPoint.Y() = aTmp.Top(); + else if ( rPoint.Y() > aTmp.Bottom() ) + rPoint.Y() = aTmp.Bottom(); + +} + +const SwCntntFrm *FindAnchor( const SwFrm *pOldAnch, const Point &rNew, + const sal_Bool bBodyOnly ) +{ + //Zu der angegebenen DokumentPosition wird der dichteste Cnt im + //Textfluss gesucht. AusgangsFrm ist der uebergebene Anker. + const SwCntntFrm* pCnt; + if ( pOldAnch->IsCntntFrm() ) + { + pCnt = (const SwCntntFrm*)pOldAnch; + } + else + { + Point aTmp( rNew ); + SwLayoutFrm *pTmpLay = (SwLayoutFrm*)pOldAnch; + if( pTmpLay->IsRootFrm() ) + { + SwRect aTmpRect( aTmp, Size(0,0) ); + pTmpLay = (SwLayoutFrm*)::FindPage( aTmpRect, pTmpLay->Lower() ); + } + pCnt = pTmpLay->GetCntntPos( aTmp, sal_False, bBodyOnly ); + } + + //Beim Suchen darauf achten, dass die Bereiche sinnvoll erhalten + //bleiben. D.h. in diesem Fall nicht in Header/Footer hinein und + //nicht aus Header/Footer hinaus. + const sal_Bool bBody = pCnt->IsInDocBody() || bBodyOnly; + const sal_Bool bFtn = !bBodyOnly && pCnt->IsInFtn(); + + Point aNew( rNew ); + if ( bBody ) + { + //#38848 Vom Seitenrand in den Body ziehen. + const SwFrm *pPage = pCnt->FindPageFrm(); + ::lcl_PointToPrt( aNew, pPage->GetUpper() ); + SwRect aTmp( aNew, Size( 0, 0 ) ); + pPage = ::FindPage( aTmp, pPage ); + ::lcl_PointToPrt( aNew, pPage ); + } + + if ( pCnt->IsInDocBody() == bBody && pCnt->Frm().IsInside( aNew ) ) + return pCnt; + else if ( pOldAnch->IsInDocBody() || pOldAnch->IsPageFrm() ) + { + //Vielleicht befindet sich der gewuenschte Anker ja auf derselben + //Seite wie der aktuelle Anker. + //So gibt es kein Problem mit Spalten. + Point aTmp( aNew ); + const SwCntntFrm *pTmp = pCnt->FindPageFrm()-> + GetCntntPos( aTmp, sal_False, sal_True, sal_False ); + if ( pTmp && pTmp->Frm().IsInside( aNew ) ) + return pTmp; + } + + //Ausgehend vom Anker suche ich jetzt in beide Richtungen bis ich + //den jeweils dichtesten gefunden habe. + //Nicht die direkte Entfernung ist relevant sondern die Strecke die + //im Textfluss zurueckgelegt werden muss. + const SwCntntFrm *pUpLst; + const SwCntntFrm *pUpFrm = pCnt; + SwDistance nUp, nUpLst; + ::lcl_CalcDownDist( nUp, aNew, pUpFrm ); + SwDistance nDown = nUp; + sal_Bool bNegAllowed = sal_True;//Einmal aus dem negativen Bereich heraus lassen. + do + { + pUpLst = pUpFrm; nUpLst = nUp; + pUpFrm = pUpLst->GetPrevCntntFrm(); + while ( pUpFrm && + (bBody != pUpFrm->IsInDocBody() || bFtn != pUpFrm->IsInFtn())) + pUpFrm = pUpFrm->GetPrevCntntFrm(); + if ( pUpFrm ) + { + ::lcl_CalcDownDist( nUp, aNew, pUpFrm ); + //Wenn die Distanz innnerhalb einer Tabelle waechst, so lohnt es + //sich weiter zu suchen. + if ( pUpLst->IsInTab() && pUpFrm->IsInTab() ) + { + while ( pUpFrm && ((nUpLst < nUp && pUpFrm->IsInTab()) || + bBody != pUpFrm->IsInDocBody()) ) + { + pUpFrm = pUpFrm->GetPrevCntntFrm(); + if ( pUpFrm ) + ::lcl_CalcDownDist( nUp, aNew, pUpFrm ); + } + } + } + if ( !pUpFrm ) + nUp.nMain = LONG_MAX; + if ( nUp.nMain >= 0 && LONG_MAX != nUp.nMain ) + { + bNegAllowed = sal_False; + if ( nUpLst.nMain < 0 ) //nicht den falschen erwischen, wenn der Wert + //gerade von negativ auf positiv gekippt ist. + { pUpLst = pUpFrm; + nUpLst = nUp; + } + } + } while ( pUpFrm && ( ( bNegAllowed && nUp.nMain < 0 ) || ( nUp <= nUpLst ) ) ); + + const SwCntntFrm *pDownLst; + const SwCntntFrm *pDownFrm = pCnt; + SwDistance nDownLst; + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + do + { + pDownLst = pDownFrm; nDownLst = nDown; + pDownFrm = pDownLst->GetNextCntntFrm(); + while ( pDownFrm && + (bBody != pDownFrm->IsInDocBody() || bFtn != pDownFrm->IsInFtn())) + pDownFrm = pDownFrm->GetNextCntntFrm(); + if ( pDownFrm ) + { + ::lcl_CalcDownDist( nDown, aNew, pDownFrm ); + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + //Wenn die Distanz innnerhalb einer Tabelle waechst, so lohnt es + //sich weiter zu suchen. + if ( pDownLst->IsInTab() && pDownFrm->IsInTab() ) + { + while ( pDownFrm && ( ( nDown.nMain != LONG_MAX && nDownLst < nDownLst + && pDownFrm->IsInTab()) || bBody != pDownFrm->IsInDocBody() ) ) + { + pDownFrm = pDownFrm->GetNextCntntFrm(); + if ( pDownFrm ) + ::lcl_CalcDownDist( nDown, aNew, pDownFrm ); + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + } + } + } + if ( !pDownFrm ) + nDown.nMain = LONG_MAX; + + } while ( pDownFrm && nDown <= nDownLst && + nDown.nMain != LONG_MAX && nDownLst.nMain != LONG_MAX ); + + //Wenn ich in beide Richtungen keinen gefunden habe, so suche ich mir + //denjenigen Cntnt dessen linke obere Ecke dem Point am naechsten liegt. + //Eine derartige Situation tritt z.b. auf, wenn der Point nicht im Text- + //fluss sondern in irgendwelchen Raendern steht. + if ( nDownLst.nMain == LONG_MAX && nUpLst.nMain == LONG_MAX ) + { + // If an OLE objects, which is contained in a fly frame + // is resized in inplace mode and the new Position is outside the + // fly frame, we do not want to leave our fly frame. + if ( pCnt->IsInFly() ) + return pCnt; + + return ::lcl_FindCnt( aNew, pCnt, bBody, bFtn ); + } + else + return nDownLst < nUpLst ? pDownLst : pUpLst; +} + +/************************************************************************* +|* +|* SwFlyAtCntFrm::SetAbsPos() +|* +|*************************************************************************/ + +void SwFlyAtCntFrm::SetAbsPos( const Point &rNew ) +{ + SwPageFrm *pOldPage = FindPageFrm(); + const SwRect aOld( GetObjRectWithSpaces() ); + Point aNew( rNew ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( ( GetAnchorFrm()->IsVertical() && !GetAnchorFrm()->IsVertLR() ) || GetAnchorFrm()->IsRightToLeft() ) + aNew.X() += Frm().Width(); + SwCntntFrm *pCnt = (SwCntntFrm*)::FindAnchor( GetAnchorFrm(), aNew ); + if( pCnt->IsProtected() ) + pCnt = (SwCntntFrm*)GetAnchorFrm(); + + SwPageFrm *pTmpPage = 0; + const bool bVert = pCnt->IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + const bool bVertL2R = pCnt->IsVertLR(); + const sal_Bool bRTL = pCnt->IsRightToLeft(); + + if( ( !bVert != !GetAnchorFrm()->IsVertical() ) || + ( !bRTL != !GetAnchorFrm()->IsRightToLeft() ) ) + { + if( bVert || bRTL ) + aNew.X() += Frm().Width(); + else + aNew.X() -= Frm().Width(); + } + + if ( pCnt->IsInDocBody() ) + { + //#38848 Vom Seitenrand in den Body ziehen. + pTmpPage = pCnt->FindPageFrm(); + ::lcl_PointToPrt( aNew, pTmpPage->GetUpper() ); + SwRect aTmp( aNew, Size( 0, 0 ) ); + pTmpPage = (SwPageFrm*)::FindPage( aTmp, pTmpPage ); + ::lcl_PointToPrt( aNew, pTmpPage ); + } + + //RelPos einstellen, nur auf Wunsch invalidieren. + //rNew ist eine Absolute Position. Um die RelPos korrekt einzustellen + //muessen wir uns die Entfernung von rNew zum Anker im Textfluss besorgen. +//!!!!!Hier kann Optimiert werden: FindAnchor koennte die RelPos mitliefern! + const SwFrm *pFrm = 0; + SwTwips nY; + if ( pCnt->Frm().IsInside( aNew ) ) + { + // #i70582# + const SwTwips nTopForObjPos = + bVert + ? ( bVertL2R + ? ( pCnt->Frm().Left() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) + : ( pCnt->Frm().Left() + + pCnt->Frm().Width() - + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) ) + : ( pCnt->Frm().Top() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ); + if( bVert ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( bVertL2R ) + nY = rNew.X() - nTopForObjPos; + else + nY = nTopForObjPos - rNew.X() - Frm().Width(); + } + else + { + nY = rNew.Y() - nTopForObjPos; + } + } + else + { + SwDistance aDist; + pFrm = ::lcl_CalcDownDist( aDist, aNew, pCnt ); + nY = aDist.nMain + aDist.nSub; + } + + SwTwips nX = 0; + + if ( pCnt->IsFollow() ) + { + //Flys haengen niemals an einem Follow sondern immer am + //Master, den suchen wir uns jetzt. + const SwCntntFrm *pOriginal = pCnt; + const SwCntntFrm *pFollow = pCnt; + while ( pCnt->IsFollow() ) + { + do + { pCnt = pCnt->GetPrevCntntFrm(); + } while ( pCnt->GetFollow() != pFollow ); + pFollow = pCnt; + } + SwTwips nDiff = 0; + do + { const SwFrm *pUp = pFollow->GetUpper(); + if( pUp->IsVertical() ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( pUp->IsVertLR() ) + nDiff += pUp->Prt().Width() - pFollow->GetRelPos().X(); + else + nDiff += pFollow->Frm().Left() + pFollow->Frm().Width() + - pUp->Frm().Left() - pUp->Prt().Left(); + } + else + nDiff += pUp->Prt().Height() - pFollow->GetRelPos().Y(); + pFollow = pFollow->GetFollow(); + } while ( pFollow != pOriginal ); + nY += nDiff; + if( bVert ) + nX = pCnt->Frm().Top() - pOriginal->Frm().Top(); + else + nX = pCnt->Frm().Left() - pOriginal->Frm().Left(); + } + + if ( nY == LONG_MAX ) + { + // #i70582# + const SwTwips nTopForObjPos = + bVert + ? ( bVertL2R + ? ( pCnt->Frm().Left() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) + : ( pCnt->Frm().Left() + + pCnt->Frm().Width() - + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ) ) + : ( pCnt->Frm().Top() + + pCnt->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() ); + if( bVert ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + if ( bVertL2R ) + nY = rNew.X() - nTopForObjPos; + else + nY = nTopForObjPos - rNew.X(); + } + else + { + nY = rNew.Y() - nTopForObjPos; + } + } + + SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt(); + const SwFmtSurround& rSurround = pFmt->GetSurround(); + const sal_Bool bWrapThrough = + rSurround.GetSurround() == SURROUND_THROUGHT; + SwTwips nBaseOfstForFly = 0; + const SwFrm* pTmpFrm = pFrm ? pFrm : pCnt; + if ( pTmpFrm->IsTxtFrm() ) + nBaseOfstForFly = + ((SwTxtFrm*)pTmpFrm)->GetBaseOfstForFly( !bWrapThrough ); + + if( bVert ) + { + if( !pFrm ) + nX += rNew.Y() - pCnt->Frm().Top() - nBaseOfstForFly; + else + nX = rNew.Y() - pFrm->Frm().Top() - nBaseOfstForFly; + } + else + { + if( !pFrm ) + { + if ( pCnt->IsRightToLeft() ) + nX += pCnt->Frm().Right() - rNew.X() - Frm().Width() + + nBaseOfstForFly; + else + nX += rNew.X() - pCnt->Frm().Left() - nBaseOfstForFly; + } + else + { + if ( pFrm->IsRightToLeft() ) + nX += pFrm->Frm().Right() - rNew.X() - Frm().Width() + + nBaseOfstForFly; + else + nX = rNew.X() - pFrm->Frm().Left() - nBaseOfstForFly; + } + } + GetFmt()->GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); + + if( pCnt != GetAnchorFrm() || ( IsAutoPos() && pCnt->IsTxtFrm() && + GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE)) ) + { + //Das Ankerattribut auf den neuen Cnt setzen. + SwFmtAnchor aAnch( pFmt->GetAnchor() ); + SwPosition *pPos = (SwPosition*)aAnch.GetCntntAnchor(); + if( IsAutoPos() && pCnt->IsTxtFrm() ) + { + SwCrsrMoveState eTmpState( MV_SETONLYTEXT ); + Point aPt( rNew ); + if( pCnt->GetCrsrOfst( pPos, aPt, &eTmpState ) + && pPos->nNode == *pCnt->GetNode() ) + { + ResetLastCharRectHeight(); + if( text::RelOrientation::CHAR == pFmt->GetVertOrient().GetRelationOrient() ) + nY = LONG_MAX; + if( text::RelOrientation::CHAR == pFmt->GetHoriOrient().GetRelationOrient() ) + nX = LONG_MAX; + } + else + { + pPos->nNode = *pCnt->GetNode(); + pPos->nContent.Assign( pCnt->GetNode(), 0 ); + } + } + else + { + pPos->nNode = *pCnt->GetNode(); + pPos->nContent.Assign( pCnt->GetNode(), 0 ); + } + + // handle change of anchor node: + // if count of the anchor frame also change, the fly frames have to be + // re-created. Thus, delete all fly frames except the <this> before the + // anchor attribute is change and re-create them afterwards. + { + SwHandleAnchorNodeChg aHandleAnchorNodeChg( *pFmt, aAnch, this ); + pFmt->GetDoc()->SetAttr( aAnch, *pFmt ); + } + } + // #i28701# - use new method <GetPageFrm()> + else if ( pTmpPage && pTmpPage != GetPageFrm() ) + GetPageFrm()->MoveFly( this, pTmpPage ); + + const Point aRelPos = bVert ? Point( -nY, nX ) : Point( nX, nY ); + + ChgRelPos( aRelPos ); + + GetFmt()->GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + + if ( pOldPage != FindPageFrm() ) + ::Notify_Background( GetVirtDrawObj(), pOldPage, aOld, PREP_FLY_LEAVE, + sal_False ); +} + +/** method to assure that anchored object is registered at the correct + page frame + + #i28701# + takes over functionality of deleted method <SwFlyAtCntFrm::AssertPage()> +*/ +void SwFlyAtCntFrm::RegisterAtCorrectPage() +{ + SwPageFrm* pPageFrm( 0L ); + if ( GetVertPosOrientFrm() ) + { + pPageFrm = const_cast<SwPageFrm*>(GetVertPosOrientFrm()->FindPageFrm()); + } + if ( pPageFrm && GetPageFrm() != pPageFrm ) + { + if ( GetPageFrm() ) + GetPageFrm()->MoveFly( this, pPageFrm ); + else + pPageFrm->AppendFlyToPage( this ); + } +} + +// #i26791# +//void SwFlyAtCntFrm::MakeFlyPos() +void SwFlyAtCntFrm::MakeObjPos() +{ + // if fly frame position is valid, nothing is to do. Thus, return + if ( bValidPos ) + { + return; + } + + // #i26791# - validate position flag here. + bValidPos = sal_True; + + // #i35911# - no calculation of new position, if + // anchored object is marked that it clears its environment and its + // environment is already cleared. + // before checking for cleared environment + // check, if member <mpVertPosOrientFrm> is set. + if ( GetVertPosOrientFrm() && + ClearedEnvironment() && HasClearedEnvironment() ) + { + return; + } + + // use new class to position object + objectpositioning::SwToCntntAnchoredObjectPosition + aObjPositioning( *GetVirtDrawObj() ); + aObjPositioning.CalcPosition(); + + SetVertPosOrientFrm ( aObjPositioning.GetVertPosOrientFrm() ); +} + +// #i28701# +bool SwFlyAtCntFrm::_InvalidationAllowed( const InvalidationType _nInvalid ) const +{ + bool bAllowed( SwFlyFreeFrm::_InvalidationAllowed( _nInvalid ) ); + + // forbiddance of base instance can't be over ruled. + if ( bAllowed ) + { + if ( _nInvalid == INVALID_POS || + _nInvalid == INVALID_ALL ) + { + bAllowed = InvalidationOfPosAllowed(); + } + } + + return bAllowed; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flyincnt.cxx b/sw/source/core/layout/flyincnt.cxx new file mode 100644 index 000000000000..3a84f4948758 --- /dev/null +++ b/sw/source/core/layout/flyincnt.cxx @@ -0,0 +1,338 @@ +/* -*- 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 "cntfrm.hxx" +#include "doc.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "frmfmt.hxx" +#include "hints.hxx" +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include "txtfrm.hxx" //fuer IsLocked() +#include "flyfrms.hxx" +// OD 2004-01-19 #110582# +#include <dflyobj.hxx> + +//aus FlyCnt.cxx +void DeepCalc( const SwFrm *pFrm ); + +/************************************************************************* +|* +|* SwFlyInCntFrm::SwFlyInCntFrm(), ~SwFlyInCntFrm() +|* +|*************************************************************************/ +SwFlyInCntFrm::SwFlyInCntFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) : + SwFlyFrm( pFmt, pSib, pAnch ) +{ + bInCnt = bInvalidLayout = bInvalidCntnt = sal_True; + SwTwips nRel = pFmt->GetVertOrient().GetPos(); + // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject> + Point aRelPos; + if( pAnch && pAnch->IsVertical() ) + aRelPos.X() = pAnch->IsReverse() ? nRel : -nRel; + else + aRelPos.Y() = nRel; + SetCurrRelPos( aRelPos ); +} + +SwFlyInCntFrm::~SwFlyInCntFrm() +{ + //und Tschuess. + if ( !GetFmt()->GetDoc()->IsInDtor() && GetAnchorFrm() ) + { + SwRect aTmp( GetObjRectWithSpaces() ); + SwFlyInCntFrm::NotifyBackground( FindPageFrm(), aTmp, PREP_FLY_LEAVE ); + } +} + +// --> OD 2004-06-29 #i28701# +TYPEINIT1(SwFlyInCntFrm,SwFlyFrm); +// <-- +/************************************************************************* +|* +|* SwFlyInCntFrm::SetRefPoint(), +|* +|*************************************************************************/ +void SwFlyInCntFrm::SetRefPoint( const Point& rPoint, + const Point& rRelAttr, + const Point& rRelPos ) +{ + // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject> + OSL_ENSURE( rPoint != aRef || rRelAttr != GetCurrRelPos(), "SetRefPoint: no change" ); + SwFlyNotify *pNotify = NULL; + // No notify at a locked fly frame, if a fly frame is locked, there's + // already a SwFlyNotify object on the stack (MakeAll). + if( !IsLocked() ) + pNotify = new SwFlyNotify( this ); + aRef = rPoint; + SetCurrRelPos( rRelAttr ); + SWRECTFN( GetAnchorFrm() ) + (Frm().*fnRect->fnSetPos)( rPoint + rRelPos ); + // --> OD 2006-08-25 #i68520# + InvalidateObjRectWithSpaces(); + // <-- + if( pNotify ) + { + InvalidatePage(); + bValidPos = sal_False; + bInvalid = sal_True; + Calc(); + delete pNotify; + } +} + +/************************************************************************* +|* +|* SwFlyInCntFrm::Modify() +|* +|*************************************************************************/ +void SwFlyInCntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + sal_Bool bCallPrepare = sal_False; + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + if( RES_ATTRSET_CHG == nWhich ) + { + if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()-> + GetItemState( RES_SURROUND, sal_False ) || + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()-> + GetItemState( RES_FRMMACRO, sal_False ) ) + { + SwAttrSetChg aOld( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNew( *(SwAttrSetChg*)pNew ); + + aOld.ClearItem( RES_SURROUND ); + aNew.ClearItem( RES_SURROUND ); + aOld.ClearItem( RES_FRMMACRO ); + aNew.ClearItem( RES_FRMMACRO ); + if( aNew.Count() ) + { + SwFlyFrm::Modify( &aOld, &aNew ); + bCallPrepare = sal_True; + } + } + else if( ((SwAttrSetChg*)pNew)->GetChgSet()->Count()) + { + SwFlyFrm::Modify( pOld, pNew ); + bCallPrepare = sal_True; + } + } + else if( nWhich != RES_SURROUND && RES_FRMMACRO != nWhich ) + { + SwFlyFrm::Modify( pOld, pNew ); + bCallPrepare = sal_True; + } + + if ( bCallPrepare && GetAnchorFrm() ) + AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, GetFmt() ); +} +/************************************************************************* +|* +|* SwFlyInCntFrm::Format() +|* +|* Beschreibung: Hier wird der Inhalt initial mit Formatiert. +|* +|*************************************************************************/ +void SwFlyInCntFrm::Format( const SwBorderAttrs *pAttrs ) +{ + if ( !Frm().Height() ) + { + Lock(); //nicht hintenherum den Anker formatieren. + SwCntntFrm *pCntnt = ContainsCntnt(); + while ( pCntnt ) + { pCntnt->Calc(); + pCntnt = pCntnt->GetNextCntntFrm(); + } + Unlock(); + } + SwFlyFrm::Format( pAttrs ); +} +/************************************************************************* +|* +|* SwFlyInCntFrm::MakeFlyPos() +|* +|* Beschreibung Im Unterschied zu anderen Frms wird hier nur die +|* die RelPos berechnet. Die absolute Position wird ausschliesslich +|* per SetAbsPos errechnet. +|* +|*************************************************************************/ +// OD 2004-03-23 #i26791# +//void SwFlyInCntFrm::MakeFlyPos() +void SwFlyInCntFrm::MakeObjPos() +{ + if ( !bValidPos ) + { + bValidPos = sal_True; + SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt(); + const SwFmtVertOrient &rVert = pFmt->GetVertOrient(); + //Und ggf. noch die aktuellen Werte im Format updaten, dabei darf + //zu diesem Zeitpunkt natuerlich kein Modify verschickt werden. + const bool bVert = GetAnchorFrm()->IsVertical(); + const bool bRev = GetAnchorFrm()->IsReverse(); + SwTwips nOld = rVert.GetPos(); + SwTwips nAct = bVert ? -GetCurrRelPos().X() : GetCurrRelPos().Y(); + if( bRev ) + nAct = -nAct; + if( nAct != nOld ) + { + SwFmtVertOrient aVert( rVert ); + aVert.SetPos( nAct ); + pFmt->LockModify(); + pFmt->SetFmtAttr( aVert ); + pFmt->UnlockModify(); + } + } +} + +// --> OD 2004-12-02 #115759# +void SwFlyInCntFrm::_ActionOnInvalidation( const InvalidationType _nInvalid ) +{ + if ( INVALID_POS == _nInvalid || INVALID_ALL == _nInvalid ) + AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, &GetFrmFmt() ); +} +// <-- +/************************************************************************* +|* +|* SwFlyInCntFrm::NotifyBackground() +|* +|*************************************************************************/ +void SwFlyInCntFrm::NotifyBackground( SwPageFrm *, const SwRect& rRect, + PrepareHint eHint) +{ + if ( eHint == PREP_FLY_ATTR_CHG ) + AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG ); + else + AnchorFrm()->Prepare( eHint, (void*)&rRect ); +} + +/************************************************************************* +|* +|* SwFlyInCntFrm::GetRelPos() +|* +|*************************************************************************/ +const Point SwFlyInCntFrm::GetRelPos() const +{ + Calc(); + return GetCurrRelPos(); +} + +/************************************************************************* +|* +|* SwFlyInCntFrm::RegistFlys() +|* +|*************************************************************************/ +void SwFlyInCntFrm::RegistFlys() +{ + // vgl. SwRowFrm::RegistFlys() + SwPageFrm *pPage = FindPageFrm(); + OSL_ENSURE( pPage, "Flys ohne Seite anmelden?" ); + ::RegistFlys( pPage, this ); +} + +/************************************************************************* +|* +|* SwFlyInCntFrm::MakeAll() +|* +|*************************************************************************/ +void SwFlyInCntFrm::MakeAll() +{ + // OD 2004-01-19 #110582# + if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ) + { + return; + } + + if ( !GetAnchorFrm() || IsLocked() || IsColLocked() || !FindPageFrm() ) + return; + + Lock(); //Der Vorhang faellt + + //uebernimmt im DTor die Benachrichtigung + const SwFlyNotify aNotify( this ); + SwBorderAttrAccess aAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + if ( IsClipped() ) + bValidSize = bHeightClipped = bWidthClipped = sal_False; + + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + //Nur einstellen wenn das Flag gesetzt ist!! + if ( !bValidSize ) + { + bValidPrtArea = sal_False; +/* + // This is also done in the Format function, so I think + // this code is not necessary anymore: + long nOldWidth = aFrm.Width(); + const Size aRelSize( CalcRel( rFrmSz ) ); + aFrm.Width( aRelSize.Width() ); + + if ( aFrm.Width() > nOldWidth ) + //Damit sich der Inhalt anpasst + aFrm.Height( aRelSize.Height() ); +*/ + } + + if ( !bValidPrtArea ) + MakePrtArea( rAttrs ); + + if ( !bValidSize ) + Format( &rAttrs ); + + if ( !bValidPos ) + { + // OD 2004-03-23 #i26791# + //MakeFlyPos(); + MakeObjPos(); + } + + // --> OD 2006-04-13 #b6402800# + // re-activate clipping of as-character anchored Writer fly frames + // depending on compatibility option <ClipAsCharacterAnchoredWriterFlyFrames> + if ( bValidPos && bValidSize && + GetFmt()->getIDocumentSettingAccess()->get( IDocumentSettingAccess::CLIP_AS_CHARACTER_ANCHORED_WRITER_FLY_FRAME ) ) + { + SwFrm* pFrm = AnchorFrm(); + if ( Frm().Left() == (pFrm->Frm().Left()+pFrm->Prt().Left()) && + Frm().Width() > pFrm->Prt().Width() ) + { + Frm().Width( pFrm->Prt().Width() ); + bValidPrtArea = sal_False; + bWidthClipped = sal_True; + } + } + // <-- + } + Unlock(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx new file mode 100644 index 000000000000..170779683097 --- /dev/null +++ b/sw/source/core/layout/flylay.cxx @@ -0,0 +1,1319 @@ +/* -*- 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 "doc.hxx" +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "dview.hxx" +#include "dflyobj.hxx" +#include "dcontact.hxx" +#include "flyfrm.hxx" +#include "ftnfrm.hxx" +#include "frmtool.hxx" +#include "frmfmt.hxx" +#include "hints.hxx" +#include "pam.hxx" +#include "sectfrm.hxx" + + +#include <svx/svdpage.hxx> +#include <editeng/ulspitem.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include "ndole.hxx" +#include "tabfrm.hxx" +#include "flyfrms.hxx" +// #i18732# +#include <fmtfollowtextflow.hxx> +#include <environmentofanchoredobject.hxx> +// #i28701# +#include <sortedobjs.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> + + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwFlyFreeFrm::SwFlyFreeFrm(), ~SwFlyFreeFrm() +|* +|*************************************************************************/ + +SwFlyFreeFrm::SwFlyFreeFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) : + SwFlyFrm( pFmt, pSib, pAnch ), + pPage( 0 ), + // #i34753# + mbNoMakePos( false ), + // #i37068# + mbNoMoveOnCheckClip( false ) +{ +} + +SwFlyFreeFrm::~SwFlyFreeFrm() +{ + //und Tschuess. + // #i28701# - use new method <GetPageFrm()> + if( GetPageFrm() ) + { + if( GetFmt()->GetDoc()->IsInDtor() ) + { + // #i29879# - remove also to-frame anchored Writer + // fly frame from page. + const bool bRemoveFromPage = + GetPageFrm()->GetSortedObjs() && + ( IsFlyAtCntFrm() || + ( GetAnchorFrm() && GetAnchorFrm()->IsFlyFrm() ) ); + if ( bRemoveFromPage ) + { + GetPageFrm()->GetSortedObjs()->Remove( *this ); + } + } + else + { + SwRect aTmp( GetObjRectWithSpaces() ); + SwFlyFreeFrm::NotifyBackground( GetPageFrm(), aTmp, PREP_FLY_LEAVE ); + } + } +} + +// #i28701# +TYPEINIT1(SwFlyFreeFrm,SwFlyFrm); +/************************************************************************* +|* +|* SwFlyFreeFrm::NotifyBackground() +|* +|* Beschreibung Benachrichtigt den Hintergrund (alle CntntFrms die +|* gerade ueberlappt werden. Ausserdem wird das Window in einigen +|* Faellen direkt invalidiert (vor allem dort, wo keine CntntFrms +|* ueberlappt werden. +|* Es werden auch die CntntFrms innerhalb von anderen Flys +|* beruecksichtigt. +|* +|*************************************************************************/ + +void SwFlyFreeFrm::NotifyBackground( SwPageFrm *pPageFrm, + const SwRect& rRect, PrepareHint eHint ) +{ + ::Notify_Background( GetVirtDrawObj(), pPageFrm, rRect, eHint, sal_True ); +} + +/************************************************************************* +|* +|* SwFlyFreeFrm::MakeAll() +|* +|*************************************************************************/ + +void SwFlyFreeFrm::MakeAll() +{ + if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ) + { + return; + } + + if ( !GetAnchorFrm() || IsLocked() || IsColLocked() ) + return; + // #i28701# - use new method <GetPageFrm()> + if( !GetPageFrm() && GetAnchorFrm() && GetAnchorFrm()->IsInFly() ) + { + SwFlyFrm* pFly = AnchorFrm()->FindFlyFrm(); + SwPageFrm *pPageFrm = pFly ? pFly->FindPageFrm() : NULL; + if( pPageFrm ) + pPageFrm->AppendFlyToPage( this ); + } + if( !GetPageFrm() ) + return; + + Lock(); //Der Vorhang faellt + + //uebernimmt im DTor die Benachrichtigung + const SwFlyNotify aNotify( this ); + + if ( IsClipped() ) + { + bValidSize = bHeightClipped = bWidthClipped = sal_False; + // no invalidation of position, + // if anchored object is anchored inside a Writer fly frame, + // its position is already locked, and it follows the text flow. + // #i34753# - add condition: + // no invalidation of position, if no direct move is requested in <CheckClip(..)> + if ( !IsNoMoveOnCheckClip() && + !( PositionLocked() && + GetAnchorFrm()->IsInFly() && + GetFrmFmt().GetFollowTextFlow().GetValue() ) ) + { + bValidPos = sal_False; + } + } + + // #i81146# new loop control + sal_uInt16 nLoopControlRuns = 0; + const sal_uInt16 nLoopControlMax = 10; + + while ( !bValidPos || !bValidSize || !bValidPrtArea || bFormatHeightOnly ) + { + SWRECTFN( this ) + const SwFmtFrmSize *pSz; + { //Zusaetzlicher Scope, damit aAccess vor dem Check zerstoert wird! + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + pSz = &rAttrs.GetAttrSet().GetFrmSize(); + + //Nur einstellen wenn das Flag gesetzt ist!! + if ( !bValidSize ) + { + bValidPrtArea = sal_False; + } + + if ( !bValidPrtArea ) + MakePrtArea( rAttrs ); + + if ( !bValidSize || bFormatHeightOnly ) + { + bValidSize = sal_False; + Format( &rAttrs ); + bFormatHeightOnly = sal_False; + } + + if ( !bValidPos ) + { + const Point aOldPos( (Frm().*fnRect->fnGetPos)() ); + // #i26791# - use new method <MakeObjPos()> + // #i34753# - no positioning, if requested. + if ( IsNoMakePos() ) + bValidPos = sal_True; + else + // #i26791# - use new method <MakeObjPos()> + MakeObjPos(); + if( aOldPos == (Frm().*fnRect->fnGetPos)() ) + { + if( !bValidPos && GetAnchorFrm()->IsInSct() && + !GetAnchorFrm()->FindSctFrm()->IsValid() ) + bValidPos = sal_True; + } + else + bValidSize = sal_False; + } + } + + if ( bValidPos && bValidSize ) + { + ++nLoopControlRuns; + +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrm::MakeAll" ); +#endif + + if ( nLoopControlRuns < nLoopControlMax ) + CheckClip( *pSz ); + } + else + nLoopControlRuns = 0; + } + Unlock(); + +#if OSL_DEBUG_LEVEL > 1 + SWRECTFN( this ) + OSL_ENSURE( bHeightClipped || ( (Frm().*fnRect->fnGetHeight)() > 0 && + (Prt().*fnRect->fnGetHeight)() > 0), + "SwFlyFreeFrm::Format(), flipping Fly." ); + +#endif +} + +/** determines, if direct environment of fly frame has 'auto' size + + #i17297# + start with anchor frame and search via <GetUpper()> for a header, footer, + row or fly frame stopping at page frame. + return <true>, if such a frame is found and it has 'auto' size. + otherwise <false> is returned. + + @return boolean indicating, that direct environment has 'auto' size +*/ +bool SwFlyFreeFrm::HasEnvironmentAutoSize() const +{ + bool bRetVal = false; + + const SwFrm* pToBeCheckedFrm = GetAnchorFrm(); + while ( pToBeCheckedFrm && + !pToBeCheckedFrm->IsPageFrm() ) + { + if ( pToBeCheckedFrm->IsHeaderFrm() || + pToBeCheckedFrm->IsFooterFrm() || + pToBeCheckedFrm->IsRowFrm() || + pToBeCheckedFrm->IsFlyFrm() ) + { + bRetVal = ATT_FIX_SIZE != + pToBeCheckedFrm->GetAttrSet()->GetFrmSize().GetHeightSizeType(); + break; + } + else + { + pToBeCheckedFrm = pToBeCheckedFrm->GetUpper(); + } + } + + return bRetVal; +} + +/************************************************************************* +|* +|* SwFlyFreeFrm::CheckClip() +|* +|*************************************************************************/ + +void SwFlyFreeFrm::CheckClip( const SwFmtFrmSize &rSz ) +{ + //Jetzt ist es ggf. an der Zeit geignete Massnahmen zu ergreifen wenn + //der Fly nicht in seine Umgebung passt. + //Zuerst gibt der Fly seine Position auf. Danach wird er zunaechst + //formatiert. Erst wenn er auch durch die Aufgabe der Position nicht + //passt wird die Breite oder Hoehe aufgegeben - der Rahmen wird soweit + //wie notwendig zusammengequetscht. + + const SwVirtFlyDrawObj *pObj = GetVirtDrawObj(); + SwRect aClip, aTmpStretch; + ::CalcClipRect( pObj, aClip, sal_True ); + ::CalcClipRect( pObj, aTmpStretch, sal_False ); + aClip._Intersection( aTmpStretch ); + + const long nBot = Frm().Top() + Frm().Height(); + const long nRig = Frm().Left() + Frm().Width(); + const long nClipBot = aClip.Top() + aClip.Height(); + const long nClipRig = aClip.Left() + aClip.Width(); + + const sal_Bool bBot = nBot > nClipBot; + const sal_Bool bRig = nRig > nClipRig; + if ( bBot || bRig ) + { + sal_Bool bAgain = sal_False; + // #i37068# - no move, if it's requested + if ( bBot && !IsNoMoveOnCheckClip() && + !GetDrawObjs() && !GetAnchorFrm()->IsInTab() ) + { + SwFrm* pHeader = FindFooterOrHeader(); + // In a header, correction of the position is no good idea. + // If the fly moves, some paragraphs has to be formatted, this + // could cause a change of the height of the headerframe, + // now the flyframe can change its position and so on ... + if ( !pHeader || !pHeader->IsHeaderFrm() ) + { + const long nOld = Frm().Top(); + Frm().Pos().Y() = Max( aClip.Top(), nClipBot - Frm().Height() ); + if ( Frm().Top() != nOld ) + bAgain = sal_True; + bHeightClipped = sal_True; + } + } + if ( bRig ) + { + const long nOld = Frm().Left(); + Frm().Pos().X() = Max( aClip.Left(), nClipRig - Frm().Width() ); + if ( Frm().Left() != nOld ) + { + const SwFmtHoriOrient &rH = GetFmt()->GetHoriOrient(); + // Links ausgerichtete duerfen nicht nach links verschoben werden, + // wenn sie einem anderen ausweichen. + if( rH.GetHoriOrient() == text::HoriOrientation::LEFT ) + Frm().Pos().X() = nOld; + else + bAgain = sal_True; + } + bWidthClipped = sal_True; + } + if ( bAgain ) + bValidSize = sal_False; + else + { + //Wenn wir hier ankommen ragt der Frm in unerlaubte Bereiche + //hinein, und eine Positionskorrektur ist nicht erlaubt bzw. + //moeglich oder noetig. + + //Fuer Flys mit OLE-Objekten als Lower sorgen wir dafuer, dass + //immer proportional Resized wird. + Size aOldSize( Frm().SSize() ); + + //Zuerst wird das FrmRect eingestellt, und dann auf den Frm + //uebertragen. + SwRect aFrmRect( Frm() ); + + if ( bBot ) + { + long nDiff = nClipBot; + nDiff -= aFrmRect.Top(); //nDiff ist die verfuegbare Strecke. + nDiff = aFrmRect.Height() - nDiff; + aFrmRect.Height( aFrmRect.Height() - nDiff ); + bHeightClipped = sal_True; + } + if ( bRig ) + { + long nDiff = nClipRig; + nDiff -= aFrmRect.Left();//nDiff ist die verfuegbare Strecke. + nDiff = aFrmRect.Width() - nDiff; + aFrmRect.Width( aFrmRect.Width() - nDiff ); + bWidthClipped = sal_True; + } + + // #i17297# - no proportional + // scaling of graphics in environments, which determines its size + // by its content ('auto' size). Otherwise layout loops can occur and + // layout sizes of the environment can be incorrect. + // Such environment are: + // (1) header and footer frames with 'auto' size + // (2) table row frames with 'auto' size + // (3) fly frames with 'auto' size + // Note: section frames seems to be not critical - didn't found + // any critical layout situation so far. + if ( Lower() && Lower()->IsNoTxtFrm() && + ( static_cast<SwCntntFrm*>(Lower())->GetNode()->GetOLENode() || + !HasEnvironmentAutoSize() ) ) + { + //Wenn Breite und Hoehe angepasst wurden, so ist die + //groessere Veraenderung massgeblich. + if ( aFrmRect.Width() != aOldSize.Width() && + aFrmRect.Height()!= aOldSize.Height() ) + { + if ( (aOldSize.Width() - aFrmRect.Width()) > + (aOldSize.Height()- aFrmRect.Height()) ) + aFrmRect.Height( aOldSize.Height() ); + else + aFrmRect.Width( aOldSize.Width() ); + } + + //Breite angepasst? - Hoehe dann proportional verkleinern + if( aFrmRect.Width() != aOldSize.Width() ) + { + aFrmRect.Height( aFrmRect.Width() * aOldSize.Height() / + aOldSize.Width() ); + bHeightClipped = sal_True; + } + //Hoehe angepasst? - Breite dann proportional verkleinern + else if( aFrmRect.Height() != aOldSize.Height() ) + { + aFrmRect.Width( aFrmRect.Height() * aOldSize.Width() / + aOldSize.Height() ); + bWidthClipped = sal_True; + } + + // #i17297# - reactivate change + // of size attribute for fly frames containing an ole object. + + // Added the aFrmRect.HasArea() hack, because + // the environment of the ole object does not have to be valid + // at this moment, or even worse, it does not have to have a + // resonable size. In this case we do not want to change to + // attributes permanentely. Maybe one day somebody dares to remove + // this code. + if ( aFrmRect.HasArea() && + static_cast<SwCntntFrm*>(Lower())->GetNode()->GetOLENode() && + ( bWidthClipped || bHeightClipped ) ) + { + SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt(); + pFmt->LockModify(); + SwFmtFrmSize aFrmSize( rSz ); + aFrmSize.SetWidth( aFrmRect.Width() ); + aFrmSize.SetHeight( aFrmRect.Height() ); + pFmt->SetFmtAttr( aFrmSize ); + pFmt->UnlockModify(); + } + } + + //Jetzt die Einstellungen am Frm vornehmen, bei Spalten werden + //die neuen Werte in die Attribute eingetragen, weil es sonst + //ziemlich fiese Oszillationen gibt. + const long nPrtHeightDiff = Frm().Height() - Prt().Height(); + const long nPrtWidthDiff = Frm().Width() - Prt().Width(); + Frm().Height( aFrmRect.Height() ); + Frm().Width ( Max( long(MINLAY), aFrmRect.Width() ) ); + if ( Lower() && Lower()->IsColumnFrm() ) + { + ColLock(); //Grow/Shrink locken. + const Size aTmpOldSize( Prt().SSize() ); + Prt().Height( Frm().Height() - nPrtHeightDiff ); + Prt().Width ( Frm().Width() - nPrtWidthDiff ); + ChgLowersProp( aTmpOldSize ); + SwFrm *pLow = Lower(); + do + { pLow->Calc(); + // auch den (Column)BodyFrm mitkalkulieren + ((SwLayoutFrm*)pLow)->Lower()->Calc(); + pLow = pLow->GetNext(); + } while ( pLow ); + ::CalcCntnt( this ); + ColUnlock(); + if ( !bValidSize && !bWidthClipped ) + bFormatHeightOnly = bValidSize = sal_True; + } + else + { + Prt().Height( Frm().Height() - nPrtHeightDiff ); + Prt().Width ( Frm().Width() - nPrtWidthDiff ); + } + } + } + + // #i26945# + OSL_ENSURE( Frm().Height() >= 0, + "<SwFlyFreeFrm::CheckClip(..)> - fly frame has negative height now." ); +} + +/** method to determine, if a <MakeAll()> on the Writer fly frame is possible + #i43771# +*/ +bool SwFlyFreeFrm::IsFormatPossible() const +{ + return SwFlyFrm::IsFormatPossible() && + ( GetPageFrm() || + ( GetAnchorFrm() && GetAnchorFrm()->IsInFly() ) ); +} + +/************************************************************************* +|* +|* SwFlyLayFrm::SwFlyLayFrm() +|* +|*************************************************************************/ + +SwFlyLayFrm::SwFlyLayFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) : + SwFlyFreeFrm( pFmt, pSib, pAnch ) +{ + bLayout = sal_True; +} + +// #i28701# +TYPEINIT1(SwFlyLayFrm,SwFlyFreeFrm); +/************************************************************************* +|* +|* SwFlyLayFrm::Modify() +|* +|*************************************************************************/ + +void SwFlyLayFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + sal_uInt16 nWhich = pNew ? pNew->Which() : 0; + + SwFmtAnchor *pAnch = 0; + if( RES_ATTRSET_CHG == nWhich && SFX_ITEM_SET == + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_ANCHOR, sal_False, + (const SfxPoolItem**)&pAnch )) + ; // Beim GetItemState wird der AnkerPointer gesetzt ! + + else if( RES_ANCHOR == nWhich ) + { + //Ankerwechsel, ich haenge mich selbst um. + //Es darf sich nicht um einen Wechsel des Ankertyps handeln, + //dies ist nur ueber die SwFEShell moeglich. + pAnch = (SwFmtAnchor*)pNew; + } + + if( pAnch ) + { + OSL_ENSURE( pAnch->GetAnchorId() == + GetFmt()->GetAnchor().GetAnchorId(), + "8-) Unzulaessiger Wechsel des Ankertyps." ); + + //Abmelden, Seite besorgen, an den entsprechenden LayoutFrm + //haengen. + SwRect aOld( GetObjRectWithSpaces() ); + // #i28701# - use new method <GetPageFrm()> + SwPageFrm *pOldPage = GetPageFrm(); + AnchorFrm()->RemoveFly( this ); + + if ( FLY_AT_PAGE == pAnch->GetAnchorId() ) + { + sal_uInt16 nPgNum = pAnch->GetPageNum(); + SwRootFrm *pRoot = getRootFrm(); + SwPageFrm *pTmpPage = (SwPageFrm*)pRoot->Lower(); + for ( sal_uInt16 i = 1; (i <= nPgNum) && pTmpPage; ++i, + pTmpPage = (SwPageFrm*)pTmpPage->GetNext() ) + { + if ( i == nPgNum ) + { + // #i50432# - adjust synopsis of <PlaceFly(..)> + pTmpPage->PlaceFly( this, 0 ); + } + } + if( !pTmpPage ) + { + pRoot->SetAssertFlyPages(); + pRoot->AssertFlyPages(); + } + } + else + { + SwNodeIndex aIdx( pAnch->GetCntntAnchor()->nNode ); + SwCntntFrm *pCntnt = GetFmt()->GetDoc()->GetNodes().GoNext( &aIdx )-> + GetCntntNode()->getLayoutFrm( getRootFrm(), 0, 0, sal_False ); + if( pCntnt ) + { + SwFlyFrm *pTmp = pCntnt->FindFlyFrm(); + if( pTmp ) + pTmp->AppendFly( this ); + } + } + // #i28701# - use new method <GetPageFrm()> + if ( pOldPage && pOldPage != GetPageFrm() ) + NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE ); + SetCompletePaint(); + InvalidateAll(); + SetNotifyBack(); + } + else + SwFlyFrm::Modify( pOld, pNew ); +} + +/************************************************************************* +|* +|* SwPageFrm::AppendFly() +|* +|*************************************************************************/ + +void SwPageFrm::AppendFlyToPage( SwFlyFrm *pNew ) +{ + if ( !pNew->GetVirtDrawObj()->IsInserted() ) + getRootFrm()->GetDrawPage()->InsertObject( + (SdrObject*)pNew->GetVirtDrawObj(), + pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() ); + + InvalidateSpelling(); + InvalidateSmartTags(); // SMARTTAGS + InvalidateAutoCompleteWords(); + InvalidateWordCount(); + + if ( GetUpper() ) + { + ((SwRootFrm*)GetUpper())->SetIdleFlags(); + ((SwRootFrm*)GetUpper())->InvalidateBrowseWidth(); + } + + SdrObject* pObj = pNew->GetVirtDrawObj(); + OSL_ENSURE( pNew->GetAnchorFrm(), "Fly without Anchor" ); + const SwFlyFrm* pFly = pNew->GetAnchorFrm()->FindFlyFrm(); + if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() ) + { + sal_uInt32 nNewNum = pFly->GetVirtDrawObj()->GetOrdNumDirect(); + if ( pObj->GetPage() ) + pObj->GetPage()->SetObjectOrdNum( pObj->GetOrdNumDirect(), nNewNum); + else + pObj->SetOrdNum( nNewNum ); + } + + //Flys die im Cntnt sitzen beachten wir nicht weiter. + if ( pNew->IsFlyInCntFrm() ) + InvalidateFlyInCnt(); + else + { + InvalidateFlyCntnt(); + + if ( !pSortedObjs ) + pSortedObjs = new SwSortedObjs(); + +#if OSL_DEBUG_LEVEL > 1 + const bool bSucessInserted = +#endif + pSortedObjs->Insert( *pNew ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( bSucessInserted, "Fly nicht in Sorted eingetragen." ); + (void) bSucessInserted; +#endif + + // #i87493# + OSL_ENSURE( pNew->GetPageFrm() == 0 || pNew->GetPageFrm() == this, + "<SwPageFrm::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect -> please inform OD." ); + // #i28701# - use new method <SetPageFrm(..)> + pNew->SetPageFrm( this ); + pNew->InvalidatePage( this ); + // #i28701# + pNew->UnlockPosition(); + + // Notify accessible layout. That's required at this place for + // frames only where the anchor is moved. Creation of new frames + // is additionally handled by the SwFrmNotify class. + if( GetUpper() && + static_cast< SwRootFrm * >( GetUpper() )->IsAnyShellAccessible() && + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell() ) + { + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell()->Imp() + ->AddAccessibleFrm( pNew ); + } + } + + // #i28701# - correction: consider also drawing objects + if ( pNew->GetDrawObjs() ) + { + SwSortedObjs &rObjs = *pNew->GetDrawObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pTmpObj = rObjs[i]; + if ( pTmpObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pTmpFly = static_cast<SwFlyFrm*>(pTmpObj); + // #i28701# - use new method <GetPageFrm()> + if ( pTmpFly->IsFlyFreeFrm() && !pTmpFly->GetPageFrm() ) + AppendFlyToPage( pTmpFly ); + } + else if ( pTmpObj->ISA(SwAnchoredDrawObject) ) + { + // #i87493# + if ( pTmpObj->GetPageFrm() != this ) + { + if ( pTmpObj->GetPageFrm() != 0 ) + { + pTmpObj->GetPageFrm()->RemoveDrawObjFromPage( *pTmpObj ); + } + AppendDrawObjToPage( *pTmpObj ); + } + } + } + } +} + +/************************************************************************* +|* +|* SwPageFrm::RemoveFly() +|* +|*************************************************************************/ + +void SwPageFrm::RemoveFlyFromPage( SwFlyFrm *pToRemove ) +{ + const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum(); + getRootFrm()->GetDrawPage()->RemoveObject( nOrdNum ); + pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum ); + + if ( GetUpper() ) + { + if ( !pToRemove->IsFlyInCntFrm() ) + ((SwRootFrm*)GetUpper())->SetSuperfluous(); + ((SwRootFrm*)GetUpper())->InvalidateBrowseWidth(); + } + + //Flys die im Cntnt sitzen beachten wir nicht weiter. + if ( pToRemove->IsFlyInCntFrm() ) + return; + + // Notify accessible layout. That's required at this place for + // frames only where the anchor is moved. Creation of new frames + // is additionally handled by the SwFrmNotify class. + if( GetUpper() && + static_cast< SwRootFrm * >( GetUpper() )->IsAnyShellAccessible() && + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell() ) + { + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell()->Imp() + ->DisposeAccessibleFrm( pToRemove, sal_True ); + } + + //Collections noch nicht loeschen. Das passiert am Ende + //der Action im RemoveSuperfluous der Seite - angestossen von gleich- + //namiger Methode der Root. + //Die FlyColl kann bereits weg sein, weil der DTor der Seite + //gerade 'laeuft' + if ( pSortedObjs ) + { + pSortedObjs->Remove( *pToRemove ); + if ( !pSortedObjs->Count() ) + { DELETEZ( pSortedObjs ); + } + } + // #i28701# - use new method <SetPageFrm(..)> + pToRemove->SetPageFrm( 0L ); +} + +/************************************************************************* +|* +|* SwPageFrm::MoveFly +|* +|*************************************************************************/ + +void SwPageFrm::MoveFly( SwFlyFrm *pToMove, SwPageFrm *pDest ) +{ + //Invalidierungen + if ( GetUpper() ) + { + ((SwRootFrm*)GetUpper())->SetIdleFlags(); + if ( !pToMove->IsFlyInCntFrm() && pDest->GetPhyPageNum() < GetPhyPageNum() ) + ((SwRootFrm*)GetUpper())->SetSuperfluous(); + } + + pDest->InvalidateSpelling(); + pDest->InvalidateSmartTags(); // SMARTTAGS + pDest->InvalidateAutoCompleteWords(); + pDest->InvalidateWordCount(); + + if ( pToMove->IsFlyInCntFrm() ) + { + pDest->InvalidateFlyInCnt(); + return; + } + + // Notify accessible layout. That's required at this place for + // frames only where the anchor is moved. Creation of new frames + // is additionally handled by the SwFrmNotify class. + if( GetUpper() && + static_cast< SwRootFrm * >( GetUpper() )->IsAnyShellAccessible() && + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell() ) + { + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell()->Imp() + ->DisposeAccessibleFrm( pToMove, sal_True ); + } + + //Die FlyColl kann bereits weg sein, weil der DTor der Seite + //gerade 'laeuft' + if ( pSortedObjs ) + { + pSortedObjs->Remove( *pToMove ); + if ( !pSortedObjs->Count() ) + { DELETEZ( pSortedObjs ); + } + } + + //Anmelden + if ( !pDest->GetSortedObjs() ) + pDest->pSortedObjs = new SwSortedObjs(); + +#if OSL_DEBUG_LEVEL > 1 + const bool bSucessInserted = +#endif + pDest->GetSortedObjs()->Insert( *pToMove ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( bSucessInserted, "Fly nicht in Sorted eingetragen." ); + (void) bSucessInserted; +#endif + + // #i28701# - use new method <SetPageFrm(..)> + pToMove->SetPageFrm( pDest ); + pToMove->InvalidatePage( pDest ); + pToMove->SetNotifyBack(); + pDest->InvalidateFlyCntnt(); + // #i28701# + pToMove->UnlockPosition(); + + // Notify accessible layout. That's required at this place for + // frames only where the anchor is moved. Creation of new frames + // is additionally handled by the SwFrmNotify class. + if( GetUpper() && + static_cast< SwRootFrm * >( GetUpper() )->IsAnyShellAccessible() && + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell() ) + { + static_cast< SwRootFrm * >( GetUpper() )->GetCurrShell()->Imp() + ->AddAccessibleFrm( pToMove ); + } + + // #i28701# - correction: move lowers of Writer fly frame + if ( pToMove->GetDrawObjs() ) + { + SwSortedObjs &rObjs = *pToMove->GetDrawObjs(); + for ( sal_uInt32 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pObj = rObjs[i]; + if ( pObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pObj); + if ( pFly->IsFlyFreeFrm() ) + { + // #i28701# - use new method <GetPageFrm()> + SwPageFrm* pPageFrm = pFly->GetPageFrm(); + if ( pPageFrm ) + pPageFrm->MoveFly( pFly, pDest ); + else + pDest->AppendFlyToPage( pFly ); + } + } + else if ( pObj->ISA(SwAnchoredDrawObject) ) + { + RemoveDrawObjFromPage( *pObj ); + pDest->AppendDrawObjToPage( *pObj ); + } + } + } +} + +/************************************************************************* +|* +|* SwPageFrm::AppendDrawObjToPage(), RemoveDrawObjFromPage() +|* +|* #i28701# - new methods +|* +|*************************************************************************/ +void SwPageFrm::AppendDrawObjToPage( SwAnchoredObject& _rNewObj ) +{ + if ( !_rNewObj.ISA(SwAnchoredDrawObject) ) + { + OSL_FAIL( "SwPageFrm::AppendDrawObjToPage(..) - anchored object of unexcepted type -> object not appended" ); + return; + } + + if ( GetUpper() ) + { + ((SwRootFrm*)GetUpper())->InvalidateBrowseWidth(); + } + + OSL_ENSURE( _rNewObj.GetAnchorFrm(), "anchored draw object without anchor" ); + const SwFlyFrm* pFlyFrm = _rNewObj.GetAnchorFrm()->FindFlyFrm(); + if ( pFlyFrm && + _rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrm->GetVirtDrawObj()->GetOrdNum() ) + { + sal_uInt32 nNewNum = pFlyFrm->GetVirtDrawObj()->GetOrdNumDirect(); + if ( _rNewObj.GetDrawObj()->GetPage() ) + _rNewObj.DrawObj()->GetPage()->SetObjectOrdNum( + _rNewObj.GetDrawObj()->GetOrdNumDirect(), nNewNum); + else + _rNewObj.DrawObj()->SetOrdNum( nNewNum ); + } + + if ( FLY_AS_CHAR == _rNewObj.GetFrmFmt().GetAnchor().GetAnchorId() ) + { + return; + } + + if ( !pSortedObjs ) + { + pSortedObjs = new SwSortedObjs(); + } + if ( !pSortedObjs->Insert( _rNewObj ) ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( pSortedObjs->Contains( _rNewObj ), + "Drawing object not appended into list <pSortedObjs>." ); +#endif + } + // #i87493# + OSL_ENSURE( _rNewObj.GetPageFrm() == 0 || _rNewObj.GetPageFrm() == this, + "<SwPageFrm::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect -> please inform OD." ); + _rNewObj.SetPageFrm( this ); + + // invalidate page in order to force a reformat of object layout of the page. + InvalidateFlyLayout(); +} + +void SwPageFrm::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj ) +{ + if ( !_rToRemoveObj.ISA(SwAnchoredDrawObject) ) + { + OSL_FAIL( "SwPageFrm::RemoveDrawObjFromPage(..) - anchored object of unexcepted type -> object not removed" ); + return; + } + + if ( pSortedObjs ) + { + pSortedObjs->Remove( _rToRemoveObj ); + if ( !pSortedObjs->Count() ) + { + DELETEZ( pSortedObjs ); + } + if ( GetUpper() ) + { + if (FLY_AS_CHAR != + _rToRemoveObj.GetFrmFmt().GetAnchor().GetAnchorId()) + { + ((SwRootFrm*)GetUpper())->SetSuperfluous(); + InvalidatePage(); + } + ((SwRootFrm*)GetUpper())->InvalidateBrowseWidth(); + } + } + _rToRemoveObj.SetPageFrm( 0 ); +} + +/************************************************************************* +|* +|* SwPageFrm::PlaceFly +|* +|*************************************************************************/ + +// #i50432# - adjust method description and synopsis. +void SwPageFrm::PlaceFly( SwFlyFrm* pFly, SwFlyFrmFmt* pFmt ) +{ + // #i50432# - consider the case that page is an empty page: + // In this case append the fly frame at the next page + OSL_ENSURE( !IsEmptyPage() || GetNext(), + "<SwPageFrm::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" ); + if ( IsEmptyPage() && GetNext() ) + { + static_cast<SwPageFrm*>(GetNext())->PlaceFly( pFly, pFmt ); + } + else + { + //Wenn ein Fly uebergeben wurde, so benutzen wir diesen, ansonsten wird + //mit dem Format einer erzeugt. + if ( pFly ) + AppendFly( pFly ); + else + { OSL_ENSURE( pFmt, ":-( kein Format fuer Fly uebergeben." ); + pFly = new SwFlyLayFrm( (SwFlyFrmFmt*)pFmt, this, this ); + AppendFly( pFly ); + ::RegistFlys( this, pFly ); + } + } +} + +/************************************************************************* +|* +|* ::CalcClipRect +|* +|*************************************************************************/ +// #i18732# - adjustments for following text flow or not +// AND alignment at 'page areas' for to paragraph/to character anchored objects +// #i22305# - adjustment for following text flow +// for to frame anchored objects +// #i29778# - Because the calculation of the position of the +// floating screen object (Writer fly frame or drawing object) doesn't perform +// a calculation on its upper frames and its anchor frame, a calculation of +// the upper frames in this method no longer sensible. +// #i28701# - if document compatibility option 'Consider +// wrapping style influence on object positioning' is ON, the clip area +// corresponds to the one as the object doesn't follows the text flow. +sal_Bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, sal_Bool bMove ) +{ + sal_Bool bRet = sal_True; + if ( pSdrObj->ISA(SwVirtFlyDrawObj) ) + { + const SwFlyFrm* pFly = ((const SwVirtFlyDrawObj*)pSdrObj)->GetFlyFrm(); + const bool bFollowTextFlow = pFly->GetFmt()->GetFollowTextFlow().GetValue(); + // #i28701# + const bool bConsiderWrapOnObjPos = + pFly->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION); + const SwFmtVertOrient &rV = pFly->GetFmt()->GetVertOrient(); + if( pFly->IsFlyLayFrm() ) + { + const SwFrm* pClip; + // #i22305# + // #i28701# + if ( !bFollowTextFlow || bConsiderWrapOnObjPos ) + { + pClip = pFly->GetAnchorFrm()->FindPageFrm(); + } + else + { + pClip = pFly->GetAnchorFrm(); + } + + rRect = pClip->Frm(); + SWRECTFN( pClip ) + + //Vertikales clipping: Top und Bottom, ggf. an PrtArea + if( rV.GetVertOrient() != text::VertOrientation::NONE && + rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) + { + (rRect.*fnRect->fnSetTop)( (pClip->*fnRect->fnGetPrtTop)() ); + (rRect.*fnRect->fnSetBottom)( (pClip->*fnRect->fnGetPrtBottom)() ); + } + //Horizontales clipping: Left und Right, ggf. an PrtArea + const SwFmtHoriOrient &rH = pFly->GetFmt()->GetHoriOrient(); + if( rH.GetHoriOrient() != text::HoriOrientation::NONE && + rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) + { + (rRect.*fnRect->fnSetLeft)( (pClip->*fnRect->fnGetPrtLeft)() ); + (rRect.*fnRect->fnSetRight)((pClip->*fnRect->fnGetPrtRight)()); + } + } + else if( pFly->IsFlyAtCntFrm() ) + { + // #i18732# - consider following text flow or not + // AND alignment at 'page areas' + const SwFrm* pVertPosOrientFrm = pFly->GetVertPosOrientFrm(); + if ( !pVertPosOrientFrm ) + { + OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing ."); + pVertPosOrientFrm = pFly->GetAnchorFrm(); + } + + if ( !bFollowTextFlow || bConsiderWrapOnObjPos ) + { + const SwLayoutFrm* pClipFrm = pVertPosOrientFrm->FindPageFrm(); + rRect = bMove ? pClipFrm->GetUpper()->Frm() + : pClipFrm->Frm(); + // #i26945# - consider that a table, during + // its format, can exceed its upper printing area bottom. + // Thus, enlarge the clip rectangle, if such a case occurred + if ( pFly->GetAnchorFrm()->IsInTab() ) + { + const SwTabFrm* pTabFrm = const_cast<SwFlyFrm*>(pFly) + ->GetAnchorFrmContainingAnchPos()->FindTabFrm(); + SwRect aTmp( pTabFrm->Prt() ); + aTmp += pTabFrm->Frm().Pos(); + rRect.Union( aTmp ); + // #i43913# - consider also the cell frame + const SwFrm* pCellFrm = const_cast<SwFlyFrm*>(pFly) + ->GetAnchorFrmContainingAnchPos()->GetUpper(); + while ( pCellFrm && !pCellFrm->IsCellFrm() ) + { + pCellFrm = pCellFrm->GetUpper(); + } + if ( pCellFrm ) + { + aTmp = pCellFrm->Prt(); + aTmp += pCellFrm->Frm().Pos(); + rRect.Union( aTmp ); + } + } + } + else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME || + rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) + { + // new class <SwEnvironmentOfAnchoredObject> + objectpositioning::SwEnvironmentOfAnchoredObject + aEnvOfObj( bFollowTextFlow ); + const SwLayoutFrm& rVertClipFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pVertPosOrientFrm ); + if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ) + { + rRect = rVertClipFrm.Frm(); + } + else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) + { + if ( rVertClipFrm.IsPageFrm() ) + { + rRect = static_cast<const SwPageFrm&>(rVertClipFrm).PrtWithoutHeaderAndFooter(); + } + else + { + rRect = rVertClipFrm.Frm(); + } + } + const SwLayoutFrm* pHoriClipFrm = + pFly->GetAnchorFrm()->FindPageFrm()->GetUpper(); + SWRECTFN( pFly->GetAnchorFrm() ) + (rRect.*fnRect->fnSetLeft)( (pHoriClipFrm->Frm().*fnRect->fnGetLeft)() ); + (rRect.*fnRect->fnSetRight)((pHoriClipFrm->Frm().*fnRect->fnGetRight)()); + } + else + { + // #i26945# + const SwFrm *pClip = + const_cast<SwFlyFrm*>(pFly)->GetAnchorFrmContainingAnchPos(); + SWRECTFN( pClip ) + const SwLayoutFrm *pUp = pClip->GetUpper(); + const SwFrm *pCell = pUp->IsCellFrm() ? pUp : 0; + sal_uInt16 nType = bMove ? FRM_ROOT | FRM_FLY | FRM_HEADER | + FRM_FOOTER | FRM_FTN + : FRM_BODY | FRM_FLY | FRM_HEADER | + FRM_FOOTER | FRM_CELL| FRM_FTN; + + while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrm() ) + { + pUp = pUp->GetUpper(); + if ( !pCell && pUp->IsCellFrm() ) + pCell = pUp; + } + if ( bMove ) + { + if ( pUp->IsRootFrm() ) + { + rRect = pUp->Prt(); + rRect += pUp->Frm().Pos(); + pUp = 0; + } + } + if ( pUp ) + { + if ( pUp->GetType() & FRM_BODY ) + { + const SwPageFrm *pPg; + if ( pUp->GetUpper() != (pPg = pFly->FindPageFrm()) ) + pUp = pPg->FindBodyCont(); + rRect = pUp->GetUpper()->Frm(); + (rRect.*fnRect->fnSetTop)( (pUp->*fnRect->fnGetPrtTop)() ); + (rRect.*fnRect->fnSetBottom)((pUp->*fnRect->fnGetPrtBottom)()); + } + else + { + if( ( pUp->GetType() & (FRM_FLY | FRM_FTN ) ) && + !pUp->Frm().IsInside( pFly->Frm().Pos() ) ) + { + if( pUp->IsFlyFrm() ) + { + SwFlyFrm *pTmpFly = (SwFlyFrm*)pUp; + while( pTmpFly->GetNextLink() ) + { + pTmpFly = pTmpFly->GetNextLink(); + if( pTmpFly->Frm().IsInside( pFly->Frm().Pos() ) ) + break; + } + pUp = pTmpFly; + } + else if( pUp->IsInFtn() ) + { + const SwFtnFrm *pTmp = pUp->FindFtnFrm(); + while( pTmp->GetFollow() ) + { + pTmp = pTmp->GetFollow(); + if( pTmp->Frm().IsInside( pFly->Frm().Pos() ) ) + break; + } + pUp = pTmp; + } + } + rRect = pUp->Prt(); + rRect.Pos() += pUp->Frm().Pos(); + if ( pUp->GetType() & (FRM_HEADER | FRM_FOOTER) ) + { + rRect.Left ( pUp->GetUpper()->Frm().Left() ); + rRect.Width( pUp->GetUpper()->Frm().Width()); + } + else if ( pUp->IsCellFrm() ) //MA_FLY_HEIGHT + { + const SwFrm *pTab = pUp->FindTabFrm(); + (rRect.*fnRect->fnSetBottom)( + (pTab->GetUpper()->*fnRect->fnGetPrtBottom)() ); + // expand to left and right cell border + rRect.Left ( pUp->Frm().Left() ); + rRect.Width( pUp->Frm().Width() ); + } + } + } + if ( pCell ) + { + //CellFrms koennen auch in 'unerlaubten' Bereichen stehen, dann + //darf der Fly das auch. + SwRect aTmp( pCell->Prt() ); + aTmp += pCell->Frm().Pos(); + rRect.Union( aTmp ); + } + } + } + else + { + const SwFrm *pUp = pFly->GetAnchorFrm()->GetUpper(); + SWRECTFN( pFly->GetAnchorFrm() ) + while( pUp->IsColumnFrm() || pUp->IsSctFrm() || pUp->IsColBodyFrm()) + pUp = pUp->GetUpper(); + rRect = pUp->Frm(); + if( !pUp->IsBodyFrm() ) + { + rRect += pUp->Prt().Pos(); + rRect.SSize( pUp->Prt().SSize() ); + if ( pUp->IsCellFrm() ) + { + const SwFrm *pTab = pUp->FindTabFrm(); + (rRect.*fnRect->fnSetBottom)( + (pTab->GetUpper()->*fnRect->fnGetPrtBottom)() ); + } + } + else if ( pUp->GetUpper()->IsPageFrm() ) + { + // Objects anchored as character may exceed right margin + // of body frame: + (rRect.*fnRect->fnSetRight)( (pUp->GetUpper()->Frm().*fnRect->fnGetRight)() ); + } + long nHeight = (9*(rRect.*fnRect->fnGetHeight)())/10; + long nTop; + const SwFmt *pFmt = ((SwContact*)GetUserCall(pSdrObj))->GetFmt(); + const SvxULSpaceItem &rUL = pFmt->GetULSpace(); + if( bMove ) + { + nTop = bVert ? ((SwFlyInCntFrm*)pFly)->GetRefPoint().X() : + ((SwFlyInCntFrm*)pFly)->GetRefPoint().Y(); + nTop = (*fnRect->fnYInc)( nTop, -nHeight ); + long nWidth = (pFly->Frm().*fnRect->fnGetWidth)(); + (rRect.*fnRect->fnSetLeftAndWidth)( bVert ? + ((SwFlyInCntFrm*)pFly)->GetRefPoint().Y() : + ((SwFlyInCntFrm*)pFly)->GetRefPoint().X(), nWidth ); + nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper(); + } + else + { + nTop = (*fnRect->fnYInc)( (pFly->Frm().*fnRect->fnGetBottom)(), + rUL.GetLower() - nHeight ); + nHeight = 2*nHeight - (pFly->Frm().*fnRect->fnGetHeight)() + - rUL.GetLower() - rUL.GetUpper(); + } + (rRect.*fnRect->fnSetTopAndHeight)( nTop, nHeight ); + } + } + else + { + const SwDrawContact *pC = (const SwDrawContact*)GetUserCall(pSdrObj); + const SwFrmFmt *pFmt = (const SwFrmFmt*)pC->GetFmt(); + const SwFmtAnchor &rAnch = pFmt->GetAnchor(); + if ( FLY_AS_CHAR == rAnch.GetAnchorId() ) + { + const SwFrm* pAnchorFrm = pC->GetAnchorFrm( pSdrObj ); + if( !pAnchorFrm ) + { + OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." ); + ((SwDrawContact*)pC)->ConnectToLayout(); + pAnchorFrm = pC->GetAnchorFrm(); + } + const SwFrm* pUp = pAnchorFrm->GetUpper(); + rRect = pUp->Prt(); + rRect += pUp->Frm().Pos(); + SWRECTFN( pAnchorFrm ) + long nHeight = (9*(rRect.*fnRect->fnGetHeight)())/10; + long nTop; + const SvxULSpaceItem &rUL = pFmt->GetULSpace(); + SwRect aSnapRect( pSdrObj->GetSnapRect() ); + long nTmpH = 0; + if( bMove ) + { + nTop = (*fnRect->fnYInc)( bVert ? pSdrObj->GetAnchorPos().X() : + pSdrObj->GetAnchorPos().Y(), -nHeight ); + long nWidth = (aSnapRect.*fnRect->fnGetWidth)(); + (rRect.*fnRect->fnSetLeftAndWidth)( bVert ? + pSdrObj->GetAnchorPos().Y() : + pSdrObj->GetAnchorPos().X(), nWidth ); + } + else + { + // #i26791# - value of <nTmpH> is needed to + // calculate value of <nTop>. + nTmpH = bVert ? pSdrObj->GetCurrentBoundRect().GetWidth() : + pSdrObj->GetCurrentBoundRect().GetHeight(); + nTop = (*fnRect->fnYInc)( (aSnapRect.*fnRect->fnGetTop)(), + rUL.GetLower() + nTmpH - nHeight ); + } + nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper(); + (rRect.*fnRect->fnSetTopAndHeight)( nTop, nHeight ); + } + else + { + // restrict clip rectangle for drawing + // objects in header/footer to the page frame. + // #i26791# + const SwFrm* pAnchorFrm = pC->GetAnchorFrm( pSdrObj ); + if ( pAnchorFrm && pAnchorFrm->FindFooterOrHeader() ) + { + // clip frame is the page frame the header/footer is on. + const SwFrm* pClipFrm = pAnchorFrm->FindPageFrm(); + rRect = pClipFrm->Frm(); + } + else + { + bRet = sal_False; + } + } + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/flypos.cxx b/sw/source/core/layout/flypos.cxx new file mode 100644 index 000000000000..2c9c4e1b20f4 --- /dev/null +++ b/sw/source/core/layout/flypos.cxx @@ -0,0 +1,114 @@ +/* -*- 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 "doc.hxx" +#include "node.hxx" +#include <docary.hxx> +#include <fmtanchr.hxx> +#include "flypos.hxx" +#include "frmfmt.hxx" +#include "dcontact.hxx" +#include "dview.hxx" +#include "flyfrm.hxx" +#include "dflyobj.hxx" +#include "ndindex.hxx" +#include "switerator.hxx" + +SV_IMPL_OP_PTRARR_SORT( SwPosFlyFrms, SwPosFlyFrmPtr ) + +SwPosFlyFrm::SwPosFlyFrm( const SwNodeIndex& rIdx, const SwFrmFmt* pFmt, + sal_uInt16 nArrPos ) + : pFrmFmt( pFmt ), pNdIdx( (SwNodeIndex*) &rIdx ) +{ + bool bFnd = false; + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + if (FLY_AT_PAGE == rAnchor.GetAnchorId()) + { + pNdIdx = new SwNodeIndex( rIdx ); + } + else if( pFmt->GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225 + { + if( RES_FLYFRMFMT == pFmt->Which() ) + { + // Schauen, ob es ein SdrObject dafuer gibt + SwFlyFrm* pFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement(*pFmt); + if( pFly ) + { + nOrdNum = pFly->GetVirtDrawObj()->GetOrdNum(); + bFnd = true; + } + } + else if( RES_DRAWFRMFMT == pFmt->Which() ) + { + // Schauen, ob es ein SdrObject dafuer gibt + SwDrawContact* pContact = SwIterator<SwDrawContact,SwFmt>::FirstElement(*pFmt); + if( pContact ) + { + nOrdNum = pContact->GetMaster()->GetOrdNum(); + bFnd = true; + } + } + } + + if( !bFnd ) + { + nOrdNum = pFmt->GetDoc()->GetSpzFrmFmts()->Count(); + nOrdNum += nArrPos; + } +} + +SwPosFlyFrm::~SwPosFlyFrm() +{ + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + if (FLY_AT_PAGE == rAnchor.GetAnchorId()) + { + delete pNdIdx; + } +} + +sal_Bool SwPosFlyFrm::operator==( const SwPosFlyFrm& ) +{ + return sal_False; // FlyFrames koennen auf der gleichen Position stehen +} + +sal_Bool SwPosFlyFrm::operator<( const SwPosFlyFrm& rPosFly ) +{ + if( pNdIdx->GetIndex() == rPosFly.pNdIdx->GetIndex() ) + { + // dann entscheidet die Ordnungsnummer! + return nOrdNum < rPosFly.nOrdNum; + } + return pNdIdx->GetIndex() < rPosFly.pNdIdx->GetIndex(); +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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: */ diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx new file mode 100644 index 000000000000..608ecb57ddd5 --- /dev/null +++ b/sw/source/core/layout/ftnfrm.cxx @@ -0,0 +1,3241 @@ +/* -*- 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 <txtftn.hxx> +#include <fmtftn.hxx> +#include <ftnidx.hxx> +#include <pagefrm.hxx> +#include <colfrm.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <doc.hxx> +#include <ndtxt.hxx> +#include <frmtool.hxx> +#include <swtable.hxx> +#include <ftnfrm.hxx> +#include <txtfrm.hxx> +#include <tabfrm.hxx> +#include <pagedesc.hxx> +#include <ftninfo.hxx> +#include <ndindex.hxx> +#include <sectfrm.hxx> +#include <pam.hxx> +#include <objectformatter.hxx> +#include "viewopt.hxx" +#include "viewsh.hxx" +#include <switerator.hxx> + +/************************************************************************* +|* +|* lcl_FindFtnPos() Sucht die Position des Attributes im FtnArray am +|* Dokument, dort stehen die Fussnoten gluecklicherweise nach ihrem +|* Index sortiert. +|* +|*************************************************************************/ + +#define ENDNOTE 0x80000000 + +sal_uLong MA_FASTCALL lcl_FindFtnPos( const SwDoc *pDoc, const SwTxtFtn *pAttr ) +{ + const SwFtnIdxs &rFtnIdxs = pDoc->GetFtnIdxs(); + + sal_uInt16 nRet; + SwTxtFtnPtr pBla = (SwTxtFtn*)pAttr; + if ( rFtnIdxs.Seek_Entry( pBla, &nRet ) ) + { + if( pAttr->GetFtn().IsEndNote() ) + return sal_uLong(nRet) + ENDNOTE; + return nRet; + } + OSL_ENSURE( !pDoc, "FtnPos not found." ); + return 0; +} + +sal_Bool SwFtnFrm::operator<( const SwTxtFtn* pTxtFtn ) const +{ + const SwDoc* pDoc = GetFmt()->GetDoc(); + OSL_ENSURE( pDoc, "SwFtnFrm: Missing doc!" ); + return lcl_FindFtnPos( pDoc, GetAttr() ) < + lcl_FindFtnPos( pDoc, pTxtFtn ); +} + +/************************************************************************* +|* +|* sal_Bool lcl_NextFtnBoss( SwFtnBossFrm* pBoss, SwPageFrm* pPage) +|* setzt pBoss auf den naechsten SwFtnBossFrm, das kann entweder eine Spalte +|* oder eine Seite (ohne Spalten) sein. Wenn die Seite dabei gewechselt wird +|* enthaelt pPage die neue Seite und die Funktion liefert sal_True. +|* +|*************************************************************************/ + +sal_Bool lcl_NextFtnBoss( SwFtnBossFrm* &rpBoss, SwPageFrm* &rpPage, + sal_Bool bDontLeave ) +{ + if( rpBoss->IsColumnFrm() ) + { + if( rpBoss->GetNext() ) + { + rpBoss = (SwFtnBossFrm*)rpBoss->GetNext(); //naechste Spalte + return sal_False; + } + if( rpBoss->IsInSct() ) + { + SwSectionFrm* pSct = rpBoss->FindSctFrm()->GetFollow(); + if( pSct ) + { + OSL_ENSURE( pSct->Lower() && pSct->Lower()->IsColumnFrm(), + "Where's the column?" ); + rpBoss = (SwColumnFrm*)pSct->Lower(); + SwPageFrm* pOld = rpPage; + rpPage = pSct->FindPageFrm(); + return pOld != rpPage; + } + else if( bDontLeave ) + { + rpPage = NULL; + rpBoss = NULL; + return sal_False; + } + } + } + rpPage = (SwPageFrm*)rpPage->GetNext(); // naechste Seite + rpBoss = rpPage; + if( rpPage ) + { + SwLayoutFrm* pBody = rpPage->FindBodyCont(); + if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + rpBoss = (SwFtnBossFrm*)pBody->Lower(); // erste Spalte + } + return sal_True; +} + +/************************************************************************* +|* +|* sal_uInt16 lcl_ColumnNum( SwFrm* pBoss ) +|* liefert die Spaltennummer, wenn pBoss eine Spalte ist, +|* sonst eine Null (bei Seiten). +|* +|*************************************************************************/ + +sal_uInt16 lcl_ColumnNum( const SwFrm* pBoss ) +{ + sal_uInt16 nRet = 0; + if( !pBoss->IsColumnFrm() ) + return 0; + const SwFrm* pCol; + if( pBoss->IsInSct() ) + { + pCol = pBoss->GetUpper()->FindColFrm(); + if( pBoss->GetNext() || pBoss->GetPrev() ) + { + while( pBoss ) + { + ++nRet; // Section columns + pBoss = pBoss->GetPrev(); + } + } + } + else + pCol = pBoss; + while( pCol ) + { + nRet += 256; // Page columns + pCol = pCol->GetPrev(); + } + return nRet; +} + +/************************************************************************* +|* +|* SwFtnContFrm::SwFtnContFrm() +|* +|*************************************************************************/ + + +SwFtnContFrm::SwFtnContFrm( SwFrmFmt *pFmt, SwFrm* pSib ): + SwLayoutFrm( pFmt, pSib ) +{ + nType = FRMC_FTNCONT; +} + + +// lcl_Undersize(..) klappert einen SwFrm und dessen Inneres ab +// und liefert die Summe aller TxtFrm-Vergroesserungswuensche + +long lcl_Undersize( const SwFrm* pFrm ) +{ + long nRet = 0; + SWRECTFN( pFrm ) + if( pFrm->IsTxtFrm() ) + { + if( ((SwTxtFrm*)pFrm)->IsUndersized() ) + { + // Dieser TxtFrm waere gern ein bisschen groesser + nRet = ((SwTxtFrm*)pFrm)->GetParHeight() - + (pFrm->Prt().*fnRect->fnGetHeight)(); + if( nRet < 0 ) + nRet = 0; + } + } + else if( pFrm->IsLayoutFrm() ) + { + const SwFrm* pNxt = ((SwLayoutFrm*)pFrm)->Lower(); + while( pNxt ) + { + nRet += lcl_Undersize( pNxt ); + pNxt = pNxt->GetNext(); + } + } + return nRet; +} + +/************************************************************************* +|* +|* SwFtnContFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; +|* Die Fixsize wird hier nicht eingestellt. +|* +|*************************************************************************/ + + +void SwFtnContFrm::Format( const SwBorderAttrs * ) +{ + //GesamtBorder ermitteln, es gibt nur einen Abstand nach oben. + const SwPageFrm* pPage = FindPageFrm(); + const SwPageFtnInfo &rInf = pPage->GetPageDesc()->GetFtnInfo(); + const SwTwips nBorder = rInf.GetTopDist() + rInf.GetBottomDist() + + rInf.GetLineWidth(); + SWRECTFN( this ) + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + (Prt().*fnRect->fnSetTop)( nBorder ); + (Prt().*fnRect->fnSetWidth)( (Frm().*fnRect->fnGetWidth)() ); + (Prt().*fnRect->fnSetHeight)((Frm().*fnRect->fnGetHeight)() - nBorder ); + if( (Prt().*fnRect->fnGetHeight)() < 0 && !pPage->IsFtnPage() ) + bValidSize = sal_False; + } + + if ( !bValidSize ) + { + bool bGrow = pPage->IsFtnPage(); + if( bGrow ) + { + const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + bGrow = false; + } + if( bGrow ) + Grow( LONG_MAX, sal_False ); + else + { + //Die Groesse in der VarSize wird durch den Inhalt plus den + //Raendern bestimmt. + SwTwips nRemaining = 0; + SwFrm *pFrm = pLower; + while ( pFrm ) + { // lcl_Undersize(..) beruecksichtigt (rekursiv) TxtFrms, die gerne + // groesser waeren. Diese entstehen insbesondere in spaltigen Rahmen, + // wenn diese noch nicht ihre maximale Groesse haben. + nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)() + + lcl_Undersize( pFrm ); + pFrm = pFrm->GetNext(); + } + //Jetzt noch den Rand addieren + nRemaining += nBorder; + + SwTwips nDiff; + if( IsInSct() ) + { + nDiff = -(Frm().*fnRect->fnBottomDist)( + (GetUpper()->*fnRect->fnGetPrtBottom)() ); + if( nDiff > 0 ) + { + if( nDiff > (Frm().*fnRect->fnGetHeight)() ) + nDiff = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnAddBottom)( -nDiff ); + (Prt().*fnRect->fnAddHeight)( -nDiff ); + } + } + nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining; + if ( nDiff > 0 ) + Shrink( nDiff ); + else if ( nDiff < 0 ) + { + Grow( -nDiff ); + //Es kann passieren, dass weniger Platz zur Verfuegung steht, + //als der bereits der Border benoetigt - die Groesse der + //PrtArea wird dann negativ. + SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + if( nPrtHeight < 0 ) + { + const SwTwips nTmpDiff = Max( (Prt().*fnRect->fnGetTop)(), + -nPrtHeight ); + (Prt().*fnRect->fnSubTop)( nTmpDiff ); + } + } + } + bValidSize = sal_True; + } +} +/************************************************************************* +|* +|* SwFtnContFrm::GrowFrm(), ShrinkFrm() +|* +|*************************************************************************/ + +SwTwips SwFtnContFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool ) +{ + //Keine Pruefung ob FixSize oder nicht, die FtnContainer sind immer bis + //zur Maximalhoehe variabel. + //Wenn die Maximalhoehe LONG_MAX ist, so nehmen wir uns soviel Platz wie eben + //moeglich. + //Wenn die Seite eine spezielle Fussnotenseite ist, so nehmen wir uns auch + //soviel Platz wie eben moeglich. +#if OSL_DEBUG_LEVEL > 1 + if ( !GetUpper() || !GetUpper()->IsFtnBossFrm() ) + { OSL_ENSURE( !this, "Keine FtnBoss." ); + return 0; + } +#endif + + SWRECTFN( this ) + if( (Frm().*fnRect->fnGetHeight)() > 0 && + nDist > ( LONG_MAX - (Frm().*fnRect->fnGetHeight)() ) ) + nDist = LONG_MAX - (Frm().*fnRect->fnGetHeight)(); + + SwFtnBossFrm *pBoss = (SwFtnBossFrm*)GetUpper(); + if( IsInSct() ) + { + SwSectionFrm* pSect = FindSctFrm(); + OSL_ENSURE( pSect, "GrowFrm: Missing SectFrm" ); + // In a section, which has to maximize, a footnotecontainer is allowed + // to grow, when the section can't grow anymore. + if( !bTst && !pSect->IsColLocked() && + pSect->ToMaximize( sal_False ) && pSect->Growable() ) + { + pSect->InvalidateSize(); + return 0; + } + } + const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0; + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + SwPageFrm *pPage = pBoss->FindPageFrm(); + if ( bBrowseMode || !pPage->IsFtnPage() ) + { + if ( pBoss->GetMaxFtnHeight() != LONG_MAX ) + { + nDist = Min( nDist, pBoss->GetMaxFtnHeight() + - (Frm().*fnRect->fnGetHeight)() ); + if ( nDist <= 0 ) + return 0L; + } + //Der FtnBoss will bezueglich des MaxWerts auch noch mitreden. + if( !IsInSct() ) + { + const SwTwips nMax = pBoss->GetVarSpace(); + if ( nDist > nMax ) + nDist = nMax; + if ( nDist <= 0 ) + return 0L; + } + } + else if( nDist > (GetPrev()->Frm().*fnRect->fnGetHeight)() ) + //aber mehr als der Body kann koennen und wollen wir nun auch wieder + //nicht herausruecken. + nDist = (GetPrev()->Frm().*fnRect->fnGetHeight)(); + + long nAvail = 0; + if ( bBrowseMode ) + { + nAvail = GetUpper()->Prt().Height(); + const SwFrm *pAvail = GetUpper()->Lower(); + do + { nAvail -= pAvail->Frm().Height(); + pAvail = pAvail->GetNext(); + } while ( pAvail ); + if ( nAvail > nDist ) + nAvail = nDist; + } + + if ( !bTst ) + { + (Frm().*fnRect->fnSetHeight)( (Frm().*fnRect->fnGetHeight)() + nDist ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !IsReverse() ) + Frm().Pos().X() -= nDist; + } + long nGrow = nDist - nAvail, + nReal = 0; + if ( nGrow > 0 ) + { + sal_uInt8 nAdjust = pBoss->NeighbourhoodAdjustment( this ); + if( NA_ONLY_ADJUST == nAdjust ) + nReal = AdjustNeighbourhood( nGrow, bTst ); + else + { + if( NA_GROW_ADJUST == nAdjust ) + { + SwFrm* pFtn = Lower(); + if( pFtn ) + { + while( pFtn->GetNext() ) + pFtn = pFtn->GetNext(); + if( ((SwFtnFrm*)pFtn)->GetAttr()->GetFtn().IsEndNote() ) + { + nReal = AdjustNeighbourhood( nGrow, bTst ); + nAdjust = NA_GROW_SHRINK; // no more AdjustNeighbourhood + } + } + } + nReal += pBoss->Grow( nGrow - nReal, bTst ); + if( ( NA_GROW_ADJUST == nAdjust || NA_ADJUST_GROW == nAdjust ) + && nReal < nGrow ) + nReal += AdjustNeighbourhood( nGrow - nReal, bTst ); + } + } + + nReal += nAvail; + + if ( !bTst ) + { + if ( nReal != nDist ) + { + nDist -= nReal; + //Den masslosen Wunsch koennen wir leider nur in Grenzen erfuellen. + Frm().SSize().Height() -= nDist; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !IsReverse() ) + Frm().Pos().X() += nDist; + } + + //Nachfolger braucht nicht invalidiert werden, denn wir wachsen + //immer nach oben. + if( nReal ) + { + _InvalidateSize(); + _InvalidatePos(); + InvalidatePage( pPage ); + } + } + return nReal; +} + + +SwTwips SwFtnContFrm::ShrinkFrm( SwTwips nDiff, sal_Bool bTst, sal_Bool bInfo ) +{ + SwPageFrm *pPage = FindPageFrm(); + bool bShrink = false; + if ( pPage ) + { + if( !pPage->IsFtnPage() ) + bShrink = true; + else + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + bShrink = true; + } + } + if( bShrink ) + { + SwTwips nRet = SwLayoutFrm::ShrinkFrm( nDiff, bTst, bInfo ); + if( IsInSct() && !bTst ) + FindSctFrm()->InvalidateNextPos(); + if ( !bTst && nRet ) + { + _InvalidatePos(); + InvalidatePage( pPage ); + } + return nRet; + } + return 0; +} + + +/************************************************************************* +|* +|* SwFtnFrm::SwFtnFrm() +|* +|*************************************************************************/ + + +SwFtnFrm::SwFtnFrm( SwFrmFmt *pFmt, SwFrm* pSib, SwCntntFrm *pCnt, SwTxtFtn *pAt ): + SwLayoutFrm( pFmt, pSib ), + pFollow( 0 ), + pMaster( 0 ), + pRef( pCnt ), + pAttr( pAt ), + bBackMoveLocked( sal_False ), + // --> OD 2005-08-11 #i49383# + mbUnlockPosOfLowerObjs( true ) + // <-- +{ + nType = FRMC_FTN; +} + +/************************************************************************* +|* +|* SwFtnFrm::InvalidateNxtFtnCnts() +|* +|*************************************************************************/ + + +void SwFtnFrm::InvalidateNxtFtnCnts( SwPageFrm *pPage ) +{ + if ( GetNext() ) + { + SwFrm *pCnt = ((SwLayoutFrm*)GetNext())->ContainsAny(); + if( pCnt ) + { + pCnt->InvalidatePage( pPage ); + pCnt->_InvalidatePrt(); + do + { pCnt->_InvalidatePos(); + if( pCnt->IsSctFrm() ) + { + SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny(); + if( pTmp ) + pTmp->_InvalidatePos(); + } + pCnt->GetUpper()->_InvalidateSize(); + pCnt = pCnt->FindNext(); + } while ( pCnt && GetUpper()->IsAnLower( pCnt ) ); + } + } +} + +#if OSL_DEBUG_LEVEL > 1 + +SwTwips SwFtnFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + static sal_uInt16 nNum = USHRT_MAX; + SwTxtFtn* pTxtFtn = GetAttr(); + if ( pTxtFtn->GetFtn().GetNumber() == nNum ) + { + int bla = 5; + (void)bla; + + } + return SwLayoutFrm::GrowFrm( nDist, bTst, bInfo ); +} + + +SwTwips SwFtnFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + static sal_uInt16 nNum = USHRT_MAX; + if( nNum != USHRT_MAX ) + { + SwTxtFtn* pTxtFtn = GetAttr(); + if( &pTxtFtn->GetAttr() && pTxtFtn->GetFtn().GetNumber() == nNum ) + { + int bla = 5; + (void)bla; + } + } + return SwLayoutFrm::ShrinkFrm( nDist, bTst, bInfo ); +} +#endif + +/************************************************************************* +|* +|* SwFtnFrm::Cut() +|* +|*************************************************************************/ + + +void SwFtnFrm::Cut() +{ + if ( GetNext() ) + GetNext()->InvalidatePos(); + else if ( GetPrev() ) + GetPrev()->SetRetouche(); + + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + + //Verkettung korrigieren. + SwFtnFrm *pFtn = (SwFtnFrm*)this; + if ( pFtn->GetFollow() ) + pFtn->GetFollow()->SetMaster( pFtn->GetMaster() ); + if ( pFtn->GetMaster() ) + pFtn->GetMaster()->SetFollow( pFtn->GetFollow() ); + pFtn->SetFollow( 0 ); + pFtn->SetMaster( 0 ); + + // Alle Verbindungen kappen. + Remove(); + + if ( pUp ) + { + //Die letzte Fussnote nimmt ihren Container mit. + if ( !pUp->Lower() ) + { + SwPageFrm *pPage = pUp->FindPageFrm(); + if ( pPage ) + { + SwLayoutFrm *pBody = pPage->FindBodyCont(); + if( pBody && !pBody->ContainsCntnt() ) + pPage->getRootFrm()->SetSuperfluous(); + } + SwSectionFrm* pSect = pUp->FindSctFrm(); + pUp->Cut(); + delete pUp; + // Wenn der letzte Fussnotencontainer aus einem spaltigen Bereich verschwindet, + // so kann dieser, falls er keinen Follow besitzt, zusammenschrumpfen. + if( pSect && !pSect->ToMaximize( sal_False ) && !pSect->IsColLocked() ) + pSect->_InvalidateSize(); + } + else + { if ( Frm().Height() ) + pUp->Shrink( Frm().Height() ); + pUp->SetCompletePaint(); + pUp->InvalidatePage(); + } + } +} + +/************************************************************************* +|* +|* SwFtnFrm::Paste() +|* +|*************************************************************************/ + + +void SwFtnFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + SWRECTFN( this ) + if( (Frm().*fnRect->fnGetWidth)()!=(pParent->Prt().*fnRect->fnGetWidth)() ) + _InvalidateSize(); + _InvalidatePos(); + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + if ( GetNext() ) + GetNext()->_InvalidatePos(); + if( (Frm().*fnRect->fnGetHeight)() ) + pParent->Grow( (Frm().*fnRect->fnGetHeight)() ); + + //Wenn mein Vorgaenger mein Master ist und/oder wenn mein Nachfolger mein + //Follow ist so kann ich deren Inhalt uebernehmen und sie vernichten. + if ( GetPrev() && GetPrev() == GetMaster() ) + { OSL_ENSURE( SwFlowFrm::CastFlowFrm( GetPrev()->GetLower() ), + "Fussnote ohne Inhalt?" ); + (SwFlowFrm::CastFlowFrm( GetPrev()->GetLower()))-> + MoveSubTree( this, GetLower() ); + SwFrm *pDel = GetPrev(); + pDel->Cut(); + delete pDel; + } + if ( GetNext() && GetNext() == GetFollow() ) + { OSL_ENSURE( SwFlowFrm::CastFlowFrm( GetNext()->GetLower() ), + "Fussnote ohne Inhalt?" ); + (SwFlowFrm::CastFlowFrm( GetNext()->GetLower()))->MoveSubTree( this ); + SwFrm *pDel = GetNext(); + pDel->Cut(); + delete pDel; + } +#if OSL_DEBUG_LEVEL > 1 + SwDoc *pDoc = GetFmt()->GetDoc(); + if ( GetPrev() ) + { + OSL_ENSURE( lcl_FindFtnPos( pDoc, ((SwFtnFrm*)GetPrev())->GetAttr() ) <= + lcl_FindFtnPos( pDoc, GetAttr() ), "Prev ist not FtnPrev" ); + } + if ( GetNext() ) + { + OSL_ENSURE( lcl_FindFtnPos( pDoc, GetAttr() ) <= + lcl_FindFtnPos( pDoc, ((SwFtnFrm*)GetNext())->GetAttr() ), + "Next is not FtnNext" ); + } +#endif + InvalidateNxtFtnCnts( pPage ); +} + +/************************************************************************* +|* +|* SwFrm::GetNextFtnLeaf() +|* +|* Beschreibung Liefert das naechste LayoutBlatt in den das +|* Frame gemoved werden kann. +|* Neue Seiten werden nur dann erzeugt, wenn der Parameter sal_True ist. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetNextFtnLeaf( MakePageType eMakePage ) +{ + SwFtnBossFrm *pOldBoss = FindFtnBossFrm(); + SwPageFrm* pOldPage = pOldBoss->FindPageFrm(); + SwPageFrm* pPage; + SwFtnBossFrm *pBoss = pOldBoss->IsColumnFrm() ? + (SwFtnBossFrm*)pOldBoss->GetNext() : 0; // naechste Spalte, wenn vorhanden + if( pBoss ) + pPage = NULL; + else + { + if( pOldBoss->GetUpper()->IsSctFrm() ) + { // Das kann nur in einem spaltigen Bereich sein + SwLayoutFrm* pNxt = pOldBoss->GetNextSctLeaf( eMakePage ); + if( pNxt ) + { + OSL_ENSURE( pNxt->IsColBodyFrm(), "GetNextFtnLeaf: Funny Leaf" ); + pBoss = (SwFtnBossFrm*)pNxt->GetUpper(); + pPage = pBoss->FindPageFrm(); + } + else + return 0; + } + else + { + // naechste Seite + pPage = (SwPageFrm*)pOldPage->GetNext(); + // Leerseiten ueberspringen + if( pPage && pPage->IsEmptyPage() ) + pPage = (SwPageFrm*)pPage->GetNext(); + pBoss = pPage; + } + } + // Was haben wir jetzt? + // pBoss != NULL, pPage==NULL => pBoss ist die auf der gleichen Seite folgende Spalte + // pBoss != NULL, pPage!=NULL => pBoss und pPage sind die folgende Seite (Empty uebersprungen) + // pBoss == NULL => pPage == NULL, es gibt keine folgende Seite + + //Wenn die Fussnote bereits einen Follow hat brauchen wir nicht zu suchen. + //Wenn allerdings zwischen Ftn und Follow unerwuenschte Leerseiten/spalten + //herumlungern, so legen wir auf der naechstbesten Seite/Spalte einen weiteren + //Follow an, der Rest wird sich schon finden. + SwFtnFrm *pFtn = FindFtnFrm(); + if ( pFtn && pFtn->GetFollow() ) + { + SwFtnBossFrm* pTmpBoss = pFtn->GetFollow()->FindFtnBossFrm(); + // Folgende Faelle werden hier erkannt und akzeptiert + // 1. Die FtnBosse sind benachbarte Seiten oder benachbarte Spalten + // 2. Der neue ist die erste Spalte der benachbarten Seite + // 3. Der neue ist die erste Spalte in einem Bereich in der naechsten Spalte/Seite + while( pTmpBoss != pBoss && pTmpBoss && !pTmpBoss->GetPrev() ) + pTmpBoss = pTmpBoss->GetUpper()->FindFtnBossFrm(); + if( pTmpBoss == pBoss ) + return pFtn->GetFollow(); + } + + // Wenn wir keinen pBoss gefunden haben oder es sich um eine "falsche" Seite handelt, + // muss eine neue Seite her + if ( !pBoss || ( pPage && pPage->IsEndNotePage() && !pOldPage->IsEndNotePage() ) ) + { + if ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) + { + pBoss = InsertPage( pOldPage, pOldPage->IsFtnPage() ); + ((SwPageFrm*)pBoss)->SetEndNotePage( pOldPage->IsEndNotePage() ); + } + else + return 0; + } + if( pBoss->IsPageFrm() ) + { // Wenn wir auf einer spaltigen Seite gelandet sind, + // gehen wir in die erste Spalte + SwLayoutFrm* pLay = pBoss->FindBodyCont(); + if( pLay && pLay->Lower() && pLay->Lower()->IsColumnFrm() ) + pBoss = (SwFtnBossFrm*)pLay->Lower(); + } + //Seite/Spalte gefunden, da schummeln wir uns doch gleich mal 'rein + SwFtnContFrm *pCont = pBoss->FindFtnCont(); + if ( !pCont && pBoss->GetMaxFtnHeight() && + ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) ) + pCont = pBoss->MakeFtnCont(); + return pCont; +} + +/************************************************************************* +|* +|* SwFrm::GetPrevFtnLeaf() +|* +|* Beschreibung Liefert das vorhergehende LayoutBlatt in das der +|* Frame gemoved werden kann. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetPrevFtnLeaf( MakePageType eMakeFtn ) +{ + //Der Vorgaenger fuer eine Fussnote ist falls moeglich der Master + //in der Fussnoteneigenen Verkettung. + SwLayoutFrm *pRet = 0; + SwFtnFrm *pFtn = FindFtnFrm(); + pRet = pFtn->GetMaster(); + + SwFtnBossFrm* pOldBoss = FindFtnBossFrm(); + SwPageFrm *pOldPage = pOldBoss->FindPageFrm(); + + if ( !pOldBoss->GetPrev() && !pOldPage->GetPrev() ) + return pRet; // es gibt weder eine Spalte noch eine Seite vor uns + + if ( !pRet ) + { + bool bEndn = pFtn->GetAttr()->GetFtn().IsEndNote(); + SwFrm* pTmpRef = NULL; + if( bEndn && pFtn->IsInSct() ) + { + SwSectionFrm* pSect = pFtn->FindSctFrm(); + if( pSect->IsEndnAtEnd() ) + pTmpRef = pSect->FindLastCntnt( FINDMODE_LASTCNT ); + } + if( !pTmpRef ) + pTmpRef = pFtn->GetRef(); + SwFtnBossFrm* pStop = pTmpRef->FindFtnBossFrm( !bEndn ); + + const sal_uInt16 nNum = pStop->GetPhyPageNum(); + + //Wenn die Fussnoten am Dokumentende angezeigt werden, so verlassen wir + //die Entsprechenden Seiten nicht. + //Selbiges gilt analog fuer die Endnotenseiten. + const sal_Bool bEndNote = pOldPage->IsEndNotePage(); + const sal_Bool bFtnEndDoc = pOldPage->IsFtnPage(); + SwFtnBossFrm* pNxtBoss = pOldBoss; + SwSectionFrm *pSect = pNxtBoss->GetUpper()->IsSctFrm() ? + (SwSectionFrm*)pNxtBoss->GetUpper() : 0; + + do + { + if( pNxtBoss->IsColumnFrm() && pNxtBoss->GetPrev() ) + pNxtBoss = (SwFtnBossFrm*)pNxtBoss->GetPrev(); // eine Spalte zurueck + else // oder eine Seite zurueck + { + SwLayoutFrm* pBody = 0; + if( pSect ) + { + if( pSect->IsFtnLock() ) + { + if( pNxtBoss == pOldBoss ) + return 0; + pStop = pNxtBoss; + } + else + { + pSect = (SwSectionFrm*)pSect->FindMaster(); + if( !pSect || !pSect->Lower() ) + return 0; + OSL_ENSURE( pSect->Lower()->IsColumnFrm(), + "GetPrevFtnLeaf: Where's the column?" ); + pNxtBoss = (SwFtnBossFrm*)pSect->Lower(); + pBody = pSect; + } + } + else + { + SwPageFrm* pPage = (SwPageFrm*)pNxtBoss->FindPageFrm()->GetPrev(); + if( !pPage || pPage->GetPhyPageNum() < nNum || + bEndNote != pPage->IsEndNotePage() || bFtnEndDoc != pPage->IsFtnPage() ) + return NULL; // Keine in Frage kommende Seite mehr gefunden + pNxtBoss = pPage; + pBody = pPage->FindBodyCont(); + } + // Die vorherige Seite haben wir nun, ggf. sollten wir in die letzte Spalte + // der Seite wechseln + if( pBody ) + { + if ( pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + { + pNxtBoss = static_cast<SwFtnBossFrm*>(pBody->GetLastLower()); + } + } + } + SwFtnContFrm *pCont = pNxtBoss->FindFtnCont(); + if ( pCont ) + { + pRet = pCont; + break; + } + if ( pStop == pNxtBoss ) + { //Die Seite/Spalte auf der sich auch die Referenz tummelt, ist erreicht. + //Wir koennen jetzt probehalber mal einen Container erzeugen und + //uns hineinpasten. + if ( eMakeFtn == MAKEPAGE_FTN && pNxtBoss->GetMaxFtnHeight() ) + pRet = pNxtBoss->MakeFtnCont(); + break; + } + } while( !pRet ); + } + if ( pRet ) + { + const SwFtnBossFrm* pNewBoss = pRet->FindFtnBossFrm(); + sal_Bool bJump = sal_False; + if( pOldBoss->IsColumnFrm() && pOldBoss->GetPrev() ) // es gibt eine vorherige Spalte + bJump = pOldBoss->GetPrev() != (SwFrm*)pNewBoss; // sind wir darin gelandet? + else if( pNewBoss->IsColumnFrm() && pNewBoss->GetNext() ) + bJump = sal_True; // es gibt hinter dem neuen Boss noch eine Spalte, die aber nicht + // der alte Boss sein kann, das haben wir ja bereits geprueft. + else // hier landen wir nur, wenn neuer und alter Boss entweder Seiten oder letzte (neu) + { // bzw. erste (alt) Spalten einer Seite sind. In diesem Fall muss noch geprueft + // werden, ob Seiten ueberspringen wurden. + sal_uInt16 nDiff = pOldPage->GetPhyPageNum() - pRet->FindPageFrm()->GetPhyPageNum(); + if ( nDiff > 2 || + (nDiff > 1 && !((SwPageFrm*)pOldPage->GetPrev())->IsEmptyPage()) ) + bJump = sal_True; + } + if( bJump ) + SwFlowFrm::SetMoveBwdJump( sal_True ); + } + return pRet; +} + +/************************************************************************* +|* +|* SwFrm::IsFtnAllowed() +|* +|*************************************************************************/ + + +sal_Bool SwFrm::IsFtnAllowed() const +{ + if ( !IsInDocBody() ) + return sal_False; + + if ( IsInTab() ) + { + //Keine Ftns in wiederholten Headlines. + const SwTabFrm *pTab = ((SwFrm*)this)->ImplFindTabFrm(); + if ( pTab->IsFollow() ) + return !pTab->IsInHeadline( *this ); + } + return sal_True; +} + +/************************************************************************* +|* +|* SwRootFrm::UpdateFtnNums() +|* +|*************************************************************************/ + + +void SwRootFrm::UpdateFtnNums() +{ + //Seitenweise Numerierung nur wenn es am Dokument so eingestellt ist. + if ( GetFmt()->GetDoc()->GetFtnInfo().eNum == FTNNUM_PAGE ) + { + SwPageFrm *pPage = (SwPageFrm*)Lower(); + while ( pPage && !pPage->IsFtnPage() ) + { + pPage->UpdateFtnNum(); + pPage = (SwPageFrm*)pPage->GetNext(); + } + } +} + +/************************************************************************* +|* +|* RemoveFtns() Entfernen aller Fussnoten (nicht etwa die Referenzen) +|* und Entfernen aller Fussnotenseiten. +|* +|*************************************************************************/ + +void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes ) +{ + do + { + SwFtnContFrm *pCont = pBoss->FindFtnCont(); + if ( pCont ) + { + SwFtnFrm *pFtn = (SwFtnFrm*)pCont->Lower(); + OSL_ENSURE( pFtn, "FtnCont ohne Ftn." ); + if ( bPageOnly ) + while ( pFtn->GetMaster() ) + pFtn = pFtn->GetMaster(); + do + { + SwFtnFrm *pNxt = (SwFtnFrm*)pFtn->GetNext(); + if ( !pFtn->GetAttr()->GetFtn().IsEndNote() || + bEndNotes ) + { + pFtn->GetRef()->Prepare( PREP_FTN, (void*)pFtn->GetAttr() ); + if ( bPageOnly && !pNxt ) + pNxt = pFtn->GetFollow(); + pFtn->Cut(); + delete pFtn; + } + pFtn = pNxt; + + } while ( pFtn ); + } + if( !pBoss->IsInSct() ) + { + // A sectionframe with the Ftn/EndnAtEnd-flags may contain + // foot/endnotes. If the last lower frame of the bodyframe is + // a multicolumned sectionframe, it may contain footnotes, too. + SwLayoutFrm* pBody = pBoss->FindBodyCont(); + if( pBody && pBody->Lower() ) + { + SwFrm* pLow = pBody->Lower(); + while( pLow->GetNext() ) + { + if( pLow->IsSctFrm() && ( !pLow->GetNext() || + ((SwSectionFrm*)pLow)->IsAnyNoteAtEnd() ) && + ((SwSectionFrm*)pLow)->Lower() && + ((SwSectionFrm*)pLow)->Lower()->IsColumnFrm() ) + lcl_RemoveFtns( (SwColumnFrm*)((SwSectionFrm*)pLow)->Lower(), + bPageOnly, bEndNotes ); + pLow = pLow->GetNext(); + } + } + } + // noch 'ne Spalte? + pBoss = pBoss->IsColumnFrm() ? (SwColumnFrm*)pBoss->GetNext() : NULL; + } while( pBoss ); +} + +void SwRootFrm::RemoveFtns( SwPageFrm *pPage, sal_Bool bPageOnly, sal_Bool bEndNotes ) +{ + if ( !pPage ) + pPage = (SwPageFrm*)Lower(); + + do + { // Bei spaltigen Seiten muessen wir in allen Spalten aufraeumen + SwFtnBossFrm* pBoss; + SwLayoutFrm* pBody = pPage->FindBodyCont(); + if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + pBoss = (SwFtnBossFrm*)pBody->Lower(); // die erste Spalte + else + pBoss = pPage; // keine Spalten + lcl_RemoveFtns( pBoss, bPageOnly, bEndNotes ); + if ( !bPageOnly ) + { + if ( pPage->IsFtnPage() && + (!pPage->IsEndNotePage() || bEndNotes) ) + { + SwFrm *pDel = pPage; + pPage = (SwPageFrm*)pPage->GetNext(); + pDel->Cut(); + delete pDel; + } + else + pPage = (SwPageFrm*)pPage->GetNext(); + } + else + break; + + } while ( pPage ); +} + +/************************************************************************* +|* +|* SetFtnPageDescs() Seitenvorlagen der Fussnotenseiten aendern +|* +|*************************************************************************/ + +void SwRootFrm::CheckFtnPageDescs( sal_Bool bEndNote ) +{ + SwPageFrm *pPage = (SwPageFrm*)Lower(); + while ( pPage && !pPage->IsFtnPage() ) + pPage = (SwPageFrm*)pPage->GetNext(); + while ( pPage && pPage->IsEndNotePage() != bEndNote ) + pPage = (SwPageFrm*)pPage->GetNext(); + if ( pPage ) + SwFrm::CheckPageDescs( pPage, sal_False ); +} + + +/************************************************************************* +|* +|* SwFtnBossFrm::MakeFtnCont() +|* +|*************************************************************************/ + + +SwFtnContFrm *SwFtnBossFrm::MakeFtnCont() +{ + //Einfuegen eines Fussnotencontainers. Der Fussnotencontainer sitzt + //immer direkt hinter dem Bodytext. + //Sein FrmFmt ist immer das DefaultFrmFmt. + +#if OSL_DEBUG_LEVEL > 1 + if ( FindFtnCont() ) + { OSL_ENSURE( !this, "Fussnotencontainer bereits vorhanden." ); + return 0; + } +#endif + + SwFtnContFrm *pNew = new SwFtnContFrm( GetFmt()->GetDoc()->GetDfltFrmFmt(), this ); + SwLayoutFrm *pLay = FindBodyCont(); + pNew->Paste( this, pLay->GetNext() ); + return pNew; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::FindFtnCont() +|* +|*************************************************************************/ + + +SwFtnContFrm *SwFtnBossFrm::FindFtnCont() +{ + SwFrm *pFrm = Lower(); + while( pFrm && !pFrm->IsFtnContFrm() ) + pFrm = pFrm->GetNext(); + +#if OSL_DEBUG_LEVEL > 1 + if ( pFrm ) + { + SwFrm *pFtn = pFrm->GetLower(); + OSL_ENSURE( pFtn, "Cont ohne Fussnote." ); + while ( pFtn ) + { + OSL_ENSURE( pFtn->IsFtnFrm(), "Nachbar von Fussnote keine Fussnote." ); + pFtn = pFtn->GetNext(); + } + } +#endif + + return (SwFtnContFrm*)pFrm; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::FindNearestFtnCont() Sucht den naechst greifbaren Fussnotencontainer. +|* +|*************************************************************************/ + +SwFtnContFrm *SwFtnBossFrm::FindNearestFtnCont( sal_Bool bDontLeave ) +{ + SwFtnContFrm *pCont = 0; + if ( GetFmt()->GetDoc()->GetFtnIdxs().Count() ) + { + pCont = FindFtnCont(); + if ( !pCont ) + { + SwPageFrm *pPage = FindPageFrm(); + SwFtnBossFrm* pBoss = this; + sal_Bool bEndNote = pPage->IsEndNotePage(); + do + { + sal_Bool bChgPage = lcl_NextFtnBoss( pBoss, pPage, bDontLeave ); + // Haben wir noch einen Boss gefunden? Bei einem Seitenwechsel muss + // zudem noch das EndNotenFlag uebereinstimmen + if( pBoss && ( !bChgPage || pPage->IsEndNotePage() == bEndNote ) ) + pCont = pBoss->FindFtnCont(); + } while ( !pCont && pPage ); + } + } + return pCont; +} + + +/************************************************************************* +|* +|* SwFtnBossFrm::FindFirstFtn() +|* +|* Beschreibung Erste Fussnote des Fussnotenbosses suchen. +|* +|*************************************************************************/ + + +SwFtnFrm *SwFtnBossFrm::FindFirstFtn() +{ + //Erstmal den naechsten FussnotenContainer suchen. + SwFtnContFrm *pCont = FindNearestFtnCont(); + if ( !pCont ) + return 0; + + //Ab der ersten Fussnote im Container die erste suchen, die + //von der aktuellen Spalte (bzw. einspaltigen Seite) referenziert wird. + + SwFtnFrm *pRet = (SwFtnFrm*)pCont->Lower(); + const sal_uInt16 nRefNum = FindPageFrm()->GetPhyPageNum(); + const sal_uInt16 nRefCol = lcl_ColumnNum( this ); + sal_uInt16 nPgNum, nColNum; //Seitennummer, Spaltennummer + SwFtnBossFrm* pBoss; + SwPageFrm* pPage; + if( pRet ) + { + pBoss = pRet->GetRef()->FindFtnBossFrm(); + OSL_ENSURE( pBoss, "FindFirstFtn: No boss found" ); + if( !pBoss ) + return sal_False; // ?There must be a bug, but no GPF + pPage = pBoss->FindPageFrm(); + nPgNum = pPage->GetPhyPageNum(); + if ( nPgNum == nRefNum ) + { + nColNum = lcl_ColumnNum( pBoss ); + if( nColNum == nRefCol ) + return pRet; //hat ihn. + else if( nColNum > nRefCol ) + return NULL; //mind. eine Spalte zu weit. + } + else if ( nPgNum > nRefNum ) + return NULL; //mind. eine Seite zu weit. + } + else + return NULL; + // Ende, wenn Ref auf einer spaeteren Seite oder auf der gleichen Seite in einer + // spaeteren Spalte liegt + + do + { + while ( pRet->GetFollow() ) + pRet = pRet->GetFollow(); + + SwFtnFrm *pNxt = (SwFtnFrm*)pRet->GetNext(); + if ( !pNxt ) + { + pBoss = pRet->FindFtnBossFrm(); + pPage = pBoss->FindPageFrm(); + lcl_NextFtnBoss( pBoss, pPage, sal_False ); // naechster FtnBoss + pCont = pBoss ? pBoss->FindNearestFtnCont() : 0; + if ( pCont ) + pNxt = (SwFtnFrm*)pCont->Lower(); + } + if ( pNxt ) + { + pRet = pNxt; + pBoss = pRet->GetRef()->FindFtnBossFrm(); + pPage = pBoss->FindPageFrm(); + nPgNum = pPage->GetPhyPageNum(); + if ( nPgNum == nRefNum ) + { + nColNum = lcl_ColumnNum( pBoss ); + if( nColNum == nRefCol ) + break; //hat ihn. + else if( nColNum > nRefCol ) + pRet = 0; //mind. eine Spalte zu weit. + } + else if ( nPgNum > nRefNum ) + pRet = 0; //mind. eine Seite zu weit. + } + else + pRet = 0; //Gibt eben keinen. + } while( pRet ); + return pRet; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::FindFirstFtn() +|* +|* Beschreibunt Erste Fussnote zum Cnt suchen. +|* +|*************************************************************************/ + + +const SwFtnFrm *SwFtnBossFrm::FindFirstFtn( SwCntntFrm *pCnt ) const +{ + const SwFtnFrm *pRet = ((SwFtnBossFrm*)this)->FindFirstFtn(); + if ( pRet ) + { + const sal_uInt16 nColNum = lcl_ColumnNum( this ); //Spaltennummer + const sal_uInt16 nPageNum = GetPhyPageNum(); + while ( pRet && (pRet->GetRef() != pCnt) ) + { + while ( pRet->GetFollow() ) + pRet = pRet->GetFollow(); + + if ( pRet->GetNext() ) + pRet = (const SwFtnFrm*)pRet->GetNext(); + else + { SwFtnBossFrm *pBoss = (SwFtnBossFrm*)pRet->FindFtnBossFrm(); + SwPageFrm *pPage = pBoss->FindPageFrm(); + lcl_NextFtnBoss( pBoss, pPage, sal_False ); // naechster FtnBoss + SwFtnContFrm *pCont = pBoss ? pBoss->FindNearestFtnCont() : 0; + pRet = pCont ? (SwFtnFrm*)pCont->Lower() : 0; + } + if ( pRet ) + { + const SwFtnBossFrm* pBoss = pRet->GetRef()->FindFtnBossFrm(); + if( pBoss->GetPhyPageNum() != nPageNum || + nColNum != lcl_ColumnNum( pBoss ) ) + pRet = 0; + } + } + } + return pRet; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::ResetFtn() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::ResetFtn( const SwFtnFrm *pCheck ) +{ + //Vernichten der Inkarnationen von Fussnoten zum Attribut, wenn sie nicht + //zu pAssumed gehoeren. + OSL_ENSURE( !pCheck->GetMaster(), "Master not an Master." ); + + SwNodeIndex aIdx( *pCheck->GetAttr()->GetStartNode(), 1 ); + SwCntntNode *pNd = aIdx.GetNode().GetCntntNode(); + if ( !pNd ) + pNd = pCheck->GetFmt()->GetDoc()-> + GetNodes().GoNextSection( &aIdx, sal_True, sal_False ); + SwIterator<SwFrm,SwCntntNode> aIter( *pNd ); + SwFrm* pFrm = aIter.First(); + while( pFrm ) + { + if( pFrm->getRootFrm() == pCheck->getRootFrm() ) + { + SwFrm *pTmp = pFrm->GetUpper(); + while ( pTmp && !pTmp->IsFtnFrm() ) + pTmp = pTmp->GetUpper(); + + SwFtnFrm *pFtn = (SwFtnFrm*)pTmp; + while ( pFtn && pFtn->GetMaster() ) + pFtn = pFtn->GetMaster(); + if ( pFtn != pCheck ) + { + while ( pFtn ) + { + SwFtnFrm *pNxt = pFtn->GetFollow(); + pFtn->Cut(); + delete pFtn; + pFtn = pNxt; + } + } + } + + pFrm = aIter.Next(); + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::InsertFtn() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::InsertFtn( SwFtnFrm* pNew ) +{ + //Die Fussnote haben wir, sie muss jetzt nur noch irgendwo + //hin und zwar vor die Fussnote, deren Attribut vor das + //der neuen zeigt (Position wird ueber das Doc ermittelt) + //Gibt es in diesem Fussnotenboss noch keine Fussnoten, so muss eben ein + //Container erzeugt werden. + //Gibt es bereits einen Container aber noch keine Fussnote zu diesem + //Fussnotenboss, so muss die Fussnote hinter die letzte Fussnote der dichtesten + //Vorseite/spalte. + + ResetFtn( pNew ); + SwFtnFrm *pSibling = FindFirstFtn(); + sal_Bool bDontLeave = sal_False; + + // Ok, a sibling has been found, but is the sibling in an acceptable + // environment? + if( IsInSct() ) + { + SwSectionFrm* pMySect = ImplFindSctFrm(); + bool bEndnt = pNew->GetAttr()->GetFtn().IsEndNote(); + if( bEndnt ) + { + const SwSectionFmt* pEndFmt = pMySect->GetEndSectFmt(); + bDontLeave = 0 != pEndFmt; + if( pSibling ) + { + if( pEndFmt ) + { + if( !pSibling->IsInSct() || + !pSibling->ImplFindSctFrm()->IsDescendantFrom( pEndFmt ) ) + pSibling = NULL; + } + else if( pSibling->IsInSct() ) + pSibling = NULL; + } + } + else + { + bDontLeave = pMySect->IsFtnAtEnd(); + if( pSibling ) + { + if( pMySect->IsFtnAtEnd() ) + { + if( !pSibling->IsInSct() || + !pMySect->IsAnFollow( pSibling->ImplFindSctFrm() ) ) + pSibling = NULL; + } + else if( pSibling->IsInSct() ) + pSibling = NULL; + } + } + } + + if( pSibling && pSibling->FindPageFrm()->IsEndNotePage() != + FindPageFrm()->IsEndNotePage() ) + pSibling = NULL; + + //Damit die Position herausgefunden werden kann. + SwDoc *pDoc = GetFmt()->GetDoc(); + const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pNew->GetAttr() ); + + sal_uLong nCmpPos = 0; + sal_uLong nLastPos = 0; + SwFtnContFrm *pParent = 0; + if( pSibling ) + { + nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() ); + if( nCmpPos > nStPos ) + pSibling = NULL; + } + + if ( !pSibling ) + { pParent = FindFtnCont(); + if ( !pParent ) + { + //Es gibt noch keinen FussnotenContainer, also machen wir einen. + //HAAAAAAAALT! So einfach ist das leider mal wieder nicht: Es kann + //sein, dass irgendeine naechste Fussnote existiert die vor der + //einzufuegenden zu stehen hat, weil z.B. eine Fussnote ueber zig + //Seiten aufgespalten ist usw. + pParent = FindNearestFtnCont( bDontLeave ); + if ( pParent ) + { + SwFtnFrm *pFtn = (SwFtnFrm*)pParent->Lower(); + if ( pFtn ) + { + + nCmpPos = ::lcl_FindFtnPos( pDoc, pFtn->GetAttr() ); + if ( nCmpPos > nStPos ) + pParent = 0; + } + else + pParent = 0; + } + } + if ( !pParent ) + //Jetzt kann aber ein Fussnotencontainer gebaut werden. + pParent = MakeFtnCont(); + else + { + //Ausgehend von der ersten Fussnote unterhalb des Parents wird die + //erste Fussnote gesucht deren Index hinter dem Index der + //einzufuegenden liegt; vor dieser kann der neue dann gepastet + //werden. + pSibling = (SwFtnFrm*)pParent->Lower(); + if ( !pSibling ) + { OSL_ENSURE( !this, "Keinen Platz fuer Fussnote gefunden."); + return; + } + nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() ); + + SwFtnBossFrm *pNxtB = this; //Immer den letzten merken, damit wir nicht + SwFtnFrm *pLastSib = 0; //ueber das Ziel hinausschiessen. + + while ( pSibling && nCmpPos <= nStPos ) + { + pLastSib = pSibling; // der kommt schon mal in Frage + nLastPos = nCmpPos; + + while ( pSibling->GetFollow() ) + pSibling = pSibling->GetFollow(); + + if ( pSibling->GetNext() ) + { + pSibling = (SwFtnFrm*)pSibling->GetNext(); + OSL_ENSURE( !pSibling->GetMaster() || ( ENDNOTE > nStPos && + pSibling->GetAttr()->GetFtn().IsEndNote() ), + "InsertFtn: Master expected I" ); + } + else + { + pNxtB = pSibling->FindFtnBossFrm(); + SwPageFrm *pSibPage = pNxtB->FindPageFrm(); + sal_Bool bEndNote = pSibPage->IsEndNotePage(); + sal_Bool bChgPage = lcl_NextFtnBoss( pNxtB, pSibPage, bDontLeave ); + // Bei Seitenwechsel muss das EndNoteFlag ueberprueft werden. + SwFtnContFrm *pCont = pNxtB && ( !bChgPage || + pSibPage->IsEndNotePage() == bEndNote ) + ? pNxtB->FindNearestFtnCont( bDontLeave ) : 0; + if( pCont ) + pSibling = (SwFtnFrm*)pCont->Lower(); + else // kein weiterer FtnContainer, dann werden wir uns wohl hinter + break; // pSibling haengen + } + if ( pSibling ) + { + nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() ); + OSL_ENSURE( nCmpPos > nLastPos, "InsertFtn: Order of FtnFrm's buggy" ); + } + } + // pLastSib ist jetzt die letzte Fussnote vor uns, + // pSibling leer oder die erste nach uns. + if ( pSibling && pLastSib && (pSibling != pLastSib) ) + { //Sind wir vielleicht bereits ueber das Ziel hinausgeschossen? + if ( nCmpPos > nStPos ) + pSibling = pLastSib; + } + else if ( !pSibling ) + { //Eine Chance haben wir noch: wir nehmen einfach die letzte + //Fussnote im Parent. Ein Sonderfall, der z.B. beim + //zurueckfliessen von Absaetzen mit mehreren Fussnoten + //vorkommt. + //Damit wir nicht die Reihenfolge verwuerfeln muessen wir den + //Parent der letzten Fussnote, die wir an der Hand hatten benutzen. + pSibling = pLastSib; + while( pSibling->GetFollow() ) + pSibling = pSibling->GetFollow(); + OSL_ENSURE( !pSibling->GetNext(), "InsertFtn: Who's that guy?" ); + } + } + } + else + { //Die erste Fussnote der Spalte/Seite haben wir an der Hand, jetzt ausgehend + //von dieser die erste zur selben Spalte/Seite suchen deren Index hinter + //den uebergebenen zeigt, die letzte, die wir an der Hand hatten, ist + //dann der Vorgaenger. + SwFtnBossFrm* pBoss = pNew->GetRef()->FindFtnBossFrm( + !pNew->GetAttr()->GetFtn().IsEndNote() ); + sal_uInt16 nRefNum = pBoss->GetPhyPageNum(); // Die Seiten- und + sal_uInt16 nRefCol = lcl_ColumnNum( pBoss ); // Spaltennummer der neuen Fussnote + sal_Bool bEnd = sal_False; + SwFtnFrm *pLastSib = 0; + while ( pSibling && !bEnd && (nCmpPos <= nStPos) ) + { + pLastSib = pSibling; + nLastPos = nCmpPos; + + while ( pSibling->GetFollow() ) + pSibling = pSibling->GetFollow(); + + SwFtnFrm *pFoll = (SwFtnFrm*)pSibling->GetNext(); + if ( pFoll ) + { + pBoss = pSibling->GetRef()->FindFtnBossFrm( !pSibling-> + GetAttr()->GetFtn().IsEndNote() ); + sal_uInt16 nTmpRef; + if( nStPos >= ENDNOTE || + (nTmpRef = pBoss->GetPhyPageNum()) < nRefNum || + ( nTmpRef == nRefNum && lcl_ColumnNum( pBoss ) <= nRefCol )) + pSibling = pFoll; + else + bEnd = sal_True; + } + else + { + SwFtnBossFrm* pNxtB = pSibling->FindFtnBossFrm(); + SwPageFrm *pSibPage = pNxtB->FindPageFrm(); + sal_Bool bEndNote = pSibPage->IsEndNotePage(); + sal_Bool bChgPage = lcl_NextFtnBoss( pNxtB, pSibPage, bDontLeave ); + // Bei Seitenwechsel muss das EndNoteFlag ueberprueft werden. + SwFtnContFrm *pCont = pNxtB && ( !bChgPage || + pSibPage->IsEndNotePage() == bEndNote ) + ? pNxtB->FindNearestFtnCont( bDontLeave ) : 0; + if ( pCont ) + pSibling = (SwFtnFrm*)pCont->Lower(); + else + bEnd = sal_True; + } + if ( !bEnd && pSibling ) + nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() ); + if ( pSibling && pLastSib && (pSibling != pLastSib) ) + { //Sind wir vielleicht bereits ueber das Ziel hinausgeschossen? + if ( (nLastPos < nCmpPos) && (nCmpPos > nStPos) ) + { + pSibling = pLastSib; + bEnd = sal_True; + } + } + } + } + if ( pSibling ) + { + nCmpPos = ::lcl_FindFtnPos( pDoc, pSibling->GetAttr() ); + if ( nCmpPos < nStPos ) + { + while ( pSibling->GetFollow() ) + pSibling = pSibling->GetFollow(); + pParent = (SwFtnContFrm*)pSibling->GetUpper(); + pSibling = (SwFtnFrm*)pSibling->GetNext(); + } + else + { + if( pSibling->GetMaster() ) + { + if( ENDNOTE > nCmpPos || nStPos >= ENDNOTE ) + { + OSL_FAIL( "InsertFtn: Master expected II" ); + do + pSibling = pSibling->GetMaster(); + while ( pSibling->GetMaster() ); + } + } + pParent = (SwFtnContFrm*)pSibling->GetUpper(); + } + } + OSL_ENSURE( pParent, "paste in space?" ); + pNew->Paste( pParent, pSibling ); +} + +/************************************************************************* +|* +|* SwFtnBossFrm::AppendFtn() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::AppendFtn( SwCntntFrm *pRef, SwTxtFtn *pAttr ) +{ + //Wenn es die Fussnote schon gibt tun wir nix. + if ( FindFtn( pRef, pAttr ) ) + return; + + //Wenn Fussnoten am Dokumentende eingestellt sind, so brauchen wir 'eh erst + //ab der entsprechenden Seite zu suchen. + //Wenn es noch keine gibt, muss eben eine erzeugt werden. + //Wenn es sich um eine Endnote handelt, muss eine Endnotenseite gesucht + //bzw. erzeugt werden. + SwDoc *pDoc = GetFmt()->GetDoc(); + SwFtnBossFrm *pBoss = this; + SwPageFrm *pPage = FindPageFrm(); + SwPageFrm *pMyPage = pPage; + sal_Bool bChgPage = sal_False; + sal_Bool bEnd = sal_False; + if ( pAttr->GetFtn().IsEndNote() ) + { + bEnd = sal_True; + if( GetUpper()->IsSctFrm() && + ((SwSectionFrm*)GetUpper())->IsEndnAtEnd() ) + { + SwFrm* pLast = + ((SwSectionFrm*)GetUpper())->FindLastCntnt( FINDMODE_ENDNOTE ); + if( pLast ) + { + pBoss = pLast->FindFtnBossFrm(); + pPage = pBoss->FindPageFrm(); + } + } + else + { + while ( pPage->GetNext() && !pPage->IsEndNotePage() ) + { + pPage = (SwPageFrm*)pPage->GetNext(); + bChgPage = sal_True; + } + if ( !pPage->IsEndNotePage() ) + { + SwPageDesc *pDesc = pDoc->GetEndNoteInfo().GetPageDesc( *pDoc ); + pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(), + !pPage->OnRightPage(), sal_False, sal_True, 0 ); + pPage->SetEndNotePage( sal_True ); + bChgPage = sal_True; + } + else + { + //Wir koennen wenigstens schon mal ungefaehr die richtige Seite + //suchen. Damit stellen wir sicher das wir auch bei hunderten + //Fussnoten noch in endlicher Zeit fertig werden. + SwPageFrm *pNxt = (SwPageFrm*)pPage->GetNext(); + const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pAttr ); + while ( pNxt && pNxt->IsEndNotePage() ) + { + SwFtnContFrm *pCont = pNxt->FindFtnCont(); + if ( pCont && pCont->Lower() ) + { + OSL_ENSURE( pCont->Lower()->IsFtnFrm(), "Keine Ftn im Container" ); + if ( nStPos > ::lcl_FindFtnPos( pDoc, + ((SwFtnFrm*)pCont->Lower())->GetAttr())) + { + pPage = pNxt; + pNxt = (SwPageFrm*)pPage->GetNext(); + continue; + } + } + break; + } + } + } + } + else if( FTNPOS_CHAPTER == pDoc->GetFtnInfo().ePos && ( !GetUpper()-> + IsSctFrm() || !((SwSectionFrm*)GetUpper())->IsFtnAtEnd() ) ) + { + while ( pPage->GetNext() && !pPage->IsFtnPage() && + !((SwPageFrm*)pPage->GetNext())->IsEndNotePage() ) + { + pPage = (SwPageFrm*)pPage->GetNext(); + bChgPage = sal_True; + } + + if ( !pPage->IsFtnPage() ) + { + SwPageDesc *pDesc = pDoc->GetFtnInfo().GetPageDesc( *pDoc ); + pPage = ::InsertNewPage( *pDesc, pPage->GetUpper(), + !pPage->OnRightPage(), sal_False, sal_True, pPage->GetNext() ); + bChgPage = sal_True; + } + else + { + //Wir koennen wenigstens schon mal ungefaehr die richtige Seite + //suchen. Damit stellen wir sicher das wir auch bei hunderten + //Fussnoten noch in endlicher Zeit fertig werden. + SwPageFrm *pNxt = (SwPageFrm*)pPage->GetNext(); + const sal_uLong nStPos = ::lcl_FindFtnPos( pDoc, pAttr ); + while ( pNxt && pNxt->IsFtnPage() && !pNxt->IsEndNotePage() ) + { + SwFtnContFrm *pCont = pNxt->FindFtnCont(); + if ( pCont && pCont->Lower() ) + { + OSL_ENSURE( pCont->Lower()->IsFtnFrm(), "Keine Ftn im Container" ); + if ( nStPos > ::lcl_FindFtnPos( pDoc, + ((SwFtnFrm*)pCont->Lower())->GetAttr())) + { + pPage = pNxt; + pNxt = (SwPageFrm*)pPage->GetNext(); + continue; + } + } + break; + } + } + } + + //Erstmal eine Fussnote und die benoetigten CntntFrms anlegen. + if ( !pAttr->GetStartNode() ) + { OSL_ENSURE( !this, "Kein Fussnoteninhalt." ); + return; + } + + // Wenn es auf der Seite/Spalte bereits einen FtnCont gibt, + // kann in einen spaltigen Bereich keiner erzeugt werden. + if( pBoss->IsInSct() && pBoss->IsColumnFrm() && !pPage->IsFtnPage() ) + { + SwSectionFrm* pSct = pBoss->FindSctFrm(); + if( bEnd ? !pSct->IsEndnAtEnd() : !pSct->IsFtnAtEnd() ) + { + SwFtnContFrm* pFtnCont = pSct->FindFtnBossFrm(!bEnd)->FindFtnCont(); + if( pFtnCont ) + { + SwFtnFrm* pTmp = (SwFtnFrm*)pFtnCont->Lower(); + if( bEnd ) + while( pTmp && !pTmp->GetAttr()->GetFtn().IsEndNote() ) + pTmp = (SwFtnFrm*)pTmp->GetNext(); + if( pTmp && *pTmp < pAttr ) + return; + } + } + } + + SwFtnFrm *pNew = new SwFtnFrm( pDoc->GetDfltFrmFmt(), this, pRef, pAttr ); + { + SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 ); + ::_InsertCnt( pNew, pDoc, aIdx.GetIndex() ); + } + // Wenn die Seite gewechselt (oder gar neu angelegt) wurde, + // muessen wir uns dort in die erste Spalte setzen + if( bChgPage ) + { + SwLayoutFrm* pBody = pPage->FindBodyCont(); + OSL_ENSURE( pBody, "AppendFtn: NoPageBody?" ); + if( pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + pBoss = (SwFtnBossFrm*)pBody->Lower(); + else + pBoss = pPage; // bei nichtspaltigen Seiten auf die Seite selbst + } + pBoss->InsertFtn( pNew ); + if ( pNew->GetUpper() ) //Eingesetzt oder nicht? + { + ::RegistFlys( pNew->FindPageFrm(), pNew ); + SwSectionFrm* pSect = FindSctFrm(); + // Der Inhalt des FtnContainers in einem (spaltigen) Bereich + // braucht nur kalkuliert zu werden, + // wenn der Bereich bereits bis zur Unterkante seines Uppers geht. + if( pSect && !pSect->IsJoinLocked() && ( bEnd ? !pSect->IsEndnAtEnd() : + !pSect->IsFtnAtEnd() ) && pSect->Growable() ) + pSect->InvalidateSize(); + else + { + // --> OD 2005-05-18 #i49383# - disable unlock of position of + // lower objects during format of footnote content. + const bool bOldFtnFrmLocked( pNew->IsColLocked() ); + pNew->ColLock(); + pNew->KeepLockPosOfLowerObjs(); + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// SwLayNotify* pFtnFrmNotitfy = new SwLayNotify( pNew ); + // <-- + SwCntntFrm *pCnt = pNew->ContainsCntnt(); + while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr ) + { + pCnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + { + // restart format with first content + pCnt = pNew->ContainsCntnt(); + continue; + } + } + // <-- + pCnt = (SwCntntFrm*)pCnt->FindNextCnt(); + } + // --> OD 2005-05-18 #i49383# + if ( !bOldFtnFrmLocked ) + { + pNew->ColUnlock(); + } + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // enable lock of lower object position before format of footnote frame. + pNew->UnlockPosOfLowerObjs(); + // <-- + pNew->Calc(); + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// pNew->UnlockPosOfLowerObjs(); +// delete pFtnFrmNotitfy; + // <-- + if ( !bOldFtnFrmLocked && !pNew->GetLower() && + !pNew->IsColLocked() && !pNew->IsBackMoveLocked() ) + { + pNew->Cut(); + delete pNew; + } + // <-- + } + pMyPage->UpdateFtnNum(); + } + else + delete pNew; +} +/************************************************************************* +|* +|* SwFtnBossFrm::FindFtn() +|* +|*************************************************************************/ + + +SwFtnFrm *SwFtnBossFrm::FindFtn( const SwCntntFrm *pRef, const SwTxtFtn *pAttr ) +{ + //Der einfachste und sicherste Weg geht ueber das Attribut. + OSL_ENSURE( pAttr->GetStartNode(), "FtnAtr ohne StartNode." ); + SwNodeIndex aIdx( *pAttr->GetStartNode(), 1 ); + SwCntntNode *pNd = aIdx.GetNode().GetCntntNode(); + if ( !pNd ) + pNd = pRef->GetAttrSet()->GetDoc()-> + GetNodes().GoNextSection( &aIdx, sal_True, sal_False ); + if ( !pNd ) + return 0; + SwIterator<SwFrm,SwCntntNode> aIter( *pNd ); + SwFrm* pFrm = aIter.First(); + if( pFrm ) + do + { + pFrm = pFrm->GetUpper(); + // #i28500#, #i27243# Due to the endnode collector, there are + // SwFtnFrms, which are not in the layout. Therefore the + // bInfFtn flags are not set correctly, and a cell of FindFtnFrm + // would return 0. Therefore we better call ImplFindFtnFrm(). + SwFtnFrm *pFtn = pFrm->ImplFindFtnFrm(); + if ( pFtn && pFtn->GetRef() == pRef ) + { + // The following condition becomes true, if the whole + // footnotecontent is a section. While no frames exist, + // the HiddenFlag of the section is set, this causes + // the GoNextSection-function leaves the footnote. + if( pFtn->GetAttr() != pAttr ) + return 0; + while ( pFtn && pFtn->GetMaster() ) + pFtn = pFtn->GetMaster(); + return pFtn; + } + + } while ( 0 != (pFrm = aIter.Next()) ); + + return 0; +} +/************************************************************************* +|* +|* SwFtnBossFrm::RemoveFtn() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::RemoveFtn( const SwCntntFrm *pRef, const SwTxtFtn *pAttr, + sal_Bool bPrep ) +{ + SwFtnFrm *pFtn = FindFtn( pRef, pAttr ); + if( pFtn ) + { + do + { + SwFtnFrm *pFoll = pFtn->GetFollow(); + pFtn->Cut(); + delete pFtn; + pFtn = pFoll; + } while ( pFtn ); + if( bPrep && pRef->IsFollow() ) + { + OSL_ENSURE( pRef->IsTxtFrm(), "NoTxtFrm has Footnote?" ); + SwTxtFrm* pMaster = (SwTxtFrm*)pRef->FindMaster(); + if( !pMaster->IsLocked() ) + pMaster->Prepare( PREP_FTN_GONE ); + } + } + FindPageFrm()->UpdateFtnNum(); +} + +/************************************************************************* +|* +|* SwFtnBossFrm::ChangeFtnRef() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::ChangeFtnRef( const SwCntntFrm *pOld, const SwTxtFtn *pAttr, + SwCntntFrm *pNew ) +{ + SwFtnFrm *pFtn = FindFtn( pOld, pAttr ); + while ( pFtn ) + { + pFtn->SetRef( pNew ); + pFtn = pFtn->GetFollow(); + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::CollectFtns() +|* +|*************************************************************************/ + + +/// OD 03.04.2003 #108446# - add parameter <_bCollectOnlyPreviousFtns> in +/// order to control, if only footnotes, which are positioned before the +/// footnote boss frame <this> have to be collected. +void SwFtnBossFrm::CollectFtns( const SwCntntFrm* _pRef, + SwFtnBossFrm* _pOld, + SvPtrarr& _rFtnArr, + const sal_Bool _bCollectOnlyPreviousFtns ) +{ + SwFtnFrm *pFtn = _pOld->FindFirstFtn(); + while( !pFtn ) + { + if( _pOld->IsColumnFrm() ) + { // Spalten abklappern + while ( !pFtn && _pOld->GetPrev() ) + { + //Wenn wir keine Fussnote gefunden haben, ist noch nicht alles zu + //spaet. Die Schleife wird beim Aufnehmen von Follow-Zeilen durch + //Tabellen benoetigt. Fuer alle anderen Faelle ist sie in der Lage + //'krumme' Verhaeltnisse zu korrigieren. + _pOld = (SwFtnBossFrm*)_pOld->GetPrev(); + pFtn = _pOld->FindFirstFtn(); + } + } + if( !pFtn ) + { + // vorherige Seite + SwPageFrm* pPg; + for ( SwFrm* pTmp = _pOld; + 0 != ( pPg = (SwPageFrm*)pTmp->FindPageFrm()->GetPrev()) + && pPg->IsEmptyPage() ; + ) + { + pTmp = pPg; + } + if( !pPg ) + return; + + SwLayoutFrm* pBody = pPg->FindBodyCont(); + if( pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + { + // mehrspaltige Seite => letzte Spalte suchen + _pOld = static_cast<SwFtnBossFrm*>(pBody->GetLastLower()); + } + else + _pOld = pPg; // einspaltige Seite + pFtn = _pOld->FindFirstFtn(); + } + } + // OD 03.04.2003 #108446# - consider new parameter <_bCollectOnlyPreviousFtns> + SwFtnBossFrm* pRefBossFrm = NULL; + if ( _bCollectOnlyPreviousFtns ) + { + pRefBossFrm = this; + } + _CollectFtns( _pRef, pFtn, _rFtnArr, _bCollectOnlyPreviousFtns, pRefBossFrm ); +} + + +/************************************************************************* +|* +|* SwFtnBossFrm::_CollectFtns() +|* +|*************************************************************************/ +inline void FtnInArr( SvPtrarr& rFtnArr, SwFtnFrm* pFtn ) +{ + if ( USHRT_MAX == rFtnArr.GetPos( (VoidPtr)pFtn ) ) + rFtnArr.Insert( (VoidPtr)pFtn, rFtnArr.Count() ); +} + +/// OD 03.04.2003 #108446# - add parameters <_bCollectOnlyPreviousFtns> and +/// <_pRefFtnBossFrm> in order to control, if only footnotes, which are positioned +/// before the given reference footnote boss frame have to be collected. +/// Note: if parameter <_bCollectOnlyPreviousFtns> is true, then parameter +/// <_pRefFtnBossFrm> have to be referenced to an object. +/// Adjust parameter names. +void SwFtnBossFrm::_CollectFtns( const SwCntntFrm* _pRef, + SwFtnFrm* _pFtn, + SvPtrarr& _rFtnArr, + sal_Bool _bCollectOnlyPreviousFtns, + const SwFtnBossFrm* _pRefFtnBossFrm) +{ + // OD 03.04.2003 #108446# - assert, that no reference footnote boss frame + // is set, in spite of the order, that only previous footnotes has to be + // collected. + OSL_ENSURE( !_bCollectOnlyPreviousFtns || _pRefFtnBossFrm, + "<SwFtnBossFrm::_CollectFtns(..)> - No reference footnote boss frame for collecting only previous footnotes set.\nCrash will be caused!" ); + + //Alle Fussnoten die von pRef referenziert werden nacheinander + //einsammeln (Attribut fuer Attribut), zusammengefuegen + //(der Inhalt zu einem Attribut kann ueber mehrere Seiten verteilt sein) + //und ausschneiden. + + SvPtrarr aNotFtnArr( 20, 20 ); //Zur Robustheit werden hier die nicht + //dazugehoerigen Fussnoten eingetragen. + //Wenn eine Fussnote zweimal angefasst wird + //ists vorbei! So kommt die Funktion auch + //noch mit einem kaputten Layout + //einigermassen (ohne Schleife und Absturz) + //"klar". + + //Hier sollte keiner mit einer Follow-Ftn ankommen, es sei denn er hat + //ernste Absichten (:-)); spricht er kommt mit einer Ftn an die vor der + //ersten der Referenz liegt. + OSL_ENSURE( !_pFtn->GetMaster() || _pFtn->GetRef() != _pRef, "FollowFtn moven?" ); + while ( _pFtn->GetMaster() ) + _pFtn = _pFtn->GetMaster(); + + sal_Bool bFound = sal_False; + + while ( _pFtn ) + { + //Erstmal die naechste Fussnote der Spalte/Seite suchen, damit wir nicht + //nach dem Cut jeder Fussnote von vorn anfangen muessen. + SwFtnFrm *pNxtFtn = _pFtn; + while ( pNxtFtn->GetFollow() ) + pNxtFtn = pNxtFtn->GetFollow(); + pNxtFtn = (SwFtnFrm*)pNxtFtn->GetNext(); + + if ( !pNxtFtn ) + { + SwFtnBossFrm* pBoss = _pFtn->FindFtnBossFrm(); + SwPageFrm* pPage = pBoss->FindPageFrm(); + do + { + lcl_NextFtnBoss( pBoss, pPage, sal_False ); + if( pBoss ) + { + SwLayoutFrm* pCont = pBoss->FindFtnCont(); + if( pCont ) + { + pNxtFtn = (SwFtnFrm*)pCont->Lower(); + if( pNxtFtn ) + { + while( pNxtFtn->GetMaster() ) + pNxtFtn = pNxtFtn->GetMaster(); + if( pNxtFtn == _pFtn ) + pNxtFtn = NULL; + } + } + } + } while( !pNxtFtn && pBoss ); + } + else if( !pNxtFtn->GetAttr()->GetFtn().IsEndNote() ) + { OSL_ENSURE( !pNxtFtn->GetMaster(), "_CollectFtn: Master exspected" ); + while ( pNxtFtn->GetMaster() ) + pNxtFtn = pNxtFtn->GetMaster(); + } + if ( pNxtFtn == _pFtn ) + { + OSL_FAIL( "_CollectFtn: Devil's circle" ); + pNxtFtn = 0; + } + + // OD 03.04.2003 #108446# - determine, if found footnote has to be collected. + sal_Bool bCollectFoundFtn = sal_False; + if ( _pFtn->GetRef() == _pRef && !_pFtn->GetAttr()->GetFtn().IsEndNote() ) + { + if ( _bCollectOnlyPreviousFtns ) + { + SwFtnBossFrm* pBossOfFoundFtn = _pFtn->FindFtnBossFrm( sal_True ); + OSL_ENSURE( pBossOfFoundFtn, + "<SwFtnBossFrm::_CollectFtns(..)> - footnote boss frame of found footnote frame missing.\nWrong layout!" ); + if ( !pBossOfFoundFtn || // don't crash, if no footnote boss is found. + pBossOfFoundFtn->IsBefore( _pRefFtnBossFrm ) + ) + { + bCollectFoundFtn = sal_True; + } + } + else + { + bCollectFoundFtn = sal_True; + } + } + + if ( bCollectFoundFtn ) + { + OSL_ENSURE( !_pFtn->GetMaster(), "FollowFtn moven?" ); + SwFtnFrm *pNxt = _pFtn->GetFollow(); + while ( pNxt ) + { + SwFrm *pCnt = pNxt->ContainsAny(); + if ( pCnt ) + { //Unterwegs wird der Follow zerstoert weil er leer wird! + do + { SwFrm *pNxtCnt = pCnt->GetNext(); + pCnt->Cut(); + pCnt->Paste( _pFtn ); + pCnt = pNxtCnt; + } while ( pCnt ); + } + else + { OSL_ENSURE( !pNxt, "Fussnote ohne Inhalt?" ); + pNxt->Cut(); + delete pNxt; + } + pNxt = _pFtn->GetFollow(); + } + _pFtn->Cut(); + FtnInArr( _rFtnArr, _pFtn ); + bFound = sal_True; + } + else + { + FtnInArr( aNotFtnArr, _pFtn ); + if( bFound ) + break; + } + if ( pNxtFtn && + USHRT_MAX == _rFtnArr.GetPos( (VoidPtr)pNxtFtn ) && + USHRT_MAX == aNotFtnArr.GetPos( (VoidPtr)pNxtFtn ) ) + _pFtn = pNxtFtn; + else + break; + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::_MoveFtns() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::_MoveFtns( SvPtrarr &rFtnArr, sal_Bool bCalc ) +{ + //Alle Fussnoten die von pRef referenziert werden muessen von der + //aktuellen Position, die sich durch die alte Spalte/Seite ergab, auf eine + //neue Position, bestimmt durch die neue Spalte/Seite, gemoved werden. + const sal_uInt16 nMyNum = FindPageFrm()->GetPhyPageNum(); + const sal_uInt16 nMyCol = lcl_ColumnNum( this ); + SWRECTFN( this ) + + // --> OD 2004-06-11 #i21478# - keep last inserted footnote in order to + // format the content of the following one. + SwFtnFrm* pLastInsertedFtn = 0L; + for ( sal_uInt16 i = 0; i < rFtnArr.Count(); ++i ) + { + SwFtnFrm *pFtn = (SwFtnFrm*)rFtnArr[i]; + + SwFtnBossFrm* pRefBoss = pFtn->GetRef()->FindFtnBossFrm( sal_True ); + if( pRefBoss != this ) + { + const sal_uInt16 nRefNum = pRefBoss->FindPageFrm()->GetPhyPageNum(); + const sal_uInt16 nRefCol = lcl_ColumnNum( this ); + if( nRefNum < nMyNum || ( nRefNum == nMyNum && nRefCol <= nMyCol ) ) + pRefBoss = this; + } + pRefBoss->InsertFtn( pFtn ); + + if ( pFtn->GetUpper() ) //Robust, z.B. bei doppelten + { + // Damit FtnFrms, die nicht auf die Seite passen, nicht fuer zuviel + // Unruhe sorgen (Loop 66312), wird ihr Inhalt zunaechst zusammengestaucht. + // Damit wird der FtnCont erst gegrowt, wenn der Inhalt formatiert wird + // und feststellt, dass er auf die Seite passt. + SwFrm *pCnt = pFtn->ContainsAny(); + while( pCnt ) + { + if( pCnt->IsLayoutFrm() ) + { + SwFrm* pTmp = ((SwLayoutFrm*)pCnt)->ContainsAny(); + while( pTmp && ((SwLayoutFrm*)pCnt)->IsAnLower( pTmp ) ) + { + pTmp->Prepare( PREP_MOVEFTN ); + (pTmp->Frm().*fnRect->fnSetHeight)(0); + (pTmp->Prt().*fnRect->fnSetHeight)(0); + pTmp = pTmp->FindNext(); + } + } + else + pCnt->Prepare( PREP_MOVEFTN ); + (pCnt->Frm().*fnRect->fnSetHeight)(0); + (pCnt->Prt().*fnRect->fnSetHeight)(0); + pCnt = pCnt->GetNext(); + } + (pFtn->Frm().*fnRect->fnSetHeight)(0); + (pFtn->Prt().*fnRect->fnSetHeight)(0); + pFtn->Calc(); + pFtn->GetUpper()->Calc(); + + if( bCalc ) + { + SwTxtFtn *pAttr = pFtn->GetAttr(); + pCnt = pFtn->ContainsAny(); + sal_Bool bUnlock = !pFtn->IsBackMoveLocked(); + pFtn->LockBackMove(); + + // --> OD 2005-05-18 #i49383# - disable unlock of position of + // lower objects during format of footnote content. + pFtn->KeepLockPosOfLowerObjs(); + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// SwLayNotify aFtnFrmNotitfy( pFtn ); + // <-- + + while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr ) + { + pCnt->_InvalidatePos(); + pCnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + { + // restart format with first content + pCnt = pFtn->ContainsAny(); + continue; + } + } + // <-- + if( pCnt->IsSctFrm() ) + { // Wenn es sich um einen nichtleeren Bereich handelt, + // iterieren wir auch ueber seinen Inhalt + SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny(); + if( pTmp ) + pCnt = pTmp; + else + pCnt = pCnt->FindNext(); + } + else + pCnt = pCnt->FindNext(); + } + if( bUnlock ) + { + pFtn->UnlockBackMove(); + if( !pFtn->ContainsAny() && !pFtn->IsColLocked() ) + { + pFtn->Cut(); + delete pFtn; + // --> OD 2004-06-10 #i21478# + pFtn = 0L; + } + } + // --> OD 2005-05-18 #i49383# + if ( pFtn ) + { + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // enable lock of lower object position before format of footnote frame. + pFtn->UnlockPosOfLowerObjs(); + pFtn->Calc(); +// pFtn->UnlockPosOfLowerObjs(); + // <-- + } + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// else +// { +// aFtnFrmNotitfy.FrmDeleted(); +// } + // <-- + } + } + else + { OSL_ENSURE( !pFtn->GetMaster() && !pFtn->GetFollow(), + "DelFtn und Master/Follow?" ); + delete pFtn; + // --> OD 2004-06-10 #i21478# + pFtn = 0L; + } + + // --> OD 2004-06-10 #i21478# + if ( pFtn ) + { + pLastInsertedFtn = pFtn; + } + } + + // --> OD 2004-06-10 #i21478# - format content of footnote following + // the new inserted ones. + if ( bCalc && pLastInsertedFtn ) + { + if ( pLastInsertedFtn->GetNext() ) + { + SwFtnFrm* pNextFtn = static_cast<SwFtnFrm*>(pLastInsertedFtn->GetNext()); + SwTxtFtn* pAttr = pNextFtn->GetAttr(); + SwFrm* pCnt = pNextFtn->ContainsAny(); + + sal_Bool bUnlock = !pNextFtn->IsBackMoveLocked(); + pNextFtn->LockBackMove(); + // --> OD 2005-05-18 #i49383# - disable unlock of position of + // lower objects during format of footnote content. + pNextFtn->KeepLockPosOfLowerObjs(); + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// SwLayNotify aFtnFrmNotitfy( pNextFtn ); + // <-- + + while ( pCnt && pCnt->FindFtnFrm()->GetAttr() == pAttr ) + { + pCnt->_InvalidatePos(); + pCnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + { + // restart format with first content + pCnt = pNextFtn->ContainsAny(); + continue; + } + } + // <-- + if( pCnt->IsSctFrm() ) + { // Wenn es sich um einen nichtleeren Bereich handelt, + // iterieren wir auch ueber seinen Inhalt + SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny(); + if( pTmp ) + pCnt = pTmp; + else + pCnt = pCnt->FindNext(); + } + else + pCnt = pCnt->FindNext(); + } + if( bUnlock ) + { + pNextFtn->UnlockBackMove(); + } + // --> OD 2005-05-18 #i49383# + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // enable lock of lower object position before format of footnote frame. + pNextFtn->UnlockPosOfLowerObjs(); + pNextFtn->Calc(); +// pNextFtn->UnlockPosOfLowerObjs(); + // <-- + } + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::MoveFtns() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::MoveFtns( const SwCntntFrm *pSrc, SwCntntFrm *pDest, + SwTxtFtn *pAttr ) +{ + if( ( GetFmt()->GetDoc()->GetFtnInfo().ePos == FTNPOS_CHAPTER && + (!GetUpper()->IsSctFrm() || !((SwSectionFrm*)GetUpper())->IsFtnAtEnd())) + || pAttr->GetFtn().IsEndNote() ) + return; + + OSL_ENSURE( this == pSrc->FindFtnBossFrm( sal_True ), + "SwPageFrm::MoveFtns: source frame isn't on that FtnBoss" ); + + SwFtnFrm *pFtn = FindFirstFtn(); + if( pFtn ) + { + ChangeFtnRef( pSrc, pAttr, pDest ); + SwFtnBossFrm *pDestBoss = pDest->FindFtnBossFrm( sal_True ); + OSL_ENSURE( pDestBoss, "+SwPageFrm::MoveFtns: no destination boss" ); + if( pDestBoss ) // robust + { + SvPtrarr aFtnArr( 5, 5 ); + pDestBoss->_CollectFtns( pDest, pFtn, aFtnArr ); + if ( aFtnArr.Count() ) + { + pDestBoss->_MoveFtns( aFtnArr, sal_True ); + SwPageFrm* pSrcPage = FindPageFrm(); + SwPageFrm* pDestPage = pDestBoss->FindPageFrm(); + // Nur beim Seitenwechsel FtnNum Updaten + if( pSrcPage != pDestPage ) + { + if( pSrcPage->GetPhyPageNum() > pDestPage->GetPhyPageNum() ) + pSrcPage->UpdateFtnNum(); + pDestPage->UpdateFtnNum(); + } + } + } + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::RearrangeFtns() +|* +|*************************************************************************/ + + +void SwFtnBossFrm::RearrangeFtns( const SwTwips nDeadLine, const sal_Bool bLock, + const SwTxtFtn *pAttr ) +{ + //Alle Fussnoten der Spalte/Seite dergestalt anformatieren, + //dass sie ggf. die Spalte/Seite wechseln. + + SwSaveFtnHeight aSave( this, nDeadLine ); + SwFtnFrm *pFtn = FindFirstFtn(); + if( pFtn && pFtn->GetPrev() && bLock ) + { + SwFtnFrm* pFirst = (SwFtnFrm*)pFtn->GetUpper()->Lower(); + SwFrm* pCntnt = pFirst->ContainsAny(); + if( pCntnt ) + { + sal_Bool bUnlock = !pFirst->IsBackMoveLocked(); + pFirst->LockBackMove(); + pFirst->Calc(); + pCntnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCntnt->IsTxtFrm() && pCntnt->IsValid() ) + { + SwObjectFormatter::FormatObjsAtFrm( *pCntnt, + *(pCntnt->FindPageFrm()) ); + } + // <-- + if( bUnlock ) + pFirst->UnlockBackMove(); + } + pFtn = FindFirstFtn(); + } + SwDoc *pDoc = GetFmt()->GetDoc(); + const sal_uLong nFtnPos = pAttr ? ::lcl_FindFtnPos( pDoc, pAttr ) : 0; + SwFrm *pCnt = pFtn ? pFtn->ContainsAny() : 0; + if ( pCnt ) + { + sal_Bool bMore = sal_True; + sal_Bool bStart = pAttr == 0; // wenn kein Attribut uebergeben wird, alle bearbeiten + // --> OD 2005-05-18 #i49383# - disable unlock of position of + // lower objects during format of footnote and footnote content. + SwFtnFrm* pLastFtnFrm( 0L ); + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// SwLayNotify* pFtnFrmNotify( 0L ); + // footnote frame needs to be locked, if <bLock> isn't set. + bool bUnlockLastFtnFrm( false ); + // <-- + do + { + if( !bStart ) + bStart = ::lcl_FindFtnPos( pDoc, pCnt->FindFtnFrm()->GetAttr() ) + == nFtnPos; + if( bStart ) + { + pCnt->_InvalidatePos(); + pCnt->_InvalidateSize(); + pCnt->Prepare( PREP_ADJUST_FRM ); + SwFtnFrm* pFtnFrm = pCnt->FindFtnFrm(); + // --> OD 2005-05-18 #i49383# + if ( pFtnFrm != pLastFtnFrm ) + { + if ( pLastFtnFrm ) + { + if ( !bLock && bUnlockLastFtnFrm ) + { + pLastFtnFrm->ColUnlock(); + } + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // enable lock of lower object position before format of footnote frame. + pLastFtnFrm->UnlockPosOfLowerObjs(); + pLastFtnFrm->Calc(); +// pLastFtnFrm->UnlockPosOfLowerObjs(); + // no extra notify for footnote frame +// delete pFtnFrmNotify; + // <-- + if ( !bLock && bUnlockLastFtnFrm && + !pLastFtnFrm->GetLower() && + !pLastFtnFrm->IsColLocked() && + !pLastFtnFrm->IsBackMoveLocked() ) + { + pLastFtnFrm->Cut(); + delete pLastFtnFrm; + pLastFtnFrm = 0L; + } + } + if ( !bLock ) + { + bUnlockLastFtnFrm = !pFtnFrm->IsColLocked(); + pFtnFrm->ColLock(); + } + pFtnFrm->KeepLockPosOfLowerObjs(); + pLastFtnFrm = pFtnFrm; + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// pFtnFrmNotify = new SwLayNotify( pLastFtnFrm ); + // <-- + } + // <-- + // OD 30.10.2002 #97265# - invalidate position of footnote + // frame, if it's below its footnote container, in order to + // assure its correct position, probably calculating its previous + // footnote frames. + { + SWRECTFN( this ); + SwFrm* aFtnContFrm = pFtnFrm->GetUpper(); + if ( (pFtnFrm->Frm().*fnRect->fnTopDist)((aFtnContFrm->*fnRect->fnGetPrtBottom)()) > 0 ) + { + pFtnFrm->_InvalidatePos(); + } + } + if ( bLock ) + { + sal_Bool bUnlock = !pFtnFrm->IsBackMoveLocked(); + pFtnFrm->LockBackMove(); + pFtnFrm->Calc(); + pCnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + { + // restart format with first content + pCnt = pFtn->ContainsAny(); + continue; + } + } + // <-- + if( bUnlock ) + { + pFtnFrm->UnlockBackMove(); + if( !pFtnFrm->Lower() && + !pFtnFrm->IsColLocked() ) + { + // --> OD 2005-08-10 #i49383# + OSL_ENSURE( pLastFtnFrm == pFtnFrm, + "<SwFtnBossFrm::RearrangeFtns(..)> - <pLastFtnFrm> != <pFtnFrm>" ); + pLastFtnFrm = 0L; + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // no extra notify for footnote frame +// pFtnFrmNotify->FrmDeleted(); +// delete pFtnFrmNotify; + // <-- + pFtnFrm->Cut(); + delete pFtnFrm; + } + } + } + else + { + pFtnFrm->Calc(); + pCnt->Calc(); + // --> OD 2005-05-17 #i49383# - format anchored objects + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + { + // restart format with first content + pCnt = pFtn->ContainsAny(); + continue; + } + } + // <-- + } + } + SwSectionFrm *pDel = NULL; + if( pCnt->IsSctFrm() ) + { + SwFrm* pTmp = ((SwSectionFrm*)pCnt)->ContainsAny(); + if( pTmp ) + { + pCnt = pTmp; + continue; + } + pDel = (SwSectionFrm*)pCnt; + } + if ( pCnt->GetNext() ) + pCnt = pCnt->GetNext(); + else + { + pCnt = pCnt->FindNext(); + if ( pCnt ) + { + SwFtnFrm* pFtnFrm = pCnt->FindFtnFrm(); + if( pFtnFrm->GetRef()->FindFtnBossFrm( + pFtnFrm->GetAttr()->GetFtn().IsEndNote() ) != this ) + bMore = sal_False; + } + else + bMore = sal_False; + } + if( pDel ) + { + pDel->Cut(); + delete pDel; + } + if ( bMore ) + { + //Nicht weiter als bis zur angegebenen Fussnote, falls eine + //angegeben wurde. + if ( pAttr && + (::lcl_FindFtnPos( pDoc, + pCnt->FindFtnFrm()->GetAttr()) > nFtnPos ) ) + bMore = sal_False; + } + } while ( bMore ); + // --> OD 2005-05-18 #i49383# + if ( pLastFtnFrm ) + { + if ( !bLock && bUnlockLastFtnFrm ) + { + pLastFtnFrm->ColUnlock(); + } + // --> OD 2006-02-02 #i57914# - adjust fix #i49383# + // enable lock of lower object position before format of footnote frame. + pLastFtnFrm->UnlockPosOfLowerObjs(); + pLastFtnFrm->Calc(); +// pLastFtnFrm->UnlockPosOfLowerObjs(); + // no extra notify for footnote frame +// delete pFtnFrmNotify; + // <-- + if ( !bLock && bUnlockLastFtnFrm && + !pLastFtnFrm->GetLower() && + !pLastFtnFrm->IsColLocked() && + !pLastFtnFrm->IsBackMoveLocked() ) + { + pLastFtnFrm->Cut(); + delete pLastFtnFrm; + } + } + // <-- + } +} + +/************************************************************************* +|* +|* SwPageFrm::UpdateFtnNum() +|* +|*************************************************************************/ + +void SwPageFrm::UpdateFtnNum() +{ + //Seitenweise Numerierung nur wenn es am Dokument so eingestellt ist. + if ( GetFmt()->GetDoc()->GetFtnInfo().eNum != FTNNUM_PAGE ) + return; + + SwLayoutFrm* pBody = FindBodyCont(); + if( !pBody || !pBody->Lower() ) + return; + + SwCntntFrm* pCntnt = pBody->ContainsCntnt(); + sal_uInt16 nNum = 0; + + while( pCntnt && pCntnt->FindPageFrm() == this ) + { + if( ((SwTxtFrm*)pCntnt)->HasFtn() ) + { + SwFtnBossFrm* pBoss = pCntnt->FindFtnBossFrm( sal_True ); + if( pBoss->GetUpper()->IsSctFrm() && + ((SwSectionFrm*)pBoss->GetUpper())->IsOwnFtnNum() ) + pCntnt = ((SwSectionFrm*)pBoss->GetUpper())->FindLastCntnt(); + else + { + SwFtnFrm* pFtn = (SwFtnFrm*)pBoss->FindFirstFtn( pCntnt ); + while( pFtn ) + { + SwTxtFtn* pTxtFtn = pFtn->GetAttr(); + if( !pTxtFtn->GetFtn().IsEndNote() && + !pTxtFtn->GetFtn().GetNumStr().Len() && + !pFtn->GetMaster() && + (pTxtFtn->GetFtn().GetNumber() != ++nNum) ) + pTxtFtn->SetNumber( nNum ); + if ( pFtn->GetNext() ) + pFtn = (SwFtnFrm*)pFtn->GetNext(); + else + { + SwFtnBossFrm* pTmpBoss = pFtn->FindFtnBossFrm( sal_True ); + if( pTmpBoss ) + { + SwPageFrm* pPage = pTmpBoss->FindPageFrm(); + pFtn = NULL; + lcl_NextFtnBoss( pTmpBoss, pPage, sal_False ); + SwFtnContFrm *pCont = pTmpBoss->FindNearestFtnCont(); + if ( pCont ) + pFtn = (SwFtnFrm*)pCont->Lower(); + } + } + if( pFtn && pFtn->GetRef() != pCntnt ) + pFtn = NULL; + } + } + } + pCntnt = pCntnt->FindNextCnt(); + } +} + +/************************************************************************* +|* +|* SwFtnBossFrm::SetFtnDeadLine() +|* +|*************************************************************************/ + +void SwFtnBossFrm::SetFtnDeadLine( const SwTwips nDeadLine ) +{ + SwFrm *pBody = FindBodyCont(); + pBody->Calc(); + + SwFrm *pCont = FindFtnCont(); + const SwTwips nMax = nMaxFtnHeight;//Aktuelle MaxHeight nicht ueberschreiten. + SWRECTFN( this ) + if ( pCont ) + { + pCont->Calc(); + nMaxFtnHeight = -(pCont->Frm().*fnRect->fnBottomDist)( nDeadLine ); + } + else + nMaxFtnHeight = -(pBody->Frm().*fnRect->fnBottomDist)( nDeadLine ); + + const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + nMaxFtnHeight += pBody->Grow( LONG_MAX, sal_True ); + if ( IsInSct() ) + nMaxFtnHeight += FindSctFrm()->Grow( LONG_MAX, sal_True ); + + if ( nMaxFtnHeight < 0 ) + nMaxFtnHeight = 0; + if ( nMax != LONG_MAX && nMaxFtnHeight > nMax ) + nMaxFtnHeight = nMax; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::GetVarSpace() +|* +|*************************************************************************/ +SwTwips SwFtnBossFrm::GetVarSpace() const +{ + //Fuer Seiten soll ein Wert von 20% der Seitenhoehe nicht unterschritten + //werden (->AMA: was macht MS da?) + //->AMA: Was ist da fuer Bereiche sinnvoll (und kompatibel zu MS ;-)? + //AMA: MS kennt scheinbar kein Begrenzung, die Fussnoten nehmen durchaus + // die ganze Seite/Spalte ein. + + const SwPageFrm* pPg = FindPageFrm(); + OSL_ENSURE( pPg || IsInSct(), "Footnote lost page" ); + + const SwFrm *pBody = FindBodyCont(); + SwTwips nRet; + if( pBody ) + { + SWRECTFN( this ) + if( IsInSct() ) + { + nRet = 0; + SwTwips nTmp = (*fnRect->fnYDiff)( (pBody->*fnRect->fnGetPrtTop)(), + (Frm().*fnRect->fnGetTop)() ); + const SwSectionFrm* pSect = FindSctFrm(); + // Endnotes in a ftncontainer causes a deadline: + // the bottom of the last contentfrm + if( pSect->IsEndnAtEnd() ) // endnotes allowed? + { + OSL_ENSURE( !Lower() || !Lower()->GetNext() || Lower()->GetNext()-> + IsFtnContFrm(), "FtnContainer exspected" ); + const SwFtnContFrm* pCont = Lower() ? + (SwFtnContFrm*)Lower()->GetNext() : 0; + if( pCont ) + { + SwFtnFrm* pFtn = (SwFtnFrm*)pCont->Lower(); + while( pFtn) + { + if( pFtn->GetAttr()->GetFtn().IsEndNote() ) + { // endnote found + SwFrm* pFrm = ((SwLayoutFrm*)Lower())->Lower(); + if( pFrm ) + { + while( pFrm->GetNext() ) + pFrm = pFrm->GetNext(); // last cntntfrm + nTmp += (*fnRect->fnYDiff)( + (Frm().*fnRect->fnGetTop)(), + (pFrm->Frm().*fnRect->fnGetBottom)() ); + } + break; + } + pFtn = (SwFtnFrm*)pFtn->GetNext(); + } + } + } + if( nTmp < nRet ) + nRet = nTmp; + } + else + nRet = - (pPg->Prt().*fnRect->fnGetHeight)()/5; + nRet += (pBody->Frm().*fnRect->fnGetHeight)(); + if( nRet < 0 ) + nRet = 0; + } + else + nRet = 0; + if ( IsPageFrm() ) + { + const ViewShell *pSh = getRootFrm() ? getRootFrm()->GetCurrShell() : 0; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + nRet += BROWSE_HEIGHT - Frm().Height(); + } + return nRet; +} + +/************************************************************************* +|* +|* SwFtnBossFrm::NeighbourhoodAdjustment(SwFrm*) +|* +|* gibt Auskunft, ob die Groessenveraenderung von pFrm von AdjustNeighbourhood(...) +|* oder von Grow/Shrink(..) verarbeitet werden sollte. +|* Bei einem PageFrm oder in Spalten direkt unterhalb der Seite muss AdjustNei.. +|* gerufen werden, in Rahmenspalten Grow/Shrink. +|* Spannend sind die spaltigen Bereiche: Wenn es in der Spalte einen Fussnotencontainer +|* gibt und die Fussnoten nicht vom Bereich eingesammelt werden, ist ein Adjust.., +|* ansonsten ein Grow/Shrink notwendig. +|* +|*************************************************************************/ + +sal_uInt8 SwFtnBossFrm::_NeighbourhoodAdjustment( const SwFrm* ) const +{ + sal_uInt8 nRet = NA_ONLY_ADJUST; + if( GetUpper() && !GetUpper()->IsPageBodyFrm() ) + { + // Spaltige Rahmen erfordern Grow/Shrink + if( GetUpper()->IsFlyFrm() ) + nRet = NA_GROW_SHRINK; + else + { + OSL_ENSURE( GetUpper()->IsSctFrm(), "NeighbourhoodAdjustment: Unexspected Upper" ); + if( !GetNext() && !GetPrev() ) + nRet = NA_GROW_ADJUST; // section with a single column (FtnAtEnd) + else + { + const SwFrm* pTmp = Lower(); + OSL_ENSURE( pTmp, "NeighbourhoodAdjustment: Missing Lower()" ); + if( !pTmp->GetNext() ) + nRet = NA_GROW_SHRINK; + else if( !GetUpper()->IsColLocked() ) + nRet = NA_ADJUST_GROW; + OSL_ENSURE( !pTmp->GetNext() || pTmp->GetNext()->IsFtnContFrm(), + "NeighbourhoodAdjustment: Who's that guy?" ); + } + } + } + return nRet; +} + +/************************************************************************* +|* +|* SwPageFrm::SetColMaxFtnHeight() +|* +|*************************************************************************/ +void SwPageFrm::SetColMaxFtnHeight() +{ + SwLayoutFrm *pBody = FindBodyCont(); + if( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() ) + { + SwColumnFrm* pCol = (SwColumnFrm*)pBody->Lower(); + do + { + pCol->SetMaxFtnHeight( GetMaxFtnHeight() ); + pCol = (SwColumnFrm*)pCol->GetNext(); + } while ( pCol ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::MoveLowerFtns +|* +|*************************************************************************/ + + +sal_Bool SwLayoutFrm::MoveLowerFtns( SwCntntFrm *pStart, SwFtnBossFrm *pOldBoss, + SwFtnBossFrm *pNewBoss, const sal_Bool bFtnNums ) +{ + SwDoc *pDoc = GetFmt()->GetDoc(); + if ( !pDoc->GetFtnIdxs().Count() ) + return sal_False; + if( pDoc->GetFtnInfo().ePos == FTNPOS_CHAPTER && + ( !IsInSct() || !FindSctFrm()->IsFtnAtEnd() ) ) + return sal_True; + + if ( !pNewBoss ) + pNewBoss = FindFtnBossFrm( sal_True ); + if ( pNewBoss == pOldBoss ) + return sal_False; + + sal_Bool bMoved = sal_False; + if( !pStart ) + pStart = ContainsCntnt(); + + SvPtrarr aFtnArr( 5, 5 ); + + while ( IsAnLower( pStart ) ) + { + if ( ((SwTxtFrm*)pStart)->HasFtn() ) + { + // OD 03.04.2003 #108446# - To avoid unnecessary moves of footnotes + // use new parameter <_bCollectOnlyPreviousFtn> (4th parameter of + // method <SwFtnBossFrm::CollectFtn(..)>) to control, that only + // footnotes have to be collected, that are positioned before the + // new dedicated footnote boss frame. + pNewBoss->CollectFtns( pStart, pOldBoss, aFtnArr, sal_True ); + } + pStart = pStart->GetNextCntntFrm(); + } + + OSL_ENSURE( pOldBoss->IsInSct() == pNewBoss->IsInSct(), + "MoveLowerFtns: Section confusion" ); + SvPtrarr *pFtnArr; + SwLayoutFrm* pNewChief = 0; + SwLayoutFrm* pOldChief = 0; + if( pStart && pOldBoss->IsInSct() && ( pOldChief = pOldBoss->FindSctFrm() ) + != ( pNewChief = pNewBoss->FindSctFrm() ) ) + { + pFtnArr = new SvPtrarr( 5, 5 ); + pOldChief = pOldBoss->FindFtnBossFrm( sal_True ); + pNewChief = pNewBoss->FindFtnBossFrm( sal_True ); + while( pOldChief->IsAnLower( pStart ) ) + { + if ( ((SwTxtFrm*)pStart)->HasFtn() ) + ((SwFtnBossFrm*)pNewChief)->CollectFtns( pStart, + (SwFtnBossFrm*)pOldBoss, *pFtnArr ); + pStart = pStart->GetNextCntntFrm(); + } + if( !pFtnArr->Count() ) + { + delete pFtnArr; + pFtnArr = NULL; + } + } + else + pFtnArr = NULL; + + if ( aFtnArr.Count() || pFtnArr ) + { + if( aFtnArr.Count() ) + pNewBoss->_MoveFtns( aFtnArr, sal_True ); + if( pFtnArr ) + { + ((SwFtnBossFrm*)pNewChief)->_MoveFtns( *pFtnArr, sal_True ); + delete pFtnArr; + } + bMoved = sal_True; + + // Nur bei einem Seitenwechsel muss die FtnNum neu berechnet werden + if ( bFtnNums ) + { + SwPageFrm* pOldPage = pOldBoss->FindPageFrm(); + SwPageFrm* pNewPage =pNewBoss->FindPageFrm(); + if( pOldPage != pNewPage ) + { + pOldPage->UpdateFtnNum(); + pNewPage->UpdateFtnNum(); + } + } + } + return bMoved; +} + +/************************************************************************* +|* +|* SwLayoutFrm::MoveFtnCntFwd() +|* +|*************************************************************************/ + + +sal_Bool SwCntntFrm::MoveFtnCntFwd( sal_Bool bMakePage, SwFtnBossFrm *pOldBoss ) +{ + OSL_ENSURE( IsInFtn(), "Keine Ftn." ); + SwLayoutFrm *pFtn = FindFtnFrm(); + + // The first paragraph in the first footnote in the first column in the + // sectionfrm at the top of the page has not to move forward, if the + // columnbody is empty. + if( pOldBoss->IsInSct() && !pOldBoss->GetIndPrev() && !GetIndPrev() && + !pFtn->GetPrev() ) + { + SwLayoutFrm* pBody = pOldBoss->FindBodyCont(); + if( !pBody || !pBody->Lower() ) + return sal_True; + } + + //fix(9538): Wenn die Ftn noch Nachbarn hinter sich hat, so muessen + //diese ersteinmal verschwinden. + SwLayoutFrm *pNxt = (SwLayoutFrm*)pFtn->GetNext(); + SwLayoutFrm *pLst = 0; + while ( pNxt ) + { + while ( pNxt->GetNext() ) + pNxt = (SwLayoutFrm*)pNxt->GetNext(); + if ( pNxt == pLst ) + pNxt = 0; + else + { pLst = pNxt; + SwCntntFrm *pCnt = pNxt->ContainsCntnt(); + if( pCnt ) + pCnt->MoveFtnCntFwd( sal_True, pOldBoss ); + pNxt = (SwLayoutFrm*)pFtn->GetNext(); + } + } + + sal_Bool bSamePage = sal_True; + SwLayoutFrm *pNewUpper = + GetLeaf( bMakePage ? MAKEPAGE_INSERT : MAKEPAGE_NONE, sal_True ); + + if ( pNewUpper ) + { + sal_Bool bSameBoss = sal_True; + SwFtnBossFrm * const pNewBoss = pNewUpper->FindFtnBossFrm(); + //Wechseln wir die Spalte/Seite? + if ( sal_False == ( bSameBoss = pNewBoss == pOldBoss ) ) + { + bSamePage = pOldBoss->FindPageFrm() == pNewBoss->FindPageFrm(); // Seitenwechsel? + pNewUpper->Calc(); + } + + //Das Layoutblatt, dass wir fuer Fussnoten bekommen ist entweder + //ein Fussnotencontainer oder eine Fussnote + //Wenn es eine Fussnote ist, und sie die gleiche Fussnotenreferez + //wie der alte Upper hat, so moven wir uns direkt hinein. + //Ist die Referenz einen andere oder ist es ein Container, so wird + //eine neue Fussnote erzeugt und in den Container gestellt. + // Wenn wir in einem Bereich innerhalb der Fussnote sind, muss + // SectionFrame noch angelegt werden. + SwFtnFrm* pTmpFtn = pNewUpper->IsFtnFrm() ? ((SwFtnFrm*)pNewUpper) : 0; + if( !pTmpFtn ) + { + OSL_ENSURE( pNewUpper->IsFtnContFrm(), "Neuer Upper kein FtnCont."); + SwFtnContFrm *pCont = (SwFtnContFrm*)pNewUpper; + + //Fussnote erzeugen. + SwFtnFrm *pOld = FindFtnFrm(); + pTmpFtn = new SwFtnFrm( pOld->GetFmt()->GetDoc()->GetDfltFrmFmt(), + pOld, pOld->GetRef(), pOld->GetAttr() ); + //Verkettung der Fussnoten. + if ( pOld->GetFollow() ) + { + pTmpFtn->SetFollow( pOld->GetFollow() ); + pOld->GetFollow()->SetMaster( pTmpFtn ); + } + pOld->SetFollow( pTmpFtn ); + pTmpFtn->SetMaster( pOld ); + SwFrm* pNx = pCont->Lower(); + if( pNx && pTmpFtn->GetAttr()->GetFtn().IsEndNote() ) + while(pNx && !((SwFtnFrm*)pNx)->GetAttr()->GetFtn().IsEndNote()) + pNx = pNx->GetNext(); + pTmpFtn->Paste( pCont, pNx ); + pTmpFtn->Calc(); + } + OSL_ENSURE( pTmpFtn->GetAttr() == FindFtnFrm()->GetAttr(), "Wrong Footnote!" ); + // Bereiche in Fussnoten beduerfen besonderer Behandlung + SwLayoutFrm *pNewUp = pTmpFtn; + if( IsInSct() ) + { + SwSectionFrm* pSect = FindSctFrm(); + // Bereich in Fussnote (oder nur Fussnote in Bereich)? + if( pSect->IsInFtn() ) + { + if( pTmpFtn->Lower() && pTmpFtn->Lower()->IsSctFrm() && + pSect->GetFollow() == (SwSectionFrm*)pTmpFtn->Lower() ) + pNewUp = (SwSectionFrm*)pTmpFtn->Lower(); + else + { + pNewUp = new SwSectionFrm( *pSect, sal_False ); + pNewUp->InsertBefore( pTmpFtn, pTmpFtn->Lower() ); + static_cast<SwSectionFrm*>(pNewUp)->Init(); + pNewUp->Frm().Pos() = pTmpFtn->Frm().Pos(); + pNewUp->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. + + // Wenn unser Bereichsframe einen Nachfolger hat, so muss dieser + // umgehaengt werden hinter den neuen Follow der Bereichsframes. + SwFrm* pTmp = pSect->GetNext(); + if( pTmp ) + { + SwFlowFrm* pTmpNxt; + if( pTmp->IsCntntFrm() ) + pTmpNxt = (SwCntntFrm*)pTmp; + else if( pTmp->IsSctFrm() ) + pTmpNxt = (SwSectionFrm*)pTmp; + else + { + OSL_ENSURE( pTmp->IsTabFrm(), "GetNextSctLeaf: Wrong Type" ); + pTmpNxt = (SwTabFrm*)pTmp; + } + pTmpNxt->MoveSubTree( pTmpFtn, pNewUp->GetNext() ); + } + } + } + } + + MoveSubTree( pNewUp, pNewUp->Lower() ); + + if( !bSameBoss ) + Prepare( PREP_BOSS_CHGD ); + } + return bSamePage; +} + +/************************************************************************* +|* +|* class SwSaveFtnHeight +|* +|*************************************************************************/ + + +SwSaveFtnHeight::SwSaveFtnHeight( SwFtnBossFrm *pBs, const SwTwips nDeadLine ) : + pBoss( pBs ), + nOldHeight( pBs->GetMaxFtnHeight() ) +{ + pBoss->SetFtnDeadLine( nDeadLine ); + nNewHeight = pBoss->GetMaxFtnHeight(); +} + + + +SwSaveFtnHeight::~SwSaveFtnHeight() +{ + //Wenn zwischendurch jemand an der DeadLine gedreht hat, so lassen wir + //ihm seinen Spass! + if ( nNewHeight == pBoss->GetMaxFtnHeight() ) + pBoss->nMaxFtnHeight = nOldHeight; +} + + +#if OSL_DEBUG_LEVEL > 1 +//JP 15.10.2001: in a non pro version test if the attribute has the same +// meaning which his reference is + +// Normally, the pRef member and the GetRefFromAttr() result has to be +// identically. Sometimes footnote will be moved from a master to its follow, +// but the GetRef() is called first, so we have to ignore a master/follow +// mismatch. + +const SwCntntFrm* SwFtnFrm::GetRef() const +{ + const SwCntntFrm* pRefAttr = GetRefFromAttr(); + OSL_ENSURE( pRef == pRefAttr || pRef->IsAnFollow( pRefAttr ) + || pRefAttr->IsAnFollow( pRef ), + "access to deleted Frame? pRef != pAttr->GetRef()" ); + return pRef; +} + +SwCntntFrm* SwFtnFrm::GetRef() +{ + const SwCntntFrm* pRefAttr = GetRefFromAttr(); + OSL_ENSURE( pRef == pRefAttr || pRef->IsAnFollow( pRefAttr ) + || pRefAttr->IsAnFollow( pRef ), + "access to deleted Frame? pRef != pAttr->GetRef()" ); + return pRef; +} + +#endif + +const SwCntntFrm* SwFtnFrm::GetRefFromAttr() const +{ + SwFtnFrm* pThis = (SwFtnFrm*)this; + return pThis->GetRefFromAttr(); +} + +SwCntntFrm* SwFtnFrm::GetRefFromAttr() +{ + OSL_ENSURE( pAttr, "invalid Attribute" ); + SwTxtNode& rTNd = (SwTxtNode&)pAttr->GetTxtNode(); + SwPosition aPos( rTNd, SwIndex( &rTNd, *pAttr->GetStart() )); + SwCntntFrm* pCFrm = rTNd.getLayoutFrm( getRootFrm(), 0, &aPos, sal_False ); + return pCFrm; +} + +/** search for last content in the current footnote frame + + OD 2005-12-02 #i27138# + + @author OD +*/ +SwCntntFrm* SwFtnFrm::FindLastCntnt() +{ + SwCntntFrm* pLastCntntFrm( 0L ); + + // find last lower, which is a content frame or contains content. + // hidden text frames, empty sections and empty tables have to be skipped. + SwFrm* pLastLowerOfFtn( GetLower() ); + SwFrm* pTmpLastLower( pLastLowerOfFtn ); + while ( pTmpLastLower && pTmpLastLower->GetNext() ) + { + pTmpLastLower = pTmpLastLower->GetNext(); + if ( ( pTmpLastLower->IsTxtFrm() && + !static_cast<SwTxtFrm*>(pTmpLastLower)->IsHiddenNow() ) || + ( pTmpLastLower->IsSctFrm() && + static_cast<SwSectionFrm*>(pTmpLastLower)->GetSection() && + static_cast<SwSectionFrm*>(pTmpLastLower)->ContainsCntnt() ) || + ( pTmpLastLower->IsTabFrm() && + static_cast<SwTabFrm*>(pTmpLastLower)->ContainsCntnt() ) ) + { + pLastLowerOfFtn = pTmpLastLower; + } + } + + // determine last content frame depending on type of found last lower. + if ( pLastLowerOfFtn && pLastLowerOfFtn->IsTabFrm() ) + { + pLastCntntFrm = static_cast<SwTabFrm*>(pLastLowerOfFtn)->FindLastCntnt(); + } + else if ( pLastLowerOfFtn && pLastLowerOfFtn->IsSctFrm() ) + { + pLastCntntFrm = static_cast<SwSectionFrm*>(pLastLowerOfFtn)->FindLastCntnt(); + } + else + { + pLastCntntFrm = dynamic_cast<SwCntntFrm*>(pLastLowerOfFtn); + } + + return pLastCntntFrm; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/hffrm.cxx b/sw/source/core/layout/hffrm.cxx new file mode 100644 index 000000000000..b8168dca941a --- /dev/null +++ b/sw/source/core/layout/hffrm.cxx @@ -0,0 +1,796 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include "pagefrm.hxx" +#include "viewsh.hxx" +#include "doc.hxx" +#include <fmtcntnt.hxx> +#include <fmthdft.hxx> +#include <fmtfsize.hxx> +#include "viewopt.hxx" +#include "hffrm.hxx" +#include "rootfrm.hxx" +#include "txtfrm.hxx" +#include "sectfrm.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "dflyobj.hxx" +#include "frmfmt.hxx" +#include "ndindex.hxx" +#include "hfspacingitem.hxx" +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> +// --> OD 2005-03-03 #i43771# +#include <objectformatter.hxx> +// <-- + +extern sal_Bool bObjsDirect; //frmtool.cxx + +static SwTwips lcl_GetFrmMinHeight(const SwLayoutFrm & rFrm) +{ + const SwFmtFrmSize &rSz = rFrm.GetFmt()->GetFrmSize(); + SwTwips nMinHeight; + + switch (rSz.GetHeightSizeType()) + { + case ATT_MIN_SIZE: + nMinHeight = rSz.GetHeight(); + + break; + + default: + nMinHeight = 0; + } + + + return nMinHeight; +} + + +static SwTwips lcl_CalcContentHeight(SwLayoutFrm & frm) +{ + SwFrm* pFrm = frm.Lower(); + + SwTwips nRemaining = 0; + sal_uInt16 nNum = 0; + pFrm = frm.Lower(); + while ( pFrm ) + { + SwTwips nTmp; + + nTmp = pFrm->Frm().Height(); + nRemaining += nTmp; + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() ) + { + nTmp = ((SwTxtFrm*)pFrm)->GetParHeight() + - pFrm->Prt().Height(); + // Dieser TxtFrm waere gern ein bisschen groesser + nRemaining += nTmp; + } + else if( pFrm->IsSctFrm() && ((SwSectionFrm*)pFrm)->IsUndersized() ) + { + nTmp = ((SwSectionFrm*)pFrm)->Undersize(); + nRemaining += nTmp; + } + pFrm = pFrm->GetNext(); + + nNum++; + } + + return nRemaining; +} + +static void lcl_LayoutFrmEnsureMinHeight(SwLayoutFrm & rFrm, + const SwBorderAttrs * ) +{ + SwTwips nMinHeight = lcl_GetFrmMinHeight(rFrm); + + if (rFrm.Frm().Height() < nMinHeight) + { + rFrm.Grow(nMinHeight - rFrm.Frm().Height()); + } +} + +SwHeadFootFrm::SwHeadFootFrm( SwFrmFmt * pFmt, SwFrm* pSib, sal_uInt16 nTypeIn) + : SwLayoutFrm( pFmt, pSib ) +{ + nType = nTypeIn; + SetDerivedVert( sal_False ); + + const SwFmtCntnt &rCnt = pFmt->GetCntnt(); + + OSL_ENSURE( rCnt.GetCntntIdx(), "Kein Inhalt fuer Header." ); + + //Fuer Header Footer die Objekte gleich erzeugen lassen. + sal_Bool bOld = bObjsDirect; + bObjsDirect = sal_True; + sal_uLong nIndex = rCnt.GetCntntIdx()->GetIndex(); + ::_InsertCnt( this, pFmt->GetDoc(), ++nIndex ); + bObjsDirect = bOld; +} + +void SwHeadFootFrm::FormatPrt(SwTwips & nUL, const SwBorderAttrs * pAttrs) +{ + if (GetEatSpacing()) + { + /* The minimal height of the print area is the minimal height of the + frame without the height needed for borders and shadow. */ + SwTwips nMinHeight = lcl_GetFrmMinHeight(*this); + + nMinHeight -= pAttrs->CalcTop(); + nMinHeight -= pAttrs->CalcBottom(); + + /* If the minimal height of the print area is negative, try to + compensate by overlapping */ + SwTwips nOverlap = 0; + if (nMinHeight < 0) + { + nOverlap = -nMinHeight; + nMinHeight = 0; + } + + /* Calculate desired height of content. The minimal height has to be + adhered. */ + SwTwips nHeight; + + if ( ! HasFixSize() ) + nHeight = lcl_CalcContentHeight(*this); + else + nHeight = nMinHeight; + + if (nHeight < nMinHeight) + nHeight = nMinHeight; + + /* calculate initial spacing/line space */ + SwTwips nSpace, nLine; + + if (IsHeaderFrm()) + { + nSpace = pAttrs->CalcBottom(); + nLine = pAttrs->CalcBottomLine(); + } + else + { + nSpace = pAttrs->CalcTop(); + nLine = pAttrs->CalcTopLine(); + } + + /* calculate overlap and correct spacing */ + nOverlap += nHeight - nMinHeight; + if (nOverlap < nSpace - nLine) + nSpace -= nOverlap; + else + nSpace = nLine; + + /* calculate real vertical space between frame and print area */ + if (IsHeaderFrm()) + nUL = pAttrs->CalcTop() + nSpace; + else + nUL = pAttrs->CalcBottom() + nSpace; + + /* set print area */ + // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)> + SwTwips nLR = pAttrs->CalcLeft( this ) + pAttrs->CalcRight( this ); + + aPrt.Left(pAttrs->CalcLeft(this)); + + if (IsHeaderFrm()) + aPrt.Top(pAttrs->CalcTop()); + else + aPrt.Top(nSpace); + + aPrt.Width(aFrm.Width() - nLR); + + SwTwips nNewHeight; + + if (nUL < aFrm.Height()) + nNewHeight = aFrm.Height() - nUL; + else + nNewHeight = 0; + + aPrt.Height(nNewHeight); + + } + else + { + //Position einstellen. + aPrt.Left( pAttrs->CalcLeft( this ) ); + aPrt.Top ( pAttrs->CalcTop() ); + + //Sizes einstellen; die Groesse gibt der umgebende Frm vor, die + //die Raender werden einfach abgezogen. + // OD 23.01.2003 #106895# - add first parameter to <SwBorderAttrs::CalcRight(..)> + SwTwips nLR = pAttrs->CalcLeft( this ) + pAttrs->CalcRight( this ); + aPrt.Width ( aFrm.Width() - nLR ); + aPrt.Height( aFrm.Height()- nUL ); + + } + + bValidPrtArea = sal_True; +} + +void SwHeadFootFrm::FormatSize(SwTwips nUL, const SwBorderAttrs * pAttrs) +{ + if ( !HasFixSize() ) + { + if( !IsColLocked() ) + { + bValidSize = bValidPrtArea = sal_True; + + const SwTwips nBorder = nUL; + SwTwips nMinHeight = lcl_GetFrmMinHeight(*this); + nMinHeight -= pAttrs->CalcTop(); + nMinHeight -= pAttrs->CalcBottom(); + + if (nMinHeight < 0) + nMinHeight = 0; + + ColLock(); + + SwTwips nMaxHeight = LONG_MAX; + SwTwips nRemaining, nOldHeight; + // --> OD 2006-05-24 #i64301# + // use the position of the footer printing area to control invalidation + // of the first footer content. + Point aOldFooterPrtPos; + // <-- + + do + { + nOldHeight = Prt().Height(); + SwFrm* pFrm = Lower(); + // --> OD 2006-05-24 #i64301# + if ( pFrm && + aOldFooterPrtPos != ( Frm().Pos() + Prt().Pos() ) ) + { + pFrm->_InvalidatePos(); + aOldFooterPrtPos = Frm().Pos() + Prt().Pos(); + } + // <-- + while( pFrm ) + { + pFrm->Calc(); + // --> OD 2005-03-03 #i43771# - format also object anchored + // at the frame + // --> OD 2005-05-03 #i46941# - frame has to be valid. + // Note: frame could be invalid after calling its format, + // if it's locked + OSL_ENSURE( StackHack::IsLocked() || !pFrm->IsTxtFrm() || + pFrm->IsValid() || + static_cast<SwTxtFrm*>(pFrm)->IsJoinLocked(), + "<SwHeadFootFrm::FormatSize(..)> - text frame invalid and not locked." ); + if ( pFrm->IsTxtFrm() && pFrm->IsValid() ) + { + if ( !SwObjectFormatter::FormatObjsAtFrm( *pFrm, + *(pFrm->FindPageFrm()) ) ) + { + // restart format with first content + pFrm = Lower(); + continue; + } + } + // <-- + pFrm = pFrm->GetNext(); + } + nRemaining = 0; + pFrm = Lower(); + + while ( pFrm ) + { + nRemaining += pFrm->Frm().Height(); + + if( pFrm->IsTxtFrm() && + ((SwTxtFrm*)pFrm)->IsUndersized() ) + // Dieser TxtFrm waere gern ein bisschen groesser + nRemaining += ((SwTxtFrm*)pFrm)->GetParHeight() + - pFrm->Prt().Height(); + else if( pFrm->IsSctFrm() && + ((SwSectionFrm*)pFrm)->IsUndersized() ) + nRemaining += ((SwSectionFrm*)pFrm)->Undersize(); + pFrm = pFrm->GetNext(); + } + if ( nRemaining < nMinHeight ) + nRemaining = nMinHeight; + + SwTwips nDiff = nRemaining - nOldHeight; + + if( !nDiff ) + break; + if( nDiff < 0 ) + { + nMaxHeight = nOldHeight; + + if( nRemaining <= nMinHeight ) + nRemaining = ( nMaxHeight + nMinHeight + 1 ) / 2; + } + else + { + if (nOldHeight > nMinHeight) + nMinHeight = nOldHeight; + + if( nRemaining >= nMaxHeight ) + nRemaining = ( nMaxHeight + nMinHeight + 1 ) / 2; + } + + nDiff = nRemaining - nOldHeight; + + if ( nDiff ) + { + ColUnlock(); + if ( nDiff > 0 ) + { + if ( Grow( nDiff ) ) + { + pFrm = Lower(); + + while ( pFrm ) + { + if( pFrm->IsTxtFrm()) + { + SwTxtFrm * pTmpFrm = (SwTxtFrm*) pFrm; + if (pTmpFrm->IsUndersized() ) + { + pTmpFrm->InvalidateSize(); + pTmpFrm->Prepare(PREP_ADJUST_FRM); + } + } + /* #i3568# Undersized sections need to be + invalidated too. */ + else if (pFrm->IsSctFrm()) + { + SwSectionFrm * pTmpFrm = + (SwSectionFrm*) pFrm; + if (pTmpFrm->IsUndersized() ) + { + pTmpFrm->InvalidateSize(); + pTmpFrm->Prepare(PREP_ADJUST_FRM); + } + } + pFrm = pFrm->GetNext(); + } + } + } + else + Shrink( -nDiff ); + //Schnell auf dem kurzen Dienstweg die Position updaten. + + MakePos(); + ColLock(); + } + else + break; + //Unterkante des Uppers nicht ueberschreiten. + if ( GetUpper() && Frm().Height() ) + { + const SwTwips nDeadLine = GetUpper()->Frm().Top() + + GetUpper()->Prt().Bottom(); + const SwTwips nBot = Frm().Bottom(); + if ( nBot > nDeadLine ) + { + Frm().Bottom( nDeadLine ); + Prt().SSize().Height() = Frm().Height() - nBorder; + } + } + bValidSize = bValidPrtArea = sal_True; + } while( nRemaining<=nMaxHeight && nOldHeight!=Prt().Height() ); + ColUnlock(); + } + bValidSize = bValidPrtArea = sal_True; + } + else //if ( GetType() & 0x0018 ) + { + do + { + if ( Frm().Height() != pAttrs->GetSize().Height() ) + ChgSize( Size( Frm().Width(), pAttrs->GetSize().Height())); + bValidSize = sal_True; + MakePos(); + } while ( !bValidSize ); + } +} + +void SwHeadFootFrm::Format(const SwBorderAttrs * pAttrs) +{ + OSL_ENSURE( pAttrs, "SwFooterFrm::Format, pAttrs ist 0." ); + + if ( bValidPrtArea && bValidSize ) + return; + + if ( ! GetEatSpacing() && IsHeaderFrm()) + { + SwLayoutFrm::Format(pAttrs); + } + else + { + lcl_LayoutFrmEnsureMinHeight(*this, pAttrs); + + long nUL = pAttrs->CalcTop() + pAttrs->CalcBottom(); + + if ( !bValidPrtArea ) + FormatPrt(nUL, pAttrs); + + if ( !bValidSize ) + FormatSize(nUL, pAttrs); + } +} + +SwTwips SwHeadFootFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SwTwips nResult; + + if ( IsColLocked() ) + { + nResult = 0; + } + else if (!GetEatSpacing()) + { + nResult = SwLayoutFrm::GrowFrm(nDist, bTst, bInfo); + } + else + { + nResult = 0; + + SwBorderAttrAccess * pAccess = + new SwBorderAttrAccess( SwFrm::GetCache(), this ); + OSL_ENSURE(pAccess, "no border attributes"); + + SwBorderAttrs * pAttrs = pAccess->Get(); + + /* First assume the whole amount to grow can be provided by eating + spacing. */ + SwTwips nEat = nDist; + SwTwips nMaxEat; + + /* calculate maximum eatable spacing */ + if (IsHeaderFrm()) + nMaxEat = aFrm.Height() - aPrt.Top() - aPrt.Height() - pAttrs->CalcBottomLine(); + else + nMaxEat = aPrt.Top() - pAttrs->CalcTopLine(); + + delete pAccess; + + if (nMaxEat < 0) + nMaxEat = 0; + + /* If the frame is too small, eat less spacing thus letting the frame + grow more. */ + SwTwips nMinHeight = lcl_GetFrmMinHeight(*this); + SwTwips nFrameTooSmall = nMinHeight - Frm().Height(); + + if (nFrameTooSmall > 0) + nEat -= nFrameTooSmall; + + /* No negative eating, not eating more than allowed. */ + if (nEat < 0) + nEat = 0; + else if (nEat > nMaxEat) + nEat = nMaxEat; + + // OD 10.04.2003 #108719# - Notify fly frame, if header frame + // grows. Consider, that 'normal' grow of layout frame already notifys + // the fly frames. + sal_Bool bNotifyFlys = sal_False; + if (nEat > 0) + { + if ( ! bTst) + { + if (! IsHeaderFrm()) + { + aPrt.Top(aPrt.Top() - nEat); + aPrt.Height(aPrt.Height() - nEat); + } + + InvalidateAll(); + } + + nResult += nEat; + // OD 14.04.2003 #108719# - trigger fly frame notify. + if ( IsHeaderFrm() ) + { + bNotifyFlys = sal_True; + } + } + + if (nDist - nEat > 0) + { + SwTwips nFrmGrow = + SwLayoutFrm::GrowFrm( nDist - nEat, bTst, bInfo ); + + nResult += nFrmGrow; + if ( nFrmGrow > 0 ) + { + bNotifyFlys = sal_False; + } + } + + // OD 10.04.2003 #108719# - notify fly frames, if necessary and triggered. + if ( ( nResult > 0 ) && bNotifyFlys ) + { + NotifyLowerObjs(); + } + } + + if ( nResult && !bTst ) + SetCompletePaint(); + + return nResult; +} + +SwTwips SwHeadFootFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SwTwips nResult; + + if ( IsColLocked() ) + { + nResult = 0; + } + else if (! GetEatSpacing()) + { + nResult = SwLayoutFrm::ShrinkFrm(nDist, bTst, bInfo); + } + else + { + nResult = 0; + + SwTwips nMinHeight = lcl_GetFrmMinHeight(*this); + SwTwips nOldHeight = Frm().Height(); + SwTwips nRest = 0; // Amount to shrink by spitting out spacing + + if ( nOldHeight >= nMinHeight ) + { + /* If the frame's height is bigger than its minimum height, shrink + the frame towards its minimum height. If this is not sufficient + to provide the shrinking requested provide the rest by spitting + out spacing. */ + + SwTwips nBiggerThanMin = nOldHeight - nMinHeight; + + if (nBiggerThanMin < nDist) + { + nRest = nDist - nBiggerThanMin; + } + /* info: declaration of nRest -> else nRest = 0 */ + } + else + /* The frame cannot shrink. Provide shrinking by spitting out + spacing. */ + nRest = nDist; + + // OD 10.04.2003 #108719# - Notify fly frame, if header/footer frame + // shrinks. Consider, that 'normal' shrink of layout frame already notifys + // the fly frames. + sal_Bool bNotifyFlys = sal_False; + if (nRest > 0) + { + + SwBorderAttrAccess * pAccess = + new SwBorderAttrAccess( SwFrm::GetCache(), this ); + OSL_ENSURE(pAccess, "no border attributes"); + + SwBorderAttrs * pAttrs = pAccess->Get(); + + /* minimal height of print area */ + SwTwips nMinPrtHeight = nMinHeight + - pAttrs->CalcTop() + - pAttrs->CalcBottom(); + + if (nMinPrtHeight < 0) + nMinPrtHeight = 0; + + delete pAccess; + + /* assume all shrinking can be provided */ + SwTwips nShrink = nRest; + + /* calculate maximum shrinking */ + SwTwips nMaxShrink = aPrt.Height() - nMinPrtHeight; + + /* shrink no more than maximum shrinking */ + if (nShrink > nMaxShrink) + { + //nRest -= nShrink - nMaxShrink; + nShrink = nMaxShrink; + } + + if (!bTst) + { + if (! IsHeaderFrm() ) + { + aPrt.Top(aPrt.Top() + nShrink); + aPrt.Height(aPrt.Height() - nShrink); + } + + InvalidateAll(); + } + nResult += nShrink; + // OD 14.04.2003 #108719# - trigger fly frame notify. + if ( IsHeaderFrm() ) + { + bNotifyFlys = sal_True; + } + } + + /* The shrinking not providable by spitting out spacing has to be done + by the frame. */ + if (nDist - nRest > 0) + { + SwTwips nShrinkAmount = SwLayoutFrm::ShrinkFrm( nDist - nRest, bTst, bInfo ); + nResult += nShrinkAmount; + if ( nShrinkAmount > 0 ) + { + bNotifyFlys = sal_False; + } + } + + // OD 10.04.2003 #108719# - notify fly frames, if necessary. + if ( ( nResult > 0 ) && bNotifyFlys ) + { + NotifyLowerObjs(); + } + } + + return nResult; +} + +sal_Bool SwHeadFootFrm::GetEatSpacing() const +{ + const SwFrmFmt * pFmt = GetFmt(); + OSL_ENSURE(pFmt, "SwHeadFootFrm: no format?"); + + if (pFmt->GetHeaderAndFooterEatSpacing().GetValue()) + return sal_True; + + return sal_False; +} + + +/************************************************************************* +|* +|* SwPageFrm::PrepareHeader() +|* +|* Beschreibung Erzeugt oder Entfernt Header +|* +|*************************************************************************/ + + +void DelFlys( SwLayoutFrm *pFrm, SwPageFrm *pPage ) +{ + for ( int i = 0; pPage->GetSortedObjs() && + pPage->GetSortedObjs()->Count() && + i < (int)pPage->GetSortedObjs()->Count(); ++i ) + { + SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i]; + if ( pObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFlyFrm = static_cast<SwFlyFrm*>(pObj); + if ( pFrm->IsAnLower( pFlyFrm ) ) + { + delete pFlyFrm; + --i; + } + } + } +} + + + +void SwPageFrm::PrepareHeader() +{ + SwLayoutFrm *pLay = (SwLayoutFrm*)Lower(); + if ( !pLay ) + return; + + const SwFmtHeader &rH = ((SwFrmFmt*)GetRegisteredIn())->GetHeader(); + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bOn = !(pSh && pSh->GetViewOptions()->getBrowseMode()); + + if ( bOn && rH.IsActive() ) + { //Header einsetzen, vorher entfernen falls vorhanden. + OSL_ENSURE( rH.GetHeaderFmt(), "FrmFmt fuer Header nicht gefunden." ); + + if ( pLay->GetFmt() == (SwFrmFmt*)rH.GetHeaderFmt() ) + return; //Der Footer ist bereits der richtige + + if ( pLay->IsHeaderFrm() ) + { SwLayoutFrm *pDel = pLay; + pLay = (SwLayoutFrm*)pLay->GetNext(); + ::DelFlys( pDel, this ); + pDel->Cut(); + delete pDel; + } + OSL_ENSURE( pLay, "Wohin mit dem Header?" ); + SwHeaderFrm *pH = new SwHeaderFrm( (SwFrmFmt*)rH.GetHeaderFmt(), this ); + pH->Paste( this, pLay ); + if ( GetUpper() ) + ::RegistFlys( this, pH ); + } + else if ( pLay && pLay->IsHeaderFrm() ) + { //Header entfernen falls vorhanden. + ::DelFlys( pLay, this ); + pLay->Cut(); + delete pLay; + } +} +/************************************************************************* +|* +|* SwPageFrm::PrepareFooter() +|* +|* Beschreibung Erzeugt oder Entfernt Footer +|* +|*************************************************************************/ + + +void SwPageFrm::PrepareFooter() +{ + SwLayoutFrm *pLay = (SwLayoutFrm*)Lower(); + if ( !pLay ) + return; + + const SwFmtFooter &rF = ((SwFrmFmt*)GetRegisteredIn())->GetFooter(); + while ( pLay->GetNext() ) + pLay = (SwLayoutFrm*)pLay->GetNext(); + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bOn = !(pSh && pSh->GetViewOptions()->getBrowseMode()); + + if ( bOn && rF.IsActive() ) + { //Footer einsetzen, vorher entfernen falls vorhanden. + OSL_ENSURE( rF.GetFooterFmt(), "FrmFmt fuer Footer nicht gefunden." ); + + if ( pLay->GetFmt() == (SwFrmFmt*)rF.GetFooterFmt() ) + return; //Der Footer ist bereits der richtige. + + if ( pLay->IsFooterFrm() ) + { ::DelFlys( pLay, this ); + pLay->Cut(); + delete pLay; + } + SwFooterFrm *pF = new SwFooterFrm( (SwFrmFmt*)rF.GetFooterFmt(), this ); + pF->Paste( this ); + if ( GetUpper() ) + ::RegistFlys( this, pF ); + } + else if ( pLay && pLay->IsFooterFrm() ) + { //Footer entfernen falls vorhanden. + ::DelFlys( pLay, this ); + ViewShell *pShell; + if ( pLay->GetPrev() && 0 != (pShell = getRootFrm()->GetCurrShell()) && + pShell->VisArea().HasArea() ) + pShell->InvalidateWindows( pShell->VisArea() ); + pLay->Cut(); + delete pLay; + } +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx new file mode 100644 index 000000000000..e0b4cd7432dc --- /dev/null +++ b/sw/source/core/layout/layact.cxx @@ -0,0 +1,2546 @@ +/* -*- 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 <time.h> +#include "rootfrm.hxx" +#include "pagefrm.hxx" +#include "cntfrm.hxx" +#include "doc.hxx" +#include "IDocumentDrawModelAccess.hxx" +#include "IDocumentSettingAccess.hxx" +#include "IDocumentLayoutAccess.hxx" +#include "IDocumentStatistics.hxx" +#include "IDocumentTimerAccess.hxx" +#include "viewimp.hxx" +#include "crsrsh.hxx" +#include "dflyobj.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "dcontact.hxx" +#include "ndtxt.hxx" // OnlineSpelling +#include "frmfmt.hxx" +#include "swregion.hxx" +#include "viewopt.hxx" // OnlineSpelling ueber Internal-TabPage testen. +#include "pam.hxx" // OnlineSpelling wg. der aktuellen Cursorposition +#include "dbg_lay.hxx" +#include "layouter.hxx" // LoopControlling +#include "docstat.hxx" +#include "swevent.hxx" + +#include <sfx2/event.hxx> + +#include <ftnidx.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/brshitem.hxx> +#include <SwSmartTagMgr.hxx> + +#define _LAYACT_CXX +#include "layact.hxx" +#include <swwait.hxx> +#include <fmtsrnd.hxx> +#include <fmtanchr.hxx> +#include <tools/shl.hxx> +#include <sfx2/progress.hxx> +#include <docsh.hxx> + +#include "swmodule.hxx" +#include "fmtline.hxx" +#include "tabfrm.hxx" +#include "ftnfrm.hxx" +#include "txtfrm.hxx" +#include "notxtfrm.hxx" +#include "flyfrms.hxx" +#include "mdiexp.hxx" +#include "fmtornt.hxx" +#include "sectfrm.hxx" +#include "lineinfo.hxx" +#include <acmplwrd.hxx> +// --> OD 2004-06-28 #i28701# +#include <sortedobjs.hxx> +#include <objectformatter.hxx> +#include <PostItMgr.hxx> +#include <vector> + +// <-- +//#pragma optimize("ity",on) + +/************************************************************************* +|* +|* SwLayAction Statisches Geraffel +|* +|*************************************************************************/ + +#define IS_FLYS (pPage->GetSortedObjs()) +#define IS_INVAFLY (pPage->IsInvalidFly()) + + +//Sparen von Schreibarbeit um den Zugriff auf zerstoerte Seiten zu vermeiden. +#if OSL_DEBUG_LEVEL > 1 + +static void BreakPoint() +{ + return; +} + +#define CHECKPAGE \ + { if ( IsAgain() ) \ + { BreakPoint(); \ + return; \ + } \ + } + +#define XCHECKPAGE \ + { if ( IsAgain() ) \ + { BreakPoint(); \ + if( bNoLoop ) \ + pLayoutAccess->GetLayouter()->EndLoopControl(); \ + return; \ + } \ + } +#else +#define CHECKPAGE \ + { if ( IsAgain() ) \ + return; \ + } + +#define XCHECKPAGE \ + { if ( IsAgain() ) \ + { \ + if( bNoLoop ) \ + pLayoutAccess->GetLayouter()->EndLoopControl(); \ + return; \ + } \ + } +#endif + +#define RESCHEDULE \ + { \ + if ( IsReschedule() ) \ + { \ + if (pProgress) pProgress->Reschedule(); \ + ::RescheduleProgress( pImp->GetShell()->GetDoc()->GetDocShell() ); \ + } \ + } + +inline sal_uLong Ticks() +{ + return 1000 * clock() / CLOCKS_PER_SEC; +} + +void SwLayAction::CheckWaitCrsr() +{ + RESCHEDULE + if ( !IsWait() && IsWaitAllowed() && IsPaint() && + ((Ticks() - GetStartTicks()) >= CLOCKS_PER_SEC/2) ) + { + pWait = new SwWait( *pRoot->GetFmt()->GetDoc()->GetDocShell(), sal_True ); + } +} + +/************************************************************************* +|* +|* SwLayAction::CheckIdleEnd() +|* +|*************************************************************************/ +//Ist es wirklich schon soweit... +inline void SwLayAction::CheckIdleEnd() +{ + if ( !IsInput() ) + bInput = GetInputType() && Application::AnyInput( GetInputType() ); +} + +/************************************************************************* +|* +|* SwLayAction::SetStatBar() +|* +|*************************************************************************/ +void SwLayAction::SetStatBar( sal_Bool bNew ) +{ + if ( bNew ) + { + nEndPage = pRoot->GetPageNum(); + nEndPage += nEndPage * 10 / 100; + } + else + nEndPage = USHRT_MAX; +} + +/************************************************************************* +|* +|* SwLayAction::PaintCntnt() +|* +|* Beschreibung Je nach Typ wird der Cntnt entsprechend seinen +|* Veraenderungen ausgegeben bzw. wird die auszugebende Flaeche in der +|* Region eingetragen. +|* PaintCntnt: fuellt die Region, +|* +|*************************************************************************/ +sal_Bool SwLayAction::PaintWithoutFlys( const SwRect &rRect, const SwCntntFrm *pCnt, + const SwPageFrm *pPage ) +{ + SwRegionRects aTmp( rRect ); + const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + const SwFlyFrm *pSelfFly = pCnt->FindFlyFrm(); + sal_uInt16 i; + + for ( i = 0; i < rObjs.Count() && aTmp.Count(); ++i ) + { + SdrObject *pO = rObjs[i]->DrawObj(); + if ( !pO->ISA(SwVirtFlyDrawObj) ) + continue; + + // OD 2004-01-15 #110582# - do not consider invisible objects + const IDocumentDrawModelAccess* pIDDMA = pPage->GetFmt()->getIDocumentDrawModelAccess(); + if ( !pIDDMA->IsVisibleLayerId( pO->GetLayer() ) ) + { + continue; + } + + SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pO)->GetFlyFrm(); + + if ( pFly == pSelfFly || !rRect.IsOver( pFly->Frm() ) ) + continue; + + if ( pSelfFly && pSelfFly->IsLowerOf( pFly ) ) + continue; + + if ( pFly->GetVirtDrawObj()->GetLayer() == pIDDMA->GetHellId() ) + continue; + + if ( pSelfFly ) + { + const SdrObject *pTmp = pSelfFly->GetVirtDrawObj(); + if ( pO->GetLayer() == pTmp->GetLayer() ) + { + if ( pO->GetOrdNumDirect() < pTmp->GetOrdNumDirect() ) + //Im gleichen Layer werden nur obenliegende beachtet. + continue; + } + else + { + const sal_Bool bLowerOfSelf = pFly->IsLowerOf( pSelfFly ); + if ( !bLowerOfSelf && !pFly->GetFmt()->GetOpaque().GetValue() ) + //Aus anderem Layer interessieren uns nur nicht transparente + //oder innenliegende + continue; + } + } + + /// OD 19.08.2002 #99657# + /// Fly frame without a lower have to be subtracted from paint region. + /// For checking, if fly frame contains transparent graphic or + /// has surrounded contour, assure that fly frame has a lower + if ( pFly->Lower() && + pFly->Lower()->IsNoTxtFrm() && + ( ((SwNoTxtFrm*)pFly->Lower())->IsTransparent() || + pFly->GetFmt()->GetSurround().IsContour() ) + ) + { + continue; + } + + /// OD 19.08.2002 #99657# + /// Region of a fly frame with transparent background or a transparent + /// shadow have not to be subtracted from paint region + if ( pFly->IsBackgroundTransparent() || + pFly->IsShadowTransparent() ) + { + continue; + } + + aTmp -= pFly->Frm(); + } + + sal_Bool bRetPaint = sal_False; + const SwRect *pData = aTmp.GetData(); + for ( i = 0; i < aTmp.Count(); ++pData, ++i ) + bRetPaint |= pImp->GetShell()->AddPaintRect( *pData ); + return bRetPaint; +} + +inline sal_Bool SwLayAction::_PaintCntnt( const SwCntntFrm *pCntnt, + const SwPageFrm *pPage, + const SwRect &rRect ) +{ + if ( rRect.HasArea() ) + { + if ( pPage->GetSortedObjs() ) + return PaintWithoutFlys( rRect, pCntnt, pPage ); + else + return pImp->GetShell()->AddPaintRect( rRect ); + } + return sal_False; +} + +void SwLayAction::PaintCntnt( const SwCntntFrm *pCnt, + const SwPageFrm *pPage, + const SwRect &rOldRect, + long nOldBottom ) +{ + SWRECTFN( pCnt ) + + if ( pCnt->IsCompletePaint() || !pCnt->IsTxtFrm() ) + { + SwRect aPaint( pCnt->PaintArea() ); + if ( !_PaintCntnt( pCnt, pPage, aPaint ) ) + pCnt->ResetCompletePaint(); + } + else + { + // paint the area between printing bottom and frame bottom and + // the area left and right beside the frame, if its height changed. + long nOldHeight = (rOldRect.*fnRect->fnGetHeight)(); + long nNewHeight = (pCnt->Frm().*fnRect->fnGetHeight)(); + const bool bHeightDiff = nOldHeight != nNewHeight; + if( bHeightDiff ) + { + // OD 05.11.2002 #94454# - consider whole potential paint area. + //SwRect aDrawRect( pCnt->UnionFrm( sal_True ) ); + SwRect aDrawRect( pCnt->PaintArea() ); + if( nOldHeight > nNewHeight ) + nOldBottom = (pCnt->*fnRect->fnGetPrtBottom)(); + (aDrawRect.*fnRect->fnSetTop)( nOldBottom ); + _PaintCntnt( pCnt, pPage, aDrawRect ); + } + // paint content area + SwRect aPaintRect = static_cast<SwTxtFrm*>(const_cast<SwCntntFrm*>(pCnt))->Paint(); + _PaintCntnt( pCnt, pPage, aPaintRect ); + } + + if ( pCnt->IsRetouche() && !pCnt->GetNext() ) + { + const SwFrm *pTmp = pCnt; + if( pCnt->IsInSct() ) + { + const SwSectionFrm* pSct = pCnt->FindSctFrm(); + if( pSct->IsRetouche() && !pSct->GetNext() ) + pTmp = pSct; + } + SwRect aRect( pTmp->GetUpper()->PaintArea() ); + (aRect.*fnRect->fnSetTop)( (pTmp->*fnRect->fnGetPrtBottom)() ); + if ( !_PaintCntnt( pCnt, pPage, aRect ) ) + pCnt->ResetRetouche(); + } +} + +/************************************************************************* +|* +|* SwLayAction::SwLayAction() +|* +|*************************************************************************/ +SwLayAction::SwLayAction( SwRootFrm *pRt, SwViewImp *pI ) : + pRoot( pRt ), + pImp( pI ), + pOptTab( 0 ), + pWait( 0 ), + pProgress(NULL), + nPreInvaPage( USHRT_MAX ), + nStartTicks( Ticks() ), + nInputType( 0 ), + nEndPage( USHRT_MAX ), + nCheckPageNum( USHRT_MAX ) +{ + bPaintExtraData = ::IsExtraData( pImp->GetShell()->GetDoc() ); + bPaint = bComplete = bWaitAllowed = bCheckPages = sal_True; + bInput = bAgain = bNextCycle = bCalcLayout = bIdle = bReschedule = + bUpdateExpFlds = bBrowseActionStop = bActionInProgress = sal_False; + // OD 14.04.2003 #106346# - init new flag <mbFormatCntntOnInterrupt>. + mbFormatCntntOnInterrupt = sal_False; + + pImp->pLayAct = this; //Anmelden +} + +SwLayAction::~SwLayAction() +{ + OSL_ENSURE( !pWait, "Wait object not destroyed" ); + pImp->pLayAct = 0; //Abmelden +} + +/************************************************************************* +|* +|* SwLayAction::Reset() +|* +|*************************************************************************/ +void SwLayAction::Reset() +{ + pOptTab = 0; + nStartTicks = Ticks(); + nInputType = 0; + nEndPage = nPreInvaPage = nCheckPageNum = USHRT_MAX; + bPaint = bComplete = bWaitAllowed = bCheckPages = sal_True; + bInput = bAgain = bNextCycle = bCalcLayout = bIdle = bReschedule = + bUpdateExpFlds = bBrowseActionStop = sal_False; +} + +/************************************************************************* +|* +|* SwLayAction::RemoveEmptyBrowserPages() +|* +|*************************************************************************/ + +sal_Bool SwLayAction::RemoveEmptyBrowserPages() +{ + //Beim umschalten vom normalen in den Browsermodus bleiben u.U. einige + //unangenehm lange stehen. Diese beseiten wir mal schnell. + sal_Bool bRet = sal_False; + const ViewShell *pSh = pRoot->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + SwPageFrm *pPage = (SwPageFrm*)pRoot->Lower(); + do + { + if ( (pPage->GetSortedObjs() && pPage->GetSortedObjs()->Count()) || + pPage->ContainsCntnt() ) + pPage = (SwPageFrm*)pPage->GetNext(); + else + { + bRet = sal_True; + SwPageFrm *pDel = pPage; + pPage = (SwPageFrm*)pPage->GetNext(); + pDel->Cut(); + delete pDel; + } + } while ( pPage ); + } + return bRet; +} + + +/************************************************************************* +|* +|* SwLayAction::Action() +|* +|*************************************************************************/ +void SwLayAction::Action() +{ + bActionInProgress = sal_True; + + //TurboMode? Disqualifiziert fuer Idle-Format. + if ( IsPaint() && !IsIdle() && TurboAction() ) + { + delete pWait, pWait = 0; + pRoot->ResetTurboFlag(); + bActionInProgress = sal_False; + pRoot->DeleteEmptySct(); + return; + } + else if ( pRoot->GetTurbo() ) + { + pRoot->DisallowTurbo(); + const SwFrm *pFrm = pRoot->GetTurbo(); + pRoot->ResetTurbo(); + pFrm->InvalidatePage(); + } + pRoot->DisallowTurbo(); + + if ( IsCalcLayout() ) + SetCheckPages( sal_False ); + + InternalAction(); + bAgain |= RemoveEmptyBrowserPages(); + while ( IsAgain() ) + { + bAgain = bNextCycle = sal_False; + InternalAction(); + bAgain |= RemoveEmptyBrowserPages(); + } + pRoot->DeleteEmptySct(); + + delete pWait, pWait = 0; + + //Turbo-Action ist auf jedenfall wieder erlaubt. + pRoot->ResetTurboFlag(); + pRoot->ResetTurbo(); + + SetCheckPages( sal_True ); + + bActionInProgress = sal_False; +} + +SwPageFrm* SwLayAction::CheckFirstVisPage( SwPageFrm *pPage ) +{ + SwCntntFrm *pCnt = pPage->FindFirstBodyCntnt(); + SwCntntFrm *pChk = pCnt; + sal_Bool bPageChgd = sal_False; + while ( pCnt && pCnt->IsFollow() ) + pCnt = static_cast<SwCntntFrm*>(pCnt)->FindMaster(); + if ( pCnt && pChk != pCnt ) + { bPageChgd = sal_True; + pPage = pCnt->FindPageFrm(); + } + + if ( pPage->GetFmt()->GetDoc()->GetFtnIdxs().Count() ) + { + SwFtnContFrm *pCont = pPage->FindFtnCont(); + if ( pCont ) + { + pCnt = pCont->ContainsCntnt(); + pChk = pCnt; + while ( pCnt && pCnt->IsFollow() ) + pCnt = (SwCntntFrm*)pCnt->FindPrev(); + if ( pCnt && pCnt != pChk ) + { + if ( bPageChgd ) + { + //Die 'oberste' Seite benutzten. + SwPageFrm *pTmp = pCnt->FindPageFrm(); + if ( pPage->GetPhyPageNum() > pTmp->GetPhyPageNum() ) + pPage = pTmp; + } + else + pPage = pCnt->FindPageFrm(); + } + } + } + return pPage; +} + +// OD 2004-05-12 #i28701# +// --> OD 2004-11-03 #i114798# - unlock position on start and end of page +// layout process. +class NotifyLayoutOfPageInProgress +{ + private: + SwPageFrm& mrPageFrm; + + void _UnlockPositionOfObjs() + { + SwSortedObjs* pObjs = mrPageFrm.GetSortedObjs(); + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pObj = (*pObjs)[i]; + pObj->UnlockPosition(); + } + } + } + public: + NotifyLayoutOfPageInProgress( SwPageFrm& _rPageFrm ) + : mrPageFrm( _rPageFrm ) + { + _UnlockPositionOfObjs(); + _rPageFrm.SetLayoutInProgress( true ); + } + ~NotifyLayoutOfPageInProgress() + { + mrPageFrm.SetLayoutInProgress( false ); + _UnlockPositionOfObjs(); + } +}; +// <-- + +void SwLayAction::InternalAction() +{ + OSL_ENSURE( pRoot->Lower()->IsPageFrm(), ":-( Keine Seite unterhalb der Root."); + + pRoot->Calc(); + + //Die erste ungueltige bzw. zu formatierende Seite ermitteln. + //Bei einer Complete-Action ist es die erste ungueltige; mithin ist die + //erste zu formatierende Seite diejenige Seite mit der Numemr eins. + //Bei einer Luegen-Formatierung ist die Nummer der erste Seite die Nummer + //der ersten Sichtbaren Seite. + SwPageFrm *pPage = IsComplete() ? (SwPageFrm*)pRoot->Lower() : + pImp->GetFirstVisPage(); + if ( !pPage ) + pPage = (SwPageFrm*)pRoot->Lower(); + + //Wenn ein "Erster-Fliess-Cntnt" innerhalb der der ersten sichtbaren Seite + //ein Follow ist, so schalten wir die Seite zurueck auf den Ur-Master dieses + //Cntnt's + if ( !IsComplete() ) + pPage = CheckFirstVisPage( pPage ); + sal_uInt16 nFirstPageNum = pPage->GetPhyPageNum(); + + while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() ) + pPage = (SwPageFrm*)pPage->GetNext(); + + IDocumentLayoutAccess *pLayoutAccess = pRoot->GetFmt()->getIDocumentLayoutAccess(); + sal_Bool bNoLoop = pPage ? SwLayouter::StartLoopControl( pRoot->GetFmt()->GetDoc(), pPage ) : sal_False; + sal_uInt16 nPercentPageNum = 0; + while ( (pPage && !IsInterrupt()) || nCheckPageNum != USHRT_MAX ) + { + if ( !pPage && nCheckPageNum != USHRT_MAX && + (!pPage || pPage->GetPhyPageNum() >= nCheckPageNum) ) + { + if ( !pPage || pPage->GetPhyPageNum() > nCheckPageNum ) + { + SwPageFrm *pPg = (SwPageFrm*)pRoot->Lower(); + while ( pPg && pPg->GetPhyPageNum() < nCheckPageNum ) + pPg = (SwPageFrm*)pPg->GetNext(); + if ( pPg ) + pPage = pPg; + if ( !pPage ) + break; + } + SwPageFrm *pTmp = pPage->GetPrev() ? + (SwPageFrm*)pPage->GetPrev() : pPage; + SetCheckPages( sal_True ); + SwFrm::CheckPageDescs( pPage ); + SetCheckPages( sal_False ); + nCheckPageNum = USHRT_MAX; + pPage = pTmp; + continue; + } + + if ( nEndPage != USHRT_MAX && pPage->GetPhyPageNum() > nPercentPageNum ) + { + nPercentPageNum = pPage->GetPhyPageNum(); + ::SetProgressState( nPercentPageNum, pImp->GetShell()->GetDoc()->GetDocShell()); + } + pOptTab = 0; + //Kein ShortCut fuer Idle oder CalcLayout + if ( !IsIdle() && !IsComplete() && IsShortCut( pPage ) ) + { + pRoot->DeleteEmptySct(); + XCHECKPAGE; + if ( !IsInterrupt() && + (pRoot->IsSuperfluous() || pRoot->IsAssertFlyPages()) ) + { + if ( pRoot->IsAssertFlyPages() ) + pRoot->AssertFlyPages(); + if ( pRoot->IsSuperfluous() ) + { + sal_Bool bOld = IsAgain(); + pRoot->RemoveSuperfluous(); + bAgain = bOld; + } + if ( IsAgain() ) + { + if( bNoLoop ) + pLayoutAccess->GetLayouter()->EndLoopControl(); + return; + } + pPage = (SwPageFrm*)pRoot->Lower(); + while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() ) + pPage = (SwPageFrm*)pPage->GetNext(); + while ( pPage && pPage->GetNext() && + pPage->GetPhyPageNum() < nFirstPageNum ) + pPage = (SwPageFrm*)pPage->GetNext(); + continue; + } + break; + } + else + { + pRoot->DeleteEmptySct(); + XCHECKPAGE; + + // OD 2004-05-12 #i28701# - scope for instance of class + // <NotifyLayoutOfPageInProgress> + { + NotifyLayoutOfPageInProgress aLayoutOfPageInProgress( *pPage ); + + while ( !IsInterrupt() && !IsNextCycle() && + ((IS_FLYS && IS_INVAFLY) || pPage->IsInvalid()) ) + { + // OD 2004-05-10 #i28701# + SwObjectFormatter::FormatObjsAtFrm( *pPage, *pPage, this ); + if ( !IS_FLYS ) + { + //Wenn keine Flys (mehr) da sind, sind die Flags + //mehr als fluessig. + pPage->ValidateFlyLayout(); + pPage->ValidateFlyCntnt(); + } + // OD 2004-05-10 #i28701# - change condition + while ( !IsInterrupt() && !IsNextCycle() && + ( pPage->IsInvalid() || + (IS_FLYS && IS_INVAFLY) ) ) + { + PROTOCOL( pPage, PROT_FILE_INIT, 0, 0) + XCHECKPAGE; + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_1 = 0; + const sal_uInt16 nLoopControlMax = 20; + + while ( !IsNextCycle() && pPage->IsInvalidLayout() ) + { + pPage->ValidateLayout(); + + if ( ++nLoopControlRuns_1 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl_1 in SwLayAction::InternalAction" ); + +#endif + break; + } + + FormatLayout( pPage ); + XCHECKPAGE; + } + // OD 2004-05-10 #i28701# - change condition + if ( !IsNextCycle() && + ( pPage->IsInvalidCntnt() || + (IS_FLYS && IS_INVAFLY) ) ) + { + pPage->ValidateFlyInCnt(); + pPage->ValidateCntnt(); + // --> OD 2004-05-10 #i28701# + pPage->ValidateFlyLayout(); + pPage->ValidateFlyCntnt(); + // <-- + if ( !FormatCntnt( pPage ) ) + { + XCHECKPAGE; + pPage->InvalidateCntnt(); + pPage->InvalidateFlyInCnt(); + // --> OD 2004-05-10 #i28701# + pPage->InvalidateFlyLayout(); + pPage->InvalidateFlyCntnt(); + // <-- + if ( IsBrowseActionStop() ) + bInput = sal_True; + } + } + if( bNoLoop ) + pLayoutAccess->GetLayouter()->LoopControl( pPage, LOOP_PAGE ); + } + } + } // end of scope for instance of class <NotifyLayoutOfPageInProgress> + + + //Eine vorige Seite kann wieder invalid sein. + XCHECKPAGE; + if ( !IS_FLYS ) + { + //Wenn keine Flys (mehr) da sind, sind die Flags + //mehr als fluessig. + pPage->ValidateFlyLayout(); + pPage->ValidateFlyCntnt(); + } + if ( !IsInterrupt() ) + { + SetNextCycle( sal_False ); + + if ( nPreInvaPage != USHRT_MAX ) + { + if( !IsComplete() && nPreInvaPage + 2 < nFirstPageNum ) + { + pImp->SetFirstVisPageInvalid(); + SwPageFrm *pTmpPage = pImp->GetFirstVisPage(); + nFirstPageNum = pTmpPage->GetPhyPageNum(); + if( nPreInvaPage < nFirstPageNum ) + { + nPreInvaPage = nFirstPageNum; + pPage = pTmpPage; + } + } + while ( pPage->GetPrev() && pPage->GetPhyPageNum() > nPreInvaPage ) + pPage = (SwPageFrm*)pPage->GetPrev(); + nPreInvaPage = USHRT_MAX; + } + + while ( pPage->GetPrev() && + ( ((SwPageFrm*)pPage->GetPrev())->IsInvalid() || + ( ((SwPageFrm*)pPage->GetPrev())->GetSortedObjs() && + ((SwPageFrm*)pPage->GetPrev())->IsInvalidFly())) && + (((SwPageFrm*)pPage->GetPrev())->GetPhyPageNum() >= + nFirstPageNum) ) + { + pPage = (SwPageFrm*)pPage->GetPrev(); + } + + //Weiter bis zur naechsten invaliden Seite. + while ( pPage && !pPage->IsInvalid() && + (!IS_FLYS || !IS_INVAFLY) ) + { + pPage = (SwPageFrm*)pPage->GetNext(); + } + if( bNoLoop ) + pLayoutAccess->GetLayouter()->LoopControl( pPage, LOOP_PAGE ); + } + CheckIdleEnd(); + } + if ( !pPage && !IsInterrupt() && + (pRoot->IsSuperfluous() || pRoot->IsAssertFlyPages()) ) + { + if ( pRoot->IsAssertFlyPages() ) + pRoot->AssertFlyPages(); + if ( pRoot->IsSuperfluous() ) + { + sal_Bool bOld = IsAgain(); + pRoot->RemoveSuperfluous(); + bAgain = bOld; + } + if ( IsAgain() ) + { + if( bNoLoop ) + pLayoutAccess->GetLayouter()->EndLoopControl(); + return; + } + pPage = (SwPageFrm*)pRoot->Lower(); + while ( pPage && !pPage->IsInvalid() && !pPage->IsInvalidFly() ) + pPage = (SwPageFrm*)pPage->GetNext(); + while ( pPage && pPage->GetNext() && + pPage->GetPhyPageNum() < nFirstPageNum ) + pPage = (SwPageFrm*)pPage->GetNext(); + } + } + if ( IsInterrupt() && pPage ) + { + //Wenn ein Input anliegt wollen wir keinen Inhalt mehr Formatieren, + //Das Layout muessen wir aber schon in Ordnung bringen. + //Andernfalls kann folgende Situation auftreten (Bug: 3244): + //Am Ende des Absatz der letzten Seite wird Text eingegeben, so das + //der Absatz einen Follow fuer die nachste Seite erzeugt, ausserdem + //wird gleich schnell weitergetippt - Es liegt waehrend der + //Verarbeitung ein Input an. Der Absatz auf der neuen Seite wurde + //bereits anformatiert, die neue Seite ist Formatiert und steht + //auf CompletePaint, hat sich aber noch nicht im Auszugebenden Bereich + //eingetragen. Es wird gepaintet, das CompletePaint der Seite wird + //zurueckgesetzt weil der neue Absatz sich bereits eingetragen hatte, + //aber die Raender der Seite werden nicht gepaintet. Naja, bei der + //zwangslaeufig auftretenden naechsten LayAction traegt sich die Seite + //nicht mehr ein, weil ihre (LayoutFrm-)Flags bereits zurueckgesetzt + //wurden -- Der Rand der Seite wird nie gepaintet. + SwPageFrm *pPg = pPage; + XCHECKPAGE; + const SwRect &rVis = pImp->GetShell()->VisArea(); + + while( pPg && pPg->Frm().Bottom() < rVis.Top() ) + pPg = (SwPageFrm*)pPg->GetNext(); + if( pPg != pPage ) + pPg = pPg ? (SwPageFrm*)pPg->GetPrev() : pPage; + + // OD 14.04.2003 #106346# - set flag for interrupt content formatting + mbFormatCntntOnInterrupt = IsInput() && !IsStopPrt(); + long nBottom = rVis.Bottom(); + // --> OD 2005-02-15 #i42586# - format current page, if idle action is active + // This is an optimization for the case that the interrupt is created by + // the move of a form control object, which is represented by a window. + while ( pPg && ( pPg->Frm().Top() < nBottom || + ( IsIdle() && pPg == pPage ) ) ) + // <-- + { + // --> OD 2004-10-11 #i26945# - follow-up of #i28701# + NotifyLayoutOfPageInProgress aLayoutOfPageInProgress( *pPg ); + + XCHECKPAGE; + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_2 = 0; + const sal_uInt16 nLoopControlMax = 20; + + // OD 14.04.2003 #106346# - special case: interrupt content formatting + // --> OD 2004-07-08 #i28701# - conditions, introduced by #106346#, + // are incorrect (marcos IS_FLYS and IS_INVAFLY only works for <pPage>) + // and are too strict. + // --> OD 2005-06-09 #i50432# - adjust interrupt formatting to + // normal page formatting - see above. + while ( ( mbFormatCntntOnInterrupt && + ( pPg->IsInvalid() || + ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) ) || + ( !mbFormatCntntOnInterrupt && pPg->IsInvalidLayout() ) ) + { + XCHECKPAGE; + // --> OD 2005-06-09 #i50432# - format also at-page anchored objects + SwObjectFormatter::FormatObjsAtFrm( *pPg, *pPg, this ); + // <-- + // --> OD 2005-06-09 #i50432# + if ( !pPg->GetSortedObjs() ) + { + pPg->ValidateFlyLayout(); + pPg->ValidateFlyCntnt(); + } + // <-- + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_3 = 0; + + while ( pPg->IsInvalidLayout() ) + { + pPg->ValidateLayout(); + + if ( ++nLoopControlRuns_3 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl_3 in Interrupt formatting in SwLayAction::InternalAction" ); +#endif + break; + } + + FormatLayout( pPg ); + XCHECKPAGE; + } + + // --> OD 2005-06-09 #i50432# + if ( mbFormatCntntOnInterrupt && + ( pPg->IsInvalidCntnt() || + ( pPg->GetSortedObjs() && pPg->IsInvalidFly() ) ) ) + // <-- + { + pPg->ValidateFlyInCnt(); + pPg->ValidateCntnt(); + // --> OD 2004-05-10 #i26945# - follow-up of fix #117736# + pPg->ValidateFlyLayout(); + pPg->ValidateFlyCntnt(); + // <-- + + if ( ++nLoopControlRuns_2 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl_2 in Interrupt formatting in SwLayAction::InternalAction" ); +#endif + break; + } + + if ( !FormatCntnt( pPg ) ) + { + XCHECKPAGE; + pPg->InvalidateCntnt(); + pPg->InvalidateFlyInCnt(); + // --> OD 2004-05-10 #i26945# - follow-up of fix #117736# + pPg->InvalidateFlyLayout(); + pPg->InvalidateFlyCntnt(); + // <-- + } + // --> OD 2005-04-06 #i46807# - we are statisfied, if the + // content is formatted once complete. + else + { + break; + } + // <-- + } + } + // <-- + pPg = (SwPageFrm*)pPg->GetNext(); + } + // OD 14.04.2003 #106346# - reset flag for special interrupt content formatting. + mbFormatCntntOnInterrupt = sal_False; + } + pOptTab = 0; + if( bNoLoop ) + pLayoutAccess->GetLayouter()->EndLoopControl(); +} +/************************************************************************* +|* +|* SwLayAction::TurboAction(), _TurboAction() +|* +|*************************************************************************/ +sal_Bool SwLayAction::_TurboAction( const SwCntntFrm *pCnt ) +{ + + const SwPageFrm *pPage = 0; + if ( !pCnt->IsValid() || pCnt->IsCompletePaint() || pCnt->IsRetouche() ) + { + const SwRect aOldRect( pCnt->UnionFrm( sal_True ) ); + const long nOldBottom = pCnt->Frm().Top() + pCnt->Prt().Bottom(); + pCnt->Calc(); + if ( pCnt->Frm().Bottom() < aOldRect.Bottom() ) + pCnt->SetRetouche(); + + pPage = pCnt->FindPageFrm(); + PaintCntnt( pCnt, pPage, aOldRect, nOldBottom ); + + if ( !pCnt->GetValidLineNumFlag() && pCnt->IsTxtFrm() ) + { + const sal_uLong nAllLines = ((SwTxtFrm*)pCnt)->GetAllLines(); + ((SwTxtFrm*)pCnt)->RecalcAllLines(); + if ( nAllLines != ((SwTxtFrm*)pCnt)->GetAllLines() ) + { + if ( IsPaintExtraData() ) + pImp->GetShell()->AddPaintRect( pCnt->Frm() ); + //Damit die restlichen LineNums auf der Seite bereichnet werden + //und nicht hier abgebrochen wird. + //Das im RecalcAllLines zu erledigen waere teuer, weil dort + //auch in unnoetigen Faellen (normale Action) auch immer die + //Seite benachrichtigt werden muesste. + const SwCntntFrm *pNxt = pCnt->GetNextCntntFrm(); + while ( pNxt && + (pNxt->IsInTab() || pNxt->IsInDocBody() != pCnt->IsInDocBody()) ) + pNxt = pNxt->GetNextCntntFrm(); + if ( pNxt ) + pNxt->InvalidatePage(); + } + return sal_False; + } + + if ( pPage->IsInvalidLayout() || (IS_FLYS && IS_INVAFLY) ) + return sal_False; + } + if ( !pPage ) + pPage = pCnt->FindPageFrm(); + + // OD 2004-05-10 #i28701# - format floating screen objects at content frame. + if ( pCnt->IsTxtFrm() && + !SwObjectFormatter::FormatObjsAtFrm( *(const_cast<SwCntntFrm*>(pCnt)), + *pPage, this ) ) + { + return sal_False; + } + + if ( pPage->IsInvalidCntnt() ) + return sal_False; + return sal_True; +} + +sal_Bool SwLayAction::TurboAction() +{ + sal_Bool bRet = sal_True; + + if ( pRoot->GetTurbo() ) + { + if ( !_TurboAction( pRoot->GetTurbo() ) ) + { + CheckIdleEnd(); + bRet = sal_False; + } + pRoot->ResetTurbo(); + } + else + bRet = sal_False; + return bRet; +} +/************************************************************************* +|* +|* SwLayAction::IsShortCut() +|* +|* Beschreibung: Liefert ein True, wenn die Seite vollstaendig unter +|* oder rechts neben dem sichbaren Bereich liegt. +|* Es kann passieren, dass sich die Verhaeltnisse derart aendern, dass +|* die Verarbeitung (des Aufrufers!) mit der Vorgaengerseite der +|* uebergebenen Seite weitergefuehrt werden muss. Der Paramter wird also +|* ggf. veraendert! +|* Fuer den BrowseMode kann auch dann der ShortCut aktiviert werden, +|* wenn der ungueltige Inhalt der Seite unterhalb des sichbaren +|* bereiches liegt. +|* +|*************************************************************************/ +static bool lcl_IsInvaLay( const SwFrm *pFrm, long nBottom ) +{ + if ( + !pFrm->IsValid() || + (pFrm->IsCompletePaint() && ( pFrm->Frm().Top() < nBottom ) ) + ) + { + return true; + } + return false; +} + +static const SwFrm *lcl_FindFirstInvaLay( const SwFrm *pFrm, long nBottom ) +{ + OSL_ENSURE( pFrm->IsLayoutFrm(), "FindFirstInvaLay, no LayFrm" ); + + if (lcl_IsInvaLay(pFrm, nBottom)) + return pFrm; + pFrm = ((SwLayoutFrm*)pFrm)->Lower(); + while ( pFrm ) + { + if ( pFrm->IsLayoutFrm() ) + { + if (lcl_IsInvaLay(pFrm, nBottom)) + return pFrm; + const SwFrm *pTmp; + if ( 0 != (pTmp = lcl_FindFirstInvaLay( pFrm, nBottom )) ) + return pTmp; + } + pFrm = pFrm->GetNext(); + } + return 0; +} + +static const SwFrm *lcl_FindFirstInvaCntnt( const SwLayoutFrm *pLay, long nBottom, + const SwCntntFrm *pFirst ) +{ + const SwCntntFrm *pCnt = pFirst ? pFirst->GetNextCntntFrm() : + pLay->ContainsCntnt(); + while ( pCnt ) + { + if ( !pCnt->IsValid() || pCnt->IsCompletePaint() ) + { + if ( pCnt->Frm().Top() <= nBottom ) + return pCnt; + } + + if ( pCnt->GetDrawObjs() ) + { + const SwSortedObjs &rObjs = *pCnt->GetDrawObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + const SwAnchoredObject* pObj = rObjs[i]; + if ( pObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pObj); + if ( pFly->IsFlyInCntFrm() ) + { + if ( ((SwFlyInCntFrm*)pFly)->IsInvalid() || + pFly->IsCompletePaint() ) + { + if ( pFly->Frm().Top() <= nBottom ) + return pFly; + } + const SwFrm *pFrm = lcl_FindFirstInvaCntnt( pFly, nBottom, 0 ); + if ( pFrm && pFrm->Frm().Bottom() <= nBottom ) + return pFrm; + } + } + } + } + if ( pCnt->Frm().Top() > nBottom && !pCnt->IsInTab() ) + return 0; + pCnt = pCnt->GetNextCntntFrm(); + if ( !pLay->IsAnLower( pCnt ) ) + break; + } + return 0; +} + +// --> OD 2005-02-21 #i37877# - consider drawing objects +static const SwAnchoredObject* lcl_FindFirstInvaObj( const SwPageFrm* _pPage, + long _nBottom ) +{ + OSL_ENSURE( _pPage->GetSortedObjs(), "FindFirstInvaObj, no Objs" ); + + for ( sal_uInt16 i = 0; i < _pPage->GetSortedObjs()->Count(); ++i ) + { + const SwAnchoredObject* pObj = (*_pPage->GetSortedObjs())[i]; + if ( pObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pObj); + if ( pFly->Frm().Top() <= _nBottom ) + { + if ( pFly->IsInvalid() || pFly->IsCompletePaint() ) + return pFly; + + const SwFrm* pTmp; + if ( 0 != (pTmp = lcl_FindFirstInvaCntnt( pFly, _nBottom, 0 )) && + pTmp->Frm().Top() <= _nBottom ) + return pFly; + } + } + else if ( pObj->ISA(SwAnchoredDrawObject) ) + { + if ( !static_cast<const SwAnchoredDrawObject*>(pObj)->IsValidPos() ) + { + return pObj; + } + } + } + return 0; +} +// <-- + +sal_Bool SwLayAction::IsShortCut( SwPageFrm *&prPage ) +{ + sal_Bool bRet = sal_False; + const ViewShell *pSh = pRoot->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + + //Wenn die Seite nicht Gueltig ist wird sie schnell formatiert, sonst + //gibts nix als Aerger. + if ( !prPage->IsValid() ) + { + if ( bBrowse ) + { + /// OD 15.10.2002 #103517# - format complete page + /// Thus, loop on all lowers of the page <prPage>, instead of only + /// format its first lower. + /// NOTE: In online layout (bBrowse == sal_True) a page can contain + /// a header frame and/or a footer frame beside the body frame. + prPage->Calc(); + SwFrm* pPageLowerFrm = prPage->Lower(); + while ( pPageLowerFrm ) + { + pPageLowerFrm->Calc(); + pPageLowerFrm = pPageLowerFrm->GetNext(); + } + } + else + FormatLayout( prPage ); + if ( IsAgain() ) + return sal_False; + } + + + const SwRect &rVis = pImp->GetShell()->VisArea(); + if ( (prPage->Frm().Top() >= rVis.Bottom()) || + (prPage->Frm().Left()>= rVis.Right()) ) + { + bRet = sal_True; + + //Jetzt wird es ein bischen unangenehm: Der erste CntntFrm dieser Seite + //im Bodytext muss Formatiert werden, wenn er dabei die Seite + //wechselt, muss ich nochmal eine Seite zuvor anfangen, denn + //es wurde ein PageBreak verarbeitet. +//Noch unangenehmer: Der naechste CntntFrm ueberhaupt muss + //Formatiert werden, denn es kann passieren, dass kurzfristig + //leere Seiten existieren (Bsp. Absatz ueber mehrere Seiten + //wird geloescht oder verkleinert). + + //Ist fuer den Browser uninteressant, wenn der letzte Cnt davor bereits + //nicht mehr sichbar ist. + + const SwPageFrm *p2ndPage = prPage; + const SwCntntFrm *pCntnt; + const SwLayoutFrm* pBody = p2ndPage->FindBodyCont(); + if( p2ndPage->IsFtnPage() && pBody ) + pBody = (SwLayoutFrm*)pBody->GetNext(); + pCntnt = pBody ? pBody->ContainsCntnt() : 0; + while ( p2ndPage && !pCntnt ) + { + p2ndPage = (SwPageFrm*)p2ndPage->GetNext(); + if( p2ndPage ) + { + pBody = p2ndPage->FindBodyCont(); + if( p2ndPage->IsFtnPage() && pBody ) + pBody = (SwLayoutFrm*)pBody->GetNext(); + pCntnt = pBody ? pBody->ContainsCntnt() : 0; + } + } + if ( pCntnt ) + { + sal_Bool bTstCnt = sal_True; + if ( bBrowse ) + { + //Der Cnt davor schon nicht mehr sichtbar? + const SwFrm *pLst = pCntnt; + if ( pLst->IsInTab() ) + pLst = pCntnt->FindTabFrm(); + if ( pLst->IsInSct() ) + pLst = pCntnt->FindSctFrm(); + pLst = pLst->FindPrev(); + if ( pLst && + (pLst->Frm().Top() >= rVis.Bottom() || + pLst->Frm().Left()>= rVis.Right()) ) + { + bTstCnt = sal_False; + } + } + + if ( bTstCnt ) + { + // --> OD 2004-06-04 #i27756# - check after each frame calculation, + // if the content frame has changed the page. If yes, no other + // frame calculation is performed + bool bPageChg = false; + + if ( pCntnt->IsInSct() ) + { + const SwSectionFrm *pSct = ((SwFrm*)pCntnt)->ImplFindSctFrm(); + if ( !pSct->IsValid() ) + { + pSct->Calc(); + pSct->SetCompletePaint(); + if ( IsAgain() ) + return sal_False; + // --> OD 2004-06-04 #i27756# + bPageChg = pCntnt->FindPageFrm() != p2ndPage && + prPage->GetPrev(); + } + } + + if ( !bPageChg && !pCntnt->IsValid() ) + { + pCntnt->Calc(); + pCntnt->SetCompletePaint(); + if ( IsAgain() ) + return sal_False; + // --> OD 2004-06-04 #i27756# + bPageChg = pCntnt->FindPageFrm() != p2ndPage && + prPage->GetPrev(); + } + + if ( !bPageChg && pCntnt->IsInTab() ) + { + const SwTabFrm *pTab = ((SwFrm*)pCntnt)->ImplFindTabFrm(); + if ( !pTab->IsValid() ) + { + pTab->Calc(); + pTab->SetCompletePaint(); + if ( IsAgain() ) + return sal_False; + // --> OD 2004-06-04 #i27756# + bPageChg = pCntnt->FindPageFrm() != p2ndPage && + prPage->GetPrev(); + } + } + + if ( !bPageChg && pCntnt->IsInSct() ) + { + const SwSectionFrm *pSct = ((SwFrm*)pCntnt)->ImplFindSctFrm(); + if ( !pSct->IsValid() ) + { + pSct->Calc(); + pSct->SetCompletePaint(); + if ( IsAgain() ) + return sal_False; + // --> OD 2004-06-04 #i27756# + bPageChg = pCntnt->FindPageFrm() != p2ndPage && + prPage->GetPrev(); + } + } + + // --> OD 2004-06-04 #i27756# + if ( bPageChg ) + { + bRet = sal_False; + const SwPageFrm* pTmp = pCntnt->FindPageFrm(); + if ( pTmp->GetPhyPageNum() < prPage->GetPhyPageNum() && + pTmp->IsInvalid() ) + { + prPage = (SwPageFrm*)pTmp; + } + else + { + prPage = (SwPageFrm*)prPage->GetPrev(); + } + } + // --> OD 2005-04-25 #121980# - no shortcut, if at previous page + // an anchored object is registered, whose anchor is <pCntnt>. + else if ( prPage->GetPrev() && + static_cast<SwPageFrm*>(prPage->GetPrev())->GetSortedObjs() ) + { + SwSortedObjs* pObjs = + static_cast<SwPageFrm*>(prPage->GetPrev())->GetSortedObjs(); + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pObj = (*pObjs)[i]; + if ( pObj->GetAnchorFrmContainingAnchPos() == pCntnt ) + { + bRet = sal_False; + break; + } + } + } + } + // <-- + } + } + } + + if ( !bRet && bBrowse ) + { + const long nBottom = rVis.Bottom(); + const SwAnchoredObject* pObj( 0L ); + if ( prPage->GetSortedObjs() && + (prPage->IsInvalidFlyLayout() || prPage->IsInvalidFlyCntnt()) && + 0 != (pObj = lcl_FindFirstInvaObj( prPage, nBottom )) && + pObj->GetObjRect().Top() <= nBottom ) + { + return sal_False; + } + const SwFrm* pFrm( 0L ); + if ( prPage->IsInvalidLayout() && + 0 != (pFrm = lcl_FindFirstInvaLay( prPage, nBottom )) && + pFrm->Frm().Top() <= nBottom ) + { + return sal_False; + } + if ( (prPage->IsInvalidCntnt() || prPage->IsInvalidFlyInCnt()) && + 0 != (pFrm = lcl_FindFirstInvaCntnt( prPage, nBottom, 0 )) && + pFrm->Frm().Top() <= nBottom ) + { + return sal_False; + } + bRet = sal_True; + } + return bRet; +} + +/************************************************************************* +|* +|* SwLayAction::FormatLayout(), FormatLayoutFly, FormatLayoutTab() +|* +|*************************************************************************/ +// OD 15.11.2002 #105155# - introduce support for vertical layout +sal_Bool SwLayAction::FormatLayout( SwLayoutFrm *pLay, sal_Bool bAddRect ) +{ + OSL_ENSURE( !IsAgain(), "Ungueltige Seite beachten." ); + if ( IsAgain() ) + return sal_False; + + sal_Bool bChanged = sal_False; + sal_Bool bAlreadyPainted = sal_False; + // OD 11.11.2002 #104414# - remember frame at complete paint + SwRect aFrmAtCompletePaint; + + if ( !pLay->IsValid() || pLay->IsCompletePaint() ) + { + if ( pLay->GetPrev() && !pLay->GetPrev()->IsValid() ) + pLay->GetPrev()->SetCompletePaint(); + + SwRect aOldFrame( pLay->Frm() ); + SwRect aOldRect( aOldFrame ); + if( pLay->IsPageFrm() ) + { + aOldRect = static_cast<SwPageFrm*>(pLay)->GetBoundRect(); + } + + pLay->Calc(); + if ( aOldFrame != pLay->Frm() ) + bChanged = sal_True; + + sal_Bool bNoPaint = sal_False; + if ( pLay->IsPageBodyFrm() && + pLay->Frm().Pos() == aOldRect.Pos() && + pLay->Lower() ) + { + const ViewShell *pSh = pLay->getRootFrm()->GetCurrShell(); + //Einschraenkungen wegen Kopf-/Fusszeilen + if( pSh && pSh->GetViewOptions()->getBrowseMode() && + !( pLay->IsCompletePaint() && pLay->FindPageFrm()->FindFtnCont() ) ) + bNoPaint = sal_True; + } + + if ( !bNoPaint && IsPaint() && bAddRect && (pLay->IsCompletePaint() || bChanged) ) + { + SwRect aPaint( pLay->Frm() ); + // OD 13.02.2003 #i9719#, #105645# - consider border and shadow for + // page frames -> enlarge paint rectangle correspondingly. + if ( pLay->IsPageFrm() ) + { + SwPageFrm* pPageFrm = static_cast<SwPageFrm*>(pLay); + aPaint = pPageFrm->GetBoundRect(); + } + + sal_Bool bPageInBrowseMode = pLay->IsPageFrm(); + if( bPageInBrowseMode ) + { + const ViewShell *pSh = pLay->getRootFrm()->GetCurrShell(); + if( !pSh || !pSh->GetViewOptions()->getBrowseMode() ) + bPageInBrowseMode = sal_False; + } + if( bPageInBrowseMode ) + { + // NOTE: no vertical layout in online layout + //Ist die Aenderung ueberhaupt sichtbar? + if ( pLay->IsCompletePaint() ) + { + pImp->GetShell()->AddPaintRect( aPaint ); + bAddRect = sal_False; + } + else + { + sal_uInt16 i; + + SwRegionRects aRegion( aOldRect ); + aRegion -= aPaint; + for ( i = 0; i < aRegion.Count(); ++i ) + pImp->GetShell()->AddPaintRect( aRegion[i] ); + aRegion.ChangeOrigin( aPaint ); + aRegion.Remove( 0, aRegion.Count() ); + aRegion.Insert( aPaint, 0 ); + aRegion -= aOldRect; + for ( i = 0; i < aRegion.Count(); ++i ) + pImp->GetShell()->AddPaintRect( aRegion[i] ); + } + + } + else + { + pImp->GetShell()->AddPaintRect( aPaint ); + bAlreadyPainted = sal_True; + // OD 11.11.2002 #104414# - remember frame at complete paint + aFrmAtCompletePaint = pLay->Frm(); + } + + // OD 13.02.2003 #i9719#, #105645# - provide paint of spacing + // between pages (not only for in online mode). + if ( pLay->IsPageFrm() ) + { + const SwTwips nHalfDocBorder = GAPBETWEENPAGES; + const bool bLeftToRightViewLayout = pRoot->IsLeftToRightViewLayout(); + const bool bPrev = bLeftToRightViewLayout ? pLay->GetPrev() : pLay->GetNext(); + const bool bNext = bLeftToRightViewLayout ? pLay->GetNext() : pLay->GetPrev(); + SwPageFrm* pPageFrm = static_cast<SwPageFrm*>(pLay); + const ViewShell *pSh = pLay->getRootFrm()->GetCurrShell(); + SwRect aPageRect( pLay->Frm() ); + + if(pSh) + { + SwPageFrm::GetBorderAndShadowBoundRect(aPageRect, pSh, + aPageRect, pPageFrm->IsLeftShadowNeeded(), pPageFrm->IsRightShadowNeeded(), + pPageFrm->SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT); + } + + if ( bPrev ) + { + // top + SwRect aSpaceToPrevPage( aPageRect ); + aSpaceToPrevPage.Top( aSpaceToPrevPage.Top() - nHalfDocBorder ); + aSpaceToPrevPage.Bottom( pLay->Frm().Top() ); + if(aSpaceToPrevPage.Height() > 0 && aSpaceToPrevPage.Width() > 0) + pImp->GetShell()->AddPaintRect( aSpaceToPrevPage ); + + pSh->GetOut()->DrawRect( aSpaceToPrevPage.SVRect() ); + + // left + aSpaceToPrevPage = aPageRect; + aSpaceToPrevPage.Left( aSpaceToPrevPage.Left() - nHalfDocBorder ); + aSpaceToPrevPage.Right( pLay->Frm().Left() ); + if(aSpaceToPrevPage.Height() > 0 && aSpaceToPrevPage.Width() > 0) + pImp->GetShell()->AddPaintRect( aSpaceToPrevPage ); + } + if ( bNext ) + { + // bottom + SwRect aSpaceToNextPage( aPageRect ); + aSpaceToNextPage.Bottom( aSpaceToNextPage.Bottom() + nHalfDocBorder ); + aSpaceToNextPage.Top( pLay->Frm().Bottom() ); + if(aSpaceToNextPage.Height() > 0 && aSpaceToNextPage.Width() > 0) + pImp->GetShell()->AddPaintRect( aSpaceToNextPage ); + + // right + aSpaceToNextPage = aPageRect; + aSpaceToNextPage.Right( aSpaceToNextPage.Right() + nHalfDocBorder ); + aSpaceToNextPage.Left( pLay->Frm().Right() ); + if(aSpaceToNextPage.Height() > 0 && aSpaceToNextPage.Width() > 0) + pImp->GetShell()->AddPaintRect( aSpaceToNextPage ); + } + } + } + pLay->ResetCompletePaint(); + } + + if ( IsPaint() && bAddRect && + !pLay->GetNext() && pLay->IsRetoucheFrm() && pLay->IsRetouche() ) + { + // OD 15.11.2002 #105155# - vertical layout support + SWRECTFN( pLay ); + SwRect aRect( pLay->GetUpper()->PaintArea() ); + (aRect.*fnRect->fnSetTop)( (pLay->*fnRect->fnGetPrtBottom)() ); + if ( !pImp->GetShell()->AddPaintRect( aRect ) ) + pLay->ResetRetouche(); + } + + if( bAlreadyPainted ) + bAddRect = sal_False; + + CheckWaitCrsr(); + + if ( IsAgain() ) + return sal_False; + + //Jetzt noch diejenigen Lowers versorgen die LayoutFrm's sind + + if ( pLay->IsFtnFrm() ) //Hat keine LayFrms als Lower. + return bChanged; + + SwFrm *pLow = pLay->Lower(); + sal_Bool bTabChanged = sal_False; + while ( pLow && pLow->GetUpper() == pLay ) + { + if ( pLow->IsLayoutFrm() ) + { + if ( pLow->IsTabFrm() ) + bTabChanged |= FormatLayoutTab( (SwTabFrm*)pLow, bAddRect ); + // bereits zum Loeschen angemeldete Ueberspringen + else if( !pLow->IsSctFrm() || ((SwSectionFrm*)pLow)->GetSection() ) + bChanged |= FormatLayout( (SwLayoutFrm*)pLow, bAddRect ); + } + else if ( pImp->GetShell()->IsPaintLocked() ) + //Abkuerzung im die Zyklen zu minimieren, bei Lock kommt das + //Paint sowieso (Primaer fuer Browse) + pLow->OptCalc(); + + if ( IsAgain() ) + return sal_False; + pLow = pLow->GetNext(); + } + // OD 11.11.2002 #104414# - add complete frame area as paint area, if frame + // area has been already added and after formating its lowers the frame area + // is enlarged. + SwRect aBoundRect(pLay->IsPageFrm() ? static_cast<SwPageFrm*>(pLay)->GetBoundRect() : pLay->Frm() ); + + if ( bAlreadyPainted && + ( aBoundRect.Width() > aFrmAtCompletePaint.Width() || + aBoundRect.Height() > aFrmAtCompletePaint.Height() ) + ) + { + pImp->GetShell()->AddPaintRect( aBoundRect ); + } + return bChanged || bTabChanged; +} + +sal_Bool SwLayAction::FormatLayoutFly( SwFlyFrm* pFly ) +{ + OSL_ENSURE( !IsAgain(), "Ungueltige Seite beachten." ); + if ( IsAgain() ) + return sal_False; + + sal_Bool bChanged = false; + sal_Bool bAddRect = true; + + if ( !pFly->IsValid() || pFly->IsCompletePaint() || pFly->IsInvalid() ) + { + //Der Frame hat sich veraendert, er wird jetzt Formatiert + const SwRect aOldRect( pFly->Frm() ); + pFly->Calc(); + bChanged = aOldRect != pFly->Frm(); + + if ( IsPaint() && (pFly->IsCompletePaint() || bChanged) && + pFly->Frm().Top() > 0 && pFly->Frm().Left() > 0 ) + pImp->GetShell()->AddPaintRect( pFly->Frm() ); + + if ( bChanged ) + pFly->Invalidate(); + else + pFly->Validate(); +/* + //mba: it's unclear why we should invalidate always, so I remove it + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( IsPaint() && bAddRect && pFly->Frm().Top() > 0 && pFly->Frm().Left() > 0 ) + pImp->GetShell()->AddPaintRect( pFly->Frm() ); + + pFly->Invalidate(); +*/ + bAddRect = false; + pFly->ResetCompletePaint(); + } + + if ( IsAgain() ) + return sal_False; + + //Jetzt noch diejenigen Lowers versorgen die LayoutFrm's sind + sal_Bool bTabChanged = false; + SwFrm *pLow = pFly->Lower(); + while ( pLow ) + { + if ( pLow->IsLayoutFrm() ) + { + if ( pLow->IsTabFrm() ) + bTabChanged |= FormatLayoutTab( (SwTabFrm*)pLow, bAddRect ); + else + bChanged |= FormatLayout( (SwLayoutFrm*)pLow, bAddRect ); + } + pLow = pLow->GetNext(); + } + return bChanged || bTabChanged; +} + +// OD 31.10.2002 #104100# +// Implement vertical layout support +sal_Bool SwLayAction::FormatLayoutTab( SwTabFrm *pTab, sal_Bool bAddRect ) +{ + OSL_ENSURE( !IsAgain(), "8-) Ungueltige Seite beachten." ); + if ( IsAgain() || !pTab->Lower() ) + return sal_False; + + IDocumentTimerAccess *pTimerAccess = pRoot->GetFmt()->getIDocumentTimerAccess(); + pTimerAccess->BlockIdling(); + + sal_Bool bChanged = sal_False; + sal_Bool bPainted = sal_False; + + const SwPageFrm *pOldPage = pTab->FindPageFrm(); + + // OD 31.10.2002 #104100# - vertical layout support + // use macro to declare and init <sal_Bool bVert>, <sal_Bool bRev> and + // <SwRectFn fnRect> for table frame <pTab>. + SWRECTFN( pTab ); + + if ( !pTab->IsValid() || pTab->IsCompletePaint() || pTab->IsComplete() ) + { + if ( pTab->GetPrev() && !pTab->GetPrev()->IsValid() ) + { + pTab->GetPrev()->SetCompletePaint(); + } + + const SwRect aOldRect( pTab->Frm() ); + pTab->SetLowersFormatted( sal_False ); + pTab->Calc(); + if ( aOldRect != pTab->Frm() ) + { + bChanged = sal_True; + } + const SwRect aPaintFrm = pTab->PaintArea(); + + if ( IsPaint() && bAddRect ) + { + // OD 01.11.2002 #104100# - add condition <pTab->Frm().HasArea()> + if ( !pTab->IsCompletePaint() && + pTab->IsComplete() && + ( pTab->Frm().SSize() != pTab->Prt().SSize() || + // OD 31.10.2002 #104100# - vertical layout support + (pTab->*fnRect->fnGetLeftMargin)() ) && + pTab->Frm().HasArea() + ) + { + // OD 01.11.2002 #104100# - re-implement calculation of margin rectangles. + SwRect aMarginRect; + + SwTwips nLeftMargin = (pTab->*fnRect->fnGetLeftMargin)(); + if ( nLeftMargin > 0) + { + aMarginRect = pTab->Frm(); + (aMarginRect.*fnRect->fnSetWidth)( nLeftMargin ); + pImp->GetShell()->AddPaintRect( aMarginRect ); + } + + if ( (pTab->*fnRect->fnGetRightMargin)() > 0) + { + aMarginRect = pTab->Frm(); + (aMarginRect.*fnRect->fnSetLeft)( (pTab->*fnRect->fnGetPrtRight)() ); + pImp->GetShell()->AddPaintRect( aMarginRect ); + } + + SwTwips nTopMargin = (pTab->*fnRect->fnGetTopMargin)(); + if ( nTopMargin > 0) + { + aMarginRect = pTab->Frm(); + (aMarginRect.*fnRect->fnSetHeight)( nTopMargin ); + pImp->GetShell()->AddPaintRect( aMarginRect ); + } + + if ( (pTab->*fnRect->fnGetBottomMargin)() > 0) + { + aMarginRect = pTab->Frm(); + (aMarginRect.*fnRect->fnSetTop)( (pTab->*fnRect->fnGetPrtBottom)() ); + pImp->GetShell()->AddPaintRect( aMarginRect ); + } + } + else if ( pTab->IsCompletePaint() ) + { + pImp->GetShell()->AddPaintRect( aPaintFrm ); + bAddRect = sal_False; + bPainted = sal_True; + } + + if ( pTab->IsRetouche() && !pTab->GetNext() ) + { + SwRect aRect( pTab->GetUpper()->PaintArea() ); + // OD 04.11.2002 #104100# - vertical layout support + (aRect.*fnRect->fnSetTop)( (pTab->*fnRect->fnGetPrtBottom)() ); + if ( !pImp->GetShell()->AddPaintRect( aRect ) ) + pTab->ResetRetouche(); + } + } + else + bAddRect = sal_False; + + if ( pTab->IsCompletePaint() && !pOptTab ) + pOptTab = pTab; + pTab->ResetCompletePaint(); + } + if ( IsPaint() && bAddRect && pTab->IsRetouche() && !pTab->GetNext() ) + { + // OD 04.10.2002 #102779# + // set correct rectangle for retouche: area between bottom of table frame + // and bottom of paint area of the upper frame. + SwRect aRect( pTab->GetUpper()->PaintArea() ); + // OD 04.11.2002 #104100# - vertical layout support + (aRect.*fnRect->fnSetTop)( (pTab->*fnRect->fnGetPrtBottom)() ); + if ( !pImp->GetShell()->AddPaintRect( aRect ) ) + pTab->ResetRetouche(); + } + + CheckWaitCrsr(); + + pTimerAccess->UnblockIdling(); + + //Heftige Abkuerzung! + if ( pTab->IsLowersFormatted() && + (bPainted || !pImp->GetShell()->VisArea().IsOver( pTab->Frm())) ) + return sal_False; + + //Jetzt noch die Lowers versorgen + if ( IsAgain() ) + return sal_False; + + // OD 20.10.2003 #112464# - for savety reasons: + // check page number before formatting lowers. + if ( pOldPage->GetPhyPageNum() > (pTab->FindPageFrm()->GetPhyPageNum() + 1) ) + SetNextCycle( sal_True ); + + // OD 20.10.2003 #112464# - format lowers, only if table frame is valid + if ( pTab->IsValid() ) + { + SwLayoutFrm *pLow = (SwLayoutFrm*)pTab->Lower(); + while ( pLow ) + { + bChanged |= FormatLayout( (SwLayoutFrm*)pLow, bAddRect ); + if ( IsAgain() ) + return sal_False; + pLow = (SwLayoutFrm*)pLow->GetNext(); + } + } + + return bChanged; +} + +/************************************************************************* +|* +|* SwLayAction::FormatCntnt() +|* +|*************************************************************************/ +sal_Bool SwLayAction::FormatCntnt( const SwPageFrm *pPage ) +{ + const SwCntntFrm *pCntnt = pPage->ContainsCntnt(); + const ViewShell *pSh = pRoot->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + + while ( pCntnt && pPage->IsAnLower( pCntnt ) ) + { + //Wenn der Cntnt sich eh nicht veraendert koennen wir ein paar + //Abkuerzungen nutzen. + const sal_Bool bFull = !pCntnt->IsValid() || pCntnt->IsCompletePaint() || + pCntnt->IsRetouche() || pCntnt->GetDrawObjs(); + if ( bFull ) + { + //Damit wir nacher nicht suchen muessen. + const sal_Bool bNxtCnt = IsCalcLayout() && !pCntnt->GetFollow(); + const SwCntntFrm *pCntntNext = bNxtCnt ? pCntnt->GetNextCntntFrm() : 0; + const SwCntntFrm *pCntntPrev = pCntnt->GetPrev() ? pCntnt->GetPrevCntntFrm() : 0; + + const SwLayoutFrm*pOldUpper = pCntnt->GetUpper(); + const SwTabFrm *pTab = pCntnt->FindTabFrm(); + const sal_Bool bInValid = !pCntnt->IsValid() || pCntnt->IsCompletePaint(); + const sal_Bool bOldPaint = IsPaint(); + bPaint = bOldPaint && !(pTab && pTab == pOptTab); + _FormatCntnt( pCntnt, pPage ); + // --> OD 2004-11-05 #i26945# - reset <bPaint> before format objects + bPaint = bOldPaint; + // <-- + + // OD 2004-05-10 #i28701# - format floating screen object at content frame. + // No format, if action flag <bAgain> is set or action is interrupted. + // OD 2004-08-30 #117736# - allow format on interruption of action, if + // it's the format for this interrupt + // --> OD 2004-11-01 #i23129#, #i36347# - pass correct page frame + // to the object formatter. + if ( !IsAgain() && + ( !IsInterrupt() || mbFormatCntntOnInterrupt ) && + pCntnt->IsTxtFrm() && + !SwObjectFormatter::FormatObjsAtFrm( *(const_cast<SwCntntFrm*>(pCntnt)), + *(pCntnt->FindPageFrm()), this ) ) + // <-- + { + return sal_False; + } + + if ( !pCntnt->GetValidLineNumFlag() && pCntnt->IsTxtFrm() ) + { + const sal_uLong nAllLines = ((SwTxtFrm*)pCntnt)->GetAllLines(); + ((SwTxtFrm*)pCntnt)->RecalcAllLines(); + if ( IsPaintExtraData() && IsPaint() && + nAllLines != ((SwTxtFrm*)pCntnt)->GetAllLines() ) + pImp->GetShell()->AddPaintRect( pCntnt->Frm() ); + } + + if ( IsAgain() ) + return sal_False; + + //Wenn Layout oder Flys wieder Invalid sind breche ich die Verarbeitung + //vorlaeufig ab - allerdings nicht fuer die BrowseView, denn dort wird + //das Layout staendig ungueltig, weil die Seitenhoehe angepasst wird. + //Desgleichen wenn der Benutzer weiterarbeiten will und mindestens ein + //Absatz verarbeitet wurde. + if ( (!pTab || (pTab && !bInValid)) ) + { + CheckIdleEnd(); + // OD 14.04.2003 #106346# - consider interrupt formatting. + if ( ( IsInterrupt() && !mbFormatCntntOnInterrupt ) || + ( !bBrowse && pPage->IsInvalidLayout() ) || + // OD 07.05.2003 #109435# - consider interrupt formatting + ( IS_FLYS && IS_INVAFLY && !mbFormatCntntOnInterrupt ) + ) + return sal_False; + } + if ( pOldUpper != pCntnt->GetUpper() ) + { + const sal_uInt16 nCurNum = pCntnt->FindPageFrm()->GetPhyPageNum(); + if ( nCurNum < pPage->GetPhyPageNum() ) + nPreInvaPage = nCurNum; + + //Wenn der Frm mehr als eine Seite rueckwaerts geflossen ist, so + //fangen wir nocheinmal von vorn an damit wir nichts auslassen. + if ( !IsCalcLayout() && pPage->GetPhyPageNum() > nCurNum+1 ) + { + SetNextCycle( sal_True ); + // OD 07.05.2003 #109435# - consider interrupt formatting + if ( !mbFormatCntntOnInterrupt ) + { + return sal_False; + } + } + } + //Wenn der Frame die Seite vorwaerts gewechselt hat, so lassen wir + //den Vorgaenger nocheinmal durchlaufen. + //So werden einerseits Vorgaenger erwischt, die jetzt f?r Retouche + //verantwortlich sind, andererseits werden die Fusszeilen + //auch angefasst. + sal_Bool bSetCntnt = sal_True; + if ( pCntntPrev ) + { + if ( !pCntntPrev->IsValid() && pPage->IsAnLower( pCntntPrev ) ) + pPage->InvalidateCntnt(); + if ( pOldUpper != pCntnt->GetUpper() && + pPage->GetPhyPageNum() < pCntnt->FindPageFrm()->GetPhyPageNum() ) + { + pCntnt = pCntntPrev; + bSetCntnt = sal_False; + } + } + if ( bSetCntnt ) + { + if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() && + pCntnt->Frm().Top() > pImp->GetShell()->VisArea().Bottom()) + { + const long nBottom = pImp->GetShell()->VisArea().Bottom(); + const SwFrm *pTmp = lcl_FindFirstInvaCntnt( pPage, + nBottom, pCntnt ); + if ( !pTmp ) + { + if ( (!(IS_FLYS && IS_INVAFLY) || + !lcl_FindFirstInvaObj( pPage, nBottom )) && + (!pPage->IsInvalidLayout() || + !lcl_FindFirstInvaLay( pPage, nBottom ))) + SetBrowseActionStop( sal_True ); + // OD 14.04.2003 #106346# - consider interrupt formatting. + if ( !mbFormatCntntOnInterrupt ) + { + return sal_False; + } + } + } + pCntnt = bNxtCnt ? pCntntNext : pCntnt->GetNextCntntFrm(); + } + + RESCHEDULE; + } + else + { + if ( !pCntnt->GetValidLineNumFlag() && pCntnt->IsTxtFrm() ) + { + const sal_uLong nAllLines = ((SwTxtFrm*)pCntnt)->GetAllLines(); + ((SwTxtFrm*)pCntnt)->RecalcAllLines(); + if ( IsPaintExtraData() && IsPaint() && + nAllLines != ((SwTxtFrm*)pCntnt)->GetAllLines() ) + pImp->GetShell()->AddPaintRect( pCntnt->Frm() ); + } + + //Falls der Frm schon vor der Abarbeitung hier formatiert wurde. + if ( pCntnt->IsTxtFrm() && ((SwTxtFrm*)pCntnt)->HasRepaint() && + IsPaint() ) + PaintCntnt( pCntnt, pPage, pCntnt->Frm(), pCntnt->Frm().Bottom()); + if ( IsIdle() ) + { + CheckIdleEnd(); + // OD 14.04.2003 #106346# - consider interrupt formatting. + if ( IsInterrupt() && !mbFormatCntntOnInterrupt ) + return sal_False; + } + if ( bBrowse && !IsIdle() && !IsCalcLayout() && !IsComplete() && + pCntnt->Frm().Top() > pImp->GetShell()->VisArea().Bottom()) + { + const long nBottom = pImp->GetShell()->VisArea().Bottom(); + const SwFrm *pTmp = lcl_FindFirstInvaCntnt( pPage, + nBottom, pCntnt ); + if ( !pTmp ) + { + if ( (!(IS_FLYS && IS_INVAFLY) || + !lcl_FindFirstInvaObj( pPage, nBottom )) && + (!pPage->IsInvalidLayout() || + !lcl_FindFirstInvaLay( pPage, nBottom ))) + SetBrowseActionStop( sal_True ); + // OD 14.04.2003 #106346# - consider interrupt formatting. + if ( !mbFormatCntntOnInterrupt ) + { + return sal_False; + } + } + } + pCntnt = pCntnt->GetNextCntntFrm(); + } + } + CheckWaitCrsr(); + // OD 14.04.2003 #106346# - consider interrupt formatting. + return !IsInterrupt() || mbFormatCntntOnInterrupt; +} +/************************************************************************* +|* +|* SwLayAction::_FormatCntnt() +|* +|* Beschreibung Returnt sal_True wenn der Absatz verarbeitet wurde, +|* sal_False wenn es nichts zu verarbeiten gab. +|* +|*************************************************************************/ +void SwLayAction::_FormatCntnt( const SwCntntFrm *pCntnt, + const SwPageFrm *pPage ) +{ + //wird sind hier evtl. nur angekommen, weil der Cntnt DrawObjekte haelt. + const bool bDrawObjsOnly = pCntnt->IsValid() && !pCntnt->IsCompletePaint() && + !pCntnt->IsRetouche(); + SWRECTFN( pCntnt ) + if ( !bDrawObjsOnly && IsPaint() ) + { + const SwRect aOldRect( pCntnt->UnionFrm() ); + const long nOldBottom = (pCntnt->*fnRect->fnGetPrtBottom)(); + pCntnt->OptCalc(); + if( IsAgain() ) + return; + if( (*fnRect->fnYDiff)( (pCntnt->Frm().*fnRect->fnGetBottom)(), + (aOldRect.*fnRect->fnGetBottom)() ) < 0 ) + { + pCntnt->SetRetouche(); + } + PaintCntnt( pCntnt, pCntnt->FindPageFrm(), aOldRect, nOldBottom); + } + else + { + if ( IsPaint() && pCntnt->IsTxtFrm() && ((SwTxtFrm*)pCntnt)->HasRepaint() ) + PaintCntnt( pCntnt, pPage, pCntnt->Frm(), + (pCntnt->Frm().*fnRect->fnGetBottom)() ); + pCntnt->OptCalc(); + } +} + +/************************************************************************* +|* +|* SwLayAction::_FormatFlyCntnt() +|* +|* Beschreibung: +|* - Returnt sal_True wenn alle Cntnts des Flys vollstaendig verarbeitet +|* wurden. sal_False wenn vorzeitig unterbrochen wurde. +|* +|*************************************************************************/ +sal_Bool SwLayAction::_FormatFlyCntnt( const SwFlyFrm *pFly ) +{ + const SwCntntFrm *pCntnt = pFly->ContainsCntnt(); + + while ( pCntnt ) + { + // OD 2004-05-10 #i28701# + _FormatCntnt( pCntnt, pCntnt->FindPageFrm() ); + + // --> OD 2004-07-23 #i28701# - format floating screen objects + // at content text frame + // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame + // to the object formatter. + if ( pCntnt->IsTxtFrm() && + !SwObjectFormatter::FormatObjsAtFrm( + *(const_cast<SwCntntFrm*>(pCntnt)), + *(pCntnt->FindPageFrm()), this ) ) + // <-- + { + // restart format with first content + pCntnt = pFly->ContainsCntnt(); + continue; + } + // <-- + + if ( !pCntnt->GetValidLineNumFlag() && pCntnt->IsTxtFrm() ) + { + const sal_uLong nAllLines = ((SwTxtFrm*)pCntnt)->GetAllLines(); + ((SwTxtFrm*)pCntnt)->RecalcAllLines(); + if ( IsPaintExtraData() && IsPaint() && + nAllLines != ((SwTxtFrm*)pCntnt)->GetAllLines() ) + pImp->GetShell()->AddPaintRect( pCntnt->Frm() ); + } + + if ( IsAgain() ) + return sal_False; + + //wenn eine Eingabe anliegt breche ich die Verarbeitung ab. + if ( !pFly->IsFlyInCntFrm() ) + { + CheckIdleEnd(); + // OD 14.04.2003 #106346# - consider interrupt formatting. + if ( IsInterrupt() && !mbFormatCntntOnInterrupt ) + return sal_False; + } + pCntnt = pCntnt->GetNextCntntFrm(); + } + CheckWaitCrsr(); + // OD 14.04.2003 #106346# - consider interrupt formatting. + return !(IsInterrupt() && !mbFormatCntntOnInterrupt); +} + +sal_Bool SwLayAction::IsStopPrt() const +{ + sal_Bool bResult = sal_False; + + if (pImp != NULL && pProgress != NULL) + bResult = pImp->IsStopPrt(); + + return bResult; +} + +/************************************************************************* +|* +|* SwLayAction::FormatSpelling(), _FormatSpelling() +|* +|*************************************************************************/ +sal_Bool SwLayIdle::_DoIdleJob( const SwCntntFrm *pCnt, IdleJobType eJob ) +{ + OSL_ENSURE( pCnt->IsTxtFrm(), "NoTxt neighbour of Txt" ); + // robust against misuse by e.g. #i52542# + if( !pCnt->IsTxtFrm() ) + return sal_False; + + const SwTxtNode* pTxtNode = pCnt->GetNode()->GetTxtNode(); + + bool bProcess = false; + switch ( eJob ) + { + case ONLINE_SPELLING : + bProcess = pTxtNode->IsWrongDirty(); break; + case AUTOCOMPLETE_WORDS : + bProcess = pTxtNode->IsAutoCompleteWordDirty(); break; + case WORD_COUNT : + bProcess = pTxtNode->IsWordCountDirty(); break; + case SMART_TAGS : // SMARTTAGS + bProcess = pTxtNode->IsSmartTagDirty(); break; + } + + if( bProcess ) + { + ViewShell *pSh = pImp->GetShell(); + if( STRING_LEN == nTxtPos ) + { + --nTxtPos; + if( pSh->ISA(SwCrsrShell) && !((SwCrsrShell*)pSh)->IsTableMode() ) + { + SwPaM *pCrsr = ((SwCrsrShell*)pSh)->GetCrsr(); + if( !pCrsr->HasMark() && pCrsr == pCrsr->GetNext() ) + { + pCntntNode = pCrsr->GetCntntNode(); + nTxtPos = pCrsr->GetPoint()->nContent.GetIndex(); + } + } + } + + switch ( eJob ) + { + case ONLINE_SPELLING : + { + SwRect aRepaint( ((SwTxtFrm*)pCnt)->_AutoSpell( pCntntNode, *pSh->GetViewOptions(), nTxtPos ) ); + bPageValid = bPageValid && !pTxtNode->IsWrongDirty(); + if( !bPageValid ) + bAllValid = sal_False; + if ( aRepaint.HasArea() ) + pImp->GetShell()->InvalidateWindows( aRepaint ); + if ( Application::AnyInput( INPUT_MOUSEANDKEYBOARD|INPUT_OTHER|INPUT_PAINT ) ) + return sal_True; + break; + } + case AUTOCOMPLETE_WORDS : + ((SwTxtFrm*)pCnt)->CollectAutoCmplWrds( pCntntNode, nTxtPos ); + if ( Application::AnyInput( INPUT_ANY ) ) + return sal_True; + break; + case WORD_COUNT : + { + const xub_StrLen nEnd = pTxtNode->GetTxt().Len(); + SwDocStat aStat; + pTxtNode->CountWords( aStat, 0, nEnd ); + if ( Application::AnyInput( INPUT_ANY ) ) + return sal_True; + break; + } + case SMART_TAGS : // SMARTTAGS + { + const SwRect aRepaint( ((SwTxtFrm*)pCnt)->SmartTagScan( pCntntNode, nTxtPos ) ); + bPageValid = bPageValid && !pTxtNode->IsSmartTagDirty(); + if( !bPageValid ) + bAllValid = sal_False; + if ( aRepaint.HasArea() ) + pImp->GetShell()->InvalidateWindows( aRepaint ); + if ( Application::AnyInput( INPUT_MOUSEANDKEYBOARD|INPUT_OTHER|INPUT_PAINT ) ) + return sal_True; + break; + } + } + } + + //Die im Absatz verankerten Flys wollen auch mitspielen. + 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() ) + { + const SwCntntFrm *pC = pFly->ContainsCntnt(); + while( pC ) + { + if ( pC->IsTxtFrm() ) + { + if ( _DoIdleJob( pC, eJob ) ) + return sal_True; + } + pC = pC->GetNextCntntFrm(); + } + } + } + } + } + return sal_False; +} + +sal_Bool SwLayIdle::DoIdleJob( IdleJobType eJob, sal_Bool bVisAreaOnly ) +{ + //Spellchecken aller Inhalte der Seiten. Entweder nur der sichtbaren + //Seiten oder eben aller. + const ViewShell* pViewShell = pImp->GetShell(); + const SwViewOption* pViewOptions = pViewShell->GetViewOptions(); + const SwDoc* pDoc = pViewShell->GetDoc(); + + switch ( eJob ) + { + case ONLINE_SPELLING : + if( !pViewOptions->IsOnlineSpell() ) + return sal_False; + break; + case AUTOCOMPLETE_WORDS : + if( !pViewOptions->IsAutoCompleteWords() || + pDoc->GetAutoCompleteWords().IsLockWordLstLocked()) + return sal_False; + break; + case WORD_COUNT : + if ( !pViewShell->getIDocumentStatistics()->GetDocStat().bModified ) + return sal_False; + break; + case SMART_TAGS : + if ( pDoc->GetDocShell()->IsHelpDocument() || + pDoc->isXForms() || + !SwSmartTagMgr::Get().IsSmartTagsEnabled() ) + return sal_False; + break; + default: OSL_FAIL( "Unknown idle job type" ); + } + + SwPageFrm *pPage; + if ( bVisAreaOnly ) + pPage = pImp->GetFirstVisPage(); + else + pPage = (SwPageFrm*)pRoot->Lower(); + + pCntntNode = NULL; + nTxtPos = STRING_LEN; + + while ( pPage ) + { + bPageValid = sal_True; + const SwCntntFrm *pCnt = pPage->ContainsCntnt(); + while( pCnt && pPage->IsAnLower( pCnt ) ) + { + if ( _DoIdleJob( pCnt, eJob ) ) + return sal_True; + pCnt = pCnt->GetNextCntntFrm(); + } + if ( pPage->GetSortedObjs() ) + { + for ( sal_uInt16 i = 0; pPage->GetSortedObjs() && + i < pPage->GetSortedObjs()->Count(); ++i ) + { + const SwAnchoredObject* pObj = (*pPage->GetSortedObjs())[i]; + if ( pObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pObj); + const SwCntntFrm *pC = pFly->ContainsCntnt(); + while( pC ) + { + if ( pC->IsTxtFrm() ) + { + if ( _DoIdleJob( pC, eJob ) ) + return sal_True; + } + pC = pC->GetNextCntntFrm(); + } + } + } + } + + if( bPageValid ) + { + switch ( eJob ) + { + case ONLINE_SPELLING : pPage->ValidateSpelling(); break; + case AUTOCOMPLETE_WORDS : pPage->ValidateAutoCompleteWords(); break; + case WORD_COUNT : pPage->ValidateWordCount(); break; + case SMART_TAGS : pPage->ValidateSmartTags(); break; // SMARTTAGS + } + } + + pPage = (SwPageFrm*)pPage->GetNext(); + if ( pPage && bVisAreaOnly && + !pPage->Frm().IsOver( pImp->GetShell()->VisArea())) + break; + } + return sal_False; +} + + +#if OSL_DEBUG_LEVEL > 1 + +/************************************************************************* +|* +|* void SwLayIdle::SwLayIdle() +|* +|*************************************************************************/ +void SwLayIdle::ShowIdle( ColorData eColorData ) +{ + if ( !bIndicator ) + { + bIndicator = sal_True; + Window *pWin = pImp->GetShell()->GetWin(); + if ( pWin ) + { + Rectangle aRect( 0, 0, 5, 5 ); + aRect = pWin->PixelToLogic( aRect ); + // OD 2004-04-23 #116347# + pWin->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pWin->SetFillColor( eColorData ); + pWin->SetLineColor(); + pWin->DrawRect( aRect ); + pWin->Pop(); + } + } +} +#define SHOW_IDLE( ColorData ) ShowIdle( ColorData ) +#else +#define SHOW_IDLE( ColorData ) +#endif + +/************************************************************************* +|* +|* void SwLayIdle::SwLayIdle() +|* +|*************************************************************************/ +SwLayIdle::SwLayIdle( SwRootFrm *pRt, SwViewImp *pI ) : + pRoot( pRt ), + pImp( pI ) +#if OSL_DEBUG_LEVEL > 1 + , bIndicator( sal_False ) +#endif +{ + pImp->pIdleAct = this; + + SHOW_IDLE( COL_LIGHTRED ); + + pImp->GetShell()->EnableSmooth( sal_False ); + + //Zuerst den Sichtbaren Bereich Spellchecken, nur wenn dort nichts + //zu tun war wird das IdleFormat angestossen. + if ( !DoIdleJob( SMART_TAGS, sal_True ) && + !DoIdleJob( ONLINE_SPELLING, sal_True ) && + !DoIdleJob( AUTOCOMPLETE_WORDS, sal_True ) ) // SMARTTAGS + { + //Formatieren und ggf. Repaint-Rechtecke an der ViewShell vormerken. + //Dabei muessen kuenstliche Actions laufen, damit es z.B. bei + //Veraenderungen der Seitenzahl nicht zu unerwuenschten Effekten kommt. + //Wir merken uns bei welchen Shells der Cursor sichtbar ist, damit + //wir ihn bei Dokumentaenderung ggf. wieder sichbar machen koennen. + std::vector<bool> aBools; + ViewShell *pSh = pImp->GetShell(); + do + { ++pSh->nStartAction; + sal_Bool bVis = sal_False; + if ( pSh->ISA(SwCrsrShell) ) + { +#ifdef SW_CRSR_TIMER + ((SwCrsrShell*)pSh)->ChgCrsrTimerFlag( sal_False ); +#endif + bVis = ((SwCrsrShell*)pSh)->GetCharRect().IsOver(pSh->VisArea()); + } + aBools.push_back( bVis ); + pSh = (ViewShell*)pSh->GetNext(); + } while ( pSh != pImp->GetShell() ); + + SwLayAction aAction( pRoot, pImp ); + aAction.SetInputType( INPUT_ANY ); + aAction.SetIdle( sal_True ); + aAction.SetWaitAllowed( sal_False ); + aAction.Action(); + + //Weitere Start-/EndActions nur auf wenn irgendwo Paints aufgelaufen + //sind oder wenn sich die Sichtbarkeit des CharRects veraendert hat. + sal_Bool bActions = sal_False; + sal_uInt16 nBoolIdx = 0; + do + { + --pSh->nStartAction; + + if ( pSh->Imp()->GetRegion() ) + bActions = sal_True; + else + { + SwRect aTmp( pSh->VisArea() ); + pSh->UISizeNotify(); + + // --> FME 2006-08-03 #137134# + // Are we supposed to crash if pSh isn't a cursor shell?! + // bActions |= aTmp != pSh->VisArea() || + // aBools[nBoolIdx] != ((SwCrsrShell*)pSh)->GetCharRect().IsOver( pSh->VisArea() ); + + // aBools[ i ] is true, if the i-th shell is a cursor shell (!!!) + // and the cursor is visible. + bActions |= aTmp != pSh->VisArea(); + if ( aTmp == pSh->VisArea() && pSh->ISA(SwCrsrShell) ) + { + bActions |= aBools[nBoolIdx] != + static_cast<SwCrsrShell*>(pSh)->GetCharRect().IsOver( pSh->VisArea() ); + } + } + + pSh = (ViewShell*)pSh->GetNext(); + ++nBoolIdx; + } while ( pSh != pImp->GetShell() ); + + if ( bActions ) + { + //Start- EndActions aufsetzen. ueber die CrsrShell, damit der + //Cursor/Selektion und die VisArea korrekt gesetzt werden. + nBoolIdx = 0; + do + { + sal_Bool bCrsrShell = pSh->IsA( TYPE(SwCrsrShell) ); + + if ( bCrsrShell ) + ((SwCrsrShell*)pSh)->SttCrsrMove(); +// else +// pSh->StartAction(); + + //Wenn Paints aufgelaufen sind, ist es am sinnvollsten schlicht das + //gesamte Window zu invalidieren. Anderfalls gibt es Paintprobleme + //deren Loesung unverhaeltnissmaessig aufwendig waere. + //fix(18176): + SwViewImp *pViewImp = pSh->Imp(); + sal_Bool bUnlock = sal_False; + if ( pViewImp->GetRegion() ) + { + pViewImp->DelRegion(); + + //Fuer Repaint mit virtuellem Device sorgen. + pSh->LockPaint(); + bUnlock = sal_True; + } + + if ( bCrsrShell ) + //Wenn der Crsr sichbar war wieder sichbar machen, sonst + //EndCrsrMove mit sal_True fuer IdleEnd. + ((SwCrsrShell*)pSh)->EndCrsrMove( sal_True^aBools[nBoolIdx] ); +// else +// pSh->EndAction(); + if( bUnlock ) + { + if( bCrsrShell ) + { + // UnlockPaint overwrite the selection from the + // CrsrShell and calls the virtual method paint + // to fill the virtual device. This fill dont have + // paint the selection! -> Set the focus flag at + // CrsrShell and it dont paint the selection. + ((SwCrsrShell*)pSh)->ShLooseFcs(); + pSh->UnlockPaint( sal_True ); + ((SwCrsrShell*)pSh)->ShGetFcs( sal_False ); + } + else + pSh->UnlockPaint( sal_True ); + } + + pSh = (ViewShell*)pSh->GetNext(); + ++nBoolIdx; + + } while ( pSh != pImp->GetShell() ); + } + + if ( !aAction.IsInterrupt() ) + { + if ( !DoIdleJob( WORD_COUNT, sal_False ) ) + if ( !DoIdleJob( SMART_TAGS, sal_False ) ) + if ( !DoIdleJob( ONLINE_SPELLING, sal_False ) ) + DoIdleJob( AUTOCOMPLETE_WORDS, sal_False ); // SMARTTAGS + } + + bool bInValid = false; + const SwViewOption& rVOpt = *pImp->GetShell()->GetViewOptions(); + const ViewShell* pViewShell = pImp->GetShell(); + // See conditions in DoIdleJob() + const sal_Bool bSpell = rVOpt.IsOnlineSpell(); + const sal_Bool bACmplWrd = rVOpt.IsAutoCompleteWords(); + const sal_Bool bWordCount = pViewShell->getIDocumentStatistics()->GetDocStat().bModified; + const sal_Bool bSmartTags = !pViewShell->GetDoc()->GetDocShell()->IsHelpDocument() && + !pViewShell->GetDoc()->isXForms() && + SwSmartTagMgr::Get().IsSmartTagsEnabled(); // SMARTTAGS + + SwPageFrm *pPg = (SwPageFrm*)pRoot->Lower(); + do + { + bInValid = pPg->IsInvalidCntnt() || pPg->IsInvalidLayout() || + pPg->IsInvalidFlyCntnt() || pPg->IsInvalidFlyLayout() || + pPg->IsInvalidFlyInCnt() || + (bSpell && pPg->IsInvalidSpelling()) || + (bACmplWrd && pPg->IsInvalidAutoCompleteWords()) || + (bWordCount && pPg->IsInvalidWordCount()) || + (bSmartTags && pPg->IsInvalidSmartTags()); // SMARTTAGS + + pPg = (SwPageFrm*)pPg->GetNext(); + + } while ( pPg && !bInValid ); + + if ( !bInValid ) + { + pRoot->ResetIdleFormat(); + SfxObjectShell* pDocShell = pImp->GetShell()->GetDoc()->GetDocShell(); + pDocShell->Broadcast( SfxEventHint( SW_EVENT_LAYOUT_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_LAYOUT_FINISHED), pDocShell ) ); + } + } + + pImp->GetShell()->EnableSmooth( sal_True ); + + if( pImp->IsAccessible() ) + pImp->FireAccessibleEvents(); + +#if OSL_DEBUG_LEVEL > 1 + if ( bIndicator && pImp->GetShell()->GetWin() ) + { + // #i75172# Do not invalidate indicator, this may cause a endless loop. Instead, just repaint it + // This should be replaced by an overlay object in the future, anyways. Since it's only for debug + // purposes, it is not urgent. + bIndicator = false; SHOW_IDLE( COL_LIGHTGREEN ); + } +#endif +} + +SwLayIdle::~SwLayIdle() +{ + pImp->pIdleAct = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/laycache.cxx b/sw/source/core/layout/laycache.cxx new file mode 100644 index 000000000000..60ac1238c19c --- /dev/null +++ b/sw/source/core/layout/laycache.cxx @@ -0,0 +1,1338 @@ +/* -*- 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 <editeng/brkitem.hxx> +#include <tools/stream.hxx> +#include <doc.hxx> +#include <docstat.hxx> +#include <docary.hxx> +#include <fmtpdsc.hxx> +#include <laycache.hxx> +#include <layhelp.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <colfrm.hxx> +#include <bodyfrm.hxx> +#include <ndindex.hxx> +#include <sectfrm.hxx> +#include <frmfmt.hxx> +#include <fmtcntnt.hxx> +#include <pagedesc.hxx> +#include <frmtool.hxx> +#include <dflyobj.hxx> +#include <dcontact.hxx> +#include "viewopt.hxx" +#include "viewsh.hxx" +#include <flyfrm.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> +// --> OD 2006-03-22 #b6375613# +#include <pam.hxx> +#include <docsh.hxx> +#include <com/sun/star/document/XDocumentInfoSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <set> + + +using namespace ::com::sun::star; +// <-- + +SV_IMPL_PTRARR( SwPageFlyCache, SwFlyCachePtr ) + +/*-----------------28.5.2001 10:06------------------ + * Reading and writing of the layout cache. + * The layout cache is not necessary, but it improves + * the performance and reduces the text flow during + * the formatting. + * The layout cache contains the index of the paragraphs/tables + * at the top of every page, so it's possible to create + * the right count of pages and to distribute the document content + * to this pages before the formatting starts. + *--------------------------------------------------*/ + +void SwLayoutCache::Read( SvStream &rStream ) +{ + if( !pImpl ) + { + pImpl = new SwLayCacheImpl; + if( !pImpl->Read( rStream ) ) + { + delete pImpl; + pImpl = 0; + } + } +} + +//----------------------------------------------------------------------------- + +void SwLayCacheImpl::Insert( sal_uInt16 nType, sal_uLong nIndex, xub_StrLen nOffset ) +{ + aType.Insert( nType, aType.Count() ); + SvULongs::Insert( nIndex, SvULongs::Count() ); + aOffset.push_back( nOffset ); +} + +sal_Bool SwLayCacheImpl::Read( SvStream& rStream ) +{ + SwLayCacheIoImpl aIo( rStream, sal_False ); + if( aIo.GetMajorVersion() > SW_LAYCACHE_IO_VERSION_MAJOR ) + return sal_False; + + // Due to an evil bug in the layout cache (#102759#), we cannot trust the + // sizes of fly frames which have been written using the "old" layout cache. + // This flag should indicate that we do not want to trust the width and + // height of fly frames + bUseFlyCache = aIo.GetMinorVersion() >= 1; + + sal_uInt8 cFlags; + sal_uInt32 nIndex, nOffset; + + aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES ); + aIo.OpenFlagRec(); + aIo.CloseFlagRec(); + while( aIo.BytesLeft() && !aIo.HasError() ) + { + switch( aIo.Peek() ) + { + case SW_LAYCACHE_IO_REC_PARA: + aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA ); + cFlags = aIo.OpenFlagRec(); + aIo.GetStream() >> nIndex; + if( (cFlags & 0x01) != 0 ) + aIo.GetStream() >> nOffset; + else + nOffset = STRING_LEN; + aIo.CloseFlagRec(); + Insert( SW_LAYCACHE_IO_REC_PARA, nIndex, (xub_StrLen)nOffset ); + aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA ); + break; + case SW_LAYCACHE_IO_REC_TABLE: + aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE ); + aIo.OpenFlagRec(); + aIo.GetStream() >> nIndex + >> nOffset; + Insert( SW_LAYCACHE_IO_REC_TABLE, nIndex, (xub_StrLen)nOffset ); + aIo.CloseFlagRec(); + aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE ); + break; + case SW_LAYCACHE_IO_REC_FLY: + { + aIo.OpenRec( SW_LAYCACHE_IO_REC_FLY ); + aIo.OpenFlagRec(); + aIo.CloseFlagRec(); + long nX, nY, nW, nH; + sal_uInt16 nPgNum; + aIo.GetStream() >> nPgNum >> nIndex + >> nX >> nY >> nW >> nH; + SwFlyCache* pFly = new SwFlyCache( nPgNum, nIndex, nX, nY, nW, nH ); + aFlyCache.Insert( pFly, aFlyCache.Count() ); + aIo.CloseRec( SW_LAYCACHE_IO_REC_FLY ); + break; + } + default: + aIo.SkipRec(); + break; + } + } + aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES ); + + return !aIo.HasError(); +} + +/*-----------------28.5.2001 10:19------------------ + * SwLayoutCache::Write(..) + * writes the index (more precise: the difference between + * the index and the first index of the document content) + * of the first paragraph/table at the top of every page. + * If at the top of a page is the rest of a paragraph/table + * from the bottom of the previous page, the character/row + * number is stored, too. + * The position, size and page number of the text frames + * are stored, too + * --------------------------------------------------*/ + +void SwLayoutCache::Write( SvStream &rStream, const SwDoc& rDoc ) +{ + if( rDoc.GetCurrentLayout() ) // the layout itself .. //swmod 080218 + { + SwLayCacheIoImpl aIo( rStream, sal_True ); + // We want to save the relative index, so we need the index + // of the first content + sal_uLong nStartOfContent = rDoc.GetNodes().GetEndOfContent(). + StartOfSectionNode()->GetIndex(); + // The first page.. + SwPageFrm* pPage = (SwPageFrm*)rDoc.GetCurrentLayout()->Lower(); //swmod 080218 + + aIo.OpenRec( SW_LAYCACHE_IO_REC_PAGES ); + aIo.OpenFlagRec( 0, 0 ); + aIo.CloseFlagRec(); + while( pPage ) + { + if( pPage->GetPrev() ) + { + SwLayoutFrm* pLay = pPage->FindBodyCont(); + SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL; + // We are only interested in paragraph or table frames, + // a section frames contains paragraphs/tables. + if( pTmp && pTmp->IsSctFrm() ) + pTmp = ((SwSectionFrm*)pTmp)->ContainsAny(); + + if( pTmp ) // any content + { + if( pTmp->IsTxtFrm() ) + { + sal_uLong nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + /* Open Paragraph Record */ + aIo.OpenRec( SW_LAYCACHE_IO_REC_PARA ); + sal_Bool bFollow = ((SwTxtFrm*)pTmp)->IsFollow(); + aIo.OpenFlagRec( bFollow ? 0x01 : 0x00, + bFollow ? 8 : 4 ); + nNdIdx -= nStartOfContent; + aIo.GetStream() << static_cast<sal_uInt32>(nNdIdx); + if( bFollow ) + aIo.GetStream() << static_cast<sal_uInt32>(((SwTxtFrm*)pTmp)->GetOfst()); + aIo.CloseFlagRec(); + /* Close Paragraph Record */ + aIo.CloseRec( SW_LAYCACHE_IO_REC_PARA ); + } + } + else if( pTmp->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)pTmp; + sal_uLong nOfst = STRING_LEN; + if( pTab->IsFollow() ) + { + // If the table is a follow, we have to look for the + // master and to count all rows to get the row number + nOfst = 0; + if( pTab->IsFollow() ) + pTab = pTab->FindMaster( true ); + while( pTab != pTmp ) + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + OSL_ENSURE( pTab, "Table follow without master" ); + } + } + do + { + sal_uLong nNdIdx = + pTab->GetTable()->GetTableNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + /* Open Table Record */ + aIo.OpenRec( SW_LAYCACHE_IO_REC_TABLE ); + aIo.OpenFlagRec( 0, 8 ); + nNdIdx -= nStartOfContent; + aIo.GetStream() << static_cast<sal_uInt32>(nNdIdx) + << static_cast<sal_uInt32>(nOfst); + aIo.CloseFlagRec(); + /* Close Table Record */ + aIo.CloseRec( SW_LAYCACHE_IO_REC_TABLE ); + } + // If the table has a follow on the next page, + // we know already the row number and store this + // immediately. + if( pTab->GetFollow() ) + { + if( nOfst == STRING_LEN ) + nOfst = 0; + do + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + SwPageFrm *pTabPage = pTab->FindPageFrm(); + if( pTabPage != pPage ) + { + OSL_ENSURE( pPage->GetPhyPageNum() < + pTabPage->GetPhyPageNum(), + "Looping Tableframes" ); + pPage = pTabPage; + break; + } + } while ( pTab->GetFollow() ); + } + else + break; + } while( pTab ); + } + } + } + if( pPage->GetSortedObjs() ) + { + SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + if( pFly->Frm().Left() != WEIT_WECH && + !pFly->GetAnchorFrm()->FindFooterOrHeader() ) + { + const SwContact *pC = + ::GetUserCall(pAnchoredObj->GetDrawObj()); + if( pC ) + { + sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum(); + sal_uInt16 nPageNum = pPage->GetPhyPageNum(); + /* Open Fly Record */ + aIo.OpenRec( SW_LAYCACHE_IO_REC_FLY ); + aIo.OpenFlagRec( 0, 0 ); + aIo.CloseFlagRec(); + SwRect &rRct = pFly->Frm(); + sal_Int32 nX = rRct.Left() - pPage->Frm().Left(); + sal_Int32 nY = rRct.Top() - pPage->Frm().Top(); + aIo.GetStream() << nPageNum << nOrdNum + << nX << nY << rRct.Width() + << rRct.Height(); + /* Close Fly Record */ + aIo.CloseRec( SW_LAYCACHE_IO_REC_FLY ); + } + } + } + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + aIo.CloseRec( SW_LAYCACHE_IO_REC_PAGES ); + } +} + +#if OSL_DEBUG_LEVEL > 1 +sal_Bool SwLayoutCache::CompareLayout( const SwDoc& rDoc ) const +{ + if( !pImpl ) + return sal_True; + const SwRootFrm *pRootFrm = rDoc.GetCurrentLayout(); + sal_Bool bRet = sal_True; + if( pRootFrm ) + { + sal_uInt16 nIndex = 0; + sal_uLong nStartOfContent = rDoc.GetNodes().GetEndOfContent(). + StartOfSectionNode()->GetIndex(); + SwPageFrm* pPage = (SwPageFrm*)pRootFrm->Lower(); + if( pPage ) + pPage = (SwPageFrm*)pPage->GetNext(); + while( pPage ) + { + if( nIndex >= pImpl->Count() ) + { + if( bRet ) + bRet = sal_False; + break; + } + SwLayoutFrm* pLay = pPage->FindBodyCont(); + SwFrm* pTmp = pLay ? pLay->ContainsAny() : NULL; + if( pTmp && pTmp->IsSctFrm() ) + pTmp = ((SwSectionFrm*)pTmp)->ContainsAny(); + if( pTmp ) + { + if( pTmp->IsTxtFrm() ) + { + sal_uLong nNdIdx = ((SwTxtFrm*)pTmp)->GetNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + sal_Bool bFollow = ((SwTxtFrm*)pTmp)->IsFollow(); + nNdIdx -= nStartOfContent; + if( pImpl->GetBreakIndex( nIndex ) != nNdIdx || + SW_LAYCACHE_IO_REC_PARA != + pImpl->GetBreakType( nIndex ) || + ( bFollow ? ((SwTxtFrm*)pTmp)->GetOfst() + : STRING_LEN ) != pImpl->GetBreakOfst( nIndex ) ) + { + if( bRet ) + bRet = sal_False; + } + ++nIndex; + } + } + else if( pTmp->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)pTmp; + sal_uLong nOfst = STRING_LEN; + if( pTab->IsFollow() ) + { + nOfst = 0; + if( pTab->IsFollow() ) + pTab = pTab->FindMaster( true ); + while( pTab != pTmp ) + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + } + } + do + { + sal_uLong nNdIdx = + pTab->GetTable()->GetTableNode()->GetIndex(); + if( nNdIdx > nStartOfContent ) + { + nNdIdx -= nStartOfContent; + if( pImpl->GetBreakIndex( nIndex ) != nNdIdx || + SW_LAYCACHE_IO_REC_TABLE != + pImpl->GetBreakType( nIndex ) || + nOfst != pImpl->GetBreakOfst( nIndex ) ) + { + if( bRet ) + bRet = sal_False; + } + ++nIndex; + } + if( pTab->GetFollow() ) + { + if( nOfst == STRING_LEN ) + nOfst = 0; + do + { + SwFrm* pSub = pTab->Lower(); + while( pSub ) + { + ++nOfst; + pSub = pSub->GetNext(); + } + pTab = pTab->GetFollow(); + SwPageFrm *pTabPage = pTab->FindPageFrm(); + if( pTabPage != pPage ) + { + pPage = pTabPage; + break; + } + } while ( pTab->GetFollow() ); + } + else + break; + } while( pTab ); + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + } + return bRet; +} +#endif + +void SwLayoutCache::ClearImpl() +{ + if( !IsLocked() ) + { + delete pImpl; + pImpl = 0; + } +} + + +SwLayoutCache::~SwLayoutCache() +{ + OSL_ENSURE( !nLockCount, "Deleting a locked SwLayoutCache!?" ); + delete pImpl; +} + +/*-----------------28.5.2001 10:47------------------ + * SwActualSection, + * a help class to create not nested section frames + * for nested sections. + * --------------------------------------------------*/ + +SwActualSection::SwActualSection( SwActualSection *pUp, + SwSectionFrm *pSect, + SwSectionNode *pNd ) : + pUpper( pUp ), + pSectFrm( pSect ), + pSectNode( pNd ) +{ + if ( !pSectNode ) + { + const SwNodeIndex *pIndex = pSect->GetFmt()->GetCntnt().GetCntntIdx(); + pSectNode = pIndex->GetNode().FindSectionNode(); + } +} + +/*-----------------28.5.2001 11:09------------------ + * SwLayHelper + * is the helper class, which utilizes the layout cache information + * to distribute the document content to the rigth pages. + * It's used by the _InsertCnt(..)-function. + * If there's no layout cache, the distibution to the pages is more + * a guess, but a guess with statistical background. + * --------------------------------------------------*/ + +SwLayHelper::SwLayHelper( SwDoc *pD, SwFrm* &rpF, SwFrm* &rpP, SwPageFrm* &rpPg, + SwLayoutFrm* &rpL, SwActualSection* &rpA, sal_Bool &rB, + sal_uLong nNodeIndex, sal_Bool bCache ) + : rpFrm( rpF ), rpPrv( rpP ), rpPage( rpPg ), rpLay( rpL ), + rpActualSection( rpA ), rbBreakAfter(rB), pDoc(pD), nMaxParaPerPage( 25 ), + nParagraphCnt( bCache ? 0 : USHRT_MAX ), bFirst( bCache ) +{ + pImpl = pDoc->GetLayoutCache() ? pDoc->GetLayoutCache()->LockImpl() : NULL; + if( pImpl ) + { + nMaxParaPerPage = 1000; + nStartOfContent = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode() + ->GetIndex(); + nNodeIndex -= nStartOfContent; + nIndex = 0; + nFlyIdx = 0; + while( nIndex < pImpl->Count() && (*pImpl)[ nIndex ] < nNodeIndex ) + ++nIndex; + if( nIndex >= pImpl->Count() ) + { + pDoc->GetLayoutCache()->UnlockImpl(); + pImpl = NULL; + } + } + else + { + nIndex = USHRT_MAX; + nStartOfContent = ULONG_MAX; + } +} + +SwLayHelper::~SwLayHelper() +{ + if( pImpl ) + { + OSL_ENSURE( pDoc && pDoc->GetLayoutCache(), "Missing layoutcache" ); + pDoc->GetLayoutCache()->UnlockImpl(); + } +} + +/*-----------------23.5.2001 16:40------------------ + * SwLayHelper::CalcPageCount() does not really calculate the page count, + * it returns the page count value from the layout cache, if available, + * otherwise it estimates the page count. + * --------------------------------------------------*/ + +sal_uLong SwLayHelper::CalcPageCount() +{ + sal_uLong nPgCount; + SwLayCacheImpl *pCache = pDoc->GetLayoutCache() ? + pDoc->GetLayoutCache()->LockImpl() : NULL; + if( pCache ) + { + nPgCount = pCache->Count() + 1; + pDoc->GetLayoutCache()->UnlockImpl(); + } + else + { + nPgCount = pDoc->GetDocStat().nPage; + if ( nPgCount <= 10 ) // no page insertion for less than 10 pages + nPgCount = 0; + sal_uLong nNdCount = pDoc->GetDocStat().nPara; + if ( nNdCount <= 1 ) + { + //Estimates the number of paragraphs. + sal_uLong nTmp = pDoc->GetNodes().GetEndOfContent().GetIndex() - + pDoc->GetNodes().GetEndOfExtras().GetIndex(); + //Tables have a little overhead.. + nTmp -= pDoc->GetTblFrmFmts()->Count() * 25; + //Fly frames, too .. + nTmp -= (pDoc->GetNodes().GetEndOfAutotext().GetIndex() - + pDoc->GetNodes().GetEndOfInserts().GetIndex()) / 3 * 5; + if ( nTmp > 0 ) + nNdCount = nTmp; + } + if ( nNdCount > 100 ) // no estimation below this value + { + if ( nPgCount > 0 ) + nMaxParaPerPage = nNdCount / nPgCount; + else + { + nMaxParaPerPage = Max( sal_uLong(20), + sal_uLong(20 + nNdCount / 1000 * 3) ); +#ifdef PM2 + const sal_uLong nMax = 49; +#else + const sal_uLong nMax = 53; +#endif + nMaxParaPerPage = Min( nMaxParaPerPage, nMax ); + nPgCount = nNdCount / nMaxParaPerPage; + } + if ( nNdCount < 1000 ) + nPgCount = 0;// no progress bar for small documents + ViewShell *pSh = 0; + if( rpLay && rpLay->getRootFrm() ) + pSh = rpLay->getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + nMaxParaPerPage *= 6; + } + } + return nPgCount; +} + +/*-----------------23.5.2001 16:44------------------ + * SwLayHelper::CheckInsertPage() + * inserts a page and return sal_True, if + * - the break after flag is set + * - the actual content wants a break before + * - the maximum count of paragraph/rows is reached + * + * The break after flag is set, if the actual content + * wants a break after. + * --------------------------------------------------*/ + +sal_Bool SwLayHelper::CheckInsertPage() +{ + sal_Bool bEnd = 0 == rpPage->GetNext(); + const SwAttrSet* pAttr = rpFrm->GetAttrSet(); + const SvxFmtBreakItem& rBrk = pAttr->GetBreak(); + const SwFmtPageDesc& rDesc = pAttr->GetPageDesc(); + // --> FME 2004-10-26 #118195# Do not evaluate page description if frame + // is a follow frame! + const SwPageDesc* pDesc = rpFrm->IsFlowFrm() && + SwFlowFrm::CastFlowFrm( rpFrm )->IsFollow() ? + 0 : + rDesc.GetPageDesc(); + // <-- + + sal_Bool bBrk = nParagraphCnt > nMaxParaPerPage || rbBreakAfter; + rbBreakAfter = rBrk.GetBreak() == SVX_BREAK_PAGE_AFTER || + rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; + if ( !bBrk ) + bBrk = rBrk.GetBreak() == SVX_BREAK_PAGE_BEFORE || + rBrk.GetBreak() == SVX_BREAK_PAGE_BOTH; + + if ( bBrk || pDesc ) + { + sal_uInt16 nPgNum = 0; + if ( !pDesc ) + pDesc = rpPage->GetPageDesc()->GetFollow(); + else + { + if ( 0 != (nPgNum = rDesc.GetNumOffset()) ) + ((SwRootFrm*)rpPage->GetUpper())->SetVirtPageNum(sal_True); + } + sal_Bool bNextPageOdd = !rpPage->OnRightPage(); + sal_Bool bInsertEmpty = sal_False; + if( nPgNum && bNextPageOdd != ( ( nPgNum % 2 ) != 0 ) ) + { + bNextPageOdd = !bNextPageOdd; + bInsertEmpty = sal_True; + } + ::InsertNewPage( (SwPageDesc&)*pDesc, rpPage->GetUpper(), + bNextPageOdd, bInsertEmpty, sal_False, rpPage->GetNext() ); + if ( bEnd ) + { + OSL_ENSURE( rpPage->GetNext(), "Keine neue Seite?" ); + do + { rpPage = (SwPageFrm*)rpPage->GetNext(); + } while ( rpPage->GetNext() ); + } + else + { + OSL_ENSURE( rpPage->GetNext(), "Keine neue Seite?" ); + rpPage = (SwPageFrm*)rpPage->GetNext(); + if ( rpPage->IsEmptyPage() ) + { + OSL_ENSURE( rpPage->GetNext(), "Keine neue Seite?" ); + rpPage = (SwPageFrm*)rpPage->GetNext(); + } + } + rpLay = rpPage->FindBodyCont(); + while( rpLay->Lower() ) + rpLay = (SwLayoutFrm*)rpLay->Lower(); + return sal_True; + } + return sal_False; +} + +// --> OD 2006-03-22 #b6375613# +bool lcl_HasTextFrmAnchoredObjs( SwTxtFrm* p_pTxtFrm ) +{ + bool bHasTextFrmAnchoredObjs( false ); + + const SwSpzFrmFmts* pSpzFrmFmts = p_pTxtFrm->GetTxtNode()->GetDoc()->GetSpzFrmFmts(); + for ( sal_uInt16 i = 0; i < pSpzFrmFmts->Count(); ++i ) + { + SwFrmFmt *pFmt = (SwFrmFmt*)(*pSpzFrmFmts)[i]; + const SwFmtAnchor &rAnch = pFmt->GetAnchor(); + if ( rAnch.GetCntntAnchor() && + ((rAnch.GetAnchorId() == FLY_AT_PARA) || + (rAnch.GetAnchorId() == FLY_AT_CHAR)) && + rAnch.GetCntntAnchor()->nNode.GetIndex() == + p_pTxtFrm->GetTxtNode()->GetIndex() ) + { + bHasTextFrmAnchoredObjs = true; + break; + } + } + + return bHasTextFrmAnchoredObjs; +} + +void lcl_ApplyWorkaroundForB6375613( SwFrm* p_pFirstFrmOnNewPage ) +{ + SwTxtFrm* pFirstTextFrmOnNewPage = dynamic_cast<SwTxtFrm*>(p_pFirstFrmOnNewPage); + // + if ( pFirstTextFrmOnNewPage && + !pFirstTextFrmOnNewPage->IsFollow() && + pFirstTextFrmOnNewPage->GetTxt().Len() == 0 && + lcl_HasTextFrmAnchoredObjs( pFirstTextFrmOnNewPage ) ) + { + // apply page break before at this text frame to assure, that it doesn't flow backward. + const SvxBreak eBreak = + pFirstTextFrmOnNewPage->GetAttrSet()->GetBreak().GetBreak(); + if ( eBreak == SVX_BREAK_NONE ) + { + pFirstTextFrmOnNewPage->GetTxtNode()->LockModify(); + SwDoc* pDoc( pFirstTextFrmOnNewPage->GetTxtNode()->GetDoc() ); + IDocumentContentOperations* pIDCO = pFirstTextFrmOnNewPage->GetTxtNode()->getIDocumentContentOperations(); + const SwPaM aTmpPaM( *(pFirstTextFrmOnNewPage->GetTxtNode()) ); + pIDCO->InsertPoolItem( aTmpPaM, + SvxFmtBreakItem( SVX_BREAK_PAGE_BEFORE, RES_BREAK ), 0 ); + pFirstTextFrmOnNewPage->GetTxtNode()->UnlockModify(); + + uno::Reference< document::XDocumentInfoSupplier > xDoc( + pDoc->GetDocShell()->GetBaseModel(), + uno::UNO_QUERY); + uno::Reference< beans::XPropertySet > xDocInfo( + xDoc->getDocumentInfo(), + uno::UNO_QUERY ); + try + { + xDocInfo->setPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WorkaroundForB6375613Applied")), uno::makeAny( true ) ); + } + catch( uno::Exception& ) + { + } + } + } +} +// <-- + +/*-----------------28.5.2001 11:31------------------ + * SwLayHelper::CheckInsert + * is the entry point for the _InsertCnt-function. + * The document content index is checked either it is + * in the layout cache either it's time to insert a page + * cause the maximal estimation of content per page is reached. + * A really big table or long paragraph may contains more than + * one page, in this case the needed count of pages will inserted. + * --------------------------------------------------*/ + +sal_Bool SwLayHelper::CheckInsert( sal_uLong nNodeIndex ) +{ + sal_Bool bRet = sal_False; + sal_Bool bLongTab = sal_False; + sal_uLong nMaxRowPerPage( 0 ); + nNodeIndex -= nStartOfContent; + sal_uInt16 nRows( 0 ); + if( rpFrm->IsTabFrm() ) + { + //Inside a table counts every row as a paragraph + SwFrm *pLow = ((SwTabFrm*)rpFrm)->Lower(); + nRows = 0; + do + { + ++nRows; + pLow = pLow->GetNext(); + } while ( pLow ); + nParagraphCnt += nRows; + if( !pImpl && nParagraphCnt > nMaxParaPerPage + 10 ) + { + // OD 09.04.2003 #108698# - improve heuristics: + // Assume that a table, which has more than three times the quantity + // of maximal paragraphs per page rows, consists of rows, which have + // the height of a normal paragraph. Thus, allow as much rows per page + // as much paragraphs are allowed. + if ( nRows > ( 3*nMaxParaPerPage ) ) + { + nMaxRowPerPage = nMaxParaPerPage; + } + else + { + SwFrm *pTmp = ((SwTabFrm*)rpFrm)->Lower(); + if( pTmp->GetNext() ) + pTmp = pTmp->GetNext(); + pTmp = ((SwRowFrm*)pTmp)->Lower(); + sal_uInt16 nCnt = 0; + do + { + ++nCnt; + pTmp = pTmp->GetNext(); + } while( pTmp ); + nMaxRowPerPage = Max( sal_uLong(2), nMaxParaPerPage / nCnt ); + } + bLongTab = sal_True; + } + } + else + ++nParagraphCnt; + if( bFirst && pImpl && nIndex < pImpl->Count() && + pImpl->GetBreakIndex( nIndex ) == nNodeIndex && + ( pImpl->GetBreakOfst( nIndex ) < STRING_LEN || + ( ++nIndex < pImpl->Count() && + pImpl->GetBreakIndex( nIndex ) == nNodeIndex ) ) ) + bFirst = sal_False; +#if OSL_DEBUG_LEVEL > 1 + sal_uLong nBreakIndex = ( pImpl && nIndex < pImpl->Count() ) ? + pImpl->GetBreakIndex(nIndex) : 0xffff; + (void)nBreakIndex; +#endif + // OD 09.04.2003 #108698# - always split a big tables. + if ( !bFirst || + ( rpFrm->IsTabFrm() && bLongTab ) + ) + { + sal_uLong nRowCount = 0; + do + { + if( pImpl || bLongTab ) + { +#if OSL_DEBUG_LEVEL > 1 + sal_uLong nBrkIndex = ( pImpl && nIndex < pImpl->Count() ) ? + pImpl->GetBreakIndex(nIndex) : 0xffff; + (void)nBrkIndex; +#endif + xub_StrLen nOfst = STRING_LEN; + sal_uInt16 nType = SW_LAYCACHE_IO_REC_PAGES; + if( bLongTab ) + { + rbBreakAfter = sal_True; + nOfst = static_cast<xub_StrLen>(nRowCount + nMaxRowPerPage); + } + else + { + while( nIndex < pImpl->Count() && + pImpl->GetBreakIndex(nIndex) < nNodeIndex) + ++nIndex; + if( nIndex < pImpl->Count() && + pImpl->GetBreakIndex(nIndex) == nNodeIndex ) + { + nType = pImpl->GetBreakType( nIndex ); + nOfst = pImpl->GetBreakOfst( nIndex++ ); + rbBreakAfter = sal_True; + } + } + + if( nOfst < STRING_LEN ) + { + sal_Bool bSplit = sal_False; + sal_uInt16 nRepeat( 0 ); + if( !bLongTab && rpFrm->IsTxtFrm() && + SW_LAYCACHE_IO_REC_PARA == nType && + nOfst<((SwTxtFrm*)rpFrm)->GetTxtNode()->GetTxt().Len() ) + bSplit = sal_True; + else if( rpFrm->IsTabFrm() && nRowCount < nOfst && + ( bLongTab || SW_LAYCACHE_IO_REC_TABLE == nType ) ) + { + nRepeat = ((SwTabFrm*)rpFrm)-> + GetTable()->GetRowsToRepeat(); + bSplit = nOfst < nRows && nRowCount + nRepeat < nOfst; + bLongTab = bLongTab && bSplit; + } + if( bSplit ) + { + rpFrm->InsertBehind( rpLay, rpPrv ); + rpFrm->Frm().Pos() = rpLay->Frm().Pos(); + rpFrm->Frm().Pos().Y() += 1; + rpPrv = rpFrm; + if( rpFrm->IsTabFrm() ) + { + SwTabFrm* pTab = (SwTabFrm*)rpFrm; + // --> OD 2004-09-23 #i33629#, #i29955# + ::RegistFlys( pTab->FindPageFrm(), pTab ); + // <-- + SwFrm *pRow = pTab->Lower(); + SwTabFrm *pFoll = new SwTabFrm( *pTab ); + + SwFrm *pPrv; + if( nRepeat > 0 ) + { + bDontCreateObjects = sal_True; //frmtool + + // Insert new headlines: + sal_uInt16 nRowIdx = 0; + SwRowFrm* pHeadline = 0; + while( nRowIdx < nRepeat ) + { + OSL_ENSURE( pTab->GetTable()->GetTabLines()[ nRowIdx ], "Table ohne Zeilen?" ); + pHeadline = + new SwRowFrm( *pTab->GetTable()->GetTabLines()[ nRowIdx ], pTab ); + pHeadline->SetRepeatedHeadline( true ); + pHeadline->InsertBefore( pFoll, 0 ); + pHeadline->RegistFlys(); + + ++nRowIdx; + } + + bDontCreateObjects = sal_False; + pPrv = pHeadline; + nRows = nRows + nRepeat; + } + else + pPrv = 0; + while( pRow && nRowCount < nOfst ) + { + pRow = pRow->GetNext(); + ++nRowCount; + } + while ( pRow ) + { + SwFrm* pNxt = pRow->GetNext(); + pRow->Remove(); + pRow->InsertBehind( pFoll, pPrv ); + pPrv = pRow; + pRow = pNxt; + } + rpFrm = pFoll; + } + else + { + SwTxtFrm *pNew = new SwTxtFrm( ((SwTxtFrm*)rpFrm)-> + GetTxtNode(), rpFrm ); + pNew->_SetIsFollow( sal_True ); + pNew->ManipOfst( nOfst ); + pNew->SetFollow( ((SwTxtFrm*)rpFrm)->GetFollow() ); + ((SwTxtFrm*)rpFrm)->SetFollow( pNew ); + rpFrm = pNew; + } + } + } + } + + SwPageFrm* pLastPage = rpPage; + if( CheckInsertPage() ) + { + // --> OD 2006-03-21 #b6375613# + if ( pDoc->ApplyWorkaroundForB6375613() ) + { + lcl_ApplyWorkaroundForB6375613( rpFrm ); + } + // <-- + _CheckFlyCache( pLastPage ); + if( rpPrv && rpPrv->IsTxtFrm() && !rpPrv->GetValidSizeFlag() ) + rpPrv->Frm().Height( rpPrv->GetUpper()->Prt().Height() ); + + bRet = sal_True; + rpPrv = 0; + nParagraphCnt = 0; + + if ( rpActualSection ) + { + //Hatte der SectionFrm ueberhaupt Inhalt? Wenn + //nicht kann er gleich umgehaengt werden. + SwSectionFrm *pSct; + bool bInit = false; + if ( !rpActualSection->GetSectionFrm()->ContainsCntnt()) + { + pSct = rpActualSection->GetSectionFrm(); + pSct->Remove(); + } + else + { + pSct = new SwSectionFrm( + *rpActualSection->GetSectionFrm(), sal_False ); + rpActualSection->GetSectionFrm()->SimpleFormat(); + bInit = true; + } + rpActualSection->SetSectionFrm( pSct ); + pSct->InsertBehind( rpLay, 0 ); + if( bInit ) + pSct->Init(); + pSct->Frm().Pos() = rpLay->Frm().Pos(); + pSct->Frm().Pos().Y() += 1; //wg. Benachrichtigungen. + + rpLay = pSct; + if ( rpLay->Lower() && rpLay->Lower()->IsLayoutFrm() ) + rpLay = rpLay->GetNextLayoutLeaf(); + } + } + } while( bLongTab || ( pImpl && nIndex < pImpl->Count() && + (*pImpl)[ nIndex ] == nNodeIndex ) ); + } + bFirst = sal_False; + return bRet; +} + +struct SdrObjectCompare +{ + bool operator()( const SdrObject* pF1, const SdrObject* pF2 ) const + { + return pF1->GetOrdNum() < pF2->GetOrdNum(); + } +}; + +struct FlyCacheCompare +{ + bool operator()( const SwFlyCache* pC1, const SwFlyCache* pC2 ) const + { + return pC1->nOrdNum < pC2->nOrdNum; + } +}; + + /*-----------------28.6.2001 14:40------------------ + * SwLayHelper::_CheckFlyCache(..) + * If a new page is inserted, the last page is analysed. + * If there are text frames with default position, the fly cache + * is checked, if these frames are stored in the cache. + * --------------------------------------------------*/ + +void SwLayHelper::_CheckFlyCache( SwPageFrm* pPage ) +{ + if( !pImpl || !pPage ) + return; + sal_uInt16 nFlyCount = pImpl->GetFlyCount(); + // Any text frames at the page, fly cache avaiable? + if( pPage->GetSortedObjs() && nFlyIdx < nFlyCount ) + { + SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + sal_uInt16 nPgNum = pPage->GetPhyPageNum(); + + // + // NOTE: Here we do not use the absolute ordnums but + // relative ordnums for the objects on this page. + + // skip fly frames from pages before the current page + SwFlyCache* pFlyC; + while( nFlyIdx < nFlyCount && ( pFlyC = pImpl-> + GetFlyCache(nFlyIdx) )->nPageNum < nPgNum) + ++nFlyIdx; + + // sort cached objects on this page by ordnum + std::set< const SwFlyCache*, FlyCacheCompare > aFlyCacheSet; + sal_uInt16 nIdx = nFlyIdx; + + while( nIdx < nFlyCount && ( pFlyC = pImpl-> + GetFlyCache( nIdx ) )->nPageNum == nPgNum ) + { + aFlyCacheSet.insert( pFlyC ); + ++nIdx; + } + + // sort objects on this page by ordnum + std::set< const SdrObject*, SdrObjectCompare > aFlySet; + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) // a text frame? + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + if( pFly->GetAnchorFrm() && + !pFly->GetAnchorFrm()->FindFooterOrHeader() ) + { + const SwContact *pC = ::GetUserCall( pAnchoredObj->GetDrawObj() ); + if( pC ) + { + aFlySet.insert( pAnchoredObj->GetDrawObj() ); + } + } + } + } + + if ( aFlyCacheSet.size() == aFlySet.size() ) + { + std::set< const SwFlyCache*, FlyCacheCompare >::iterator aFlyCacheSetIt = + aFlyCacheSet.begin(); + std::set< const SdrObject*, SdrObjectCompare >::iterator aFlySetIt = + aFlySet.begin(); + + while ( aFlyCacheSetIt != aFlyCacheSet.end() ) + { + const SwFlyCache* pFlyCache = *aFlyCacheSetIt; + SwFlyFrm* pFly = ((SwVirtFlyDrawObj*)*aFlySetIt)->GetFlyFrm(); + + if ( pFly->Frm().Left() == WEIT_WECH ) + { + // we get the stored information + pFly->Frm().Pos().X() = pFlyCache->Left() + + pPage->Frm().Left(); + pFly->Frm().Pos().Y() = pFlyCache->Top() + + pPage->Frm().Top(); + if ( pImpl->IsUseFlyCache() ) + { + pFly->Frm().Width( pFlyCache->Width() ); + pFly->Frm().Height( pFlyCache->Height() ); + } + } + + ++aFlyCacheSetIt; + ++aFlySetIt; + } + } + } +} + +/*-----------------28.6.2001 14:48------------------ + * SwLayHelper::CheckPageFlyCache(..) + * looks for the given text frame in the fly cache and sets + * the position and size, if possible. + * The fly cache is sorted by pages and we start searching with the given page. + * If we found the page number in the fly cache, we set + * the rpPage parameter to the right page, if possible. + * --------------------------------------------------*/ + +sal_Bool SwLayHelper::CheckPageFlyCache( SwPageFrm* &rpPage, SwFlyFrm* pFly ) +{ + if( !pFly->GetAnchorFrm() || !pFly->GetVirtDrawObj() || + pFly->GetAnchorFrm()->FindFooterOrHeader() ) + return sal_False; + sal_Bool bRet = sal_False; + SwDoc* pDoc = rpPage->GetFmt()->GetDoc(); + SwLayCacheImpl *pCache = pDoc->GetLayoutCache() ? + pDoc->GetLayoutCache()->LockImpl() : NULL; + if( pCache ) + { + sal_uInt16 nPgNum = rpPage->GetPhyPageNum(); + sal_uInt16 nIdx = 0; + sal_uInt16 nCnt = pCache->GetFlyCount(); + sal_uLong nOrdNum = pFly->GetVirtDrawObj()->GetOrdNum(); + SwFlyCache* pFlyC = 0; + + // skip fly frames from pages before the current page + while( nIdx < nCnt && + nPgNum > (pFlyC = pCache->GetFlyCache( nIdx ))->nPageNum ) + ++nIdx; + + while( nIdx < nCnt && + nOrdNum != (pFlyC = pCache->GetFlyCache( nIdx ))->nOrdNum ) + ++nIdx; + if( nIdx < nCnt ) + { + SwPageFrm *pPage = rpPage; + while( pPage && pPage->GetPhyPageNum() < pFlyC->nPageNum ) + pPage = (SwPageFrm*)pPage->GetNext(); + // --> OD 2005-02-22 #i43266# - if the found page is an empty page, + // take the previous one (take next one, if previous one doesn't exists) + if ( pPage && pPage->IsEmptyPage() ) + { + pPage = static_cast<SwPageFrm*>( pPage->GetPrev() + ? pPage->GetPrev() + : pPage->GetNext() ); + } + // <-- + if( pPage ) + { + rpPage = pPage; + pFly->Frm().Pos().X() = pFlyC->Left() + pPage->Frm().Left(); + pFly->Frm().Pos().Y() = pFlyC->Top() + pPage->Frm().Top(); + if ( pCache->IsUseFlyCache() ) + { + pFly->Frm().Width( pFlyC->Width() ); + pFly->Frm().Height( pFlyC->Height() ); + } + bRet = sal_True; + } + } + pDoc->GetLayoutCache()->UnlockImpl(); + } + return bRet; +} + +// ----------------------------------------------------------------------------- + +SwLayCacheIoImpl::SwLayCacheIoImpl( SvStream& rStrm, sal_Bool bWrtMd ) : + pStream( &rStrm ), + nMajorVersion(SW_LAYCACHE_IO_VERSION_MAJOR), + nMinorVersion(SW_LAYCACHE_IO_VERSION_MINOR), + bWriteMode( bWrtMd ), + bError( sal_False ) +{ + if( bWriteMode ) + *pStream << nMajorVersion + << nMinorVersion; + + else + *pStream >> nMajorVersion + >> nMinorVersion; +} + +sal_Bool SwLayCacheIoImpl::OpenRec( sal_uInt8 cType ) +{ + sal_Bool bRes = sal_True; + sal_uInt32 nPos = pStream->Tell(); + if( bWriteMode ) + { + aRecords.push_back( RecTypeSize(cType, nPos) ); + *pStream << (sal_uInt32) 0; + } + else + { + sal_uInt32 nVal; + *pStream >> nVal; + sal_uInt8 cRecTyp = (sal_uInt8)nVal; + if( !nVal || cRecTyp != cType || + pStream->GetErrorCode() != SVSTREAM_OK || pStream->IsEof() ) + { + OSL_ENSURE( nVal, "OpenRec: Record-Header is 0" ); + OSL_ENSURE( cRecTyp == cType, "OpenRec: Wrong Record Type" ); + aRecords.push_back( RecTypeSize(0, pStream->Tell()) ); + bRes = sal_False; + bError = sal_True; + } + else + { + sal_uInt32 nSize = nVal >> 8; + aRecords.push_back( RecTypeSize(cRecTyp, nPos+nSize) ); + } + } + return bRes; +} + +// Close record + +sal_Bool SwLayCacheIoImpl::CloseRec( sal_uInt8 ) +{ + sal_Bool bRes = sal_True; + OSL_ENSURE( !aRecords.empty(), "CloseRec: no levels" ); + if( !aRecords.empty() ) + { + sal_uInt32 nPos = pStream->Tell(); + if( bWriteMode ) + { + sal_uInt32 nBgn = aRecords.back().size; + pStream->Seek( nBgn ); + sal_uInt32 nSize = nPos - nBgn; + sal_uInt32 nVal = ( nSize << 8 ) | aRecords.back().type; + *pStream << nVal; + pStream->Seek( nPos ); + if( pStream->GetError() != SVSTREAM_OK ) + bRes = sal_False; + } + else + { + sal_uInt32 n = aRecords.back().size; + OSL_ENSURE( n >= nPos, "CloseRec: to much data read" ); + if( n != nPos ) + { + pStream->Seek( n ); + if( n < nPos ) + bRes = sal_False; + } + if( pStream->GetErrorCode() != SVSTREAM_OK ) + bRes = sal_False; + } + aRecords.pop_back(); + } + + if( !bRes ) + bError = sal_True; + + return bRes; +} + +sal_uInt32 SwLayCacheIoImpl::BytesLeft() +{ + sal_uInt32 n = 0; + if( !bError && !aRecords.empty() ) + { + sal_uInt32 nEndPos = aRecords.back().size; + sal_uInt32 nPos = pStream->Tell(); + if( nEndPos > nPos ) + n = nEndPos - nPos; + } + return n; +} + +sal_uInt8 SwLayCacheIoImpl::Peek() +{ + sal_uInt8 c = 0; + if( !bError ) + { + sal_uInt32 nPos = pStream->Tell(); + *pStream >> c; + pStream->Seek( nPos ); + if( pStream->GetErrorCode() != SVSTREAM_OK ) + { + c = 0; + bError = sal_True; + } + } + return c; +} + +void SwLayCacheIoImpl::SkipRec() +{ + sal_uInt8 c = Peek(); + OpenRec( c ); + pStream->Seek( aRecords.back().size ); + CloseRec( c ); +} + +sal_uInt8 SwLayCacheIoImpl::OpenFlagRec() +{ + OSL_ENSURE( !bWriteMode, "OpenFlagRec illegal in write mode" ); + sal_uInt8 cFlags; + *pStream >> cFlags; + nFlagRecEnd = pStream->Tell() + ( cFlags & 0x0F ); + return (cFlags >> 4); +} + +void SwLayCacheIoImpl::OpenFlagRec( sal_uInt8 nFlags, sal_uInt8 nLen ) +{ + OSL_ENSURE( bWriteMode, "OpenFlagRec illegal in read mode" ); + OSL_ENSURE( (nFlags & 0xF0) == 0, "illegal flags set" ); + OSL_ENSURE( nLen < 16, "wrong flag record length" ); + sal_uInt8 cFlags = (nFlags << 4) + nLen; + *pStream << cFlags; + nFlagRecEnd = pStream->Tell() + nLen; +} + +void SwLayCacheIoImpl::CloseFlagRec() +{ + if( bWriteMode ) + { + OSL_ENSURE( pStream->Tell() == nFlagRecEnd, "Wrong amount of data written" ); + } + else + { + OSL_ENSURE( pStream->Tell() <= nFlagRecEnd, "To many data read" ); + if( pStream->Tell() != nFlagRecEnd ) + pStream->Seek( nFlagRecEnd ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/layhelp.hxx b/sw/source/core/layout/layhelp.hxx new file mode 100644 index 000000000000..d690940320d7 --- /dev/null +++ b/sw/source/core/layout/layhelp.hxx @@ -0,0 +1,240 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _LAYHELP_HXX +#define _LAYHELP_HXX +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_USHORTS +#define _SVSTDARR_ULONGS +#define _SVSTDARR_XUB_STRLEN +#include <svl/svstdarr.hxx> +#endif +#include <swrect.hxx> +#include <vector> + +class SwDoc; +class SwFrm; +class SwLayoutFrm; +class SwPageFrm; +class SwFlyFrm; +class SwSectionFrm; +class SwSectionNode; +class SvStream; + +/************************************************************************* + * class SwLayCacheImpl + * contains the page break information and the text frame positions + * of the document (after loading) + * and is used inside the constructor of the layout rootframe to + * insert content and text frames at the right pages. + * For every page of the main text (body content, no footnotes, text frames etc.) + * we have the nodeindex of the first content at the page, + * the type of content ( table or paragraph ) + * and if it's not the first part of the table/paragraph, + * the row/character-offset inside the table/paragraph. + * The text frame positions are stored in the SwPageFlyCache array. + *************************************************************************/ + +class SwFlyCache; +typedef SwFlyCache* SwFlyCachePtr; +SV_DECL_PTRARR_DEL( SwPageFlyCache, SwFlyCachePtr, 0, 4 ) + +class SwLayCacheImpl : public SvULongs +{ + SvXub_StrLens aOffset; + SvUShorts aType; + SwPageFlyCache aFlyCache; + sal_Bool bUseFlyCache; + void Insert( sal_uInt16 nType, sal_uLong nIndex, xub_StrLen nOffset ); + +public: + SwLayCacheImpl() : SvULongs( 20, 10 ), aType( 20, 10 ) {} + sal_Bool Read( SvStream& rStream ); + + sal_uLong GetBreakIndex( sal_uInt16 nIdx ) const { return GetObject( nIdx ); } + xub_StrLen GetBreakOfst( size_t nIdx ) const { return aOffset[ nIdx ]; } + sal_uInt16 GetBreakType( sal_uInt16 nIdx ) const { return aType[ nIdx ]; } + + sal_uInt16 GetFlyCount() const { return aFlyCache.Count(); } + SwFlyCache *GetFlyCache( sal_uInt16 nIdx ) const { return aFlyCache[ nIdx ]; } + + sal_Bool IsUseFlyCache() const { return bUseFlyCache; } +}; + +/************************************************************************* + * class SwActualSection + * helps to create the sectionframes during the _InsertCnt-function + * by controlling nested sections. + *************************************************************************/ + +class SwActualSection +{ + SwActualSection *pUpper; + SwSectionFrm *pSectFrm; + SwSectionNode *pSectNode; +public: + SwActualSection( SwActualSection *pUpper, + SwSectionFrm *pSect, + SwSectionNode *pNd ); + + SwSectionFrm *GetSectionFrm() { return pSectFrm; } + void SetSectionFrm( SwSectionFrm *p ) { pSectFrm = p; } + SwSectionNode *GetSectionNode() { return pSectNode;} + SwActualSection *GetUpper() { return pUpper; } +}; + +/************************************************************************* + * class SwLayHelper + * helps during the _InsertCnt-function to create new pages. + * If there's a layoutcache available, this information is used. + *************************************************************************/ + +class SwLayHelper +{ + SwFrm* &rpFrm; + SwFrm* &rpPrv; + SwPageFrm* &rpPage; + SwLayoutFrm* &rpLay; + SwActualSection* &rpActualSection; + sal_Bool &rbBreakAfter; + SwDoc* pDoc; + SwLayCacheImpl* pImpl; + sal_uLong nMaxParaPerPage; + sal_uLong nParagraphCnt; + sal_uLong nStartOfContent; + sal_uInt16 nIndex; // the index in the page break array + sal_uInt16 nFlyIdx; // the index in the fly cache array + sal_Bool bFirst : 1; + void _CheckFlyCache( SwPageFrm* pPage ); +public: + SwLayHelper( SwDoc *pD, SwFrm* &rpF, SwFrm* &rpP, SwPageFrm* &rpPg, + SwLayoutFrm* &rpL, SwActualSection* &rpA, sal_Bool &rBrk, + sal_uLong nNodeIndex, sal_Bool bCache ); + ~SwLayHelper(); + sal_uLong CalcPageCount(); + sal_Bool CheckInsert( sal_uLong nNodeIndex ); + + sal_Bool BreakPage( xub_StrLen& rOffs, sal_uLong nNodeIndex ); + sal_Bool CheckInsertPage(); + + // Look for fresh text frames at this (new) page and set them to the right + // position, if they are in the fly cache. + void CheckFlyCache( SwPageFrm* pPage ) + { if( pImpl && nFlyIdx < pImpl->GetFlyCount() ) _CheckFlyCache( pPage ); } + + // Look for this text frame and set it to the right position, + // if it's in the fly cache. + static sal_Bool CheckPageFlyCache( SwPageFrm* &rpPage, SwFlyFrm* pFly ); +}; + +/************************************************************************* + * class SwLayCacheIoImpl + * contains the data structures that are required to read and write a + * layout cache. + *************************************************************************/ + +#define SW_LAYCACHE_IO_REC_PAGES 'p' +#define SW_LAYCACHE_IO_REC_PARA 'P' +#define SW_LAYCACHE_IO_REC_TABLE 'T' +#define SW_LAYCACHE_IO_REC_FLY 'F' + +#define SW_LAYCACHE_IO_VERSION_MAJOR 1 +#define SW_LAYCACHE_IO_VERSION_MINOR 1 + +class SwLayCacheIoImpl +{ +private: + struct RecTypeSize { + sal_uInt8 type; + sal_uLong size; + RecTypeSize(sal_uInt8 typ, sal_uLong siz) : type(typ), size(siz) {} + }; + std::vector<RecTypeSize> aRecords; + + SvStream *pStream; + + sal_uLong nFlagRecEnd; + + sal_uInt16 nMajorVersion; + sal_uInt16 nMinorVersion; + + sal_Bool bWriteMode : 1; + sal_Bool bError : 1; + +public: + SwLayCacheIoImpl( SvStream& rStrm, sal_Bool bWrtMd ); + + // Get input or output stream + SvStream& GetStream() const { return *pStream; } + + // Open a record of type "nType" + sal_Bool OpenRec( sal_uInt8 nType ); + + // Close a record of type "nType". This skips any unread data that + // remains in the record. + sal_Bool CloseRec( sal_uInt8 nType ); + + // Return the number of bytes contained in the current record that + // haven't been read by now. + sal_uInt32 BytesLeft(); + + // Return the current record's type + sal_uInt8 Peek(); + + // Skip the current record + void SkipRec(); + + // Open a flag record for reading. The uppermost four bits are flags, + // while the lowermost are the flag record's size. Flag records cannot + // be nested. + sal_uInt8 OpenFlagRec(); + + // Open flag record for writing; + void OpenFlagRec( sal_uInt8 nFlags, sal_uInt8 nLen ); + + // Close a flag record. Any bytes left are skipped. + void CloseFlagRec(); + + sal_Bool HasError() const { return bError; } + + sal_uInt16 GetMajorVersion() const { return nMajorVersion; } + sal_uInt16 GetMinorVersion() const { return nMinorVersion; } +}; + +// Stored information about text frames: +class SwFlyCache : public SwRect // position and size +{ +public: + sal_uLong nOrdNum; // Id to recognize text frames + sal_uInt16 nPageNum; // page number + SwFlyCache( sal_uInt16 nP, sal_uLong nO, long nXL, long nYL, long nWL, long nHL ) : + SwRect( nXL, nYL, nWL, nHL ), nOrdNum( nO ), nPageNum( nP ){} +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/layouter.cxx b/sw/source/core/layout/layouter.cxx new file mode 100644 index 000000000000..a02b17401c01 --- /dev/null +++ b/sw/source/core/layout/layouter.cxx @@ -0,0 +1,565 @@ +/* -*- 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 "layouter.hxx" +#include "doc.hxx" +#include "sectfrm.hxx" +#include "ftnboss.hxx" +#include "cntfrm.hxx" +#include "pagefrm.hxx" +#include "ftnfrm.hxx" +#include "txtfrm.hxx" + +// --> OD 2004-06-23 #i28701# +#include <movedfwdfrmsbyobjpos.hxx> +// <-- +// --> OD 2004-10-22 #i35911# +#include <objstmpconsiderwrapinfl.hxx> +// <-- + +#define LOOP_DETECT 250 + +class SwLooping +{ + sal_uInt16 nMinPage; + sal_uInt16 nMaxPage; + sal_uInt16 nCount; + sal_uInt16 mnLoopControlStage; +public: + SwLooping( SwPageFrm* pPage ); + void Control( SwPageFrm* pPage ); + void Drastic( SwFrm* pFrm ); + bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; }; +}; + +class SwEndnoter +{ + SwLayouter* pMaster; + SwSectionFrm* pSect; + SvPtrarr* pEndArr; +public: + SwEndnoter( SwLayouter* pLay ) + : pMaster( pLay ), pSect( NULL ), pEndArr( NULL ) {} + ~SwEndnoter() { delete pEndArr; } + void CollectEndnotes( SwSectionFrm* pSct ); + void CollectEndnote( SwFtnFrm* pFtn ); + const SwSectionFrm* GetSect() const { return pSect; } + void InsertEndnotes(); + sal_Bool HasEndnotes() const { return pEndArr && pEndArr->Count(); } +}; + +void SwEndnoter::CollectEndnotes( SwSectionFrm* pSct ) +{ + OSL_ENSURE( pSct, "CollectEndnotes: Which section?" ); + if( !pSect ) + pSect = pSct; + else if( pSct != pSect ) + return; + pSect->CollectEndnotes( pMaster ); +} + +void SwEndnoter::CollectEndnote( SwFtnFrm* pFtn ) +{ + if( pEndArr && USHRT_MAX != pEndArr->GetPos( (VoidPtr)pFtn ) ) + return; + + if( pFtn->GetUpper() ) + { + // pFtn is the master, he incorporates its follows + SwFtnFrm *pNxt = pFtn->GetFollow(); + while ( pNxt ) + { + SwFrm *pCnt = pNxt->ContainsAny(); + if ( pCnt ) + { + do + { SwFrm *pNxtCnt = pCnt->GetNext(); + pCnt->Cut(); + pCnt->Paste( pFtn ); + pCnt = pNxtCnt; + } while ( pCnt ); + } + else + { OSL_ENSURE( pNxt->Lower() && pNxt->Lower()->IsSctFrm(), + "Endnote without content?" ); + pNxt->Cut(); + delete pNxt; + } + pNxt = pFtn->GetFollow(); + } + if( pFtn->GetMaster() ) + return; + pFtn->Cut(); + } + else if( pEndArr ) + { + for ( sal_uInt16 i = 0; i < pEndArr->Count(); ++i ) + { + SwFtnFrm *pEndFtn = (SwFtnFrm*)((*pEndArr)[i]); + if( pEndFtn->GetAttr() == pFtn->GetAttr() ) + { + delete pFtn; + return; + } + } + } + if( !pEndArr ) + pEndArr = new SvPtrarr( 5, 5 ); // deleted from the SwLayouter + pEndArr->Insert( (VoidPtr)pFtn, pEndArr->Count() ); +} + +void SwEndnoter::InsertEndnotes() +{ + if( !pSect ) + return; + if( !pEndArr || !pEndArr->Count() ) + { + pSect = NULL; + return; + } + OSL_ENSURE( pSect->Lower() && pSect->Lower()->IsFtnBossFrm(), + "InsertEndnotes: Where's my column?" ); + SwFrm* pRef = pSect->FindLastCntnt( FINDMODE_MYLAST ); + SwFtnBossFrm *pBoss = pRef ? pRef->FindFtnBossFrm() + : (SwFtnBossFrm*)pSect->Lower(); + pBoss->_MoveFtns( *pEndArr ); + delete pEndArr; + pEndArr = NULL; + pSect = NULL; +} + +SwLooping::SwLooping( SwPageFrm* pPage ) +{ + OSL_ENSURE( pPage, "Where's my page?" ); + nMinPage = pPage->GetPhyPageNum(); + nMaxPage = nMinPage; + nCount = 0; + mnLoopControlStage = 0; +} + +void SwLooping::Drastic( SwFrm* pFrm ) +{ + while( pFrm ) + { + pFrm->ValidateThisAndAllLowers( mnLoopControlStage ); + pFrm = pFrm->GetNext(); + } +} + +void SwLooping::Control( SwPageFrm* pPage ) +{ + if( !pPage ) + return; + sal_uInt16 nNew = pPage->GetPhyPageNum(); + if( nNew > nMaxPage ) + nMaxPage = nNew; + if( nNew < nMinPage ) + { + nMinPage = nNew; + nMaxPage = nNew; + nCount = 0; + mnLoopControlStage = 0; + } + else if( nNew > nMinPage + 2 ) + { + nMinPage = nNew - 2; + nMaxPage = nNew; + nCount = 0; + mnLoopControlStage = 0; + } + else if( ++nCount > LOOP_DETECT ) + { +#if OSL_DEBUG_LEVEL > 1 + static sal_Bool bNoLouie = sal_False; + if( bNoLouie ) + return; + + // FME 2007-08-30 #i81146# new loop control + OSL_ENSURE( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" ); + OSL_ENSURE( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" ); + OSL_ENSURE( 2 > mnLoopControlStage, "Looping Louie: Stage 3!!!" ); +#endif + + Drastic( pPage->Lower() ); + if( nNew > nMinPage && pPage->GetPrev() ) + Drastic( ((SwPageFrm*)pPage->GetPrev())->Lower() ); + if( nNew < nMaxPage && pPage->GetNext() ) + Drastic( ((SwPageFrm*)pPage->GetNext())->Lower() ); + + ++mnLoopControlStage; + nCount = 0; + } +} + +/************************************************************************* +|* +|* SwLayouter::SwLayouter() +|* +|*************************************************************************/ + +SwLayouter::SwLayouter() + : pEndnoter( NULL ), + pLooping( NULL ), + // --> OD 2004-06-23 #i28701# + mpMovedFwdFrms( 0L ), + // <-- + // --> OD 2004-10-22 #i35911# + mpObjsTmpConsiderWrapInfl( 0L ) + // <-- +{ +} + +SwLayouter::~SwLayouter() +{ + delete pEndnoter; + delete pLooping; + // --> OD 2004-06-23 #i28701# + delete mpMovedFwdFrms; + mpMovedFwdFrms = 0L; + // <-- + // --> OD 2004-10-22 #i35911# + delete mpObjsTmpConsiderWrapInfl; + mpObjsTmpConsiderWrapInfl = 0L; + // <-- +} + +void SwLayouter::_CollectEndnotes( SwSectionFrm* pSect ) +{ + if( !pEndnoter ) + pEndnoter = new SwEndnoter( this ); + pEndnoter->CollectEndnotes( pSect ); +} + +sal_Bool SwLayouter::HasEndnotes() const +{ + return pEndnoter->HasEndnotes(); +} + +void SwLayouter::CollectEndnote( SwFtnFrm* pFtn ) +{ + pEndnoter->CollectEndnote( pFtn ); +} + +void SwLayouter::InsertEndnotes( SwSectionFrm* pSect ) +{ + if( !pEndnoter || pEndnoter->GetSect() != pSect ) + return; + pEndnoter->InsertEndnotes(); +} + +void SwLayouter::LoopControl( SwPageFrm* pPage, sal_uInt8 ) +{ + OSL_ENSURE( pLooping, "Looping: Lost control" ); + pLooping->Control( pPage ); +} + +void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTxtFrm& rFrm ) +{ + if ( pLooping && pLooping->IsLoopingLouieLight() ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "Looping Louie (Light): Fixating fractious frame" ); +#endif + SwLayouter::InsertMovedFwdFrm( rDoc, rFrm, rFrm.FindPageFrm()->GetPhyPageNum() ); + } +} + +sal_Bool SwLayouter::StartLooping( SwPageFrm* pPage ) +{ + if( pLooping ) + return sal_False; + pLooping = new SwLooping( pPage ); + return sal_True; +} + +void SwLayouter::EndLoopControl() +{ + delete pLooping; + pLooping = NULL; +} + +void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrm* pSect ) +{ + OSL_ENSURE( pDoc, "No doc, no fun" ); + if( !pDoc->GetLayouter() ) + pDoc->SetLayouter( new SwLayouter() ); + pDoc->GetLayouter()->_CollectEndnotes( pSect ); +} + +sal_Bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrm* pSect, SwFtnFrm* pFtn ) +{ + if( !pDoc->GetLayouter() ) + return sal_False; + SwLayouter *pLayouter = pDoc->GetLayouter(); + if( pLayouter->pEndnoter && pLayouter->pEndnoter->GetSect() && pSect && + ( pLayouter->pEndnoter->GetSect()->IsAnFollow( pSect ) || + pSect->IsAnFollow( pLayouter->pEndnoter->GetSect() ) ) ) + { + if( pFtn ) + pLayouter->CollectEndnote( pFtn ); + return sal_True; + } + return sal_False; +} + +sal_Bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrm *pPage ) +{ + OSL_ENSURE( pDoc, "No doc, no fun" ); + if( !pDoc->GetLayouter() ) + pDoc->SetLayouter( new SwLayouter() ); + return !pDoc->GetLayouter()->pLooping && + pDoc->GetLayouter()->StartLooping( pPage ); +} + +// --> OD 2004-06-23 #i28701# +// ----------------------------------------------------------------------------- +// methods to manage text frames, which are moved forward by the positioning +// of its anchored objects +// ----------------------------------------------------------------------------- +void SwLayouter::ClearMovedFwdFrms( const SwDoc& _rDoc ) +{ + if ( _rDoc.GetLayouter() && + _rDoc.GetLayouter()->mpMovedFwdFrms ) + { + _rDoc.GetLayouter()->mpMovedFwdFrms->Clear(); + } +} + +void SwLayouter::InsertMovedFwdFrm( const SwDoc& _rDoc, + const SwTxtFrm& _rMovedFwdFrmByObjPos, + const sal_uInt32 _nToPageNum ) +{ + if ( !_rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); + } + + if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) + { + const_cast<SwDoc&>(_rDoc).GetLayouter()->mpMovedFwdFrms = + new SwMovedFwdFrmsByObjPos(); + } + + _rDoc.GetLayouter()->mpMovedFwdFrms->Insert( _rMovedFwdFrmByObjPos, + _nToPageNum ); +} + +// --> OD 2005-01-12 #i40155# +void SwLayouter::RemoveMovedFwdFrm( const SwDoc& _rDoc, + const SwTxtFrm& _rTxtFrm ) +{ + sal_uInt32 nDummy; + if ( SwLayouter::FrmMovedFwdByObjPos( _rDoc, _rTxtFrm, nDummy ) ) + { + _rDoc.GetLayouter()->mpMovedFwdFrms->Remove( _rTxtFrm ); + } +} +// <-- + +bool SwLayouter::FrmMovedFwdByObjPos( const SwDoc& _rDoc, + const SwTxtFrm& _rTxtFrm, + sal_uInt32& _ornToPageNum ) +{ + if ( !_rDoc.GetLayouter() ) + { + _ornToPageNum = 0; + return false; + } + else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) + { + _ornToPageNum = 0; + return false; + } + else + { + return _rDoc.GetLayouter()->mpMovedFwdFrms-> + FrmMovedFwdByObjPos( _rTxtFrm, _ornToPageNum ); + } +} +// <-- +// --> OD 2004-10-05 #i26945# +bool SwLayouter::DoesRowContainMovedFwdFrm( const SwDoc& _rDoc, + const SwRowFrm& _rRowFrm ) +{ + if ( !_rDoc.GetLayouter() ) + { + return false; + } + else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms ) + { + return false; + } + else + { + return _rDoc.GetLayouter()-> + mpMovedFwdFrms->DoesRowContainMovedFwdFrm( _rRowFrm ); + } +} +// <-- + +// --> OD 2004-10-22 #i35911# +void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc ) +{ + if ( _rDoc.GetLayouter() && + _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl ) + { + _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear(); + } +} +void SwLayouter::InsertObjForTmpConsiderWrapInfluence( + const SwDoc& _rDoc, + SwAnchoredObject& _rAnchoredObj ) +{ + if ( !_rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); + } + + if ( !_rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl ) + { + const_cast<SwDoc&>(_rDoc).GetLayouter()->mpObjsTmpConsiderWrapInfl = + new SwObjsMarkedAsTmpConsiderWrapInfluence(); + } + + _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj ); +} +// <-- +// --> OD 2005-01-12 #i40155# +void SwLayouter::ClearFrmsNotToWrap( const SwDoc& _rDoc ) +{ + if ( _rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.clear(); + } +} + +void SwLayouter::InsertFrmNotToWrap( const SwDoc& _rDoc, + const SwFrm& _rFrm ) +{ + if ( !_rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() ); + } + + if ( !SwLayouter::FrmNotToWrap( _rDoc, _rFrm ) ) + { + const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.push_back( &_rFrm ); + } +} + +bool SwLayouter::FrmNotToWrap( const IDocumentLayoutAccess& _rDLA, + const SwFrm& _rFrm ) +{ + const SwLayouter* pLayouter = _rDLA.GetLayouter(); + if ( !pLayouter ) + { + return false; + } + else + { + bool bFrmNotToWrap( false ); + std::vector< const SwFrm* >::const_iterator aIter = + pLayouter->maFrmsNotToWrap.begin(); + for ( ; aIter != pLayouter->maFrmsNotToWrap.end(); ++aIter ) + { + const SwFrm* pFrm = *(aIter); + if ( pFrm == &_rFrm ) + { + bFrmNotToWrap = true; + break; + } + } + return bFrmNotToWrap; + } +} +// <-- + +void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTxtFrm& rTxtFrm ) +{ + if ( bCondition ) + { + const SwDoc& rDoc = *rTxtFrm.GetAttrSet()->GetDoc(); + if ( rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(rDoc).GetLayouter()->LoopingLouieLight( rDoc, rTxtFrm ); + } + } +} + +// --> OD 2006-05-10 #i65250# +bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc, + const SwFlowFrm& p_rFlowFrm, + const SwLayoutFrm& p_rNewUpperFrm ) +{ + bool bMoveBwdSuppressed( false ); + + if ( !p_rDoc.GetLayouter() ) + { + const_cast<SwDoc&>(p_rDoc).SetLayouter( new SwLayouter() ); + } + + // create hash map key + tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo; + aMoveBwdLayoutInfo.mnFrmId = p_rFlowFrm.GetFrm()->GetFrmId(); + aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrm.Frm().Pos().X(); + aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrm.Frm().Pos().Y(); + aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrm.Frm().Width(); + aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrm.Frm().Height(); + SWRECTFN( (&p_rNewUpperFrm) ) + const SwFrm* pLastLower( p_rNewUpperFrm.Lower() ); + while ( pLastLower && pLastLower->GetNext() ) + { + pLastLower = pLastLower->GetNext(); + } + aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper = + pLastLower + ? (pLastLower->Frm().*fnRect->fnBottomDist)( (p_rNewUpperFrm.*fnRect->fnGetPrtBottom)() ) + : (p_rNewUpperFrm.Frm().*fnRect->fnGetHeight)(); + + // check for moving backward suppress threshold + const sal_uInt16 cMoveBwdCountSuppressThreshold = 20; + if ( ++const_cast<SwDoc&>(p_rDoc).GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] > + cMoveBwdCountSuppressThreshold ) + { + bMoveBwdSuppressed = true; + } + + return bMoveBwdSuppressed; +} + +void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc ) +{ + if ( _rDoc.GetLayouter() ) + const_cast<SwDoc&>(_rDoc).GetLayouter()->maMoveBwdLayoutInfo.clear(); +} +// <-- + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx b/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx new file mode 100644 index 000000000000..7ce3bf320579 --- /dev/null +++ b/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx @@ -0,0 +1,108 @@ +/* -*- 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 <movedfwdfrmsbyobjpos.hxx> +#include <txtfrm.hxx> +#include <rowfrm.hxx> +#include <pagefrm.hxx> +#include <ndtxt.hxx> +#include <switerator.hxx> + +SwMovedFwdFrmsByObjPos::SwMovedFwdFrmsByObjPos() +{ +} + +SwMovedFwdFrmsByObjPos::~SwMovedFwdFrmsByObjPos() +{ + Clear(); +} + +void SwMovedFwdFrmsByObjPos::Insert( const SwTxtFrm& _rMovedFwdFrmByObjPos, + const sal_uInt32 _nToPageNum ) +{ + if ( maMovedFwdFrms.end() == + maMovedFwdFrms.find( _rMovedFwdFrmByObjPos.GetTxtNode() ) ) + { + const NodeMapEntry aEntry( _rMovedFwdFrmByObjPos.GetTxtNode(), _nToPageNum ); + maMovedFwdFrms.insert( aEntry ); + } +} + +void SwMovedFwdFrmsByObjPos::Remove( const SwTxtFrm& _rTxtFrm ) +{ + maMovedFwdFrms.erase( _rTxtFrm.GetTxtNode() ); +}; + +bool SwMovedFwdFrmsByObjPos::FrmMovedFwdByObjPos( const SwTxtFrm& _rTxtFrm, + sal_uInt32& _ornToPageNum ) const +{ + NodeMapIter aIter = maMovedFwdFrms.find( _rTxtFrm.GetTxtNode() ); + if ( maMovedFwdFrms.end() != aIter ) + { + _ornToPageNum = (*aIter).second; + return true; + } + + return false; +} + +// --> OD 2004-10-05 #i26945# +bool SwMovedFwdFrmsByObjPos::DoesRowContainMovedFwdFrm( const SwRowFrm& _rRowFrm ) const +{ + bool bDoesRowContainMovedFwdFrm( false ); + + const sal_uInt32 nPageNumOfRow = _rRowFrm.FindPageFrm()->GetPhyPageNum(); + + NodeMapIter aIter = maMovedFwdFrms.begin(); + for ( ; aIter != maMovedFwdFrms.end(); ++aIter ) + { + const NodeMapEntry& rEntry = *(aIter); + if ( rEntry.second >= nPageNumOfRow ) + { + SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *rEntry.first ); + for( SwTxtFrm* pTxtFrm = aFrmIter.First(); pTxtFrm; pTxtFrm = (SwTxtFrm*)aFrmIter.Next() ) + { + // --> OD 2004-12-03 #115759# - assure that found text frame + // is the first one. + if ( _rRowFrm.IsAnLower( pTxtFrm ) && !pTxtFrm->GetIndPrev() ) + // <-- + { + bDoesRowContainMovedFwdFrm = true; + break; + } + } + } + } + + return bDoesRowContainMovedFwdFrm; +} +// <-- + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx new file mode 100644 index 000000000000..faefa9c3e8b0 --- /dev/null +++ b/sw/source/core/layout/newfrm.cxx @@ -0,0 +1,679 @@ +/* -*- 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 <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> +#include <fmtfordr.hxx> +#include <fmtpdsc.hxx> +#include <frmfmt.hxx> +#include <swtable.hxx> +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <viewsh.hxx> +#include <doc.hxx> +#include <node.hxx> +#include <dflyobj.hxx> +#include <frmtool.hxx> +#include <virtoutp.hxx> +#include <blink.hxx> +#include <ndindex.hxx> +#include <sectfrm.hxx> +#include <notxtfrm.hxx> +#include <pagedesc.hxx> +#include "viewimp.hxx" +#include "IDocumentTimerAccess.hxx" +#include "IDocumentLayoutAccess.hxx" +#include "IDocumentFieldsAccess.hxx" +#include "IDocumentSettingAccess.hxx" +#include "IDocumentDrawModelAccess.hxx" +#include <hints.hxx> +#include <viewopt.hxx> + +SwLayVout *SwRootFrm::pVout = 0; +sal_Bool SwRootFrm::bInPaint = sal_False; +sal_Bool SwRootFrm::bNoVirDev = sal_False; + +SwCache *SwFrm::pCache = 0; + +long FirstMinusSecond( long nFirst, long nSecond ) + { return nFirst - nSecond; } +long SecondMinusFirst( long nFirst, long nSecond ) + { return nSecond - nFirst; } +long SwIncrement( long nA, long nAdd ) + { return nA + nAdd; } +long SwDecrement( long nA, long nSub ) + { return nA - nSub; } + +static SwRectFnCollection aHorizontal = { + /* fnRectGet */ + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Width, + &SwRect::_Height, + &SwRect::TopLeft, + &SwRect::_Size, + /* fnRectSet */ + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Width, + &SwRect::_Height, + + &SwRect::SubTop, + &SwRect::AddBottom, + &SwRect::SubLeft, + &SwRect::AddRight, + &SwRect::AddWidth, + &SwRect::AddHeight, + + &SwRect::SetPosX, + &SwRect::SetPosY, + + &SwFrm::GetTopMargin, + &SwFrm::GetBottomMargin, + &SwFrm::GetLeftMargin, + &SwFrm::GetRightMargin, + &SwFrm::SetLeftRightMargins, + &SwFrm::SetTopBottomMargins, + &SwFrm::GetPrtTop, + &SwFrm::GetPrtBottom, + &SwFrm::GetPrtLeft, + &SwFrm::GetPrtRight, + &SwRect::GetTopDistance, + &SwRect::GetBottomDistance, + &SwRect::GetLeftDistance, + &SwRect::GetRightDistance, + &SwFrm::SetMaxBottom, + &SwRect::OverStepBottom, + + &SwRect::SetUpperLeftCorner, + &SwFrm::MakeBelowPos, + &FirstMinusSecond, + &FirstMinusSecond, + &SwIncrement, + &SwIncrement, + &SwRect::SetLeftAndWidth, + &SwRect::SetTopAndHeight +}; + +static SwRectFnCollection aVertical = { + /* fnRectGet */ + &SwRect::_Right, + &SwRect::_Left, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + &SwRect::TopRight, + &SwRect::SwappedSize, + /* fnRectSet */ + &SwRect::_Right, + &SwRect::_Left, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + + &SwRect::AddRight, + &SwRect::SubLeft, + &SwRect::SubTop, + &SwRect::AddBottom, + &SwRect::AddHeight, + &SwRect::AddWidth, + + &SwRect::SetPosY, + &SwRect::SetPosX, + + &SwFrm::GetRightMargin, + &SwFrm::GetLeftMargin, + &SwFrm::GetTopMargin, + &SwFrm::GetBottomMargin, + &SwFrm::SetTopBottomMargins, + &SwFrm::SetRightLeftMargins, + &SwFrm::GetPrtRight, + &SwFrm::GetPrtLeft, + &SwFrm::GetPrtTop, + &SwFrm::GetPrtBottom, + &SwRect::GetRightDistance, + &SwRect::GetLeftDistance, + &SwRect::GetTopDistance, + &SwRect::GetBottomDistance, + &SwFrm::SetMinLeft, + &SwRect::OverStepLeft, + + &SwRect::SetUpperRightCorner, + &SwFrm::MakeLeftPos, + &FirstMinusSecond, + &SecondMinusFirst, + &SwIncrement, + &SwDecrement, + &SwRect::SetTopAndHeight, + &SwRect::SetRightAndWidth +}; + +static SwRectFnCollection aBottomToTop = { + /* fnRectGet */ + &SwRect::_Bottom, + &SwRect::_Top, + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Width, + &SwRect::_Height, + &SwRect::BottomLeft, + &SwRect::_Size, + /* fnRectSet */ + &SwRect::_Bottom, + &SwRect::_Top, + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Width, + &SwRect::_Height, + + &SwRect::AddBottom, + &SwRect::SubTop, + &SwRect::SubLeft, + &SwRect::AddRight, + &SwRect::AddWidth, + &SwRect::AddHeight, + + &SwRect::SetPosX, + &SwRect::SetPosY, + + &SwFrm::GetBottomMargin, + &SwFrm::GetTopMargin, + &SwFrm::GetLeftMargin, + &SwFrm::GetRightMargin, + &SwFrm::SetLeftRightMargins, + &SwFrm::SetBottomTopMargins, + &SwFrm::GetPrtBottom, + &SwFrm::GetPrtTop, + &SwFrm::GetPrtLeft, + &SwFrm::GetPrtRight, + &SwRect::GetBottomDistance, + &SwRect::GetTopDistance, + &SwRect::GetLeftDistance, + &SwRect::GetRightDistance, + &SwFrm::SetMinTop, + &SwRect::OverStepTop, + + &SwRect::SetLowerLeftCorner, + &SwFrm::MakeUpperPos, + &FirstMinusSecond, + &SecondMinusFirst, + &SwIncrement, + &SwDecrement, + &SwRect::SetLeftAndWidth, + &SwRect::SetBottomAndHeight +}; + +static SwRectFnCollection aVerticalRightToLeft = { + /* fnRectGet */ + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + &SwRect::BottomRight, + &SwRect::SwappedSize, + /* fnRectSet */ + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + + &SwRect::SubLeft, + &SwRect::AddRight, + &SwRect::SubTop, + &SwRect::AddBottom, + &SwRect::AddHeight, + &SwRect::AddWidth, + + &SwRect::SetPosY, + &SwRect::SetPosX, + + &SwFrm::GetLeftMargin, + &SwFrm::GetRightMargin, + &SwFrm::GetTopMargin, + &SwFrm::GetBottomMargin, + &SwFrm::SetTopBottomMargins, + &SwFrm::SetLeftRightMargins, + &SwFrm::GetPrtLeft, + &SwFrm::GetPrtRight, + &SwFrm::GetPrtBottom, + &SwFrm::GetPrtTop, + &SwRect::GetLeftDistance, + &SwRect::GetRightDistance, + &SwRect::GetBottomDistance, + &SwRect::GetTopDistance, + &SwFrm::SetMaxRight, + &SwRect::OverStepRight, + + &SwRect::SetLowerLeftCorner, + &SwFrm::MakeRightPos, + &FirstMinusSecond, + &FirstMinusSecond, + &SwDecrement, + &SwIncrement, + &SwRect::SetBottomAndHeight, + &SwRect::SetLeftAndWidth +}; +//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin +static SwRectFnCollection aVerticalLeftToRight = { + /* fnRectGet */ + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + &SwRect::TopLeft, + &SwRect::SwappedSize, + /* fnRectSet */ + &SwRect::_Left, + &SwRect::_Right, + &SwRect::_Top, + &SwRect::_Bottom, + &SwRect::_Height, + &SwRect::_Width, + + &SwRect::SubLeft, + &SwRect::AddRight, + &SwRect::SubTop, + &SwRect::AddBottom, + &SwRect::AddHeight, + &SwRect::AddWidth, + + &SwRect::SetPosY, + &SwRect::SetPosX, + + &SwFrm::GetLeftMargin, + &SwFrm::GetRightMargin, + &SwFrm::GetTopMargin, + &SwFrm::GetBottomMargin, + &SwFrm::SetTopBottomMargins, + &SwFrm::SetLeftRightMargins, + &SwFrm::GetPrtLeft, + &SwFrm::GetPrtRight, + &SwFrm::GetPrtTop, + &SwFrm::GetPrtBottom, + &SwRect::GetLeftDistance, + &SwRect::GetRightDistance, + &SwRect::GetTopDistance, + &SwRect::GetBottomDistance, + &SwFrm::SetMaxRight, + &SwRect::OverStepRight, + + &SwRect::SetUpperLeftCorner, + &SwFrm::MakeRightPos, + &FirstMinusSecond, + &FirstMinusSecond, + &SwIncrement, + &SwIncrement, + &SwRect::SetTopAndHeight, + &SwRect::SetLeftAndWidth +}; +//End of SCMS +SwRectFn fnRectHori = &aHorizontal; +SwRectFn fnRectVert = &aVertical; +//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin +SwRectFn fnRectVertL2R = &aVerticalLeftToRight; +//End of SCMS +SwRectFn fnRectB2T = &aBottomToTop; +SwRectFn fnRectVL2R = &aVerticalRightToLeft; + +// --> OD 2006-05-10 #i65250# +sal_uInt32 SwFrm::mnLastFrmId=0; +// <-- + +TYPEINIT1(SwFrm,SwClient); //rtti fuer SwFrm +TYPEINIT1(SwCntntFrm,SwFrm); //rtti fuer SwCntntFrm + + +void _FrmInit() +{ + SwRootFrm::pVout = new SwLayVout(); + SwCache *pNew = new SwCache( 100, 100 +#if OSL_DEBUG_LEVEL > 1 + , "static SwBorderAttrs::pCache" +#endif + ); + SwFrm::SetCache( pNew ); +} + + + +void _FrmFinit() +{ +#if OSL_DEBUG_LEVEL > 1 + // im Chache duerfen nur noch 0-Pointer stehen + for( sal_uInt16 n = SwFrm::GetCachePtr()->Count(); n; ) + if( (*SwFrm::GetCachePtr())[ --n ] ) + { + SwCacheObj* pObj = (*SwFrm::GetCachePtr())[ n ]; + OSL_ENSURE( !pObj, "Wer hat sich nicht ausgetragen?"); + } +#endif + delete SwRootFrm::pVout; + delete SwFrm::GetCachePtr(); +} + +/************************************************************************* +|* +|* RootFrm::Alles was so zur CurrShell gehoert +|* +|*************************************************************************/ + +typedef CurrShell* CurrShellPtr; +SV_DECL_PTRARR_SORT(SwCurrShells,CurrShellPtr,4,4) +SV_IMPL_PTRARR_SORT(SwCurrShells,CurrShellPtr) + +CurrShell::CurrShell( ViewShell *pNew ) +{ + OSL_ENSURE( pNew, "0-Shell einsetzen?" ); + pRoot = pNew->GetLayout(); + if ( pRoot ) + { + pPrev = pRoot->pCurrShell; + pRoot->pCurrShell = pNew; + pRoot->pCurrShells->Insert( this ); + } + else + pPrev = 0; +} + +CurrShell::~CurrShell() +{ + if ( pRoot ) + { + pRoot->pCurrShells->Remove( this ); + if ( pPrev ) + pRoot->pCurrShell = pPrev; + if ( !pRoot->pCurrShells->Count() && pRoot->pWaitingCurrShell ) + { + pRoot->pCurrShell = pRoot->pWaitingCurrShell; + pRoot->pWaitingCurrShell = 0; + } + } +} + +void SetShell( ViewShell *pSh ) +{ + SwRootFrm *pRoot = pSh->GetLayout(); + if ( !pRoot->pCurrShells->Count() ) + pRoot->pCurrShell = pSh; + else + pRoot->pWaitingCurrShell = pSh; +} + +void SwRootFrm::DeRegisterShell( ViewShell *pSh ) +{ + //Wenn moeglich irgendeine Shell aktivieren + if ( pCurrShell == pSh ) + pCurrShell = pSh->GetNext() != pSh ? (ViewShell*)pSh->GetNext() : 0; + + //Das hat sich eruebrigt + if ( pWaitingCurrShell == pSh ) + pWaitingCurrShell = 0; + + //Referenzen entfernen. + for ( sal_uInt16 i = 0; i < pCurrShells->Count(); ++i ) + { + CurrShell *pC = (*pCurrShells)[i]; + if (pC->pPrev == pSh) + pC->pPrev = 0; + } +} + +void InitCurrShells( SwRootFrm *pRoot ) +{ + pRoot->pCurrShells = new SwCurrShells; +} + + +/************************************************************************* +|* +|* SwRootFrm::SwRootFrm() +|* +|* Beschreibung: +|* Der RootFrm laesst sich grundsaetzlich vom Dokument ein eigenes +|* FrmFmt geben. Dieses loescht er dann selbst im DTor. +|* Das eigene FrmFmt wird vom uebergebenen Format abgeleitet. +|* +|*************************************************************************/ + + +SwRootFrm::SwRootFrm( SwFrmFmt *pFmt, ViewShell * pSh ) : + SwLayoutFrm( pFmt->GetDoc()->MakeFrmFmt( + XubString( "Root", RTL_TEXTENCODING_MS_1252 ), pFmt ), 0 ), + // --> PAGES01 + maPagesArea(), + mnViewWidth( -1 ), + mnColumns( 0 ), + mbBookMode( false ), + mbSidebarChanged( false ), + mbNeedGrammarCheck( false ), + // <-- + nBrowseWidth( MM50*4 ), //2cm Minimum + pTurbo( 0 ), + pLastPage( 0 ), + pCurrShell( pSh ), + pWaitingCurrShell( 0 ), + pDrawPage( 0 ), + pDestroy( 0 ), + nPhyPageNums( 0 ), + nAccessibleShells( 0 ) +{ + nType = FRMC_ROOT; + bIdleFormat = bTurboAllowed = bAssertFlyPages = bIsNewLayout = sal_True; + bCheckSuperfluous = bBrowseWidthValid = sal_False; + setRootFrm( this ); +} + +void SwRootFrm::Init( SwFrmFmt* pFmt ) +{ + InitCurrShells( this ); + + IDocumentTimerAccess *pTimerAccess = pFmt->getIDocumentTimerAccess(); + IDocumentLayoutAccess *pLayoutAccess = pFmt->getIDocumentLayoutAccess(); + IDocumentFieldsAccess *pFieldsAccess = pFmt->getIDocumentFieldsAccess(); + const IDocumentSettingAccess *pSettingAccess = pFmt->getIDocumentSettingAccess(); + pTimerAccess->StopIdling(); + pLayoutAccess->SetCurrentViewShell( this->GetCurrShell() ); //Fuer das Erzeugen der Flys durch MakeFrms() //swmod 071108//swmod 071225 + bCallbackActionEnabled = sal_False; //vor Verlassen auf sal_True setzen! + + SdrModel *pMd = pFmt->getIDocumentDrawModelAccess()->GetDrawModel(); + if ( pMd ) + { + // Disable "multiple layout" + pDrawPage = pMd->GetPage(0); //pMd->AllocPage( FALSE ); + //pMd->InsertPage( pDrawPage ); + // end of disabling + + pDrawPage->SetSize( Frm().SSize() ); + } + + //Initialisierung des Layouts: Seiten erzeugen. Inhalt mit cntnt verbinden + //usw. + //Zuerst einiges initialiseren und den ersten Node besorgen (der wird + //fuer den PageDesc benoetigt). + + SwDoc* pDoc = pFmt->GetDoc(); + SwNodeIndex aIndex( *pDoc->GetNodes().GetEndOfContent().StartOfSectionNode() ); + SwCntntNode *pNode = pDoc->GetNodes().GoNextSection( &aIndex, sal_True, sal_False ); + // --> FME 2005-05-25 #123067# pNode = 0 can really happen: + SwTableNode *pTblNd= pNode ? pNode->FindTableNode() : 0; + // <-- + + //PageDesc besorgen (entweder vom FrmFmt des ersten Node oder den + //initialen.) + SwPageDesc *pDesc = 0; + sal_uInt16 nPgNum = 1; + + if ( pTblNd ) + { + const SwFmtPageDesc &rDesc = pTblNd->GetTable().GetFrmFmt()->GetPageDesc(); + pDesc = (SwPageDesc*)rDesc.GetPageDesc(); + //#19104# Seitennummeroffset beruecksictigen!! + bIsVirtPageNum = 0 != ( nPgNum = rDesc.GetNumOffset() ); + } + else if ( pNode ) + { + const SwFmtPageDesc &rDesc = pNode->GetSwAttrSet().GetPageDesc(); + pDesc = (SwPageDesc*)rDesc.GetPageDesc(); + //#19104# Seitennummeroffset beruecksictigen!! + bIsVirtPageNum = 0 != ( nPgNum = rDesc.GetNumOffset() ); + } + else + bIsVirtPageNum = sal_False; + if ( !pDesc ) + pDesc = (SwPageDesc*) + &const_cast<const SwDoc *>(pDoc)->GetPageDesc( 0 ); + const sal_Bool bOdd = !nPgNum || 0 != ( nPgNum % 2 ); + + //Eine Seite erzeugen und in das Layout stellen + SwPageFrm *pPage = ::InsertNewPage( *pDesc, this, bOdd, sal_False, sal_False, 0 ); + + //Erstes Blatt im Bodytext-Bereich suchen. + SwLayoutFrm *pLay = pPage->FindBodyCont(); + while( pLay->Lower() ) + pLay = (SwLayoutFrm*)pLay->Lower(); + + SwNodeIndex aTmp( *pDoc->GetNodes().GetEndOfContent().StartOfSectionNode(), 1 ); + ::_InsertCnt( pLay, pDoc, aTmp.GetIndex(), sal_True ); + //Noch nicht ersetzte Master aus der Liste entfernen. + RemoveMasterObjs( pDrawPage ); + if( pSettingAccess->get(IDocumentSettingAccess::GLOBAL_DOCUMENT) ) + pFieldsAccess->UpdateRefFlds( NULL ); + //b6433357: Update page fields after loading + // ---> + if ( !pCurrShell || !pCurrShell->Imp()->IsUpdateExpFlds() ) + { + SwDocPosUpdate aMsgHnt( pPage->Frm().Top() ); + pFieldsAccess->UpdatePageFlds( &aMsgHnt ); + } + // <--- + + pTimerAccess->StartIdling(); + bCallbackActionEnabled = sal_True; + + ViewShell *pViewSh = GetCurrShell(); + if (pViewSh) + mbNeedGrammarCheck = pViewSh->GetViewOptions()->IsOnlineSpell(); +} + +/************************************************************************* +|* +|* SwRootFrm::~SwRootFrm() +|* +|*************************************************************************/ + + + +SwRootFrm::~SwRootFrm() +{ + bTurboAllowed = sal_False; + pTurbo = 0; + if(pBlink) + pBlink->FrmDelete( this ); + static_cast<SwFrmFmt*>(GetRegisteredInNonConst())->GetDoc()->DelFrmFmt( static_cast<SwFrmFmt*>(GetRegisteredInNonConst()) ); + delete pDestroy; + pDestroy = 0; + + //Referenzen entfernen. + for ( sal_uInt16 i = 0; i < pCurrShells->Count(); ++i ) + (*pCurrShells)[i]->pRoot = 0; + + delete pCurrShells; + + OSL_ENSURE( 0==nAccessibleShells, "Some accessible shells are left" ); +} + +/************************************************************************* +|* +|* SwRootFrm::RemoveMasterObjs() +|* +|*************************************************************************/ + + +void SwRootFrm::RemoveMasterObjs( SdrPage *pPg ) +{ + //Alle Masterobjekte aus der Page entfernen. Nicht loeschen!! + for( sal_uLong i = pPg ? pPg->GetObjCount() : 0; i; ) + { + SdrObject* pObj = pPg->GetObj( --i ); + if( pObj->ISA(SwFlyDrawObj ) ) + pPg->RemoveObject( i ); + } +} + + +void SwRootFrm::AllCheckPageDescs() const +{ + CheckPageDescs( (SwPageFrm*)this->Lower() ); +} +//swmod 080226 +void SwRootFrm::AllInvalidateAutoCompleteWords() const +{ + SwPageFrm *pPage = (SwPageFrm*)this->Lower(); + while ( pPage ) + { + pPage->InvalidateAutoCompleteWords(); + pPage = (SwPageFrm*)pPage->GetNext(); + } +}//swmod 080305 +void SwRootFrm::AllAddPaintRect() const +{ + GetCurrShell()->AddPaintRect( this->Frm() ); +}//swmod 080305 +void SwRootFrm::AllRemoveFtns() +{ + RemoveFtns(); +} +void SwRootFrm::AllInvalidateSmartTagsOrSpelling(sal_Bool bSmartTags) const +{ + SwPageFrm *pPage = (SwPageFrm*)this->Lower(); + while ( pPage ) + { + if ( bSmartTags ) + pPage->InvalidateSmartTags(); + + pPage->InvalidateSpelling(); + pPage = (SwPageFrm*)pPage->GetNext(); + } //swmod 080218 +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objectformatter.cxx b/sw/source/core/layout/objectformatter.cxx new file mode 100644 index 000000000000..c9cebfd93ce6 --- /dev/null +++ b/sw/source/core/layout/objectformatter.cxx @@ -0,0 +1,580 @@ +/* -*- 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 <objectformatter.hxx> +#include <objectformattertxtfrm.hxx> +#include <objectformatterlayfrm.hxx> +#include <anchoredobject.hxx> +#include <anchoreddrawobject.hxx> +#include <sortedobjs.hxx> +#include <pagefrm.hxx> +#include <flyfrms.hxx> +#include <txtfrm.hxx> +#include <layact.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <doc.hxx> + +#include <vector> + +// ============================================================================= +// helper class <SwPageNumAndTypeOfAnchors> +// --> #i26945# - Additionally the type of the anchor text frame +// is collected - by type is meant 'master' or 'follow'. +// ============================================================================= +class SwPageNumAndTypeOfAnchors +{ + private: + struct tEntry + { + SwAnchoredObject* mpAnchoredObj; + sal_uInt32 mnPageNumOfAnchor; + bool mbAnchoredAtMaster; + }; + + std::vector< tEntry* > maObjList; + + public: + inline SwPageNumAndTypeOfAnchors() + { + } + inline ~SwPageNumAndTypeOfAnchors() + { + for ( std::vector< tEntry* >::iterator aIter = maObjList.begin(); + aIter != maObjList.end(); ++aIter ) + { + delete (*aIter); + } + maObjList.clear(); + } + + inline void Collect( SwAnchoredObject& _rAnchoredObj ) + { + tEntry* pNewEntry = new tEntry(); + pNewEntry->mpAnchoredObj = &_rAnchoredObj; + // --> #i33751#, #i34060# - method <GetPageFrmOfAnchor()> + // is replaced by method <FindPageFrmOfAnchor()>. It's return value + // have to be checked. + SwPageFrm* pPageFrmOfAnchor = _rAnchoredObj.FindPageFrmOfAnchor(); + if ( pPageFrmOfAnchor ) + { + pNewEntry->mnPageNumOfAnchor = pPageFrmOfAnchor->GetPhyPageNum(); + } + else + { + pNewEntry->mnPageNumOfAnchor = 0; + } + // <-- + // --> #i26945# - collect type of anchor + SwTxtFrm* pAnchorCharFrm = _rAnchoredObj.FindAnchorCharFrm(); + if ( pAnchorCharFrm ) + { + pNewEntry->mbAnchoredAtMaster = !pAnchorCharFrm->IsFollow(); + } + else + { + pNewEntry->mbAnchoredAtMaster = true; + } + // <-- + maObjList.push_back( pNewEntry ); + } + + inline SwAnchoredObject* operator[]( sal_uInt32 _nIndex ) + { + SwAnchoredObject* bRetObj = 0L; + + if ( _nIndex < Count()) + { + bRetObj = maObjList[_nIndex]->mpAnchoredObj; + } + + return bRetObj; + } + + inline sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const + { + sal_uInt32 nRetPgNum = 0L; + + if ( _nIndex < Count()) + { + nRetPgNum = maObjList[_nIndex]->mnPageNumOfAnchor; + } + + return nRetPgNum; + } + + // --> #i26945# + inline bool AnchoredAtMaster( sal_uInt32 _nIndex ) + { + bool bAnchoredAtMaster( true ); + + if ( _nIndex < Count()) + { + bAnchoredAtMaster = maObjList[_nIndex]->mbAnchoredAtMaster; + } + + return bAnchoredAtMaster; + } + // <-- + + inline sal_uInt32 Count() const + { + return maObjList.size(); + } +}; + +// ============================================================================= +// implementation of class <SwObjectFormatter> +// ============================================================================= +SwObjectFormatter::SwObjectFormatter( const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction, + const bool _bCollectPgNumOfAnchors ) + : mrPageFrm( _rPageFrm ), + mbFormatOnlyAsCharAnchored( false ), + mbConsiderWrapOnObjPos( _rPageFrm.GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ), + mpLayAction( _pLayAction ), + // --> #i26945# + mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : 0L ) + // <-- +{ +} + +SwObjectFormatter::~SwObjectFormatter() +{ + delete mpPgNumAndTypeOfAnchors; +} + +SwObjectFormatter* SwObjectFormatter::CreateObjFormatter( + SwFrm& _rAnchorFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ) +{ + SwObjectFormatter* pObjFormatter = 0L; + if ( _rAnchorFrm.IsTxtFrm() ) + { + pObjFormatter = SwObjectFormatterTxtFrm::CreateObjFormatter( + static_cast<SwTxtFrm&>(_rAnchorFrm), + _rPageFrm, _pLayAction ); + } + else if ( _rAnchorFrm.IsLayoutFrm() ) + { + pObjFormatter = SwObjectFormatterLayFrm::CreateObjFormatter( + static_cast<SwLayoutFrm&>(_rAnchorFrm), + _rPageFrm, _pLayAction ); + } + else + { + OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexcepted type of anchor frame" ); + } + + return pObjFormatter; +} + +/** method to format all floating screen objects at the given anchor frame + + @author OD +*/ +bool SwObjectFormatter::FormatObjsAtFrm( SwFrm& _rAnchorFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ) +{ + bool bSuccess( true ); + + // create corresponding object formatter + SwObjectFormatter* pObjFormatter = + SwObjectFormatter::CreateObjFormatter( _rAnchorFrm, _rPageFrm, _pLayAction ); + + if ( pObjFormatter ) + { + // format anchored floating screen objects + bSuccess = pObjFormatter->DoFormatObjs(); + } + delete pObjFormatter; + + return bSuccess; +} + +/** method to format a given floating screen object + + @author OD +*/ +bool SwObjectFormatter::FormatObj( SwAnchoredObject& _rAnchoredObj, + SwFrm* _pAnchorFrm, + const SwPageFrm* _pPageFrm, + SwLayAction* _pLayAction ) +{ + bool bSuccess( true ); + + OSL_ENSURE( _pAnchorFrm || _rAnchoredObj.GetAnchorFrm(), + "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" ); + SwFrm& rAnchorFrm = _pAnchorFrm ? *(_pAnchorFrm) : *(_rAnchoredObj.AnchorFrm()); + + OSL_ENSURE( _pPageFrm || rAnchorFrm.FindPageFrm(), + "<SwObjectFormatter::FormatObj(..)> - missing page frame" ); + const SwPageFrm& rPageFrm = _pPageFrm ? *(_pPageFrm) : *(rAnchorFrm.FindPageFrm()); + + // create corresponding object formatter + SwObjectFormatter* pObjFormatter = + SwObjectFormatter::CreateObjFormatter( rAnchorFrm, rPageFrm, _pLayAction ); + + if ( pObjFormatter ) + { + // format given floating screen object + // --> #i40147# - check for moved forward anchor frame + bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true ); + // <-- + } + delete pObjFormatter; + + return bSuccess; +} + +/** helper method for method <_FormatObj(..)> - performs the intrinsic format + of the layout of the given layout frame and all its lower layout frames. + + #i28701# + IMPORTANT NOTE: + Method corresponds to methods <SwLayAction::FormatLayoutFly(..)> and + <SwLayAction::FormatLayout(..)>. Thus, its code for the formatting have + to be synchronised. + + @author OD +*/ +void SwObjectFormatter::_FormatLayout( SwLayoutFrm& _rLayoutFrm ) +{ + _rLayoutFrm.Calc(); + + SwFrm* pLowerFrm = _rLayoutFrm.Lower(); + while ( pLowerFrm ) + { + if ( pLowerFrm->IsLayoutFrm() ) + { + _FormatLayout( *(static_cast<SwLayoutFrm*>(pLowerFrm)) ); + } + pLowerFrm = pLowerFrm->GetNext(); + } +} + +/** helper method for method <_FormatObj(..)> - performs the intrinsic + format of the content of the given floating screen object. + + #i28701# + + @author OD +*/ +void SwObjectFormatter::_FormatObjCntnt( SwAnchoredObject& _rAnchoredObj ) +{ + if ( !_rAnchoredObj.ISA(SwFlyFrm) ) + { + // only Writer fly frames have content + return; + } + + SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj); + SwCntntFrm* pCntnt = rFlyFrm.ContainsCntnt(); + + while ( pCntnt ) + { + // format content + pCntnt->OptCalc(); + + // format floating screen objects at content text frame + // --> #i23129#, #i36347# - pass correct page frame to + // the object formatter + if ( pCntnt->IsTxtFrm() && + !SwObjectFormatter::FormatObjsAtFrm( *pCntnt, + *(pCntnt->FindPageFrm()), + GetLayAction() ) ) + // <-- + { + // restart format with first content + pCntnt = rFlyFrm.ContainsCntnt(); + continue; + } + + // continue with next content + pCntnt = pCntnt->GetNextCntntFrm(); + } +} + +/** performs the intrinsic format of a given floating screen object and its content. + + #i28701# + + @author OD +*/ +void SwObjectFormatter::_FormatObj( SwAnchoredObject& _rAnchoredObj ) +{ + // check, if only as-character anchored object have to be formatted, and + // check the anchor type + if ( FormatOnlyAsCharAnchored() && + !(_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) ) + { + return; + } + + // collect anchor object and its 'anchor' page number, if requested + if ( mpPgNumAndTypeOfAnchors ) + { + mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj ); + } + + if ( _rAnchoredObj.ISA(SwFlyFrm) ) + { + SwFlyFrm& rFlyFrm = static_cast<SwFlyFrm&>(_rAnchoredObj); + // --> #i34753# - reset flag, which prevents a positioning + if ( rFlyFrm.IsFlyLayFrm() ) + { + static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( false ); + } + // <-- + + // #i81146# new loop control + sal_uInt16 nLoopControlRuns = 0; + const sal_uInt16 nLoopControlMax = 15; + + do { + if ( mpLayAction ) + { + mpLayAction->FormatLayoutFly( &rFlyFrm ); + // --> consider, if the layout action + // has to be restarted due to a delete of a page frame. + if ( mpLayAction->IsAgain() ) + { + break; + } + // <-- + } + else + { + _FormatLayout( rFlyFrm ); + } + // --> #i34753# - prevent further positioning, if + // to-page|to-fly anchored Writer fly frame is already clipped. + if ( rFlyFrm.IsFlyLayFrm() && rFlyFrm.IsClipped() ) + { + static_cast<SwFlyLayFrm&>(rFlyFrm).SetNoMakePos( true ); + } + // <-- + // --> #i23129#, #i36347# - pass correct page frame + // to the object formatter + SwObjectFormatter::FormatObjsAtFrm( rFlyFrm, + *(rFlyFrm.FindPageFrm()), + mpLayAction ); + // <-- + if ( mpLayAction ) + { + mpLayAction->_FormatFlyCntnt( &rFlyFrm ); + // --> consider, if the layout action + // has to be restarted due to a delete of a page frame. + if ( mpLayAction->IsAgain() ) + { + break; + } + // <-- + } + else + { + _FormatObjCntnt( rFlyFrm ); + } + + if ( ++nLoopControlRuns >= nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl in SwObjectFormatter::_FormatObj: Stage 3!!!" ); +#endif + rFlyFrm.ValidateThisAndAllLowers( 2 ); + nLoopControlRuns = 0; + } + + // --> #i57917# + // stop formatting of anchored object, if restart of layout process is requested. + } while ( !rFlyFrm.IsValid() && + !_rAnchoredObj.RestartLayoutProcess() && + rFlyFrm.GetAnchorFrm() == &GetAnchorFrm() ); + // <-- + } + else if ( _rAnchoredObj.ISA(SwAnchoredDrawObject) ) + { + _rAnchoredObj.MakeObjPos(); + } +} + +/** invokes the intrinsic format method for all floating screen objects, + anchored at anchor frame on the given page frame + + #i28701# + #i26945# - for format of floating screen objects for + follow text frames, the 'master' text frame is passed to the method. + Thus, the objects, whose anchor character is inside the follow text + frame can be formatted. + + @author OD +*/ +bool SwObjectFormatter::_FormatObjsAtFrm( SwTxtFrm* _pMasterTxtFrm ) +{ + // --> #i26945# + SwFrm* pAnchorFrm( 0L ); + if ( GetAnchorFrm().IsTxtFrm() && + static_cast<SwTxtFrm&>(GetAnchorFrm()).IsFollow() && + _pMasterTxtFrm ) + { + pAnchorFrm = _pMasterTxtFrm; + } + else + { + pAnchorFrm = &GetAnchorFrm(); + } + // <-- + if ( !pAnchorFrm->GetDrawObjs() ) + { + // nothing to do, if no floating screen object is registered at the anchor frame. + return true; + } + + bool bSuccess( true ); + + sal_uInt32 i = 0; + for ( ; i < pAnchorFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pAnchorFrm->GetDrawObjs())[i]; + + // check, if object's anchor is on the given page frame or + // object is registered at the given page frame. + // --> #i26945# - check, if the anchor character of the + // anchored object is located in a follow text frame. If this anchor + // follow text frame differs from the given anchor frame, the given + // anchor frame is a 'master' text frame of the anchor follow text frame. + // If the anchor follow text frame is in the same body as its 'master' + // text frame, do not format the anchored object. + // E.g., this situation can occur during the table row splitting algorithm. + SwTxtFrm* pAnchorCharFrm = pAnchoredObj->FindAnchorCharFrm(); + const bool bAnchoredAtFollowInSameBodyAsMaster = + pAnchorCharFrm && pAnchorCharFrm->IsFollow() && + pAnchorCharFrm != pAnchoredObj->GetAnchorFrm() && + pAnchorCharFrm->FindBodyFrm() == + static_cast<SwTxtFrm*>(pAnchoredObj->AnchorFrm())->FindBodyFrm(); + if ( bAnchoredAtFollowInSameBodyAsMaster ) + { + continue; + } + // <-- + // --> #i33751#, #i34060# - method <GetPageFrmOfAnchor()> + // is replaced by method <FindPageFrmOfAnchor()>. It's return value + // have to be checked. + SwPageFrm* pPageFrmOfAnchor = pAnchoredObj->FindPageFrmOfAnchor(); + OSL_ENSURE( pPageFrmOfAnchor, + "<SwObjectFormatter::_FormatObjsAtFrm()> - missing page frame." ); + // --> #i26945# + if ( pPageFrmOfAnchor && pPageFrmOfAnchor == &mrPageFrm ) + // <-- + { + // if format of object fails, stop formatting and pass fail to + // calling method via the return value. + if ( !DoFormatObj( *pAnchoredObj ) ) + { + bSuccess = false; + break; + } + + // considering changes at <pAnchorFrm->GetDrawObjs()> during + // format of the object. + if ( !pAnchorFrm->GetDrawObjs() || + i > pAnchorFrm->GetDrawObjs()->Count() ) + { + break; + } + else + { + sal_uInt32 nActPosOfObj = + pAnchorFrm->GetDrawObjs()->ListPosOf( *pAnchoredObj ); + if ( nActPosOfObj == pAnchorFrm->GetDrawObjs()->Count() || + nActPosOfObj > i ) + { + --i; + } + else if ( nActPosOfObj < i ) + { + i = nActPosOfObj; + } + } + } + } // end of loop on <pAnchorFrm->.GetDrawObjs()> + + return bSuccess; +} + +/** accessor to collected anchored object + + #i28701# + + @author OD +*/ +SwAnchoredObject* SwObjectFormatter::GetCollectedObj( const sal_uInt32 _nIndex ) +{ + return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : 0L; +} + +/** accessor to 'anchor' page number of collected anchored object + + #i28701# + + @author OD +*/ +sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex ) +{ + return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0L; +} + +/** accessor to 'anchor' type of collected anchored object + + #i26945# + + @author OD +*/ +bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex ) +{ + return mpPgNumAndTypeOfAnchors + ? mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex) + : true; +} + +/** accessor to total number of collected anchored objects + + #i28701# + + @author OD +*/ +sal_uInt32 SwObjectFormatter::CountOfCollected() +{ + return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0L; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objectformatterlayfrm.cxx b/sw/source/core/layout/objectformatterlayfrm.cxx new file mode 100644 index 000000000000..80fc372eb2f6 --- /dev/null +++ b/sw/source/core/layout/objectformatterlayfrm.cxx @@ -0,0 +1,216 @@ +/* -*- 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 <objectformatterlayfrm.hxx> +#include <anchoredobject.hxx> +#include <sortedobjs.hxx> +#include <layfrm.hxx> +#include <pagefrm.hxx> + +// --> OD 2005-07-13 #124218# +#include <layact.hxx> +// <-- + +// ============================================================================= +// implementation of class <SwObjectFormatterLayFrm> +// ============================================================================= +SwObjectFormatterLayFrm::SwObjectFormatterLayFrm( SwLayoutFrm& _rAnchorLayFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ) + : SwObjectFormatter( _rPageFrm, _pLayAction ), + mrAnchorLayFrm( _rAnchorLayFrm ) +{ +} + +SwObjectFormatterLayFrm::~SwObjectFormatterLayFrm() +{ +} + +SwObjectFormatterLayFrm* SwObjectFormatterLayFrm::CreateObjFormatter( + SwLayoutFrm& _rAnchorLayFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ) +{ + if ( !_rAnchorLayFrm.IsPageFrm() && + !_rAnchorLayFrm.IsFlyFrm() ) + { + OSL_FAIL( "<SwObjectFormatterLayFrm::CreateObjFormatter(..)> - unexcepted type of anchor frame " ); + return 0L; + } + + SwObjectFormatterLayFrm* pObjFormatter = 0L; + + // create object formatter, if floating screen objects are registered at + // given anchor layout frame. + if ( _rAnchorLayFrm.GetDrawObjs() || + ( _rAnchorLayFrm.IsPageFrm() && + static_cast<SwPageFrm&>(_rAnchorLayFrm).GetSortedObjs() ) ) + { + pObjFormatter = + new SwObjectFormatterLayFrm( _rAnchorLayFrm, _rPageFrm, _pLayAction ); + } + + return pObjFormatter; +} + +SwFrm& SwObjectFormatterLayFrm::GetAnchorFrm() +{ + return mrAnchorLayFrm; +} + +// --> OD 2005-01-10 #i40147# - add parameter <_bCheckForMovedFwd>. +// Not relevant for objects anchored at layout frame. +bool SwObjectFormatterLayFrm::DoFormatObj( SwAnchoredObject& _rAnchoredObj, + const bool ) +// <-- +{ + _FormatObj( _rAnchoredObj ); + + // --> OD 2005-07-13 #124218# - consider that the layout action has to be + // restarted due to a deleted page frame. + return GetLayAction() ? !GetLayAction()->IsAgain() : true; + // <-- +} + +bool SwObjectFormatterLayFrm::DoFormatObjs() +{ + bool bSuccess( true ); + + bSuccess = _FormatObjsAtFrm(); + + if ( bSuccess && GetAnchorFrm().IsPageFrm() ) + { + // anchor layout frame is a page frame. + // Thus, format also all anchored objects, which are registered at + // this page frame, whose 'anchor' isn't on this page frame and whose + // anchor frame is valid. + bSuccess = _AdditionalFormatObjsOnPage(); + } + + return bSuccess; +} + +/** method to format all anchored objects, which are registered at + the page frame, whose 'anchor' isn't on this page frame and whose + anchor frame is valid. + + OD 2004-07-02 #i28701# + + @author +*/ +bool SwObjectFormatterLayFrm::_AdditionalFormatObjsOnPage() +{ + if ( !GetAnchorFrm().IsPageFrm() ) + { + OSL_FAIL( "<SwObjectFormatterLayFrm::_AdditionalFormatObjsOnPage()> - mis-usage of method, call only for anchor frames of type page frame" ); + return true; + } + + // --> OD 2005-07-13 #124218# - consider, if the layout action + // has to be restarted due to a delete of a page frame. + if ( GetLayAction() && GetLayAction()->IsAgain() ) + { + return false; + } + // <-- + + + SwPageFrm& rPageFrm = static_cast<SwPageFrm&>(GetAnchorFrm()); + + if ( !rPageFrm.GetSortedObjs() ) + { + // nothing to do, if no floating screen object is registered at the anchor frame. + return true; + } + + bool bSuccess( true ); + + sal_uInt32 i = 0; + for ( ; i < rPageFrm.GetSortedObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*rPageFrm.GetSortedObjs())[i]; + + // --> OD 2005-08-18 #i51941# - do not format object, which are anchored + // inside or at fly frame. + if ( pAnchoredObj->GetAnchorFrm()->FindFlyFrm() ) + { + continue; + } + // <-- + // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()> + // is replaced by method <FindPageFrmOfAnchor()>. It's return value + // have to be checked. + SwPageFrm* pPageFrmOfAnchor = pAnchoredObj->FindPageFrmOfAnchor(); + // --> OD 2004-10-08 #i26945# - check, if the page frame of the + // object's anchor frame isn't the given page frame + OSL_ENSURE( pPageFrmOfAnchor, + "<SwObjectFormatterLayFrm::_AdditionalFormatObjsOnPage()> - missing page frame" ); + if ( pPageFrmOfAnchor && + // --> OD 2004-10-22 #i35911# + pPageFrmOfAnchor->GetPhyPageNum() < rPageFrm.GetPhyPageNum() ) + // <-- + // <-- + { + // if format of object fails, stop formatting and pass fail to + // calling method via the return value. + if ( !DoFormatObj( *pAnchoredObj ) ) + { + bSuccess = false; + break; + } + + // considering changes at <GetAnchorFrm().GetDrawObjs()> during + // format of the object. + if ( !rPageFrm.GetSortedObjs() || + i > rPageFrm.GetSortedObjs()->Count() ) + { + break; + } + else + { + sal_uInt32 nActPosOfObj = + rPageFrm.GetSortedObjs()->ListPosOf( *pAnchoredObj ); + if ( nActPosOfObj == rPageFrm.GetSortedObjs()->Count() || + nActPosOfObj > i ) + { + --i; + } + else if ( nActPosOfObj < i ) + { + i = nActPosOfObj; + } + } + } + } // end of loop on <rPageFrm.GetSortedObjs()> + + return bSuccess; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objectformatterlayfrm.hxx b/sw/source/core/layout/objectformatterlayfrm.hxx new file mode 100644 index 000000000000..a2199030a61c --- /dev/null +++ b/sw/source/core/layout/objectformatterlayfrm.hxx @@ -0,0 +1,84 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _OBJECTFORMATTERLAYFRM_HXX +#define _OBJECTFORMATTERLAYFRM_HXX + +#include <objectformatter.hxx> + +class SwLayoutFrm; + +// ----------------------------------------------------------------------------- +// Format floating screen objects, which are anchored at a given anchor text frame +// and registered at the given page frame. +// ----------------------------------------------------------------------------- +class SwObjectFormatterLayFrm : public SwObjectFormatter +{ + private: + // anchor layout frame + SwLayoutFrm& mrAnchorLayFrm; + + SwObjectFormatterLayFrm( SwLayoutFrm& _rAnchorLayFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ); + + /** method to format all anchored objects, which are registered at + the page frame, whose 'anchor' isn't on this page frame and whose + anchor frame is valid. + + OD 2004-07-02 #i28701# + + @author OD + + @return boolean + indicates, if format was successfull + */ + bool _AdditionalFormatObjsOnPage(); + + protected: + + virtual SwFrm& GetAnchorFrm(); + + public: + virtual ~SwObjectFormatterLayFrm(); + + // --> OD 2005-01-10 #i40147# - add parameter <_bCheckForMovedFwd>. + // Not relevant for objects anchored at layout frame. + virtual bool DoFormatObj( SwAnchoredObject& _rAnchoredObj, + const bool _bCheckForMovedFwd = false ); + // <-- + virtual bool DoFormatObjs(); + + static SwObjectFormatterLayFrm* CreateObjFormatter( + SwLayoutFrm& _rAnchorLayFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx new file mode 100644 index 000000000000..a3593f5cc479 --- /dev/null +++ b/sw/source/core/layout/objectformattertxtfrm.cxx @@ -0,0 +1,814 @@ +/* -*- 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 <objectformattertxtfrm.hxx> +#include <anchoredobject.hxx> +#include <sortedobjs.hxx> +#include <flyfrms.hxx> +#include <txtfrm.hxx> +#include <pagefrm.hxx> +#include <rowfrm.hxx> +#include <layouter.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <fmtfollowtextflow.hxx> +#include <layact.hxx> + +using namespace ::com::sun::star; + +// ============================================================================= + +// little helper class to forbid follow formatting for the given text frame +class SwForbidFollowFormat +{ +private: + SwTxtFrm& mrTxtFrm; + const bool bOldFollowFormatAllowed; + +public: + SwForbidFollowFormat( SwTxtFrm& _rTxtFrm ) + : mrTxtFrm( _rTxtFrm ), + bOldFollowFormatAllowed( _rTxtFrm.FollowFormatAllowed() ) + { + mrTxtFrm.ForbidFollowFormat(); + } + + ~SwForbidFollowFormat() + { + if ( bOldFollowFormatAllowed ) + { + mrTxtFrm.AllowFollowFormat(); + } + } +}; + +// ============================================================================= +// implementation of class <SwObjectFormatterTxtFrm> +// ============================================================================= +SwObjectFormatterTxtFrm::SwObjectFormatterTxtFrm( SwTxtFrm& _rAnchorTxtFrm, + const SwPageFrm& _rPageFrm, + SwTxtFrm* _pMasterAnchorTxtFrm, + SwLayAction* _pLayAction ) + : SwObjectFormatter( _rPageFrm, _pLayAction, true ), + mrAnchorTxtFrm( _rAnchorTxtFrm ), + mpMasterAnchorTxtFrm( _pMasterAnchorTxtFrm ) +{ +} + +SwObjectFormatterTxtFrm::~SwObjectFormatterTxtFrm() +{ +} + +SwObjectFormatterTxtFrm* SwObjectFormatterTxtFrm::CreateObjFormatter( + SwTxtFrm& _rAnchorTxtFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ) +{ + SwObjectFormatterTxtFrm* pObjFormatter = 0L; + + // determine 'master' of <_rAnchorTxtFrm>, if anchor frame is a follow text frame. + SwTxtFrm* pMasterOfAnchorFrm = 0L; + if ( _rAnchorTxtFrm.IsFollow() ) + { + pMasterOfAnchorFrm = _rAnchorTxtFrm.FindMaster(); + while ( pMasterOfAnchorFrm && pMasterOfAnchorFrm->IsFollow() ) + { + pMasterOfAnchorFrm = pMasterOfAnchorFrm->FindMaster(); + } + } + + // create object formatter, if floating screen objects are registered + // at anchor frame (or at 'master' anchor frame) + if ( _rAnchorTxtFrm.GetDrawObjs() || + ( pMasterOfAnchorFrm && pMasterOfAnchorFrm->GetDrawObjs() ) ) + { + pObjFormatter = + new SwObjectFormatterTxtFrm( _rAnchorTxtFrm, _rPageFrm, + pMasterOfAnchorFrm, _pLayAction ); + } + + return pObjFormatter; +} + +SwFrm& SwObjectFormatterTxtFrm::GetAnchorFrm() +{ + return mrAnchorTxtFrm; +} + +// #i40147# - add parameter <_bCheckForMovedFwd>. +bool SwObjectFormatterTxtFrm::DoFormatObj( SwAnchoredObject& _rAnchoredObj, + const bool _bCheckForMovedFwd ) +{ + // check, if only as-character anchored object have to be formatted, and + // check the anchor type + if ( FormatOnlyAsCharAnchored() && + !(_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR) ) + { + return true; + } + + // consider, if the layout action has to be + // restarted due to a delete of a page frame. + if ( GetLayAction() && GetLayAction()->IsAgain() ) + { + return false; + } + + bool bSuccess( true ); + + if ( _rAnchoredObj.IsFormatPossible() ) + { + _rAnchoredObj.SetRestartLayoutProcess( false ); + + _FormatObj( _rAnchoredObj ); + // consider, if the layout action has to be + // restarted due to a delete of a page frame. + if ( GetLayAction() && GetLayAction()->IsAgain() ) + { + return false; + } + + // check, if layout process has to be restarted. + // if yes, perform needed invalidations. + + // no restart of layout process, + // if anchored object is anchored inside a Writer fly frame, + // its position is already locked, and it follows the text flow. + const bool bRestart = + _rAnchoredObj.RestartLayoutProcess() && + !( _rAnchoredObj.PositionLocked() && + _rAnchoredObj.GetAnchorFrm()->IsInFly() && + _rAnchoredObj.GetFrmFmt().GetFollowTextFlow().GetValue() ); + if ( bRestart ) + { + bSuccess = false; + _InvalidatePrevObjs( _rAnchoredObj ); + _InvalidateFollowObjs( _rAnchoredObj, true ); + } + + // format anchor text frame, if wrapping style influence of the object + // has to be considered and it's <NONE_SUCCESSIVE_POSITIONED> + // #i3317# - consider also anchored objects, whose + // wrapping style influence is temporarly considered. + // #i40147# - consider also anchored objects, for + // whose the check of a moved forward anchor frame is requested. + // revise decision made for i3317: + // anchored objects, whose wrapping style influence is temporarly considered, + // have to be considered in method <SwObjectFormatterTxtFrm::DoFormatObjs()> + if ( bSuccess && + _rAnchoredObj.ConsiderObjWrapInfluenceOnObjPos() && + ( _bCheckForMovedFwd || + _rAnchoredObj.GetFrmFmt().GetWrapInfluenceOnObjPos(). + // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE + GetWrapInfluenceOnObjPos( true ) == + // #i35017# - constant name has changed + text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) ) + { + // #i26945# - check conditions for move forward of + // anchor text frame + // determine, if anchor text frame has previous frame + const bool bDoesAnchorHadPrev = ( mrAnchorTxtFrm.GetIndPrev() != 0 ); + + // #i40141# - use new method - it also formats the + // section the anchor frame is in. + _FormatAnchorFrmForCheckMoveFwd(); + + // #i35911# + if ( _rAnchoredObj.HasClearedEnvironment() ) + { + _rAnchoredObj.SetClearedEnvironment( true ); + // #i44049# - consider, that anchor frame + // could already been marked to move forward. + SwPageFrm* pAnchorPageFrm( mrAnchorTxtFrm.FindPageFrm() ); + if ( pAnchorPageFrm != _rAnchoredObj.GetPageFrm() ) + { + bool bInsert( true ); + sal_uInt32 nToPageNum( 0L ); + const SwDoc& rDoc = *(GetPageFrm().GetFmt()->GetDoc()); + if ( SwLayouter::FrmMovedFwdByObjPos( + rDoc, mrAnchorTxtFrm, nToPageNum ) ) + { + if ( nToPageNum < pAnchorPageFrm->GetPhyPageNum() ) + SwLayouter::RemoveMovedFwdFrm( rDoc, mrAnchorTxtFrm ); + else + bInsert = false; + } + if ( bInsert ) + { + SwLayouter::InsertMovedFwdFrm( rDoc, mrAnchorTxtFrm, + pAnchorPageFrm->GetPhyPageNum() ); + mrAnchorTxtFrm.InvalidatePos(); + bSuccess = false; + _InvalidatePrevObjs( _rAnchoredObj ); + _InvalidateFollowObjs( _rAnchoredObj, true ); + } + else + { + OSL_FAIL( "<SwObjectFormatterTxtFrm::DoFormatObj(..)> - anchor frame not marked to move forward" ); + } + } + } + else if ( !mrAnchorTxtFrm.IsFollow() && bDoesAnchorHadPrev ) + { + // index of anchored object in collection of page numbers and + // anchor types + sal_uInt32 nIdx( CountOfCollected() ); + OSL_ENSURE( nIdx > 0, + "<SwObjectFormatterTxtFrm::DoFormatObj(..)> - anchored object not collected!?" ); + --nIdx; + + sal_uInt32 nToPageNum( 0L ); + // #i43913# + bool bDummy( false ); + // #i58182# - consider new method signature + if ( SwObjectFormatterTxtFrm::CheckMovedFwdCondition( *GetCollectedObj( nIdx ), + GetPgNumOfCollected( nIdx ), + IsCollectedAnchoredAtMaster( nIdx ), + nToPageNum, bDummy ) ) + { + // #i49987# - consider, that anchor frame + // could already been marked to move forward. + bool bInsert( true ); + sal_uInt32 nMovedFwdToPageNum( 0L ); + const SwDoc& rDoc = *(GetPageFrm().GetFmt()->GetDoc()); + if ( SwLayouter::FrmMovedFwdByObjPos( + rDoc, mrAnchorTxtFrm, nMovedFwdToPageNum ) ) + { + if ( nMovedFwdToPageNum < nToPageNum ) + SwLayouter::RemoveMovedFwdFrm( rDoc, mrAnchorTxtFrm ); + else + bInsert = false; + } + if ( bInsert ) + { + // Indicate that anchor text frame has to move forward and + // invalidate its position to force a re-format. + SwLayouter::InsertMovedFwdFrm( rDoc, mrAnchorTxtFrm, + nToPageNum ); + mrAnchorTxtFrm.InvalidatePos(); + + // Indicate restart of the layout process + bSuccess = false; + + // If needed, invalidate previous objects anchored at same anchor + // text frame. + _InvalidatePrevObjs( _rAnchoredObj ); + + // Invalidate object and following objects for the restart of the + // layout process + _InvalidateFollowObjs( _rAnchoredObj, true ); + } + else + { + OSL_FAIL( "<SwObjectFormatterTxtFrm::DoFormatObj(..)> - anchor frame not marked to move forward" ); + } + } + } + // i40155# - mark anchor frame not to wrap around + // objects under the condition, that its follow contains all its text. + else if ( !mrAnchorTxtFrm.IsFollow() && + mrAnchorTxtFrm.GetFollow() && + mrAnchorTxtFrm.GetFollow()->GetOfst() == 0 ) + { + SwLayouter::InsertFrmNotToWrap( + *(mrAnchorTxtFrm.FindPageFrm()->GetFmt()->GetDoc()), + mrAnchorTxtFrm ); + SwLayouter::RemoveMovedFwdFrm( + *(mrAnchorTxtFrm.FindPageFrm()->GetFmt()->GetDoc()), + mrAnchorTxtFrm ); + } + } + } + + return bSuccess; +} + +bool SwObjectFormatterTxtFrm::DoFormatObjs() +{ + if ( !mrAnchorTxtFrm.IsValid() ) + { + if ( GetLayAction() && + mrAnchorTxtFrm.FindPageFrm() != &GetPageFrm() ) + { + // notify layout action, thus is can restart the layout process on + // a previous page. + GetLayAction()->SetAgain(); + } + else + { + // the anchor text frame has to be valid, thus assert. + OSL_FAIL( "<SwObjectFormatterTxtFrm::DoFormatObjs()> called for invalidate anchor text frame." ); + } + + return false; + } + + bool bSuccess( true ); + + if ( mrAnchorTxtFrm.IsFollow() ) + { + // Only floating screen objects anchored as-character are directly + // registered at a follow text frame. The other floating screen objects + // are registered at the 'master' anchor text frame. + // Thus, format the other floating screen objects through the 'master' + // anchor text frame + OSL_ENSURE( mpMasterAnchorTxtFrm, + "SwObjectFormatterTxtFrm::DoFormatObjs() - missing 'master' anchor text frame" ); + bSuccess = _FormatObjsAtFrm( mpMasterAnchorTxtFrm ); + + if ( bSuccess ) + { + // format of as-character anchored floating screen objects - no failure + // excepted on the format of these objects. + bSuccess = _FormatObjsAtFrm(); + } + } + else + { + bSuccess = _FormatObjsAtFrm(); + } + + // consider anchored objects, whose wrapping style influence are temporarly + // considered. + if ( bSuccess && + ( ConsiderWrapOnObjPos() || + ( !mrAnchorTxtFrm.IsFollow() && + _AtLeastOneObjIsTmpConsiderWrapInfluence() ) ) ) + { + const bool bDoesAnchorHadPrev = ( mrAnchorTxtFrm.GetIndPrev() != 0 ); + + // Format anchor text frame after its objects are formatted. + // Note: The format of the anchor frame also formats the invalid + // previous frames of the anchor frame. The format of the previous + // frames is needed to get a correct result of format of the + // anchor frame for the following check for moved forward anchors + // #i40141# - use new method - it also formats the + // section the anchor frame is in. + _FormatAnchorFrmForCheckMoveFwd(); + + sal_uInt32 nToPageNum( 0L ); + // #i43913# + bool bInFollow( false ); + SwAnchoredObject* pObj = 0L; + if ( !mrAnchorTxtFrm.IsFollow() ) + { + pObj = _GetFirstObjWithMovedFwdAnchor( + // #i35017# - constant name has changed + text::WrapInfluenceOnPosition::ONCE_CONCURRENT, + nToPageNum, bInFollow ); + } + // #i35911# + if ( pObj && pObj->HasClearedEnvironment() ) + { + pObj->SetClearedEnvironment( true ); + // #i44049# - consider, that anchor frame + // could already been marked to move forward. + SwPageFrm* pAnchorPageFrm( mrAnchorTxtFrm.FindPageFrm() ); + // #i43913# - consider, that anchor frame + // is a follow or is in a follow row, which will move forward. + if ( pAnchorPageFrm != pObj->GetPageFrm() || + bInFollow ) + { + bool bInsert( true ); + sal_uInt32 nTmpToPageNum( 0L ); + const SwDoc& rDoc = *(GetPageFrm().GetFmt()->GetDoc()); + if ( SwLayouter::FrmMovedFwdByObjPos( + rDoc, mrAnchorTxtFrm, nTmpToPageNum ) ) + { + if ( nTmpToPageNum < pAnchorPageFrm->GetPhyPageNum() ) + SwLayouter::RemoveMovedFwdFrm( rDoc, mrAnchorTxtFrm ); + else + bInsert = false; + } + if ( bInsert ) + { + SwLayouter::InsertMovedFwdFrm( rDoc, mrAnchorTxtFrm, + pAnchorPageFrm->GetPhyPageNum() ); + mrAnchorTxtFrm.InvalidatePos(); + bSuccess = false; + _InvalidatePrevObjs( *pObj ); + _InvalidateFollowObjs( *pObj, true ); + } + else + { + OSL_FAIL( "<SwObjectFormatterTxtFrm::DoFormatObjs(..)> - anchor frame not marked to move forward" ); + } + } + } + else if ( pObj && bDoesAnchorHadPrev ) + { + // Object found, whose anchor is moved forward + + // #i49987# - consider, that anchor frame + // could already been marked to move forward. + bool bInsert( true ); + sal_uInt32 nMovedFwdToPageNum( 0L ); + const SwDoc& rDoc = *(GetPageFrm().GetFmt()->GetDoc()); + if ( SwLayouter::FrmMovedFwdByObjPos( + rDoc, mrAnchorTxtFrm, nMovedFwdToPageNum ) ) + { + if ( nMovedFwdToPageNum < nToPageNum ) + SwLayouter::RemoveMovedFwdFrm( rDoc, mrAnchorTxtFrm ); + else + bInsert = false; + } + if ( bInsert ) + { + // Indicate that anchor text frame has to move forward and + // invalidate its position to force a re-format. + SwLayouter::InsertMovedFwdFrm( rDoc, mrAnchorTxtFrm, nToPageNum ); + mrAnchorTxtFrm.InvalidatePos(); + + // Indicate restart of the layout process + bSuccess = false; + + // If needed, invalidate previous objects anchored at same anchor + // text frame. + _InvalidatePrevObjs( *pObj ); + + // Invalidate object and following objects for the restart of the + // layout process + _InvalidateFollowObjs( *pObj, true ); + } + else + { + OSL_FAIL( "<SwObjectFormatterTxtFrm::DoFormatObjs(..)> - anchor frame not marked to move forward" ); + } + } + // #i40155# - mark anchor frame not to wrap around + // objects under the condition, that its follow contains all its text. + else if ( !mrAnchorTxtFrm.IsFollow() && + mrAnchorTxtFrm.GetFollow() && + mrAnchorTxtFrm.GetFollow()->GetOfst() == 0 ) + { + SwLayouter::InsertFrmNotToWrap( + *(mrAnchorTxtFrm.FindPageFrm()->GetFmt()->GetDoc()), + mrAnchorTxtFrm ); + SwLayouter::RemoveMovedFwdFrm( + *(mrAnchorTxtFrm.FindPageFrm()->GetFmt()->GetDoc()), + mrAnchorTxtFrm ); + } + } + + return bSuccess; +} + +void SwObjectFormatterTxtFrm::_InvalidatePrevObjs( SwAnchoredObject& _rAnchoredObj ) +{ + // invalidate all previous objects, whose wrapping influence on the object + // positioning is <NONE_CONCURRENT_POSIITIONED>. + // Note: list of objects at anchor frame is sorted by this property. + if ( _rAnchoredObj.GetFrmFmt().GetWrapInfluenceOnObjPos(). + // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE + GetWrapInfluenceOnObjPos( true ) == + // #i35017# - constant name has changed + text::WrapInfluenceOnPosition::ONCE_CONCURRENT ) + { + const SwSortedObjs* pObjs = GetAnchorFrm().GetDrawObjs(); + if ( pObjs ) + { + // determine start index + sal_Int32 i = pObjs->ListPosOf( _rAnchoredObj ) - 1; + for ( ; i >= 0; --i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj->GetFrmFmt().GetWrapInfluenceOnObjPos(). + // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE + GetWrapInfluenceOnObjPos( true ) == + // #i35017# - constant name has changed + text::WrapInfluenceOnPosition::ONCE_CONCURRENT ) + { + pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence( true ); + } + } + } + } +} + +void SwObjectFormatterTxtFrm::_InvalidateFollowObjs( SwAnchoredObject& _rAnchoredObj, + const bool _bInclObj ) +{ + if ( _bInclObj ) + { + _rAnchoredObj.InvalidateObjPosForConsiderWrapInfluence( true ); + } + + const SwSortedObjs* pObjs = GetPageFrm().GetSortedObjs(); + if ( pObjs ) + { + // determine start index + sal_uInt32 i = pObjs->ListPosOf( _rAnchoredObj ) + 1; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence( true ); + } + } +} + +SwAnchoredObject* SwObjectFormatterTxtFrm::_GetFirstObjWithMovedFwdAnchor( + const sal_Int16 _nWrapInfluenceOnPosition, + sal_uInt32& _noToPageNum, + bool& _boInFollow ) +{ + // #i35017# - constant names have changed + OSL_ENSURE( _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE || + _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_CONCURRENT, + "<SwObjectFormatterTxtFrm::_GetFirstObjWithMovedFwdAnchor(..)> - invalid value for parameter <_nWrapInfluenceOnPosition>" ); + + SwAnchoredObject* pRetAnchoredObj = 0L; + + sal_uInt32 i = 0L; + for ( ; i < CountOfCollected(); ++i ) + { + SwAnchoredObject* pAnchoredObj = GetCollectedObj(i); + if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() && + pAnchoredObj->GetFrmFmt().GetWrapInfluenceOnObjPos(). + // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE + GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition ) + { + // #i26945# - use new method <_CheckMovedFwdCondition(..)> + // #i43913# + // #i58182# - consider new method signature + if ( SwObjectFormatterTxtFrm::CheckMovedFwdCondition( *GetCollectedObj( i ), + GetPgNumOfCollected( i ), + IsCollectedAnchoredAtMaster( i ), + _noToPageNum, _boInFollow ) ) + { + pRetAnchoredObj = pAnchoredObj; + break; + } + } + } + + return pRetAnchoredObj; +} + +// #i58182# +// - replace private method by corresponding static public method +bool SwObjectFormatterTxtFrm::CheckMovedFwdCondition( + SwAnchoredObject& _rAnchoredObj, + const sal_uInt32 _nFromPageNum, + const bool _bAnchoredAtMasterBeforeFormatAnchor, + sal_uInt32& _noToPageNum, + bool& _boInFollow ) +{ + bool bAnchorIsMovedForward( false ); + + SwPageFrm* pPageFrmOfAnchor = _rAnchoredObj.FindPageFrmOfAnchor(); + if ( pPageFrmOfAnchor ) + { + const sal_uInt32 nPageNum = pPageFrmOfAnchor->GetPhyPageNum(); + if ( nPageNum > _nFromPageNum ) + { + _noToPageNum = nPageNum; + // Handling of special case: + // If anchor frame is move forward into a follow flow row, + // <_noToPageNum> is set to <_nFromPageNum + 1>, because it is + // possible that the anchor page frame isn't valid, because the + // page distance between master row and follow flow row is greater + // than 1. + if ( _noToPageNum > (_nFromPageNum + 1) ) + { + SwFrm* pAnchorFrm = _rAnchoredObj.GetAnchorFrmContainingAnchPos(); + if ( pAnchorFrm->IsInTab() && + pAnchorFrm->IsInFollowFlowRow() ) + { + _noToPageNum = _nFromPageNum + 1; + } + } + bAnchorIsMovedForward = true; + } + } + // #i26945# - check, if an at-paragraph|at-character + // anchored object is now anchored at a follow text frame, which will be + // on the next page. Also check, if an at-character anchored object + // is now anchored at a text frame, which is in a follow flow row, + // which will be on the next page. + if ( !bAnchorIsMovedForward && + _bAnchoredAtMasterBeforeFormatAnchor && + ((_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR) || + (_rAnchoredObj.GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_PARA))) + { + SwFrm* pAnchorFrm = _rAnchoredObj.GetAnchorFrmContainingAnchPos(); + OSL_ENSURE( pAnchorFrm->IsTxtFrm(), + "<SwObjectFormatterTxtFrm::CheckMovedFwdCondition(..) - wrong type of anchor frame>" ); + SwTxtFrm* pAnchorTxtFrm = static_cast<SwTxtFrm*>(pAnchorFrm); + bool bCheck( false ); + if ( pAnchorTxtFrm->IsFollow() ) + { + bCheck = true; + } + else if( pAnchorTxtFrm->IsInTab() ) + { + const SwRowFrm* pMasterRow = pAnchorTxtFrm->IsInFollowFlowRow(); + if ( pMasterRow && + pMasterRow->FindPageFrm() == pPageFrmOfAnchor ) + { + bCheck = true; + } + } + if ( bCheck ) + { + // check, if found text frame will be on the next page + // by checking, if it's in a column, which has no next. + SwFrm* pColFrm = pAnchorTxtFrm->FindColFrm(); + while ( pColFrm && !pColFrm->GetNext() ) + { + pColFrm = pColFrm->FindColFrm(); + } + if ( !pColFrm || !pColFrm->GetNext() ) + { + _noToPageNum = _nFromPageNum + 1; + bAnchorIsMovedForward = true; + // #i43913# + _boInFollow = true; + } + } + } + + return bAnchorIsMovedForward; +} + +// #i40140# - helper method to format layout frames used by +// method <SwObjectFormatterTxtFrm::_FormatAnchorFrmForCheckMoveFwd()> +// #i44049# - format till a certain lower frame, if provided. +void lcl_FormatCntntOfLayoutFrm( SwLayoutFrm* pLayFrm, + SwFrm* pLastLowerFrm = 0L ) +{ + SwFrm* pLowerFrm = pLayFrm->GetLower(); + while ( pLowerFrm ) + { + // #i44049# + if ( pLastLowerFrm && pLowerFrm == pLastLowerFrm ) + { + break; + } + if ( pLowerFrm->IsLayoutFrm() ) + lcl_FormatCntntOfLayoutFrm( static_cast<SwLayoutFrm*>(pLowerFrm), + pLastLowerFrm ); + else + pLowerFrm->Calc(); + + pLowerFrm = pLowerFrm->GetNext(); + } +} + +/** method to format given anchor text frame and its previous frames + + #i56300# + Usage: Needed to check, if the anchor text frame is moved forward + due to the positioning and wrapping of its anchored objects, and + to format the frames, which have become invalid due to the anchored + object formatting in the iterative object positioning algorithm +*/ +void SwObjectFormatterTxtFrm::FormatAnchorFrmAndItsPrevs( SwTxtFrm& _rAnchorTxtFrm ) +{ + // #i47014# - no format of section and previous columns + // for follow text frames. + if ( !_rAnchorTxtFrm.IsFollow() ) + { + // if anchor frame is directly inside a section, format this section and + // its previous frames. + // Note: It's a very simple format without formatting objects. + if ( _rAnchorTxtFrm.IsInSct() ) + { + SwFrm* pSectFrm = _rAnchorTxtFrm.GetUpper(); + while ( pSectFrm ) + { + if ( pSectFrm->IsSctFrm() || pSectFrm->IsCellFrm() ) + { + break; + } + pSectFrm = pSectFrm->GetUpper(); + } + if ( pSectFrm && pSectFrm->IsSctFrm() ) + { + // #i44049# + _rAnchorTxtFrm.LockJoin(); + SwFrm* pFrm = pSectFrm->GetUpper()->GetLower(); + // #i49605# - section frame could move forward + // by the format of its previous frame. + // Thus, check for valid <pFrm>. + while ( pFrm && pFrm != pSectFrm ) + { + if ( pFrm->IsLayoutFrm() ) + lcl_FormatCntntOfLayoutFrm( static_cast<SwLayoutFrm*>(pFrm) ); + else + pFrm->Calc(); + + pFrm = pFrm->GetNext(); + } + lcl_FormatCntntOfLayoutFrm( static_cast<SwLayoutFrm*>(pSectFrm), + &_rAnchorTxtFrm ); + // #i44049# + _rAnchorTxtFrm.UnlockJoin(); + } + } + + // #i40140# - if anchor frame is inside a column, + // format the content of the previous columns. + // Note: It's a very simple format without formatting objects. + SwFrm* pColFrmOfAnchor = _rAnchorTxtFrm.FindColFrm(); + if ( pColFrmOfAnchor ) + { + // #i44049# + _rAnchorTxtFrm.LockJoin(); + SwFrm* pColFrm = pColFrmOfAnchor->GetUpper()->GetLower(); + while ( pColFrm != pColFrmOfAnchor ) + { + SwFrm* pFrm = pColFrm->GetLower(); + while ( pFrm ) + { + if ( pFrm->IsLayoutFrm() ) + lcl_FormatCntntOfLayoutFrm( static_cast<SwLayoutFrm*>(pFrm) ); + else + pFrm->Calc(); + + pFrm = pFrm->GetNext(); + } + + pColFrm = pColFrm->GetNext(); + } + // #i44049# + _rAnchorTxtFrm.UnlockJoin(); + } + } + + // format anchor frame - format of its follow not needed + // #i43255# - forbid follow format, only if anchor text + // frame is in table + if ( _rAnchorTxtFrm.IsInTab() ) + { + SwForbidFollowFormat aForbidFollowFormat( _rAnchorTxtFrm ); + _rAnchorTxtFrm.Calc(); + } + else + { + _rAnchorTxtFrm.Calc(); + } +} + +/** method to format the anchor frame for checking of the move forward condition + + #i40141# +*/ +void SwObjectFormatterTxtFrm::_FormatAnchorFrmForCheckMoveFwd() +{ + SwObjectFormatterTxtFrm::FormatAnchorFrmAndItsPrevs( mrAnchorTxtFrm ); +} + +/** method to determine if at least one anchored object has state + <temporarly consider wrapping style influence> set. +*/ +bool SwObjectFormatterTxtFrm::_AtLeastOneObjIsTmpConsiderWrapInfluence() +{ + bool bRet( false ); + + const SwSortedObjs* pObjs = GetAnchorFrm().GetDrawObjs(); + if ( pObjs && pObjs->Count() > 1 ) + { + sal_uInt32 i = 0; + for ( ; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() ) + { + bRet = true; + break; + } + } + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objectformattertxtfrm.hxx b/sw/source/core/layout/objectformattertxtfrm.hxx new file mode 100644 index 000000000000..3d526f9dd214 --- /dev/null +++ b/sw/source/core/layout/objectformattertxtfrm.hxx @@ -0,0 +1,201 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _OBJECTFORMATTERTXTFRM_HXX +#define _OBJECTFORMATTERTXTFRM_HXX + +#include <objectformatter.hxx> +#include <sal/types.h> + +class SwTxtFrm; + +// ----------------------------------------------------------------------------- +// #i28701# +// Format floating screen objects, which are anchored at a given anchor text frame +// and registered at the given page frame. +// ----------------------------------------------------------------------------- +class SwObjectFormatterTxtFrm : public SwObjectFormatter +{ + private: + // anchor text frame + SwTxtFrm& mrAnchorTxtFrm; + + // 'master' anchor text frame + SwTxtFrm* mpMasterAnchorTxtFrm; + + SwObjectFormatterTxtFrm( SwTxtFrm& _rAnchorTxtFrm, + const SwPageFrm& _rPageFrm, + SwTxtFrm* _pMasterAnchorTxtFrm, + SwLayAction* _pLayAction ); + + /** method to invalidate objects, anchored previous to given object at + the anchor text frame + + @param _rAnchoredObj + reference to anchored object - objects, anchored previous to + this one will be invalidated. + */ + void _InvalidatePrevObjs( SwAnchoredObject& _rAnchoredObj ); + + /** method to invalidate objects, anchored after the given object at + the page frame + + @param _rAnchoredObj + reference to anchored object - objects, anchored after this one will + be invalidated. + + @param _bInclObj + boolean indicates, if given anchored object <_rAnchoredObj> also have + to be invalidated. + */ + void _InvalidateFollowObjs( SwAnchoredObject& _rAnchoredObj, + const bool _bInclObj ); + + /** method to determine first anchored object, whose 'anchor is moved + forward'. + + 'anchor (of an object) is moved forward', if the anchor frame + respectively the anchor character of the object isn't on the + proposed page frame. Instead its on a following page + + #i26945# - For at-character anchored objects, + it has also to be checked, if the anchor character is in a follow + text frame, which would move to the next page. + + #i43913# - add output parameter <_boInFollow> + + @param _nWrapInfluenceOnPosition + input parameter - only object with this given wrapping style + influence are investigated. + + @param _nFromPageNum + input parameter - number of page frame, the 'anchor' should be + + @param _noToPageNum + output parameter - number of page frame, the 'anchor' of the returned + anchored object is. + + @param _boInFollow + output parameter - boolean, indicating that anchor text frame is + currently on the same page, but it's a follow of in a follow row, + which will move forward. value only relevant, if method returns + an anchored object + + @return SwAnchoredObject* + anchored object with a 'moved forward anchor'. If NULL, no such + anchored object is found. + */ + SwAnchoredObject* _GetFirstObjWithMovedFwdAnchor( + const sal_Int16 _nWrapInfluenceOnPosition, + sal_uInt32& _noToPageNum, + bool& _boInFollow ); + + /** method to format the anchor frame for checking of the move forward condition + + #i40141# + */ + void _FormatAnchorFrmForCheckMoveFwd(); + + /** method to determine if at least one anchored object has state + <temporarly consider wrapping style influence> set. + */ + bool _AtLeastOneObjIsTmpConsiderWrapInfluence(); + + protected: + + virtual SwFrm& GetAnchorFrm(); + + public: + virtual ~SwObjectFormatterTxtFrm(); + + // #i40147# - add parameter <_bCheckForMovedFwd>. + virtual bool DoFormatObj( SwAnchoredObject& _rAnchoredObj, + const bool _bCheckForMovedFwd = false ); + virtual bool DoFormatObjs(); + + /** method to create an instance of <SwObjectFormatterTxtFrm> is + necessary. + */ + static SwObjectFormatterTxtFrm* CreateObjFormatter( + SwTxtFrm& _rAnchorTxtFrm, + const SwPageFrm& _rPageFrm, + SwLayAction* _pLayAction ); + + /** method to format given anchor text frame and its previous frames + + #i56300# + Usage: Needed to check, if the anchor text frame is moved forward + due to the positioning and wrapping of its anchored objects, and + to format the frames, which have become invalid due to the anchored + object formatting in the iterative object positioning algorithm + + @param _rAnchorTxtFrm + input parameter - reference to anchor text frame, which has to be + formatted including its previous frames of the page. + */ + static void FormatAnchorFrmAndItsPrevs( SwTxtFrm& _rAnchorTxtFrm ); + + /** method to check the conditions, if 'anchor is moved forward' + + #i26945# + #i43913# - add output parameter <_boInFollow> + #i58182# - replace method by a corresponding static + method, because it's needed for the iterative positioning algorithm. + + @param _rAnchoredObj + input parameter - anchored object, for which the condition has to checked. + + @param _nFromPageNum + input parameter - number of the page, on which the check is performed + + @param _bAnchoredAtMasterBeforeFormatAnchor + input parameter - boolean indicating, that the given anchored object + was anchored at the master frame before the anchor frame has been + formatted. + + @param _noToPageNum + output parameter - number of page frame, the 'anchor' of the returned + anchored object is. + + @param _boInFollow + output parameter - boolean, indicating that anchor text frame is + currently on the same page, but it's a follow of in a follow row, + which will move forward. value only relevant, if method return <true>. + + @return boolean + indicating, if 'anchor is moved forward' + */ + static bool CheckMovedFwdCondition( SwAnchoredObject& _rAnchoredObj, + const sal_uInt32 _nFromPageNum, + const bool _bAnchoredAtMasterBeforeFormatAnchor, + sal_uInt32& _noToPageNum, + bool& _boInFollow ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objstmpconsiderwrapinfl.cxx b/sw/source/core/layout/objstmpconsiderwrapinfl.cxx new file mode 100644 index 000000000000..1c32c9c75f26 --- /dev/null +++ b/sw/source/core/layout/objstmpconsiderwrapinfl.cxx @@ -0,0 +1,76 @@ +/* -*- 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 <objstmpconsiderwrapinfl.hxx> +#include <anchoredobject.hxx> + +SwObjsMarkedAsTmpConsiderWrapInfluence::SwObjsMarkedAsTmpConsiderWrapInfluence() +{ +} + +SwObjsMarkedAsTmpConsiderWrapInfluence::~SwObjsMarkedAsTmpConsiderWrapInfluence() +{ + Clear(); +} + +void SwObjsMarkedAsTmpConsiderWrapInfluence::Insert( SwAnchoredObject& _rAnchoredObj ) +{ + + bool bAlreadyInserted( false ); + std::vector< SwAnchoredObject* >::const_iterator aIter = maObjsTmpConsiderWrapInfl.begin(); + for ( ; aIter != maObjsTmpConsiderWrapInfl.end(); ++aIter ) + { + const SwAnchoredObject* pAnchoredObj = *(aIter); + if ( pAnchoredObj == &_rAnchoredObj ) + { + bAlreadyInserted = true; + break; + } + } + + if ( !bAlreadyInserted ) + { + maObjsTmpConsiderWrapInfl.push_back( &_rAnchoredObj ); + } +} + +void SwObjsMarkedAsTmpConsiderWrapInfluence::Clear() +{ + while ( maObjsTmpConsiderWrapInfl.size() ) + { + SwAnchoredObject* pAnchoredObj = maObjsTmpConsiderWrapInfl.back(); + pAnchoredObj->SetTmpConsiderWrapInfluence( false ); + pAnchoredObj->SetClearedEnvironment( false ); + + maObjsTmpConsiderWrapInfl.pop_back(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/objstmpconsiderwrapinfl.hxx b/sw/source/core/layout/objstmpconsiderwrapinfl.hxx new file mode 100644 index 000000000000..f5fd89b3b435 --- /dev/null +++ b/sw/source/core/layout/objstmpconsiderwrapinfl.hxx @@ -0,0 +1,50 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _OBJSTMPCONSIDERWRAPINFL_HXX +#define _OBJSTMPCONSIDERWRAPINFL_HXX + +#include <vector> + +class SwAnchoredObject; + +class SwObjsMarkedAsTmpConsiderWrapInfluence +{ + private: + std::vector< SwAnchoredObject* > maObjsTmpConsiderWrapInfl; + + public: + SwObjsMarkedAsTmpConsiderWrapInfluence(); + ~SwObjsMarkedAsTmpConsiderWrapInfluence(); + + void Insert( SwAnchoredObject& _rAnchoredObj ); + void Clear(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx new file mode 100644 index 000000000000..aa7aa23e02c0 --- /dev/null +++ b/sw/source/core/layout/pagechg.cxx @@ -0,0 +1,2454 @@ +/* -*- 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 <com/sun/star/embed/EmbedStates.hpp> +#include <ndole.hxx> +#include <docary.hxx> +#include <svl/itemiter.hxx> +#include <fmtfsize.hxx> +#include <fmthdft.hxx> +#include <fmtclds.hxx> +#include <fmtanchr.hxx> +#include <fmtpdsc.hxx> +#include <fmtfordr.hxx> +#include <fmtfld.hxx> +#include <fmtornt.hxx> +#include <ftninfo.hxx> +#include <tgrditem.hxx> +#include <viewopt.hxx> +#include <docsh.hxx> + +#include "viewimp.hxx" +#include "viewopt.hxx" +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "flyfrm.hxx" +#include "doc.hxx" +#include "fesh.hxx" +#include "dview.hxx" +#include "dflyobj.hxx" +#include "dcontact.hxx" +#include "frmtool.hxx" +#include "fldbas.hxx" +#include "hints.hxx" +#include "swtable.hxx" + +#include "ftnidx.hxx" +#include "bodyfrm.hxx" +#include "ftnfrm.hxx" +#include "tabfrm.hxx" +#include "txtfrm.hxx" +#include "layact.hxx" +#include "flyfrms.hxx" +#include "htmltbl.hxx" +#include "pagedesc.hxx" +#include "poolfmt.hxx" +#include <editeng/frmdiritem.hxx> +#include <swfntcch.hxx> // SwFontAccess +#include <sortedobjs.hxx> +#include <switerator.hxx> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwBodyFrm::SwBodyFrm() +|* +|*************************************************************************/ +SwBodyFrm::SwBodyFrm( SwFrmFmt *pFmt, SwFrm* pSib ): + SwLayoutFrm( pFmt, pSib ) +{ + nType = FRMC_BODY; +} + +/************************************************************************* +|* +|* SwBodyFrm::Format() +|* +|*************************************************************************/ +void SwBodyFrm::Format( const SwBorderAttrs * ) +{ + //Formatieren des Body ist zu einfach, deshalb bekommt er ein eigenes + //Format; Umrandungen und dergl. sind hier nicht zu beruecksichtigen. + //Breite ist die der PrtArea des Uppers, Hoehe ist die Hoehe der PrtArea + //des Uppers abzueglich der Nachbarn (Wird eigentlich eingestellt aber + //Vorsicht ist die Mutter der Robustheit). + //Die PrtArea ist stets so gross wie der Frm itself. + + if ( !bValidSize ) + { + SwTwips nHeight = GetUpper()->Prt().Height(); + SwTwips nWidth = GetUpper()->Prt().Width(); + const SwFrm *pFrm = GetUpper()->Lower(); + do + { + if ( pFrm != this ) + { + if( pFrm->IsVertical() ) + nWidth -= pFrm->Frm().Width(); + else + nHeight -= pFrm->Frm().Height(); + } + pFrm = pFrm->GetNext(); + } while ( pFrm ); + if ( nHeight < 0 ) + nHeight = 0; + Frm().Height( nHeight ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !IsReverse() && nWidth != Frm().Width() ) + Frm().Pos().X() += Frm().Width() - nWidth; + Frm().Width( nWidth ); + } + + sal_Bool bNoGrid = sal_True; + if( GetUpper()->IsPageFrm() && ((SwPageFrm*)GetUpper())->HasGrid() ) + { + GETGRID( ((SwPageFrm*)GetUpper()) ) + if( pGrid ) + { + bNoGrid = sal_False; + long nSum = pGrid->GetBaseHeight() + pGrid->GetRubyHeight(); + SWRECTFN( this ) + long nSize = (Frm().*fnRect->fnGetWidth)(); + long nBorder = 0; + if( GRID_LINES_CHARS == pGrid->GetGridType() ) + { + //for textgrid refactor + SwDoc *pDoc = GetFmt()->GetDoc(); + nBorder = nSize % (GETGRIDWIDTH(pGrid, pDoc)); + nSize -= nBorder; + nBorder /= 2; + } + (Prt().*fnRect->fnSetPosX)( nBorder ); + (Prt().*fnRect->fnSetWidth)( nSize ); + + // Height of body frame: + nBorder = (Frm().*fnRect->fnGetHeight)(); + + // Number of possible lines in area of body frame: + long nNumberOfLines = nBorder / nSum; + if( nNumberOfLines > pGrid->GetLines() ) + nNumberOfLines = pGrid->GetLines(); + + // Space required for nNumberOfLines lines: + nSize = nNumberOfLines * nSum; + nBorder -= nSize; + nBorder /= 2; + + // #i21774# Footnotes and centering the grid does not work together: + const bool bAdjust = 0 == ((SwPageFrm*)GetUpper())->GetFmt()->GetDoc()-> + GetFtnIdxs().Count(); + + (Prt().*fnRect->fnSetPosY)( bAdjust ? nBorder : 0 ); + (Prt().*fnRect->fnSetHeight)( nSize ); + } + } + if( bNoGrid ) + { + Prt().Pos().X() = Prt().Pos().Y() = 0; + Prt().Height( Frm().Height() ); + Prt().Width( Frm().Width() ); + } + bValidSize = bValidPrtArea = sal_True; +} + +void SwBodyFrm::Paint( const SwRect& rRect, const SwPrintData* ) const +{ +#if OSL_DEBUG_LAYOUT > 1 + // Paint a red border around the SwBodyFrm in debug mode + ViewShell *pSh = GetShell(); + OutputDevice* pOut = pSh->GetOut(); + pOut->Push(); + pOut->SetLineColor(Color(255, 0, 0)); + pOut->SetFillColor(COL_TRANSPARENT); + SwRect aRect = Frm(); + pOut->DrawRect(aRect.SVRect()); + pOut->Pop(); +#endif + SwLayoutFrm::Paint(rRect); +} + +/************************************************************************* +|* +|* SwPageFrm::SwPageFrm(), ~SwPageFrm() +|* +|*************************************************************************/ +SwPageFrm::SwPageFrm( SwFrmFmt *pFmt, SwFrm* pSib, SwPageDesc *pPgDsc ) : + SwFtnBossFrm( pFmt, pSib ), + pSortedObjs( 0 ), + pDesc( pPgDsc ), + nPhyPageNum( 0 ), + // OD 2004-05-17 #i28701# + mbLayoutInProgress( false ) +{ + SetDerivedVert( sal_False ); + SetDerivedR2L( sal_False ); + if( pDesc ) + { + bHasGrid = sal_True; + GETGRID( this ) + if( !pGrid ) + bHasGrid = sal_False; + } + else + bHasGrid = sal_False; + SetMaxFtnHeight( pPgDsc->GetFtnInfo().GetHeight() ? + pPgDsc->GetFtnInfo().GetHeight() : LONG_MAX ), + nType = FRMC_PAGE; + bInvalidLayout = bInvalidCntnt = bInvalidSpelling = bInvalidSmartTags = bInvalidAutoCmplWrds = bInvalidWordCount = sal_True; + bInvalidFlyLayout = bInvalidFlyCntnt = bInvalidFlyInCnt = bFtnPage = bEndNotePage = sal_False; + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + if ( bBrowseMode ) + { + Frm().Height( 0 ); + long nWidth = pSh->VisArea().Width(); + if ( !nWidth ) + nWidth = 5000L; //aendert sich sowieso + Frm().Width ( nWidth ); + } + else + Frm().SSize( pFmt->GetFrmSize().GetSize() ); + + //Body-Bereich erzeugen und einsetzen, aber nur wenn ich nicht gerade + //eine Leerseite bin. + SwDoc *pDoc = pFmt->GetDoc(); + if ( sal_False == (bEmptyPage = pFmt == pDoc->GetEmptyPageFmt()) ) + { + bEmptyPage = sal_False; + Calc(); //Damit die PrtArea stimmt. + SwBodyFrm *pBodyFrm = new SwBodyFrm( pDoc->GetDfltFrmFmt(), this ); + pBodyFrm->ChgSize( Prt().SSize() ); + pBodyFrm->Paste( this ); + pBodyFrm->Calc(); //Damit die Spalten korrekt + //eingesetzt werden koennen. + pBodyFrm->InvalidatePos(); + + if ( bBrowseMode ) + _InvalidateSize(); //Alles nur gelogen + + //Header/Footer einsetzen, nur rufen wenn aktiv. + if ( pFmt->GetHeader().IsActive() ) + PrepareHeader(); + if ( pFmt->GetFooter().IsActive() ) + PrepareFooter(); + + const SwFmtCol &rCol = pFmt->GetCol(); + if ( rCol.GetNumCols() > 1 ) + { + const SwFmtCol aOld; //ChgColumns() verlaesst sich darauf, dass ein + //Old-Wert hereingereicht wird. + pBodyFrm->ChgColumns( aOld, rCol ); + } + } +} + +SwPageFrm::~SwPageFrm() +{ + //FlyContainer entleeren, delete der Flys uebernimmt der Anchor + //(Basisklasse SwFrm) + if ( pSortedObjs ) + { + //Objekte koennen (warum auch immer) auch an Seiten verankert sein, + //die vor Ihren Ankern stehen. Dann wuerde auf bereits freigegebenen + //Speicher zugegriffen. + for ( sal_uInt16 i = 0; i < pSortedObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pSortedObjs)[i]; + pAnchoredObj->SetPageFrm( 0L ); + } + delete pSortedObjs; + pSortedObjs = 0; //Auf 0 setzen, sonst rauchts beim Abmdelden von Flys! + } + + //Damit der Zugriff auf zerstoerte Seiten verhindert werden kann. + if ( !IsEmptyPage() ) //#59184# sollte fuer Leerseiten unnoetig sein. + { + SwDoc *pDoc = GetFmt()->GetDoc(); + if( pDoc && !pDoc->IsInDtor() ) + { + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( pSh ) + { + SwViewImp *pImp = pSh->Imp(); + pImp->SetFirstVisPageInvalid(); + if ( pImp->IsAction() ) + pImp->GetLayAction().SetAgain(); + // OD 12.02.2003 #i9719#, #105645# - retouche area of page + // including border and shadow area. + const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT); + SwRect aRetoucheRect; + SwPageFrm::GetBorderAndShadowBoundRect( Frm(), pSh, aRetoucheRect, IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar ); + pSh->AddPaintRect( aRetoucheRect ); + } + } + } +} + + +void SwPageFrm::CheckGrid( sal_Bool bInvalidate ) +{ + sal_Bool bOld = bHasGrid; + bHasGrid = sal_True; + GETGRID( this ) + bHasGrid = 0 != pGrid; + if( bInvalidate || bOld != bHasGrid ) + { + SwLayoutFrm* pBody = FindBodyCont(); + if( pBody ) + { + pBody->InvalidatePrt(); + SwCntntFrm* pFrm = pBody->ContainsCntnt(); + while( pBody->IsAnLower( pFrm ) ) + { + ((SwTxtFrm*)pFrm)->Prepare( PREP_CLEAR ); + pFrm = pFrm->GetNextCntntFrm(); + } + } + SetCompletePaint(); + } +} + + +void SwPageFrm::CheckDirection( sal_Bool bVert ) +{ + sal_uInt16 nDir = + ((SvxFrameDirectionItem&)GetFmt()->GetFmtAttr( RES_FRAMEDIR )).GetValue(); + if( bVert ) + { + if( FRMDIR_HORI_LEFT_TOP == nDir || FRMDIR_HORI_RIGHT_TOP == nDir ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + bVertLR = 0; + bVertical = 0; + } + else + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + bVertLR = 0; + bVertical = 0; + } + else + { + bVertical = 1; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if(FRMDIR_VERT_TOP_RIGHT == nDir) + bVertLR = 0; + else if(FRMDIR_VERT_TOP_LEFT==nDir) + bVertLR = 1; + } + } + + bReverse = 0; + bInvalidVert = 0; + } + else + { + if( FRMDIR_HORI_RIGHT_TOP == nDir ) + bRightToLeft = 1; + else + bRightToLeft = 0; + bInvalidR2L = 0; + } +} + +/************************************************************************* +|* +|* SwPageFrm::PreparePage() +|* +|* Beschreibung Erzeugt die Spezifischen Flys zur Seite und formatiert +|* generischen Cntnt +|* +|*************************************************************************/ +void MA_FASTCALL lcl_FormatLay( SwLayoutFrm *pLay ) +{ + //Alle LayoutFrms - nicht aber Tables, Flys o.ae. - formatieren. + + SwFrm *pTmp = pLay->Lower(); + //Erst die untergeordneten + while ( pTmp ) + { + if ( pTmp->GetType() & 0x00FF ) + ::lcl_FormatLay( (SwLayoutFrm*)pTmp ); + pTmp = pTmp->GetNext(); + } + pLay->Calc(); +} + +void MA_FASTCALL lcl_MakeObjs( const SwSpzFrmFmts &rTbl, SwPageFrm *pPage ) +{ + //Anlegen bzw. registrieren von Flys und Drawobjekten. + //Die Formate stehen in der SpzTbl (vom Dokument). + //Flys werden angelegt, DrawObjekte werden bei der Seite angemeldet. + + for ( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) + { + SdrObject *pSdrObj; + SwFrmFmt *pFmt = rTbl[i]; + const SwFmtAnchor &rAnch = pFmt->GetAnchor(); + if ( rAnch.GetPageNum() == pPage->GetPhyPageNum() ) + { + if( rAnch.GetCntntAnchor() ) + { + if (FLY_AT_PAGE == rAnch.GetAnchorId()) + { + SwFmtAnchor aAnch( rAnch ); + aAnch.SetAnchor( 0 ); + pFmt->SetFmtAttr( aAnch ); + } + else + continue; + } + + //Wird ein Rahmen oder ein SdrObject beschrieben? + sal_Bool bSdrObj = RES_DRAWFRMFMT == pFmt->Which(); + pSdrObj = 0; + if ( bSdrObj && 0 == (pSdrObj = pFmt->FindSdrObject()) ) + { + OSL_FAIL( "DrawObject not found." ); + pFmt->GetDoc()->DelFrmFmt( pFmt ); + --i; + continue; + } + //Das Objekt kann noch an einer anderen Seite verankert sein. + //Z.B. beim Einfuegen einer neuen Seite aufgrund eines + //Pagedescriptor-Wechsels. Das Objekt muss dann umgehaengt + //werden. + //Fuer bestimmte Faelle ist das Objekt bereits an der richtigen + //Seite verankert. Das wird hier automatisch erledigt und braucht + //- wenngleich performater machbar - nicht extra codiert werden. + SwPageFrm *pPg = pPage->IsEmptyPage() ? (SwPageFrm*)pPage->GetNext() : pPage; + if ( bSdrObj ) + { + // OD 23.06.2003 #108784# - consider 'virtual' drawing objects + SwDrawContact *pContact = + static_cast<SwDrawContact*>(::GetUserCall(pSdrObj)); + if ( pSdrObj->ISA(SwDrawVirtObj) ) + { + SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(pSdrObj); + if ( pContact ) + { + pDrawVirtObj->RemoveFromWriterLayout(); + pDrawVirtObj->RemoveFromDrawingPage(); + pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pDrawVirtObj )) ); + } + } + else + { + if ( pContact->GetAnchorFrm() ) + pContact->DisconnectFromLayout( false ); + pPg->AppendDrawObj( *(pContact->GetAnchoredObj( pSdrObj )) ); + } + } + else + { + SwIterator<SwFlyFrm,SwFmt> aIter( *pFmt ); + SwFlyFrm *pFly = aIter.First(); + if ( pFly) + { + if( pFly->GetAnchorFrm() ) + pFly->AnchorFrm()->RemoveFly( pFly ); + } + else + pFly = new SwFlyLayFrm( (SwFlyFrmFmt*)pFmt, pPg, pPg ); + pPg->AppendFly( pFly ); + ::RegistFlys( pPg, pFly ); + } + } + } +} + +void SwPageFrm::PreparePage( sal_Bool bFtn ) +{ + SetFtnPage( bFtn ); + + // --> OD 2008-01-30 #i82258# + // Due to made change on OOo 2.0 code line, method <::lcl_FormatLay(..)> has + // the side effect, that the content of page header and footer are formatted. + // For this formatting it is needed that the anchored objects are registered + // at the <SwPageFrm> instance. + // Thus, first calling <::RegistFlys(..)>, then call <::lcl_FormatLay(..)> + ::RegistFlys( this, this ); + + if ( Lower() ) + { + ::lcl_FormatLay( this ); + } + // <-- + + //Flys und DrawObjekte die noch am Dokument bereitstehen. + //Fussnotenseiten tragen keine Seitengebundenen Flys! + //Es kann Flys und Objekte geben, die auf Leerseiten (Seitennummernmaessig) + //stehen wollen, diese werden jedoch von den Leerseiten ignoriert; + //sie werden von den Folgeseiten aufgenommen. + if ( !bFtn && !IsEmptyPage() ) + { + SwDoc *pDoc = GetFmt()->GetDoc(); + + if ( GetPrev() && ((SwPageFrm*)GetPrev())->IsEmptyPage() ) + lcl_MakeObjs( *pDoc->GetSpzFrmFmts(), (SwPageFrm*)GetPrev() ); + lcl_MakeObjs( *pDoc->GetSpzFrmFmts(), this ); + + //Kopf-/Fusszeilen) formatieren. + SwLayoutFrm *pLow = (SwLayoutFrm*)Lower(); + while ( pLow ) + { + if ( pLow->GetType() & (FRMTYPE_HEADER|FRMTYPE_FOOTER) ) + { + SwCntntFrm *pCntnt = pLow->ContainsCntnt(); + while ( pCntnt && pLow->IsAnLower( pCntnt ) ) + { + pCntnt->OptCalc(); //Nicht die Vorgaenger + pCntnt = pCntnt->GetNextCntntFrm(); + } + } + pLow = (SwLayoutFrm*)pLow->GetNext(); + } + } +} + +/************************************************************************* +|* +|* SwPageFrm::Modify() +|* +|*************************************************************************/ +void SwPageFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( pSh ) + pSh->SetFirstVisPageInvalid(); + sal_uInt8 nInvFlags = 0; + + if( pNew && RES_ATTRSET_CHG == pNew->Which() ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + InvalidatePage( this ); + if ( nInvFlags & 0x01 ) + _InvalidatePrt(); + if ( nInvFlags & 0x02 ) + SetCompletePaint(); + if ( nInvFlags & 0x04 && GetNext() ) + GetNext()->InvalidatePos(); + if ( nInvFlags & 0x08 ) + PrepareHeader(); + if ( nInvFlags & 0x10 ) + PrepareFooter(); + if ( nInvFlags & 0x20 ) + CheckGrid( nInvFlags & 0x40 ); + } +} + +void SwPageFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { + case RES_FMT_CHG: + { + //Wenn sich das FrmFmt aendert kann hier einiges passieren. + //Abgesehen von den Grossenverhaeltnissen sind noch andere + //Dinge betroffen. + //1. Spaltigkeit. + OSL_ENSURE( pOld && pNew, "FMT_CHG Missing Format." ); + const SwFmt* pOldFmt = ((SwFmtChg*)pOld)->pChangedFmt; + const SwFmt* pNewFmt = ((SwFmtChg*)pNew)->pChangedFmt; + OSL_ENSURE( pOldFmt && pNewFmt, "FMT_CHG Missing Format." ); + + const SwFmtCol &rOldCol = pOldFmt->GetCol(); + const SwFmtCol &rNewCol = pNewFmt->GetCol(); + if( rOldCol != rNewCol ) + { + SwLayoutFrm *pB = FindBodyCont(); + OSL_ENSURE( pB, "Seite ohne Body." ); + pB->ChgColumns( rOldCol, rNewCol ); + rInvFlags |= 0x20; + } + + //2. Kopf- und Fusszeilen. + const SwFmtHeader &rOldH = pOldFmt->GetHeader(); + const SwFmtHeader &rNewH = pNewFmt->GetHeader(); + if( rOldH != rNewH ) + rInvFlags |= 0x08; + + const SwFmtFooter &rOldF = pOldFmt->GetFooter(); + const SwFmtFooter &rNewF = pNewFmt->GetFooter(); + if( rOldF != rNewF ) + rInvFlags |= 0x10; + CheckDirChange(); + } + /* kein break hier */ + case RES_FRM_SIZE: + { + const SwRect aOldPageFrmRect( Frm() ); + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + bValidSize = sal_False; + // OD 28.10.2002 #97265# - Don't call <SwPageFrm::MakeAll()> + // Calculation of the page is not necessary, because its size is + // is invalidated here and further invalidation is done in the + // calling method <SwPageFrm::Modify(..)> and probably by calling + // <SwLayoutFrm::Modify(..)> at the end. + // It can also causes inconsistences, because the lowers are + // adjusted, but not calculated, and a <SwPageFrm::MakeAll()> of + // a next page is called. This is performed on the switch to the + // online layout. + //MakeAll(); + } + else + { + const SwFmtFrmSize &rSz = nWhich == RES_FMT_CHG ? + ((SwFmtChg*)pNew)->pChangedFmt->GetFrmSize() : + (const SwFmtFrmSize&)*pNew; + + Frm().Height( Max( rSz.GetHeight(), long(MINLAY) ) ); + Frm().Width ( Max( rSz.GetWidth(), long(MINLAY) ) ); + + // PAGES01 + if ( GetUpper() ) + static_cast<SwRootFrm*>(GetUpper())->CheckViewLayout( 0, 0 ); + } + //Window aufraeumen. + if( pSh && pSh->GetWin() && aOldPageFrmRect.HasArea() ) + { + // OD 12.02.2003 #i9719#, #105645# - consider border and shadow of + // page frame for determine 'old' rectangle - it's used for invalidating. + const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT); + SwRect aOldRectWithBorderAndShadow; + SwPageFrm::GetBorderAndShadowBoundRect( aOldPageFrmRect, pSh, aOldRectWithBorderAndShadow, + IsLeftShadowNeeded(), IsRightShadowNeeded(), bRightSidebar ); + pSh->InvalidateWindows( aOldRectWithBorderAndShadow ); + } + rInvFlags |= 0x03; + if ( aOldPageFrmRect.Height() != Frm().Height() ) + rInvFlags |= 0x04; + } + break; + + case RES_COL: + { + SwLayoutFrm *pB = FindBodyCont(); + OSL_ENSURE( pB, "Seite ohne Body." ); + pB->ChgColumns( *(const SwFmtCol*)pOld, *(const SwFmtCol*)pNew ); + rInvFlags |= 0x22; + } + break; + + case RES_HEADER: + rInvFlags |= 0x08; + break; + + case RES_FOOTER: + rInvFlags |= 0x10; + break; + case RES_TEXTGRID: + rInvFlags |= 0x60; + break; + + case RES_PAGEDESC_FTNINFO: + //Die derzeit einzig sichere Methode: + ((SwRootFrm*)GetUpper())->SetSuperfluous(); + SetMaxFtnHeight( pDesc->GetFtnInfo().GetHeight() ); + if ( !GetMaxFtnHeight() ) + SetMaxFtnHeight( LONG_MAX ); + SetColMaxFtnHeight(); + //Hier wird die Seite ggf. zerstoert! + ((SwRootFrm*)GetUpper())->RemoveFtns( 0, sal_False, sal_True ); + break; + case RES_FRAMEDIR : + CheckDirChange(); + break; + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrm::Modify( pOld, pNew ); + } +} + +/************************************************************************* +|* +|* SwPageFrm::GetInfo() +|* +|* Beschreibung erfragt Informationen +|* +*************************************************************************/ + // erfrage vom Modify Informationen +sal_Bool SwPageFrm::GetInfo( SfxPoolItem & rInfo ) const +{ + if( RES_AUTOFMT_DOCNODE == rInfo.Which() ) + { + // es gibt einen PageFrm also wird er benutzt + return sal_False; + } + return sal_True; // weiter suchen +} + +/************************************************************************* +|* +|* SwPageFrm::SetPageDesc() +|* +|*************************************************************************/ +void SwPageFrm::SetPageDesc( SwPageDesc *pNew, SwFrmFmt *pFmt ) +{ + pDesc = pNew; + if ( pFmt ) + SetFrmFmt( pFmt ); +} + +/************************************************************************* +|* +|* SwPageFrm::FindPageDesc() +|* +|* Beschreibung Der richtige PageDesc wird bestimmt: +|* 0. Vom Dokument bei Fussnotenseiten und Endnotenseiten +|* 1. vom ersten BodyCntnt unterhalb der Seite. +|* 2. vom PageDesc der vorstehenden Seite. +|* 3. bei Leerseiten vom PageDesc der vorigen Seite. +|* 3.1 vom PageDesc der folgenden Seite wenn es keinen Vorgaenger gibt. +|* 4. es ist der Default-PageDesc sonst. +|* 5. Im BrowseMode ist der Pagedesc immer der vom ersten Absatz im +|* Dokument oder Standard (der 0-te) wenn der erste Absatz keinen +|* wuenscht. +|* (6. Im HTML-Mode ist der Pagedesc immer die HTML-Seitenvorlage.) +|* +|*************************************************************************/ +SwPageDesc *SwPageFrm::FindPageDesc() +{ + //0. + if ( IsFtnPage() ) + { + SwDoc *pDoc = GetFmt()->GetDoc(); + if ( IsEndNotePage() ) + return pDoc->GetEndNoteInfo().GetPageDesc( *pDoc ); + else + return pDoc->GetFtnInfo().GetPageDesc( *pDoc ); + } + + //6. + //if ( GetFmt()->GetDoc()->IsHTMLMode() ) + // return GetFmt()->GetDoc()->GetPageDescFromPool( RES_POOLPAGE_HTML ); + + SwPageDesc *pRet = 0; + + //5. + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + SwCntntFrm *pFrm = GetUpper()->ContainsCntnt(); + while ( !pFrm->IsInDocBody() ) + pFrm = pFrm->GetNextCntntFrm(); + SwFrm *pFlow = pFrm; + if ( pFlow->IsInTab() ) + pFlow = pFlow->FindTabFrm(); + pRet = (SwPageDesc*)pFlow->GetAttrSet()->GetPageDesc().GetPageDesc(); + if ( !pRet ) + pRet = &GetFmt()->GetDoc()->_GetPageDesc( 0 ); + return pRet; + } + + SwFrm *pFlow = FindFirstBodyCntnt(); + if ( pFlow && pFlow->IsInTab() ) + pFlow = pFlow->FindTabFrm(); + + //1. + if ( pFlow ) + { + SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow ); + if ( !pTmp->IsFollow() ) + pRet = (SwPageDesc*)pFlow->GetAttrSet()->GetPageDesc().GetPageDesc(); + } + + //3. und 3.1 + if ( !pRet && IsEmptyPage() ) + // FME 2008-03-03 #i81544# lijian/fme: an empty page should have + // the same page description as its prev, just like after construction + // of the empty page. + pRet = GetPrev() ? ((SwPageFrm*)GetPrev())->GetPageDesc() : + GetNext() ? ((SwPageFrm*)GetNext())->GetPageDesc() : 0; + + //2. + if ( !pRet ) + pRet = GetPrev() ? + ((SwPageFrm*)GetPrev())->GetPageDesc()->GetFollow() : 0; + + //4. + if ( !pRet ) + pRet = (SwPageDesc*)&(const_cast<const SwDoc *>(GetFmt()->GetDoc()) + ->GetPageDesc( 0 )); + + + OSL_ENSURE( pRet, "Kein Descriptor gefunden." ); + return pRet; +} + +//Wenn der RootFrm seine Groesse aendert muss benachrichtigt werden. +void AdjustSizeChgNotify( SwRootFrm *pRoot ) +{ + const sal_Bool bOld = pRoot->IsSuperfluous(); + pRoot->bCheckSuperfluous = sal_False; + ViewShell *pSh = pRoot->GetCurrShell(); + if ( pSh ) + { + do + { + if( pRoot == pSh->GetLayout() ) + { + pSh->SizeChgNotify(); + pSh->Imp()->NotifySizeChg( pRoot->Frm().SSize() ); + } + pSh = (ViewShell*)pSh->GetNext(); + } while ( pSh != pRoot->GetCurrShell() ); + } + pRoot->bCheckSuperfluous = bOld; +} + + +inline void SetLastPage( SwPageFrm *pPage ) +{ + ((SwRootFrm*)pPage->GetUpper())->pLastPage = pPage; +} + +/************************************************************************* +|* +|* SwPageFrm::Cut() +|* +|*************************************************************************/ +void SwPageFrm::Cut() +{ + // PAGES01 + //AdjustRootSize( CHG_CUTPAGE, 0 ); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( !IsEmptyPage() ) + { + if ( GetNext() ) + GetNext()->InvalidatePos(); + + //Flys deren Anker auf anderen Seiten stehen umhaengen. + //DrawObjecte spielen hier keine Rolle. + if ( GetSortedObjs() ) + { + for ( int i = 0; GetSortedObjs() && + (sal_uInt16)i < GetSortedObjs()->Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i]; + + if ( pAnchoredObj->ISA(SwFlyAtCntFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyAtCntFrm*>(pAnchoredObj); + SwPageFrm *pAnchPage = pFly->GetAnchorFrm() ? + pFly->AnchorFrm()->FindPageFrm() : 0; + if ( pAnchPage && (pAnchPage != this) ) + { + MoveFly( pFly, pAnchPage ); + --i; + pFly->InvalidateSize(); + pFly->_InvalidatePos(); + } + } + // <-- + } + } + //Window aufraeumen + if ( pSh && pSh->GetWin() ) + pSh->InvalidateWindows( Frm() ); + } + + // die Seitennummer der Root runterzaehlen. + ((SwRootFrm*)GetUpper())->DecrPhyPageNums(); + SwPageFrm *pPg = (SwPageFrm*)GetNext(); + if ( pPg ) + { + while ( pPg ) + { + pPg->DecrPhyPageNum(); //inline --nPhyPageNum + pPg = (SwPageFrm*)pPg->GetNext(); + } + } + else + ::SetLastPage( (SwPageFrm*)GetPrev() ); + + SwFrm* pRootFrm = GetUpper(); + + // Alle Verbindungen kappen. + Remove(); + + // PAGES01 + if ( pRootFrm ) + static_cast<SwRootFrm*>(pRootFrm)->CheckViewLayout( 0, 0 ); +} + +/************************************************************************* +|* +|* SwPageFrm::Paste() +|* +|*************************************************************************/ +void SwPageFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent->IsRootFrm(), "Parent ist keine Root." ); + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + // die Seitennummer am Root hochzaehlen. + ((SwRootFrm*)GetUpper())->IncrPhyPageNums(); + if( GetPrev() ) + SetPhyPageNum( ((SwPageFrm*)GetPrev())->GetPhyPageNum() + 1 ); + else + SetPhyPageNum( 1 ); + SwPageFrm *pPg = (SwPageFrm*)GetNext(); + if ( pPg ) + { + while ( pPg ) + { + pPg->IncrPhyPageNum(); //inline ++nPhyPageNum + pPg->_InvalidatePos(); + pPg->InvalidateLayout(); + pPg = (SwPageFrm*)pPg->GetNext(); + } + } + else + ::SetLastPage( this ); + + if( Frm().Width() != pParent->Prt().Width() ) + _InvalidateSize(); + + InvalidatePos(); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( pSh ) + pSh->SetFirstVisPageInvalid(); + // PAGES01 + getRootFrm()->CheckViewLayout( 0, 0 ); +} + +/************************************************************************* +|* +|* SwPageFrm::PrepareRegisterChg() +|* +|*************************************************************************/ +void lcl_PrepFlyInCntRegister( SwCntntFrm *pFrm ) +{ + pFrm->Prepare( PREP_REGISTER ); + if( pFrm->GetDrawObjs() ) + { + for( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyInCntFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyInCntFrm*>(pAnchoredObj); + SwCntntFrm *pCnt = pFly->ContainsCntnt(); + while ( pCnt ) + { + lcl_PrepFlyInCntRegister( pCnt ); + pCnt = pCnt->GetNextCntntFrm(); + } + } + // <-- + } + } +} + +void SwPageFrm::PrepareRegisterChg() +{ + SwCntntFrm *pFrm = FindFirstBodyCntnt(); + while( pFrm ) + { + lcl_PrepFlyInCntRegister( pFrm ); + pFrm = pFrm->GetNextCntntFrm(); + if( !IsAnLower( pFrm ) ) + break; + } + if( GetSortedObjs() ) + { + for( sal_uInt16 i = 0; i < GetSortedObjs()->Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + pFrm = pFly->ContainsCntnt(); + while ( pFrm ) + { + ::lcl_PrepFlyInCntRegister( pFrm ); + pFrm = pFrm->GetNextCntntFrm(); + } + } + } + } +} + +/************************************************************************* +|* +|* SwFrm::CheckPageDescs() +|* +|* Beschreibung Prueft alle Seiten ab der uebergebenen, daraufhin, +|* ob sie das richtige FrmFmt verwenden. Wenn 'falsche' Seiten +|* aufgespuehrt werden, so wird versucht die Situation moeglichst +|* einfache zu bereinigen. +|* +|*************************************************************************/ +void SwFrm::CheckPageDescs( SwPageFrm *pStart, sal_Bool bNotifyFields ) +{ + OSL_ENSURE( pStart, "Keine Startpage." ); + + ViewShell *pSh = pStart->getRootFrm()->GetCurrShell(); + SwViewImp *pImp = pSh ? pSh->Imp() : 0; + + if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() ) + { + pImp->GetLayAction().SetCheckPageNum( pStart->GetPhyPageNum() ); + return; + } + + //Fuer das Aktualisieren der Seitennummern-Felder gibt nDocPos + //die Seitenposition an, _ab_ der invalidiert werden soll. + SwTwips nDocPos = LONG_MAX; + + SwRootFrm *pRoot = (SwRootFrm*)pStart->GetUpper(); + SwDoc* pDoc = pStart->GetFmt()->GetDoc(); + const sal_Bool bFtns = 0 != pDoc->GetFtnIdxs().Count(); + + SwPageFrm *pPage = pStart; + if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() ) + pPage = (SwPageFrm*)pPage->GetPrev(); + while ( pPage ) + { + //gewuenschten PageDesc und FrmFmt festellen. + SwPageDesc *pDesc = pPage->FindPageDesc(); + sal_Bool bCheckEmpty = pPage->IsEmptyPage(); + sal_Bool bActOdd = pPage->OnRightPage(); + sal_Bool bOdd = pPage->WannaRightPage(); + SwFrmFmt *pFmtWish = bOdd ? pDesc->GetRightFmt() + : pDesc->GetLeftFmt(); + + if ( bActOdd != bOdd || + pDesc != pPage->GetPageDesc() || //falscher Desc + ( pFmtWish != pPage->GetFmt() && //falsches Format und + ( !pPage->IsEmptyPage() || pFmtWish ) //nicht Leerseite + ) + ) + { + //Wenn wir schon ein Seite veraendern muessen kann das eine + //Weile dauern, deshalb hier den WaitCrsr pruefen. + if( pImp ) + pImp->CheckWaitCrsr(); + + //Ab hier muessen die Felder invalidiert werden! + if ( nDocPos == LONG_MAX ) + nDocPos = pPage->GetPrev() ? + pPage->GetPrev()->Frm().Top() : pPage->Frm().Top(); + + //Faelle: + //1. Wir haben eine EmptyPage und wollen eine "Normalseite". + // ->EmptyPage wegwerfen und weiter mit der naechsten. + //2. Wir haben eine EmptyPage und wollen eine EmptyPage mit + // anderem Descriptor. + // ->Descriptor austauschen. + //3. Wir haben eine "Normalseite" und wollen eine EmptyPage. + // ->Emptypage einfuegen, nicht aber wenn die Vorseite + // bereits eine EmptyPage ist -> 6. + //4. Wir haben eine "Normalseite" und wollen eine "Normalseite" + // mit anderem Descriptor + // ->Descriptor und Format austauschen + //5. Wir haben eine "Normalseite" und wollen eine "Normalseite" + // mit anderem Format + // ->Format austauschen. + //6. Wir haben kein Wunschformat erhalten, also nehmen wir das + // 'andere' Format (rechts/links) des PageDesc. + + if ( pPage->IsEmptyPage() && ( pFmtWish || //1. + ( !bOdd && !pPage->GetPrev() ) ) ) + { + SwPageFrm *pTmp = (SwPageFrm*)pPage->GetNext(); + pPage->Cut(); + delete pPage; + if ( pStart == pPage ) + pStart = pTmp; + pPage = pTmp; + continue; + } + else if ( pPage->IsEmptyPage() && !pFmtWish && //2. + pDesc != pPage->GetPageDesc() ) + { + pPage->SetPageDesc( pDesc, 0 ); + } + else if ( !pPage->IsEmptyPage() && //3. + bActOdd != bOdd && + ( ( !pPage->GetPrev() && !bOdd ) || + ( pPage->GetPrev() && + !((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() ) + ) + ) + { + if ( pPage->GetPrev() ) + pDesc = ((SwPageFrm*)pPage->GetPrev())->GetPageDesc(); + SwPageFrm *pTmp = new SwPageFrm( pDoc->GetEmptyPageFmt(),pRoot,pDesc); + pTmp->Paste( pRoot, pPage ); + pTmp->PreparePage( sal_False ); + pPage = pTmp; + } + else if ( pPage->GetPageDesc() != pDesc ) //4. + { + SwPageDesc *pOld = pPage->GetPageDesc(); + pPage->SetPageDesc( pDesc, pFmtWish ); + if ( bFtns ) + { + //Wenn sich bestimmte Werte der FtnInfo veraendert haben + //muss etwas passieren. Wir versuchen den Schaden zu + //begrenzen. + //Wenn die Seiten keinen FtnCont hat, ist zwar theoretisches + //ein Problem denkbar, aber das ignorieren wir mit aller Kraft. + //Bei Aenderungen hoffen wir mal, dass eine Invalidierung + //ausreicht, denn alles andere wuerde viel Kraft kosten. + SwFtnContFrm *pCont = pPage->FindFtnCont(); + if ( pCont && !(pOld->GetFtnInfo() == pDesc->GetFtnInfo()) ) + pCont->_InvalidateAll(); + } + } + else if ( pFmtWish && pPage->GetFmt() != pFmtWish ) //5. + { + pPage->SetFrmFmt( pFmtWish ); + } + else if ( !pFmtWish ) //6. + { + //Format mit verdrehter Logic besorgen. + pFmtWish = bOdd ? pDesc->GetLeftFmt() : pDesc->GetRightFmt(); + if ( pPage->GetFmt() != pFmtWish ) + pPage->SetFrmFmt( pFmtWish ); + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OSL_FAIL( "CheckPageDescs, missing solution" ); + } +#endif + } + if ( bCheckEmpty ) + { + //Es kann noch sein, dass die Leerseite schlicht ueberflussig ist. + //Obiger Algorithmus kann dies leider nicht feststellen. + //Eigentlich muesste die Leerseite einfach praeventiv entfernt + //werden; sie wuerde ja ggf. wieder eingefuegt. + //Die EmptyPage ist genau dann ueberfluessig, wenn die Folgeseite + //auch ohne sie auskommt. Dazu muessen wir uns die Verhaeltnisse + //genauer ansehen. Wir bestimmen den PageDesc und die virtuelle + //Seitennummer manuell. + SwPageFrm *pPg = (SwPageFrm*)pPage->GetNext(); + if( !pPg || pPage->OnRightPage() == pPg->WannaRightPage() ) + { + //Die Folgeseite hat kein Problem ein FrmFmt zu finden oder keinen + //Nachfolger, also ist die Leerseite ueberfluessig. + SwPageFrm *pTmp = (SwPageFrm*)pPage->GetNext(); + pPage->Cut(); + delete pPage; + if ( pStart == pPage ) + pStart = pTmp; + pPage = pTmp; + continue; + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } + + pRoot->SetAssertFlyPages(); + pRoot->AssertPageFlys( pStart ); + + if ( bNotifyFields && (!pImp || !pImp->IsUpdateExpFlds()) ) + { + SwDocPosUpdate aMsgHnt( nDocPos ); + pDoc->UpdatePageFlds( &aMsgHnt ); + } + +#if OSL_DEBUG_LEVEL > 1 + //Ein paar Pruefungen muessen schon erlaubt sein. + + //1. Keine zwei EmptyPages hintereinander. + //2. Alle PageDescs richtig? + sal_Bool bEmpty = sal_False; + SwPageFrm *pPg = pStart; + while ( pPg ) + { + if ( pPg->IsEmptyPage() ) + { + if ( bEmpty ) + { + OSL_FAIL( "Doppelte Leerseiten." ); + break; //Einmal reicht. + } + bEmpty = sal_True; + } + else + bEmpty = sal_False; + +//MA 21. Jun. 95: Kann zu testzwecken 'rein, ist aber bei zyklen durchaus +//moeglich: Ein paar Seiten, auf der ersten 'erste Seite' anwenden, +//rechte als folge der ersten, linke als folge der rechten, rechte als +//folge der linken. +// OSL_ENSURE( pPg->GetPageDesc() == pPg->FindPageDesc(), +// "Seite mit falschem Descriptor." ); + + pPg = (SwPageFrm*)pPg->GetNext(); + } +#endif +} + +/************************************************************************* +|* +|* SwFrm::InsertPage() +|* +|*************************************************************************/ +SwPageFrm *SwFrm::InsertPage( SwPageFrm *pPrevPage, sal_Bool bFtn ) +{ + SwRootFrm *pRoot = (SwRootFrm*)pPrevPage->GetUpper(); + SwPageFrm *pSibling = (SwPageFrm*)pRoot->GetLower(); + SwPageDesc *pDesc = pSibling->GetPageDesc(); + + pSibling = (SwPageFrm*)pPrevPage->GetNext(); + //Rechte (ungerade) oder linke (gerade) Seite einfuegen? + sal_Bool bNextOdd = !pPrevPage->OnRightPage(); + sal_Bool bWishedOdd = bNextOdd; + + //Welcher PageDesc gilt? + //Bei CntntFrm der aus dem Format wenn einer angegeben ist, + //der Follow vom bereits in der PrevPage gueltigen sonst. + pDesc = 0; + if ( IsFlowFrm() && !SwFlowFrm::CastFlowFrm( this )->IsFollow() ) + { SwFmtPageDesc &rDesc = (SwFmtPageDesc&)GetAttrSet()->GetPageDesc(); + pDesc = rDesc.GetPageDesc(); + if ( rDesc.GetNumOffset() ) + { + bWishedOdd = rDesc.GetNumOffset() % 2 ? sal_True : sal_False; + //Die Gelegenheit nutzen wir um das Flag an der Root zu pflegen. + pRoot->SetVirtPageNum( sal_True ); + } + } + if ( !pDesc ) + pDesc = pPrevPage->GetPageDesc()->GetFollow(); + + OSL_ENSURE( pDesc, "Missing PageDesc" ); + if( !(bWishedOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt()) ) + bWishedOdd = !bWishedOdd; + + SwDoc *pDoc = pPrevPage->GetFmt()->GetDoc(); + SwFrmFmt *pFmt; + sal_Bool bCheckPages = sal_False; + //Wenn ich kein FrmFmt fuer die Seite gefunden habe, muss ich eben eine + //Leerseite einfuegen. + if( bWishedOdd != bNextOdd ) + { pFmt = pDoc->GetEmptyPageFmt(); + SwPageDesc *pTmpDesc = pPrevPage->GetPageDesc(); + SwPageFrm *pPage = new SwPageFrm( pFmt, pRoot, pTmpDesc ); + pPage->Paste( pRoot, pSibling ); + pPage->PreparePage( bFtn ); + //Wenn der Sibling keinen Bodytext enthaelt kann ich ihn vernichten + //Es sei denn, es ist eine Fussnotenseite + if ( pSibling && !pSibling->IsFtnPage() && + !pSibling->FindFirstBodyCntnt() ) + { + SwPageFrm *pDel = pSibling; + pSibling = (SwPageFrm*)pSibling->GetNext(); + if ( pDoc->GetFtnIdxs().Count() ) + pRoot->RemoveFtns( pDel, sal_True ); + pDel->Cut(); + delete pDel; + } + else + bCheckPages = sal_True; + } + pFmt = bWishedOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt(); + OSL_ENSURE( pFmt, "Descriptor without format." ); + SwPageFrm *pPage = new SwPageFrm( pFmt, pRoot, pDesc ); + pPage->Paste( pRoot, pSibling ); + pPage->PreparePage( bFtn ); + //Wenn der Sibling keinen Bodytext enthaelt kann ich ihn vernichten + //Es sei denn es ist eine Fussnotenseite. + if ( pSibling && !pSibling->IsFtnPage() && + !pSibling->FindFirstBodyCntnt() ) + { + SwPageFrm *pDel = pSibling; + pSibling = (SwPageFrm*)pSibling->GetNext(); + if ( pDoc->GetFtnIdxs().Count() ) + pRoot->RemoveFtns( pDel, sal_True ); + pDel->Cut(); + delete pDel; + } + else + bCheckPages = sal_True; + + if ( pSibling ) + { + if ( bCheckPages ) + { + CheckPageDescs( pSibling, sal_False ); + ViewShell *pSh = getRootFrm()->GetCurrShell(); + SwViewImp *pImp = pSh ? pSh->Imp() : 0; + if ( pImp && pImp->IsAction() && !pImp->GetLayAction().IsCheckPages() ) + { + const sal_uInt16 nNum = pImp->GetLayAction().GetCheckPageNum(); + if ( nNum == pPrevPage->GetPhyPageNum() + 1 ) + pImp->GetLayAction().SetCheckPageNumDirect( + pSibling->GetPhyPageNum() ); + return pPage; + } + } + else + pRoot->AssertPageFlys( pSibling ); + } + + //Fuer das Aktualisieren der Seitennummern-Felder gibt nDocPos + //die Seitenposition an, _ab_ der invalidiert werden soll. + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( !pSh || !pSh->Imp()->IsUpdateExpFlds() ) + { + SwDocPosUpdate aMsgHnt( pPrevPage->Frm().Top() ); + pDoc->UpdatePageFlds( &aMsgHnt ); + } + return pPage; +} + +sw::sidebarwindows::SidebarPosition SwPageFrm::SidebarPosition() const +{ + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( !pSh || pSh->GetViewOptions()->getBrowseMode() ) + { + return sw::sidebarwindows::SIDEBAR_RIGHT; + } + else + { + const bool bLTR = getRootFrm()->IsLeftToRightViewLayout(); + const bool bBookMode = pSh->GetViewOptions()->IsViewLayoutBookMode(); + const bool bRightSidebar = bLTR ? (!bBookMode || OnRightPage()) : (bBookMode && !OnRightPage()); + + return bRightSidebar + ? sw::sidebarwindows::SIDEBAR_RIGHT + : sw::sidebarwindows::SIDEBAR_LEFT; + } +} + +/************************************************************************* +|* +|* SwRootFrm::GrowFrm() +|* +|*************************************************************************/ + +SwTwips SwRootFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool ) +{ + if ( !bTst ) + Frm().SSize().Height() += nDist; + return nDist; +} +/************************************************************************* +|* +|* SwRootFrm::ShrinkFrm() +|* +|*************************************************************************/ +SwTwips SwRootFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool ) +{ + OSL_ENSURE( nDist >= 0, "nDist < 0." ); + OSL_ENSURE( nDist <= Frm().Height(), "nDist > als aktuelle Groesse." ); + + if ( !bTst ) + Frm().SSize().Height() -= nDist; + return nDist; +} + +/************************************************************************* +|* +|* SwRootFrm::RemoveSuperfluous() +|* +|* Beschreibung: Entfernung von ueberfluessigen Seiten. +|* Arbeitet nur wenn das Flag bCheckSuperfluous gesetzt ist. +|* Definition: Eine Seite ist genau dann leer, wenn der +|* Body-Textbereich keinen CntntFrm enthaelt, aber nicht, wenn noch +|* mindestens ein Fly an der Seite klebt. +|* Die Seite ist auch dann nicht leer, wenn sie noch eine +|* Fussnote enthaelt. +|* Es muss zweimal angesetzt werden um leeren Seiten aufzuspueren: +|* - einmal fuer die Endnotenseiten. +|* - und einmal fuer die Seiten des Bodytextes. +|* +|*************************************************************************/ +void SwRootFrm::RemoveSuperfluous() +{ + if ( !IsSuperfluous() ) + return; + bCheckSuperfluous = sal_False; + + SwPageFrm *pPage = GetLastPage(); + long nDocPos = LONG_MAX; + + //Jetzt wird fuer die jeweils letzte Seite geprueft ob sie leer ist + //bei der ersten nicht leeren Seite wird die Schleife beendet. + do + { + bool bExistEssentialObjs = ( 0 != pPage->GetSortedObjs() ); + if ( bExistEssentialObjs ) + { + //Nur weil die Seite Flys hat sind wir noch lange nicht fertig, + //denn wenn alle Flys an generischem Inhalt haengen, so ist sie + //trotzdem ueberfluessig (Ueberpruefung auf DocBody sollte reichen). + // OD 19.06.2003 #108784# - consider that drawing objects in + // header/footer are supported now. + bool bOnlySuperfluosObjs = true; + SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for ( sal_uInt16 i = 0; bOnlySuperfluosObjs && i < rObjs.Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = rObjs[i]; + // OD 2004-01-19 #110582# - do not consider hidden objects + if ( pPage->GetFmt()->GetDoc()->IsVisibleLayerId( + pAnchoredObj->GetDrawObj()->GetLayer() ) && + !pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) + { + bOnlySuperfluosObjs = false; + } + // <-- + } + bExistEssentialObjs = !bOnlySuperfluosObjs; + } + + // OD 19.06.2003 #108784# - optimization: check first, if essential objects + // exists. + const SwLayoutFrm* pBody = 0; + if ( bExistEssentialObjs || + pPage->FindFtnCont() || + ( 0 != ( pBody = pPage->FindBodyCont() ) && + ( pBody->ContainsCntnt() || + // --> FME 2005-05-18 #i47580# + // Do not delete page if there's an empty tabframe + // left. I think it might be correct to use ContainsAny() + // instead of ContainsCntnt() to cover the empty-table-case, + // but I'm not fully sure, since ContainsAny() also returns + // SectionFrames. Therefore I prefer to do it the safe way: + ( pBody->Lower() && pBody->Lower()->IsTabFrm() ) ) ) ) + // <-- + { + if ( pPage->IsFtnPage() ) + { + while ( pPage->IsFtnPage() ) + { + pPage = (SwPageFrm*)pPage->GetPrev(); + OSL_ENSURE( pPage, "Nur noch Endnotenseiten uebrig." ); + } + continue; + } + else + pPage = 0; + } + + if ( pPage ) + { + SwPageFrm *pEmpty = pPage; + pPage = (SwPageFrm*)pPage->GetPrev(); + if ( GetFmt()->GetDoc()->GetFtnIdxs().Count() ) + RemoveFtns( pEmpty, sal_True ); + pEmpty->Cut(); + delete pEmpty; + nDocPos = pPage ? pPage->Frm().Top() : 0; + } + } while ( pPage ); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( nDocPos != LONG_MAX && + (!pSh || !pSh->Imp()->IsUpdateExpFlds()) ) + { + SwDocPosUpdate aMsgHnt( nDocPos ); + GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt ); + } +} + +/************************************************************************* +|* +|* SwRootFrm::AssertFlyPages() +|* +|* Beschreibung Stellt sicher, dass genuegend Seiten vorhanden +|* sind, damit alle Seitengebundenen Rahmen und DrawObject +|* untergebracht sind. +|* +|*************************************************************************/ +void SwRootFrm::AssertFlyPages() +{ + if ( !IsAssertFlyPages() ) + return; + bAssertFlyPages = sal_False; + + SwDoc *pDoc = GetFmt()->GetDoc(); + const SwSpzFrmFmts *pTbl = pDoc->GetSpzFrmFmts(); + + //Auf welche Seite will der 'letzte' Fly? + sal_uInt16 nMaxPg = 0; + sal_uInt16 i; + + for ( i = 0; i < pTbl->Count(); ++i ) + { + const SwFmtAnchor &rAnch = (*pTbl)[i]->GetAnchor(); + if ( !rAnch.GetCntntAnchor() && nMaxPg < rAnch.GetPageNum() ) + nMaxPg = rAnch.GetPageNum(); + } + //Wieviele Seiten haben wir derzeit? + SwPageFrm *pPage = (SwPageFrm*)Lower(); + while ( pPage && pPage->GetNext() && + !((SwPageFrm*)pPage->GetNext())->IsFtnPage() ) + { + pPage = (SwPageFrm*)pPage->GetNext(); + } + + if ( nMaxPg > pPage->GetPhyPageNum() ) + { + //Die Seiten werden ausgehend von der letzten Seite konsequent + //nach den Regeln der PageDescs weitergefuehrt. + sal_Bool bOdd = pPage->GetPhyPageNum() % 2 ? sal_True : sal_False; + SwPageDesc *pDesc = pPage->GetPageDesc(); + SwFrm *pSibling = pPage->GetNext(); + for ( i = pPage->GetPhyPageNum(); i < nMaxPg; ++i ) + { + if ( !(bOdd ? pDesc->GetRightFmt() : pDesc->GetLeftFmt()) ) + { + //Leerseite einfuegen, die Flys werden aber erst von + //der naechsten Seite aufgenommen! + pPage = new SwPageFrm( pDoc->GetEmptyPageFmt(), this, pDesc ); + pPage->Paste( this, pSibling ); + pPage->PreparePage( sal_False ); + bOdd = bOdd ? sal_False : sal_True; + ++i; + } + pPage = new + SwPageFrm( (bOdd ? pDesc->GetRightFmt() : + pDesc->GetLeftFmt()), this, pDesc ); + pPage->Paste( this, pSibling ); + pPage->PreparePage( sal_False ); + bOdd = bOdd ? sal_False : sal_True; + pDesc = pDesc->GetFollow(); + } + //Jetzt koennen die Endnotenseiten natuerlich wieder krumm sein; + //in diesem Fall werden sie vernichtet. + if ( pDoc->GetFtnIdxs().Count() ) + { + pPage = (SwPageFrm*)Lower(); + while ( pPage && !pPage->IsFtnPage() ) + pPage = (SwPageFrm*)pPage->GetNext(); + + if ( pPage ) + { + SwPageDesc *pTmpDesc = pPage->FindPageDesc(); + bOdd = pPage->OnRightPage(); + if ( pPage->GetFmt() != + (bOdd ? pTmpDesc->GetRightFmt() : pTmpDesc->GetLeftFmt()) ) + RemoveFtns( pPage, sal_False, sal_True ); + } + } + } +} + +/************************************************************************* +|* +|* SwRootFrm::AssertPageFlys() +|* +|* Beschreibung Stellt sicher, dass ab der uebergebenen Seite +|* auf allen Seiten die Seitengebunden Objecte auf der richtigen +|* Seite (Seitennummer stehen). +|* +|*************************************************************************/ +void SwRootFrm::AssertPageFlys( SwPageFrm *pPage ) +{ + while ( pPage ) + { + if ( pPage->GetSortedObjs() ) + { + pPage->GetSortedObjs(); + for ( int i = 0; + pPage->GetSortedObjs() && sal_uInt16(i) < pPage->GetSortedObjs()->Count(); + ++i) + { + // --> OD 2004-06-29 #i28701# + SwFrmFmt& rFmt = (*pPage->GetSortedObjs())[i]->GetFrmFmt(); + const SwFmtAnchor &rAnch = rFmt.GetAnchor(); + const sal_uInt16 nPg = rAnch.GetPageNum(); + if ((rAnch.GetAnchorId() == FLY_AT_PAGE) && + nPg != pPage->GetPhyPageNum() ) + { + //Das er auf der falschen Seite steht muss noch nichts + //heissen, wenn er eigentlich auf der Vorseite + //stehen will und diese eine EmptyPage ist. + if( nPg && !(pPage->GetPhyPageNum()-1 == nPg && + ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage()) ) + { + //Umhaengen kann er sich selbst, indem wir ihm + //einfach ein Modify mit seinem AnkerAttr schicken. +#if OSL_DEBUG_LEVEL > 1 + const sal_uInt32 nCnt = pPage->GetSortedObjs()->Count(); + rFmt.NotifyClients( 0, (SwFmtAnchor*)&rAnch ); + OSL_ENSURE( !pPage->GetSortedObjs() || + nCnt != pPage->GetSortedObjs()->Count(), + "Object couldn't be reattached!" ); +#else + rFmt.NotifyClients( 0, (SwFmtAnchor*)&rAnch ); +#endif + --i; + } + } + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } +} + +/************************************************************************* +|* +|* SwRootFrm::ChgSize() +|* +|*************************************************************************/ +Size SwRootFrm::ChgSize( const Size& aNewSize ) +{ + Frm().SSize() = aNewSize; + _InvalidatePrt(); + bFixSize = sal_False; + return Frm().SSize(); +} + +/************************************************************************* +|* +|* SwRootFrm::MakeAll() +|* +|*************************************************************************/ +void SwRootFrm::MakeAll() +{ + if ( !bValidPos ) + { bValidPos = sal_True; + aFrm.Pos().X() = aFrm.Pos().Y() = DOCUMENTBORDER; + } + if ( !bValidPrtArea ) + { bValidPrtArea = sal_True; + aPrt.Pos().X() = aPrt.Pos().Y() = 0; + aPrt.SSize( aFrm.SSize() ); + } + if ( !bValidSize ) + //SSize wird von den Seiten (Cut/Paste) eingestellt. + bValidSize = sal_True; +} + +/************************************************************************* +|* +|* SwRootFrm::ImplInvalidateBrowseWidth() +|* +|*************************************************************************/ +void SwRootFrm::ImplInvalidateBrowseWidth() +{ + bBrowseWidthValid = sal_False; + SwFrm *pPg = Lower(); + while ( pPg ) + { + pPg->InvalidateSize(); + pPg = pPg->GetNext(); + } +} + +/************************************************************************* +|* +|* SwRootFrm::ImplCalcBrowseWidth() +|* +|*************************************************************************/ +void SwRootFrm::ImplCalcBrowseWidth() +{ + OSL_ENSURE( GetCurrShell() && GetCurrShell()->GetViewOptions()->getBrowseMode(), + "CalcBrowseWidth and not in BrowseView" ); + + //Die (minimale) Breite wird von Rahmen, Tabellen und Zeichenobjekten + //bestimmt. Die Breite wird nicht anhand ihrer aktuellen Groessen bestimmt, + //sondern anhand der Attribute. Es interessiert also nicht wie breit sie + //sind, sondern wie breit sie sein wollen. + //Rahmen und Zeichenobjekte innerhalb ander Objekte (Rahmen, Tabellen) + //Zaehlen nicht. + //Seitenraender und Spalten werden hier nicht beruecksichtigt. + + SwFrm *pFrm = ContainsCntnt(); + while ( pFrm && !pFrm->IsInDocBody() ) + pFrm = ((SwCntntFrm*)pFrm)->GetNextCntntFrm(); + if ( !pFrm ) + return; + + bBrowseWidthValid = sal_True; + ViewShell *pSh = getRootFrm()->GetCurrShell(); + nBrowseWidth = pSh + ? MINLAY + 2 * pSh->GetOut()-> + PixelToLogic( pSh->GetBrowseBorder() ).Width() + : 5000; + do + { + if ( pFrm->IsInTab() ) + pFrm = pFrm->FindTabFrm(); + + if ( pFrm->IsTabFrm() && + !((SwLayoutFrm*)pFrm)->GetFmt()->GetFrmSize().GetWidthPercent() ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + const SwFmtHoriOrient &rHori = rAttrs.GetAttrSet().GetHoriOrient(); + long nWidth = rAttrs.GetSize().Width(); + if ( nWidth < USHRT_MAX-2000 && //-2000, weil bei Randeinstellung per + //Zuppeln das USHRT_MAX verlorengeht! + text::HoriOrientation::FULL != rHori.GetHoriOrient() ) + { + const SwHTMLTableLayout *pLayoutInfo = + ((const SwTabFrm *)pFrm)->GetTable() + ->GetHTMLTableLayout(); + if ( pLayoutInfo ) + nWidth = Min( nWidth, pLayoutInfo->GetBrowseWidthMin() ); + + switch ( rHori.GetHoriOrient() ) + { + case text::HoriOrientation::NONE: + // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> + nWidth += rAttrs.CalcLeft( pFrm ) + rAttrs.CalcRight( pFrm ); + break; + case text::HoriOrientation::LEFT_AND_WIDTH: + nWidth += rAttrs.CalcLeft( pFrm ); + break; + default: + break; + + } + nBrowseWidth = Max( nBrowseWidth, nWidth ); + } + } + else if ( pFrm->GetDrawObjs() ) + { + for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + // --> OD 2004-06-29 #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + const SwFrmFmt& rFmt = pAnchoredObj->GetFrmFmt(); + const sal_Bool bFly = pAnchoredObj->ISA(SwFlyFrm); + if ((bFly && (WEIT_WECH == pAnchoredObj->GetObjRect().Width())) + || rFmt.GetFrmSize().GetWidthPercent()) + { + continue; + } + + long nWidth = 0; + switch ( rFmt.GetAnchor().GetAnchorId() ) + { + case FLY_AS_CHAR: + nWidth = bFly ? rFmt.GetFrmSize().GetWidth() : + pAnchoredObj->GetObjRect().Width(); + break; + case FLY_AT_PARA: + { + // --> FME 2004-09-13 #i33170# + // Reactivated old code because + // nWidth = pAnchoredObj->GetObjRect().Right() + // gives wrong results for objects that are still + // at position WEIT_WECH. + if ( bFly ) + { + nWidth = rFmt.GetFrmSize().GetWidth(); + const SwFmtHoriOrient &rHori = rFmt.GetHoriOrient(); + switch ( rHori.GetHoriOrient() ) + { + case text::HoriOrientation::NONE: + nWidth += rHori.GetPos(); + break; + case text::HoriOrientation::INSIDE: + case text::HoriOrientation::LEFT: + if ( text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() ) + nWidth += pFrm->Prt().Left(); + break; + default: + break; + } + } + else + //Fuer Zeichenobjekte ist die Auswahl sehr klein, + //weil sie keine Attribute haben, also durch ihre + //aktuelle Groesse bestimmt werden. + nWidth = pAnchoredObj->GetObjRect().Right() - + pAnchoredObj->GetDrawObj()->GetAnchorPos().X(); + // <-- + } + break; + default: /* do nothing */; + } + nBrowseWidth = Max( nBrowseWidth, nWidth ); + } + } + pFrm = pFrm->FindNextCnt(); + } while ( pFrm ); +} + +/************************************************************************* +|* +|* SwRootFrm::StartAllAction() +|* +|*************************************************************************/ + +void SwRootFrm::StartAllAction() +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { if ( pSh->ISA( SwCrsrShell ) ) + ((SwCrsrShell*)pSh)->StartAction(); + else + pSh->StartAction(); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != GetCurrShell() ); +} + +void SwRootFrm::EndAllAction( sal_Bool bVirDev ) +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { + const sal_Bool bOldEndActionByVirDev = pSh->IsEndActionByVirDev(); + pSh->SetEndActionByVirDev( bVirDev ); + if ( pSh->ISA( SwCrsrShell ) ) + { + ((SwCrsrShell*)pSh)->EndAction(); + ((SwCrsrShell*)pSh)->CallChgLnk(); + if ( pSh->ISA( SwFEShell ) ) + ((SwFEShell*)pSh)->SetChainMarker(); + } + else + pSh->EndAction(); + pSh->SetEndActionByVirDev( bOldEndActionByVirDev ); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != GetCurrShell() ); +} + +void SwRootFrm::UnoRemoveAllActions() +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { + // --> OD 2008-05-16 #i84729# + // No end action, if <ViewShell> instance is currently in its end action. + // Recursives calls to <::EndAction()> are not allowed. + if ( !pSh->IsInEndAction() ) + { + DBG_ASSERT(!pSh->GetRestoreActions(), "Restore action count is already set!"); + sal_Bool bCrsr = pSh->ISA( SwCrsrShell ); + sal_Bool bFE = pSh->ISA( SwFEShell ); + sal_uInt16 nRestore = 0; + while( pSh->ActionCount() ) + { + if( bCrsr ) + { + ((SwCrsrShell*)pSh)->EndAction(); + ((SwCrsrShell*)pSh)->CallChgLnk(); + if ( bFE ) + ((SwFEShell*)pSh)->SetChainMarker(); + } + else + pSh->EndAction(); + nRestore++; + } + pSh->SetRestoreActions(nRestore); + } + // <-- + pSh->LockView(sal_True); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != GetCurrShell() ); +} + +void SwRootFrm::UnoRestoreAllActions() +{ + ViewShell *pSh = GetCurrShell(); + if ( pSh ) + do + { + sal_uInt16 nActions = pSh->GetRestoreActions(); + while( nActions-- ) + { + if ( pSh->ISA( SwCrsrShell ) ) + ((SwCrsrShell*)pSh)->StartAction(); + else + pSh->StartAction(); + } + pSh->SetRestoreActions(0); + pSh->LockView(sal_False); + pSh = (ViewShell*)pSh->GetNext(); + + } while ( pSh != GetCurrShell() ); +} + +// PAGES01: Helper functions for SwRootFrm::CheckViewLayout +void lcl_MoveAllLowers( SwFrm* pFrm, const Point& rOffset ); + +void lcl_MoveAllLowerObjs( SwFrm* pFrm, const Point& rOffset ) +{ + SwSortedObjs* pSortedObj = 0; + const bool bPage = pFrm->IsPageFrm(); + + if ( bPage ) + pSortedObj = static_cast<SwPageFrm*>(pFrm)->GetSortedObjs(); + else + pSortedObj = pFrm->GetDrawObjs(); + + for ( sal_uInt16 i = 0; pSortedObj && i < pSortedObj->Count(); ++i) + { + SwAnchoredObject* pAnchoredObj = (*pSortedObj)[i]; + + const SwFrmFmt& rObjFmt = pAnchoredObj->GetFrmFmt(); + const SwFmtAnchor& rAnchor = rObjFmt.GetAnchor(); + + // all except from the as character anchored objects are moved + // when processing the page frame: + const bool bAsChar = (rAnchor.GetAnchorId() == FLY_AS_CHAR); + if ( !bPage && !bAsChar ) + continue; + + SwObjPositioningInProgress aPosInProgress( *pAnchoredObj ); + + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFlyFrm( static_cast<SwFlyFrm*>(pAnchoredObj) ); + lcl_MoveAllLowers( pFlyFrm, rOffset ); + pFlyFrm->NotifyDrawObj(); + // --> let the active embedded object be moved + if ( pFlyFrm->Lower() ) + { + if ( pFlyFrm->Lower()->IsNoTxtFrm() ) + { + SwCntntFrm* pCntntFrm = static_cast<SwCntntFrm*>(pFlyFrm->Lower()); + SwRootFrm* pRoot = pFlyFrm->Lower()->getRootFrm(); + ViewShell *pSh = pRoot ? pRoot->GetCurrShell() : 0; + if ( pSh ) + { + SwOLENode* pNode = pCntntFrm->GetNode()->GetOLENode(); + if ( pNode ) + { + svt::EmbeddedObjectRef& xObj = pNode->GetOLEObj().GetObject(); + if ( xObj.is() ) + { + ViewShell* pTmp = pSh; + do + { + SwFEShell* pFEShell = dynamic_cast< SwFEShell* >( pTmp ); + if ( pFEShell ) + pFEShell->MoveObjectIfActive( xObj, rOffset ); + pTmp = static_cast<ViewShell*>( pTmp->GetNext() ); + } while( pTmp != pSh ); + } + } + } + } + } + // <-- + } + else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) + { + SwAnchoredDrawObject* pAnchoredDrawObj( static_cast<SwAnchoredDrawObject*>(pAnchoredObj) ); + + // don't touch objects that are not yet positioned: + const bool bNotYetPositioned = pAnchoredDrawObj->NotYetPositioned(); + if ( bNotYetPositioned ) + continue; + + const Point aCurrAnchorPos = pAnchoredDrawObj->GetDrawObj()->GetAnchorPos(); + const Point aNewAnchorPos( ( aCurrAnchorPos + rOffset ) ); + pAnchoredDrawObj->DrawObj()->SetAnchorPos( aNewAnchorPos ); + pAnchoredDrawObj->SetLastObjRect( pAnchoredDrawObj->GetObjRect().SVRect() ); + } + // --> OD 2009-08-20 #i92511# + // cache for object rectangle inclusive spaces has to be invalidated. + pAnchoredObj->InvalidateObjRectWithSpaces(); + // <-- + } +} + +void lcl_MoveAllLowers( SwFrm* pFrm, const Point& rOffset ) +{ + const SwRect aFrm( pFrm->Frm() ); + + // first move the current frame + pFrm->Frm().Pos() += rOffset; + + // Don't forget accessibility: + if( pFrm->IsAccessibleFrm() ) + { + SwRootFrm *pRootFrm = pFrm->getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pFrm, aFrm ); + } + } + + // the move any objects + lcl_MoveAllLowerObjs( pFrm, rOffset ); + + // finally, for layout frames we have to call this function recursively: + if ( pFrm->ISA(SwLayoutFrm) ) + { + SwFrm* pLowerFrm = pFrm->GetLower(); + while ( pLowerFrm ) + { + lcl_MoveAllLowers( pLowerFrm, rOffset ); + pLowerFrm = pLowerFrm->GetNext(); + } + } +} + +// PAGES01: Calculate how the pages have to be positioned +void SwRootFrm::CheckViewLayout( const SwViewOption* pViewOpt, const SwRect* pVisArea ) +{ + // --> OD 2008-07-07 #i91432# + // No calculation of page positions, if only an empty page is present. + // This situation occurs when <SwRootFrm> instance is in construction + // and the document contains only left pages. + if ( Lower()->GetNext() == 0 && + static_cast<SwPageFrm*>(Lower())->IsEmptyPage() ) + { + return; + } + // <-- + + if ( !pVisArea ) + { + // no early return for bNewPage + if ( mnViewWidth < 0 ) + mnViewWidth = 0; + } + else + { + OSL_ENSURE( pViewOpt, "CheckViewLayout required ViewOptions" ); + + const sal_uInt16 nColumns = pViewOpt->GetViewLayoutColumns(); + const bool bBookMode = pViewOpt->IsViewLayoutBookMode(); + + if ( nColumns == mnColumns && bBookMode == mbBookMode && pVisArea->Width() == mnViewWidth && !mbSidebarChanged ) + return; + + mnColumns = nColumns; + mbBookMode = bBookMode; + mnViewWidth = pVisArea->Width(); + mbSidebarChanged = false; + } + + if( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE ) ) + { + mnColumns = 1; + mbBookMode = false; + } + + Calc(); + + const sal_Bool bOldCallbackActionEnabled = IsCallbackActionEnabled(); + SetCallbackActionEnabled( sal_False ); + + maPageRects.clear(); + + const long nBorder = Frm().Pos().X(); + const long nVisWidth = mnViewWidth - 2 * nBorder; + const long nGapBetweenPages = GAPBETWEENPAGES; + + // check how many pages fit into the first page layout row: + SwPageFrm* pPageFrm = static_cast<SwPageFrm*>(Lower()); + + // will contain the number of pages per row. 0 means that + // the page does not fit. + long nWidthRemain = nVisWidth; + + // after one row has been processed, these variables contain + // the width of the row and the maxium of the page heights + long nCurrentRowHeight = 0; + long nCurrentRowWidth = 0; + + // these variables are used to finally set the size of the + // root frame + long nSumRowHeight = 0; + SwTwips nMinPageLeft = TWIPS_MAX; + SwTwips nMaxPageRight = 0; + SwPageFrm* pStartOfRow = pPageFrm; + sal_uInt16 nNumberOfPagesInRow = mbBookMode ? 1 : 0; // in book view, start with right page + bool bFirstRow = true; + + bool bPageChanged = false; + const bool bRTL = !IsLeftToRightViewLayout(); + const SwTwips nSidebarWidth = SwPageFrm::GetSidebarBorderWidth( GetCurrShell() ); + + while ( pPageFrm ) + { + // we consider the current page to be "start of row" if + // 1. it is the first page in the current row or + // 2. it is the second page in the row and the first page is an empty page in non-book view: + const bool bStartOfRow = pPageFrm == pStartOfRow || + ( pStartOfRow->IsEmptyPage() && pPageFrm == pStartOfRow->GetNext() && !mbBookMode ); + + const bool bEmptyPage = pPageFrm->IsEmptyPage() && !mbBookMode; + + // no half doc border space for first page in each row and + long nPageWidth = 0; + long nPageHeight = 0; + + if ( mbBookMode ) + { + const SwFrm& rFormatPage = pPageFrm->GetFormatPage(); + + nPageWidth = rFormatPage.Frm().Width() + nSidebarWidth + ((bStartOfRow || 1 == (pPageFrm->GetPhyPageNum()%2)) ? 0 : nGapBetweenPages); + nPageHeight = rFormatPage.Frm().Height() + nGapBetweenPages; + } + else + { + SwRect aPageFrm; + if ( !pPageFrm->IsEmptyPage() ) + { + nPageWidth = pPageFrm->Frm().Width() + nSidebarWidth + (bStartOfRow ? 0 : nGapBetweenPages); + nPageHeight = pPageFrm->Frm().Height() + nGapBetweenPages; + } + } + + if ( !bEmptyPage ) + ++nNumberOfPagesInRow; + + // finish current row if + // 1. in dynamic mode the current page does not fit anymore or + // 2. the current page exceeds the maximum number of columns + bool bRowFinished = (0 == mnColumns && nWidthRemain < nPageWidth ) || + (0 != mnColumns && mnColumns < nNumberOfPagesInRow); + + // make sure that at least one page goes to the current row: + if ( !bRowFinished || bStartOfRow ) + { + // current page is allowed to be in current row + nWidthRemain = nWidthRemain - nPageWidth; + + nCurrentRowWidth = nCurrentRowWidth + nPageWidth; + nCurrentRowHeight = Max( nCurrentRowHeight, nPageHeight ); + + pPageFrm = static_cast<SwPageFrm*>(pPageFrm->GetNext()); + + if ( !pPageFrm ) + bRowFinished = true; + } + + if ( bRowFinished ) + { + // pPageFrm now points to the first page in the new row or null + // pStartOfRow points to the first page in the current row + + // special centering for last row. pretend to fill the last row with virtual copies of the last page before centering: + if ( !pPageFrm && nWidthRemain > 0 ) + { + // find last page in current row: + const SwPageFrm* pLastPageInCurrentRow = pStartOfRow; + while( pLastPageInCurrentRow->GetNext() ) + pLastPageInCurrentRow = static_cast<const SwPageFrm*>(pLastPageInCurrentRow->GetNext()); + + if ( pLastPageInCurrentRow->IsEmptyPage() ) + pLastPageInCurrentRow = static_cast<const SwPageFrm*>(pLastPageInCurrentRow->GetPrev()); + + // check how many times the last page would still fit into the remaining space: + sal_uInt16 nNumberOfVirtualPages = 0; + const sal_uInt16 nMaxNumberOfVirtualPages = mnColumns > 0 ? mnColumns - nNumberOfPagesInRow : USHRT_MAX; + SwTwips nRemain = nWidthRemain; + SwTwips nVirtualPagesWidth = 0; + SwTwips nLastPageWidth = pLastPageInCurrentRow->Frm().Width() + nSidebarWidth; + + while ( ( mnColumns > 0 || nRemain > 0 ) && nNumberOfVirtualPages < nMaxNumberOfVirtualPages ) + { + SwTwips nLastPageWidthWithGap = nLastPageWidth; + if ( !mbBookMode || ( 0 == (nNumberOfVirtualPages + nNumberOfPagesInRow) %2) ) + nLastPageWidthWithGap += nGapBetweenPages; + + if ( mnColumns > 0 || nLastPageWidthWithGap < nRemain ) + { + ++nNumberOfVirtualPages; + nVirtualPagesWidth += nLastPageWidthWithGap; + } + nRemain = nRemain - nLastPageWidthWithGap; + } + + nCurrentRowWidth = nCurrentRowWidth + nVirtualPagesWidth; + } + + // first page in book mode is always special: + if ( bFirstRow && mbBookMode ) + { + // #i88036# + nCurrentRowWidth += + pStartOfRow->GetFormatPage().Frm().Width() + nSidebarWidth; + } + + // center page if possible + const long nSizeDiff = nVisWidth > nCurrentRowWidth ? + ( nVisWidth - nCurrentRowWidth ) / 2 : + 0; + + // adjust positions of pages in current row + long nX = nSizeDiff; + + const long nRowStart = nBorder + nSizeDiff; + const long nRowEnd = nRowStart + nCurrentRowWidth; + + if ( bFirstRow && mbBookMode ) + { + // #i88036# + nX += pStartOfRow->GetFormatPage().Frm().Width() + nSidebarWidth; + } + + SwPageFrm* pEndOfRow = pPageFrm; + SwPageFrm* pPageToAdjust = pStartOfRow; + + do + { + const SwPageFrm* pFormatPage = pPageToAdjust; + if ( mbBookMode ) + pFormatPage = &pPageToAdjust->GetFormatPage(); + + const SwTwips nCurrentPageWidth = pFormatPage->Frm().Width() + (pFormatPage->IsEmptyPage() ? 0 : nSidebarWidth); + const Point aOldPagePos = pPageToAdjust->Frm().Pos(); + const bool bLeftSidebar = pPageToAdjust->SidebarPosition() == sw::sidebarwindows::SIDEBAR_LEFT; + const SwTwips nLeftPageAddOffset = bLeftSidebar ? + nSidebarWidth : + 0; + + Point aNewPagePos( nBorder + nX, nBorder + nSumRowHeight ); + Point aNewPagePosWithLeftOffset( nBorder + nX + nLeftPageAddOffset, nBorder + nSumRowHeight ); + + // RTL view layout: Calculate mirrored page position + if ( bRTL ) + { + const long nXOffsetInRow = aNewPagePos.X() - nRowStart; + aNewPagePos.X() = nRowEnd - nXOffsetInRow - nCurrentPageWidth; + aNewPagePosWithLeftOffset = aNewPagePos; + aNewPagePosWithLeftOffset.X() += nLeftPageAddOffset; + } + + if ( aNewPagePosWithLeftOffset != aOldPagePos ) + { + lcl_MoveAllLowers( pPageToAdjust, aNewPagePosWithLeftOffset - aOldPagePos ); + pPageToAdjust->SetCompletePaint(); + bPageChanged = true; + } + + // calculate area covered by the current page and store to + // maPageRects. This is used e.g., for cursor setting + const bool bFirstColumn = pPageToAdjust == pStartOfRow; + const bool bLastColumn = pPageToAdjust->GetNext() == pEndOfRow; + const bool bLastRow = !pEndOfRow; + + nMinPageLeft = Min( nMinPageLeft, aNewPagePos.X() ); + nMaxPageRight = Max( nMaxPageRight, aNewPagePos.X() + nCurrentPageWidth); + + // border of nGapBetweenPages around the current page: + SwRect aPageRectWithBorders( aNewPagePos.X() - nGapBetweenPages, + aNewPagePos.Y(), + pPageToAdjust->Frm().SSize().Width() + nGapBetweenPages + nSidebarWidth, + nCurrentRowHeight ); + + static const long nOuterClickDiff = 1000000; + + // adjust borders for these special cases: + if ( (bFirstColumn && !bRTL) || (bLastColumn && bRTL) ) + aPageRectWithBorders.SubLeft( nOuterClickDiff ); + if ( (bLastColumn && !bRTL) || (bFirstColumn && bRTL) ) + aPageRectWithBorders.AddRight( nOuterClickDiff ); + if ( bFirstRow ) + aPageRectWithBorders.SubTop( nOuterClickDiff ); + if ( bLastRow ) + aPageRectWithBorders.AddBottom( nOuterClickDiff ); + + maPageRects.push_back( aPageRectWithBorders ); + + nX = nX + nCurrentPageWidth; + pPageToAdjust = static_cast<SwPageFrm*>(pPageToAdjust->GetNext()); + + // distance to next page + if ( pPageToAdjust && pPageToAdjust != pEndOfRow ) + { + // in book view, we add the x gap before left (even) pages: + if ( mbBookMode ) + { + if ( 0 == (pPageToAdjust->GetPhyPageNum()%2) ) + nX = nX + nGapBetweenPages; + } + else + { + // in non-book view, dont add x gap before + // 1. the last empty page in a row + // 2. after an empty page + const bool bDontAddGap = ( pPageToAdjust->IsEmptyPage() && pPageToAdjust->GetNext() == pEndOfRow ) || + ( static_cast<SwPageFrm*>(pPageToAdjust->GetPrev())->IsEmptyPage() ); + + if ( !bDontAddGap ) + nX = nX + nGapBetweenPages; + } + } + } + while ( pPageToAdjust != pEndOfRow ); + + // adjust values for root frame size + nSumRowHeight = nSumRowHeight + nCurrentRowHeight; + + // start new row: + nCurrentRowHeight = 0; + nCurrentRowWidth = 0; + pStartOfRow = pEndOfRow; + nWidthRemain = nVisWidth; + nNumberOfPagesInRow = 0; + bFirstRow = false; + } // end row finished + } // end while + + // set size of root frame: + const Size aOldSize( Frm().SSize() ); + const Size aNewSize( nMaxPageRight - nBorder, nSumRowHeight - nGapBetweenPages ); + + if ( bPageChanged || aNewSize != aOldSize ) + { + ChgSize( aNewSize ); + ::AdjustSizeChgNotify( this ); + Calc(); + + ViewShell* pSh = GetCurrShell(); + + if ( pSh && pSh->GetDoc()->GetDocShell() ) + { + pSh->SetFirstVisPageInvalid(); + if (bOldCallbackActionEnabled) + { + pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) ); + pSh->GetDoc()->GetDocShell()->Broadcast(SfxSimpleHint(SFX_HINT_DOCCHANGED)); + } + } + } + + maPagesArea.Pos( Frm().Pos() ); + maPagesArea.SSize( aNewSize ); + if ( TWIPS_MAX != nMinPageLeft ) + maPagesArea._Left( nMinPageLeft ); + + SetCallbackActionEnabled( bOldCallbackActionEnabled ); +} + +bool SwRootFrm::IsLeftToRightViewLayout() const +{ + // Layout direction determined by layout direction of the first page. + // --> OD 2008-04-08 #i88036# + // Only ask a non-empty page frame for its layout direction +// const SwPageFrm* pPage = dynamic_cast<const SwPageFrm*>(Lower()); +// return !pPage->IsRightToLeft() && !pPage->IsVertical(); + const SwPageFrm& rPage = + dynamic_cast<const SwPageFrm*>(Lower())->GetFormatPage(); + return !rPage.IsRightToLeft() && !rPage.IsVertical(); + // <-- +} + +const SwPageFrm& SwPageFrm::GetFormatPage() const +{ + const SwPageFrm* pRet = this; + if ( IsEmptyPage() ) + { + pRet = static_cast<const SwPageFrm*>( OnRightPage() ? GetNext() : GetPrev() ); + // --> OD 2008-04-08 #i88035# + // Typically a right empty page frame has a next non-empty page frame and + // a left empty page frame has a previous non-empty page frame. + // But under certain cirsumstances this assumption is not true - + // e.g. during insertion of a left page at the end of the document right + // after a left page in an intermediate state a right empty page does not + // have a next page frame. + if ( pRet == 0 ) + { + if ( OnRightPage() ) + { + pRet = static_cast<const SwPageFrm*>( GetPrev() ); + } + else + { + pRet = static_cast<const SwPageFrm*>( GetNext() ); + } + } + OSL_ENSURE( pRet, + "<SwPageFrm::GetFormatPage()> - inconsistent layout: empty page without previous and next page frame --> crash." ); + // <-- + } + return *pRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/pagedesc.cxx b/sw/source/core/layout/pagedesc.cxx new file mode 100644 index 000000000000..dec5a75becf5 --- /dev/null +++ b/sw/source/core/layout/pagedesc.cxx @@ -0,0 +1,487 @@ +/* -*- 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 <editeng/pbinitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/lrspitem.hxx> +#include "editeng/frmdiritem.hxx" +#include <fmtclds.hxx> +#include <fmtfsize.hxx> +#include <frmatr.hxx> +#include <pagefrm.hxx> +#include <pagedesc.hxx> +#include <frmfmt.hxx> +#include <fmtcol.hxx> // SwTxtFmtColl +#include <node.hxx> +#include <swtable.hxx> +#include <frmtool.hxx> +#include <doc.hxx> // fuer GetAttrPool +#include <poolfmt.hxx> +#include <switerator.hxx> + +/************************************************************************* +|* +|* SwPageDesc::SwPageDesc() +|* +|*************************************************************************/ + + + +SwPageDesc::SwPageDesc( const String& rName, SwFrmFmt *pFmt, SwDoc *pDc ) : + SwModify( 0 ), + aDescName( rName ), + aMaster( pDc->GetAttrPool(), rName, pFmt ), + aLeft( pDc->GetAttrPool(), rName, pFmt ), + aDepend( this, 0 ), + pFollow( this ), + nRegHeight( 0 ), + nRegAscent( 0 ), + eUse( (UseOnPage)(nsUseOnPage::PD_ALL | nsUseOnPage::PD_HEADERSHARE | nsUseOnPage::PD_FOOTERSHARE) ), + bLandscape( sal_False ), + aFtnInfo() +{ +} + +SwPageDesc::SwPageDesc( const SwPageDesc &rCpy ) : + SwModify( 0 ), + aDescName( rCpy.GetName() ), + aNumType( rCpy.GetNumType() ), + aMaster( rCpy.GetMaster() ), + aLeft( rCpy.GetLeft() ), + aDepend( this, (SwModify*)rCpy.aDepend.GetRegisteredIn() ), + pFollow( rCpy.pFollow ), + nRegHeight( rCpy.GetRegHeight() ), + nRegAscent( rCpy.GetRegAscent() ), + eUse( rCpy.ReadUseOn() ), + bLandscape( rCpy.GetLandscape() ), + aFtnInfo( rCpy.GetFtnInfo() ) +{ +} + +SwPageDesc & SwPageDesc::operator = (const SwPageDesc & rSrc) +{ + aDescName = rSrc.aDescName; + aNumType = rSrc.aNumType; + aMaster = rSrc.aMaster; + aLeft = rSrc.aLeft; + + if (rSrc.pFollow == &rSrc) + pFollow = this; + else + pFollow = rSrc.pFollow; + + nRegHeight = rSrc.nRegHeight; + nRegAscent = rSrc.nRegAscent; + eUse = rSrc.eUse; + bLandscape = rSrc.bLandscape; + return *this; +} + +SwPageDesc::~SwPageDesc() +{ +} + +/************************************************************************* +|* +|* SwPageDesc::Mirror() +|* +|* Beschreibung Gespiegelt werden nur die Raender. +|* Attribute wie Umrandung und dergleichen werden 1:1 kopiert. +|* +|*************************************************************************/ + + + +void SwPageDesc::Mirror() +{ + //Das Spiegeln findet nur beim RandAttribut statt, alle anderen Werte + //werden schlicht uebertragen. + SvxLRSpaceItem aLR( RES_LR_SPACE ); + const SvxLRSpaceItem &rLR = aMaster.GetLRSpace(); + aLR.SetLeft( rLR.GetRight() ); + aLR.SetRight( rLR.GetLeft() ); + + SfxItemSet aSet( *aMaster.GetAttrSet().GetPool(), + aMaster.GetAttrSet().GetRanges() ); + aSet.Put( aLR ); + aSet.Put( aMaster.GetFrmSize() ); + aSet.Put( aMaster.GetPaperBin() ); + aSet.Put( aMaster.GetULSpace() ); + aSet.Put( aMaster.GetBox() ); + aSet.Put( aMaster.GetBackground() ); + aSet.Put( aMaster.GetShadow() ); + aSet.Put( aMaster.GetCol() ); + aSet.Put( aMaster.GetFrmDir() ); // #112217# + aLeft.SetFmtAttr( aSet ); +} + +void SwPageDesc::ResetAllAttr( sal_Bool bLeft ) +{ + SwFrmFmt& rFmt = bLeft ? GetLeft() : GetMaster(); + + // --> OD 2007-01-25 #i73790# - method renamed + rFmt.ResetAllFmtAttr(); + // <-- + rFmt.SetFmtAttr( SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR) ); +} + +/************************************************************************* +|* +|* SwPageDesc::GetInfo() +|* +|* Beschreibung erfragt Informationen +|* +*************************************************************************/ + + + // erfrage vom Modify Informationen +sal_Bool SwPageDesc::GetInfo( SfxPoolItem & rInfo ) const +{ + if( !aMaster.GetInfo( rInfo ) ) + return sal_False; // found + return aLeft.GetInfo( rInfo ); +} + +/************************************************************************* +|* +|* SwPageDesc::SetRegisterFmtColl() +|* +|* Beschreibung setzt die Vorlage fuer die Registerhaltigkeit +|* +*************************************************************************/ + + +void SwPageDesc::SetRegisterFmtColl( const SwTxtFmtColl* pFmt ) +{ + if( pFmt != GetRegisterFmtColl() ) + { + if( pFmt ) + ((SwTxtFmtColl*)pFmt)->Add( &aDepend ); + else + ((SwTxtFmtColl*)GetRegisterFmtColl())->Remove( &aDepend ); + + RegisterChange(); + } +} + +/************************************************************************* +|* +|* SwPageDesc::GetRegisterFmtColl() +|* +|* Beschreibung holt die Vorlage fuer die Registerhaltigkeit +|* +*************************************************************************/ + + +const SwTxtFmtColl* SwPageDesc::GetRegisterFmtColl() const +{ + const SwModify* pReg = aDepend.GetRegisteredIn(); + return (SwTxtFmtColl*)pReg; +} + +/************************************************************************* +|* +|* SwPageDesc::RegisterChange() +|* +|* Beschreibung benachrichtigt alle betroffenen PageFrames +|* +*************************************************************************/ + + +void SwPageDesc::RegisterChange() +{ + // --> OD 2004-06-15 #117072# - During destruction of the document <SwDoc> + // the page description is modified. Thus, do nothing, if the document + // is in destruction respectively if no viewshell exists. + SwDoc* pDoc = GetMaster().GetDoc(); + if ( !pDoc || pDoc->IsInDtor() ) + { + return; + } + ViewShell* pSh = 0L; + pDoc->GetEditShell( &pSh ); + if ( !pSh ) + { + return; + } + + nRegHeight = 0; + { + SwIterator<SwFrm,SwFmt> aIter( GetMaster() ); + for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pLast->IsPageFrm() ) + ((SwPageFrm*)pLast)->PrepareRegisterChg(); + } + } + { + SwIterator<SwFrm,SwFmt> aIter( GetLeft() ); + for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pLast->IsPageFrm() ) + ((SwPageFrm*)pLast)->PrepareRegisterChg(); + } + } +} + +/************************************************************************* +|* +|* SwPageDesc::Modify() +|* +|* Beschreibung reagiert insbesondere auf Aenderungen +|* der Vorlage fuer die Registerhaltigkeit +|* +*************************************************************************/ + + +void SwPageDesc::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + NotifyClients( pOld, pNew ); + + if ( (RES_ATTRSET_CHG == nWhich) || (RES_FMT_CHG == nWhich) + || isCHRATR(nWhich) || (RES_PARATR_LINESPACING == nWhich) ) + { + RegisterChange(); + } +} + +static const SwFrm* lcl_GetFrmOfNode( const SwNode& rNd ) +{ + SwModify* pMod; + sal_uInt16 nFrmType = FRM_CNTNT; + + if( rNd.IsCntntNode() ) + { + pMod = &(SwCntntNode&)rNd; + } + else if( rNd.IsTableNode() ) + { + pMod = ((SwTableNode&)rNd).GetTable().GetFrmFmt(); + nFrmType = FRM_TAB; + } + else + pMod = 0; + + Point aNullPt; + return pMod ? ::GetFrmOfModify( 0, *pMod, nFrmType, &aNullPt, 0, sal_False ) + : 0; +} + +const SwPageDesc* SwPageDesc::GetPageDescOfNode(const SwNode& rNd) +{ + const SwPageDesc* pRet = 0; + const SwFrm* pChkFrm = lcl_GetFrmOfNode( rNd ); + if (pChkFrm && 0 != (pChkFrm = pChkFrm->FindPageFrm())) + pRet = ((const SwPageFrm*)pChkFrm)->GetPageDesc(); + return pRet; +} + +const SwFrmFmt* SwPageDesc::GetPageFmtOfNode( const SwNode& rNd, + sal_Bool bCheckForThisPgDc ) const +{ + // welches PageDescFormat ist fuer diesen Node gueltig? + const SwFrmFmt* pRet; + const SwFrm* pChkFrm = lcl_GetFrmOfNode( rNd ); + + if( pChkFrm && 0 != ( pChkFrm = pChkFrm->FindPageFrm() )) + { + const SwPageDesc* pPd = bCheckForThisPgDc ? this : + ((SwPageFrm*)pChkFrm)->GetPageDesc(); + pRet = &pPd->GetMaster(); + OSL_ENSURE( ((SwPageFrm*)pChkFrm)->GetPageDesc() == pPd, "Wrong node for detection of page format!" ); + // an welchem Format haengt diese Seite? + if( !pChkFrm->KnowsFormat(*pRet) ) + { + pRet = &pPd->GetLeft(); + OSL_ENSURE( pChkFrm->KnowsFormat(*pRet), "Wrong node for detection of page format!" ); + } + } + else + pRet = &GetMaster(); + return pRet; +} + +sal_Bool SwPageDesc::IsFollowNextPageOfNode( const SwNode& rNd ) const +{ + sal_Bool bRet = sal_False; + if( GetFollow() && this != GetFollow() ) + { + const SwFrm* pChkFrm = lcl_GetFrmOfNode( rNd ); + if( pChkFrm && 0 != ( pChkFrm = pChkFrm->FindPageFrm() ) && + pChkFrm->IsPageFrm() && + ( !pChkFrm->GetNext() || GetFollow() == + ((SwPageFrm*)pChkFrm->GetNext())->GetPageDesc() )) + // die Seite gefunden, auf die der Follow verweist + bRet = sal_True; + } + return bRet; +} + +/************************************************************************* +|* +|* SwPageFtnInfo::SwPageFtnInfo() +|* +|*************************************************************************/ + + + +SwPageFtnInfo::SwPageFtnInfo() : + nMaxHeight( 0 ), +// aPen( PEN_SOLID ), + nLineWidth(10), + eLineStyle( editeng::SOLID ), + aWidth( 25, 100 ), + nTopDist( 57 ), //1mm + nBottomDist( 57 ) +{ + eAdj = FRMDIR_HORI_RIGHT_TOP == GetDefaultFrameDirection(GetAppLanguage()) ? + FTNADJ_RIGHT : + FTNADJ_LEFT; +// aPen.SetWidth( 10 ); +} + + + +SwPageFtnInfo::SwPageFtnInfo( const SwPageFtnInfo &rCpy ) : + nMaxHeight( rCpy.GetHeight() ), + nLineWidth(rCpy.nLineWidth), + eLineStyle(rCpy.eLineStyle), + aLineColor(rCpy.aLineColor), + aWidth( rCpy.GetWidth() ), + eAdj( rCpy.GetAdj() ), + nTopDist( rCpy.GetTopDist() ), + nBottomDist( rCpy.GetBottomDist() ) +{ +} + +/************************************************************************* +|* +|* SwPageFtnInfo::operator= +|* +|*************************************************************************/ + + + +SwPageFtnInfo &SwPageFtnInfo::operator=( const SwPageFtnInfo& rCpy ) +{ + nMaxHeight = rCpy.GetHeight(); + nLineWidth = rCpy.nLineWidth; + eLineStyle = rCpy.eLineStyle; + aLineColor = rCpy.aLineColor; + aWidth = rCpy.GetWidth(); + eAdj = rCpy.GetAdj(); + nTopDist = rCpy.GetTopDist(); + nBottomDist = rCpy.GetBottomDist(); + return *this; +} +/************************************************************************* +|* +|* SwPageFtnInfo::operator== +|* +|*************************************************************************/ + + + +sal_Bool SwPageFtnInfo::operator==( const SwPageFtnInfo& rCmp ) const +{ + return ( nMaxHeight == rCmp.GetHeight() && + nLineWidth == rCmp.nLineWidth && + eLineStyle == rCmp.eLineStyle && + aLineColor == rCmp.aLineColor && + aWidth == rCmp.GetWidth() && + eAdj == rCmp.GetAdj() && + nTopDist == rCmp.GetTopDist() && + nBottomDist== rCmp.GetBottomDist() ); +} + +SwPageDescExt::SwPageDescExt(const SwPageDesc & rPageDesc, SwDoc * _pDoc) + : aPageDesc(rPageDesc), pDoc(_pDoc) +{ + SetPageDesc(rPageDesc); +} + +SwPageDescExt::SwPageDescExt(const SwPageDescExt & rSrc) + : aPageDesc(rSrc.aPageDesc), pDoc(rSrc.pDoc) +{ + SetPageDesc(rSrc.aPageDesc); +} + +SwPageDescExt::~SwPageDescExt() +{ +} + +const String & SwPageDescExt::GetName() const +{ + return aPageDesc.GetName(); +} + +void SwPageDescExt::SetPageDesc(const SwPageDesc & _aPageDesc) +{ + aPageDesc = _aPageDesc; + + if (aPageDesc.GetFollow()) + sFollow = aPageDesc.GetFollow()->GetName(); +} + +SwPageDescExt & SwPageDescExt::operator = (const SwPageDesc & rSrc) +{ + SetPageDesc(rSrc); + + return *this; +} + +SwPageDescExt & SwPageDescExt::operator = (const SwPageDescExt & rSrc) +{ + SetPageDesc(rSrc.aPageDesc); + + return *this; +} + +SwPageDescExt::operator SwPageDesc() const +{ + SwPageDesc aResult(aPageDesc); + + SwPageDesc * pPageDesc = pDoc->GetPageDesc(sFollow); + + if ( 0 != pPageDesc ) + aResult.SetFollow(pPageDesc); + + return aResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/pagefrm.src b/sw/source/core/layout/pagefrm.src new file mode 100644 index 000000000000..1c5cafc38c4d --- /dev/null +++ b/sw/source/core/layout/pagefrm.src @@ -0,0 +1,7 @@ +#include "pagefrm.hrc" + +Bitmap BMP_PAGE_SHADOW_MASK +{ + File = "page-shadow-mask.png"; +}; + diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx new file mode 100644 index 000000000000..8744151ef0e2 --- /dev/null +++ b/sw/source/core/layout/paintfrm.cxx @@ -0,0 +1,6701 @@ +/* -*- 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 <com/sun/star/text/HoriOrientation.hpp> +#include <hintids.hxx> +#include <vcl/sound.hxx> +#include <tools/poly.hxx> +#include <svl/svstdarr.hxx> +#include <svx/xoutbmp.hxx> +#include <sfx2/progress.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/shaditem.hxx> +#include <svx/framelink.hxx> +#include <vcl/graph.hxx> +#include <svx/svdpagv.hxx> +#include <tgrditem.hxx> +#include <switerator.hxx> +#include <fmtsrnd.hxx> +#include <fmtclds.hxx> +#include <tools/shl.hxx> +#include <comcore.hrc> +#include <swmodule.hxx> +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <viewsh.hxx> +#include <section.hxx> +#include <sectfrm.hxx> +#include <doc.hxx> +#include <viewimp.hxx> +#include <dflyobj.hxx> +#include <flyfrm.hxx> +#include <frmtool.hxx> +#include <viewopt.hxx> +#include <dview.hxx> +#include <dcontact.hxx> +#include <txtfrm.hxx> +#include <ftnfrm.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <notxtfrm.hxx> +#include <swregion.hxx> +#include <layact.hxx> +#include <pagedesc.hxx> +#include <ptqueue.hxx> +#include <noteurl.hxx> +#include <virtoutp.hxx> +#include <lineinfo.hxx> +#include <dbg_lay.hxx> +#include <accessibilityoptions.hxx> +#include <docsh.hxx> +#include <swtable.hxx> +#include <svx/svdogrp.hxx> +#include <sortedobjs.hxx> +#include <EnhancedPDFExportHelper.hxx> +#include <ndole.hxx> +#include <svtools/chartprettypainter.hxx> +#include <PostItMgr.hxx> +#include <tools/color.hxx> +#include <vcl/svapp.hxx> + +#define COL_NOTES_SIDEPANE RGB_COLORDATA(230,230,230) +#define COL_NOTES_SIDEPANE_BORDER RGB_COLORDATA(200,200,200) +#define COL_NOTES_SIDEPANE_SCROLLAREA RGB_COLORDATA(230,230,220) + +#include <svtools/borderhelper.hxx> + +#include "pagefrm.hrc" +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> +#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx> +#include <svx/sdr/contact/objectcontacttools.hxx> +#include <svx/unoapi.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +using namespace ::editeng; +using namespace ::com::sun::star; + +#define GETOBJSHELL() ((SfxObjectShell*)rSh.GetDoc()->GetDocShell()) + +//Tabellenhilfslinien an? +#define IS_SUBS_TABLE \ + (pGlobalShell->GetViewOptions()->IsTable() && \ + !pGlobalShell->GetViewOptions()->IsPagePreview()&&\ + !pGlobalShell->GetViewOptions()->IsReadonly()&&\ + !pGlobalShell->GetViewOptions()->IsFormView() &&\ + SwViewOption::IsTableBoundaries()) +//sonstige Hilfslinien an? +#define IS_SUBS (!pGlobalShell->GetViewOptions()->IsPagePreview() && \ + !pGlobalShell->GetViewOptions()->IsReadonly() && \ + !pGlobalShell->GetViewOptions()->IsFormView() &&\ + SwViewOption::IsDocBoundaries()) +//Hilfslinien fuer Bereiche +#define IS_SUBS_SECTION (!pGlobalShell->GetViewOptions()->IsPagePreview() && \ + !pGlobalShell->GetViewOptions()->IsReadonly()&&\ + !pGlobalShell->GetViewOptions()->IsFormView() &&\ + SwViewOption::IsSectionBoundaries()) +#define IS_SUBS_FLYS (!pGlobalShell->GetViewOptions()->IsPagePreview() && \ + !pGlobalShell->GetViewOptions()->IsReadonly()&&\ + !pGlobalShell->GetViewOptions()->IsFormView() &&\ + SwViewOption::IsObjectBoundaries()) + +#define SW_MAXBORDERCACHE 20 + +//Klassendeklarationen. Hier weil sie eben nur in diesem File benoetigt +//werden. + +#define SUBCOL_PAGE 0x01 //Helplines of the page +#define SUBCOL_BREAK 0x02 //Helpline for a page or column break +#define SUBCOL_TAB 0x08 //Helplines inside tables +#define SUBCOL_FLY 0x10 //Helplines inside fly frames +#define SUBCOL_SECT 0x20 //Helplines inside sections + +//----- Klassen zum Sammeln von Umrandungen und Hilfslinien --- +class SwLineRect : public SwRect +{ + Color aColor; + SvxBorderStyle nStyle; + const SwTabFrm *pTab; + sal_uInt8 nSubColor; //Hilfslinien einfaerben + sal_Bool bPainted; //schon gepaintet? + sal_uInt8 nLock; //Um die Linien zum Hell-Layer abzugrenzen. +public: + SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderStyle nStyle, + const SwTabFrm *pT , const sal_uInt8 nSCol ); + + const Color *GetColor() const { return &aColor;} + SvxBorderStyle GetStyle() const { return nStyle; } + const SwTabFrm *GetTab() const { return pTab; } + void SetPainted() { bPainted = sal_True; } + void Lock( sal_Bool bLock ) { if ( bLock ) + ++nLock; + else if ( nLock ) + --nLock; + } + sal_Bool IsPainted() const { return bPainted; } + sal_Bool IsLocked() const { return nLock != 0; } + sal_uInt8 GetSubColor() const { return nSubColor;} + + sal_Bool MakeUnion( const SwRect &rRect ); +}; + +SV_DECL_VARARR( SwLRects, SwLineRect, 100, 100 ) + +class SwLineRects : public SwLRects +{ + sal_uInt16 nLastCount; //unuetze Durchlaeufe im PaintLines verhindern. +public: + SwLineRects() : nLastCount( 0 ) {} + void AddLineRect( const SwRect& rRect, const Color *pColor, const SvxBorderStyle nStyle, + const SwTabFrm *pTab, const sal_uInt8 nSCol ); + void ConnectEdges( OutputDevice *pOut ); + void PaintLines ( OutputDevice *pOut ); + void LockLines( sal_Bool bLock ); + + /// OD 13.08.2002 - correct type of function + sal_uInt16 Free() const { return nFree; } +}; + +class SwSubsRects : public SwLineRects +{ + void RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects ); //;-) +public: + void PaintSubsidiary( OutputDevice *pOut, const SwLineRects *pRects ); + + inline void Ins( const SwRect &rRect, const sal_uInt8 nSCol ); +}; + +//----------------- End Klassen Umrandungen ---------------------- + +static ViewShell *pGlobalShell = 0; + +//Wenn durchsichtige FlyInCnts im PaintBackground gepainted werden so soll der +//Hintergrund nicht mehr retouchiert werden. +//static sal_Bool bLockFlyBackground = sal_False; + +//Wenn vom Fly ein Metafile abgezogen wird, so soll nur der FlyInhalt und vor +//nur hintergrund vom FlyInhalt gepaintet werden. +static sal_Bool bFlyMetafile = sal_False; +static OutputDevice *pFlyMetafileOut = 0; + +//Die Retouche fuer Durchsichtige Flys wird vom Hintergrund der Flys +//erledigt. Dabei darf der Fly selbst natuerlich nicht ausgespart werden. +//siehe PaintBackground und lcl_SubtractFlys() +static SwFlyFrm *pRetoucheFly = 0; +static SwFlyFrm *pRetoucheFly2 = 0; + +//Groesse eines Pixel und die Haelfte davon. Wird jeweils bei Eintritt in +//SwRootFrm::Paint neu gesetzt. +static long nPixelSzW = 0, nPixelSzH = 0; +static long nHalfPixelSzW = 0, nHalfPixelSzH = 0; +static long nMinDistPixelW = 0, nMinDistPixelH = 0; + +//Aktueller Zoomfaktor +static double aScaleX = 1.0; +static double aScaleY = 1.0; +static double aMinDistScale = 0.73; +static double aEdgeScale = 0.5; + +//In pLines werden Umrandungen waehrend des Paint gesammelt und soweit +//moeglich zusammengefasst. +//In pSubsLines werden Hilfslinien gesammelt und zusammengefasst. Diese +//werden vor der Ausgabe mit pLines abgeglichen, so dass moeglichst keine +//Umrandungen von den Hilfslinen verdeckt werden. +//bTablines ist waerend des Paints einer Tabelle sal_True. +static SwLineRects *pLines = 0; +static SwSubsRects *pSubsLines = 0; +// OD 18.11.2002 #99672# - global variable for sub-lines of body, header, footer, +// section and footnote frames. +static SwSubsRects *pSpecSubsLines = 0; + +static SfxProgress *pProgress = 0; + +static SwFlyFrm *pFlyOnlyDraw = 0; + +//Damit die Flys auch fuer den Hack richtig gepaintet werden koennen. +static sal_Bool bTableHack = sal_False; + +//Um das teure Ermitteln der RetoucheColor zu optimieren +Color aGlobalRetoucheColor; + +//Statics fuer Umrandungsalignment setzen. +// OD 05.05.2003 #107169# - adjustment for 'small' twip-to-pixel relations: +// For 'small' twip-to-pixel relations (less then 2:1) +// values of <nHalfPixelSzW> and <nHalfPixelSzH> are set to ZERO. +void SwCalcPixStatics( OutputDevice *pOut ) +{ + // OD 30.04.2003 #107169# - determine 'small' twip-to-pixel relation + sal_Bool bSmallTwipToPxRelW = sal_False; + sal_Bool bSmallTwipToPxRelH = sal_False; + { + Size aCheckTwipToPxRelSz( pOut->PixelToLogic( Size( 100, 100 )) ); + if ( (aCheckTwipToPxRelSz.Width()/100.0) < 2.0 ) + { + bSmallTwipToPxRelW = sal_True; + } + if ( (aCheckTwipToPxRelSz.Height()/100.0) < 2.0 ) + { + bSmallTwipToPxRelH = sal_True; + } + } + + Size aSz( pOut->PixelToLogic( Size( 1,1 )) ); + + nPixelSzW = aSz.Width(); + if( !nPixelSzW ) + nPixelSzW = 1; + nPixelSzH = aSz.Height(); + if( !nPixelSzH ) + nPixelSzH = 1; + + // OD 06.05.2003 #107169# - consider 'small' twip-to-pixel relations + if ( !bSmallTwipToPxRelW ) + { + nHalfPixelSzW = nPixelSzW / 2 + 1; + } + else + { + nHalfPixelSzW = 0; + } + // OD 06.05.2003 #107169# - consider 'small' twip-to-pixel relations + if ( !bSmallTwipToPxRelH ) + { + nHalfPixelSzH = nPixelSzH / 2 + 1; + } + else + { + nHalfPixelSzH = 0; + } + + nMinDistPixelW = nPixelSzW * 2 + 1; + nMinDistPixelH = nPixelSzH * 2 + 1; + + const MapMode &rMap = pOut->GetMapMode(); + aScaleX = rMap.GetScaleX(); + aScaleY = rMap.GetScaleY(); +} + +//Zum Sichern der statics, damit das Paint (quasi) reentrant wird. +class SwSavePaintStatics +{ + sal_Bool bSFlyMetafile, + bSPageOnly; + ViewShell *pSGlobalShell; + OutputDevice *pSFlyMetafileOut; + SwFlyFrm *pSRetoucheFly, + *pSRetoucheFly2, + *pSFlyOnlyDraw; + SwLineRects *pSLines; + SwSubsRects *pSSubsLines; + // --> OD 2005-07-04 #123196# + SwSubsRects* pSSpecSubsLines; + // <-- + SfxProgress *pSProgress; + long nSPixelSzW, + nSPixelSzH, + nSHalfPixelSzW, + nSHalfPixelSzH, + nSMinDistPixelW, + nSMinDistPixelH; + Color aSGlobalRetoucheColor; + double aSScaleX, + aSScaleY; +public: + SwSavePaintStatics(); + ~SwSavePaintStatics(); +}; + +SwSavePaintStatics::SwSavePaintStatics() : + bSFlyMetafile ( bFlyMetafile ), + pSGlobalShell ( pGlobalShell ), + pSFlyMetafileOut ( pFlyMetafileOut ), + pSRetoucheFly ( pRetoucheFly ), + pSRetoucheFly2 ( pRetoucheFly2 ), + pSFlyOnlyDraw ( pFlyOnlyDraw ), + pSLines ( pLines ), + pSSubsLines ( pSubsLines ), + // --> OD 2005-07-04 #123196# + pSSpecSubsLines ( pSpecSubsLines ), + // <-- + pSProgress ( pProgress ), + nSPixelSzW ( nPixelSzW ), + nSPixelSzH ( nPixelSzH ), + nSHalfPixelSzW ( nHalfPixelSzW ), + nSHalfPixelSzH ( nHalfPixelSzH ), + nSMinDistPixelW ( nMinDistPixelW ), + nSMinDistPixelH ( nMinDistPixelH ), + aSGlobalRetoucheColor( aGlobalRetoucheColor ), + aSScaleX ( aScaleX ), + aSScaleY ( aScaleY ) +{ + bFlyMetafile = sal_False; + pFlyMetafileOut = 0; + pRetoucheFly = 0; + pRetoucheFly2 = 0; + nPixelSzW = nPixelSzH = + nHalfPixelSzW = nHalfPixelSzH = + nMinDistPixelW = nMinDistPixelH = 0; + aScaleX = aScaleY = 1.0; + aMinDistScale = 0.73; + aEdgeScale = 0.5; + pLines = 0; + pSubsLines = 0; + // --> OD 2005-07-04 #123196# + pSpecSubsLines = 0L; + // <-- + pProgress = 0; +} + +SwSavePaintStatics::~SwSavePaintStatics() +{ + pGlobalShell = pSGlobalShell; + bFlyMetafile = bSFlyMetafile; + pFlyMetafileOut = pSFlyMetafileOut; + pRetoucheFly = pSRetoucheFly; + pRetoucheFly2 = pSRetoucheFly2; + pFlyOnlyDraw = pSFlyOnlyDraw; + pLines = pSLines; + pSubsLines = pSSubsLines; + // --> OD 2005-07-04 #123196# + pSpecSubsLines = pSSpecSubsLines; + // <-- + pProgress = pSProgress; + nPixelSzW = nSPixelSzW; + nPixelSzH = nSPixelSzH; + nHalfPixelSzW = nSHalfPixelSzW; + nHalfPixelSzH = nSHalfPixelSzH; + nMinDistPixelW = nSMinDistPixelW; + nMinDistPixelH = nSMinDistPixelH; + aGlobalRetoucheColor = aSGlobalRetoucheColor; + aScaleX = aSScaleX; + aScaleY = aSScaleY; +} + +//----------------- Implementierungen fuer Tabellenumrandung -------------- + +SV_IMPL_VARARR( SwLRects, SwLineRect ); + +SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderStyle nStyl, + const SwTabFrm *pT, const sal_uInt8 nSCol ) : + SwRect( rRect ), + nStyle( nStyl ), + pTab( pT ), + nSubColor( nSCol ), + bPainted( sal_False ), + nLock( 0 ) +{ + if ( pCol != NULL ) + aColor = *pCol; +} + +sal_Bool SwLineRect::MakeUnion( const SwRect &rRect ) +{ + //Es wurde bereits ausserhalb geprueft, ob die Rechtecke die gleiche + //Ausrichtung (horizontal bzw. vertikal), Farbe usw. besitzen. + if ( Height() > Width() ) //Vertikale Linie + { + if ( Left() == rRect.Left() && Width() == rRect.Width() ) + { + //Zusammenfassen wenn kein Luecke zwischen den Linien ist. + const long nAdd = nPixelSzW + nHalfPixelSzW; + if ( Bottom() + nAdd >= rRect.Top() && + Top() - nAdd <= rRect.Bottom() ) + { + Bottom( Max( Bottom(), rRect.Bottom() ) ); + Top ( Min( Top(), rRect.Top() ) ); + return sal_True; + } + } + } + else + { + if ( Top() == rRect.Top() && Height() == rRect.Height() ) + { + //Zusammenfassen wenn kein Luecke zwischen den Linien ist. + const long nAdd = nPixelSzW + nHalfPixelSzW; + if ( Right() + nAdd >= rRect.Left() && + Left() - nAdd <= rRect.Right() ) + { + Right( Max( Right(), rRect.Right() ) ); + Left ( Min( Left(), rRect.Left() ) ); + return sal_True; + } + } + } + return sal_False; +} + +void SwLineRects::AddLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderStyle nStyle, + const SwTabFrm *pTab, const sal_uInt8 nSCol ) +{ + //Rueckwaerts durch, weil Linien die zusammengefasst werden koennen i.d.R. + //im gleichen Kontext gepaintet werden. + for ( sal_uInt16 i = Count(); i ; ) + { + SwLineRect &rLRect = operator[](--i); + //Pruefen von Ausrichtung, Farbe, Tabelle. + if ( rLRect.GetTab() == pTab && + !rLRect.IsPainted() && rLRect.GetSubColor() == nSCol && + (rLRect.Height() > rLRect.Width()) == (rRect.Height() > rRect.Width()) && + ((!rLRect.GetColor() && !pCol) || + (rLRect.GetColor() && pCol && *rLRect.GetColor() == *pCol)) ) + { + if ( rLRect.MakeUnion( rRect ) ) + return; + } + } + Insert( SwLineRect( rRect, pCol, nStyle, pTab, nSCol ), Count() ); +} + +void SwLineRects::ConnectEdges( OutputDevice *pOut ) +{ + if ( pOut->GetOutDevType() != OUTDEV_PRINTER ) + { + //Fuer einen zu kleinen Zoom arbeite ich nicht. + if ( aScaleX < aEdgeScale || aScaleY < aEdgeScale ) + return; + } + + static const long nAdd = 20; + + SvPtrarr aCheck( 64, 64 ); + + for ( int i = 0; i < (int)Count(); ++i ) + { + SwLineRect &rL1 = operator[](sal_uInt16(i)); + if ( !rL1.GetTab() || rL1.IsPainted() || rL1.IsLocked() ) + continue; + + aCheck.Remove( 0, aCheck.Count() ); + + const sal_Bool bVert = rL1.Height() > rL1.Width(); + long nL1a, nL1b, nL1c, nL1d; + + if ( bVert ) + { + nL1a = rL1.Top(); nL1b = rL1.Left(); + nL1c = rL1.Right(); nL1d = rL1.Bottom(); + } + else + { + nL1a = rL1.Left(); nL1b = rL1.Top(); + nL1c = rL1.Bottom(); nL1d = rL1.Right(); + } + + //Alle moeglicherweise mit i1 zu verbindenden Linien einsammeln. + for ( sal_uInt16 i2 = 0; i2 < Count(); ++i2 ) + { + SwLineRect &rL2 = operator[](i2); + if ( rL2.GetTab() != rL1.GetTab() || + rL2.IsPainted() || + rL2.IsLocked() || + (bVert == (rL2.Height() > rL2.Width())) ) + continue; + + long nL2a, nL2b, nL2c, nL2d; + if ( bVert ) + { + nL2a = rL2.Top(); nL2b = rL2.Left(); + nL2c = rL2.Right(); nL2d = rL2.Bottom(); + } + else + { + nL2a = rL2.Left(); nL2b = rL2.Top(); + nL2c = rL2.Bottom(); nL2d = rL2.Right(); + } + + if ( (nL1a - nAdd < nL2d && nL1d + nAdd > nL2a) && + ((nL1b > nL2b && nL1c < nL2c) || + (nL1c >= nL2c && nL1b - nAdd < nL2c) || + (nL1b <= nL2b && nL1c + nAdd > nL2b)) ) + { + SwLineRect *pMSC = &rL2; + aCheck.Insert( pMSC, aCheck.Count() ); + } + } + if ( aCheck.Count() < 2 ) + continue; + + sal_Bool bRemove = sal_False; + + //Fuer jede Linie jede alle folgenden checken. + for ( sal_uInt16 k = 0; !bRemove && k < aCheck.Count(); ++k ) + { + SwLineRect &rR1 = (SwLineRect&)*(SwLineRect*)aCheck[k]; + + for ( sal_uInt16 k2 = k+1; !bRemove && k2 < aCheck.Count(); ++k2 ) + { + SwLineRect &rR2 = (SwLineRect&)*(SwLineRect*)aCheck[k2]; + if ( bVert ) + { + SwLineRect *pLA = 0; + SwLineRect *pLB = 0; + if ( rR1.Top() < rR2.Top() ) + { + pLA = &rR1; pLB = &rR2; + } + else if ( rR1.Top() > rR2.Top() ) + { + pLA = &rR2; pLB = &rR1; + } + //beschreiben k1 und k2 eine Doppellinie? + if ( pLA && pLA->Bottom() + 60 > pLB->Top() ) + { + if ( rL1.Top() < pLA->Top() ) + { + if ( rL1.Bottom() == pLA->Bottom() ) + continue; //kleiner Irrtum (woher?) + + SwRect aIns( rL1 ); + aIns.Bottom( pLA->Bottom() ); + if ( !rL1.IsInside( aIns ) ) + continue; + const sal_uInt16 nTmpFree = Free(); + Insert( SwLineRect( aIns, rL1.GetColor(), SOLID, + rL1.GetTab(), SUBCOL_TAB ), Count() ); + if ( !nTmpFree ) + { + --i; + k = aCheck.Count(); + break; + } + } + + if ( rL1.Bottom() > pLB->Bottom() ) + rL1.Top( pLB->Top() ); //i1 nach oben verlaengern + else + bRemove = sal_True; //abbrechen, i1 entfernen + } + } + else + { + SwLineRect *pLA = 0; + SwLineRect *pLB = 0; + if ( rR1.Left() < rR2.Left() ) + { + pLA = &rR1; pLB = &rR2; + } + else if ( rR1.Left() > rR2.Left() ) + { + pLA = &rR2; pLB = &rR1; + } + //Liegt eine 'doppellinie' vor? + if ( pLA && pLA->Right() + 60 > pLB->Left() ) + { + if ( rL1.Left() < pLA->Left() ) + { + if ( rL1.Right() == pLA->Right() ) + continue; //kleiner irrtum + + SwRect aIns( rL1 ); + aIns.Right( pLA->Right() ); + if ( !rL1.IsInside( aIns ) ) + continue; + const sal_uInt16 nTmpFree = Free(); + Insert( SwLineRect( aIns, rL1.GetColor(), SOLID, + rL1.GetTab(), SUBCOL_TAB ), Count() ); + if ( !nTmpFree ) + { + --i; + k = aCheck.Count(); + break; + } + } + if ( rL1.Right() > pLB->Right() ) + rL1.Left( pLB->Left() ); + else + bRemove = sal_True; + } + } + } + } + if ( bRemove ) + { + Remove( static_cast<sal_uInt16>(i), 1 ); + --i; //keinen auslassen! + } + } +} + +inline void SwSubsRects::Ins( const SwRect &rRect, const sal_uInt8 nSCol ) +{ + //Linien die kuerzer als die breiteste Linienbreite sind werden + //nicht aufgenommen. + if ( rRect.Height() > DEF_LINE_WIDTH_4 || rRect.Width() > DEF_LINE_WIDTH_4 ) + Insert( SwLineRect( rRect, 0, SOLID, 0, nSCol ), Count()); +} + +void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects ) +{ + //Alle Hilfslinien, die sich mit irgendwelchen Umrandungen decken werden + //entfernt bzw. zerstueckelt.. + for ( sal_uInt16 i = 0; i < Count(); ++i ) + { + // OD 18.11.2002 #99672# - get a copy instead of a reference, because + // an <insert> may destroy the object due to a necessary array resize. + const SwLineRect aSubsLineRect = SwLineRect( operator[](i) ); + + // OD 19.12.2002 #106318# - add condition <aSubsLineRect.IsLocked()> + // in order to consider only border lines, which are *not* locked. + if ( aSubsLineRect.IsPainted() || + aSubsLineRect.IsLocked() ) + continue; + + const bool bVerticalSubs = aSubsLineRect.Height() > aSubsLineRect.Width(); + SwRect aSubsRect( aSubsLineRect ); + if ( bVerticalSubs ) + { + aSubsRect.Left ( aSubsRect.Left() - (nPixelSzW+nHalfPixelSzW) ); + aSubsRect.Right ( aSubsRect.Right() + (nPixelSzW+nHalfPixelSzW) ); + } + else + { + aSubsRect.Top ( aSubsRect.Top() - (nPixelSzH+nHalfPixelSzH) ); + aSubsRect.Bottom( aSubsRect.Bottom() + (nPixelSzH+nHalfPixelSzH) ); + } + for ( sal_uInt16 k = 0; k < rRects.Count(); ++k ) + { + SwLineRect &rLine = rRects[k]; + + // OD 20.12.2002 #106318# - do *not* consider painted or locked + // border lines. + // OD 20.01.2003 #i1837# - locked border lines have to be considered. + if ( rLine.IsLocked () ) + continue; + + if ( !bVerticalSubs == ( rLine.Height() > rLine.Width() ) ) //same direction? + continue; + + if ( aSubsRect.IsOver( rLine ) ) + { + if ( bVerticalSubs ) // Vertical? + { + if ( aSubsRect.Left() <= rLine.Right() && + aSubsRect.Right() >= rLine.Left() ) + { + long nTmp = rLine.Top()-(nPixelSzH+1); + if ( aSubsLineRect.Top() < nTmp ) + { + SwRect aNewSubsRect( aSubsLineRect ); + aNewSubsRect.Bottom( nTmp ); + Insert( SwLineRect( aNewSubsRect, 0, aSubsLineRect.GetStyle(), 0, + aSubsLineRect.GetSubColor() ), Count()); + } + nTmp = rLine.Bottom()+nPixelSzH+1; + if ( aSubsLineRect.Bottom() > nTmp ) + { + SwRect aNewSubsRect( aSubsLineRect ); + aNewSubsRect.Top( nTmp ); + Insert( SwLineRect( aNewSubsRect, 0, aSubsLineRect.GetStyle(), 0, + aSubsLineRect.GetSubColor() ), Count()); + } + Remove( i, 1 ); + --i; + break; + } + } + else //Horizontal + { + if ( aSubsRect.Top() <= rLine.Bottom() && + aSubsRect.Bottom() >= rLine.Top() ) + { + long nTmp = rLine.Left()-(nPixelSzW+1); + if ( aSubsLineRect.Left() < nTmp ) + { + SwRect aNewSubsRect( aSubsLineRect ); + aNewSubsRect.Right( nTmp ); + Insert( SwLineRect( aNewSubsRect, 0, aSubsLineRect.GetStyle(), 0, + aSubsLineRect.GetSubColor() ), Count()); + } + nTmp = rLine.Right()+nPixelSzW+1; + if ( aSubsLineRect.Right() > nTmp ) + { + SwRect aNewSubsRect( aSubsLineRect ); + aNewSubsRect.Left( nTmp ); + Insert( SwLineRect( aNewSubsRect, 0, aSubsLineRect.GetStyle(), 0, + aSubsLineRect.GetSubColor() ), Count()); + } + Remove( i, 1 ); + --i; + break; + } + } + } + } + } +} + +void SwLineRects::LockLines( sal_Bool bLock ) +{ + for ( sal_uInt16 i = 0; i < Count(); ++i ) + operator[](i).Lock( bLock ); +} + +void lcl_DrawDashedRect( OutputDevice * pOut, SwLineRect & rLRect ) +{ + double nHalfLWidth = rLRect.Height( ); + if ( nHalfLWidth > 1 ) + { + nHalfLWidth = nHalfLWidth / 2; + } + else + { + nHalfLWidth = 1; + } + + long startX = rLRect.Left( ); + long startY = rLRect.Top( ) + nHalfLWidth; + long endX = rLRect.Left( ) + rLRect.Width( ); + long endY = rLRect.Top( ) + nHalfLWidth; + + if ( rLRect.Height( ) > rLRect.Width( ) ) + { + nHalfLWidth = rLRect.Width( ); + if ( nHalfLWidth > 1 ) + { + nHalfLWidth = nHalfLWidth / 2; + } + else + { + nHalfLWidth = 1; + } + startX = rLRect.Left( ) + nHalfLWidth; + startY = rLRect.Top( ); + endX = rLRect.Left( ) + nHalfLWidth; + endY = rLRect.Top( ) + rLRect.Height( ); + } + + svtools::DrawLine( *pOut, Point( startX, startY ), Point( endX, endY ), + sal_uInt32( nHalfLWidth * 2 ), rLRect.GetStyle( ) ); +} + +void SwLineRects::PaintLines( OutputDevice *pOut ) +{ + //Painten der Umrandungen. Leider muessen wir zweimal durch. + //Einmal fuer die innenliegenden und einmal fuer die Aussenkanten + //der Tabellen. + if ( Count() != nLastCount ) + { + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pOut ); + // <-- + + // OD 2004-04-23 #116347# + pOut->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOut->SetFillColor(); + pOut->SetLineColor(); + ConnectEdges( pOut ); + const Color *pLast = 0; + + sal_Bool bPaint2nd = sal_False; + sal_uInt16 nMinCount = Count(); + sal_uInt16 i; + + for ( i = 0; i < Count(); ++i ) + { + SwLineRect &rLRect = operator[](i); + + if ( rLRect.IsPainted() ) + continue; + + if ( rLRect.IsLocked() ) + { + nMinCount = Min( nMinCount, i ); + continue; + } + + //Jetzt malen oder erst in der zweiten Runde? + sal_Bool bPaint = sal_True; + if ( rLRect.GetTab() ) + { + if ( rLRect.Height() > rLRect.Width() ) + { + //Senkrechte Kante, ueberlappt sie mit der TabellenKante? + SwTwips nLLeft = rLRect.Left() - 30, + nLRight = rLRect.Right() + 30, + nTLeft = rLRect.GetTab()->Frm().Left() + rLRect.GetTab()->Prt().Left(), + nTRight = rLRect.GetTab()->Frm().Left() + rLRect.GetTab()->Prt().Right(); + if ( (nTLeft >= nLLeft && nTLeft <= nLRight) || + (nTRight>= nLLeft && nTRight<= nLRight) ) + bPaint = sal_False; + } + else + { //Waagerechte Kante, ueberlappt sie mit der Tabellenkante? + SwTwips nLTop = rLRect.Top() - 30, + nLBottom = rLRect.Bottom() + 30, + nTTop = rLRect.GetTab()->Frm().Top() + rLRect.GetTab()->Prt().Top(), + nTBottom = rLRect.GetTab()->Frm().Top() + rLRect.GetTab()->Prt().Bottom(); + if ( (nTTop >= nLTop && nTTop <= nLBottom) || + (nTBottom >= nLTop && nTBottom <= nLBottom) ) + bPaint = sal_False; + } + } + if ( bPaint ) + { + if ( !pLast || *pLast != *rLRect.GetColor() ) + { + pLast = rLRect.GetColor(); + + sal_uLong nOldDrawMode = pOut->GetDrawMode(); + if( pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + pOut->SetDrawMode( 0 ); + + pOut->SetLineColor( *pLast ); + pOut->SetFillColor( *pLast ); + pOut->SetDrawMode( nOldDrawMode ); + } + + if( !rLRect.IsEmpty() ) + lcl_DrawDashedRect( pOut, rLRect ); + rLRect.SetPainted(); + } + else + bPaint2nd = sal_True; + } + if ( bPaint2nd ) + for ( i = 0; i < Count(); ++i ) + { + SwLineRect &rLRect = operator[](i); + if ( rLRect.IsPainted() ) + continue; + + if ( rLRect.IsLocked() ) + { + nMinCount = Min( nMinCount, i ); + continue; + } + + if ( !pLast || *pLast != *rLRect.GetColor() ) + { + pLast = rLRect.GetColor(); + + sal_uLong nOldDrawMode = pOut->GetDrawMode(); + if( pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + pOut->SetDrawMode( 0 ); + } + + pOut->SetFillColor( *pLast ); + pOut->SetDrawMode( nOldDrawMode ); + } + if( !rLRect.IsEmpty() ) + lcl_DrawDashedRect( pOut, rLRect ); + rLRect.SetPainted(); + } + nLastCount = nMinCount; + pOut->Pop(); + } +} + +void SwSubsRects::PaintSubsidiary( OutputDevice *pOut, + const SwLineRects *pRects ) +{ + if ( Count() ) + { + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pOut ); + // <-- + + //Alle Hilfslinien, die sich fast decken entfernen (Tabellen) + for ( sal_uInt16 i = 0; i < Count(); ++i ) + { + SwLineRect &rLi = operator[](i); + const bool bVerticalSubs = rLi.Height() > rLi.Width(); + + for ( sal_uInt16 k = i+1; k < Count(); ++k ) + { + SwLineRect &rLk = operator[](k); + if ( rLi.SSize() == rLk.SSize() ) + { + if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) ) + { + if ( bVerticalSubs ) + { + long nLi = rLi.Right(); + long nLk = rLk.Right(); + if ( rLi.Top() == rLk.Top() && + ((nLi < rLk.Left() && nLi+21 > rLk.Left()) || + (nLk < rLi.Left() && nLk+21 > rLi.Left()))) + { + Remove( k, 1 ); + //Nicht mit der inneren Schleife weiter, weil + //das Array schrumpfen koennte! + --i; k = Count(); + } + } + else + { + long nLi = rLi.Bottom(); + long nLk = rLk.Bottom(); + if ( rLi.Left() == rLk.Left() && + ((nLi < rLk.Top() && nLi+21 > rLk.Top()) || + (nLk < rLi.Top() && nLk+21 > rLi.Top()))) + { + Remove( k, 1 ); + --i; k = Count(); + } + } + } + } + } + } + + if ( pRects && pRects->Count() ) + RemoveSuperfluousSubsidiaryLines( *pRects ); + + if ( Count() ) + { + // OD 2004-04-23 #116347# + pOut->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOut->SetLineColor(); + + // OD 14.01.2003 #106660# - reset draw mode in high contrast + // mode in order to get fill color set at output device. + // Recover draw mode after draw of lines. + // Necessary for the subsidiary lines painted by the fly frames. + sal_uLong nOldDrawMode = pOut->GetDrawMode(); + if( pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + pOut->SetDrawMode( 0 ); + } + + for ( sal_uInt16 i = 0; i < Count(); ++i ) + { + SwLineRect &rLRect = operator[](i); + // OD 19.12.2002 #106318# - add condition <!rLRect.IsLocked()> + // to prevent paint of locked subsidiary lines. + if ( !rLRect.IsPainted() && + !rLRect.IsLocked() ) + { + const Color *pCol = 0; + switch ( rLRect.GetSubColor() ) + { + case SUBCOL_PAGE: pCol = &SwViewOption::GetDocBoundariesColor(); break; + case SUBCOL_FLY: pCol = &SwViewOption::GetObjectBoundariesColor(); break; + case SUBCOL_TAB: pCol = &SwViewOption::GetTableBoundariesColor(); break; + case SUBCOL_SECT: pCol = &SwViewOption::GetSectionBoundColor(); break; + case SUBCOL_BREAK: pCol = &SwViewOption::GetPageBreakColor(); break; + } + + if ( pOut->GetFillColor() != *pCol ) + pOut->SetFillColor( *pCol ); + pOut->DrawRect( rLRect.SVRect() ); + + rLRect.SetPainted(); + } + } + + // OD 14.01.2003 #106660# - recovering draw mode + pOut->SetDrawMode( nOldDrawMode ); + + pOut->Pop(); + } + } +} + +//------------------------------------------------------------------------- +//Diverse Functions die in diesem File so verwendet werden. + +// OD 20.02.2003 - Note: function <SwAlignRect(..)> also used outside this file. +// OD 29.04.2003 #107169# - correction: adjust rectangle on pixel level in order +// to assure, that the border 'leaves its original pixel', if it has to. +// No prior adjustments for odd relation between pixel and twip. +void MA_FASTCALL SwAlignRect( SwRect &rRect, const ViewShell *pSh ) +{ + if( !rRect.HasArea() ) + return; + + // OD 03.09.2002 #102450# + // Assure that view shell (parameter <pSh>) exists, if the output device + // is taken from this view shell --> no output device, no alignment. + // Output device taken from view shell <pSh>, if <bFlyMetafile> not set. + if ( !bFlyMetafile && !pSh ) + { + return; + } + + const OutputDevice *pOut = bFlyMetafile ? + pFlyMetafileOut : pSh->GetOut(); + + // OD 28.04.2003 #107169# - hold original rectangle in pixel + const Rectangle aOrgPxRect = pOut->LogicToPixel( rRect.SVRect() ); + // OD 29.04.2003 #107169# - determine pixel-center rectangle in twip + const SwRect aPxCenterRect( pOut->PixelToLogic( aOrgPxRect ) ); + + // OD 06.05.2003 #107169# - perform adjustments on pixel level. + SwRect aAlignedPxRect( aOrgPxRect ); + if ( rRect.Top() > aPxCenterRect.Top() ) + { + // 'leave pixel overlapping on top' + aAlignedPxRect.Top( aAlignedPxRect.Top() + 1 ); + } + + if ( rRect.Bottom() < aPxCenterRect.Bottom() ) + { + // 'leave pixel overlapping on bottom' + aAlignedPxRect.Bottom( aAlignedPxRect.Bottom() - 1 ); + } + + if ( rRect.Left() > aPxCenterRect.Left() ) + { + // 'leave pixel overlapping on left' + aAlignedPxRect.Left( aAlignedPxRect.Left() + 1 ); + } + + if ( rRect.Right() < aPxCenterRect.Right() ) + { + // 'leave pixel overlapping on right' + aAlignedPxRect.Right( aAlignedPxRect.Right() - 1 ); + } + + // OD 11.10.2002 #103636# - consider negative width/height + // check, if aligned SwRect has negative width/height. + // If Yes, adjust it to width/height = 0 twip. + // NOTE: A SwRect with negative width/height can occur, if the width/height + // of the given SwRect in twip was less than a pixel in twip and that + // the alignment calculates that the aligned SwRect should not contain + // the pixels the width/height is on. + if ( aAlignedPxRect.Width() < 0 ) + { + aAlignedPxRect.Width(0); + } + if ( aAlignedPxRect.Height() < 0 ) + { + aAlignedPxRect.Height(0); + } + // OD 30.04.2003 #107169# - consider zero width/height + // For converting a rectangle from pixel to logic it needs a width/height. + // Thus, set width/height to one, if it's zero and correct this on the twip + // level after the conversion. + sal_Bool bZeroWidth = sal_False; + if ( aAlignedPxRect.Width() == 0 ) + { + aAlignedPxRect.Width(1); + bZeroWidth = sal_True; + } + sal_Bool bZeroHeight = sal_False; + if ( aAlignedPxRect.Height() == 0 ) + { + aAlignedPxRect.Height(1); + bZeroHeight = sal_True; + } + + rRect = pOut->PixelToLogic( aAlignedPxRect.SVRect() ); + + // OD 30.04.2003 #107169# - consider zero width/height and adjust calculated + // aligned twip rectangle. + // OD 19.05.2003 #109667# - reset width/height to zero; previous negative + // width/height haven't to be considered. + if ( bZeroWidth ) + { + rRect.Width(0); + } + if ( bZeroHeight ) + { + rRect.Height(0); + } +} + +/** OD 19.05.2003 #109667# - helper method for twip adjustments on pixel base + + method compares the x- or y-pixel position of two twip-point. If the x-/y-pixel + positions are the same, the x-/y-pixel position of the second twip point is + adjusted by a given amount of pixels. + + @author OD +*/ +void lcl_CompPxPosAndAdjustPos( const OutputDevice& _rOut, + const Point& _rRefPt, + Point& _rCompPt, + const sal_Bool _bChkXPos, + const sal_Int8 _nPxAdjustment ) +{ + const Point aRefPxPt = _rOut.LogicToPixel( _rRefPt ); + Point aCompPxPt = _rOut.LogicToPixel( _rCompPt ); + + if ( _bChkXPos ) + { + if ( aCompPxPt.X() == aRefPxPt.X() ) + { + aCompPxPt.X() += _nPxAdjustment ; + const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt ); + _rCompPt.X() = aAdjustedCompPt.X(); + } + } + else + { + if ( aCompPxPt.Y() == aRefPxPt.Y() ) + { + aCompPxPt.Y() += _nPxAdjustment ; + const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt ); + _rCompPt.Y() = aAdjustedCompPt.Y(); + } + } +} + +/** OD 25.09.2002 #99739# - method to pixel-align rectangle for drawing graphic object + + Because for drawing a graphic left-top-corner and size coordinations are + used, these coordinations have to be determined on pixel level. + Thus, convert rectangle to pixel and then convert left-top-corner and + size of pixel rectangle back to logic. + This calculation is necessary, because there exists a different between + the convert from logic to pixel of a normal rectangle with its left-top- + and right-bottom-corner and the same convert of the same rectangle + with left-top-corner and size. + Call this method before each <GraphicObject.Draw(...)> + + @author OD +*/ +void SwAlignGrfRect( SwRect *pGrfRect, const OutputDevice &rOut ) +{ + Rectangle aPxRect = rOut.LogicToPixel( pGrfRect->SVRect() ); + pGrfRect->Pos( rOut.PixelToLogic( aPxRect.TopLeft() ) ); + pGrfRect->SSize( rOut.PixelToLogic( aPxRect.GetSize() ) ); +} + +long MA_FASTCALL lcl_AlignWidth( const long nWidth ) +{ + if ( nWidth ) + { + const long nW = nWidth % nPixelSzW; + + if ( !nW || nW > nHalfPixelSzW ) + return Max(1L, nWidth - nHalfPixelSzW); + } + return nWidth; +} + +long MA_FASTCALL lcl_AlignHeight( const long nHeight ) +{ + if ( nHeight ) + { + const long nH = nHeight % nPixelSzH; + + if ( !nH || nH > nHalfPixelSzH ) + return Max(1L, nHeight - nHalfPixelSzH); + } + return nHeight; +} + +long MA_FASTCALL lcl_MinHeightDist( const long nDist ) +{ + if ( aScaleX < aMinDistScale || aScaleY < aMinDistScale ) + return nDist; + return ::lcl_AlignHeight( Max( nDist, nMinDistPixelH )); +} + +long MA_FASTCALL lcl_MinWidthDist( const long nDist ) +{ + if ( aScaleX < aMinDistScale || aScaleY < aMinDistScale ) + return nDist; + return ::lcl_AlignWidth( Max( nDist, nMinDistPixelW )); +} + +//Ermittelt PrtArea plus Umrandung plus Schatten. +void MA_FASTCALL lcl_CalcBorderRect( SwRect &rRect, const SwFrm *pFrm, + const SwBorderAttrs &rAttrs, + const sal_Bool bShadow ) +{ + // OD 23.01.2003 #106386# - special handling for cell frames. + // The printing area of a cell frame is completely enclosed in the frame area + // and a cell frame has no shadow. Thus, for cell frames the calculated + // area equals the frame area. + // Notes: Borders of cell frames in R2L text direction will switch its side + // - left border is painted on the right; right border on the left. + // See <lcl_PaintLeftLine> and <lcl_PaintRightLine>. + if( pFrm->IsSctFrm() ) + { + rRect = pFrm->Prt(); + rRect.Pos() += pFrm->Frm().Pos(); + } + else if ( pFrm->IsCellFrm() ) + rRect = pFrm->Frm(); + else + { + rRect = pFrm->Prt(); + rRect.Pos() += pFrm->Frm().Pos(); + + if ( rAttrs.IsLine() || rAttrs.IsBorderDist() || + (bShadow && rAttrs.GetShadow().GetLocation() != SVX_SHADOW_NONE) ) + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = pFrm->IsVertical() ? ( pFrm->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + + const SvxBoxItem &rBox = rAttrs.GetBox(); + const sal_Bool bTop = 0 != (pFrm->*fnRect->fnGetTopMargin)(); + if ( bTop ) + { + SwTwips nDiff = rBox.GetTop() ? + rBox.CalcLineSpace( BOX_LINE_TOP ) : + ( rAttrs.IsBorderDist() ? + // OD 23.01.2003 #106386# - increase of distance by + // one twip is incorrect. + rBox.GetDistance( BOX_LINE_TOP ) : 0 ); + if( nDiff ) + (rRect.*fnRect->fnSubTop)( nDiff ); + } + + const sal_Bool bBottom = 0 != (pFrm->*fnRect->fnGetBottomMargin)(); + if ( bBottom ) + { + SwTwips nDiff = 0; + // --> collapsing borders FME 2005-05-27 #i29550# + if ( pFrm->IsTabFrm() && + ((SwTabFrm*)pFrm)->IsCollapsingBorders() ) + { + // For collapsing borders, we have to add the height of + // the height of the last line + nDiff = ((SwTabFrm*)pFrm)->GetBottomLineSize(); + } + // <-- collapsing + else + { + nDiff = rBox.GetBottom() ? + rBox.CalcLineSpace( BOX_LINE_BOTTOM ) : + ( rAttrs.IsBorderDist() ? + // OD 23.01.2003 #106386# - increase of distance by + // one twip is incorrect. + rBox.GetDistance( BOX_LINE_BOTTOM ) : 0 ); + } + if( nDiff ) + (rRect.*fnRect->fnAddBottom)( nDiff ); + } + + if ( rBox.GetLeft() ) + (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( BOX_LINE_LEFT ) ); + else if ( rAttrs.IsBorderDist() ) + // OD 23.01.2003 #106386# - increase of distance by one twip is incorrect. + (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( BOX_LINE_LEFT ) ); + + if ( rBox.GetRight() ) + (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( BOX_LINE_RIGHT ) ); + else if ( rAttrs.IsBorderDist() ) + // OD 23.01.2003 #106386# - increase of distance by one twip is incorrect. + (rRect.*fnRect->fnAddRight)( rBox.GetDistance( BOX_LINE_RIGHT ) ); + + if ( bShadow && rAttrs.GetShadow().GetLocation() != SVX_SHADOW_NONE ) + { + const SvxShadowItem &rShadow = rAttrs.GetShadow(); + if ( bTop ) + (rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SHADOW_TOP)); + (rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SHADOW_LEFT)); + if ( bBottom ) + (rRect.*fnRect->fnAddBottom) + (rShadow.CalcShadowSpace( SHADOW_BOTTOM )); + (rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SHADOW_RIGHT)); + } + } + } + + ::SwAlignRect( rRect, pGlobalShell ); +} + +void MA_FASTCALL lcl_ExtendLeftAndRight( SwRect& _rRect, + const SwFrm& _rFrm, + const SwBorderAttrs& _rAttrs, + const SwRectFn& _rRectFn ) +{ + // OD 21.05.2003 #108789# - extend left/right border/shadow rectangle to + // bottom of previous frame/to top of next frame, if border/shadow is joined + // with previous/next frame. + if ( _rAttrs.JoinedWithPrev( _rFrm ) ) + { + const SwFrm* pPrevFrm = _rFrm.GetPrev(); + (_rRect.*_rRectFn->fnSetTop)( (pPrevFrm->*_rRectFn->fnGetPrtBottom)() ); + } + if ( _rAttrs.JoinedWithNext( _rFrm ) ) + { + const SwFrm* pNextFrm = _rFrm.GetNext(); + (_rRect.*_rRectFn->fnSetBottom)( (pNextFrm->*_rRectFn->fnGetPrtTop)() ); + } +} + +void MA_FASTCALL lcl_SubtractFlys( const SwFrm *pFrm, const SwPageFrm *pPage, + const SwRect &rRect, SwRegionRects &rRegion ) +{ + const SwSortedObjs& rObjs = *pPage->GetSortedObjs(); + const SwFlyFrm* pSelfFly = pFrm->IsInFly() ? pFrm->FindFlyFrm() : pRetoucheFly2; + if ( !pRetoucheFly ) + pRetoucheFly = pRetoucheFly2; + + for ( sal_uInt16 j = 0; (j < rObjs.Count()) && rRegion.Count(); ++j ) + { + const SwAnchoredObject* pAnchoredObj = rObjs[j]; + const SdrObject* pSdrObj = pAnchoredObj->GetDrawObj(); + + // OD 2004-01-15 #110582# - do not consider invisible objects + if ( !pPage->GetFmt()->GetDoc()->IsVisibleLayerId( pSdrObj->GetLayer() ) ) + continue; + + if ( !pAnchoredObj->ISA(SwFlyFrm) ) + continue; + + const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + + if ( pSelfFly == pFly || pRetoucheFly == pFly || !rRect.IsOver( pFly->Frm() ) ) + continue; + + if ( !pFly->GetFmt()->GetPrint().GetValue() && + (OUTDEV_PRINTER == pGlobalShell->GetOut()->GetOutDevType() || + pGlobalShell->IsPreView())) + continue; + + const sal_Bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly ) ? + sal_True : sal_False; + + //Bei zeichengebundenem Fly nur diejenigen betrachten, in denen er + //nicht selbst verankert ist. + //#33429# Warum nur bei zeichengebundenen? Es macht doch nie Sinn + //Rahmen abzuziehen in denen er selbst verankert ist oder? + if ( pSelfFly && pSelfFly->IsLowerOf( pFly ) ) + continue; + + //#57194# Und warum gilt das nicht analog fuer den RetoucheFly? + if ( pRetoucheFly && pRetoucheFly->IsLowerOf( pFly ) ) + continue; + +#if OSL_DEBUG_LEVEL > 1 + //Flys, die innerhalb des eigenen verankert sind, muessen eine + //groessere OrdNum haben oder Zeichengebunden sein. + if ( pSelfFly && bLowerOfSelf ) + { + OSL_ENSURE( pFly->IsFlyInCntFrm() || + pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(), + "Fly with wrong z-Order" ); + } +#endif + + sal_Bool bStopOnHell = sal_True; + if ( pSelfFly ) + { + const SdrObject *pTmp = pSelfFly->GetVirtDrawObj(); + if ( pSdrObj->GetLayer() == pTmp->GetLayer() ) + { + if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() ) + //Im gleichen Layer werden nur obenliegende beachtet. + continue; + } + else + { + if ( !bLowerOfSelf && !pFly->GetFmt()->GetOpaque().GetValue() ) + //Aus anderem Layer interessieren uns nur nicht transparente + //oder innenliegende + continue; + bStopOnHell = sal_False; + } + } + if ( pRetoucheFly ) + { + const SdrObject *pTmp = pRetoucheFly->GetVirtDrawObj(); + if ( pSdrObj->GetLayer() == pTmp->GetLayer() ) + { + if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() ) + //Im gleichen Layer werden nur obenliegende beachtet. + continue; + } + else + { + if ( !pFly->IsLowerOf( pRetoucheFly ) && !pFly->GetFmt()->GetOpaque().GetValue() ) + //Aus anderem Layer interessieren uns nur nicht transparente + //oder innenliegende + continue; + bStopOnHell = sal_False; + } + } + + //Wenn der Inhalt des Fly Transparent ist, wird er nicht abgezogen, es sei denn + //er steht im Hell-Layer (#31941#) + const IDocumentDrawModelAccess* pIDDMA = pFly->GetFmt()->getIDocumentDrawModelAccess(); + sal_Bool bHell = pSdrObj->GetLayer() == pIDDMA->GetHellId(); + if ( (bStopOnHell && bHell) || + /// OD 05.08.2002 - change internal order of condition + /// first check "!bHell", then "..->Lower()" and "..->IsNoTxtFrm()" + /// have not to be performed, if frame is in "Hell" + ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTxtFrm() && + ( ((SwNoTxtFrm*)pFly->Lower())->IsTransparent() || + ((SwNoTxtFrm*)pFly->Lower())->HasAnimation() || + pFly->GetFmt()->GetSurround().IsContour() + ) + ) + ) + continue; + + // OD 08.10.2002 #103898# + // Own if-statements for transparent background/shadow of fly frames + // (#99657#) in order to handle special conditions. + if ( pFly->IsBackgroundTransparent() ) + { + // Background <pFly> is transparent drawn. Thus normally, its region + // have not to be substracted from given region. + // But, if method is called for a fly frame and + // <pFly> is a direct lower of this fly frame and + // <pFly> inherites its transparent background brush from its parent, + // then <pFly> frame area have to be subtracted from given region. + // NOTE: Because in Status Quo transparent backgrounds can only be + // assigned to fly frames, the handle of this special case + // avoids drawing of transparent areas more than once, if + // a fly frame inherites a transparent background from its + // parent fly frame. + if ( pFrm->IsFlyFrm() && + (pFly->GetAnchorFrm()->FindFlyFrm() == pFrm) && + static_cast<const SwFlyFrmFmt*>(pFly->GetFmt())->IsBackgroundBrushInherited() + ) + { + SwRect aRect; + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)pFly ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + ::lcl_CalcBorderRect( aRect, pFly, rAttrs, sal_True ); + rRegion -= aRect; + continue; + } + else + { + continue; + } + } + if ( pFly->IsShadowTransparent() ) + { + continue; + } + + if ( bHell && pFly->GetAnchorFrm()->IsInFly() ) + { + //Damit die Umrandung nicht vom Hintergrund des anderen Flys + //zerlegt wird. + SwRect aRect; + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)pFly ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + ::lcl_CalcBorderRect( aRect, pFly, rAttrs, sal_True ); + rRegion -= aRect; + } + else + { + SwRect aRect( pFly->Prt() ); + aRect += pFly->Frm().Pos(); + rRegion -= aRect; + } + } + if ( pRetoucheFly == pRetoucheFly2 ) + pRetoucheFly = 0; +} + +//---------------- Ausgabe fuer das BrushItem ---------------- + +/** lcl_DrawGraphicBackgrd - local help method to draw a background for a graphic + + OD 17.10.2002 #103876# + Under certain circumstances we have to draw a background for a graphic. + This method takes care of the conditions and draws the background with the + corresponding color. + Method introduced for bug fix #103876# in order to optimize drawing tiled + background graphics. Previously, this code was integrated in method + <lcl_DrawGraphic>. + Method implemented as a inline, checking the conditions and calling method + method <lcl_implDrawGraphicBackgrd(..)> for the intrinsic drawing. + + @author OD + + @param _rBackgrdBrush + background brush contain the color the background has to be drawn. + + @param _pOut + output device the background has to be drawn in. + + @param _rPaintRect + paint retangle in the output device, which has to be drawn with the background. + rectangle have to be aligned by method ::SwAlignRect + + @param _rGraphicObj + graphic object, for which the background has to be drawn. Used for checking + the transparency of its bitmap, its type and if the graphic is drawn transparent + + @param _bNumberingGraphic + boolean indicating that graphic is used as a numbering. + + @param _bBackgrdAlreadyDrawn + boolean (optional; default: false) indicating, if the background is already drawn. +*/ +void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush, + OutputDevice* _pOut, + const SwRect& _rAlignedPaintRect, + const GraphicObject& _rGraphicObj ) +{ + /// determine color of background + /// If color of background brush is not "no fill"/"auto fill" or + /// <bFlyMetafile> is set, use color of background brush, otherwise + /// use global retouche color. + const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || bFlyMetafile ) + ? _rBackgrdBrush.GetColor() + : aGlobalRetoucheColor ); + + /// determine, if background color have to be drawn transparent + /// and calculate transparency percent value + sal_Int8 nTransparencyPercent = 0; + bool bDrawTransparent = false; + if ( aColor.GetTransparency() != 0 ) + /// background color is transparent --> draw transparent. + { + bDrawTransparent = true; + nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF; + } + else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) && + (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) ) + /// graphic is drawn transparent and background color is + /// "no fill"/"auto fill" --> draw transparent + { + bDrawTransparent = true; + nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF; + } + + if ( bDrawTransparent ) + { + /// draw background transparent + if( _pOut->GetFillColor() != aColor.GetRGBColor() ) + _pOut->SetFillColor( aColor.GetRGBColor() ); + PolyPolygon aPoly( _rAlignedPaintRect.SVRect() ); + _pOut->DrawTransparent( aPoly, nTransparencyPercent ); + } + else + { + /// draw background opaque + if ( _pOut->GetFillColor() != aColor ) + _pOut->SetFillColor( aColor ); + _pOut->DrawRect( _rAlignedPaintRect.SVRect() ); + } +} + +inline void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush, + OutputDevice* _pOut, + const SwRect& _rAlignedPaintRect, + const GraphicObject& _rGraphicObj, + bool _bNumberingGraphic, + bool _bBackgrdAlreadyDrawn = false ) +{ + /// draw background with background color, if + /// (1) graphic is not used as a numbering AND + /// (2) background is not already drawn AND + /// (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists + if ( !_bNumberingGraphic && + !_bBackgrdAlreadyDrawn && + ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GRAPHIC_NONE ) + ) + { + lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj ); + } +} + +/// OD 06.08.2002 #99657# - Note: the transparency of the background graphic +/// is saved in SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency() +/// and is considered in the drawing of the graphic. +/// Thus, to provide transparent background graphic for text frames nothing +/// has to be coded. +/// OD 25.09.2002 #99739# - use align rectangle for drawing graphic +/// OD 25.09.2002 #99739# - pixel-align coordinations for drawing graphic. +/// OD 17.10.2002 #103876# - outsource code for drawing background of the graphic +/// with a background color in method <lcl_DrawGraphicBackgrd> +/// Also, change type of <bGrfNum> and <bClip> from <sal_Bool> to <bool>. +void lcl_DrawGraphic( const SvxBrushItem& rBrush, OutputDevice *pOut, + ViewShell &rSh, const SwRect &rGrf, const SwRect &rOut, + bool bClip, bool bGrfNum, + bool bBackgrdAlreadyDrawn = false ) + /// OD 02.09.2002 #99657# + /// add parameter <bBackgrdAlreadyDrawn> to indicate + /// that the background is already drawn. +{ + /// OD 25.09.2002 #99739# - calculate align rectangle from parameter <rGrf> + /// and use aligned rectangle <aAlignedGrfRect> in the following code + SwRect aAlignedGrfRect = rGrf; + ::SwAlignRect( aAlignedGrfRect, &rSh ); + + /// OD 17.10.2002 #103876# - change type from <sal_Bool> to <bool>. + const bool bNotInside = bClip && !rOut.IsInside( aAlignedGrfRect ); + if ( bNotInside ) + { + pOut->Push( PUSH_CLIPREGION ); + pOut->IntersectClipRegion( rOut.SVRect() ); + } + + //Hier kein Link, wir wollen die Grafik synchron laden! + ((SvxBrushItem&)rBrush).SetDoneLink( Link() ); + GraphicObject *pGrf = (GraphicObject*)rBrush.GetGraphicObject(); + + /// OD 17.10.2002 #103876# - outsourcing drawing of background with a background color. + ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, bBackgrdAlreadyDrawn ); + + /// OD 25.09.2002 #99739# - + /// Because for drawing a graphic left-top-corner and size coordinations are + /// used, these coordinations have to be determined on pixel level. + ::SwAlignGrfRect( &aAlignedGrfRect, *pOut ); + pGrf->DrawWithPDFHandling( *pOut, aAlignedGrfRect.Pos(), aAlignedGrfRect.SSize() ); + + if ( bNotInside ) + pOut->Pop(); +} // end of method <lcl_DrawGraphic> + +void MA_FASTCALL DrawGraphic( const SvxBrushItem *pBrush, + OutputDevice *pOutDev, + const SwRect &rOrg, + const SwRect &rOut, + const sal_uInt8 nGrfNum, + const sal_Bool bConsiderBackgroundTransparency ) + /// OD 05.08.2002 #99657# - add 6th parameter to indicate that method should + /// consider background transparency, saved in the color of the brush item +{ + ViewShell &rSh = *pGlobalShell; + /// OD 17.10.2002 #103876# - change type from <sal_Bool> to <bool> + bool bReplaceGrfNum = GRFNUM_REPLACE == nGrfNum; + bool bGrfNum = GRFNUM_NO != nGrfNum; + Size aGrfSize; + SvxGraphicPosition ePos = GPOS_NONE; + if( pBrush && !bReplaceGrfNum ) + { + if( rSh.GetViewOptions()->IsGraphic() ) + { + //#125488#: load graphic directly in PDF import + // --> OD 2006-08-25 #i68953# - also during print load graphic directly. + if ( (rSh).GetViewOptions()->IsPDFExport() || + rSh.GetOut()->GetOutDevType() == OUTDEV_PRINTER ) + // <-- + { + ((SvxBrushItem*)pBrush)->PurgeMedium(); + ((SvxBrushItem*)pBrush)->SetDoneLink( Link() ); + } + else + ((SvxBrushItem*)pBrush)->SetDoneLink( STATIC_LINK( + rSh.GetDoc(), SwDoc, BackgroundDone ) ); + //SfxObjectShell &rObjSh = *GETOBJSHELL(); + const Graphic* pGrf = pBrush->GetGraphic(); + if( pGrf && GRAPHIC_NONE != pGrf->GetType() ) + { + ePos = pBrush->GetGraphicPos(); + if( pGrf->IsSupportedGraphic() ) + // don't the use the specific output device! Bug 94802 + aGrfSize = ::GetGraphicSizeTwip( *pGrf, 0 ); + } + } + else + bReplaceGrfNum = bGrfNum; + } + + SwRect aGrf; + aGrf.SSize( aGrfSize ); + sal_Bool bDraw = sal_True; + sal_Bool bRetouche = sal_True; + switch ( ePos ) + { + case GPOS_LT: + aGrf.Pos() = rOrg.Pos(); + break; + + case GPOS_MT: + aGrf.Pos().Y() = rOrg.Top(); + aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2; + break; + + case GPOS_RT: + aGrf.Pos().Y() = rOrg.Top(); + aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width(); + break; + + case GPOS_LM: + aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2; + aGrf.Pos().X() = rOrg.Left(); + break; + + case GPOS_MM: + aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2; + aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2; + break; + + case GPOS_RM: + aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2; + aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width(); + break; + + case GPOS_LB: + aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height(); + aGrf.Pos().X() = rOrg.Left(); + break; + + case GPOS_MB: + aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height(); + aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2; + break; + + case GPOS_RB: + aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height(); + aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width(); + break; + + case GPOS_AREA: + aGrf = rOrg; + /// OD 05.09.2002 #102912# + /// In spite the fact that the background graphic have to fill the complete + /// area, it has been checked, if the graphic will completely fill out + /// the region to be painted <rOut> and thus, nothing has to be retouched. + /// For example, this is the case for a fly frame without a background + /// brush positioned on the border of the page and inherited the + /// background brush from the page. + bRetouche = !rOut.IsInside( aGrf ); + break; + + case GPOS_TILED: + { + // OD 17.10.2002 #103876# - draw background of tiled graphic + // before drawing tiled graphic in loop + // determine graphic object + GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject()); + // calculate aligned paint rectangle + SwRect aAlignedPaintRect = rOut; + ::SwAlignRect( aAlignedPaintRect, &rSh ); + // OD 25.10.2002 #103876# - draw background color for aligned paint rectangle + lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum ); + + // set left-top-corner of background graphic to left-top-corner of the + // area, from which the background brush is determined. + aGrf.Pos() = rOrg.Pos(); + // setup clipping at output device + pOutDev->Push( PUSH_CLIPREGION ); + pOutDev->IntersectClipRegion( rOut.SVRect() ); + // OD 28.10.2002 #103876# - use new method <GraphicObject::DrawTiled(::)> + { + // calculate paint offset + Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() ); + // draw background graphic tiled for aligned paint rectangle + // --> OD 2005-02-15 #i42643# - apply fix #104004# for Calc + // also for Writer - see /sc/source/view/printfun.cxx + // For PDF export, every draw operation for bitmaps takes a + // noticeable amount of place (~50 characters). Thus, optimize + // between tile bitmap size and number of drawing operations here. + // + // A_out + // n_chars = k1 * ---------- + k2 * A_bitmap + // A_bitmap + // + // minimum n_chars is obtained for (derive for A_bitmap, + // set to 0, take positive solution): + // k1 + // A_bitmap = Sqrt( ---- A_out ) + // k2 + // + // where k1 is the number of chars per draw operation, and + // k2 is the number of chars per bitmap pixel. + // This is approximately 50 and 7 for current PDF writer, respectively. + // + const double k1( 50 ); + const double k2( 7 ); + const Size aSize( aAlignedPaintRect.SSize() ); + const double Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() ); + + pGraphicObj->DrawTiled( pOutDev, + aAlignedPaintRect.SVRect(), + aGrf.SSize(), + Size( aPaintOffset.X(), aPaintOffset.Y() ), + NULL, GRFMGR_DRAW_STANDARD, + ::std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) ); + // <-- + } + // reset clipping at output device + pOutDev->Pop(); + // set <bDraw> and <bRetouche> to false, indicating that background + // graphic and background are already drawn. + bDraw = bRetouche = sal_False; + } + break; + + case GPOS_NONE: + bDraw = sal_False; + break; + + default: OSL_ENSURE( !pOutDev, "new Graphic position?" ); + } + + /// OD 02.09.2002 #99657# + /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of + /// graphic is already drawn or not. + bool bGrfBackgrdAlreadyDrawn = false; + if ( bRetouche ) + { + // OD 2004-04-23 #116347# + pOutDev->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOutDev->SetLineColor(); + + // OD 07.08.2002 #99657# #GetTransChg# + // check, if a existing background graphic (not filling the complete + // background) is transparent drawn and the background color is + // "no fill" respectively "auto fill", if background transparency + // has to be considered. + // If YES, memorise transparency of background graphic. + // check also, if background graphic bitmap is transparent. + bool bTransparentGrfWithNoFillBackgrd = false; + sal_Int32 nGrfTransparency = 0; + bool bGrfIsTransparent = false; + if ( (ePos != GPOS_NONE) && + (ePos != GPOS_TILED) && (ePos != GPOS_AREA) + ) + { + GraphicObject *pGrf = (GraphicObject*)pBrush->GetGraphicObject(); + if ( bConsiderBackgroundTransparency ) + { + GraphicAttr pGrfAttr = pGrf->GetAttr(); + if ( (pGrfAttr.GetTransparency() != 0) && + ( pBrush && (pBrush->GetColor() == COL_TRANSPARENT) ) + ) + { + bTransparentGrfWithNoFillBackgrd = true; + nGrfTransparency = pGrfAttr.GetTransparency(); + } + } + if ( pGrf->IsTransparent() ) + { + bGrfIsTransparent = true; + } + } + + /// OD 06.08.2002 #99657# #GetTransChg# - to get color of brush, + /// check background color against COL_TRANSPARENT ("no fill"/"auto fill") + /// instead of checking, if transparency is not set. + const Color aColor( pBrush && + ( !(pBrush->GetColor() == COL_TRANSPARENT) || + bFlyMetafile ) + ? pBrush->GetColor() + : aGlobalRetoucheColor ); + + /// OD 08.08.2002 #99657# - determine, if background region have to be + /// drawn transparent. + /// background region has to be drawn transparent, if + /// background transparency have to be considered + /// AND + /// ( background color is transparent OR + /// background graphic is transparent and background color is "no fill" + /// ) + sal_Bool bDrawTransparent = bConsiderBackgroundTransparency && + ( ( aColor.GetTransparency() != 0) || + bTransparentGrfWithNoFillBackgrd ); + + // --> OD 2008-06-02 #i75614# + // reset draw mode in high contrast mode in order to get fill color set + const sal_uLong nOldDrawMode = pOutDev->GetDrawMode(); + if ( pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + pOutDev->SetDrawMode( 0 ); + } + // <-- + + /// OD 06.08.2002 #99657# - if background region have to be drawn + /// transparent, set only the RGB values of the background color as + /// the fill color for the output device. + if ( bDrawTransparent ) + { + if( pOutDev->GetFillColor() != aColor.GetRGBColor() ) + pOutDev->SetFillColor( aColor.GetRGBColor() ); + } + else + { + if( pOutDev->GetFillColor() != aColor ) + pOutDev->SetFillColor( aColor ); + } + + // --> OD 2008-06-02 #i75614# + // restore draw mode + pOutDev->SetDrawMode( nOldDrawMode ); + // <-- + + /// OD 02.09.2002 #99657# + if ( bDrawTransparent ) + { + /// background region have to be drawn transparent. + /// Thus, create a poly-polygon from the region and draw it with + /// the corresponding transparency precent. + PolyPolygon aDrawPoly( rOut.SVRect() ); + if ( aGrf.HasArea() ) + { + if ( !bGrfIsTransparent ) + { + /// substract area of background graphic from draw area + /// OD 08.10.2002 #103898# - consider only that part of the + /// graphic area that is overlapping with draw area. + SwRect aTmpGrf = aGrf; + aTmpGrf.Intersection( rOut ); + if ( aTmpGrf.HasArea() ) + { + Polygon aGrfPoly( aTmpGrf.SVRect() ); + aDrawPoly.Insert( aGrfPoly ); + } + } + else + bGrfBackgrdAlreadyDrawn = true; + } + /// calculate transparency percent: + /// ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF + /// If there is a background graphic with a background color "no fill"/"auto fill", + /// the transparency value is taken from the background graphic, + /// otherwise take the transparency value from the color. + sal_Int8 nTransparencyPercent = static_cast<sal_Int8>( + (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency() + )*100 + 0x7F)/0xFF); + /// draw poly-polygon transparent + pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent ); + } + else + { + SwRegionRects aRegion( rOut, 4 ); + if ( !bGrfIsTransparent ) + aRegion -= aGrf; + else + bGrfBackgrdAlreadyDrawn = true; + /// loop rectangles of background region, which has to be drawn + for( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + { + pOutDev->DrawRect( aRegion[i].SVRect() ); + } + } + pOutDev ->Pop(); + } + + if( bDraw && aGrf.IsOver( rOut ) ) + /// OD 02.09.2002 #99657# + /// add parameter <bGrfBackgrdAlreadyDrawn> + lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, true, bGrfNum, + bGrfBackgrdAlreadyDrawn ); + + if( bReplaceGrfNum ) + { + const BitmapEx& rBmp = ViewShell::GetReplacementBitmap( false ); + Font aTmp( pOutDev->GetFont() ); + Graphic::DrawEx( pOutDev, aEmptyStr, aTmp, rBmp, rOrg.Pos(), rOrg.SSize() ); + } +} + +//------------------------------------------------------------------------ + +/** local help method for SwRootFrm::Paint(..) - Adjust given rectangle to pixel size + + By OD at 27.09.2002 for #103636# + In order to avoid paint errors caused by multiple alignments - e.g. method + ::SwAlignRect(..) - and other changes to the rectangle to be painted, + this method is called for the rectangle to be painted in order to + adjust it to the pixel it is overlapping. + + @author OD +*/ +void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const OutputDevice &aOut ) +{ + /// local constant object of class <Size> to determine number of Twips + /// representing a pixel. + const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) ); + + /// local object of class <Rectangle> in Twip coordinates + /// calculated from given rectangle aligned to pixel centers. + const Rectangle aPxCenterRect = aOut.PixelToLogic( + aOut.LogicToPixel( io_aSwRect.SVRect() ) ); + + /// local constant object of class <Rectangle> representing given rectangle + /// in pixel. + const Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() ); + + /// calculate adjusted rectangle from pixel centered rectangle. + /// Due to rounding differences <aPxCenterRect> doesn't exactly represents + /// the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1. + /// Afterwards, adjust calculated Twip-positions of the all borders. + Rectangle aSizedRect = aPxCenterRect; + aSizedRect.Left() -= (aTwipToPxSize.Width()/2 + 1); + aSizedRect.Right() += (aTwipToPxSize.Width()/2 + 1); + aSizedRect.Top() -= (aTwipToPxSize.Height()/2 + 1); + aSizedRect.Bottom() += (aTwipToPxSize.Height()/2 + 1); + + /// adjust left() + while ( (aOut.LogicToPixel(aSizedRect)).Left() < aOrgPxRect.Left() ) + { + ++aSizedRect.Left(); + } + /// adjust right() + while ( (aOut.LogicToPixel(aSizedRect)).Right() > aOrgPxRect.Right() ) + { + --aSizedRect.Right(); + } + /// adjust top() + while ( (aOut.LogicToPixel(aSizedRect)).Top() < aOrgPxRect.Top() ) + { + ++aSizedRect.Top(); + } + /// adjust bottom() + while ( (aOut.LogicToPixel(aSizedRect)).Bottom() > aOrgPxRect.Bottom() ) + { + --aSizedRect.Bottom(); + } + + io_aSwRect = SwRect( aSizedRect ); + +#if OSL_DEBUG_LEVEL > 1 + Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() ); + Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect ); + OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect, + "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size"); + Rectangle aTestNewRect( aSizedRect ); + /// check Left() + --aSizedRect.Left(); + aTestNewPxRect = aOut.LogicToPixel( aSizedRect ); + OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1), + "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted"); + ++aSizedRect.Left(); + /// check Right() + ++aSizedRect.Right(); + aTestNewPxRect = aOut.LogicToPixel( aSizedRect ); + OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1), + "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted"); + --aSizedRect.Right(); + /// check Top() + --aSizedRect.Top(); + aTestNewPxRect = aOut.LogicToPixel( aSizedRect ); + OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1), + "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted"); + ++aSizedRect.Top(); + /// check Bottom() + ++aSizedRect.Bottom(); + aTestNewPxRect = aOut.LogicToPixel( aSizedRect ); + OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1), + "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted"); + --aSizedRect.Bottom(); +#endif +} + +// +// FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START +// + +struct SwLineEntry +{ + SwTwips mnKey; + SwTwips mnStartPos; + SwTwips mnEndPos; + + svx::frame::Style maAttribute; + + enum OverlapType { NO_OVERLAP, OVERLAP1, OVERLAP2, OVERLAP3 }; + +public: + SwLineEntry( SwTwips nKey, + SwTwips nStartPos, + SwTwips nEndPos, + const svx::frame::Style& rAttribute ); + + OverlapType Overlaps( const SwLineEntry& rComp ) const; +}; + +SwLineEntry::SwLineEntry( SwTwips nKey, + SwTwips nStartPos, + SwTwips nEndPos, + const svx::frame::Style& rAttribute ) + : mnKey( nKey ), + mnStartPos( nStartPos ), + mnEndPos( nEndPos ), + maAttribute( rAttribute ) +{ +} + +/* + + 1. ---------- rOld + ---------- rNew + + 2. ---------- rOld + ------------- rNew + + 3. ------- rOld + ------------- rNew + + 4. ------------- rOld + ---------- rNew + + 5. ---------- rOld + ---- rNew + + 6. ---------- rOld + ---------- rNew + + 7. ------------- rOld + ---------- rNew + + 8. ---------- rOld + ------------- rNew + + 9. ---------- rOld + ---------- rNew +*/ + +SwLineEntry::OverlapType SwLineEntry::Overlaps( const SwLineEntry& rNew ) const +{ + SwLineEntry::OverlapType eRet = OVERLAP3; + + if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos ) + eRet = NO_OVERLAP; + + // 1, 2, 3 + else if ( mnEndPos < rNew.mnEndPos ) + eRet = OVERLAP1; + + // 4, 5, 6, 7 + else if ( mnStartPos <= rNew.mnStartPos && mnEndPos >= rNew.mnEndPos ) + eRet = OVERLAP2; + + // 8, 9 + return eRet; +} + +struct lt_SwLineEntry +{ + bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const + { + return e1.mnStartPos < e2.mnStartPos; + } +}; + +typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet; +typedef std::set< SwLineEntry, lt_SwLineEntry >::iterator SwLineEntrySetIter; +typedef std::set< SwLineEntry, lt_SwLineEntry >::const_iterator SwLineEntrySetConstIter; +typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap; +typedef std::map< SwTwips, SwLineEntrySet >::iterator SwLineEntryMapIter; +typedef std::map< SwTwips, SwLineEntrySet >::const_iterator SwLineEntryMapConstIter; + +class SwTabFrmPainter +{ + SwLineEntryMap maVertLines; + SwLineEntryMap maHoriLines; + const SwTabFrm& mrTabFrm; + + void Insert( SwLineEntry&, bool bHori ); + void Insert( const SwFrm& rFrm, const SvxBoxItem& rBoxItem ); + void HandleFrame( const SwLayoutFrm& rFrm ); + void FindStylesForLine( const Point&, + const Point&, + svx::frame::Style*, + bool bHori ) const; + +public: + SwTabFrmPainter( const SwTabFrm& rTabFrm ); + + void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const; +}; + +SwTabFrmPainter::SwTabFrmPainter( const SwTabFrm& rTabFrm ) + : mrTabFrm( rTabFrm ) +{ + HandleFrame( rTabFrm ); +} + +void SwTabFrmPainter::HandleFrame( const SwLayoutFrm& rLayoutFrm ) +{ + // Add border lines of cell frames. Skip covered cells. Skip cells + // in special row span row, which do not have a negative row span: + if ( rLayoutFrm.IsCellFrm() && !rLayoutFrm.IsCoveredCell() ) + { + const SwCellFrm* pThisCell = static_cast<const SwCellFrm*>(&rLayoutFrm); + const SwRowFrm* pRowFrm = static_cast<const SwRowFrm*>(pThisCell->GetUpper()); + const long nRowSpan = pThisCell->GetTabBox()->getRowSpan(); + if ( !pRowFrm->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), &rLayoutFrm ); + const SwBorderAttrs& rAttrs = *aAccess.Get(); + const SvxBoxItem& rBox = rAttrs.GetBox(); + Insert( rLayoutFrm, rBox ); + } + } + + // Recurse into lower layout frames, but do not recurse into lower tabframes. + const SwFrm* pLower = rLayoutFrm.Lower(); + while ( pLower ) + { + const SwLayoutFrm* pLowerLayFrm = dynamic_cast<const SwLayoutFrm*>(pLower); + if ( pLowerLayFrm && !pLowerLayFrm->IsTabFrm() ) + HandleFrame( *pLowerLayFrm ); + + pLower = pLower->GetNext(); + } +} + +void SwTabFrmPainter::PaintLines( OutputDevice& rDev, const SwRect& rRect ) const +{ + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, rDev ); + // <-- + + const SwFrm* pTmpFrm = &mrTabFrm; + const bool bVert = pTmpFrm->IsVertical(); + + SwLineEntryMapConstIter aIter = maHoriLines.begin(); + bool bHori = true; + + // color for subsidiary lines: + const Color& rCol( SwViewOption::GetTableBoundariesColor() ); + + // high contrast mode: + // overrides the color of non-subsidiary lines. + const Color* pHCColor = 0; + sal_uLong nOldDrawMode = rDev.GetDrawMode(); + if( pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + pHCColor = &SwViewOption::GetFontColor(); + rDev.SetDrawMode( 0 ); + } + + // set clip region: + rDev.Push( PUSH_CLIPREGION ); + Size aSize( rRect.SSize() ); + // Hack! Necessary, because the layout is not pixel aligned! + aSize.Width() += nPixelSzW; aSize.Height() += nPixelSzH; + rDev.SetClipRegion( Rectangle( rRect.Pos(), aSize ) ); + + // The following stuff if necessary to have the new table borders fit + // into a ::SwAlignRect adjusted world. + const SwTwips nTwipXCorr = bVert ? 0 : Max( 0L, nHalfPixelSzW - 2 ); // 1 < 2 < 3 ;-) + const SwTwips nTwipYCorr = !bVert ? 0 : Max( 0L, nHalfPixelSzW - 2 ); // 1 < 2 < 3 ;-) + const SwFrm* pUpper = mrTabFrm.GetUpper(); + SwRect aUpper( pUpper->Prt() ); + aUpper.Pos() += pUpper->Frm().Pos(); + SwRect aUpperAligned( aUpper ); + ::SwAlignRect( aUpperAligned, pGlobalShell ); + + while ( true ) + { + if ( bHori && aIter == maHoriLines.end() ) + { + aIter = maVertLines.begin(); + bHori = false; + } + + if ( !bHori && aIter == maVertLines.end() ) + break; + + const SwLineEntrySet& rEntrySet = (*aIter).second; + SwLineEntrySetConstIter aSetIter = rEntrySet.begin(); + while ( aSetIter != rEntrySet.end() ) + { + const SwLineEntry& rEntry = *aSetIter; + const svx::frame::Style& rEntryStyle( (*aSetIter).maAttribute ); + + Point aStart, aEnd; + if ( bHori ) + { + aStart.X() = rEntry.mnStartPos; + aStart.Y() = rEntry.mnKey; + aEnd.X() = rEntry.mnEndPos; + aEnd.Y() = rEntry.mnKey; + } + else + { + aStart.X() = rEntry.mnKey; + aStart.Y() = rEntry.mnStartPos; + aEnd.X() = rEntry.mnKey; + aEnd.Y() = rEntry.mnEndPos; + } + + SwRect aRepaintRect( aStart, aEnd ); + + // the repaint rectangle has to be moved a bit for the centered lines: + SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth(); + if ( bHori ) + { + aRepaintRect.Height( 2 * nRepaintRectSize ); + aRepaintRect.Pos().Y() -= nRepaintRectSize; + } + else + { + aRepaintRect.Width( 2 * nRepaintRectSize ); + aRepaintRect.Pos().X() -= nRepaintRectSize; + } + + if ( rRect.IsOver( aRepaintRect ) ) + { + svx::frame::Style aStyles[ 7 ]; + aStyles[ 0 ] = rEntryStyle; + FindStylesForLine( aStart, aEnd, aStyles, bHori ); + + // subsidiary lines + const Color* pTmpColor = 0; + if ( 0 == aStyles[ 0 ].GetWidth() ) + { + if ( IS_SUBS_TABLE && pGlobalShell->GetWin() ) + aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 ); + } + else + pTmpColor = pHCColor; + + // The line sizes stored in the line style have to be adjusted as well. + // This will guarantee that lines with the same twip size will have the + // same pixel size. + for ( int i = 0; i < 7; ++i ) + { + sal_uInt16 nPrim = aStyles[ i ].Prim(); + sal_uInt16 nDist = aStyles[ i ].Dist(); + sal_uInt16 nSecn = aStyles[ i ].Secn(); + + if ( nPrim > 0 ) + nPrim = (sal_uInt16)( Max( 1L, nPixelSzH * ( nPrim / nPixelSzH ) ) ); + if ( nDist > 0 ) + nDist = (sal_uInt16)( Max( 1L, nPixelSzH * ( nDist / nPixelSzH ) ) ); + if ( nSecn > 0 ) + nSecn = (sal_uInt16)( Max( 1L, nPixelSzH * ( nSecn / nPixelSzH ) ) ); + + aStyles[ i ].Set( nPrim, nDist, nSecn ); + } + + // The (twip) positions will be adjusted to meet these requirements: + // 1. The y coordinates are located in the middle of the pixel grid + // 2. The x coordinated are located at the beginning of the pixel grid + // This is done, because the horizontal lines are painted "at beginning", + // whereas the vertical lines are painted "centered". By making the line + // sizes a multiple of one pixel size, we can assure, that all lines having + // the same twip size have the same pixel size, independent of their position + // on the screen. + Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel( aStart ) ); + Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel( aEnd ) ); + + if( pGlobalShell->GetWin() ) + { + // The table borders do not use SwAlignRect, but all the other frames do. + // Therefore we tweak the outer borders a bit to achieve that the outer + // borders match the subsidiary lines of the upper: + if ( aStart.X() == aUpper.Left() ) + aPaintStart.X() = aUpperAligned.Left(); + else if ( aStart.X() == aUpper._Right() ) + aPaintStart.X() = aUpperAligned._Right(); + if ( aStart.Y() == aUpper.Top() ) + aPaintStart.Y() = aUpperAligned.Top(); + else if ( aStart.Y() == aUpper._Bottom() ) + aPaintStart.Y() = aUpperAligned._Bottom(); + + if ( aEnd.X() == aUpper.Left() ) + aPaintEnd.X() = aUpperAligned.Left(); + else if ( aEnd.X() == aUpper._Right() ) + aPaintEnd.X() = aUpperAligned._Right(); + if ( aEnd.Y() == aUpper.Top() ) + aPaintEnd.Y() = aUpperAligned.Top(); + else if ( aEnd.Y() == aUpper._Bottom() ) + aPaintEnd.Y() = aUpperAligned._Bottom(); + } + + aPaintStart.X() -= nTwipXCorr; // nHalfPixelSzW - 2 to assure that we do not leave the pixel + aPaintEnd.X() -= nTwipXCorr; + aPaintStart.Y() -= nTwipYCorr; + aPaintEnd.Y() -= nTwipYCorr; + + // Here comes the painting stuff: Thank you, DR, great job!!! + if ( bHori ) + { + mrTabFrm.ProcessPrimitives( svx::frame::CreateBorderPrimitives( + aPaintStart, + aPaintEnd, + aStyles[ 0 ], // current style + aStyles[ 1 ], // aLFromT + aStyles[ 2 ], // aLFromL + aStyles[ 3 ], // aLFromB + aStyles[ 4 ], // aRFromT + aStyles[ 5 ], // aRFromR + aStyles[ 6 ], // aRFromB + pTmpColor + ) + ); + } + else + { + mrTabFrm.ProcessPrimitives( svx::frame::CreateBorderPrimitives( + aPaintEnd, + aPaintStart, + aStyles[ 0 ], // current style + aStyles[ 4 ], // aBFromL + aStyles[ 5 ], // aBFromB + aStyles[ 6 ], // aBFromR + aStyles[ 1 ], // aTFromL + aStyles[ 2 ], // aTFromT + aStyles[ 3 ], // aTFromR + pTmpColor + ) + ); + } + } + + ++aSetIter; + } + + ++aIter; + } + + // restore output device: + rDev.Pop(); + rDev.SetDrawMode( nOldDrawMode ); +} + +// Finds the lines that join the line defined by (StartPoint, EndPoint) in either +// StartPoint or Endpoint. The styles of these lines are required for DR's magic +// line painting functions. +void SwTabFrmPainter::FindStylesForLine( const Point& rStartPoint, + const Point& rEndPoint, + svx::frame::Style* pStyles, + bool bHori ) const +{ + // pStyles[ 1 ] = bHori ? aLFromT : TFromL + // pStyles[ 2 ] = bHori ? aLFromL : TFromT, + // pStyles[ 3 ] = bHori ? aLFromB : TFromR, + // pStyles[ 4 ] = bHori ? aRFromT : BFromL, + // pStyles[ 5 ] = bHori ? aRFromR : BFromB, + // pStyles[ 6 ] = bHori ? aRFromB : BFromR, + + SwLineEntryMapConstIter aMapIter = maVertLines.find( rStartPoint.X() ); + OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" ); + const SwLineEntrySet& rVertSet = (*aMapIter).second; + SwLineEntrySetConstIter aIter = rVertSet.begin(); + + while ( aIter != rVertSet.end() ) + { + const SwLineEntry& rEntry = *aIter; + if ( bHori ) + { + if ( rStartPoint.Y() == rEntry.mnStartPos ) + pStyles[ 3 ] = rEntry.maAttribute; + else if ( rStartPoint.Y() == rEntry.mnEndPos ) + pStyles[ 1 ] = rEntry.maAttribute; + } + else + { + if ( rStartPoint.Y() == rEntry.mnEndPos ) + pStyles[ 2 ] = rEntry.maAttribute; + else if ( rEndPoint.Y() == rEntry.mnStartPos ) + pStyles[ 5 ] = rEntry.maAttribute; + } + ++aIter; + } + + aMapIter = maHoriLines.find( rStartPoint.Y() ); + OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" ); + const SwLineEntrySet& rHoriSet = (*aMapIter).second; + aIter = rHoriSet.begin(); + + while ( aIter != rHoriSet.end() ) + { + const SwLineEntry& rEntry = *aIter; + if ( bHori ) + { + if ( rStartPoint.X() == rEntry.mnEndPos ) + pStyles[ 2 ] = rEntry.maAttribute; + else if ( rEndPoint.X() == rEntry.mnStartPos ) + pStyles[ 5 ] = rEntry.maAttribute; + } + else + { + if ( rStartPoint.X() == rEntry.mnEndPos ) + pStyles[ 1 ] = rEntry.maAttribute; + else if ( rStartPoint.X() == rEntry.mnStartPos ) + pStyles[ 3 ] = rEntry.maAttribute; + } + ++aIter; + } + + if ( bHori ) + { + aMapIter = maVertLines.find( rEndPoint.X() ); + OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" ); + const SwLineEntrySet& rVertSet2 = (*aMapIter).second; + aIter = rVertSet2.begin(); + + while ( aIter != rVertSet2.end() ) + { + const SwLineEntry& rEntry = *aIter; + if ( rEndPoint.Y() == rEntry.mnStartPos ) + pStyles[ 6 ] = rEntry.maAttribute; + else if ( rEndPoint.Y() == rEntry.mnEndPos ) + pStyles[ 4 ] = rEntry.maAttribute; + ++aIter; + } + } + else + { + aMapIter = maHoriLines.find( rEndPoint.Y() ); + OSL_ENSURE( aMapIter != maHoriLines.end(), "FindStylesForLine: Error" ); + const SwLineEntrySet& rHoriSet2 = (*aMapIter).second; + aIter = rHoriSet2.begin(); + + while ( aIter != rHoriSet2.end() ) + { + const SwLineEntry& rEntry = *aIter; + if ( rEndPoint.X() == rEntry.mnEndPos ) + pStyles[ 4 ] = rEntry.maAttribute; + else if ( rEndPoint.X() == rEntry.mnStartPos ) + pStyles[ 6 ] = rEntry.maAttribute; + ++aIter; + } + } +} + +void SwTabFrmPainter::Insert( const SwFrm& rFrm, const SvxBoxItem& rBoxItem ) +{ + std::vector< const SwFrm* > aTestVec; + aTestVec.push_back( &rFrm ); + aTestVec.push_back( &rFrm ); + aTestVec.push_back( &rFrm ); + + // build 4 line entries for the 4 borders: + SwRect aBorderRect = rFrm.Frm(); + if ( rFrm.IsTabFrm() ) + { + aBorderRect = rFrm.Prt(); + aBorderRect.Pos() += rFrm.Frm().Pos(); + } + + const SwTwips nLeft = aBorderRect._Left(); + const SwTwips nRight = aBorderRect._Right(); + const SwTwips nTop = aBorderRect._Top(); + const SwTwips nBottom = aBorderRect._Bottom(); + + svx::frame::Style aL( rBoxItem.GetLeft() ); + svx::frame::Style aR( rBoxItem.GetRight() ); + svx::frame::Style aT( rBoxItem.GetTop() ); + svx::frame::Style aB( rBoxItem.GetBottom() ); + + const SwTwips nHalfTopWidth = aT.GetWidth() / 2; + + aR.MirrorSelf(); + aB.MirrorSelf(); + + bool bVert = mrTabFrm.IsVertical(); + bool bR2L = mrTabFrm.IsRightToLeft(); + + aL.SetRefMode( svx::frame::REFMODE_CENTERED ); + aR.SetRefMode( svx::frame::REFMODE_CENTERED ); + aT.SetRefMode( !bVert ? svx::frame::REFMODE_BEGIN : svx::frame::REFMODE_END ); + aB.SetRefMode( !bVert ? svx::frame::REFMODE_BEGIN : svx::frame::REFMODE_END ); + + SwLineEntry aLeft ( nLeft, nTop + nHalfTopWidth, nBottom + nHalfTopWidth, bVert ? aB : ( bR2L ? aR : aL ) ); + SwLineEntry aRight ( nRight, nTop + nHalfTopWidth, nBottom + nHalfTopWidth, bVert ? aT : ( bR2L ? aL : aR ) ); + SwLineEntry aTop ( nTop + nHalfTopWidth, nLeft, nRight, bVert ? aL : aT ); + SwLineEntry aBottom( nBottom + nHalfTopWidth, nLeft, nRight, bVert ? aR : aB ); + + Insert( aLeft, false ); + Insert( aRight, false ); + Insert( aTop, true ); + Insert( aBottom, true ); + + const SwRowFrm* pThisRowFrm = dynamic_cast<const SwRowFrm*>(rFrm.GetUpper()); + + // special case: #i9860# + // first line in follow table without repeated headlines + if ( pThisRowFrm && + pThisRowFrm->GetUpper() == &mrTabFrm && + mrTabFrm.IsFollow() && + !mrTabFrm.GetTable()->GetRowsToRepeat() && + (!pThisRowFrm->GetPrev() || static_cast<const SwRowFrm*>(pThisRowFrm->GetPrev())->IsRowSpanLine()) && + !rBoxItem.GetTop() && + rBoxItem.GetBottom() ) + { + SwLineEntry aFollowTop( !bVert ? nTop : nRight, !bVert ? nLeft : nTop, !bVert ? nRight : nBottom, aB ); + Insert( aFollowTop, !bVert ); + } +} + +void SwTabFrmPainter::Insert( SwLineEntry& rNew, bool bHori ) +{ + // get all lines from structure, that have key entry of pLE + SwLineEntryMap* pLine2 = bHori ? &maHoriLines : &maVertLines; + const SwTwips nKey = rNew.mnKey; + SwLineEntryMapIter aMapIter = pLine2->find( nKey ); + + SwLineEntrySet* pLineSet = aMapIter != pLine2->end() ? &((*aMapIter).second) : 0; + if ( !pLineSet ) + { + SwLineEntrySet aNewSet; + (*pLine2)[ nKey ] = aNewSet; + pLineSet = &(*pLine2)[ nKey ]; + } + SwLineEntrySetIter aIter = pLineSet->begin(); + + while ( pLineSet && aIter != pLineSet->end() && rNew.mnStartPos < rNew.mnEndPos ) + { + const SwLineEntry& rOld = *aIter; + const SwLineEntry::OverlapType nOverlapType = rOld.Overlaps( rNew ); + + const svx::frame::Style& rOldAttr = rOld.maAttribute; + const svx::frame::Style& rNewAttr = rNew.maAttribute; + const svx::frame::Style& rCmpAttr = rNewAttr > rOldAttr ? rNewAttr : rOldAttr; + + if ( SwLineEntry::OVERLAP1 == nOverlapType ) + { + OSL_ENSURE( rNew.mnStartPos >= rOld.mnStartPos, "Overlap type 3? How this?" ); + + // new left segment + const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr ); + + // new middle segment + const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rOld.mnEndPos, rCmpAttr ); + + // new right segment + rNew.mnStartPos = rOld.mnEndPos; + + // update current lines set + pLineSet->erase( aIter ); + if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft ); + if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle ); + + aIter = pLineSet->begin(); + + continue; // start over + } + else if ( SwLineEntry::OVERLAP2 == nOverlapType ) + { + // new left segment + const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, rOldAttr ); + + // new middle segment + const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rNew.mnEndPos, rCmpAttr ); + + // new right segment + const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr ); + + // update current lines set + pLineSet->erase( aIter ); + if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft ); + if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle ); + if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight ); + + rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted! + + break; // we are finished + } + else if ( SwLineEntry::OVERLAP3 == nOverlapType ) + { + // new left segment + const SwLineEntry aLeft( nKey, rNew.mnStartPos, rOld.mnStartPos, rNewAttr ); + + // new middle segment + const SwLineEntry aMiddle( nKey, rOld.mnStartPos, rNew.mnEndPos, rCmpAttr ); + + // new right segment + const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, rOldAttr ); + + // update current lines set + pLineSet->erase( aIter ); + if ( aLeft.mnStartPos < aLeft.mnEndPos ) pLineSet->insert( aLeft ); + if ( aMiddle.mnStartPos < aMiddle.mnEndPos ) pLineSet->insert( aMiddle ); + if ( aRight.mnStartPos < aRight.mnEndPos ) pLineSet->insert( aRight ); + + rNew.mnStartPos = rNew.mnEndPos; // rNew should not be inserted! + + break; // we are finished + } + + ++aIter; + } + + if ( rNew.mnStartPos < rNew.mnEndPos ) // insert rest + pLineSet->insert( rNew ); +} + +// +// FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES END +// + +/************************************************************************* +|* +|* SwRootFrm::Paint() +|* +|* Beschreibung +|* Fuer jede sichtbare Seite, die von Rect ber?hrt wird einmal Painten. +|* 1. Umrandungen und Hintergruende Painten. +|* 2. Den Draw Layer (Ramen und Zeichenobjekte) der unter dem Dokument +|* liegt painten (Hoelle). +|* 3. Den Dokumentinhalt (Text) Painten. +|* 4. Den Drawlayer der ueber dem Dokuemnt liegt painten. +|* +|*************************************************************************/ + +void +SwRootFrm::Paint(SwRect const& rRect, SwPrintData const*const pPrintData) const +{ + OSL_ENSURE( Lower() && Lower()->IsPageFrm(), "Lower der Root keine Seite." ); + + PROTOCOL( this, PROT_FILE_INIT, 0, 0) + + sal_Bool bResetRootPaint = sal_False; + ViewShell *pSh = pCurrShell; + + if ( pSh->GetWin() ) + { + if ( pSh->GetOut() == pSh->GetWin() && !pSh->GetWin()->IsVisible() ) + { + return; + } + if ( SwRootFrm::bInPaint ) + { + SwPaintQueue::Add( pSh, rRect ); + return; + } + } + else + SwRootFrm::bInPaint = bResetRootPaint = sal_True; + + SwSavePaintStatics *pStatics = 0; + if ( pGlobalShell ) + pStatics = new SwSavePaintStatics(); + pGlobalShell = pSh; + + if( !pSh->GetWin() ) + pProgress = SfxProgress::GetActiveProgress( (SfxObjectShell*) pSh->GetDoc()->GetDocShell() ); + + ::SwCalcPixStatics( pSh->GetOut() ); + aGlobalRetoucheColor = pSh->Imp()->GetRetoucheColor(); + + //Ggf. eine Action ausloesen um klare Verhaeltnisse zu schaffen. + //Durch diesen Kunstgriff kann in allen Paints davon ausgegangen werden, + //das alle Werte gueltigt sind - keine Probleme, keine Sonderbehandlung(en). + // --> OD 2008-10-07 #i92745# + // Extend check on certain states of the 'current' <ViewShell> instance to + // all existing <ViewShell> instances. + bool bPerformLayoutAction( true ); + { + ViewShell* pTmpViewShell = pSh; + do { + if ( pTmpViewShell->IsInEndAction() || + pTmpViewShell->IsPaintInProgress() || + ( pTmpViewShell->Imp()->IsAction() && + pTmpViewShell->Imp()->GetLayAction().IsActionInProgress() ) ) + { + bPerformLayoutAction = false; + } + + pTmpViewShell = static_cast<ViewShell*>(pTmpViewShell->GetNext()); + } while ( bPerformLayoutAction && pTmpViewShell != pSh ); + } + if ( bPerformLayoutAction ) + // <-- + { + ((SwRootFrm*)this)->ResetTurbo(); + SwLayAction aAction( (SwRootFrm*)this, pSh->Imp() ); + aAction.SetPaint( sal_False ); + aAction.SetComplete( sal_False ); + aAction.SetReschedule( pProgress ? sal_True : sal_False ); + aAction.Action(); + ((SwRootFrm*)this)->ResetTurboFlag(); + if ( !pSh->ActionPend() ) + pSh->Imp()->DelRegion(); + } + + SwRect aRect( rRect ); + aRect.Intersection( pSh->VisArea() ); + + const sal_Bool bExtraData = ::IsExtraData( GetFmt()->GetDoc() ); + + pLines = new SwLineRects; //Sammler fuer Umrandungen. + + // #104289#. During painting, something (OLE) can + // load the linguistic, which in turn can cause a reformat + // of the document. Dangerous! We better set this flag to + // avoid the reformat. + const sal_Bool bOldAction = IsCallbackActionEnabled(); + ((SwRootFrm*)this)->SetCallbackActionEnabled( sal_False ); + + const SwPageFrm *pPage = pSh->Imp()->GetFirstVisPage(); + + const bool bBookMode = pGlobalShell->GetViewOptions()->IsViewLayoutBookMode(); + if ( bBookMode && pPage->GetPrev() && static_cast<const SwPageFrm*>(pPage->GetPrev())->IsEmptyPage() ) + pPage = static_cast<const SwPageFrm*>(pPage->GetPrev()); + + // #i68597# + const bool bGridPainting(pSh->GetWin() && pSh->Imp()->HasDrawView() && pSh->Imp()->GetDrawView()->IsGridVisible()); + + // --> OD 2008-05-16 #i84659# +// while ( pPage && !::IsShortCut( aRect, pPage->Frm() ) ) + while ( pPage ) + // <-- + { + const bool bPaintRightShadow = pPage->IsRightShadowNeeded(); + const bool bPaintLeftShadow = pPage->IsLeftShadowNeeded(); + const bool bRightSidebar = pPage->SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT; + + if ( !pPage->IsEmptyPage() ) + { + SwRect aPaintRect; + SwPageFrm::GetBorderAndShadowBoundRect( pPage->Frm(), pSh, aPaintRect, + bPaintLeftShadow, bPaintRightShadow, bRightSidebar ); + + if ( aRect.IsOver( aPaintRect ) ) + // <-- + { + if ( pSh->GetWin() ) + { + pSubsLines = new SwSubsRects; + // OD 18.11.2002 #99672# - create array for special sub-lines + pSpecSubsLines = new SwSubsRects; + } + + aPaintRect._Intersection( aRect ); + + if ( bExtraData && + pSh->GetWin() && pSh->IsInEndAction() ) + { + // enlarge paint rectangle to complete page width, subtract + // current paint area and invalidate the resulting region. + SWRECTFN( pPage ) + SwRect aPageRectTemp( aPaintRect ); + (aPageRectTemp.*fnRect->fnSetLeftAndWidth)( + (pPage->Frm().*fnRect->fnGetLeft)(), + (pPage->Frm().*fnRect->fnGetWidth)() ); + aPageRectTemp._Intersection( pSh->VisArea() ); + Region aPageRectRegion( aPageRectTemp.SVRect() ); + aPageRectRegion.Exclude( aPaintRect.SVRect() ); + pSh->GetWin()->Invalidate( aPageRectRegion, INVALIDATE_CHILDREN ); + } + // <-- + + // --> OD 2007-08-20 #i80793# + // enlarge paint rectangle for objects overlapping the same pixel + // in all cases and before the DrawingLayer overlay is initialized. + lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) ); + // <-- + + // #i68597# + // moved paint pre-process for DrawingLayer overlay here since the above + // code dependent from bExtraData may expand the PaintRect + { + // #i75172# if called from ViewShell::ImplEndAction it sould no longer + // really be used but handled by ViewShell::ImplEndAction already + const Region aDLRegion(aPaintRect.SVRect()); + pSh->DLPrePaint2(aDLRegion); + } + + if(OUTDEV_WINDOW == pGlobalShell->GetOut()->GetOutDevType()) + { + /// OD 27.09.2002 #103636# - changed method SwLayVout::Enter(..) + /// 2nd parameter is no longer <const> and will be set to the + /// rectangle the virtual output device is calculated from <aPaintRect>, + /// if the virtual output is used. + pVout->Enter( pSh, aPaintRect, !bNoVirDev ); + + /// OD 27.09.2002 #103636# - adjust paint rectangle to pixel size + /// Thus, all objects overlapping on pixel level with the unadjusted + /// paint rectangle will be considered in the paint. + lcl_AdjustRectToPixelSize( aPaintRect, *(pSh->GetOut()) ); + } + + // maybe this can be put in the above scope. Since we are not sure, just leave it ATM + pVout->SetOrgRect( aPaintRect ); + + /// OD 29.08.2002 #102450# + /// determine background color of page for <PaintLayer> method + /// calls, paint <hell> or <heaven> + const Color aPageBackgrdColor = pPage->GetDrawBackgrdColor(); + + pPage->PaintBaBo( aPaintRect, pPage, sal_True ); + + if ( pSh->Imp()->HasDrawView() ) + { + pLines->LockLines( sal_True ); + // OD 29.08.2002 #102450# - add 3rd parameter + // OD 09.12.2002 #103045# - add 4th parameter for horizontal text direction. + const IDocumentDrawModelAccess* pIDDMA = pSh->getIDocumentDrawModelAccess(); + pSh->Imp()->PaintLayer( pIDDMA->GetHellId(), pPrintData, aPaintRect, + &aPageBackgrdColor, (pPage->IsRightToLeft() ? true : false) ); + pLines->PaintLines( pSh->GetOut() ); + pLines->LockLines( sal_False ); + } + + if( pSh->GetWin() ) + { + // OD 18.11.2002 #99672# - collect sub-lines + pPage->RefreshSubsidiary( aPaintRect ); + // OD 18.11.2002 #99672# - paint special sub-lines + pSpecSubsLines->PaintSubsidiary( pSh->GetOut(), NULL ); + } + + pPage->Paint( aPaintRect ); + + // OD 20.12.2002 #94627# - no paint of page border and shadow, if + // writer is in place mode. + if( pSh->GetWin() && pSh->GetDoc()->GetDocShell() && + !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() ) + { + // OD 12.02.2003 #i9719#, #105645# - use new method + // <SwPageFrm::PaintBorderAndShadow(..)>. + SwPageFrm::PaintBorderAndShadow( pPage->Frm(), pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar ); + SwPageFrm::PaintNotesSidebar( pPage->Frm(), pSh, pPage->GetPhyPageNum(), bRightSidebar); + } + + pLines->PaintLines( pSh->GetOut() ); + + if ( pSh->Imp()->HasDrawView() ) + { + /// OD 29.08.2002 #102450# - add 3rd parameter + // OD 09.12.2002 #103045# - add 4th parameter for horizontal text direction. + pSh->Imp()->PaintLayer( pSh->GetDoc()->GetHeavenId(), pPrintData, aPaintRect, + &aPageBackgrdColor, + (pPage->IsRightToLeft() ? true : false) ); + } + + if ( bExtraData ) + pPage->RefreshExtraData( aPaintRect ); + + if ( pSh->GetWin() ) + { + pSubsLines->PaintSubsidiary( pSh->GetOut(), pLines ); + DELETEZ( pSubsLines ); + DELETEZ( pSpecSubsLines ); + } + pVout->Leave(); + + // #i68597# + // needed to move grid painting inside Begin/EndDrawLayer bounds and to change + // output rect for it accordingly + if(bGridPainting) + { + SdrPaintView* pPaintView = pSh->Imp()->GetDrawView(); + SdrPageView* pPageView = pPaintView->GetSdrPageView(); + pPageView->DrawPageViewGrid(*pSh->GetOut(), aPaintRect.SVRect(), SwViewOption::GetTextGridColor() ); + } + + // #i68597# + // moved paint post-process for DrawingLayer overlay here, see above + { + pSh->DLPostPaint2(true); + } + } + } + else if ( bBookMode && pSh->GetWin() && !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() ) + { + // paint empty page + SwRect aPaintRect; + SwRect aEmptyPageRect( pPage->Frm() ); + + // code from vprint.cxx + const SwPageFrm& rFormatPage = pPage->GetFormatPage(); + aEmptyPageRect.SSize() = rFormatPage.Frm().SSize(); + + SwPageFrm::GetBorderAndShadowBoundRect( aEmptyPageRect, pSh, aPaintRect, + bPaintLeftShadow, bPaintRightShadow, bRightSidebar ); + aPaintRect._Intersection( aRect ); + + if ( aRect.IsOver( aEmptyPageRect ) ) + { + // #i75172# if called from ViewShell::ImplEndAction it sould no longer + // really be used but handled by ViewShell::ImplEndAction already + { + const Region aDLRegion(aPaintRect.SVRect()); + pSh->DLPrePaint2(aDLRegion); + } + + if( pSh->GetOut()->GetFillColor() != aGlobalRetoucheColor ) + pSh->GetOut()->SetFillColor( aGlobalRetoucheColor ); + + pSh->GetOut()->SetLineColor(); // OD 20.02.2003 #107369# - no line color + // OD 20.02.2003 #107369# - use aligned page rectangle + { + SwRect aTmpPageRect( aEmptyPageRect ); + ::SwAlignRect( aTmpPageRect, pSh ); + aEmptyPageRect = aTmpPageRect; + } + + pSh->GetOut()->DrawRect( aEmptyPageRect.SVRect() ); + + // paint empty page text + const Font& rEmptyPageFont = SwPageFrm::GetEmptyPageFont(); + const Font aOldFont( pSh->GetOut()->GetFont() ); + + pSh->GetOut()->SetFont( rEmptyPageFont ); + pSh->GetOut()->DrawText( aEmptyPageRect.SVRect(), SW_RESSTR( STR_EMPTYPAGE ), + TEXT_DRAW_VCENTER | + TEXT_DRAW_CENTER | + TEXT_DRAW_CLIP ); + + pSh->GetOut()->SetFont( aOldFont ); + // paint shadow and border for empty page + // OD 19.02.2003 #107369# - use new method to paint page border and + // shadow + SwPageFrm::PaintBorderAndShadow( aEmptyPageRect, pSh, bPaintLeftShadow, bPaintRightShadow, bRightSidebar ); + SwPageFrm::PaintNotesSidebar( aEmptyPageRect, pSh, pPage->GetPhyPageNum(), bRightSidebar); + + { + pSh->DLPostPaint2(true); + } + } + } + + OSL_ENSURE( !pPage->GetNext() || pPage->GetNext()->IsPageFrm(), + "Nachbar von Seite keine Seite." ); + pPage = (SwPageFrm*)pPage->GetNext(); + } + + DELETEZ( pLines ); + + if ( bResetRootPaint ) + SwRootFrm::bInPaint = sal_False; + if ( pStatics ) + delete pStatics; + else + { + pProgress = 0; + pGlobalShell = 0; + } + + ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction ); +} + +/************************************************************************* +|* +|* SwLayoutFrm::Paint() +|* +|*************************************************************************/ + +void MA_FASTCALL lcl_EmergencyFormatFtnCont( SwFtnContFrm *pCont ) +{ + //Es kann sein, dass der Cont vernichtet wird. + SwCntntFrm *pCnt = pCont->ContainsCntnt(); + while ( pCnt && pCnt->IsInFtn() ) + { + pCnt->Calc(); + pCnt = pCnt->GetNextCntntFrm(); + } +} + +class SwShortCut +{ + SwRectDist fnCheck; + long nLimit; +public: + SwShortCut( const SwFrm& rFrm, const SwRect& rRect ); + sal_Bool Stop( const SwRect& rRect ) const + { return (rRect.*fnCheck)( nLimit ) > 0; } +}; + +SwShortCut::SwShortCut( const SwFrm& rFrm, const SwRect& rRect ) +{ + sal_Bool bVert = rFrm.IsVertical(); + sal_Bool bR2L = rFrm.IsRightToLeft(); + if( rFrm.IsNeighbourFrm() && bVert == bR2L ) + { + if( bVert ) + { + fnCheck = &SwRect::GetBottomDistance; + nLimit = rRect.Top(); + } + else + { + fnCheck = &SwRect::GetLeftDistance; + nLimit = rRect.Left() + rRect.Width(); + } + } + else if( bVert == rFrm.IsNeighbourFrm() ) + { + fnCheck = &SwRect::GetTopDistance; + nLimit = rRect.Top() + rRect.Height(); + } + else + { + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( rFrm.IsVertLR() ) + { + fnCheck = &SwRect::GetLeftDistance; + nLimit = rRect.Right(); + } + else + { + fnCheck = &SwRect::GetRightDistance; + nLimit = rRect.Left(); + } + } +} + +void SwLayoutFrm::Paint(SwRect const& rRect, SwPrintData const*const) const +{ + ViewShell *pSh = getRootFrm()->GetCurrShell(); + + // --> FME 2004-06-24 #i16816# tagged pdf support + Frm_Info aFrmInfo( *this ); + SwTaggedPDFHelper aTaggedPDFHelper( 0, &aFrmInfo, 0, *pSh->GetOut() ); + // <-- + + const SwFrm *pFrm = Lower(); + if ( !pFrm ) + return; + + SwShortCut aShortCut( *pFrm, rRect ); + sal_Bool bCnt; + if ( sal_True == (bCnt = pFrm->IsCntntFrm()) ) + pFrm->Calc(); + + if ( pFrm->IsFtnContFrm() ) + { + ::lcl_EmergencyFormatFtnCont( (SwFtnContFrm*)pFrm ); + pFrm = Lower(); + } + + const SwPageFrm *pPage = 0; + const sal_Bool bWin = pGlobalShell->GetWin() ? sal_True : sal_False; + + while ( IsAnLower( pFrm ) ) + { + SwRect aPaintRect( pFrm->PaintArea() ); + if( aShortCut.Stop( aPaintRect ) ) + break; + if ( bCnt && pProgress ) + pProgress->Reschedule(); + + //Wenn ein Frm es explizit will muss retouchiert werden. + //Erst die Retouche, denn selbige koennte die aligned'en Raender + //plaetten. + if ( pFrm->IsRetouche() ) + { + if ( pFrm->IsRetoucheFrm() && bWin && !pFrm->GetNext() ) + { if ( !pPage ) + pPage = FindPageFrm(); + pFrm->Retouche( pPage, rRect ); + } + pFrm->ResetRetouche(); + } + + if ( rRect.IsOver( aPaintRect ) ) + { + if ( bCnt && pFrm->IsCompletePaint() && + !rRect.IsInside( aPaintRect ) && GetpApp()->AnyInput( INPUT_KEYBOARD ) ) + { + //fix(8104): Es kann vorkommen, dass die Verarbeitung nicht + //vollstaendig war, aber trotzdem Teile des Absatzes gepaintet + //werden. In der Folge werden dann evtl. wiederum andere Teile + //des Absatzes garnicht mehr gepaintet. Einziger Ausweg scheint + //hier ein Invalidieren der Windows zu sein. + //Um es nicht alzu Heftig werden zu lassen versuche ich hier + //das Rechteck zu begrenzen indem der gewuenschte Teil gepaintet + //und nur die uebrigen Absatzanteile invalidiert werden. + if ( aPaintRect.Left() == rRect.Left() && + aPaintRect.Right() == rRect.Right() ) + { + aPaintRect.Bottom( rRect.Top() - 1 ); + if ( aPaintRect.Height() > 0 ) + pGlobalShell->InvalidateWindows(aPaintRect); + aPaintRect.Top( rRect.Bottom() + 1 ); + aPaintRect.Bottom( pFrm->Frm().Bottom() ); + if ( aPaintRect.Height() > 0 ) + pGlobalShell->InvalidateWindows(aPaintRect); + aPaintRect.Top( pFrm->Frm().Top() ); + aPaintRect.Bottom( pFrm->Frm().Bottom() ); + } + else + { + pGlobalShell->InvalidateWindows( aPaintRect ); + pFrm = pFrm->GetNext(); + if ( pFrm && (sal_True == (bCnt = pFrm->IsCntntFrm())) ) + pFrm->Calc(); + continue; + } + } + pFrm->ResetCompletePaint(); + aPaintRect._Intersection( rRect ); + + pFrm->Paint( aPaintRect ); + + if ( Lower() && Lower()->IsColumnFrm() ) + { + //Ggf. die Spaltentrennlinien malen. Fuer den Seitenbody ist + //nicht der Upper sondern die Seite Zustaendig. + const SwFrmFmt *pFmt = GetUpper() && GetUpper()->IsPageFrm() + ? GetUpper()->GetFmt() + : GetFmt(); + const SwFmtCol &rCol = pFmt->GetCol(); + if ( rCol.GetLineAdj() != COLADJ_NONE ) + { + if ( !pPage ) + pPage = pFrm->FindPageFrm(); + + PaintColLines( aPaintRect, rCol, pPage ); + } + } + } + if ( !bCnt && pFrm->GetNext() && pFrm->GetNext()->IsFtnContFrm() ) + ::lcl_EmergencyFormatFtnCont( (SwFtnContFrm*)pFrm->GetNext() ); + + pFrm = pFrm->GetNext(); + if ( pFrm && (sal_True == (bCnt = pFrm->IsCntntFrm())) ) + pFrm->Calc(); + } +} + +/** FlyFrm::IsBackgroundTransparent - for feature #99657# + + OD 12.08.2002 + determines, if background of fly frame has to be drawn transparent + declaration found in /core/inc/flyfrm.cxx + OD 08.10.2002 #103898# - If the background of the fly frame itself is not + transparent and the background is inherited from its parent/grandparent, + the background brush, used for drawing, has to be investigated for transparency. + + @author OD + + @return true, if background is transparent drawn. +*/ +sal_Bool SwFlyFrm::IsBackgroundTransparent() const +{ + sal_Bool bBackgroundTransparent = GetFmt()->IsBackgroundTransparent(); + if ( !bBackgroundTransparent && + static_cast<const SwFlyFrmFmt*>(GetFmt())->IsBackgroundBrushInherited() ) + { + const SvxBrushItem* pBackgrdBrush = 0; + const Color* pSectionTOXColor = 0; + SwRect aDummyRect; + if ( GetBackgroundBrush( pBackgrdBrush, pSectionTOXColor, aDummyRect, false) ) + { + if ( pSectionTOXColor && + (pSectionTOXColor->GetTransparency() != 0) && + (pSectionTOXColor->GetColor() != COL_TRANSPARENT) ) + { + bBackgroundTransparent = sal_True; + } + else if ( pBackgrdBrush ) + { + if ( (pBackgrdBrush->GetColor().GetTransparency() != 0) && + (pBackgrdBrush->GetColor() != COL_TRANSPARENT) ) + { + bBackgroundTransparent = sal_True; + } + else + { + const GraphicObject *pTmpGrf = + static_cast<const GraphicObject*>(pBackgrdBrush->GetGraphicObject()); + if ( (pTmpGrf) && + (pTmpGrf->GetAttr().GetTransparency() != 0) + ) + { + bBackgroundTransparent = sal_True; + } + } + } + } + } + + return bBackgroundTransparent; +}; + +/** FlyFrm::IsShadowTransparent - for feature #99657# + + OD 13.08.2002 + determine, if shadow color of fly frame has to be drawn transparent + declaration found in /core/inc/flyfrm.cxx + + @author OD + + @return true, if shadow color is transparent. +*/ +sal_Bool SwFlyFrm::IsShadowTransparent() const +{ + return GetFmt()->IsShadowTransparent(); +}; + +/************************************************************************* +|* +|* SwFlyFrm::IsPaint() +|* +|*************************************************************************/ + +sal_Bool SwFlyFrm::IsPaint( SdrObject *pObj, const ViewShell *pSh ) +{ + SdrObjUserCall *pUserCall; + + if ( 0 == ( pUserCall = GetUserCall(pObj) ) ) + return sal_True; + + //Attributabhaengig nicht fuer Drucker oder PreView painten + sal_Bool bPaint = pFlyOnlyDraw || + ((SwContact*)pUserCall)->GetFmt()->GetPrint().GetValue(); + if ( !bPaint ) + bPaint = pSh->GetWin() && !pSh->IsPreView(); + + if ( bPaint ) + { + //Das Paint kann evtl. von von uebergeordneten Flys verhindert werden. + SwFrm *pAnch = 0; + if ( pObj->ISA(SwVirtFlyDrawObj) ) + { + SwFlyFrm *pFly = ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm(); + if ( pFlyOnlyDraw && pFlyOnlyDraw == pFly ) + return sal_True; + + //Die Anzeige eines Zwischenstadiums vermeiden, Flys die nicht mit + //der Seite auf der sie verankert sind ueberlappen werden auch + //nicht gepaintet. + //HACK: Ausnahme: Drucken von Rahmen in Tabellen, diese koennen + //bei uebergrossen Tabellen (HTML) schon mal auserhalb der Seite + //stehen. + SwPageFrm *pPage = pFly->FindPageFrm(); + if ( pPage ) + { + if ( pPage->Frm().IsOver( pFly->Frm() ) ) + pAnch = pFly->AnchorFrm(); + else if ( bTableHack && + pFly->Frm().Top() >= pFly->GetAnchorFrm()->Frm().Top() && + pFly->Frm().Top() < pFly->GetAnchorFrm()->Frm().Bottom() && + long(pSh->GetOut()) == + long(pSh->getIDocumentDeviceAccess()->getPrinter( false ) ) ) + { + pAnch = pFly->AnchorFrm(); + } + } + + } + else + { + // OD 13.10.2003 #i19919# - consider 'virtual' drawing objects + // OD 2004-03-29 #i26791# + pAnch = ((SwDrawContact*)pUserCall)->GetAnchorFrm( pObj ); + if ( pAnch ) + { + if ( !pAnch->GetValidPosFlag() ) + pAnch = 0; + else if ( long(pSh->GetOut()) == long(pSh->getIDocumentDeviceAccess()->getPrinter( false ))) + { + //HACK: fuer das Drucken muessen wir ein paar Objekte + //weglassen, da diese sonst doppelt gedruckt werden. + //Die Objekte sollen gedruckt werden, wenn der TableHack + //gerade greift. In der Folge duerfen sie nicht gedruckt werden + //wenn sie mit der Seite dran sind, ueber der sie von der + //Position her gerade schweben. + const SwPageFrm *pPage = pAnch->FindPageFrm(); + if ( !bTableHack && + !pPage->Frm().IsOver( pObj->GetCurrentBoundRect() ) ) + pAnch = 0; + } + } + else + { + // OD 02.07.2003 #108784# - debug assert + if ( !pObj->ISA(SdrObjGroup) ) + { + OSL_FAIL( "<SwFlyFrm::IsPaint(..)> - paint of drawing object without anchor frame!?" ); + } + } + } + if ( pAnch ) + { + if ( pAnch->IsInFly() ) + bPaint = SwFlyFrm::IsPaint( pAnch->FindFlyFrm()->GetVirtDrawObj(), + pSh ); + else if ( pFlyOnlyDraw ) + bPaint = sal_False; + } + else + bPaint = sal_False; + } + return bPaint; +} + +/************************************************************************* +|* SwCellFrm::Paint( const SwRect& ) const +|*************************************************************************/ +void SwCellFrm::Paint(SwRect const& rRect, SwPrintData const*const) const +{ + if ( GetLayoutRowSpan() >= 1 ) + SwLayoutFrm::Paint( rRect ); +} + +/************************************************************************* +|* +|* SwFlyFrm::Paint() +|* +|*************************************************************************/ + +//Weiter unten definiert +void MA_FASTCALL lcl_PaintLowerBorders( const SwLayoutFrm *pLay, + const SwRect &rRect, const SwPageFrm *pPage ); + +void SwFlyFrm::Paint(SwRect const& rRect, SwPrintData const*const) const +{ + //wegen der Ueberlappung von Rahmen und Zeichenobjekten muessen die + //Flys ihre Umrandung (und die der Innenliegenden) direkt ausgeben. + //z.B. #33066# + pLines->LockLines(sal_True); + + SwRect aRect( rRect ); + aRect._Intersection( Frm() ); + + OutputDevice* pOut = pGlobalShell->GetOut(); + pOut->Push( PUSH_CLIPREGION ); + pOut->SetClipRegion(); + const SwPageFrm* pPage = FindPageFrm(); + + const SwNoTxtFrm *pNoTxt = Lower() && Lower()->IsNoTxtFrm() + ? (SwNoTxtFrm*)Lower() : 0; + + bool bIsChart = false; //#i102950# don't paint additional borders for charts + //check whether we have a chart + if(pNoTxt) + { + const SwNoTxtNode* pNoTNd = dynamic_cast<const SwNoTxtNode*>(pNoTxt->GetNode()); + if( pNoTNd ) + { + SwOLENode* pOLENd = const_cast<SwOLENode*>(pNoTNd->GetOLENode()); + if( pOLENd && ChartPrettyPainter::IsChart( pOLENd->GetOLEObj().GetObject() ) ) + bIsChart = true; + } + } + + { + bool bContour = GetFmt()->GetSurround().IsContour(); + PolyPolygon aPoly; + if ( bContour ) + { + // OD 16.04.2003 #i13147# - add 2nd parameter with value <sal_True> + // to indicate that method is called for paint in order to avoid + // load of the intrinsic graphic. + bContour = GetContour( aPoly, sal_True ); + } + + // --> OD 2005-06-08 #i47804# - distinguish complete background paint + // and margin paint. + // paint complete background for Writer text fly frames + bool bPaintCompleteBack( !pNoTxt ); + // <-- + // paint complete background for transparent graphic and contour, + // if own background color exists. + const bool bIsGraphicTransparent = pNoTxt ? pNoTxt->IsTransparent() : false; + if ( !bPaintCompleteBack && + ( bIsGraphicTransparent|| bContour ) ) + { + const SvxBrushItem &rBack = GetFmt()->GetBackground(); + // OD 07.08.2002 #99657# #GetTransChg# + // to determine, if background has to be painted, by checking, if + // background color is not COL_TRANSPARENT ("no fill"/"auto fill") + // or a background graphic exists. + bPaintCompleteBack = !(rBack.GetColor() == COL_TRANSPARENT) || + rBack.GetGraphicPos() != GPOS_NONE; + } + // paint of margin needed. + const bool bPaintMarginOnly( !bPaintCompleteBack && + Prt().SSize() != Frm().SSize() ); + + // --> OD 2005-06-08 #i47804# - paint background of parent fly frame + // for transparent graphics in layer Hell, if parent fly frame isn't + // in layer Hell. It's only painted the intersection between the + // parent fly frame area and the paint area <aRect> + const IDocumentDrawModelAccess* pIDDMA = GetFmt()->getIDocumentDrawModelAccess(); + + if ( bIsGraphicTransparent && + GetVirtDrawObj()->GetLayer() == pIDDMA->GetHellId() && + GetAnchorFrm()->FindFlyFrm() ) + { + const SwFlyFrm* pParentFlyFrm = GetAnchorFrm()->FindFlyFrm(); + if ( pParentFlyFrm->GetDrawObj()->GetLayer() != + pIDDMA->GetHellId() ) + { + SwFlyFrm* pOldRet = pRetoucheFly2; + pRetoucheFly2 = const_cast<SwFlyFrm*>(this); + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pParentFlyFrm ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + SwRect aPaintRect( aRect ); + aPaintRect._Intersection( pParentFlyFrm->Frm() ); + pParentFlyFrm->PaintBackground( aPaintRect, pPage, rAttrs, sal_False, sal_False ); + + pRetoucheFly2 = pOldRet; + } + } + + if ( bPaintCompleteBack || bPaintMarginOnly ) + { + //#24926# JP 01.02.96, PaintBaBo in teilen hier, damit PaintBorder + //das orig. Rect bekommt, aber PaintBackground das begrenzte. + + // OD 2004-04-23 #116347# + pOut->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOut->SetLineColor(); + + pPage = FindPageFrm(); + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + // paint background + { + SwRegionRects aRegion( aRect ); + // --> OD 2007-12-13 #i80822# + // suppress painting of background in printing area for + // non-transparent graphics. + if ( bPaintMarginOnly || + ( pNoTxt && !bIsGraphicTransparent ) ) + // <-- + { + //Was wir eigentlich Painten wollen ist der schmale Streifen + //zwischen PrtArea und aeusserer Umrandung. + SwRect aTmp( Prt() ); aTmp += Frm().Pos(); + aRegion -= aTmp; + } + if ( bContour ) + { + pOut->Push(); + // --> OD 2007-12-13 #i80822# + // apply clip region under the same conditions, which are + // used in <SwNoTxtFrm::Paint(..)> to set the clip region + // for painting the graphic/OLE. Thus, the clip region is + // also applied for the PDF export. + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( !pOut->GetConnectMetaFile() || !pSh || !pSh->GetWin() ) + // <-- + { + pOut->SetClipRegion( aPoly ); + } + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + PaintBackground( aRegion[i], pPage, rAttrs, sal_False, sal_True ); + pOut->Pop(); + } + else + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + PaintBackground( aRegion[i], pPage, rAttrs, sal_False, sal_True ); + } + + // OD 06.08.2002 #99657# - paint border before painting background + // paint border + { + SwRect aTmp( rRect ); + PaintBorder( aTmp, pPage, rAttrs ); + } + + pOut->Pop(); + } + } + + // OD 19.12.2002 #106318# - fly frame will paint it's subsidiary lines and + // the subsidiary lines of its lowers on its own, due to overlapping with + // other fly frames or other objects. + if( pGlobalShell->GetWin() + && !bIsChart ) //#i102950# don't paint additional borders for charts + { + bool bSubsLineRectsCreated; + if ( pSubsLines ) + { + // Lock already existing subsidiary lines + pSubsLines->LockLines( sal_True ); + bSubsLineRectsCreated = false; + } + else + { + // create new subsidiardy lines + pSubsLines = new SwSubsRects; + bSubsLineRectsCreated = true; + } + + bool bSpecSubsLineRectsCreated; + if ( pSpecSubsLines ) + { + // Lock already existing special subsidiary lines + pSpecSubsLines->LockLines( sal_True ); + bSpecSubsLineRectsCreated = false; + } + else + { + // create new special subsidiardy lines + pSpecSubsLines = new SwSubsRects; + bSpecSubsLineRectsCreated = true; + } + // Add subsidiary lines of fly frame and its lowers + RefreshLaySubsidiary( pPage, aRect ); + // paint subsidiary lines of fly frame and its lowers + pSpecSubsLines->PaintSubsidiary( pOut, NULL ); + pSubsLines->PaintSubsidiary( pOut, pLines ); + if ( !bSubsLineRectsCreated ) + // unlock subsidiary lines + pSubsLines->LockLines( sal_False ); + else + // delete created subsidiary lines container + DELETEZ( pSubsLines ); + + if ( !bSpecSubsLineRectsCreated ) + // unlock special subsidiary lines + pSpecSubsLines->LockLines( sal_False ); + else + { + // delete created special subsidiary lines container + DELETEZ( pSpecSubsLines ); + } + } + + SwLayoutFrm::Paint( aRect ); + + Validate(); + + // OD 19.12.2002 #106318# - first paint lines added by fly frame paint + // and then unlock other lines. + pLines->PaintLines( pOut ); + pLines->LockLines( sal_False ); + + pOut->Pop(); + + if ( pProgress && pNoTxt ) + pProgress->Reschedule(); +} +/************************************************************************* +|* +|* SwTabFrm::Paint() +|* +|*************************************************************************/ + +void SwTabFrm::Paint(SwRect const& rRect, SwPrintData const*const) const +{ + if ( pGlobalShell->GetViewOptions()->IsTable() ) + { + // --> collapsing borders FME 2005-05-27 #i29550# + if ( IsCollapsingBorders() ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + // paint shadow + if ( rAttrs.GetShadow().GetLocation() != SVX_SHADOW_NONE ) + { + SwRect aRect; + ::lcl_CalcBorderRect( aRect, this, rAttrs, sal_True ); + PaintShadow( rRect, aRect, rAttrs ); + } + + // paint lines + SwTabFrmPainter aHelper( *this ); + aHelper.PaintLines( *pGlobalShell->GetOut(), rRect ); + } + // <-- collapsing + + SwLayoutFrm::Paint( rRect ); + } + // OD 10.01.2003 #i6467# - no light grey rectangle for page preview + else if ( pGlobalShell->GetWin() && !pGlobalShell->IsPreView() ) + { + // OD 10.01.2003 #i6467# - intersect output rectangle with table frame + SwRect aTabRect( Prt() ); + aTabRect.Pos() += Frm().Pos(); + SwRect aTabOutRect( rRect ); + aTabOutRect.Intersection( aTabRect ); + pGlobalShell->GetViewOptions()-> + DrawRect( pGlobalShell->GetOut(), aTabOutRect, COL_LIGHTGRAY ); + } + ((SwTabFrm*)this)->ResetComplete(); +} + +/************************************************************************* +|* +|* SwFrm::PaintShadow() +|* +|* Beschreibung Malt einen Schatten wenns das FrmFormat fordert. +|* Der Schatten wird immer an den auesseren Rand des OutRect gemalt. +|* Das OutRect wird ggf. so verkleinert, dass auf diesem das +|* malen der Umrandung stattfinden kann. +|* +|*************************************************************************/ +/// OD 23.08.2002 #99657# +/// draw full shadow rectangle for frames with transparent drawn backgrounds. +void SwFrm::PaintShadow( const SwRect& rRect, SwRect& rOutRect, + const SwBorderAttrs &rAttrs ) const +{ + const SvxShadowItem &rShadow = rAttrs.GetShadow(); + const long nWidth = ::lcl_AlignWidth ( rShadow.GetWidth() ); + const long nHeight = ::lcl_AlignHeight( rShadow.GetWidth() ); + + SwRects aRegion( 2, 2 ); + SwRect aOut( rOutRect ); + + const sal_Bool bCnt = IsCntntFrm(); + const sal_Bool bTop = !bCnt || rAttrs.GetTopLine ( *(this) ) ? sal_True : sal_False; + const sal_Bool bBottom = !bCnt || rAttrs.GetBottomLine( *(this) ) ? sal_True : sal_False; + + SvxShadowLocation eLoc = rShadow.GetLocation(); + + SWRECTFN( this ) + if( IsVertical() ) + { + switch( eLoc ) + { + case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break; + case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break; + case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break; + case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_TOPLEFT; break; + default: break; + } + } + + /// OD 23.08.2002 #99657# - determine, if full shadow rectangle have to + /// be drawn or only two shadow rectangles beside the frame. + /// draw full shadow rectangle, if frame background is drawn transparent. + /// Status Quo: + /// SwLayoutFrm can have transparent drawn backgrounds. Thus, + /// "asked" their frame format. + sal_Bool bDrawFullShadowRectangle = + ( IsLayoutFrm() && + (static_cast<const SwLayoutFrm*>(this))->GetFmt()->IsBackgroundTransparent() + ); + switch ( eLoc ) + { + case SVX_SHADOW_BOTTOMRIGHT: + { + if ( bDrawFullShadowRectangle ) + { + /// OD 06.08.2002 #99657# - draw full shadow rectangle + aOut.Top( aOut.Top() + nHeight ); + aOut.Left( aOut.Left() + nWidth ); + aRegion.Insert( aOut, aRegion.Count() ); + } + else + { + aOut.Top ( aOut.Bottom() - nHeight ); + aOut.Left( aOut.Left() + nWidth ); + if ( bBottom ) + aRegion.Insert( aOut, aRegion.Count() ); + aOut.Left( aOut.Right() - nWidth ); + aOut.Top ( rOutRect.Top() + nHeight ); + if ( bBottom ) + aOut.Bottom( aOut.Bottom() - nHeight ); + if ( bCnt && (!bTop || !bBottom) ) + ::lcl_ExtendLeftAndRight( aOut, *(this), rAttrs, fnRect ); + aRegion.Insert( aOut, aRegion.Count() ); + } + + rOutRect.Right ( rOutRect.Right() - nWidth ); + rOutRect.Bottom( rOutRect.Bottom()- nHeight ); + } + break; + case SVX_SHADOW_TOPLEFT: + { + if ( bDrawFullShadowRectangle ) + { + /// OD 06.08.2002 #99657# - draw full shadow rectangle + aOut.Bottom( aOut.Bottom() - nHeight ); + aOut.Right( aOut.Right() - nWidth ); + aRegion.Insert( aOut, aRegion.Count() ); + } + else + { + aOut.Bottom( aOut.Top() + nHeight ); + aOut.Right ( aOut.Right() - nWidth ); + if ( bTop ) + aRegion.Insert( aOut, aRegion.Count() ); + aOut.Right ( aOut.Left() + nWidth ); + aOut.Bottom( rOutRect.Bottom() - nHeight ); + if ( bTop ) + aOut.Top( aOut.Top() + nHeight ); + if ( bCnt && (!bBottom || !bTop) ) + ::lcl_ExtendLeftAndRight( aOut, *(this), rAttrs, fnRect ); + aRegion.Insert( aOut, aRegion.Count() ); + } + + rOutRect.Left( rOutRect.Left() + nWidth ); + rOutRect.Top( rOutRect.Top() + nHeight ); + } + break; + case SVX_SHADOW_TOPRIGHT: + { + if ( bDrawFullShadowRectangle ) + { + /// OD 06.08.2002 #99657# - draw full shadow rectangle + aOut.Bottom( aOut.Bottom() - nHeight); + aOut.Left( aOut.Left() + nWidth ); + aRegion.Insert( aOut, aRegion.Count() ); + } + else + { + aOut.Bottom( aOut.Top() + nHeight ); + aOut.Left ( aOut.Left()+ nWidth ); + if ( bTop ) + aRegion.Insert( aOut, aRegion.Count() ); + aOut.Left ( aOut.Right() - nWidth ); + aOut.Bottom( rOutRect.Bottom() - nHeight ); + if ( bTop ) + aOut.Top( aOut.Top() + nHeight ); + if ( bCnt && (!bBottom || bTop) ) + ::lcl_ExtendLeftAndRight( aOut, *(this), rAttrs, fnRect ); + aRegion.Insert( aOut, aRegion.Count() ); + } + + rOutRect.Right( rOutRect.Right() - nWidth ); + rOutRect.Top( rOutRect.Top() + nHeight ); + } + break; + case SVX_SHADOW_BOTTOMLEFT: + { + if ( bDrawFullShadowRectangle ) + { + /// OD 06.08.2002 #99657# - draw full shadow rectangle + aOut.Top( aOut.Top() + nHeight ); + aOut.Right( aOut.Right() - nWidth ); + aRegion.Insert( aOut, aRegion.Count() ); + } + else + { + aOut.Top ( aOut.Bottom()- nHeight ); + aOut.Right( aOut.Right() - nWidth ); + if ( bBottom ) + aRegion.Insert( aOut, aRegion.Count() ); + aOut.Right( aOut.Left() + nWidth ); + aOut.Top( rOutRect.Top() + nHeight ); + if ( bBottom ) + aOut.Bottom( aOut.Bottom() - nHeight ); + if ( bCnt && (!bTop || !bBottom) ) + ::lcl_ExtendLeftAndRight( aOut, *(this), rAttrs, fnRect ); + aRegion.Insert( aOut, aRegion.Count() ); + } + + rOutRect.Left( rOutRect.Left() + nWidth ); + rOutRect.Bottom( rOutRect.Bottom() - nHeight ); + } + break; + default: + OSL_ENSURE( !this, "new ShadowLocation() ?" ); + break; + } + + OutputDevice *pOut = pGlobalShell->GetOut(); + + sal_uLong nOldDrawMode = pOut->GetDrawMode(); + Color aShadowColor( rShadow.GetColor() ); + if( aRegion.Count() && pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + // Is heigh contrast mode, the output device has already set the + // DRAWMODE_SETTINGSFILL flag. This causes the SetFillColor function + // to ignore the setting of a new color. Therefore we have to reset + // the drawing mode + pOut->SetDrawMode( 0 ); + aShadowColor = SwViewOption::GetFontColor(); + } + + if ( pOut->GetFillColor() != aShadowColor ) + pOut->SetFillColor( aShadowColor ); + + pOut->SetDrawMode( nOldDrawMode ); + + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + { + SwRect &rOut = aRegion[i]; + aOut = rOut; + // OD 30.09.2002 #103636# - no SwAlign of shadow rectangle + // no alignment necessary, because (1) <rRect> is already aligned + // and because (2) paint of border and background will occur later. + // Thus, (1) assures that no conflicts with neighbour object will occure + // and (2) assures that border and background is not affected by the + // shadow paint. + /* + ::SwAlignRect( aOut, pGlobalShell ); + */ + if ( rRect.IsOver( aOut ) && aOut.Height() > 0 && aOut.Width() > 0 ) + { + aOut._Intersection( rRect ); + pOut->DrawRect( aOut.SVRect() ); + } + } +} + +/************************************************************************* +|* +|* SwFrm::PaintBorderLine() +|* +|*************************************************************************/ + +void SwFrm::PaintBorderLine( const SwRect& rRect, + const SwRect& rOutRect, + const SwPageFrm *pPage, + const Color *pColor, + const SvxBorderStyle nStyle ) const +{ + if ( !rOutRect.IsOver( rRect ) ) + return; + + SwRect aOut( rOutRect ); + aOut._Intersection( rRect ); + + const SwTabFrm *pTab = IsCellFrm() ? FindTabFrm() : 0; + sal_uInt8 nSubCol = ( IsCellFrm() || IsRowFrm() ) ? SUBCOL_TAB : + ( IsInSct() ? SUBCOL_SECT : + ( IsInFly() ? SUBCOL_FLY : SUBCOL_PAGE ) ); + if( pColor && pGlobalShell->GetWin() && + Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + pColor = &SwViewOption::GetFontColor(); + } + + if ( pPage->GetSortedObjs() ) + { + SwRegionRects aRegion( aOut, 4, 1 ); + ::lcl_SubtractFlys( this, pPage, aOut, aRegion ); + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + pLines->AddLineRect( aRegion[i], pColor, nStyle, pTab, nSubCol ); + } + else + pLines->AddLineRect( aOut, pColor, nStyle, pTab, nSubCol ); +} + +/************************************************************************* +|* +|* SwFrm::PaintBorderLines() +|* +|* Beschreibung Nur alle Linien einfach oder alle Linien doppelt!!!! +|* +|*************************************************************************/ + +// OD 29.04.2003 #107169# - method called for left and right border rectangles. +// For a printer output device perform adjustment for non-overlapping top and +// bottom border rectangles. Thus, add parameter <_bPrtOutputDev> to indicate +// printer output device. +// NOTE: For printer output device left/right border rectangle <_iorRect> +// has to be already non-overlapping the outer top/bottom border rectangle. +void MA_FASTCALL lcl_SubTopBottom( SwRect& _iorRect, + const SvxBoxItem& _rBox, + const SwBorderAttrs& _rAttrs, + const SwFrm& _rFrm, + const SwRectFn& _rRectFn, + const sal_Bool _bPrtOutputDev ) +{ + const sal_Bool bCnt = _rFrm.IsCntntFrm(); + if ( _rBox.GetTop() && _rBox.GetTop()->GetInWidth() && + ( !bCnt || _rAttrs.GetTopLine( _rFrm ) ) + ) + { + // substract distance between outer and inner line. + SwTwips nDist = ::lcl_MinHeightDist( _rBox.GetTop()->GetDistance() ); + // OD 19.05.2003 #109667# - non-overlapping border rectangles: + // adjust x-/y-position, if inner top line is a hair line (width = 1) + sal_Bool bIsInnerTopLineHairline = sal_False; + if ( !_bPrtOutputDev ) + { + // additionally substract width of top outer line + // --> left/right inner/outer line doesn't overlap top outer line. + nDist += ::lcl_AlignHeight( _rBox.GetTop()->GetOutWidth() ); + } + else + { + // OD 29.04.2003 #107169# - additionally substract width of top inner line + // --> left/right inner/outer line doesn't overlap top inner line. + nDist += ::lcl_AlignHeight( _rBox.GetTop()->GetInWidth() ); + bIsInnerTopLineHairline = _rBox.GetTop()->GetInWidth() == 1; + } + (_iorRect.*_rRectFn->fnSubTop)( -nDist ); + // OD 19.05.2003 #109667# - adjust calculated border top, if inner top line + // is a hair line + if ( bIsInnerTopLineHairline ) + { + if ( _rFrm.IsVertical() ) + { + // right of border rectangle has to be checked and adjusted + Point aCompPt( _iorRect.Right(), 0 ); + Point aRefPt( aCompPt.X() + 1, aCompPt.Y() ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_True, -1 ); + _iorRect.Right( aCompPt.X() ); + } + else + { + // top of border rectangle has to be checked and adjusted + Point aCompPt( 0, _iorRect.Top() ); + Point aRefPt( aCompPt.X(), aCompPt.Y() - 1 ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_False, +1 ); + _iorRect.Top( aCompPt.Y() ); + } + } + } + + if ( _rBox.GetBottom() && _rBox.GetBottom()->GetInWidth() && + ( !bCnt || _rAttrs.GetBottomLine( _rFrm ) ) + ) + { + // substract distance between outer and inner line. + SwTwips nDist = ::lcl_MinHeightDist( _rBox.GetBottom()->GetDistance() ); + // OD 19.05.2003 #109667# - non-overlapping border rectangles: + // adjust x-/y-position, if inner bottom line is a hair line (width = 1) + sal_Bool bIsInnerBottomLineHairline = sal_False; + if ( !_bPrtOutputDev ) + { + // additionally substract width of bottom outer line + // --> left/right inner/outer line doesn't overlap bottom outer line. + nDist += ::lcl_AlignHeight( _rBox.GetBottom()->GetOutWidth() ); + } + else + { + // OD 29.04.2003 #107169# - additionally substract width of bottom inner line + // --> left/right inner/outer line doesn't overlap bottom inner line. + nDist += ::lcl_AlignHeight( _rBox.GetBottom()->GetInWidth() ); + bIsInnerBottomLineHairline = _rBox.GetBottom()->GetInWidth() == 1; + } + (_iorRect.*_rRectFn->fnAddBottom)( -nDist ); + // OD 19.05.2003 #109667# - adjust calculated border bottom, if inner + // bottom line is a hair line. + if ( bIsInnerBottomLineHairline ) + { + if ( _rFrm.IsVertical() ) + { + // left of border rectangle has to be checked and adjusted + Point aCompPt( _iorRect.Left(), 0 ); + Point aRefPt( aCompPt.X() - 1, aCompPt.Y() ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_True, +1 ); + _iorRect.Left( aCompPt.X() ); + } + else + { + // bottom of border rectangle has to be checked and adjusted + Point aCompPt( 0, _iorRect.Bottom() ); + Point aRefPt( aCompPt.X(), aCompPt.Y() + 1 ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_False, -1 ); + _iorRect.Bottom( aCompPt.Y() ); + } + } + } +} + +// method called for top and bottom border rectangles. +void MA_FASTCALL lcl_SubLeftRight( SwRect& rRect, + const SvxBoxItem& rBox, + const SwRectFn& rRectFn ) +{ + if ( rBox.GetLeft() && rBox.GetLeft()->GetInWidth() ) + { + const long nDist = ::lcl_MinWidthDist( rBox.GetLeft()->GetDistance() ) + + ::lcl_AlignWidth( rBox.GetLeft()->GetOutWidth() ); + (rRect.*rRectFn->fnSubLeft)( -nDist ); + } + + if ( rBox.GetRight() && rBox.GetRight()->GetInWidth() ) + { + const long nDist = ::lcl_MinWidthDist( rBox.GetRight()->GetDistance() ) + + ::lcl_AlignWidth( rBox.GetRight()->GetOutWidth() ); + (rRect.*rRectFn->fnAddRight)( -nDist ); + } +} + +sal_uInt16 lcl_GetLineWidth( const SvxBorderLine* pLine ) +{ + sal_uInt16 result = 0; + + if ( pLine != NULL ) + result = pLine->GetScaledWidth(); + + return result; +} + +double lcl_GetExtent( const SvxBorderLine* pSideLine, const SvxBorderLine* pOppositeLine ) +{ + double nExtent = 0.0; + + if ( pSideLine && !pSideLine->isEmpty() ) + nExtent = -lcl_GetLineWidth( pSideLine ) / 2.0; + else if ( pOppositeLine ) + nExtent = lcl_GetLineWidth( pOppositeLine ) / 2.0; + + return nExtent; +} + +// OD 19.05.2003 #109667# - merge <lcl_PaintLeftLine> and <lcl_PaintRightLine> +// into new method <lcl_PaintLeftRightLine(..)> +void lcl_PaintLeftRightLine( const sal_Bool _bLeft, + const SwFrm& _rFrm, + const SwPageFrm& /*_rPage*/, + const SwRect& _rOutRect, + const SwRect& /*_rRect*/, + const SwBorderAttrs& _rAttrs, + const SwRectFn& _rRectFn ) +{ + const SvxBoxItem& rBox = _rAttrs.GetBox(); + const sal_Bool bR2L = _rFrm.IsCellFrm() && _rFrm.IsRightToLeft(); + const SvxBorderLine* pLeftRightBorder = 0; + const SvxBorderLine* pTopBorder = rBox.GetTop(); + const SvxBorderLine* pBottomBorder = rBox.GetBottom(); + + if ( _bLeft ) + { + pLeftRightBorder = bR2L ? rBox.GetRight() : rBox.GetLeft(); + } + else + { + pLeftRightBorder = bR2L ? rBox.GetLeft() : rBox.GetRight(); + } + // OD 06.05.2003 #107169# - init boolean indicating printer output device. + const sal_Bool bPrtOutputDev = + ( OUTDEV_PRINTER == pGlobalShell->GetOut()->GetOutDevType() ); + + if ( !pLeftRightBorder ) + { + return; + } + + SwRect aRect( _rOutRect ); + if ( _bLeft ) + { + (aRect.*_rRectFn->fnAddRight)( ::lcl_AlignWidth( lcl_GetLineWidth( pLeftRightBorder ) ) - + (aRect.*_rRectFn->fnGetWidth)() ); + } + else + { + (aRect.*_rRectFn->fnSubLeft)( ::lcl_AlignWidth( lcl_GetLineWidth( pLeftRightBorder ) ) - + (aRect.*_rRectFn->fnGetWidth)() ); + } + + const sal_Bool bCnt = _rFrm.IsCntntFrm(); + + if ( bCnt ) + { + ::lcl_ExtendLeftAndRight( aRect, _rFrm, _rAttrs, _rRectFn ); + + // No Top / bottom borders for joint borders + if ( _rAttrs.JoinedWithPrev( _rFrm ) ) pTopBorder = NULL; + if ( _rAttrs.JoinedWithNext( _rFrm ) ) pBottomBorder = NULL; + } + + // OD 06.05.2003 #107169# - adjustments for printer output device + if ( bPrtOutputDev ) + { + // substract width of outer top line. + if ( rBox.GetTop() && (!bCnt || _rAttrs.GetTopLine( _rFrm )) ) + { + long nDist = ::lcl_AlignHeight( rBox.GetTop()->GetOutWidth() ); + (aRect.*_rRectFn->fnSubTop)( -nDist ); + // OD 19.05.2003 #109667# - If outer top line is hair line, calculated + // top has to be adjusted. + if ( nDist == 1 ) + { + if ( _rFrm.IsVertical() ) + { + // right of border rectangle has to be checked and adjusted + Point aCompPt( aRect.Right(), 0 ); + Point aRefPt( aCompPt.X() + 1, aCompPt.Y() ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_True, -1 ); + aRect.Right( aCompPt.X() ); + } + else + { + // top of border rectangle has to be checked and adjusted + Point aCompPt( 0, aRect.Top() ); + Point aRefPt( aCompPt.X(), aCompPt.Y() - 1 ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_False, +1 ); + aRect.Top( aCompPt.Y() ); + } + } + } + // substract width of outer bottom line. + if ( rBox.GetBottom() && (!bCnt || _rAttrs.GetBottomLine( _rFrm )) ) + { + long nDist = ::lcl_AlignHeight( rBox.GetBottom()->GetOutWidth()); + (aRect.*_rRectFn->fnAddBottom)( -nDist ); + // OD 19.05.2003 #109667# - If outer bottom line is hair line, calculated + // top has to be adjusted. + if ( nDist == 1 ) + { + if ( _rFrm.IsVertical() ) + { + // left of border rectangle has to be checked and adjusted + Point aCompPt( aRect.Left(), 0 ); + Point aRefPt( aCompPt.X() - 1, aCompPt.Y() ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_True, +1 ); + aRect.Left( aCompPt.X() ); + } + else + { + // bottom of border rectangle has to be checked and adjusted + Point aCompPt( 0, aRect.Bottom() ); + Point aRefPt( aCompPt.X(), aCompPt.Y() + 1 ); + lcl_CompPxPosAndAdjustPos( *(pGlobalShell->GetOut()), + aRefPt, aCompPt, + sal_False, -1 ); + aRect.Bottom( aCompPt.Y() ); + } + } + } + } + + if ( !pLeftRightBorder->GetInWidth() ) + { + // OD 06.05.2003 #107169# - add 6th parameter + ::lcl_SubTopBottom( aRect, rBox, _rAttrs, _rFrm, _rRectFn, bPrtOutputDev ); + } + + // TODO Postpone the processing of the primitives + if ( lcl_GetLineWidth( pLeftRightBorder ) > 0 ) + { + drawinglayer::primitive2d::Primitive2DSequence aSequence( 1 ); + + double nExtentIS = lcl_GetExtent( pTopBorder, NULL ); + double nExtentIE = lcl_GetExtent( pBottomBorder, NULL ); + double nExtentOS = lcl_GetExtent( NULL, pTopBorder ); + double nExtentOE = lcl_GetExtent( NULL, pBottomBorder ); + + if ( !_bLeft ) + { + nExtentIS = lcl_GetExtent( NULL, pTopBorder ); + nExtentIE = lcl_GetExtent( NULL, pBottomBorder ); + nExtentOS = lcl_GetExtent( pTopBorder, NULL ); + nExtentOE = lcl_GetExtent( pBottomBorder, NULL ); + } + + basegfx::B2DPoint aStart( aRect.Left() + aRect.Width() / 2.0, aRect.Top() + lcl_GetLineWidth( pTopBorder ) / 2.0 ); + basegfx::B2DPoint aEnd( aRect.Left() + aRect.Width() / 2.0, aRect.Bottom() - lcl_GetLineWidth( pBottomBorder ) / 2.0 ); + + double nLeftWidth = !_bLeft ? pLeftRightBorder->GetOutWidth() : pLeftRightBorder->GetInWidth( ); + double nRightWidth = !_bLeft ? pLeftRightBorder->GetInWidth() : pLeftRightBorder->GetOutWidth( ); + Color aLeftColor = _bLeft ? pLeftRightBorder->GetColorOut( _bLeft ) : pLeftRightBorder->GetColorIn( _bLeft ); + Color aRightColor = _bLeft ? pLeftRightBorder->GetColorIn( _bLeft ) : pLeftRightBorder->GetColorOut( _bLeft ); + + aSequence[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D( + aStart, aEnd, nLeftWidth, pLeftRightBorder->GetDistance(), nRightWidth, + nExtentIS, nExtentIE, nExtentOS, nExtentOE, + aLeftColor.getBColor(), aRightColor.getBColor(), + pLeftRightBorder->GetColorGap().getBColor(), + pLeftRightBorder->HasGapColor(), pLeftRightBorder->GetStyle( ) ); + + _rFrm.ProcessPrimitives( aSequence ); + } +} + +// OD 19.05.2003 #109667# - merge <lcl_PaintTopLine> and <lcl_PaintBottomLine> +// into <lcl_PaintTopLine> +void lcl_PaintTopBottomLine( const sal_Bool _bTop, + const SwFrm& _rFrm, + const SwPageFrm& /*_rPage*/, + const SwRect& _rOutRect, + const SwRect& /*_rRect*/, + const SwBorderAttrs& _rAttrs, + const SwRectFn& _rRectFn ) +{ + const SvxBoxItem& rBox = _rAttrs.GetBox(); + const SvxBorderLine* pTopBottomBorder = 0; + const SvxBorderLine* pLeftBorder = rBox.GetLeft(); + const SvxBorderLine* pRightBorder = rBox.GetRight(); + if ( _bTop ) + { + pTopBottomBorder = rBox.GetTop(); + } + else + { + pTopBottomBorder = rBox.GetBottom(); + } + + if ( !pTopBottomBorder ) + { + return; + } + + SwRect aRect( _rOutRect ); + if ( _bTop ) + { + (aRect.*_rRectFn->fnAddBottom)( ::lcl_AlignHeight( lcl_GetLineWidth( pTopBottomBorder ) ) - + (aRect.*_rRectFn->fnGetHeight)() ); + } + else + { + (aRect.*_rRectFn->fnSubTop)( ::lcl_AlignHeight( lcl_GetLineWidth( pTopBottomBorder ) ) - + (aRect.*_rRectFn->fnGetHeight)() ); + } + + // TODO Postpone the processing of the primitives + if ( lcl_GetLineWidth( pTopBottomBorder ) > 0 ) + { + drawinglayer::primitive2d::Primitive2DSequence aSequence( 1 ); + + double nExtentIS = lcl_GetExtent( pRightBorder, NULL ); + double nExtentIE = lcl_GetExtent( pLeftBorder, NULL ); + double nExtentOS = lcl_GetExtent( NULL, pRightBorder ); + double nExtentOE = lcl_GetExtent( NULL, pLeftBorder ); + + if ( !_bTop ) + { + nExtentIS = lcl_GetExtent( NULL, pRightBorder ); + nExtentIE = lcl_GetExtent( NULL, pLeftBorder ); + nExtentOS = lcl_GetExtent( pRightBorder, NULL ); + nExtentOE = lcl_GetExtent( pLeftBorder, NULL ); + } + + basegfx::B2DPoint aStart( aRect.Right() - lcl_GetLineWidth( pRightBorder ) / 2.0, aRect.Top() + aRect.Height() / 2.0 ); + basegfx::B2DPoint aEnd( aRect.Left() + lcl_GetLineWidth( pLeftBorder ) / 2.0, aRect.Top() + aRect.Height() / 2.0 ); + + double nLeftWidth = !_bTop ? pTopBottomBorder->GetOutWidth() : pTopBottomBorder->GetInWidth( ); + double nRightWidth = !_bTop ? pTopBottomBorder->GetInWidth() : pTopBottomBorder->GetOutWidth( ); + Color aLeftColor = _bTop ? pTopBottomBorder->GetColorOut( _bTop ) : pTopBottomBorder->GetColorIn( _bTop ); + Color aRightColor = _bTop ? pTopBottomBorder->GetColorIn( _bTop ) : pTopBottomBorder->GetColorOut( _bTop ); + + aSequence[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D( + aStart, aEnd, nLeftWidth, pTopBottomBorder->GetDistance(), nRightWidth, + nExtentIS, nExtentIE, nExtentOS, nExtentOE, + aLeftColor.getBColor(), aRightColor.getBColor(), + pTopBottomBorder->GetColorGap().getBColor(), + pTopBottomBorder->HasGapColor(), pTopBottomBorder->GetStyle( ) ); + + _rFrm.ProcessPrimitives( aSequence ); + } +} + +/************************************************************************* +|* +|* const SwFrm* lcl_HasNextCell( const SwFrm& rFrm ) +|* +|* No comment. #i15844# +|* +|*************************************************************************/ + +const SwFrm* lcl_HasNextCell( const SwFrm& rFrm ) +{ + OSL_ENSURE( rFrm.IsCellFrm(), + "lcl_HasNextCell( const SwFrm& rFrm ) should be called with SwCellFrm" ); + + const SwFrm* pTmpFrm = &rFrm; + do + { + if ( pTmpFrm->GetNext() ) + return pTmpFrm->GetNext(); + + pTmpFrm = pTmpFrm->GetUpper()->GetUpper(); + } + while ( pTmpFrm->IsCellFrm() ); + + return 0; +} + +/************************************************************************* +|* +|* SwFrm::PaintBorder() +|* +|* Beschreibung Malt Schatten und Umrandung +|* +|*************************************************************************/ + +/** local method to determine cell frame, from which the border attributes + for paint of top/bottom border has to be used. + + OD 21.02.2003 #b4779636#, #107692# + + @author OD + + @param _pCellFrm + input parameter - constant pointer to cell frame for which the cell frame + for the border attributes has to be determined. + + @param _rCellBorderAttrs + input parameter - constant reference to the border attributes of cell frame + <_pCellFrm>. + + @param _bTop + input parameter - boolean, that controls, if cell frame for top border or + for bottom border has to be determined. + + @return constant pointer to cell frame, for which the border attributes has + to be used +*/ +const SwFrm* lcl_GetCellFrmForBorderAttrs( const SwFrm* _pCellFrm, + const SwBorderAttrs& _rCellBorderAttrs, + const bool _bTop ) +{ + OSL_ENSURE( _pCellFrm, "No cell frame available, dying soon" ); + + // determine, if cell frame is at bottom/top border of a table frame and + // the table frame has/is a follow. + const SwFrm* pTmpFrm = _pCellFrm; + bool bCellAtBorder = true; + bool bCellAtLeftBorder = !_pCellFrm->GetPrev(); + bool bCellAtRightBorder = !_pCellFrm->GetNext(); + while( !pTmpFrm->IsRowFrm() || !pTmpFrm->GetUpper()->IsTabFrm() ) + { + pTmpFrm = pTmpFrm->GetUpper(); + if ( pTmpFrm->IsRowFrm() && + (_bTop ? pTmpFrm->GetPrev() : pTmpFrm->GetNext()) + ) + { + bCellAtBorder = false; + } + if ( pTmpFrm->IsCellFrm() ) + { + if ( pTmpFrm->GetPrev() ) + { + bCellAtLeftBorder = false; + } + if ( pTmpFrm->GetNext() ) + { + bCellAtRightBorder = false; + } + } + } + OSL_ENSURE( pTmpFrm && pTmpFrm->IsRowFrm(), "No RowFrm available" ); + + const SwLayoutFrm* pParentRowFrm = static_cast<const SwLayoutFrm*>(pTmpFrm); + const SwTabFrm* pParentTabFrm = + static_cast<const SwTabFrm*>(pParentRowFrm->GetUpper()); + + const bool bCellNeedsAttribute = bCellAtBorder && + ( _bTop ? + // bCellInFirstRowWithMaster + ( !pParentRowFrm->GetPrev() && + pParentTabFrm->IsFollow() && + 0 == pParentTabFrm->GetTable()->GetRowsToRepeat() ) : + // bCellInLastRowWithFollow + ( !pParentRowFrm->GetNext() && + pParentTabFrm->GetFollow() ) + ); + + const SwFrm* pRet = _pCellFrm; + if ( bCellNeedsAttribute ) + { + // determine, if cell frame has no borders inside the table. + const SwFrm* pNextCell = 0; + bool bNoBordersInside = false; + + if ( bCellAtLeftBorder && ( 0 != ( pNextCell = lcl_HasNextCell( *_pCellFrm ) ) ) ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNextCell ); + const SwBorderAttrs &rBorderAttrs = *aAccess.Get(); + const SvxBoxItem& rBorderBox = rBorderAttrs.GetBox(); + bCellAtRightBorder = !lcl_HasNextCell( *pNextCell ); + bNoBordersInside = + ( !rBorderBox.GetTop() || !pParentRowFrm->GetPrev() ) && + !rBorderBox.GetLeft() && + ( !rBorderBox.GetRight() || bCellAtRightBorder ) && + ( !rBorderBox.GetBottom() || !pParentRowFrm->GetNext() ); + } + else + { + const SvxBoxItem& rBorderBox = _rCellBorderAttrs.GetBox(); + bNoBordersInside = + ( !rBorderBox.GetTop() || !pParentRowFrm->GetPrev() ) && + ( !rBorderBox.GetLeft() || bCellAtLeftBorder ) && + ( !rBorderBox.GetRight() || bCellAtRightBorder ) && + ( !rBorderBox.GetBottom() || !pParentRowFrm->GetNext() ); + } + + if ( bNoBordersInside ) + { + if ( _bTop && !_rCellBorderAttrs.GetBox().GetTop() ) + { + // #b4779636#-hack: + // Cell frame has no top border and no border inside the table, but + // it is at the top border of a table frame, which is a follow. + // Thus, use border attributes of cell frame in first row of complete table. + // First, determine first table frame of complete table. + SwTabFrm* pMasterTabFrm = pParentTabFrm->FindMaster( true ); + // determine first row of complete table. + const SwFrm* pFirstRow = pMasterTabFrm->GetLower(); + // return first cell in first row + SwFrm* pLowerCell = const_cast<SwFrm*>(pFirstRow->GetLower()); + while ( !pLowerCell->IsCellFrm() || + ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrm() ) + ) + { + pLowerCell = pLowerCell->GetLower(); + } + OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrm(), "No CellFrm available" ); + pRet = pLowerCell; + } + else if ( !_bTop && !_rCellBorderAttrs.GetBox().GetBottom() ) + { + // #b4779636#-hack: + // Cell frame has no bottom border and no border inside the table, + // but it is at the bottom border of a table frame, which has a follow. + // Thus, use border attributes of cell frame in last row of complete table. + // First, determine last table frame of complete table. + SwTabFrm* pLastTabFrm = const_cast<SwTabFrm*>(pParentTabFrm->GetFollow()); + while ( pLastTabFrm->GetFollow() ) + { + pLastTabFrm = pLastTabFrm->GetFollow(); + } + // determine last row of complete table. + SwFrm* pLastRow = pLastTabFrm->GetLastLower(); + // return first bottom border cell in last row + SwFrm* pLowerCell = const_cast<SwFrm*>(pLastRow->GetLower()); + while ( !pLowerCell->IsCellFrm() || + ( pLowerCell->GetLower() && pLowerCell->GetLower()->IsRowFrm() ) + ) + { + if ( pLowerCell->IsRowFrm() ) + { + while ( pLowerCell->GetNext() ) + { + pLowerCell = pLowerCell->GetNext(); + } + } + pLowerCell = pLowerCell->GetLower(); + } + OSL_ENSURE( pLowerCell && pLowerCell->IsCellFrm(), "No CellFrm available" ); + pRet = pLowerCell; + } + } + } + + return pRet; +} + +void SwFrm::ProcessPrimitives( const drawinglayer::primitive2d::Primitive2DSequence& rSequence ) const +{ + basegfx::B2DRange aViewRange; + + SdrPage *pDrawPage = getRootFrm()->GetCurrShell()->Imp()->GetPageView()->GetPage(); + const drawinglayer::geometry::ViewInformation2D aNewViewInfos( + basegfx::B2DHomMatrix( ), + getRootFrm()->GetCurrShell()->GetOut()->GetViewTransformation(), + aViewRange, + GetXDrawPageForSdrPage( pDrawPage ), + 0.0, + uno::Sequence< beans::PropertyValue >() ); + + drawinglayer::processor2d::BaseProcessor2D * pProcessor2D = + sdr::contact::createBaseProcessor2DFromOutputDevice( + *getRootFrm()->GetCurrShell()->GetOut(), + aNewViewInfos ); + + if ( pProcessor2D ) + { + pProcessor2D->process( rSequence ); + delete pProcessor2D; + } +} + +void SwFrm::PaintBorder( const SwRect& rRect, const SwPageFrm *pPage, + const SwBorderAttrs &rAttrs ) const +{ + //fuer (Row,Body,Ftn,Root,Column,NoTxt) gibt's hier nix zu tun + if ( (GetType() & 0x90C5) ) + return; + + if ( (GetType() & 0x2000) && //Cell + !pGlobalShell->GetViewOptions()->IsTable() ) + return; + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( IsTabFrm() || IsCellFrm() || IsRowFrm() ) + { + const SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->IsCollapsingBorders() ) + return; + + if ( pTabFrm->GetTable()->IsNewModel() && ( !IsCellFrm() || IsCoveredCell() ) ) + return; + } + // <-- + + const bool bLine = rAttrs.IsLine() ? true : false; + const bool bShadow = rAttrs.GetShadow().GetLocation() != SVX_SHADOW_NONE; + + // OD 24.02.2003 #b4779636#, #107692# - flag to control, + // if #b4779636#-hack has to be used. + const bool bb4779636HackActive = true; + // OD 21.02.2003 #b4779636#, #107692# + const SwFrm* pCellFrmForBottomBorderAttrs = 0; + const SwFrm* pCellFrmForTopBorderAttrs = 0; + bool bFoundCellForTopOrBorderAttrs = false; + if ( bb4779636HackActive && IsCellFrm() ) + { + pCellFrmForBottomBorderAttrs = lcl_GetCellFrmForBorderAttrs( this, rAttrs, false ); + if ( pCellFrmForBottomBorderAttrs != this ) + bFoundCellForTopOrBorderAttrs = true; + pCellFrmForTopBorderAttrs = lcl_GetCellFrmForBorderAttrs( this, rAttrs, true ); + if ( pCellFrmForTopBorderAttrs != this ) + bFoundCellForTopOrBorderAttrs = true; + } + + // OD 24.02.2003 #b4779636#, #107692# - add condition <bFoundCellForTopOrBorderAttrs> + // for #b4779636#-hack + if ( bLine || bShadow || bFoundCellForTopOrBorderAttrs ) + { + //Wenn das Rechteck vollstandig innerhalb der PrtArea liegt, + //so braucht kein Rand gepainted werden. + //Fuer die PrtArea muss der Aligned'e Wert zugrunde gelegt werden, + //anderfalls wuerden u.U. Teile nicht verarbeitet. + SwRect aRect( Prt() ); + aRect += Frm().Pos(); + ::SwAlignRect( aRect, pGlobalShell ); + // OD 27.09.2002 #103636# - new local boolean variable in order to + // suspend border paint under special cases - see below. + // NOTE: This is a fix for the implementation of feature #99657#. + bool bDrawOnlyShadowForTransparentFrame = false; + if ( aRect.IsInside( rRect ) ) + { + // OD 27.09.2002 #103636# - paint shadow, if background is transparent. + // Because of introduced transparent background for fly frame #99657#, + // the shadow have to be drawn if the background is transparent, + // in spite the fact that the paint rectangle <rRect> lies fully + // in the printing area. + // NOTE to chosen solution: + // On transparent background, continue processing, but suspend + // drawing of border by setting <bDrawOnlyShadowForTransparentFrame> + // to true. + if ( IsLayoutFrm() && + static_cast<const SwLayoutFrm*>(this)->GetFmt()->IsBackgroundTransparent() ) + { + bDrawOnlyShadowForTransparentFrame = true; + } + else + { + return; + } + } + + if ( !pPage ) + pPage = FindPageFrm(); + + ::lcl_CalcBorderRect( aRect, this, rAttrs, sal_True ); + rAttrs.SetGetCacheLine( sal_True ); + if ( bShadow ) + PaintShadow( rRect, aRect, rAttrs ); + // OD 27.09.2002 #103636# - suspend drawing of border + // add condition < NOT bDrawOnlyShadowForTransparentFrame > - see above + // OD 24.02.2003 #b4779636#, #107692# - add condition <bFoundCellForTopOrBorderAttrs> + // for #b4779636#-hack. + if ( ( bLine || bFoundCellForTopOrBorderAttrs ) && + !bDrawOnlyShadowForTransparentFrame ) + { + const SwFrm* pDirRefFrm = IsCellFrm() ? FindTabFrm() : this; + SWRECTFN( pDirRefFrm ) + ::lcl_PaintLeftRightLine ( sal_True, *(this), *(pPage), aRect, rRect, rAttrs, fnRect ); + ::lcl_PaintLeftRightLine ( sal_False, *(this), *(pPage), aRect, rRect, rAttrs, fnRect ); + if ( !IsCntntFrm() || rAttrs.GetTopLine( *(this) ) ) + { + // OD 21.02.2003 #b4779636#, #107692# - + // #b4779636#-hack: If another cell frame for top border + // paint is found, paint its top border. + if ( IsCellFrm() && pCellFrmForTopBorderAttrs != this ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), + pCellFrmForTopBorderAttrs ); + const SwBorderAttrs &rTopAttrs = *aAccess.Get(); + ::lcl_PaintTopBottomLine( sal_True, *(this), *(pPage), aRect, rRect, rTopAttrs, fnRect ); + } + else + { + ::lcl_PaintTopBottomLine( sal_True, *(this), *(pPage), aRect, rRect, rAttrs, fnRect ); + } + } + if ( !IsCntntFrm() || rAttrs.GetBottomLine( *(this) ) ) + { + // OD 21.02.2003 #b4779636#, #107692# - + // #b4779636#-hack: If another cell frame for bottom border + // paint is found, paint its bottom border. + if ( IsCellFrm() && pCellFrmForBottomBorderAttrs != this ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), + pCellFrmForBottomBorderAttrs ); + const SwBorderAttrs &rBottomAttrs = *aAccess.Get(); + ::lcl_PaintTopBottomLine(sal_False, *(this), *(pPage), aRect, rRect, rBottomAttrs, fnRect); + } + else + { + ::lcl_PaintTopBottomLine(sal_False, *(this), *(pPage), aRect, rRect, rAttrs, fnRect); + } + } + } + rAttrs.SetGetCacheLine( sal_False ); + } +} +/************************************************************************* +|* +|* SwFtnContFrm::PaintBorder() +|* +|* Beschreibung Spezialimplementierung wg. der Fussnotenlinie. +|* Derzeit braucht nur der obere Rand beruecksichtigt werden. +|* Auf andere Linien und Schatten wird verzichtet. +|* +|*************************************************************************/ + +void SwFtnContFrm::PaintBorder( const SwRect& rRect, const SwPageFrm *pPage, + const SwBorderAttrs & ) const +{ + //Wenn das Rechteck vollstandig innerhalb der PrtArea liegt, so gibt es + //keinen Rand zu painten. + SwRect aRect( Prt() ); + aRect.Pos() += Frm().Pos(); + if ( !aRect.IsInside( rRect ) ) + PaintLine( rRect, pPage ); +} +/************************************************************************* +|* +|* SwFtnContFrm::PaintLine() +|* +|* Beschreibung Fussnotenline malen. +|* +|*************************************************************************/ + +void SwFtnContFrm::PaintLine( const SwRect& rRect, + const SwPageFrm *pPage ) const +{ + //Laenge der Linie ergibt sich aus der prozentualen Angabe am PageDesc. + //Die Position ist ebenfalls am PageDesc angegeben. + //Der Pen steht direkt im PageDesc. + + if ( !pPage ) + pPage = FindPageFrm(); + const SwPageFtnInfo &rInf = pPage->GetPageDesc()->GetFtnInfo(); + + SWRECTFN( this ) + SwTwips nPrtWidth = (Prt().*fnRect->fnGetWidth)(); + Fraction aFract( nPrtWidth, 1 ); + const SwTwips nWidth = (long)(aFract *= rInf.GetWidth()); + + SwTwips nX = (this->*fnRect->fnGetPrtLeft)(); + switch ( rInf.GetAdj() ) + { + case FTNADJ_CENTER: + nX += nPrtWidth/2 - nWidth/2; break; + case FTNADJ_RIGHT: + nX += nPrtWidth - nWidth; break; + case FTNADJ_LEFT: + /* do nothing */; break; + default: + OSL_ENSURE( !this, "Neues Adjustment fuer Fussnotenlinie?" ); + } + SwTwips nLineWidth = rInf.GetLineWidth(); + const SwRect aLineRect = bVert ? + SwRect( Point(Frm().Left()+Frm().Width()-rInf.GetTopDist()-nLineWidth, + nX), Size( nLineWidth, nWidth ) ) + : SwRect( Point( nX, Frm().Pos().Y() + rInf.GetTopDist() ), + Size( nWidth, rInf.GetLineWidth())); + if ( aLineRect.HasArea() ) + PaintBorderLine( rRect, aLineRect , pPage, &rInf.GetLineColor(), + rInf.GetLineStyle() ); +} + +/************************************************************************* +|* +|* SwLayoutFrm::PaintColLines() +|* +|* Beschreibung Painted die Trennlinien fuer die innenliegenden +|* Spalten. +|* +|*************************************************************************/ + +void SwLayoutFrm::PaintColLines( const SwRect &rRect, const SwFmtCol &rFmtCol, + const SwPageFrm *pPage ) const +{ + const SwFrm *pCol = Lower(); + if ( !pCol || !pCol->IsColumnFrm() ) + return; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + + SwRect aLineRect = Prt(); + aLineRect += Frm().Pos(); + + SwTwips nTop = ((aLineRect.*fnRect->fnGetHeight)()*rFmtCol.GetLineHeight()) + / 100 - (aLineRect.*fnRect->fnGetHeight)(); + SwTwips nBottom = 0; + + switch ( rFmtCol.GetLineAdj() ) + { + case COLADJ_CENTER: + nBottom = nTop / 2; nTop -= nBottom; break; + case COLADJ_TOP: + nBottom = nTop; nTop = 0; break; + case COLADJ_BOTTOM: + break; + default: + OSL_ENSURE( !this, "Neues Adjustment fuer Spaltenlinie?" ); + } + + if( nTop ) + (aLineRect.*fnRect->fnSubTop)( nTop ); + if( nBottom ) + (aLineRect.*fnRect->fnAddBottom)( nBottom ); + + SwTwips nPenHalf = rFmtCol.GetLineWidth(); + (aLineRect.*fnRect->fnSetWidth)( nPenHalf ); + nPenHalf /= 2; + + //Damit uns nichts verlorengeht muessen wir hier etwas grosszuegiger sein. + SwRect aRect( rRect ); + (aRect.*fnRect->fnSubLeft)( nPenHalf + nPixelSzW ); + (aRect.*fnRect->fnAddRight)( nPenHalf + nPixelSzW ); + SwRectGet fnGetX = IsRightToLeft() ? fnRect->fnGetLeft : fnRect->fnGetRight; + while ( pCol->GetNext() ) + { + (aLineRect.*fnRect->fnSetPosX) + ( (pCol->Frm().*fnGetX)() - nPenHalf ); + if ( aRect.IsOver( aLineRect ) ) + PaintBorderLine( aRect, aLineRect , pPage, &rFmtCol.GetLineColor(), + rFmtCol.GetLineStyle() ); + pCol = pCol->GetNext(); + } +} + +void SwPageFrm::PaintGrid( OutputDevice* pOut, SwRect &rRect ) const +{ + if( !bHasGrid || pRetoucheFly || pRetoucheFly2 ) + return; + GETGRID( this ) + if( pGrid && ( OUTDEV_PRINTER != pOut->GetOutDevType() ? + pGrid->GetDisplayGrid() : pGrid->GetPrintGrid() ) ) + { + const SwLayoutFrm* pBody = FindBodyCont(); + if( pBody ) + { + SwRect aGrid( pBody->Prt() ); + aGrid += pBody->Frm().Pos(); + + SwRect aInter( aGrid ); + aInter.Intersection( rRect ); + if( aInter.HasArea() ) + { + sal_Bool bGrid = pGrid->GetRubyTextBelow(); + sal_Bool bCell = GRID_LINES_CHARS == pGrid->GetGridType(); + long nGrid = pGrid->GetBaseHeight(); + const SwDoc* pDoc = GetFmt()->GetDoc(); + long nGridWidth = GETGRIDWIDTH(pGrid,pDoc); //for textgrid refactor + long nRuby = pGrid->GetRubyHeight(); + long nSum = nGrid + nRuby; + const Color *pCol = &pGrid->GetColor(); + + SwTwips nRight = aInter.Left() + aInter.Width(); + SwTwips nBottom = aInter.Top() + aInter.Height(); + if( IsVertical() ) + { + SwTwips nOrig = aGrid.Left() + aGrid.Width(); + SwTwips nY = nOrig + nSum * + ( ( nOrig - aInter.Left() ) / nSum ); + SwRect aTmp( Point( nY, aInter.Top() ), + Size( 1, aInter.Height() ) ); + SwTwips nX = aGrid.Top() + nGrid * + ( ( aInter.Top() - aGrid.Top() )/ nGrid ); + if( nX < aInter.Top() ) + nX += nGrid; + SwTwips nGridBottom = aGrid.Top() + aGrid.Height(); + sal_Bool bLeft = aGrid.Top() >= aInter.Top(); + sal_Bool bRight = nGridBottom <= nBottom; + sal_Bool bBorder = bLeft || bRight; + while( nY > nRight ) + { + aTmp.Pos().X() = nY; + if( bGrid ) + { + nY -= nGrid; + SwTwips nPosY = Max( aInter.Left(), nY ); + SwTwips nHeight = Min(nRight, aTmp.Pos().X())-nPosY; + if( nHeight > 0 ) + { + if( bCell ) + { + SwRect aVert( Point( nPosY, nX ), + Size( nHeight, 1 ) ); + while( aVert.Top() <= nBottom ) + { + PaintBorderLine(rRect,aVert,this,pCol); + aVert.Pos().Y() += nGrid; + } + } + else if( bBorder ) + { + SwRect aVert( Point( nPosY, aGrid.Top() ), + Size( nHeight, 1 ) ); + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().Y() = nGridBottom; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + else + { + nY -= nRuby; + if( bBorder ) + { + SwTwips nPos = Max( aInter.Left(), nY ); + SwTwips nW = Min(nRight, aTmp.Pos().X()) - nPos; + SwRect aVert( Point( nPos, aGrid.Top() ), + Size( nW, 1 ) ); + if( nW > 0 ) + { + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().Y() = nGridBottom; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + bGrid = !bGrid; + } + while( nY >= aInter.Left() ) + { + aTmp.Pos().X() = nY; + PaintBorderLine( rRect, aTmp, this, pCol); + if( bGrid ) + { + nY -= nGrid; + SwTwips nHeight = aTmp.Pos().X() + - Max(aInter.Left(), nY ); + if( nHeight > 0 ) + { + if( bCell ) + { + SwRect aVert( Point(aTmp.Pos().X()-nHeight, + nX ), Size( nHeight, 1 ) ); + while( aVert.Top() <= nBottom ) + { + PaintBorderLine(rRect,aVert,this,pCol); + aVert.Pos().Y() += nGrid; + } + } + else if( bBorder ) + { + SwRect aVert( Point(aTmp.Pos().X()-nHeight, + aGrid.Top() ), Size( nHeight, 1 ) ); + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().Y() = nGridBottom; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + else + { + nY -= nRuby; + if( bBorder ) + { + SwTwips nPos = Max( aInter.Left(), nY ); + SwTwips nW = Min(nRight, aTmp.Pos().X()) - nPos; + SwRect aVert( Point( nPos, aGrid.Top() ), + Size( nW, 1 ) ); + if( nW > 0 ) + { + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().Y() = nGridBottom; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + bGrid = !bGrid; + } + } + else + { + SwTwips nOrig = aGrid.Top(); + SwTwips nY = nOrig + nSum *( (aInter.Top()-nOrig)/nSum ); + SwRect aTmp( Point( aInter.Left(), nY ), + Size( aInter.Width(), 1 ) ); + //for textgrid refactor + SwTwips nX = aGrid.Left() + nGridWidth * + ( ( aInter.Left() - aGrid.Left() )/ nGridWidth ); + if( nX < aInter.Left() ) + nX += nGridWidth; + SwTwips nGridRight = aGrid.Left() + aGrid.Width(); + sal_Bool bLeft = aGrid.Left() >= aInter.Left(); + sal_Bool bRight = nGridRight <= nRight; + sal_Bool bBorder = bLeft || bRight; + while( nY < aInter.Top() ) + { + aTmp.Pos().Y() = nY; + if( bGrid ) + { + nY += nGrid; + SwTwips nPosY = Max( aInter.Top(), aTmp.Pos().Y() ); + SwTwips nHeight = Min(nBottom, nY ) - nPosY; + if( nHeight ) + { + if( bCell ) + { + SwRect aVert( Point( nX, nPosY ), + Size( 1, nHeight ) ); + while( aVert.Left() <= nRight ) + { + PaintBorderLine(rRect,aVert,this,pCol); + aVert.Pos().X() += nGridWidth; //for textgrid refactor + } + } + else if ( bBorder ) + { + SwRect aVert( Point( aGrid.Left(), nPosY ), + Size( 1, nHeight ) ); + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().X() = nGridRight; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + else + { + nY += nRuby; + if( bBorder ) + { + SwTwips nPos = Max(aInter.Top(),aTmp.Pos().Y()); + SwTwips nH = Min( nBottom, nY ) - nPos; + SwRect aVert( Point( aGrid.Left(), nPos ), + Size( 1, nH ) ); + if( nH > 0 ) + { + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().X() = nGridRight; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + bGrid = !bGrid; + } + while( nY <= nBottom ) + { + aTmp.Pos().Y() = nY; + PaintBorderLine( rRect, aTmp, this, pCol); + if( bGrid ) + { + nY += nGrid; + SwTwips nHeight = Min(nBottom, nY) - aTmp.Pos().Y(); + if( nHeight ) + { + if( bCell ) + { + SwRect aVert( Point( nX, aTmp.Pos().Y() ), + Size( 1, nHeight ) ); + while( aVert.Left() <= nRight ) + { + PaintBorderLine( rRect, aVert, this, pCol); + aVert.Pos().X() += nGridWidth; //for textgrid refactor + } + } + else if( bBorder ) + { + SwRect aVert( Point( aGrid.Left(), + aTmp.Pos().Y() ), Size( 1, nHeight ) ); + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().X() = nGridRight; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + else + { + nY += nRuby; + if( bBorder ) + { + SwTwips nPos = Max(aInter.Top(),aTmp.Pos().Y()); + SwTwips nH = Min( nBottom, nY ) - nPos; + SwRect aVert( Point( aGrid.Left(), nPos ), + Size( 1, nH ) ); + if( nH > 0 ) + { + if( bLeft ) + PaintBorderLine(rRect,aVert,this,pCol); + if( bRight ) + { + aVert.Pos().X() = nGridRight; + PaintBorderLine(rRect,aVert,this,pCol); + } + } + } + } + bGrid = !bGrid; + } + } + } + } + } +} + +/** paint margin area of a page + + OD 20.11.2002 for #104598#: + implement paint of margin area; margin area will be painted for a + view shell with a window and if the document is not in online layout. + + @author OD + + @param _rOutputRect + input parameter - constant instance reference of the rectangle, for + which an output has to be generated. + + @param _pViewShell + input parameter - instance of the view shell, on which the output + has to be generated. +*/ +void SwPageFrm::PaintMarginArea( const SwRect& _rOutputRect, + ViewShell* _pViewShell ) const +{ + if ( _pViewShell->GetWin() && + !_pViewShell->GetViewOptions()->getBrowseMode() ) + { + SwRect aPgPrtRect( Prt() ); + aPgPrtRect.Pos() += Frm().Pos(); + if ( !aPgPrtRect.IsInside( _rOutputRect ) ) + { + SwRect aPgRect = Frm(); + aPgRect._Intersection( _rOutputRect ); + if(aPgRect.Height() < 0 || aPgRect.Width() <= 0) // No intersection + return; + SwRegionRects aPgRegion( aPgRect ); + aPgRegion -= aPgPrtRect; + const SwPageFrm* pPage = static_cast<const SwPageFrm*>(this); + if ( pPage->GetSortedObjs() ) + ::lcl_SubtractFlys( this, pPage, aPgRect, aPgRegion ); + if ( aPgRegion.Count() ) + { + OutputDevice *pOut = _pViewShell->GetOut(); + if ( pOut->GetFillColor() != aGlobalRetoucheColor ) + pOut->SetFillColor( aGlobalRetoucheColor ); + for ( sal_uInt16 i = 0; i < aPgRegion.Count(); ++i ) + { + if ( 1 < aPgRegion.Count() ) + { + ::SwAlignRect( aPgRegion[i], pGlobalShell ); + if( !aPgRegion[i].HasArea() ) + continue; + } + pOut->DrawRect(aPgRegion[i].SVRect()); + } + } + } + } +} + +const sal_Int8 SwPageFrm::mnShadowPxWidth = 9; + +sal_Bool SwPageFrm::IsRightShadowNeeded() const +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const bool bIsLTR = getRootFrm()->IsLeftToRightViewLayout(); + + // We paint the right shadow if we're not in book mode + // or if we've no sibling or are the last page of the "row" + return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetNext() + || (this == Lower()) || (bIsLTR && OnRightPage()) + || (!bIsLTR && !OnRightPage()); + +} + +sal_Bool SwPageFrm::IsLeftShadowNeeded() const +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const bool bIsLTR = getRootFrm()->IsLeftToRightViewLayout(); + + // We paint the left shadow if we're not in book mode + // or if we've no sibling or are the last page of the "row" + return !pSh || (!pSh->GetViewOptions()->IsViewLayoutBookMode()) || !GetPrev() + || (bIsLTR && !OnRightPage()) + || (!bIsLTR && OnRightPage()); +} + +/** determine rectangle for bottom page shadow + + OD 12.02.2003 for #i9719# and #105645# + + @author OD +*/ +/*static*/ void SwPageFrm::GetHorizontalShadowRect( const SwRect& _rPageRect, + const ViewShell* _pViewShell, + SwRect& _orHorizontalShadowRect, + bool bPaintLeftShadow, + bool bPaintRightShadow, + bool bRightSidebar ) +{ + const SwPostItMgr *pMgr = _pViewShell ? _pViewShell->GetPostItMgr() : 0; + SwRect aAlignedPageRect( _rPageRect ); + ::SwAlignRect( aAlignedPageRect, _pViewShell ); + SwRect aPagePxRect = + _pViewShell->GetOut()->LogicToPixel( aAlignedPageRect.SVRect() ); + + long lShadowAdjustment = mnShadowPxWidth - 1; // TODO extract this + + _orHorizontalShadowRect.Chg( + Point( aPagePxRect.Left() + (bPaintLeftShadow ? lShadowAdjustment : 0), 0 ), + Size( aPagePxRect.Width() - ( (bPaintLeftShadow ? lShadowAdjustment : 0) + (bPaintRightShadow ? lShadowAdjustment : 0) ), + mnShadowPxWidth ) ); + + if(pMgr && pMgr->ShowNotes() && pMgr->HasNotes()) + { + // Notes are displayed, we've to extend borders + SwTwips aSidebarTotalWidth = pMgr->GetSidebarWidth(true) + pMgr->GetSidebarBorderWidth(true); + if(bRightSidebar) + _orHorizontalShadowRect.Right( _orHorizontalShadowRect.Right() + aSidebarTotalWidth ); + else + _orHorizontalShadowRect.Left( _orHorizontalShadowRect.Left() - aSidebarTotalWidth ); + } +} + +/** paint page border and shadow + + OD 12.02.2003 for #i9719# and #105645# + implement paint of page border and shadow + + @author OD +*/ +/*static*/ void SwPageFrm::PaintBorderAndShadow( const SwRect& _rPageRect, + const ViewShell* _pViewShell, + bool bPaintLeftShadow, + bool bPaintRightShadow, + bool bRightSidebar ) +{ + // No shadow in prefs + if( !SwViewOption::IsShadow() ) return; + + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *_pViewShell->GetOut() ); + // <-- + + static drawinglayer::primitive2d::DiscreteShadow shadowMask( SW_RES( BMP_PAGE_SHADOW_MASK ) ); + static BitmapEx aPageTopRightShadow; + static BitmapEx aPageBottomRightShadow; + static BitmapEx aPageBottomLeftShadow; + static BitmapEx aPageBottomShadowBase; + static BitmapEx aPageRightShadowBase; + static BitmapEx aPageTopShadowBase; + static BitmapEx aPageTopLeftShadow; + static BitmapEx aPageLeftShadowBase; + static Color aShadowColor( COL_AUTO ); + + SwRect aAlignedPageRect( _rPageRect ); + ::SwAlignRect( aAlignedPageRect, _pViewShell ); + SwRect aPagePxRect = + _pViewShell->GetOut()->LogicToPixel( aAlignedPageRect.SVRect() ); + + + if(aShadowColor != SwViewOption::GetShadowColor() ) { + aShadowColor = SwViewOption::GetShadowColor(); + + AlphaMask aMask( shadowMask.getBottomRight().GetBitmap() ); + Bitmap aFilledSquare( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageBottomRightShadow = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getBottomLeft().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageBottomLeftShadow = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getBottom().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageBottomShadowBase = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getTop().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageTopShadowBase = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getTopRight().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageTopRightShadow = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getRight().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageRightShadowBase = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getTopLeft().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageTopLeftShadow = BitmapEx( aFilledSquare, aMask ); + + aMask = AlphaMask( shadowMask.getLeft().GetBitmap() ); + aFilledSquare = Bitmap( aMask.GetSizePixel(), 24 ); + aFilledSquare.Erase( aShadowColor ); + aPageLeftShadowBase = BitmapEx( aFilledSquare, aMask ); + } + + SwRect aPaintRect; + OutputDevice *pOut = _pViewShell->GetOut(); + + SwPageFrm::GetHorizontalShadowRect( _rPageRect, _pViewShell, aPaintRect, bPaintLeftShadow, bPaintRightShadow, bRightSidebar ); + + // Right shadow & corners + if ( bPaintRightShadow ) + { + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Right() + 1, aPagePxRect.Bottom() + 1 - (aPageBottomRightShadow.GetSizePixel().Height() - mnShadowPxWidth) ) ), + aPageBottomRightShadow ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Right() + 1, aPagePxRect.Top() - mnShadowPxWidth ) ), + aPageTopRightShadow ); + BitmapEx aPageRightShadow = aPageRightShadowBase; + aPageRightShadow.Scale( 1, aPagePxRect.Height() - 2 * (mnShadowPxWidth - 1) ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Right() + mnShadowPxWidth, aPagePxRect.Top() + mnShadowPxWidth - 1) ), aPageRightShadow ); + } + + // Left shadows and corners + if(bPaintLeftShadow) + { + const long lLeft = aPaintRect.Left() - aPageBottomLeftShadow.GetSizePixel().Width(); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( lLeft, + aPagePxRect.Bottom() + 1 + mnShadowPxWidth - aPageBottomLeftShadow.GetSizePixel().Height() ) ), aPageBottomLeftShadow ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( lLeft, aPagePxRect.Top() - mnShadowPxWidth ) ), aPageTopLeftShadow ); + BitmapEx aPageLeftShadow = aPageLeftShadowBase; + aPageLeftShadow.Scale( 1, aPagePxRect.Height() - 2 * (mnShadowPxWidth - 1) ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( lLeft, aPagePxRect.Top() + mnShadowPxWidth - 1) ), aPageLeftShadow ); + } + + BitmapEx aPageBottomShadow = aPageBottomShadowBase; + aPageBottomShadow.Scale( aPaintRect.Width(), 1 ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Left(), aPagePxRect.Bottom() + 1 ) ), aPageBottomShadow); + BitmapEx aPageTopShadow = aPageTopShadowBase; + aPageTopShadow.Scale( aPaintRect.Width(), 1 ); + pOut->DrawBitmapEx( pOut->PixelToLogic( Point( aPaintRect.Left(), aPagePxRect.Top() - mnShadowPxWidth ) ), aPageTopShadow ); +} + +//mod #i6193# paint sidebar for notes +//IMPORTANT: if you change the rects here, also change SwPostItMgr::ScrollbarHit +/*static*/void SwPageFrm::PaintNotesSidebar(const SwRect& _rPageRect, ViewShell* _pViewShell, sal_uInt16 nPageNum, bool bRight) +{ + //TOOD: cut out scrollbar area and arrows out of sidepane rect, otherwise it could flicker when pressing arrow buttons + if (!_pViewShell ) + return; + + SwRect aPageRect( _rPageRect ); + SwAlignRect( aPageRect, _pViewShell ); + + const SwPostItMgr *pMgr = _pViewShell->GetPostItMgr(); + if (pMgr && pMgr->ShowNotes() && pMgr->HasNotes()) // do not show anything in print preview + { + sal_Int32 nScrollerHeight = pMgr->GetSidebarScrollerHeight(); + const Rectangle &aVisRect = _pViewShell->VisArea().SVRect(); + //draw border and sidepane + _pViewShell->GetOut()->SetLineColor(); + if (!bRight) + { + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_BORDER); + _pViewShell->GetOut()->DrawRect(Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height()))) ; + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + _pViewShell->GetOut()->SetFillColor(COL_BLACK); + else + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE); + _pViewShell->GetOut()->DrawRect(Rectangle(Point(aPageRect.Left()-pMgr->GetSidebarWidth()-pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height()))) ; + } + else + { + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_BORDER); + SwRect aSidebarBorder(aPageRect.TopRight(),Size(pMgr->GetSidebarBorderWidth(),aPageRect.Height())); + _pViewShell->GetOut()->DrawRect(aSidebarBorder.SVRect()); + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + _pViewShell->GetOut()->SetFillColor(COL_BLACK); + else + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE); + SwRect aSidebar(Point(aPageRect.Right()+pMgr->GetSidebarBorderWidth(),aPageRect.Top()),Size(pMgr->GetSidebarWidth(),aPageRect.Height())); + _pViewShell->GetOut()->DrawRect(aSidebar.SVRect()); + } + if (pMgr->ShowScrollbar(nPageNum)) + { + // draw scrollbar area and arrows + Point aPointBottom; + Point aPointTop; + aPointBottom = !bRight ? Point(aPageRect.Left() - pMgr->GetSidebarWidth() - pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- _pViewShell->GetOut()->PixelToLogic(Size(0,2+pMgr->GetSidebarScrollerHeight())).Height()) : + Point(aPageRect.Right() + pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Bottom()- _pViewShell->GetOut()->PixelToLogic(Size(0,2+pMgr->GetSidebarScrollerHeight())).Height()); + aPointTop = !bRight ? Point(aPageRect.Left() - pMgr->GetSidebarWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + _pViewShell->GetOut()->PixelToLogic(Size(0,2)).Height()) : + Point(aPageRect.Right() + pMgr->GetSidebarBorderWidth() + _pViewShell->GetOut()->PixelToLogic(Size(2,0)).Width(),aPageRect.Top() + _pViewShell->GetOut()->PixelToLogic(Size(0,2)).Height()); + Size aSize(pMgr->GetSidebarWidth() - _pViewShell->GetOut()->PixelToLogic(Size(4,0)).Width(), _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()) ; + Rectangle aRectBottom(aPointBottom,aSize); + Rectangle aRectTop(aPointTop,aSize); + + if (aRectBottom.IsOver(aVisRect)) + { + + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + _pViewShell->GetOut()->SetLineColor(COL_WHITE); + _pViewShell->GetOut()->SetFillColor(COL_BLACK); + } + else + { + _pViewShell->GetOut()->SetLineColor(COL_BLACK); + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_SCROLLAREA); + } + _pViewShell->GetOut()->DrawRect(aRectBottom); + _pViewShell->GetOut()->DrawLine(aPointBottom + Point(pMgr->GetSidebarWidth()/3,0), aPointBottom + Point(pMgr->GetSidebarWidth()/3 , _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height())); + + _pViewShell->GetOut()->SetLineColor(); + Point aMiddleFirst(aPointBottom + Point(pMgr->GetSidebarWidth()/6,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2)); + Point aMiddleSecond(aPointBottom + Point(pMgr->GetSidebarWidth()/3*2,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2)); + PaintNotesSidebarArrows(aMiddleFirst,aMiddleSecond,_pViewShell,pMgr->GetArrowColor(KEY_PAGEUP,nPageNum), pMgr->GetArrowColor(KEY_PAGEDOWN,nPageNum)); + } + if (aRectTop.IsOver(aVisRect)) + { + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + _pViewShell->GetOut()->SetLineColor(COL_WHITE); + _pViewShell->GetOut()->SetFillColor(COL_BLACK); + } + else + { + _pViewShell->GetOut()->SetLineColor(COL_BLACK); + _pViewShell->GetOut()->SetFillColor(COL_NOTES_SIDEPANE_SCROLLAREA); + } + _pViewShell->GetOut()->DrawRect(aRectTop); + _pViewShell->GetOut()->DrawLine(aPointTop + Point(pMgr->GetSidebarWidth()/3*2,0), aPointTop + Point(pMgr->GetSidebarWidth()/3*2 , _pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height())); + + _pViewShell->GetOut()->SetLineColor(); + Point aMiddleFirst(aPointTop + Point(pMgr->GetSidebarWidth()/3,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2)); + Point aMiddleSecond(aPointTop + Point(pMgr->GetSidebarWidth()/6*5,_pViewShell->GetOut()->PixelToLogic(Size(0,nScrollerHeight)).Height()/2)); + PaintNotesSidebarArrows(aMiddleFirst,aMiddleSecond,_pViewShell, pMgr->GetArrowColor(KEY_PAGEUP,nPageNum), pMgr->GetArrowColor(KEY_PAGEDOWN,nPageNum)); + } + } + } +} + +/*static*/ void SwPageFrm::PaintNotesSidebarArrows(const Point &aMiddleFirst, const Point &aMiddleSecond, ViewShell* _pViewShell, const Color aColorUp, const Color aColorDown) +{ + Polygon aTriangleUp(3); + Polygon aTriangleDown(3); + + aTriangleUp.SetPoint(aMiddleFirst + Point(0,_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),0); + aTriangleUp.SetPoint(aMiddleFirst + Point(_pViewShell->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),1); + aTriangleUp.SetPoint(aMiddleFirst + Point(_pViewShell->GetOut()->PixelToLogic(Size(3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),2); + + aTriangleDown.SetPoint(aMiddleSecond + Point(_pViewShell->GetOut()->PixelToLogic(Size(-3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),0); + aTriangleDown.SetPoint(aMiddleSecond + Point(_pViewShell->GetOut()->PixelToLogic(Size(+3,0)).Width(),_pViewShell->GetOut()->PixelToLogic(Size(0,-3)).Height()),1); + aTriangleDown.SetPoint(aMiddleSecond + Point(0,_pViewShell->GetOut()->PixelToLogic(Size(0,3)).Height()),2); + + _pViewShell->GetOut()->SetFillColor(aColorUp); + _pViewShell->GetOut()->DrawPolygon(aTriangleUp); + _pViewShell->GetOut()->SetFillColor(aColorDown); + _pViewShell->GetOut()->DrawPolygon(aTriangleDown); +} + +/** get bound rectangle of border and shadow for repaints + + OD 12.02.2003 for #i9719# and #105645# + + author OD +*/ +/*static*/ void SwPageFrm::GetBorderAndShadowBoundRect( const SwRect& _rPageRect, + const ViewShell* _pViewShell, + SwRect& _orBorderAndShadowBoundRect, + bool bLeftShadow, + bool bRightShadow, + bool bRightSidebar + ) +{ + SwRect aAlignedPageRect( _rPageRect ); + ::SwAlignRect( aAlignedPageRect, _pViewShell ); + SwRect aPagePxRect = + _pViewShell->GetOut()->LogicToPixel( aAlignedPageRect.SVRect() ); + aPagePxRect.Bottom( aPagePxRect.Bottom() + mnShadowPxWidth + 1 ); + aPagePxRect.Top( aPagePxRect.Top() - mnShadowPxWidth - 1 ); + + SwRect aTmpRect; + + // Always ask for full shadow since we want a bounding rect + // including at least the page frame + SwPageFrm::GetHorizontalShadowRect( _rPageRect, _pViewShell, aTmpRect, false, false, bRightSidebar ); + + if(bLeftShadow) aPagePxRect.Left( aTmpRect.Left() - mnShadowPxWidth - 1); + if(bRightShadow) aPagePxRect.Right( aTmpRect.Right() + mnShadowPxWidth + 1); + + _orBorderAndShadowBoundRect = _pViewShell->GetOut()->PixelToLogic( aPagePxRect.SVRect() ); +} + +SwRect SwPageFrm::GetBoundRect() const +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + SwRect aPageRect( Frm() ); + SwRect aResult; + + if(!pSh) { + return SwRect( Point(0, 0), Size(0, 0) ); + } + + SwPageFrm::GetBorderAndShadowBoundRect( aPageRect, pSh, aResult, + IsLeftShadowNeeded(), IsRightShadowNeeded(), SidebarPosition() == sw::sidebarwindows::SIDEBAR_RIGHT ); + return aResult; +} + +/*static*/ void SwPageFrm::AddSidebarBorders(SwRect &aRect, ViewShell* _pViewShell, bool bRightSidebar, bool bPx) +{ + const SwPostItMgr *pMgr = _pViewShell ? _pViewShell->GetPostItMgr() : 0; + if (pMgr && pMgr->ShowNotes() && pMgr->HasNotes()) + { + if (!bRightSidebar) + aRect.SetLeftAndWidth(aRect.Left() - pMgr->GetSidebarWidth(bPx) - pMgr->GetSidebarBorderWidth(bPx), aRect.Width() + pMgr->GetSidebarWidth(bPx) + pMgr->GetSidebarBorderWidth(bPx)); + else + aRect.AddRight(pMgr->GetSidebarWidth(bPx) + pMgr->GetSidebarBorderWidth(bPx)); + } +} + +/*static*/ void SwPageFrm::AddSidebarBorders(Rectangle &aRect, ViewShell* _pViewShell, bool bRightSidebar, bool bPx) +{ + const SwPostItMgr *pMgr = _pViewShell ? _pViewShell->GetPostItMgr() : 0; + if (pMgr && pMgr->ShowNotes() && pMgr->HasNotes()) + { + if (!bRightSidebar) + aRect.Left() -= (pMgr->GetSidebarWidth(bPx) + pMgr->GetSidebarBorderWidth(bPx)); + else + aRect.Right() += pMgr->GetSidebarWidth(bPx) + pMgr->GetSidebarBorderWidth(bPx); + } +} + +/*static*/ SwTwips SwPageFrm::GetSidebarBorderWidth( const ViewShell* _pViewShell ) +{ + const SwPostItMgr* pPostItMgr = _pViewShell ? _pViewShell->GetPostItMgr() : 0; + const SwTwips nRet = pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() ? pPostItMgr->GetSidebarWidth() + pPostItMgr->GetSidebarBorderWidth() : 0; + return nRet; +} + +/************************************************************************* +|* +|* SwFrm::PaintBaBo() +|* +|*************************************************************************/ + +void SwFrm::PaintBaBo( const SwRect& rRect, const SwPageFrm *pPage, + const sal_Bool bLowerBorder ) const +{ + if ( !pPage ) + pPage = FindPageFrm(); + + OutputDevice *pOut = pGlobalShell->GetOut(); + + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pOut ); + // <-- + + // OD 2004-04-23 #116347# + pOut->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOut->SetLineColor(); + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + // OD 20.11.2002 #104598# - take care of page margin area + // Note: code move from <SwFrm::PaintBackground(..)> to new method + // <SwPageFrm::Paintmargin(..)>. + if ( IsPageFrm() ) + { + static_cast<const SwPageFrm*>(this)->PaintMarginArea( rRect, pGlobalShell ); + } + + // paint background + { + PaintBackground( rRect, pPage, rAttrs, sal_False, bLowerBorder ); + } + + // OD 06.08.2002 #99657# - paint border before painting background + // paint grid for page frame and paint border + { + SwRect aRect( rRect ); + if( IsPageFrm() ) + ((SwPageFrm*)this)->PaintGrid( pOut, aRect ); + PaintBorder( aRect, pPage, rAttrs ); + } + + pOut->Pop(); +} + +/************************************************************************* +|* +|* SwFrm::PaintBackground() +|* +|*************************************************************************/ +/// OD 05.09.2002 #102912# +/// Do not paint background for fly frames without a background brush by +/// calling <PaintBaBo> at the page or at the fly frame its anchored +void SwFrm::PaintBackground( const SwRect &rRect, const SwPageFrm *pPage, + const SwBorderAttrs & rAttrs, + const sal_Bool bLowerMode, + const sal_Bool bLowerBorder ) const +{ + // OD 20.01.2003 #i1837# - no paint of table background, if corresponding + // option is *not* set. + if( IsTabFrm() && + !pGlobalShell->GetViewOptions()->IsTable() ) + { + return; + } + + // nothing to do for covered table cells: + if( IsCellFrm() && IsCoveredCell() ) + return; + + ViewShell *pSh = pGlobalShell; + + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pSh->GetOut() ); + // <-- + + const SvxBrushItem* pItem; + /// OD 05.09.2002 #102912# + /// temporary background brush for a fly frame without a background brush + SvxBrushItem* pTmpBackBrush = 0; + const Color* pCol; + SwRect aOrigBackRect; + const sal_Bool bPageFrm = IsPageFrm(); + sal_Bool bLowMode = sal_True; + + sal_Bool bBack = GetBackgroundBrush( pItem, pCol, aOrigBackRect, bLowerMode ); + //- Ausgabe wenn ein eigener Hintergrund mitgebracht wird. + bool bNoFlyBackground = !bFlyMetafile && !bBack && IsFlyFrm(); + if ( bNoFlyBackground ) + { + // OD 05.09.2002 #102912# - Fly frame has no background. + // Try to find background brush at parents, if previous call of + // <GetBackgroundBrush> disabled this option with the parameter <bLowerMode> + if ( bLowerMode ) + { + bBack = GetBackgroundBrush( pItem, pCol, aOrigBackRect, false ); + } + // If still no background found for the fly frame, initialize the + // background brush <pItem> with global retouche color and set <bBack> + // to sal_True, that fly frame will paint its background using this color. + if ( !bBack ) + { + // OD 10.01.2003 #i6467# - on print output, pdf output and + // in embedded mode not editing color COL_WHITE is used instead of + // the global retouche color. + if ( pSh->GetOut()->GetOutDevType() == OUTDEV_PRINTER || + pSh->GetViewOptions()->IsPDFExport() || + ( pSh->GetDoc()->GetDocShell()->GetCreateMode() == SFX_CREATE_MODE_EMBEDDED && + !pSh->GetDoc()->GetDocShell()->IsInPlaceActive() + ) + ) + { + pTmpBackBrush = new SvxBrushItem( Color( COL_WHITE ), RES_BACKGROUND ); + } + else + { + pTmpBackBrush = new SvxBrushItem( aGlobalRetoucheColor, RES_BACKGROUND); + } + pItem = pTmpBackBrush; + bBack = true; + } + } + + SwRect aPaintRect( Frm() ); + if( IsTxtFrm() || IsSctFrm() ) + aPaintRect = UnionFrm( sal_True ); + + if ( aPaintRect.IsOver( rRect ) ) + { + if ( bBack || bPageFrm || !bLowerMode ) + { + const sal_Bool bBrowse = pSh->GetViewOptions()->getBrowseMode(); + SwRect aRect; + if ( (bPageFrm && bBrowse) || + (IsTxtFrm() && Prt().SSize() == Frm().SSize()) ) + { + aRect = Frm(); + ::SwAlignRect( aRect, pGlobalShell ); + } + else + { + ::lcl_CalcBorderRect( aRect, this, rAttrs, sal_False ); + if ( (IsTxtFrm() || IsTabFrm()) && GetPrev() ) + { + if ( GetPrev()->GetAttrSet()->GetBackground() == + GetAttrSet()->GetBackground() ) + { + aRect.Top( Frm().Top() ); + } + } + } + aRect.Intersection( rRect ); + + OutputDevice *pOut = pSh->GetOut(); + + if ( aRect.HasArea() ) + { + SvxBrushItem* pNewItem = 0; + SwRegionRects aRegion( aRect ); + if( pCol ) + { + pNewItem = new SvxBrushItem( *pCol, RES_BACKGROUND ); + pItem = pNewItem; + } + if ( pPage->GetSortedObjs() ) + ::lcl_SubtractFlys( this, pPage, aRect, aRegion ); + + { + /// OD 06.08.2002 #99657# - determine, if background transparency + /// have to be considered for drawing. + /// --> Status Quo: background transparency have to be + /// considered for fly frames + const sal_Bool bConsiderBackgroundTransparency = IsFlyFrm(); + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + { + if ( 1 < aRegion.Count() ) + { + ::SwAlignRect( aRegion[i], pGlobalShell ); + if( !aRegion[i].HasArea() ) + continue; + } + /// OD 06.08.2002 #99657# - add 6th parameter to indicate, if + /// background transparency have to be considered + /// Set missing 5th parameter to the default value GRFNUM_NO + /// - see declaration in /core/inc/frmtool.hxx. + ::DrawGraphic( pItem, pOut, aOrigBackRect, aRegion[i], GRFNUM_NO, + bConsiderBackgroundTransparency ); + } + } + if( pCol ) + delete pNewItem; + } + } + else + bLowMode = bLowerMode ? sal_True : sal_False; + } + + /// OD 05.09.2002 #102912# + /// delete temporary background brush. + delete pTmpBackBrush; + + //Jetzt noch Lower und dessen Nachbarn. + //Wenn ein Frn dabei die Kette verlaesst also nicht mehr Lower von mir ist + //so hoert der Spass auf. + const SwFrm *pFrm = GetLower(); + if ( pFrm ) + { + SwRect aFrmRect; + SwRect aRect( PaintArea() ); + aRect._Intersection( rRect ); + SwRect aBorderRect( aRect ); + SwShortCut aShortCut( *pFrm, aBorderRect ); + do + { if ( pProgress ) + pProgress->Reschedule(); + + aFrmRect = pFrm->PaintArea(); + if ( aFrmRect.IsOver( aBorderRect ) ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), (SwFrm*)pFrm ); + const SwBorderAttrs &rTmpAttrs = *aAccess.Get(); + /// OD 06.08.2002 #99657# - paint border before painting background + if ( bLowerBorder ) + pFrm->PaintBorder( aBorderRect, pPage, rTmpAttrs ); + if ( ( pFrm->IsLayoutFrm() && bLowerBorder ) || + aFrmRect.IsOver( aRect ) ) + pFrm->PaintBackground( aRect, pPage, rTmpAttrs, bLowMode, + bLowerBorder ); + } + pFrm = pFrm->GetNext(); + } while ( pFrm && pFrm->GetUpper() == this && + !aShortCut.Stop( aFrmRect ) ); + } +} + +/************************************************************************* +|* +|* SwPageFrm::RefreshSubsidiary() +|* +|* Beschreibung Erneuert alle Hilfslinien der Seite. +|* +|*************************************************************************/ + +void SwPageFrm::RefreshSubsidiary( const SwRect &rRect ) const +{ + if ( IS_SUBS || IS_SUBS_TABLE || IS_SUBS_SECTION || IS_SUBS_FLYS ) + { + SwRect aRect( rRect ); + // OD 18.02.2003 #104989# - Not necessary and incorrect alignment of + // the output rectangle. + //::SwAlignRect( aRect, pGlobalShell ); + if ( aRect.HasArea() ) + { + //Beim Paint ueber die Root wird das Array von dort gesteuert. + //Anderfalls kuemmern wir uns selbst darum. + sal_Bool bDelSubs = sal_False; + if ( !pSubsLines ) + { + pSubsLines = new SwSubsRects; + // OD 20.12.2002 #106318# - create container for special subsidiary lines + pSpecSubsLines = new SwSubsRects; + bDelSubs = sal_True; + } + + RefreshLaySubsidiary( this, aRect ); + + if ( bDelSubs ) + { + // OD 20.12.2002 #106318# - paint special subsidiary lines + // and delete its container + pSpecSubsLines->PaintSubsidiary( pGlobalShell->GetOut(), NULL ); + DELETEZ( pSpecSubsLines ); + + pSubsLines->PaintSubsidiary( pGlobalShell->GetOut(), pLines ); + DELETEZ( pSubsLines ); + } + } + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::RefreshLaySubsidiary() +|* +|*************************************************************************/ +void SwLayoutFrm::RefreshLaySubsidiary( const SwPageFrm *pPage, + const SwRect &rRect ) const +{ + const sal_Bool bNoLowerColumn = !Lower() || !Lower()->IsColumnFrm(); + const sal_Bool bSubsOpt = IS_SUBS; + const sal_Bool bSubsTable = ((GetType() & (FRM_ROW | FRM_CELL)) && IS_SUBS_TABLE); + const sal_Bool bSubsOther = (GetType() & (FRM_HEADER | FRM_FOOTER | FRM_FTN )) && bSubsOpt; + const sal_Bool bSubsSect = IsSctFrm() && + bNoLowerColumn && + IS_SUBS_SECTION; + const sal_Bool bSubsFly = IS_SUBS_FLYS && + (GetType() & FRM_FLY) && + bNoLowerColumn && + (!Lower() || !Lower()->IsNoTxtFrm() || + !((SwNoTxtFrm*)Lower())->HasAnimation()); + sal_Bool bSubsBody = sal_False; + if ( GetType() & FRM_BODY ) + { + if ( IsPageBodyFrm() ) + bSubsBody = bSubsOpt && bNoLowerColumn; //nur ohne Spalten + else //Spaltenbody + { + if ( GetUpper()->GetUpper()->IsSctFrm() ) + bSubsBody = IS_SUBS_SECTION; + else + bSubsBody = bSubsOpt; + } + } + + if ( bSubsOther || bSubsSect || bSubsBody || bSubsTable || bSubsFly ) + PaintSubsidiaryLines( pPage, rRect ); + + const SwFrm *pLow = Lower(); + if( !pLow ) + return; + SwShortCut aShortCut( *pLow, rRect ); + while( pLow && !aShortCut.Stop( pLow->Frm() ) ) + { + if ( pLow->Frm().IsOver( rRect ) && pLow->Frm().HasArea() ) + { + if ( pLow->IsLayoutFrm() ) + ((const SwLayoutFrm*)pLow)->RefreshLaySubsidiary( pPage, rRect); + else if ( pLow->GetDrawObjs() ) + { + const SwSortedObjs& rObjs = *(pLow->GetDrawObjs()); + for ( sal_uInt32 i = 0; i < rObjs.Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pPage->GetFmt()->GetDoc()->IsVisibleLayerId( + pAnchoredObj->GetDrawObj()->GetLayer() ) && + pAnchoredObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = + static_cast<const SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsFlyInCntFrm() && pFly->Frm().IsOver( rRect ) ) + { + if ( !pFly->Lower() || !pFly->Lower()->IsNoTxtFrm() || + !((SwNoTxtFrm*)pFly->Lower())->HasAnimation()) + pFly->RefreshLaySubsidiary( pPage, rRect ); + } + } + } + } + } + pLow = pLow->GetNext(); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::PaintSubsidiaryLines() +|* +|* Beschreibung Hilfslinien um die PrtAreas malen +|* Nur die LayoutFrm's die direkt Cntnt enthalten. +|* +|*************************************************************************/ + +//Malt die angegebene Linie, achtet darauf, dass keine Flys uebermalt werden. + +typedef long Size::* SizePtr; +typedef long Point::* PointPtr; + +PointPtr pX = &Point::nA; +PointPtr pY = &Point::nB; +SizePtr pWidth = &Size::nA; +SizePtr pHeight = &Size::nB; + +// OD 18.11.2002 #99672# - new parameter <_pSubsLines> +void MA_FASTCALL lcl_RefreshLine( const SwLayoutFrm *pLay, + const SwPageFrm *pPage, + const Point &rP1, + const Point &rP2, + const sal_uInt8 nSubColor, + SwLineRects* _pSubsLines ) +{ + //In welche Richtung gehts? Kann nur Horizontal oder Vertikal sein. + OSL_ENSURE( ((rP1.X() == rP2.X()) || (rP1.Y() == rP2.Y())), + "Schraege Hilfslinien sind nicht erlaubt." ); + const PointPtr pDirPt = rP1.X() == rP2.X() ? pY : pX; + const PointPtr pOthPt = pDirPt == pX ? pY : pX; + const SizePtr pDirSz = pDirPt == pX ? pWidth : pHeight; + const SizePtr pOthSz = pDirSz == pWidth ? pHeight : pWidth; + Point aP1( rP1 ), + aP2( rP2 ); + + while ( aP1.*pDirPt < aP2.*pDirPt ) + { //Der Startpunkt wird jetzt, falls er in einem Fly sitzt, direkt + //hinter den Fly gesetzt. + //Wenn der Endpunkt in einem Fly sitzt oder zwischen Start und Endpunkt + //ein Fly sitzt, so wird der Endpunkt eben an den Start herangezogen. + //Auf diese art und weise wird eine Portion nach der anderen + //ausgegeben. + + //Wenn ich selbst ein Fly bin, weiche ich nur denjenigen Flys aus, + //die 'ueber' mir sitzen; d.h. die in dem Array hinter mir stehen. + //Auch wenn ich in einem Fly sitze oder in einem Fly im Fly usw. weiche + //ich keinem dieser Flys aus. + SwOrderIter aIter( pPage ); + const SwFlyFrm *pMyFly = pLay->FindFlyFrm(); + if ( pMyFly ) + { + aIter.Current( pMyFly->GetVirtDrawObj() ); + while ( 0 != (pMyFly = pMyFly->GetAnchorFrm()->FindFlyFrm()) ) + { + if ( aIter()->GetOrdNum() > pMyFly->GetVirtDrawObj()->GetOrdNum() ) + aIter.Current( pMyFly->GetVirtDrawObj() ); + } + } + else + aIter.Bottom(); + + while ( aIter() ) + { + const SwVirtFlyDrawObj *pObj = (SwVirtFlyDrawObj*)aIter(); + const SwFlyFrm *pFly = pObj ? pObj->GetFlyFrm() : 0; + + //Mir selbst weiche ich natuerlich nicht aus. Auch wenn ich + //_in_ dem Fly sitze weiche ich nicht aus. + if ( !pFly || (pFly == pLay || pFly->IsAnLower( pLay )) ) + { + aIter.Next(); + continue; + } + + // OD 19.12.2002 #106318# - do *not* consider fly frames with + // a transparent background. + // OD 2004-02-12 #110582#-2 - do *not* consider fly frame, which + // belongs to a invisible layer + if ( pFly->IsBackgroundTransparent() || + !pFly->GetFmt()->GetDoc()->IsVisibleLayerId( pObj->GetLayer() ) ) + { + aIter.Next(); + continue; + } + + //Sitzt das Obj auf der Linie + const Rectangle &rBound = pObj->GetCurrentBoundRect(); + const Point aDrPt( rBound.TopLeft() ); + const Size aDrSz( rBound.GetSize() ); + if ( rP1.*pOthPt >= aDrPt.*pOthPt && + rP1.*pOthPt <= (aDrPt.*pOthPt + aDrSz.*pOthSz) ) + { + if ( aP1.*pDirPt >= aDrPt.*pDirPt && + aP1.*pDirPt <= (aDrPt.*pDirPt + aDrSz.*pDirSz) ) + aP1.*pDirPt = aDrPt.*pDirPt + aDrSz.*pDirSz; + + if ( aP2.*pDirPt >= aDrPt.*pDirPt && + aP1.*pDirPt < (aDrPt.*pDirPt - 1) ) + aP2.*pDirPt = aDrPt.*pDirPt - 1; + } + aIter.Next(); + } + + if ( aP1.*pDirPt < aP2.*pDirPt ) + { + SwRect aRect( aP1, aP2 ); + // OD 18.11.2002 #99672# - use parameter <_pSubsLines> instead of + // global variable <pSubsLines>. + _pSubsLines->AddLineRect( aRect, 0, SOLID, 0, nSubColor ); + } + aP1 = aP2; + aP1.*pDirPt += 1; + aP2 = rP2; + } +} + +void SwLayoutFrm::PaintSubsidiaryLines( const SwPageFrm *pPage, + const SwRect &rRect ) const +{ + bool bNewTableModel = false; + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( IsTabFrm() || IsCellFrm() || IsRowFrm() ) + { + const SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->IsCollapsingBorders() ) + return; + + bNewTableModel = pTabFrm->GetTable()->IsNewModel(); + // in the new table model, we have an early return for all cell-related + // frames, except from non-covered table cells + if ( bNewTableModel ) + if ( IsTabFrm() || + IsRowFrm() || + ( IsCellFrm() && IsCoveredCell() ) ) + return; + } + // <-- collapsing + + const bool bFlys = pPage->GetSortedObjs() ? true : false; + + const bool bCell = IsCellFrm() ? true : false; + // use frame area for cells + // OD 13.02.2003 #i3662# - for section use also frame area + const bool bUseFrmArea = bCell || IsSctFrm(); + SwRect aOriginal( bUseFrmArea ? Frm() : Prt() ); + if ( !bUseFrmArea ) + aOriginal.Pos() += Frm().Pos(); + + // OD 13.02.2003 #i3662# - enlarge top of column body frame's printing area + // in sections to top of section frame. + const bool bColBodyInSection = IsBodyFrm() && + !IsPageBodyFrm() && + GetUpper()->GetUpper()->IsSctFrm(); + if ( bColBodyInSection ) + { + if ( IsVertical() ) + aOriginal.Right( GetUpper()->GetUpper()->Frm().Right() ); + else + aOriginal.Top( GetUpper()->GetUpper()->Frm().Top() ); + } + + ::SwAlignRect( aOriginal, pGlobalShell ); + + if ( !aOriginal.IsOver( rRect ) ) + return; + + SwRect aOut( aOriginal ); + aOut._Intersection( rRect ); + // OD 13.02.2003 #i3662# - do not intersect *enlarged* column body frame's + // printing area with the paint area of the body frame. Otherwise enlargement + // will get lost. + if ( !bColBodyInSection ) + { + aOut.Intersection( PaintArea() ); + } + + const SwTwips nRight = aOut.Right(); + const SwTwips nBottom= aOut.Bottom(); + + const Point aRT( nRight, aOut.Top() ); + const Point aRB( nRight, nBottom ); + const Point aLB( aOut.Left(), nBottom ); + + sal_uInt8 nSubColor = ( bCell || IsRowFrm() ) ? SUBCOL_TAB : + ( IsInSct() ? SUBCOL_SECT : + ( IsInFly() ? SUBCOL_FLY : SUBCOL_PAGE ) ); + + // OD 05.11.2002 #102406# - body frames are responsible for page/column breaks. + sal_Bool bBreak = sal_False; + if ( IsBodyFrm() ) + { + const SwCntntFrm *pCnt = ContainsCntnt(); + if ( pCnt ) + { + // OD 05.11.2002 #102406# - adjust setting of <bBreak>. + bBreak = pCnt->IsPageBreak( sal_True ) || + ( IsColBodyFrm() && pCnt->IsColBreak( sal_True ) ); + } + } + + // OD 18.11.2002 #99672# - collect body, header, footer, footnote and section + // sub-lines in <pSpecSubsLine> array. + const bool bSpecialSublines = IsBodyFrm() || IsHeaderFrm() || IsFooterFrm() || + IsFtnFrm() || IsSctFrm(); + SwLineRects* pUsedSubsLines = bSpecialSublines ? pSpecSubsLines : pSubsLines; + + // NOTE: for cell frames only left and right (horizontal layout) respectively + // top and bottom (vertical layout) lines painted. + // NOTE2: this does not hold for the new table model!!! We paint the top border + // of each non-covered table cell. + const bool bVert = IsVertical() ? true : false; + if ( bFlys ) + { + // OD 14.11.2002 #104822# - add control for drawing left and right lines + if ( !bCell || bNewTableModel || !bVert ) + { + if ( aOriginal.Left() == aOut.Left() ) + ::lcl_RefreshLine( this, pPage, aOut.Pos(), aLB, nSubColor, + pUsedSubsLines ); + // OD 14.11.2002 #104821# - in vertical layout set page/column break at right + if ( aOriginal.Right() == nRight ) + ::lcl_RefreshLine( this, pPage, aRT, aRB, + (bBreak && bVert) ? SUBCOL_BREAK : nSubColor, + pUsedSubsLines ); + } + // OD 14.11.2002 #104822# - adjust control for drawing top and bottom lines + if ( !bCell || bNewTableModel || bVert ) + { + if ( aOriginal.Top() == aOut.Top() ) + // OD 14.11.2002 #104821# - in horizontal layout set page/column break at top + ::lcl_RefreshLine( this, pPage, aOut.Pos(), aRT, + (bBreak && !bVert) ? SUBCOL_BREAK : nSubColor, + pUsedSubsLines ); + if ( aOriginal.Bottom() == nBottom ) + ::lcl_RefreshLine( this, pPage, aLB, aRB, nSubColor, + pUsedSubsLines ); + } + } + else + { + // OD 14.11.2002 #104822# - add control for drawing left and right lines + if ( !bCell || bNewTableModel || !bVert ) + { + if ( aOriginal.Left() == aOut.Left() ) + { + const SwRect aRect( aOut.Pos(), aLB ); + pUsedSubsLines->AddLineRect( aRect, 0, SOLID, 0, nSubColor ); + } + // OD 14.11.2002 #104821# - in vertical layout set page/column break at right + if ( aOriginal.Right() == nRight ) + { + const SwRect aRect( aRT, aRB ); + pUsedSubsLines->AddLineRect( aRect, 0, SOLID, 0, + (bBreak && bVert) ? SUBCOL_BREAK : nSubColor ); + } + } + // OD 14.11.2002 #104822# - adjust control for drawing top and bottom lines + if ( !bCell || bNewTableModel || bVert ) + { + if ( aOriginal.Top() == aOut.Top() ) + { + // OD 14.11.2002 #104821# - in horizontal layout set page/column break at top + const SwRect aRect( aOut.Pos(), aRT ); + pUsedSubsLines->AddLineRect( aRect, 0, SOLID, 0, + (bBreak && !bVert) ? SUBCOL_BREAK : nSubColor ); + } + if ( aOriginal.Bottom() == nBottom ) + { + const SwRect aRect( aLB, aRB ); + pUsedSubsLines->AddLineRect( aRect, 0, SOLID, 0, nSubColor ); + } + } + } +} + +/************************************************************************* +|* +|* SwPageFrm::RefreshExtraData(), SwLayoutFrm::RefreshExtraData() +|* +|* Beschreibung Erneuert alle Extradaten (Zeilennummern usw) der Seite. +|* Grundsaetzlich sind nur diejenigen Objekte beruecksichtig, +|* die in die seitliche Ausdehnung des Rects ragen. +|* +|*************************************************************************/ + +void SwPageFrm::RefreshExtraData( const SwRect &rRect ) const +{ + const SwLineNumberInfo &rInfo = GetFmt()->GetDoc()->GetLineNumberInfo(); + sal_Bool bLineInFly = (rInfo.IsPaintLineNumbers() && rInfo.IsCountInFlys()) + || (sal_Int16)SW_MOD()->GetRedlineMarkPos() != text::HoriOrientation::NONE; + + SwRect aRect( rRect ); + ::SwAlignRect( aRect, pGlobalShell ); + if ( aRect.HasArea() ) + { + SwLayoutFrm::RefreshExtraData( aRect ); + + if ( bLineInFly && GetSortedObjs() ) + for ( sal_uInt16 i = 0; i < GetSortedObjs()->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*GetSortedObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + if ( pFly->Frm().Top() <= aRect.Bottom() && + pFly->Frm().Bottom() >= aRect.Top() ) + pFly->RefreshExtraData( aRect ); + } + } + } +} + +void SwLayoutFrm::RefreshExtraData( const SwRect &rRect ) const +{ + + const SwLineNumberInfo &rInfo = GetFmt()->GetDoc()->GetLineNumberInfo(); + sal_Bool bLineInBody = rInfo.IsPaintLineNumbers(), + bLineInFly = bLineInBody && rInfo.IsCountInFlys(), + bRedLine = (sal_Int16)SW_MOD()->GetRedlineMarkPos()!=text::HoriOrientation::NONE; + + const SwCntntFrm *pCnt = ContainsCntnt(); + while ( pCnt && IsAnLower( pCnt ) ) + { + if ( pCnt->IsTxtFrm() && ( bRedLine || + ( !pCnt->IsInTab() && + ((bLineInBody && pCnt->IsInDocBody()) || + (bLineInFly && pCnt->IsInFly())) ) ) && + pCnt->Frm().Top() <= rRect.Bottom() && + pCnt->Frm().Bottom() >= rRect.Top() ) + { + ((SwTxtFrm*)pCnt)->PaintExtraData( rRect ); + } + if ( bLineInFly && pCnt->GetDrawObjs() ) + for ( sal_uInt32 i = 0; i < pCnt->GetDrawObjs()->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pCnt->GetDrawObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsFlyInCntFrm() && + pFly->Frm().Top() <= rRect.Bottom() && + pFly->Frm().Bottom() >= rRect.Top() ) + pFly->RefreshExtraData( rRect ); + } + } + pCnt = pCnt->GetNextCntntFrm(); + } +} + +/** SwPageFrm::GetDrawBackgrdColor - for #102450# + + determine the color, that is respectively will be drawn as background + for the page frame. + Using existing method SwFrm::GetBackgroundBrush to determine the color + that is set at the page frame respectively is parent. If none is found + return the global retouche color + + @author OD + + @return Color +*/ +const Color& SwPageFrm::GetDrawBackgrdColor() const +{ + const SvxBrushItem* pBrushItem; + const Color* pDummyColor; + SwRect aDummyRect; + if ( GetBackgroundBrush( pBrushItem, pDummyColor, aDummyRect, true) ) + return pBrushItem->GetColor(); + else + return aGlobalRetoucheColor; +} + +/************************************************************************* +|* +|* SwPageFrm::GetEmptyPageFont() +|* +|* create/return font used to paint the "empty page" string +|* +|*************************************************************************/ + +const Font& SwPageFrm::GetEmptyPageFont() +{ + static Font* pEmptyPgFont = 0; + if ( 0 == pEmptyPgFont ) + { + pEmptyPgFont = new Font; + pEmptyPgFont->SetSize( Size( 0, 80 * 20 )); // == 80 pt + pEmptyPgFont->SetWeight( WEIGHT_BOLD ); + pEmptyPgFont->SetStyleName( aEmptyStr ); + pEmptyPgFont->SetName( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "Helvetica" )) ); + pEmptyPgFont->SetFamily( FAMILY_SWISS ); + pEmptyPgFont->SetTransparent( sal_True ); + pEmptyPgFont->SetColor( COL_GRAY ); + } + + return *pEmptyPgFont; +} + +/************************************************************************* +|* +|* SwFrm::Retouche +|* +|* Beschreibung Retouche fuer einen Bereich. +|* Retouche wird nur dann durchgefuehrt, wenn der Frm der letzte seiner +|* Kette ist. Der Gesamte Bereich des Upper unterhalb des Frm wird +|* per PaintBackground gecleared. +|* +|*************************************************************************/ + +void SwFrm::Retouche( const SwPageFrm * pPage, const SwRect &rRect ) const +{ + if ( bFlyMetafile ) + return; + + OSL_ENSURE( GetUpper(), "Retoucheversuch ohne Upper." ); + OSL_ENSURE( getRootFrm()->GetCurrShell() && pGlobalShell->GetWin(), "Retouche auf dem Drucker?" ); + + SwRect aRetouche( GetUpper()->PaintArea() ); + aRetouche.Top( Frm().Top() + Frm().Height() ); + aRetouche.Intersection( pGlobalShell->VisArea() ); + + if ( aRetouche.HasArea() ) + { + //Uebergebenes Rect ausparen. Dafuer brauchen wir leider eine Region + //zum ausstanzen. + SwRegionRects aRegion( aRetouche ); + aRegion -= rRect; + ViewShell *pSh = getRootFrm()->GetCurrShell(); + + // --> FME 2004-06-24 #i16816# tagged pdf support + SwTaggedPDFHelper aTaggedPDFHelper( 0, 0, 0, *pSh->GetOut() ); + // <-- + + for ( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + { + SwRect &rRetouche = aRegion[i]; + + GetUpper()->PaintBaBo( rRetouche, pPage, sal_True ); + + //Hoelle und Himmel muessen auch refreshed werden. + //Um Rekursionen zu vermeiden muss mein Retouche Flag zuerst + //zurueckgesetzt werden! + ResetRetouche(); + SwRect aRetouchePart( rRetouche ); + if ( aRetouchePart.HasArea() ) + { + // OD 30.08.2002 #102450# + // determine background color of page for <PaintLayer> method + // calls, painting <hell> or <heaven> + const Color aPageBackgrdColor = pPage->GetDrawBackgrdColor(); + // OD 29.08.2002 #102450# + // add 3rd parameter to <PaintLayer> method calls + // OD 09.12.2002 #103045# - add 4th parameter for horizontal text direction. + const IDocumentDrawModelAccess* pIDDMA = pSh->getIDocumentDrawModelAccess(); + + pSh->Imp()->PaintLayer( pIDDMA->GetHellId(), 0, + aRetouchePart, &aPageBackgrdColor, + (pPage->IsRightToLeft() ? true : false) ); + pSh->Imp()->PaintLayer( pIDDMA->GetHeavenId(), 0, + aRetouchePart, &aPageBackgrdColor, + (pPage->IsRightToLeft() ? true : false) ); + } + + SetRetouche(); + + //Da wir uns ausserhalb aller Paint-Bereiche begeben muessen hier + //leider die Hilfslinien erneuert werden. + pPage->RefreshSubsidiary( aRetouchePart ); + } + } + if ( ViewShell::IsLstEndAction() ) + ResetRetouche(); +} + +/** SwFrm::GetBackgroundBrush + + @descr + determine the background brush for the frame: + the background brush is taken from it-self or from its parent (anchor/upper). + Normally, the background brush is taken, which has no transparent color or + which has a background graphic. But there are some special cases: + (1) No background brush is taken from a page frame, if view option "IsPageBack" + isn't set. + (2) Background brush from a index section is taken under special conditions. + In this case parameter <rpCol> is set to the index shading color. + (3) New (OD 20.08.2002) - Background brush is taken, if on background drawing + of the frame transparency is considered and its color is not "no fill"/"auto fill" + ---- old description in german: + Beschreibung Liefert die Backgroundbrush fuer den Bereich des + des Frm. Die Brush wird entweder von ihm selbst oder von einem + Upper vorgegeben, die erste Brush wird benutzt. + Ist fuer keinen Frm eine Brush angegeben, so wird sal_False zurueck- + geliefert. + + @param rpBrush + output parameter - constant reference pointer the found background brush + + @param rpCol + output parameter - constant reference pointer to the color of the index shading + set under special conditions, if background brush is taken from an index section. + + @param rOrigRect + in-/output parameter - reference to the retangle the background brush is + considered for - adjusted to the frame, from which the background brush is + taken. + + @parem bLowerMode + input parameter - boolean indicating, if background brush should *not* be + taken from parent. + + @return true, if a background brush for the frame is found +*/ +sal_Bool SwFrm::GetBackgroundBrush( const SvxBrushItem* & rpBrush, + const Color*& rpCol, + SwRect &rOrigRect, + sal_Bool bLowerMode ) const +{ + const SwFrm *pFrm = this; + ViewShell *pSh = getRootFrm()->GetCurrShell(); + const SwViewOption *pOpt = pSh->GetViewOptions(); + rpBrush = 0; + rpCol = NULL; + do + { if ( pFrm->IsPageFrm() && !pOpt->IsPageBack() ) + return sal_False; + + const SvxBrushItem &rBack = pFrm->GetAttrSet()->GetBackground(); + if( pFrm->IsSctFrm() ) + { + const SwSection* pSection = ((SwSectionFrm*)pFrm)->GetSection(); + /// OD 20.08.2002 #99657# #GetTransChg# + /// Note: If frame <pFrm> is a section of the index and + /// it its background color is "no fill"/"auto fill" and + /// it has no background graphic and + /// we are not in the page preview and + /// we are not in read-only mode and + /// option "index shadings" is set and + /// the output is not the printer + /// then set <rpCol> to the color of the index shading + if( pSection && ( TOX_HEADER_SECTION == pSection->GetType() || + TOX_CONTENT_SECTION == pSection->GetType() ) && + (rBack.GetColor() == COL_TRANSPARENT) && + ///rBack.GetColor().GetTransparency() && + rBack.GetGraphicPos() == GPOS_NONE && + !pOpt->IsPagePreview() && + !pOpt->IsReadonly() && + // --> FME 2004-06-29 #114856# Formular view + !pOpt->IsFormView() && + // <-- + SwViewOption::IsIndexShadings() && + !pOpt->IsPDFExport() && + pSh->GetOut()->GetOutDevType() != OUTDEV_PRINTER ) + { + rpCol = &SwViewOption::GetIndexShadingsColor(); + } + } + + /// OD 20.08.2002 #99657# + /// determine, if background draw of frame <pFrm> considers transparency + /// --> Status Quo: background transparency have to be + /// considered for fly frames + const sal_Bool bConsiderBackgroundTransparency = pFrm->IsFlyFrm(); + /// OD 20.08.2002 #99657# + /// add condition: + /// If <bConsiderBackgroundTransparency> is set - see above -, + /// return brush of frame <pFrm>, if its color is *not* "no fill"/"auto fill" + if ( !rBack.GetColor().GetTransparency() || + rBack.GetGraphicPos() != GPOS_NONE || + rpCol || + (bConsiderBackgroundTransparency && (rBack.GetColor() != COL_TRANSPARENT)) + ) + { + rpBrush = &rBack; + if ( pFrm->IsPageFrm() && + pSh->GetViewOptions()->getBrowseMode() ) + rOrigRect = pFrm->Frm(); + else + { + if ( pFrm->Frm().SSize() != pFrm->Prt().SSize() ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + ::lcl_CalcBorderRect( rOrigRect, pFrm, rAttrs, sal_False ); + } + else + { + rOrigRect = pFrm->Prt(); + rOrigRect += pFrm->Frm().Pos(); + } + } + return sal_True; + } + + if ( bLowerMode ) + /// Do not try to get background brush from parent (anchor/upper) + return sal_False; + + /// get parent frame - anchor or upper - for next loop + if ( pFrm->IsFlyFrm() ) + /// OD 20.08.2002 - use "static_cast" instead of "old C-cast" + pFrm = (static_cast<const SwFlyFrm*>(pFrm))->GetAnchorFrm(); + ///pFrm = ((SwFlyFrm*)pFrm)->GetAnchor(); + else + pFrm = pFrm->GetUpper(); + + } while ( pFrm ); + + return sal_False; +} + +/************************************************************************* +|* +|* SwFrmFmt::GetGraphic() +|* +|*************************************************************************/ + +void SetOutDevAndWin( ViewShell *pSh, OutputDevice *pO, + Window *pW, sal_uInt16 nZoom ) +{ + pSh->pOut = pO; + pSh->pWin = pW; + pSh->pOpt->SetZoom( nZoom ); +} + +Graphic SwFrmFmt::MakeGraphic( ImageMap* ) +{ + return Graphic(); +} + +Graphic SwFlyFrmFmt::MakeGraphic( ImageMap* pMap ) +{ + Graphic aRet; + //irgendeinen Fly suchen! + SwIterator<SwFrm,SwFmt> aIter( *this ); + SwFrm *pFirst = aIter.First(); + ViewShell *pSh; + if ( pFirst && 0 != ( pSh = pFirst->getRootFrm()->GetCurrShell()) ) + { + ViewShell *pOldGlobal = pGlobalShell; + pGlobalShell = pSh; + + sal_Bool bNoteURL = pMap && + SFX_ITEM_SET != GetAttrSet().GetItemState( RES_URL, sal_True ); + if( bNoteURL ) + { + OSL_ENSURE( !pNoteURL, "MakeGraphic: pNoteURL already used? " ); + pNoteURL = new SwNoteURL; + } + SwFlyFrm *pFly = (SwFlyFrm*)pFirst; + + OutputDevice *pOld = pSh->GetOut(); + VirtualDevice aDev( *pOld ); + aDev.EnableOutput( sal_False ); + + GDIMetaFile aMet; + MapMode aMap( pOld->GetMapMode().GetMapUnit() ); + aDev.SetMapMode( aMap ); + aMet.SetPrefMapMode( aMap ); + + ::SwCalcPixStatics( pSh->GetOut() ); + aMet.SetPrefSize( pFly->Frm().SSize() ); + + aMet.Record( &aDev ); + aDev.SetLineColor(); + aDev.SetFillColor(); + aDev.SetFont( pOld->GetFont() ); + + //Rechteck ggf. ausdehnen, damit die Umrandunge mit aufgezeichnet werden. + SwRect aOut( pFly->Frm() ); + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFly ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + if ( rAttrs.CalcRightLine() ) + aOut.SSize().Width() += 2*nPixelSzW; + if ( rAttrs.CalcBottomLine() ) + aOut.SSize().Height()+= 2*nPixelSzH; + + // #i92711# start Pre/PostPaint encapsulation before pOut is changed to the buffering VDev + const Region aRepaintRegion(aOut.SVRect()); + pSh->DLPrePaint2(aRepaintRegion); + + Window *pWin = pSh->GetWin(); + sal_uInt16 nZoom = pSh->GetViewOptions()->GetZoom(); + ::SetOutDevAndWin( pSh, &aDev, 0, 100 ); + bFlyMetafile = sal_True; + pFlyMetafileOut = pWin; + + SwViewImp *pImp = pSh->Imp(); + pFlyOnlyDraw = pFly; + pLines = new SwLineRects; + + // OD 09.12.2002 #103045# - determine page, fly frame is on + const SwPageFrm* pFlyPage = pFly->FindPageFrm(); + // OD 30.08.2002 #102450# + // determine color of page, the fly frame is on, for <PaintLayer> method + // calls, painting <hell> or <heaven> + const Color aPageBackgrdColor = pFlyPage->GetDrawBackgrdColor(); + // OD 30.08.2002 #102450# - add 3rd parameter + // OD 09.12.2002 #103045# - add 4th parameter for horizontal text direction. + const IDocumentDrawModelAccess* pIDDMA = pSh->getIDocumentDrawModelAccess(); + pImp->PaintLayer( pIDDMA->GetHellId(), 0, aOut, &aPageBackgrdColor, + (pFlyPage->IsRightToLeft() ? true : false) ); + pLines->PaintLines( &aDev ); + if ( pFly->IsFlyInCntFrm() ) + pFly->Paint( aOut ); + pLines->PaintLines( &aDev ); + /// OD 30.08.2002 #102450# - add 3rd parameter + pImp->PaintLayer( pIDDMA->GetHeavenId(), 0, aOut, &aPageBackgrdColor, + (pFlyPage->IsRightToLeft() ? true : false) ); + pLines->PaintLines( &aDev ); + DELETEZ( pLines ); + pFlyOnlyDraw = 0; + + pFlyMetafileOut = 0; + bFlyMetafile = sal_False; + ::SetOutDevAndWin( pSh, pOld, pWin, nZoom ); + + // #i92711# end Pre/PostPaint encapsulation when pOut is back and content is painted + pSh->DLPostPaint2(true); + + aMet.Stop(); + aMet.Move( -pFly->Frm().Left(), -pFly->Frm().Top() ); + aRet = Graphic( aMet ); + + if( bNoteURL ) + { + OSL_ENSURE( pNoteURL, "MakeGraphic: Good Bye, NoteURL." ); + pNoteURL->FillImageMap( pMap, pFly->Frm().Pos(), aMap ); + delete pNoteURL; + pNoteURL = NULL; + } + pGlobalShell = pOldGlobal; + } + return aRet; +} + +Graphic SwDrawFrmFmt::MakeGraphic( ImageMap* ) +{ + Graphic aRet; + SdrModel *pMod = getIDocumentDrawModelAccess()->GetDrawModel(); + if ( pMod ) + { + SdrObject *pObj = FindSdrObject(); + SdrView *pView = new SdrView( pMod ); + SdrPageView *pPgView = pView->ShowSdrPage(pView->GetModel()->GetPage(0)); + pView->MarkObj( pObj, pPgView ); + aRet = pView->GetMarkedObjBitmap(); + pView->HideSdrPage(); + delete pView; + } + return aRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx new file mode 100644 index 000000000000..d7f5364c38f7 --- /dev/null +++ b/sw/source/core/layout/sectfrm.cxx @@ -0,0 +1,2779 @@ +/* -*- 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 <svl/smplhint.hxx> +#include <svl/itemiter.hxx> +#include <hints.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <fmtclbl.hxx> +#include "sectfrm.hxx" +#include "section.hxx" // SwSection +#include "frmtool.hxx" // StackHack +#include "doc.hxx" // SwDoc +#include "cntfrm.hxx" // SwCntntFrm +#include "rootfrm.hxx" // SwRootFrm +#include "pagefrm.hxx" // SwPageFrm +#include "fmtpdsc.hxx" // SwFmtPageDesc +#include "fmtcntnt.hxx" // SwFmtCntnt +#include "ndindex.hxx" // SwNodeIndex +#include "ftnidx.hxx" +#include "txtfrm.hxx" // SwTxtFrm +#include "fmtclds.hxx" // SwFmtCol +#include "colfrm.hxx" // SwColumnFrm +#include "tabfrm.hxx" // SwTabFrm +#include "flyfrm.hxx" // SwFlyFrm +#include "ftnfrm.hxx" // SwFtnFrm +#include "layouter.hxx" // SwLayouter +#include "dbg_lay.hxx" +#include "viewsh.hxx" +#include "viewopt.hxx" +#include "viewimp.hxx" +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brshitem.hxx> +#include <fmtftntx.hxx> +// OD 2004-05-24 #i28701# +#include <dflyobj.hxx> +#include <flyfrms.hxx> +#include <sortedobjs.hxx> + +SV_IMPL_PTRARR_SORT( SwDestroyList, SwSectionFrmPtr ) + +/************************************************************************* +|* +|* SwSectionFrm::SwSectionFrm(), ~SwSectionFrm() +|* +|*************************************************************************/ +SwSectionFrm::SwSectionFrm( SwSection &rSect, SwFrm* pSib ) : + SwLayoutFrm( rSect.GetFmt(), pSib ), + SwFlowFrm( (SwFrm&)*this ), + pSection( &rSect ) +{ + nType = FRMC_SECTION; + + CalcFtnAtEndFlag(); + CalcEndAtEndFlag(); +} + +SwSectionFrm::SwSectionFrm( SwSectionFrm &rSect, sal_Bool bMaster ) : + SwLayoutFrm( rSect.GetFmt(), rSect.getRootFrm() ), + SwFlowFrm( (SwFrm&)*this ), + pSection( rSect.GetSection() ) +{ + bFtnAtEnd = rSect.IsFtnAtEnd(); + bEndnAtEnd = rSect.IsEndnAtEnd(); + bLockJoin = sal_False; + nType = FRMC_SECTION; + + PROTOCOL( this, PROT_SECTION, bMaster ? ACT_CREATE_MASTER : ACT_CREATE_FOLLOW, &rSect ) + + if( bMaster ) + { + if( rSect.IsFollow() ) + { + SwSectionFrm* pMaster = rSect.FindMaster(); + pMaster->SetFollow( this ); + bIsFollow = sal_True; + } + else + rSect.bIsFollow = sal_True; + SetFollow( &rSect ); + } + else + { + bIsFollow = sal_True; + SetFollow( rSect.GetFollow() ); + rSect.SetFollow( this ); + if( !GetFollow() ) + rSect.SimpleFormat(); + if( !rSect.IsColLocked() ) + rSect.InvalidateSize(); + } +} + +// NOTE: call <SwSectionFrm::Init()> directly after creation of a new section +// frame and its insert in the layout. +void SwSectionFrm::Init() +{ + OSL_ENSURE( GetUpper(), "SwSectionFrm::Init before insertion?!" ); + SWRECTFN( this ) + long nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + (Frm().*fnRect->fnSetWidth)( nWidth ); + (Frm().*fnRect->fnSetHeight)( 0 ); + + // #109700# LRSpace for sections + const SvxLRSpaceItem& rLRSpace = GetFmt()->GetLRSpace(); + (Prt().*fnRect->fnSetLeft)( rLRSpace.GetLeft() ); + (Prt().*fnRect->fnSetWidth)( nWidth - rLRSpace.GetLeft() - + rLRSpace.GetRight() ); + (Prt().*fnRect->fnSetHeight)( 0 ); + + const SwFmtCol &rCol = GetFmt()->GetCol(); + if( ( rCol.GetNumCols() > 1 || IsAnyNoteAtEnd() ) && !IsInFtn() ) + { + const SwFmtCol *pOld = Lower() ? &rCol : new SwFmtCol; + ChgColumns( *pOld, rCol, IsAnyNoteAtEnd() ); + if( pOld != &rCol ) + delete pOld; + } +} + +SwSectionFrm::~SwSectionFrm() +{ + if( GetFmt() && !GetFmt()->GetDoc()->IsInDtor() ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm ) + pRootFrm->RemoveFromList( this ); //swmod 071108//swmod 071225 + if( IsFollow() ) + { + SwSectionFrm *pMaster = FindMaster(); + if( pMaster ) + { + PROTOCOL( this, PROT_SECTION, ACT_DEL_FOLLOW, pMaster ) + pMaster->SetFollow( GetFollow() ); + // Ein Master greift sich immer den Platz bis zur Unterkante seines + // Uppers. Wenn er keinen Follow mehr hat, kann er diesen ggf. wieder + // freigeben, deshalb wird die Size des Masters invalidiert. + if( !GetFollow() ) + pMaster->InvalidateSize(); + } + } + else if( HasFollow() ) + { + PROTOCOL( this, PROT_SECTION, ACT_DEL_MASTER, GetFollow() ) + GetFollow()->bIsFollow = sal_False; + } + } +} + + +/************************************************************************* +|* +|* SwSectionFrm::DelEmpty() +|* +|*************************************************************************/ +void SwSectionFrm::DelEmpty( sal_Bool bRemove ) +{ + if( IsColLocked() ) + { + OSL_ENSURE( !bRemove, "Don't delete locked SectionFrms" ); + return; + } + SwFrm* pUp = GetUpper(); + if( pUp ) + { + // --> OD 2005-12-01 #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for current next paragraph will change + // and relation CONTENT_FLOWS_TO for current previous paragraph will change. + { + ViewShell* pViewShell( getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(FindPrevCnt( true )) ); + } + } + // <-- + _Cut( bRemove ); + } + if( IsFollow() ) + { + SwSectionFrm *pMaster = FindMaster(); + pMaster->SetFollow( GetFollow() ); + // Ein Master greift sich immer den Platz bis zur Unterkante seines + // Uppers. Wenn er keinen Follow mehr hat, kann er diesen ggf. wieder + // freigeben, deshalb wird die Size des Masters invalidiert. + if( !GetFollow() && !pMaster->IsColLocked() ) + pMaster->InvalidateSize(); + bIsFollow = sal_False; + } + else if( HasFollow() ) + GetFollow()->bIsFollow = sal_False; + pFollow = NULL; + if( pUp ) + { + Frm().Height( 0 ); + // Wenn wir sowieso sofort zerstoert werden, brauchen/duerfen wir + // uns gar nicht erst in die Liste eintragen + if( bRemove ) + { // Wenn wir bereits halbtot waren vor diesem DelEmpty, so + // stehen wir vermutlich auch in der Liste und muessen uns + // dort austragen + if( !pSection && getRootFrm() ) + getRootFrm()->RemoveFromList( this ); + } + else if( getRootFrm() ) + getRootFrm()->InsertEmptySct( this ); //swmod 071108//swmod 071225 + pSection = NULL; // damit ist allerdings eine Reanimierung quasi ausgeschlossen + } +} + +/************************************************************************* +|* +|* SwSectionFrm::Cut() +|* +|*************************************************************************/ +void SwSectionFrm::Cut() +{ + _Cut( sal_True ); +} + +void SwSectionFrm::_Cut( sal_Bool bRemove ) +{ + OSL_ENSURE( GetUpper(), "Cut ohne Upper()." ); + + PROTOCOL( this, PROT_CUT, 0, GetUpper() ) + + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + SwFrm *pFrm = GetNext(); + SwFrm* pPrepFrm = NULL; + while( pFrm && pFrm->IsSctFrm() && !((SwSectionFrm*)pFrm)->GetSection() ) + pFrm = pFrm->GetNext(); + if( pFrm ) + { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger + //berechnet der ist jetzt wo er der erste wird obsolete + pFrm->_InvalidatePrt(); + pFrm->_InvalidatePos(); + if( pFrm->IsSctFrm() ) + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if ( pFrm && pFrm->IsCntntFrm() ) + { + pFrm->InvalidatePage( pPage ); + if( IsInFtn() && !GetIndPrev() ) + pPrepFrm = pFrm; + } + } + else + { + InvalidateNextPos(); + //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper + if ( 0 != (pFrm = GetPrev()) ) + { pFrm->SetRetouche(); + pFrm->Prepare( PREP_WIDOWS_ORPHANS ); + if ( pFrm->IsCntntFrm() ) + pFrm->InvalidatePage( pPage ); + } + //Wenn ich der einzige FlowFrm in meinem Upper bin (war), so muss + //er die Retouche uebernehmen. + //Ausserdem kann eine Leerseite entstanden sein. + else + { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); + pRoot->SetSuperfluous(); + GetUpper()->SetCompletePaint(); + } + } + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + if( bRemove ) + { + Remove(); + if( pUp && !pUp->Lower() && pUp->IsFtnFrm() && !pUp->IsColLocked() && + pUp->GetUpper() ) + { + pUp->Cut(); + delete pUp; + pUp = NULL; + } + } + if( pPrepFrm ) + pPrepFrm->Prepare( PREP_FTN ); + if ( pUp ) + { + SWRECTFN( this ); + SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if( nFrmHeight > 0 ) + { + if( !bRemove ) + { + (Frm().*fnRect->fnSetHeight)( 0 ); + (Prt().*fnRect->fnSetHeight)( 0 ); + } + pUp->Shrink( nFrmHeight ); + } + } +} + +/************************************************************************* +|* +|* SwSectionFrm::Paste() +|* +|*************************************************************************/ + +void SwSectionFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + PROTOCOL( this, PROT_PASTE, 0, GetUpper() ) + + //In den Baum einhaengen. + SwSectionFrm* pSect = pParent->FindSctFrm(); + // --> OD 2008-06-23 #156927# + // Assure that parent is not inside a table frame, which is inside the found section frame. + if ( pSect ) + { + SwTabFrm* pTableFrm = pParent->FindTabFrm(); + if ( pTableFrm && + pSect->IsAnLower( pTableFrm ) ) + { + pSect = 0; + } + } + // <-- + + SWRECTFN( pParent ) + if( pSect && HasToBreak( pSect ) ) + { + if( pParent->IsColBodyFrm() ) // handelt es sich um einen spaltigen Bereich + { + // Falls wir zufaellig am Ende einer Spalte stehen, muss pSibling + // auf den ersten Frame der naechsten Spalte zeigen, damit + // der Inhalt der naechsten Spalte von InsertGroup richtig in den + // neu angelegten pSect umgehaengt wird. + SwColumnFrm *pCol = (SwColumnFrm*)pParent->GetUpper(); + while( !pSibling && 0 != ( pCol = (SwColumnFrm*)pCol->GetNext() ) ) + pSibling = ((SwLayoutFrm*)((SwColumnFrm*)pCol)->Lower())->Lower(); + if( pSibling ) + { + // Schlimmer noch: alle folgenden Spalteninhalte muessen + // an die pSibling-Kette angehaengt werden, damit sie + // mitgenommen werden. + SwFrm *pTmp = pSibling; + while ( 0 != ( pCol = (SwColumnFrm*)pCol->GetNext() ) ) + { + while ( pTmp->GetNext() ) + pTmp = pTmp->GetNext(); + SwFrm* pSave = ::SaveCntnt( pCol ); + ::RestoreCntnt( pSave, pSibling->GetUpper(), pTmp, true ); + } + } + } + pParent = pSect; + pSect = new SwSectionFrm( *((SwSectionFrm*)pParent)->GetSection(), pParent ); + // Wenn pParent in zwei Teile zerlegt wird, so muss sein Follow am + // neuen, zweiten Teil angebracht werden. + pSect->SetFollow( ((SwSectionFrm*)pParent)->GetFollow() ); + ((SwSectionFrm*)pParent)->SetFollow( NULL ); + if( pSect->GetFollow() ) + pParent->_InvalidateSize(); + + InsertGroupBefore( pParent, pSibling, pSect ); + pSect->Init(); + (pSect->*fnRect->fnMakePos)( pSect->GetUpper(), pSect->GetPrev(), sal_True); + if( !((SwLayoutFrm*)pParent)->Lower() ) + { + SwSectionFrm::MoveCntntAndDelete( (SwSectionFrm*)pParent, sal_False ); + pParent = this; + } + } + else + InsertGroupBefore( pParent, pSibling, NULL ); + + _InvalidateAll(); + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + + if ( pSibling ) + { + pSibling->_InvalidatePos(); + pSibling->_InvalidatePrt(); + if ( pSibling->IsCntntFrm() ) + pSibling->InvalidatePage( pPage ); + } + + SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if( nFrmHeight ) + pParent->Grow( nFrmHeight ); + + if ( GetPrev() ) + { + if ( !IsFollow() ) + { + GetPrev()->InvalidateSize(); + if ( GetPrev()->IsCntntFrm() ) + GetPrev()->InvalidatePage( pPage ); + } + } +} + + +/************************************************************************* +|* +|* SwSectionFrm::HasToBreak() +|* +|* Hier wird entschieden, ob der this-SectionFrm den uebergebenen +|* (Section)Frm aufbrechen soll oder nicht. +|* Zunaechst werden uebergeordnete Bereiche immer aufgebrochen, +|* spaeter koennte man es einstellbar machen. +|* +|*************************************************************************/ + +sal_Bool SwSectionFrm::HasToBreak( const SwFrm* pFrm ) const +{ + if( !pFrm->IsSctFrm() ) + return sal_False; + + SwSectionFmt *pTmp = (SwSectionFmt*)GetFmt(); +// if( !pTmp->GetSect().GetValue() ) +// return sal_False; + + const SwFrmFmt *pOtherFmt = ((SwSectionFrm*)pFrm)->GetFmt(); + do + { + pTmp = pTmp->GetParent(); + if( !pTmp ) + return sal_False; + if( pTmp == pOtherFmt ) + return sal_True; + } while( sal_True ); // ( pTmp->GetSect().GetValue() ); +} + +/************************************************************************* +|* +|* SwSectionFrm::MergeNext() +|* +|* Verschmilzt zwei SectionFrms, falls es sich um den +|* gleichen Bereich handelt. +|* Notwendig kann dies sein, wenn ein (Unter-)Bereich geloescht wird, der +|* einen anderen in zwei Teile zerlegt hatte. +|* +|*************************************************************************/ + +void SwSectionFrm::MergeNext( SwSectionFrm* pNxt ) +{ + if( !pNxt->IsJoinLocked() && GetSection() == pNxt->GetSection() ) + { + PROTOCOL( this, PROT_SECTION, ACT_MERGE, pNxt ) + + SwFrm* pTmp = ::SaveCntnt( pNxt ); + if( pTmp ) + { + SwFrm* pLast = Lower(); + SwLayoutFrm* pLay = this; + if( pLast ) + { + while( pLast->GetNext() ) + pLast = pLast->GetNext(); + if( pLast->IsColumnFrm() ) + { // Spalten jetzt mit BodyFrm + pLay = (SwLayoutFrm*)((SwLayoutFrm*)pLast)->Lower(); + pLast = pLay->Lower(); + if( pLast ) + while( pLast->GetNext() ) + pLast = pLast->GetNext(); + } + } + ::RestoreCntnt( pTmp, pLay, pLast, true ); + } + SetFollow( pNxt->GetFollow() ); + pNxt->SetFollow( NULL ); + pNxt->bIsFollow = sal_False; + pNxt->Cut(); + delete pNxt; + InvalidateSize(); + } +} + +/************************************************************************* +|* +|* SwSectionFrm::SplitSect() +|* +|* Zerteilt einen SectionFrm in zwei Teile, der zweite Teil beginnt mit dem +|* uebergebenen Frame. +|* Benoetigt wird dies beim Einfuegen eines inneren Bereichs, weil innerhalb +|* von Rahmen oder Tabellenzellen das MoveFwd nicht den erwuenschten Effekt +|* haben kann. +|* +|*************************************************************************/ + +sal_Bool SwSectionFrm::SplitSect( SwFrm* pFrm, sal_Bool bApres ) +{ + OSL_ENSURE( pFrm, "SplitSect: Why?" ); + SwFrm* pOther = bApres ? pFrm->FindNext() : pFrm->FindPrev(); + if( !pOther ) + return sal_False; + SwSectionFrm* pSect = pOther->FindSctFrm(); + if( pSect != this ) + return sal_False; + // Den Inhalt zur Seite stellen + SwFrm* pSav = ::SaveCntnt( this, bApres ? pOther : pFrm ); + OSL_ENSURE( pSav, "SplitSect: What's on?" ); + if( pSav ) // Robust + { // Einen neuen SctFrm anlegen, nicht als Follow/Master + SwSectionFrm* pNew = new SwSectionFrm( *pSect->GetSection(), pSect ); + pNew->InsertBehind( pSect->GetUpper(), pSect ); + pNew->Init(); + SWRECTFN( this ) + (pNew->*fnRect->fnMakePos)( NULL, pSect, sal_True ); + // OD 25.03.2003 #108339# - restore content: + // determine layout frame for restoring content after the initialization + // of the section frame. In the section initialization the columns are + // created. + { + SwLayoutFrm* pLay = pNew; + // Search for last layout frame, e.g. for columned sections. + while( pLay->Lower() && pLay->Lower()->IsLayoutFrm() ) + pLay = (SwLayoutFrm*)pLay->Lower(); + ::RestoreCntnt( pSav, pLay, NULL, true ); + } + _InvalidateSize(); + if( HasFollow() ) + { + pNew->SetFollow( GetFollow() ); + SetFollow( NULL ); + } + return sal_True; + } + return sal_False; +} + +/************************************************************************* +|* +|* SwSectionFrm::MoveCntntAndDelete() +|* +|* MoveCntnt wird zur Zerstoerung eines SectionFrms wg. Aufhebung oder +|* Verstecken des Bereichs gerufen, um den Inhalt umzuhaengen. +|* Wenn der SectionFrm keinen anderen aufbrach, so wird der Inhalt in +|* den Upper bewegt. Anderfalls wird der Inhalt in den anderen SectionFrm +|* umgehaengt, dieser muss ggf. gemergt werden. +|* +|*************************************************************************/ +// Wenn ein mehrspaltiger Bereich aufgehoben wird, muessen die ContentFrms +// invalidiert werden + +void lcl_InvalidateInfFlags( SwFrm* pFrm, sal_Bool bInva ) +{ + while ( pFrm ) + { + pFrm->InvalidateInfFlags(); + if( bInva ) + { + pFrm->_InvalidatePos(); + pFrm->_InvalidateSize(); + pFrm->_InvalidatePrt(); + } + if( pFrm->IsLayoutFrm() ) + lcl_InvalidateInfFlags( ((SwLayoutFrm*)pFrm)->GetLower(), sal_False ); + pFrm = pFrm->GetNext(); + } +} + + +// +// Works like SwCntntFrm::ImplGetNextCntntFrm, but starts with a LayoutFrm +// +SwCntntFrm* lcl_GetNextCntntFrm( const SwLayoutFrm* pLay, bool bFwd ) +{ + if ( bFwd ) + { + if ( pLay->GetNext() && pLay->GetNext()->IsCntntFrm() ) + return (SwCntntFrm*)pLay->GetNext(); + } + else + { + if ( pLay->GetPrev() && pLay->GetPrev()->IsCntntFrm() ) + return (SwCntntFrm*)pLay->GetPrev(); + } + + // #100926# + const SwFrm* pFrm = pLay; + SwCntntFrm *pCntntFrm = 0; + sal_Bool bGoingUp = sal_True; + do { + const SwFrm *p = 0; + sal_Bool bGoingFwdOrBwd = sal_False, bGoingDown = sal_False; + + bGoingDown = !bGoingUp && ( 0 != ( p = pFrm->IsLayoutFrm() ? ((SwLayoutFrm*)pFrm)->Lower() : 0 ) ); + if ( !bGoingDown ) + { + bGoingFwdOrBwd = ( 0 != ( p = pFrm->IsFlyFrm() ? + ( bFwd ? ((SwFlyFrm*)pFrm)->GetNextLink() : ((SwFlyFrm*)pFrm)->GetPrevLink() ) : + ( bFwd ? pFrm->GetNext() :pFrm->GetPrev() ) ) ); + if ( !bGoingFwdOrBwd ) + { + bGoingUp = (0 != (p = pFrm->GetUpper() ) ); + if ( !bGoingUp ) + return 0; + } + } + + bGoingUp = !( bGoingFwdOrBwd || bGoingDown ); + + if( !bFwd && bGoingDown && p ) + while ( p->GetNext() ) + p = p->GetNext(); + + pFrm = p; + } while ( 0 == (pCntntFrm = (pFrm->IsCntntFrm() ? (SwCntntFrm*)pFrm:0) )); + + return pCntntFrm; +} + +#define FIRSTLEAF( pLayFrm ) ( ( pLayFrm->Lower() && pLayFrm->Lower()->IsColumnFrm() )\ + ? pLayFrm->GetNextLayoutLeaf() \ + : pLayFrm ) + +void SwSectionFrm::MoveCntntAndDelete( SwSectionFrm* pDel, sal_Bool bSave ) +{ + sal_Bool bSize = pDel->Lower() && pDel->Lower()->IsColumnFrm(); + SwFrm* pPrv = pDel->GetPrev(); + SwLayoutFrm* pUp = pDel->GetUpper(); + // OD 27.03.2003 #i12711# - initialize local pointer variables. + SwSectionFrm* pPrvSct = NULL; + SwSectionFrm* pNxtSct = NULL; + SwSectionFmt* pParent = static_cast<SwSectionFmt*>(pDel->GetFmt())->GetParent(); + if( pDel->IsInTab() && pParent ) + { + SwTabFrm *pTab = pDel->FindTabFrm(); + // Wenn wir innerhalb einer Tabelle liegen, koennen wir nur Bereiche + // aufgebrochen haben, die ebenfalls innerhalb liegen, nicht etwa + // einen Bereich, der die gesamte Tabelle umfasst. + if( pTab->IsInSct() && pParent == pTab->FindSctFrm()->GetFmt() ) + pParent = NULL; + } + // Wenn unser Format einen Parent besitzt, so haben wir vermutlich + // einen anderen SectionFrm aufgebrochen, dies muss geprueft werden, + // dazu besorgen wir uns zunaechst den vorhergehende und den nach- + // folgenden CntntFrm, mal sehen, ob diese in SectionFrms liegen. + // OD 27.03.2003 #i12711# - check, if previous and next section belonging + // together and can be joined, *not* only if deleted section contains content. + if ( pParent ) + { + SwFrm* pPrvCntnt = lcl_GetNextCntntFrm( pDel, false ); + pPrvSct = pPrvCntnt ? pPrvCntnt->FindSctFrm() : NULL; + SwFrm* pNxtCntnt = lcl_GetNextCntntFrm( pDel, true ); + pNxtSct = pNxtCntnt ? pNxtCntnt->FindSctFrm() : NULL; + } + else + { + pParent = NULL; + pPrvSct = pNxtSct = NULL; + } + + // Jetzt wird der Inhalt beseite gestellt und der Frame zerstoert + SwFrm *pSave = bSave ? ::SaveCntnt( pDel ) : NULL; + sal_Bool bOldFtn = sal_True; + if( pSave && pUp->IsFtnFrm() ) + { + bOldFtn = ((SwFtnFrm*)pUp)->IsColLocked(); + ((SwFtnFrm*)pUp)->ColLock(); + } + pDel->DelEmpty( sal_True ); + delete pDel; + if( pParent ) + { // Hier wird die geeignete Einfuegeposition gesucht + if( pNxtSct && pNxtSct->GetFmt() == pParent ) + { // Hier koennen wir uns am Anfang einfuegen + pUp = FIRSTLEAF( pNxtSct ); + pPrv = NULL; + if( pPrvSct && !( pPrvSct->GetFmt() == pParent ) ) + pPrvSct = NULL; // damit nicht gemergt wird + } + else if( pPrvSct && pPrvSct->GetFmt() == pParent ) + { // Wunderbar, hier koennen wir uns am Ende einfuegen + pUp = pPrvSct; + if( pUp->Lower() && pUp->Lower()->IsColumnFrm() ) + { + pUp = static_cast<SwLayoutFrm*>(pUp->GetLastLower()); + // Der Body der letzten Spalte + pUp = static_cast<SwLayoutFrm*>(pUp->Lower()); + } + // damit hinter dem letzten eingefuegt wird + pPrv = pUp->GetLastLower(); + pPrvSct = NULL; // damit nicht gemergt wird + } + else + { + if( pSave ) + { // Folgende Situationen: Vor und hinter dem zu loeschenden Bereich + // ist entweder die Bereichsgrenze des umfassenden Bereichs oder + // es schliesst ein anderer (Geschwister-)Bereich direkt an, der + // vom gleichen Parent abgeleitet ist. + // Dann gibt es (noch) keinen Teil unseres Parents, der den Inhalt + // aufnehmen kann,also bauen wir ihn uns. + pPrvSct = new SwSectionFrm( *pParent->GetSection(), pUp ); + pPrvSct->InsertBehind( pUp, pPrv ); + pPrvSct->Init(); + SWRECTFN( pUp ) + (pPrvSct->*fnRect->fnMakePos)( pUp, pPrv, sal_True ); + pUp = FIRSTLEAF( pPrvSct ); + pPrv = NULL; + } + pPrvSct = NULL; // damit nicht gemergt wird + } + } + // Der Inhalt wird eingefuegt.. + if( pSave ) + { + lcl_InvalidateInfFlags( pSave, bSize ); + ::RestoreCntnt( pSave, pUp, pPrv, true ); + pUp->FindPageFrm()->InvalidateCntnt(); + if( !bOldFtn ) + ((SwFtnFrm*)pUp)->ColUnlock(); + } + // jetzt koennen eventuell zwei Teile des uebergeordneten Bereich verschmelzen + if( pPrvSct && !pPrvSct->IsJoinLocked() ) + { + OSL_ENSURE( pNxtSct, "MoveCntnt: No Merge" ); + pPrvSct->MergeNext( pNxtSct ); + } +} + +void SwSectionFrm::MakeAll() +{ + if ( IsJoinLocked() || IsColLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) + return; + if( !pSection ) // Durch DelEmpty + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( getRootFrm()->IsInDelList( this ), "SectionFrm without Section" ); +#endif + if( !bValidPos ) + { + if( GetUpper() ) + { + SWRECTFN( GetUpper() ) + (this->*fnRect->fnMakePos)( GetUpper(), GetPrev(), sal_False ); + } + } + bValidSize = bValidPos = bValidPrtArea = sal_True; + return; + } + LockJoin(); //Ich lass mich nicht unterwegs vernichten. + + while( GetNext() && GetNext() == GetFollow() ) + { + const SwFrm* pFoll = GetFollow(); + MergeNext( (SwSectionFrm*)GetNext() ); + if( pFoll == GetFollow() ) + break; + } + + // OD 2004-03-15 #116561# - In online layout join the follows, if section + // can grow. + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() && + ( Grow( LONG_MAX, true ) > 0 ) ) + { + while( GetFollow() ) + { + const SwFrm* pFoll = GetFollow(); + MergeNext( GetFollow() ); + if( pFoll == GetFollow() ) + break; + } + } + + // Ein Bereich mit Follow nimmt allen Platz bis zur Unterkante des Uppers + // in Anspruch. Bewegt er sich, so kann seine Groesse zu- oder abnehmen... + if( !bValidPos && ToMaximize( sal_False ) ) + bValidSize = sal_False; + +#if OSL_DEBUG_LEVEL > 1 + const SwFmtCol &rCol = GetFmt()->GetCol(); + (void)rCol; +#endif + SwLayoutFrm::MakeAll(); + UnlockJoin(); + if( pSection && IsSuperfluous() ) + DelEmpty( sal_False ); +} + +sal_Bool SwSectionFrm::ShouldBwdMoved( SwLayoutFrm *, sal_Bool , sal_Bool & ) +{ + OSL_FAIL( "Hups, wo ist meine Tarnkappe?" ); + return sal_False; +} + +const SwSectionFmt* SwSectionFrm::_GetEndSectFmt() const +{ + const SwSectionFmt *pFmt = pSection->GetFmt(); + while( !pFmt->GetEndAtTxtEnd().IsAtEnd() ) + { + if( pFmt->GetRegisteredIn()->ISA( SwSectionFmt ) ) + pFmt = (SwSectionFmt*)pFmt->GetRegisteredIn(); + else + return NULL; + } + return pFmt; +} + +void lcl_FindCntntFrm( SwCntntFrm* &rpCntntFrm, SwFtnFrm* &rpFtnFrm, + SwFrm* pFrm, sal_Bool &rbChkFtn ) +{ + if( pFrm ) + { + while( pFrm->GetNext() ) + pFrm = pFrm->GetNext(); + while( !rpCntntFrm && pFrm ) + { + if( pFrm->IsCntntFrm() ) + rpCntntFrm = (SwCntntFrm*)pFrm; + else if( pFrm->IsLayoutFrm() ) + { + if( pFrm->IsFtnFrm() ) + { + if( rbChkFtn ) + { + rpFtnFrm = (SwFtnFrm*)pFrm; + rbChkFtn = rpFtnFrm->GetAttr()->GetFtn().IsEndNote(); + } + } + else + lcl_FindCntntFrm( rpCntntFrm, rpFtnFrm, + ((SwLayoutFrm*)pFrm)->Lower(), rbChkFtn ); + } + pFrm = pFrm->GetPrev(); + } + } +} + +SwCntntFrm *SwSectionFrm::FindLastCntnt( sal_uInt8 nMode ) +{ + SwCntntFrm *pRet = NULL; + SwFtnFrm *pFtnFrm = NULL; + SwSectionFrm *pSect = this; + if( nMode ) + { + const SwSectionFmt *pFmt = IsEndnAtEnd() ? GetEndSectFmt() : + pSection->GetFmt(); + do { + while( pSect->HasFollow() ) + pSect = pSect->GetFollow(); + SwFrm* pTmp = pSect->FindNext(); + while( pTmp && pTmp->IsSctFrm() && + !((SwSectionFrm*)pTmp)->GetSection() ) + pTmp = pTmp->FindNext(); + if( pTmp && pTmp->IsSctFrm() && + ((SwSectionFrm*)pTmp)->IsDescendantFrom( pFmt ) ) + pSect = (SwSectionFrm*)pTmp; + else + break; + } while( sal_True ); + } + sal_Bool bFtnFound = nMode == FINDMODE_ENDNOTE; + do + { + lcl_FindCntntFrm( pRet, pFtnFrm, pSect->Lower(), bFtnFound ); + if( pRet || !pSect->IsFollow() || !nMode || + ( FINDMODE_MYLAST == nMode && this == pSect ) ) + break; + pSect = pSect->FindMaster(); + } while( pSect ); + if( ( nMode == FINDMODE_ENDNOTE ) && pFtnFrm ) + pRet = pFtnFrm->ContainsCntnt(); + return pRet; +} + +sal_Bool SwSectionFrm::CalcMinDiff( SwTwips& rMinDiff ) const +{ + if( ToMaximize( sal_True ) ) + { + SWRECTFN( this ) + rMinDiff = (GetUpper()->*fnRect->fnGetPrtBottom)(); + rMinDiff = (Frm().*fnRect->fnBottomDist)( rMinDiff ); + return sal_True; + } + return sal_False; +} + +/************************************************************************* + * + * SwSectionFrm::CollectEndnotes( ) + * + * CollectEndnotes looks for endnotes in the sectionfrm and his follows, + * the endnotes will cut off the layout and put into the array. + * If the first endnote is not a master-SwFtnFrm, the whole sectionfrm + * contains only endnotes and it is not necessary to collect them. + * + *************************************************************************/ + +SwFtnFrm* lcl_FindEndnote( SwSectionFrm* &rpSect, sal_Bool &rbEmpty, + SwLayouter *pLayouter ) +{ + // if rEmpty is set, the rpSect is already searched + SwSectionFrm* pSect = rbEmpty ? rpSect->GetFollow() : rpSect; + while( pSect ) + { + OSL_ENSURE( (pSect->Lower() && pSect->Lower()->IsColumnFrm()) || pSect->GetUpper()->IsFtnFrm(), + "InsertEndnotes: Where's my column?" ); + + // i73332: Columned section in endnote + SwColumnFrm* pCol = 0; + if(pSect->Lower() && pSect->Lower()->IsColumnFrm()) + pCol = (SwColumnFrm*)pSect->Lower(); + + while( pCol ) // check all columns + { + SwFtnContFrm* pFtnCont = pCol->FindFtnCont(); + if( pFtnCont ) + { + SwFtnFrm* pRet = (SwFtnFrm*)pFtnCont->Lower(); + while( pRet ) // look for endnotes + { + if( pRet->GetAttr()->GetFtn().IsEndNote() ) + { + if( pRet->GetMaster() ) + { + if( pLayouter ) + pLayouter->CollectEndnote( pRet ); + else + return 0; + } + else + return pRet; // Found + } + pRet = (SwFtnFrm*)pRet->GetNext(); + } + } + pCol = (SwColumnFrm*)pCol->GetNext(); + } + rpSect = pSect; + pSect = pLayouter ? pSect->GetFollow() : NULL; + rbEmpty = sal_True; + } + return NULL; +} + +void lcl_ColumnRefresh( SwSectionFrm* pSect, sal_Bool bFollow ) +{ + while( pSect ) + { + sal_Bool bOldLock = pSect->IsColLocked(); + pSect->ColLock(); + if( pSect->Lower() && pSect->Lower()->IsColumnFrm() ) + { + SwColumnFrm *pCol = (SwColumnFrm*)pSect->Lower(); + do + { pCol->_InvalidateSize(); + pCol->_InvalidatePos(); + ((SwLayoutFrm*)pCol)->Lower()->_InvalidateSize(); + pCol->Calc(); // calculation of column and + ((SwLayoutFrm*)pCol)->Lower()->Calc(); // body + pCol = (SwColumnFrm*)pCol->GetNext(); + } while ( pCol ); + } + if( !bOldLock ) + pSect->ColUnlock(); + if( bFollow ) + pSect = pSect->GetFollow(); + else + pSect = NULL; + } +} + +void SwSectionFrm::CollectEndnotes( SwLayouter* pLayouter ) +{ + OSL_ENSURE( IsColLocked(), "CollectEndnotes: You love the risk?" ); + // i73332: Section in footnode does not have columns! + OSL_ENSURE( (Lower() && Lower()->IsColumnFrm()) || GetUpper()->IsFtnFrm(), "Where's my column?" ); + + SwSectionFrm* pSect = this; + SwFtnFrm* pFtn; + sal_Bool bEmpty = sal_False; + // pSect is the last sectionfrm without endnotes or the this-pointer + // the first sectionfrm with endnotes may be destroyed, when the endnotes + // is cutted + while( 0 != (pFtn = lcl_FindEndnote( pSect, bEmpty, pLayouter )) ) + pLayouter->CollectEndnote( pFtn ); + if( pLayouter->HasEndnotes() ) + lcl_ColumnRefresh( this, sal_True ); +} + +/************************************************************************* +|* +|* SwSectionFrm::_CheckClipping( sal_Bool bGrow, sal_Bool bMaximize ) +|* +|* Beschreibung: Passt die Groesse an die Umgebung an. +|* Wer einen Follow oder Fussnoten besitzt, soll bis zur Unterkante +|* des Uppers gehen (bMaximize). +|* Niemand darf ueber den Upper hinausgehen, ggf. darf man versuchen (bGrow) +|* seinen Upper zu growen. +|* Wenn die Groesse veraendert werden musste, wird der Inhalt kalkuliert. +|* +|*************************************************************************/ + +/// OD 18.09.2002 #100522# +/// perform calculation of content, only if height has changed. +void SwSectionFrm::_CheckClipping( sal_Bool bGrow, sal_Bool bMaximize ) +{ + SWRECTFN( this ) + long nDiff; + SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if( bGrow && ( !IsInFly() || !GetUpper()->IsColBodyFrm() || + !FindFlyFrm()->IsLocked() ) ) + { + nDiff = -(Frm().*fnRect->fnBottomDist)( nDeadLine ); + if( !bMaximize ) + nDiff += Undersize(); + if( nDiff > 0 ) + { + long nAdd = GetUpper()->Grow( nDiff ); + if( bVert && !bRev ) + nDeadLine -= nAdd; + else + nDeadLine += nAdd; + } + } + nDiff = -(Frm().*fnRect->fnBottomDist)( nDeadLine ); + SetUndersized( !bMaximize && nDiff >= 0 ); + const bool bCalc = ( IsUndersized() || bMaximize ) && + ( nDiff || + (Prt().*fnRect->fnGetTop)() > (Frm().*fnRect->fnGetHeight)() ); + // OD 03.11.2003 #i19737# - introduce local variable <bExtraCalc> to indicate + // that a calculation has to be done beside the value of <bCalc>. + bool bExtraCalc = false; + if( !bCalc && !bGrow && IsAnyNoteAtEnd() && !IsInFtn() ) + { + SwSectionFrm *pSect = this; + sal_Bool bEmpty = sal_False; + SwLayoutFrm* pFtn = IsEndnAtEnd() ? + lcl_FindEndnote( pSect, bEmpty, NULL ) : NULL; + if( pFtn ) + { + pFtn = pFtn->FindFtnBossFrm(); + SwFrm* pTmp = FindLastCntnt( FINDMODE_LASTCNT ); + // OD 08.11.2002 #104840# - use <SwLayoutFrm::IsBefore(..)> + if ( pTmp && pFtn->IsBefore( pTmp->FindFtnBossFrm() ) ) + bExtraCalc = true; + } + else if( GetFollow() && !GetFollow()->ContainsAny() ) + bExtraCalc = true; + } + if ( bCalc || bExtraCalc ) + { + nDiff = (*fnRect->fnYDiff)( nDeadLine, (Frm().*fnRect->fnGetTop)() ); + if( nDiff < 0 ) + { + nDiff = 0; + nDeadLine = (Frm().*fnRect->fnGetTop)(); + } + const Size aOldSz( Prt().SSize() ); + long nTop = (this->*fnRect->fnGetTopMargin)(); + (Frm().*fnRect->fnSetBottom)( nDeadLine ); + nDiff = (Frm().*fnRect->fnGetHeight)(); + if( nTop > nDiff ) + nTop = nDiff; + (this->*fnRect->fnSetYMargins)( nTop, 0 ); + + // OD 18.09.2002 #100522# + // Determine, if height has changed. + // Note: In vertical layout the height equals the width value. + bool bHeightChanged = bVert ? + (aOldSz.Width() != Prt().Width()) : + (aOldSz.Height() != Prt().Height()); + // Wir haben zu guter Letzt noch einmal die Hoehe geaendert, + // dann wird das innere Layout (Columns) kalkuliert und + // der Inhalt ebenfalls. + // OD 18.09.2002 #100522# + // calculate content, only if height has changed. + // OD 03.11.2003 #i19737# - restriction of content calculation too strong. + // If an endnote has an incorrect position or a follow section contains + // no content except footnotes/endnotes, the content has also been calculated. + if ( ( bHeightChanged || bExtraCalc ) && Lower() ) + { + if( Lower()->IsColumnFrm() ) + { + lcl_ColumnRefresh( this, sal_False ); + ::CalcCntnt( this ); + } + else + { + ChgLowersProp( aOldSz ); + if( !bMaximize && !IsCntntLocked() ) + ::CalcCntnt( this ); + } + } + } +} + +void SwSectionFrm::SimpleFormat() +{ + if ( IsJoinLocked() || IsColLocked() ) + return; + // OSL_ENSURE( pFollow, "SimpleFormat: Follow required" ); + LockJoin(); + SWRECTFN( this ) + if( GetPrev() || GetUpper() ) + { + // --> OD 2009-09-28 #b6882166# + // assure notifications on position changes. + const SwLayNotify aNotify( this ); + // <-- + (this->*fnRect->fnMakePos)( GetUpper(), GetPrev(), sal_False ); + bValidPos = sal_True; + } + SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + // OD 22.10.2002 #97265# - call always method <lcl_ColumnRefresh(..)>, in + // order to get calculated lowers, not only if there space left in its upper. + if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) >= 0 ) + { + (Frm().*fnRect->fnSetBottom)( nDeadLine ); + long nHeight = (Frm().*fnRect->fnGetHeight)(); + long nTop = CalcUpperSpace(); + if( nTop > nHeight ) + nTop = nHeight; + (this->*fnRect->fnSetYMargins)( nTop, 0 ); + } + lcl_ColumnRefresh( this, sal_False ); + UnlockJoin(); +} + +// --> OD 2005-01-11 #i40147# - helper class to perform extra section format +// to position anchored objects and to keep the position of whose objects locked. +class ExtraFormatToPositionObjs +{ + private: + SwSectionFrm* mpSectFrm; + bool mbExtraFormatPerformed; + + public: + ExtraFormatToPositionObjs( SwSectionFrm& _rSectFrm) + : mpSectFrm( &_rSectFrm ), + mbExtraFormatPerformed( false ) + {} + + ~ExtraFormatToPositionObjs() + { + if ( mbExtraFormatPerformed ) + { + // release keep locked position of lower floating screen objects + SwPageFrm* pPageFrm = mpSectFrm->FindPageFrm(); + SwSortedObjs* pObjs = pPageFrm ? pPageFrm->GetSortedObjs() : 0L; + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( i = 0; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + + if ( mpSectFrm->IsAnLower( pAnchoredObj->GetAnchorFrm() ) ) + { + pAnchoredObj->SetKeepPosLocked( false ); + } + } + } + } + } + + // --> OD 2008-06-20 #i81555# + void InitObjs( SwFrm& rFrm ) + { + SwSortedObjs* pObjs = rFrm.GetDrawObjs(); + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( i = 0; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + + pAnchoredObj->UnlockPosition(); + pAnchoredObj->SetClearedEnvironment( false ); + } + } + SwLayoutFrm* pLayoutFrm = dynamic_cast<SwLayoutFrm*>(&rFrm); + if ( pLayoutFrm != 0 ) + { + SwFrm* pLowerFrm = pLayoutFrm->GetLower(); + while ( pLowerFrm != 0 ) + { + InitObjs( *pLowerFrm ); + + pLowerFrm = pLowerFrm->GetNext(); + } + } + } + // <-- + + void FormatSectionToPositionObjs() + { + // perform extra format for multi-columned section. + if ( mpSectFrm->Lower() && mpSectFrm->Lower()->IsColumnFrm() && + mpSectFrm->Lower()->GetNext() ) + { + // grow section till bottom of printing area of upper frame + SWRECTFN( mpSectFrm ); + SwTwips nTopMargin = (mpSectFrm->*fnRect->fnGetTopMargin)(); + Size aOldSectPrtSize( mpSectFrm->Prt().SSize() ); + SwTwips nDiff = (mpSectFrm->Frm().*fnRect->fnBottomDist)( + (mpSectFrm->GetUpper()->*fnRect->fnGetPrtBottom)() ); + (mpSectFrm->Frm().*fnRect->fnAddBottom)( nDiff ); + (mpSectFrm->*fnRect->fnSetYMargins)( nTopMargin, 0 ); + // --> OD 2006-05-08 #i59789# + // suppress formatting, if printing area of section is too narrow + if ( (mpSectFrm->Prt().*fnRect->fnGetHeight)() <= 0 ) + { + return; + } + // <-- + mpSectFrm->ChgLowersProp( aOldSectPrtSize ); + + // format column frames and its body and footnote container + SwColumnFrm* pColFrm = static_cast<SwColumnFrm*>(mpSectFrm->Lower()); + while ( pColFrm ) + { + pColFrm->Calc(); + pColFrm->Lower()->Calc(); + if ( pColFrm->Lower()->GetNext() ) + { + pColFrm->Lower()->GetNext()->Calc(); + } + + pColFrm = static_cast<SwColumnFrm*>(pColFrm->GetNext()); + } + + // unlock position of lower floating screen objects for the extra format + // --> OD 2008-06-20 #i81555# + // Section frame can already have changed the page and its content + // can still be on the former page. + // Thus, initialize objects via lower-relationship + InitObjs( *mpSectFrm ); + // <-- + + // format content - first with collecting its foot-/endnotes before content + // format, second without collecting its foot-/endnotes. + ::CalcCntnt( mpSectFrm ); + ::CalcCntnt( mpSectFrm, true ); + + // keep locked position of lower floating screen objects + SwPageFrm* pPageFrm = mpSectFrm->FindPageFrm(); + SwSortedObjs* pObjs = pPageFrm ? pPageFrm->GetSortedObjs() : 0L; + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( i = 0; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + + if ( mpSectFrm->IsAnLower( pAnchoredObj->GetAnchorFrm() ) ) + { + pAnchoredObj->SetKeepPosLocked( true ); + } + } + } + + mbExtraFormatPerformed = true; + } + } +}; + +/************************************************************************* +|* +|* SwSectionFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea. +|* +|*************************************************************************/ + +void SwSectionFrm::Format( const SwBorderAttrs *pAttr ) +{ + if( !pSection ) // Durch DelEmpty + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( getRootFrm()->IsInDelList( this ), "SectionFrm without Section" ); +#endif + bValidSize = bValidPos = bValidPrtArea = sal_True; + return; + } + SWRECTFN( this ) + if ( !bValidPrtArea ) + { + PROTOCOL( this, PROT_PRTAREA, 0, 0 ) + bValidPrtArea = sal_True; + SwTwips nUpper = CalcUpperSpace(); + + // #109700# LRSpace for sections + const SvxLRSpaceItem& rLRSpace = GetFmt()->GetLRSpace(); + (this->*fnRect->fnSetXMargins)( rLRSpace.GetLeft(), rLRSpace.GetRight() ); + + if( nUpper != (this->*fnRect->fnGetTopMargin)() ) + { + bValidSize = sal_False; + SwFrm* pOwn = ContainsAny(); + if( pOwn ) + pOwn->_InvalidatePos(); + } + (this->*fnRect->fnSetYMargins)( nUpper, 0 ); + } + + if ( !bValidSize ) + { + PROTOCOL_ENTER( this, PROT_SIZE, 0, 0 ) + const long nOldHeight = (Frm().*fnRect->fnGetHeight)(); + sal_Bool bOldLock = IsColLocked(); + ColLock(); + + bValidSize = sal_True; + + //die Groesse wird nur dann vom Inhalt bestimmt, wenn der SectFrm + //keinen Follow hat. Anderfalls fuellt er immer den Upper bis + //zur Unterkante aus. Fuer den Textfluss ist nicht er, sondern sein + //Inhalt selbst verantwortlich. + sal_Bool bMaximize = ToMaximize( sal_False ); + + // OD 2004-05-17 #i28701# - If the wrapping style has to be considered + // on object positioning, an extra formatting has to be performed + // to determine the correct positions the floating screen objects. + // --> OD 2005-01-11 #i40147# + // use new helper class <ExtraFormatToPositionObjs>. + // This class additionally keep the locked position of the objects + // and releases this position lock keeping on destruction. + ExtraFormatToPositionObjs aExtraFormatToPosObjs( *this ); + if ( !bMaximize && + GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) && + !GetFmt()->GetBalancedColumns().GetValue() ) + { + aExtraFormatToPosObjs.FormatSectionToPositionObjs(); + } + // <-- + + // Column widths have to be adjusted before calling _CheckClipping. + // _CheckClipping can cause the formatting of the lower frames + // which still have a width of 0. + const sal_Bool bHasColumns = Lower() && Lower()->IsColumnFrm(); + if ( bHasColumns && Lower()->GetNext() ) + AdjustColumns( 0, sal_False ); + + if( GetUpper() ) + { + long nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + (aFrm.*fnRect->fnSetWidth)( nWidth ); + + // #109700# LRSpace for sections + const SvxLRSpaceItem& rLRSpace = GetFmt()->GetLRSpace(); + (aPrt.*fnRect->fnSetWidth)( nWidth - rLRSpace.GetLeft() - + rLRSpace.GetRight() ); + + // OD 15.10.2002 #103517# - allow grow in online layout + // Thus, set <..IsBrowseMode()> as parameter <bGrow> on calling + // method <_CheckClipping(..)>. + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + _CheckClipping( pSh && pSh->GetViewOptions()->getBrowseMode(), bMaximize ); + bMaximize = ToMaximize( sal_False ); + bValidSize = sal_True; + } + + //Breite der Spalten pruefen und ggf. einstellen. + if ( bHasColumns && ! Lower()->GetNext() && bMaximize ) + ((SwColumnFrm*)Lower())->Lower()->Calc(); + + if ( !bMaximize ) + { + SwTwips nRemaining = (this->*fnRect->fnGetTopMargin)(); + SwFrm *pFrm = pLower; + if( pFrm ) + { + if( pFrm->IsColumnFrm() && pFrm->GetNext() ) + { + // --> OD 2006-05-08 #i61435# + // suppress formatting, if upper frame has height <= 0 + if ( (GetUpper()->Frm().*fnRect->fnGetHeight)() > 0 ) + { + FormatWidthCols( *pAttr, nRemaining, MINLAY ); + } + // <-- + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + while( HasFollow() && !GetFollow()->ContainsCntnt() && + !GetFollow()->ContainsAny( true ) ) + // <-- + { + SwFrm* pOld = GetFollow(); + GetFollow()->DelEmpty( sal_False ); + if( pOld == GetFollow() ) + break; + } + bMaximize = ToMaximize( sal_False ); + nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); + } + else + { + if( pFrm->IsColumnFrm() ) + { + pFrm->Calc(); + pFrm = ((SwColumnFrm*)pFrm)->Lower(); + pFrm->Calc(); + pFrm = ((SwLayoutFrm*)pFrm)->Lower(); + CalcFtnCntnt(); + } + // Wenn wir in einem spaltigen Rahmen stehen und dieser + // gerade im FormatWidthCols ein CalcCntnt ruft, muss + // unser Inhalt ggf. kalkuliert werden. + if( pFrm && !pFrm->IsValid() && IsInFly() && + FindFlyFrm()->IsColLocked() ) + ::CalcCntnt( this ); + nRemaining += InnerHeight(); + bMaximize = HasFollow(); + } + } + + SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining; + if( nDiff < 0) + { + SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + { + long nBottom = (Frm().*fnRect->fnGetBottom)(); + nBottom = (*fnRect->fnYInc)( nBottom, -nDiff ); + long nTmpDiff = (*fnRect->fnYDiff)( nBottom, nDeadLine ); + if( nTmpDiff > 0 ) + { + nTmpDiff = GetUpper()->Grow( nTmpDiff, sal_True ); + nDeadLine = (*fnRect->fnYInc)( nDeadLine, nTmpDiff ); + nTmpDiff = (*fnRect->fnYDiff)( nBottom, nDeadLine ); + if( nTmpDiff > 0 ) + nDiff += nTmpDiff; + if( nDiff > 0 ) + nDiff = 0; + } + } + } + if( nDiff ) + { + long nTmp = nRemaining - (Frm().*fnRect->fnGetHeight)(); + long nTop = (this->*fnRect->fnGetTopMargin)(); + (Frm().*fnRect->fnAddBottom)( nTmp ); + (this->*fnRect->fnSetYMargins)( nTop, 0 ); + InvalidateNextPos(); + if( pLower && ( !pLower->IsColumnFrm() || !pLower->GetNext() ) ) + { + // Wenn ein einspaltiger Bereich gerade den Platz geschaffen + // hat, den sich die "undersized" Absaetze gewuenscht haben, + // muessen diese invalidiert und kalkuliert werden, damit + // sie diesen ausfuellen. + pFrm = pLower; + if( pFrm->IsColumnFrm() ) + { + pFrm->_InvalidateSize(); + pFrm->_InvalidatePos(); + pFrm->Calc(); + pFrm = ((SwColumnFrm*)pFrm)->Lower(); + pFrm->Calc(); + pFrm = ((SwLayoutFrm*)pFrm)->Lower(); + CalcFtnCntnt(); + } + sal_Bool bUnderSz = sal_False; + while( pFrm ) + { + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() ) + { + pFrm->Prepare( PREP_ADJUST_FRM ); + bUnderSz = sal_True; + } + pFrm = pFrm->GetNext(); + } + if( bUnderSz && !IsCntntLocked() ) + ::CalcCntnt( this ); + } + } + } + + //Unterkante des Uppers nicht ueberschreiten. Fuer Sections mit + //Follows die Unterkante auch nicht unterschreiten. + if ( GetUpper() ) + _CheckClipping( sal_True, bMaximize ); + if( !bOldLock ) + ColUnlock(); + long nDiff = nOldHeight - (Frm().*fnRect->fnGetHeight)(); + if( nDiff > 0 ) + { + if( !GetNext() ) + SetRetouche(); // Dann muessen wir die Retusche selbst uebernehmen + if( GetUpper() && !GetUpper()->IsFooterFrm() ) + GetUpper()->Shrink( nDiff ); + } + if( IsUndersized() ) + bValidPrtArea = sal_True; + } +} + +/************************************************************************* +|* +|* SwFrm::GetNextSctLeaf() +|* +|* Beschreibung Liefert das naechste Layoutblatt in das der Frame +|* gemoved werden kann. +|* Neue Seiten werden nur dann erzeugt, wenn der Parameter sal_True ist. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetNextSctLeaf( MakePageType eMakePage ) +{ + //Achtung: Geschachtelte Bereiche werden zur Zeit nicht unterstuetzt. + + PROTOCOL_ENTER( this, PROT_LEAF, ACT_NEXT_SECT, GetUpper()->FindSctFrm() ) + + // Abkuerzungen fuer spaltige Bereiche, wenn wir noch nicht in der letzten Spalte sind. + // Koennen wir in die naechste Spalte des Bereichs rutschen? + if( IsColBodyFrm() && GetUpper()->GetNext() ) + return (SwLayoutFrm*)((SwLayoutFrm*)GetUpper()->GetNext())->Lower(); + if( GetUpper()->IsColBodyFrm() && GetUpper()->GetUpper()->GetNext() ) + return (SwLayoutFrm*)((SwLayoutFrm*)GetUpper()->GetUpper()->GetNext())->Lower(); + // Innerhalb von Bereichen in Tabellen oder Bereichen in Kopf/Fusszeilen kann + // nur ein Spaltenwechsel erfolgen, eine der oberen Abkuerzungen haette zuschlagen muessen + if( GetUpper()->IsInTab() || FindFooterOrHeader() ) + return 0; + +//MA 03. Feb. 99: Warum GetUpper()? Das knallt mit Buch.sgl weil im +//FlyAtCnt::MakeFlyPos ein Orient der SectionFrm ist und auf diesen ein +//GetLeaf gerufen wird. +// SwSectionFrm *pSect = GetUpper()->FindSctFrm(); + SwSectionFrm *pSect = FindSctFrm(); + sal_Bool bWrongPage = sal_False; + OSL_ENSURE( pSect, "GetNextSctLeaf: Missing SectionFrm" ); + + // Hier eine Abkuerzung fuer Bereiche mit Follows, + // dieser kann akzeptiert werden, wenn keine Spalten oder Seiten (ausser Dummyseiten) + // dazwischen liegen. + // Bei verketteten Rahmen und ind Fussnoten wuerde die Abkuerzung noch aufwendiger + if( pSect->HasFollow() && pSect->IsInDocBody() ) + { + if( pSect->GetFollow() == pSect->GetNext() ) + { + SwPageFrm *pPg = pSect->GetFollow()->FindPageFrm(); + if( WrongPageDesc( pPg ) ) + bWrongPage = sal_True; + else + return FIRSTLEAF( pSect->GetFollow() ); + } + else + { + SwFrm* pTmp; + if( !pSect->GetUpper()->IsColBodyFrm() || + 0 == ( pTmp = pSect->GetUpper()->GetUpper()->GetNext() ) ) + pTmp = pSect->FindPageFrm()->GetNext(); + if( pTmp ) // ist jetzt die naechste Spalte oder Seite + { + SwFrm* pTmpX = pTmp; + if( pTmp->IsPageFrm() && ((SwPageFrm*)pTmp)->IsEmptyPage() ) + pTmp = pTmp->GetNext(); // Dummyseiten ueberspringen + SwFrm *pUp = pSect->GetFollow()->GetUpper(); + // pUp wird die Spalte, wenn der Follow in einer "nicht ersten" Spalte + // liegt, ansonsten die Seite: + if( !pUp->IsColBodyFrm() || + !( pUp = pUp->GetUpper() )->GetPrev() ) + pUp = pUp->FindPageFrm(); + // Jetzt muessen pUp und pTmp die gleiche Seite/Spalte sein, + // sonst liegen Seiten oder Spalten zwischen Master und Follow. + if( pUp == pTmp || pUp->GetNext() == pTmpX ) + { + SwPageFrm* pNxtPg = pUp->IsPageFrm() ? + (SwPageFrm*)pUp : pUp->FindPageFrm(); + if( WrongPageDesc( pNxtPg ) ) + bWrongPage = sal_True; + else + return FIRSTLEAF( pSect->GetFollow() ); + } + } + } + } + + // Immer im gleichen Bereich landen: Body wieder in Body etc. + const sal_Bool bBody = IsInDocBody(); + const sal_Bool bFtnPage = FindPageFrm()->IsFtnPage(); + + SwLayoutFrm *pLayLeaf; + // Eine Abkuerzung fuer TabFrms, damit nicht alle Zellen abgehuehnert werden + if( bWrongPage ) + pLayLeaf = 0; + else if( IsTabFrm() ) + { + SwCntntFrm* pTmpCnt = ((SwTabFrm*)this)->FindLastCntnt(); + pLayLeaf = pTmpCnt ? pTmpCnt->GetUpper() : 0; + } + else + { + pLayLeaf = GetNextLayoutLeaf(); + if( IsColumnFrm() ) + { + while( pLayLeaf && ((SwColumnFrm*)this)->IsAnLower( pLayLeaf ) ) + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + } + } + + SwLayoutFrm *pOldLayLeaf = 0; //Damit bei neu erzeugten Seiten + //nicht wieder vom Anfang gesucht + //wird. + + while( sal_True ) + { + if( pLayLeaf ) + { + // Ein Layoutblatt wurde gefunden, mal sehen, ob er mich aufnehmen kann, + // ob hier ein weiterer SectionFrm eingefuegt werden kann + // oder ob wir weitersuchen muessen. + SwPageFrm* pNxtPg = pLayLeaf->FindPageFrm(); + if ( !bFtnPage && pNxtPg->IsFtnPage() ) + { //Wenn ich bei den Endnotenseiten angelangt bin hat sichs. + pLayLeaf = 0; + continue; + } + // Einmal InBody, immer InBody, nicht in Tabellen hinein + // und nicht in fremde Bereiche hinein + if ( (bBody && !pLayLeaf->IsInDocBody()) || + (IsInFtn() != pLayLeaf->IsInFtn() ) || + pLayLeaf->IsInTab() || + ( pLayLeaf->IsInSct() && ( !pSect->HasFollow() + || pSect->GetFollow() != pLayLeaf->FindSctFrm() ) ) ) + { + //Er will mich nicht; neuer Versuch, neues Glueck + pOldLayLeaf = pLayLeaf; + pLayLeaf = pLayLeaf->GetNextLayoutLeaf(); + continue; + } + if( WrongPageDesc( pNxtPg ) ) + { + if( bWrongPage ) + break; // there's a column between me and my right page + pLayLeaf = 0; + bWrongPage = sal_True; + pOldLayLeaf = 0; + continue; + } + } + //Es gibt keinen passenden weiteren LayoutFrm, also muss eine + //neue Seite her, allerdings nuetzen uns innerhalb eines Rahmens + //neue Seiten nichts. + else if( !pSect->IsInFly() && + ( eMakePage == MAKEPAGE_APPEND || eMakePage == MAKEPAGE_INSERT ) ) + { + InsertPage(pOldLayLeaf ? pOldLayLeaf->FindPageFrm() : FindPageFrm(), + sal_False ); + //und nochmal das ganze + pLayLeaf = pOldLayLeaf ? pOldLayLeaf : GetNextLayoutLeaf(); + continue; + } + break; + } + + if( pLayLeaf ) + { + // Das passende Layoutblatt haben wir gefunden, wenn es dort bereits einen + // Follow unseres Bereichs gibt, nehmen wir dessen erstes Layoutblatt, + // andernfalls wird es Zeit, einen Bereichsfollow zu erzeugen + SwSectionFrm* pNew; + + //Dies kann entfallen, wenn bei existierenden Follows bereits abgekuerzt wurde + SwFrm* pFirst = pLayLeaf->Lower(); + // Auch hier muessen zum Loeschen angemeldete SectionFrms ignoriert werden + while( pFirst && pFirst->IsSctFrm() && !((SwSectionFrm*)pFirst)->GetSection() ) + pFirst = pFirst->GetNext(); + if( pFirst && pFirst->IsSctFrm() && pSect->GetFollow() == pFirst ) + pNew = pSect->GetFollow(); + else if( MAKEPAGE_NOSECTION == eMakePage ) + return pLayLeaf; + else + { + pNew = new SwSectionFrm( *pSect, sal_False ); + pNew->InsertBefore( pLayLeaf, pLayLeaf->Lower() ); + pNew->Init(); + SWRECTFN( pNew ) + (pNew->*fnRect->fnMakePos)( pLayLeaf, NULL, sal_True ); + + // Wenn unser Bereichsframe einen Nachfolger hat, so muss dieser + // umgehaengt werden hinter den neuen Follow der Bereichsframes. + SwFrm* pTmp = pSect->GetNext(); + if( pTmp && pTmp != pSect->GetFollow() ) + { + SwFlowFrm* pNxt; + SwCntntFrm* pNxtCntnt = NULL; + if( pTmp->IsCntntFrm() ) + { + pNxt = (SwCntntFrm*)pTmp; + pNxtCntnt = (SwCntntFrm*)pTmp; + } + else + { + pNxtCntnt = ((SwLayoutFrm*)pTmp)->ContainsCntnt(); + if( pTmp->IsSctFrm() ) + pNxt = (SwSectionFrm*)pTmp; + else + { + OSL_ENSURE( pTmp->IsTabFrm(), "GetNextSctLeaf: Wrong Type" ); + pNxt = (SwTabFrm*)pTmp; + } + while( !pNxtCntnt && 0 != ( pTmp = pTmp->GetNext() ) ) + { + if( pTmp->IsCntntFrm() ) + pNxtCntnt = (SwCntntFrm*)pTmp; + else + pNxtCntnt = ((SwLayoutFrm*)pTmp)->ContainsCntnt(); + } + } + if( pNxtCntnt ) + { + SwFtnBossFrm* pOldBoss = pSect->FindFtnBossFrm( sal_True ); + if( pOldBoss == pNxtCntnt->FindFtnBossFrm( sal_True ) ) + { + SwSaveFtnHeight aHeight( pOldBoss, + pOldBoss->Frm().Top() + pOldBoss->Frm().Height() ); + pSect->GetUpper()->MoveLowerFtns( pNxtCntnt, pOldBoss, + pLayLeaf->FindFtnBossFrm( sal_True ), sal_False ); + } + } + ((SwFlowFrm*)pNxt)->MoveSubTree( pLayLeaf, pNew->GetNext() ); + } + if( pNew->GetFollow() ) + pNew->SimpleFormat(); + } + // Das gesuchte Layoutblatt ist jetzt das erste des ermittelten SctFrms: + pLayLeaf = FIRSTLEAF( pNew ); + } + return pLayLeaf; +} + +/************************************************************************* +|* +|* SwFrm::GetPrevSctLeaf() +|* +|* Beschreibung Liefert das vorhergehende LayoutBlatt in das der +|* Frame gemoved werden kann. +|* +|*************************************************************************/ + + +SwLayoutFrm *SwFrm::GetPrevSctLeaf( MakePageType ) +{ + PROTOCOL_ENTER( this, PROT_LEAF, ACT_PREV_SECT, GetUpper()->FindSctFrm() ) + + SwLayoutFrm* pCol; + // ColumnFrm beinhalten jetzt stets einen BodyFrm + if( IsColBodyFrm() ) + pCol = GetUpper(); + else if( GetUpper()->IsColBodyFrm() ) + pCol = GetUpper()->GetUpper(); + else + pCol = NULL; + sal_Bool bJump = sal_False; + if( pCol ) + { + if( pCol->GetPrev() ) + { + do + { + pCol = (SwLayoutFrm*)pCol->GetPrev(); + // Gibt es dort Inhalt? + if( ((SwLayoutFrm*)pCol->Lower())->Lower() ) + { + if( bJump ) // Haben wir eine leere Spalte uebersprungen? + SwFlowFrm::SetMoveBwdJump( sal_True ); + return (SwLayoutFrm*)pCol->Lower(); // Der Spaltenbody + } + bJump = sal_True; + } while( pCol->GetPrev() ); + + // Hier landen wir, wenn alle Spalten leer sind, + // pCol ist jetzt die erste Spalte, wir brauchen aber den Body: + pCol = (SwLayoutFrm*)pCol->Lower(); + } + else + pCol = NULL; + } + + if( bJump ) // Haben wir eine leere Spalte uebersprungen? + SwFlowFrm::SetMoveBwdJump( sal_True ); + + // Innerhalb von Bereichen in Tabellen oder Bereichen in Kopf/Fusszeilen kann + // nur ein Spaltenwechsel erfolgen, eine der oberen Abkuerzungen haette + // zuschlagen muessen, ebenso wenn der Bereich einen pPrev hat. + // Jetzt ziehen wir sogar eine leere Spalte in Betracht... + OSL_ENSURE( FindSctFrm(), "GetNextSctLeaf: Missing SectionFrm" ); + if( ( IsInTab() && !IsTabFrm() ) || FindFooterOrHeader() ) + return pCol; + + // === IMPORTANT === + // Precondition, which needs to be hold, is that the <this> frame can be + // inside a table, but then the found section frame <pSect> is also inside + // this table. + SwSectionFrm *pSect = FindSctFrm(); + + // --> OD 2009-01-16 #i95698# + // A table cell containing directly a section does not break - see lcl_FindSectionsInRow(..) + // Thus, a table inside a section, which is inside another table can only + // flow backward in the columns of its section. + // Note: The table cell, which contains the section, can not have a master table cell. + if ( IsTabFrm() && pSect->IsInTab() ) + { + return pCol; + } + // <-- + + { + SwFrm *pPrv; + if( 0 != ( pPrv = pSect->GetIndPrev() ) ) + { + // Herumlungernde, halbtote SectionFrms sollen uns nicht beirren + while( pPrv && pPrv->IsSctFrm() && !((SwSectionFrm*)pPrv)->GetSection() ) + pPrv = pPrv->GetPrev(); + if( pPrv ) + return pCol; + } + } + + const sal_Bool bBody = IsInDocBody(); + const sal_Bool bFly = IsInFly(); + + SwLayoutFrm *pLayLeaf = GetPrevLayoutLeaf(); + SwLayoutFrm *pPrevLeaf = 0; + + while ( pLayLeaf ) + { + //In Tabellen oder Bereiche geht's niemals hinein. + if ( pLayLeaf->IsInTab() || pLayLeaf->IsInSct() ) + { + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + } + else if ( bBody && pLayLeaf->IsInDocBody() ) + { + // If there is a pLayLeaf has a lower pLayLeaf is the frame we are looking for. + // Exception: pLayLeaf->Lower() is a zombie section frame + const SwFrm* pTmp = pLayLeaf->Lower(); + // OD 11.04.2003 #108824# - consider, that the zombie section frame + // can have frame below it in the found layout leaf. + // Thus, skipping zombie section frame, if possible. + while ( pTmp && pTmp->IsSctFrm() && + !( static_cast<const SwSectionFrm*>(pTmp)->GetSection() ) && + pTmp->GetNext() + ) + { + pTmp = pTmp->GetNext(); + } + if ( pTmp && + ( !pTmp->IsSctFrm() || + ( static_cast<const SwSectionFrm*>(pTmp)->GetSection() ) + ) + ) + { + break; + } + pPrevLeaf = pLayLeaf; + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + if ( pLayLeaf ) + SwFlowFrm::SetMoveBwdJump( sal_True ); + } + else if ( bFly ) + break; //Cntnts in Flys sollte jedes Layout-Blatt recht sein. Warum? + else + pLayLeaf = pLayLeaf->GetPrevLayoutLeaf(); + } + if( !pLayLeaf ) + { + if( !pPrevLeaf ) + return pCol; + pLayLeaf = pPrevLeaf; + } + + SwSectionFrm* pNew = NULL; + // Zunaechst einmal an das Ende des Layoutblatts gehen + SwFrm *pTmp = pLayLeaf->Lower(); + if( pTmp ) + { + while( pTmp->GetNext() ) + pTmp = pTmp->GetNext(); + if( pTmp->IsSctFrm() ) + { + // Halbtote stoeren hier nur... + while( !((SwSectionFrm*)pTmp)->GetSection() && pTmp->GetPrev() && + pTmp->GetPrev()->IsSctFrm() ) + pTmp = pTmp->GetPrev(); + if( ((SwSectionFrm*)pTmp)->GetFollow() == pSect ) + pNew = (SwSectionFrm*)pTmp; + } + } + if( !pNew ) + { + pNew = new SwSectionFrm( *pSect, sal_True ); + pNew->InsertBefore( pLayLeaf, NULL ); + pNew->Init(); + SWRECTFN( pNew ) + (pNew->*fnRect->fnMakePos)( pLayLeaf, pNew->GetPrev(), sal_True ); + + pLayLeaf = FIRSTLEAF( pNew ); + if( !pNew->Lower() ) // einspaltige Bereiche formatieren + { + pNew->MakePos(); + pLayLeaf->Format(); // damit die PrtArea fuers MoveBwd stimmt + } + else + pNew->SimpleFormat(); + } + else + { + pLayLeaf = FIRSTLEAF( pNew ); + if( pLayLeaf->IsColBodyFrm() ) + { + // In existent section columns we're looking for the last not empty + // column. + SwLayoutFrm *pTmpLay = pLayLeaf; + while( pLayLeaf->GetUpper()->GetNext() ) + { + pLayLeaf = (SwLayoutFrm*)((SwLayoutFrm*)pLayLeaf->GetUpper()->GetNext())->Lower(); + if( pLayLeaf->Lower() ) + pTmpLay = pLayLeaf; + } + // If we skipped an empty column, we've to set the jump-flag + if( pLayLeaf != pTmpLay ) + { + pLayLeaf = pTmpLay; + SwFlowFrm::SetMoveBwdJump( sal_True ); + } + } + } + return pLayLeaf; +} + +SwTwips lcl_DeadLine( const SwFrm* pFrm ) +{ + const SwLayoutFrm* pUp = pFrm->GetUpper(); + while( pUp && pUp->IsInSct() ) + { + if( pUp->IsSctFrm() ) + pUp = pUp->GetUpper(); + // Spalten jetzt mit BodyFrm + else if( pUp->IsColBodyFrm() && pUp->GetUpper()->GetUpper()->IsSctFrm() ) + pUp = pUp->GetUpper()->GetUpper(); + else + break; + } + SWRECTFN( pFrm ) + return pUp ? (pUp->*fnRect->fnGetPrtBottom)() : + (pFrm->Frm().*fnRect->fnGetBottom)(); +} + +// SwSectionFrm::Growable(..) prueft, ob der SectionFrm noch wachsen kann, +// ggf. muss die Umgebung gefragt werden + +sal_Bool SwSectionFrm::Growable() const +{ + SWRECTFN( this ) + if( (*fnRect->fnYDiff)( lcl_DeadLine( this ), + (Frm().*fnRect->fnGetBottom)() ) > 0 ) + return sal_True; + + return ( GetUpper() && ((SwFrm*)GetUpper())->Grow( LONG_MAX, sal_True ) ); +} + +/************************************************************************* +|* +|* SwSectionFrm::_Grow(), _Shrink() +|* +|*************************************************************************/ + +SwTwips SwSectionFrm::_Grow( SwTwips nDist, sal_Bool bTst ) +{ + if ( !IsColLocked() && !HasFixSize() ) + { + SWRECTFN( this ) + long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if( nFrmHeight > 0 && nDist > (LONG_MAX - nFrmHeight) ) + nDist = LONG_MAX - nFrmHeight; + + if ( nDist <= 0L ) + return 0L; + + sal_Bool bInCalcCntnt = GetUpper() && IsInFly() && FindFlyFrm()->IsLocked(); + // OD 2004-03-15 #116561# - allow grow in online layout + sal_Bool bGrow = !Lower() || !Lower()->IsColumnFrm() || !Lower()->GetNext() || + GetSection()->GetFmt()->GetBalancedColumns().GetValue(); + if( !bGrow ) + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + bGrow = pSh && pSh->GetViewOptions()->getBrowseMode(); + } + if( bGrow ) + { + SwTwips nGrow; + if( IsInFtn() ) + nGrow = 0; + else + { + nGrow = lcl_DeadLine( this ); + nGrow = (*fnRect->fnYDiff)( nGrow, + (Frm().*fnRect->fnGetBottom)() ); + } + SwTwips nSpace = nGrow; + if( !bInCalcCntnt && nGrow < nDist && GetUpper() ) + nGrow += GetUpper()->Grow( LONG_MAX, sal_True ); + + if( nGrow > nDist ) + nGrow = nDist; + if( nGrow <= 0 ) + { + nGrow = 0; + if( nDist && !bTst ) + { + if( bInCalcCntnt ) + _InvalidateSize(); + else + InvalidateSize(); + } + } + else if( !bTst ) + { + if( bInCalcCntnt ) + _InvalidateSize(); + else if( nSpace < nGrow && nDist != nSpace + GetUpper()-> + Grow( nGrow - nSpace, sal_False ) ) + InvalidateSize(); + else + { + const SvxGraphicPosition ePos = + GetAttrSet()->GetBackground().GetGraphicPos(); + if ( GPOS_RT < ePos && GPOS_TILED != ePos ) + { + SetCompletePaint(); + InvalidatePage(); + } + if( GetUpper() && GetUpper()->IsHeaderFrm() ) + GetUpper()->InvalidateSize(); + } + (Frm().*fnRect->fnAddBottom)( nGrow ); + long nPrtHeight = (Prt().*fnRect->fnGetHeight)() + nGrow; + (Prt().*fnRect->fnSetHeight)( nPrtHeight ); + + if( Lower() && Lower()->IsColumnFrm() && Lower()->GetNext() ) + { + SwFrm* pTmp = Lower(); + do + { + pTmp->_InvalidateSize(); + pTmp = pTmp->GetNext(); + } while ( pTmp ); + _InvalidateSize(); + } + if( GetNext() ) + { + SwFrm *pFrm = GetNext(); + while( pFrm && pFrm->IsSctFrm() && !((SwSectionFrm*)pFrm)->GetSection() ) + pFrm = pFrm->GetNext(); + if( pFrm ) + { + if( bInCalcCntnt ) + pFrm->_InvalidatePos(); + else + pFrm->InvalidatePos(); + } + } + // --> OD 2004-07-05 #i28701# - Due to the new object positioning + // the frame on the next page/column can flow backward (e.g. it + // was moved forward due to the positioning of its objects ). + // Thus, invalivate this next frame, if document compatibility + // option 'Consider wrapping style influence on object positioning' is ON. + else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + InvalidateNextPos(); + } + // <-- + } + return nGrow; + } + if ( !bTst ) + { + if( bInCalcCntnt ) + _InvalidateSize(); + else + InvalidateSize(); + } + } + return 0L; +} + +SwTwips SwSectionFrm::_Shrink( SwTwips nDist, sal_Bool bTst ) +{ + if ( Lower() && !IsColLocked() && !HasFixSize() ) + { + if( ToMaximize( sal_False ) ) + { + if( !bTst ) + InvalidateSize(); + } + else + { + SWRECTFN( this ) + long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if ( nDist > nFrmHeight ) + nDist = nFrmHeight; + + if ( Lower()->IsColumnFrm() && Lower()->GetNext() && // FtnAtEnd + !GetSection()->GetFmt()->GetBalancedColumns().GetValue() ) + { //Bei Spaltigkeit ubernimmt das Format die Kontrolle ueber + //das Wachstum (wg. des Ausgleichs). + if ( !bTst ) + InvalidateSize(); + return nDist; + } + else if( !bTst ) + { + const SvxGraphicPosition ePos = + GetAttrSet()->GetBackground().GetGraphicPos(); + if ( GPOS_RT < ePos && GPOS_TILED != ePos ) + { + SetCompletePaint(); + InvalidatePage(); + } + (Frm().*fnRect->fnAddBottom)( -nDist ); + long nPrtHeight = (Prt().*fnRect->fnGetHeight)() - nDist; + (Prt().*fnRect->fnSetHeight)( nPrtHeight ); + + // We do not allow a section frame to shrink the its upper + // footer frame. This is because in the calculation of a + // footer frame, the content of the section frame is _not_ + // calculated. If there is a fly frame overlapping with the + // footer frame, the section frame is not affected by this + // during the calculation of the footer frame size. + // The footer frame does not grow in its FormatSize function + // but during the calculation of the content of the section + // frame. The section frame grows until some of its text is + // located on top of the fly frame. The next call of CalcCntnt + // tries to shrink the section and here it would also shrink + // the footer. This may not happen, because shrinking the footer + // would cause the top of the section frame to overlap with the + // fly frame again, this would result in a perfect loop. + if( GetUpper() && !GetUpper()->IsFooterFrm() ) + GetUpper()->Shrink( nDist, bTst ); + + if( Lower() && Lower()->IsColumnFrm() && Lower()->GetNext() ) + { + SwFrm* pTmp = Lower(); + do + { + pTmp->_InvalidateSize(); + pTmp = pTmp->GetNext(); + } while ( pTmp ); + } + if( GetNext() ) + { + SwFrm* pFrm = GetNext(); + while( pFrm && pFrm->IsSctFrm() && !((SwSectionFrm*)pFrm)->GetSection() ) + pFrm = pFrm->GetNext(); + if( pFrm ) + pFrm->InvalidatePos(); + else + SetRetouche(); + } + else + SetRetouche(); + return nDist; + } + } + } + return 0L; +} + +/************************************************************************* +|* +|* SwSectionFrm::MoveAllowed() +|* +|* Wann sind Frms innerhalb eines SectionFrms moveable? +|* Wenn sie noch nicht in der letzten Spalte des SectionFrms sind, +|* wenn es einen Follow gibt, +|* wenn der SectionFrm nicht mehr wachsen kann, wird es komplizierter, +|* dann kommt es darauf an, ob der SectionFrm ein naechstes Layoutblatt +|* finden kann. In (spaltigen/verketteten) Flys wird dies via GetNextLayout +|* geprueft, in Tabellen und in Kopf/Fusszeilen gibt es keins, im DocBody +|* und auch im Fussnoten dagegen immer. +|* +|* Benutzt wird diese Routine im TxtFormatter, um zu entscheiden, ob ein +|* (Absatz-)Follow erzeugt werden darf oder ob der Absatz zusammenhalten muss. +|* +|*************************************************************************/ + +sal_Bool SwSectionFrm::MoveAllowed( const SwFrm* pFrm) const +{ + // Gibt es einen Follow oder ist der Frame nicht in der letzten Spalte? + if( HasFollow() || ( pFrm->GetUpper()->IsColBodyFrm() && + pFrm->GetUpper()->GetUpper()->GetNext() ) ) + return sal_True; + if( pFrm->IsInFtn() ) + { + if( IsInFtn() ) + { + if( GetUpper()->IsInSct() ) + { + if( Growable() ) + return sal_False; + return GetUpper()->FindSctFrm()->MoveAllowed( this ); + } + else + return sal_True; + } + // The content of footnote inside a columned sectionfrm is moveable + // except in the last column + const SwLayoutFrm *pLay = pFrm->FindFtnFrm()->GetUpper()->GetUpper(); + if( pLay->IsColumnFrm() && pLay->GetNext() ) + { + // The first paragraph in the first footnote in the first column + // in the sectionfrm at the top of the page is not moveable, + // if the columnbody is empty. + sal_Bool bRet = sal_False; + if( pLay->GetIndPrev() || pFrm->GetIndPrev() || + pFrm->FindFtnFrm()->GetPrev() ) + bRet = sal_True; + else + { + SwLayoutFrm* pBody = ((SwColumnFrm*)pLay)->FindBodyCont(); + if( pBody && pBody->Lower() ) + bRet = sal_True; + } + if( bRet && ( IsFtnAtEnd() || !Growable() ) ) + return sal_True; + } + } + // Oder kann der Bereich noch wachsen? + if( !IsColLocked() && Growable() ) + return sal_False; + // Jetzt muss untersucht werden, ob es ein Layoutblatt gibt, in dem + // ein Bereichsfollow erzeugt werden kann. + if( IsInTab() || ( !IsInDocBody() && FindFooterOrHeader() ) ) + return sal_False; // In Tabellen/Kopf/Fusszeilen geht es nicht + if( IsInFly() ) // Bei spaltigen oder verketteten Rahmen + return 0 != ((SwFrm*)GetUpper())->GetNextLeaf( MAKEPAGE_NONE ); + return sal_True; +} + +/** Called for a frame inside a section with no direct previous frame (or only + previous empty section frames) the previous frame of the outer section is + returned, if the frame is the first flowing content of this section. + + Note: For a frame inside a table frame, which is inside a section frame, + NULL is returned. +*/ +SwFrm* SwFrm::_GetIndPrev() const +{ + SwFrm *pRet = NULL; + // --> OD 2007-09-04 #i79774#, #b659654# + // Do not assert, if the frame has a direct previous frame, because it + // could be an empty section frame. The caller has to assure, that the + // frame has no direct previous frame or only empty section frames as + // previous frames. + OSL_ENSURE( /*!pPrev &&*/ IsInSct(), "Why?" ); + // <-- + const SwFrm* pSct = GetUpper(); + if( !pSct ) + return NULL; + if( pSct->IsSctFrm() ) + pRet = pSct->GetIndPrev(); + else if( pSct->IsColBodyFrm() && (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() ) + { + // Do not return the previous frame of the outer section, if in one + // of the previous columns is content. + const SwFrm* pCol = GetUpper()->GetUpper()->GetPrev(); + while( pCol ) + { + OSL_ENSURE( pCol->IsColumnFrm(), "GetIndPrev(): ColumnFrm expected" ); + OSL_ENSURE( pCol->GetLower() && pCol->GetLower()->IsBodyFrm(), + "GetIndPrev(): Where's the body?"); + if( ((SwLayoutFrm*)((SwLayoutFrm*)pCol)->Lower())->Lower() ) + return NULL; + pCol = pCol->GetPrev(); + } + pRet = pSct->GetIndPrev(); + } + + // skip empty section frames + while( pRet && pRet->IsSctFrm() && !((SwSectionFrm*)pRet)->GetSection() ) + pRet = pRet->GetIndPrev(); + return pRet; +} + +SwFrm* SwFrm::_GetIndNext() +{ + OSL_ENSURE( !pNext && IsInSct(), "Why?" ); + SwFrm* pSct = GetUpper(); + if( !pSct ) + return NULL; + if( pSct->IsSctFrm() ) + return pSct->GetIndNext(); + if( pSct->IsColBodyFrm() && (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() ) + { // Wir duerfen nur den Nachfolger des SectionFrms zurueckliefern, + // wenn in keiner folgenden Spalte mehr Inhalt ist + SwFrm* pCol = GetUpper()->GetUpper()->GetNext(); + while( pCol ) + { + OSL_ENSURE( pCol->IsColumnFrm(), "GetIndNext(): ColumnFrm expected" ); + OSL_ENSURE( pCol->GetLower() && pCol->GetLower()->IsBodyFrm(), + "GetIndNext(): Where's the body?"); + if( ((SwLayoutFrm*)((SwLayoutFrm*)pCol)->Lower())->Lower() ) + return NULL; + pCol = pCol->GetNext(); + } + return pSct->GetIndNext(); + } + return NULL; +} + +sal_Bool SwSectionFrm::IsDescendantFrom( const SwSectionFmt* pFmt ) const +{ + if( !pSection || !pFmt ) + return sal_False; + const SwSectionFmt *pMyFmt = pSection->GetFmt(); + while( pFmt != pMyFmt ) + { + if( pMyFmt->GetRegisteredIn()->ISA( SwSectionFmt ) ) + pMyFmt = (SwSectionFmt*)pMyFmt->GetRegisteredIn(); + else + return sal_False; + } + return sal_True; +} + +void SwSectionFrm::CalcFtnAtEndFlag() +{ + SwSectionFmt *pFmt = GetSection()->GetFmt(); + sal_uInt16 nVal = pFmt->GetFtnAtTxtEnd( sal_False ).GetValue(); + bFtnAtEnd = FTNEND_ATPGORDOCEND != nVal; + bOwnFtnNum = FTNEND_ATTXTEND_OWNNUMSEQ == nVal || + FTNEND_ATTXTEND_OWNNUMANDFMT == nVal; + while( !bFtnAtEnd && !bOwnFtnNum ) + { + if( pFmt->GetRegisteredIn()->ISA( SwSectionFmt ) ) + pFmt = (SwSectionFmt*)pFmt->GetRegisteredIn(); + else + break; + nVal = pFmt->GetFtnAtTxtEnd( sal_False ).GetValue(); + if( FTNEND_ATPGORDOCEND != nVal ) + { + bFtnAtEnd = sal_True; + bOwnFtnNum = bOwnFtnNum ||FTNEND_ATTXTEND_OWNNUMSEQ == nVal || + FTNEND_ATTXTEND_OWNNUMANDFMT == nVal; + } + } +} + +sal_Bool SwSectionFrm::IsEndnoteAtMyEnd() const +{ + return pSection->GetFmt()->GetEndAtTxtEnd( sal_False ).IsAtEnd(); +} + +void SwSectionFrm::CalcEndAtEndFlag() +{ + SwSectionFmt *pFmt = GetSection()->GetFmt(); + bEndnAtEnd = pFmt->GetEndAtTxtEnd( sal_False ).IsAtEnd(); + while( !bEndnAtEnd ) + { + if( pFmt->GetRegisteredIn()->ISA( SwSectionFmt ) ) + pFmt = (SwSectionFmt*)pFmt->GetRegisteredIn(); + else + break; + bEndnAtEnd = pFmt->GetEndAtTxtEnd( sal_False ).IsAtEnd(); + } +} + +/************************************************************************* +|* +|* SwSectionFrm::Modify() +|* +|*************************************************************************/ + +void SwSectionFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + + if( pNew && RES_ATTRSET_CHG == pNew->Which() ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + if ( nInvFlags & 0x01 ) + InvalidateSize(); + if ( nInvFlags & 0x10 ) + SetCompletePaint(); + } +} + +void SwSectionFrm::SwClientNotify( const SwModify& rMod, const SfxHint& rHint ) +{ + const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint); + if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING && &rMod == GetRegisteredIn() ) + { + SwSectionFrm::MoveCntntAndDelete( this, sal_True ); + } +} + +void SwSectionFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { // Mehrspaltigkeit in Fussnoten unterdruecken... + case RES_FMT_CHG: + { + const SwFmtCol& rNewCol = GetFmt()->GetCol(); + if( !IsInFtn() ) + { + //Dummer Fall. Bei der Zuweisung einer Vorlage k?nnen wir uns + //nicht auf das alte Spaltenattribut verlassen. Da diese + //wenigstens anzahlgemass fuer ChgColumns vorliegen muessen, + //bleibt uns nur einen temporaeres Attribut zu basteln. + SwFmtCol aCol; + if ( Lower() && Lower()->IsColumnFrm() ) + { + sal_uInt16 nCol = 0; + SwFrm *pTmp = Lower(); + do + { ++nCol; + pTmp = pTmp->GetNext(); + } while ( pTmp ); + aCol.Init( nCol, 0, 1000 ); + } + sal_Bool bChgFtn = IsFtnAtEnd(); + sal_Bool bChgEndn = IsEndnAtEnd(); + sal_Bool bChgMyEndn = IsEndnoteAtMyEnd(); + CalcFtnAtEndFlag(); + CalcEndAtEndFlag(); + bChgFtn = ( bChgFtn != IsFtnAtEnd() ) || + ( bChgEndn != IsEndnAtEnd() ) || + ( bChgMyEndn != IsEndnoteAtMyEnd() ); + ChgColumns( aCol, rNewCol, bChgFtn ); + rInvFlags |= 0x10; + } + rInvFlags |= 0x01; + bClear = sal_False; + } + break; + + case RES_COL: + if( !IsInFtn() ) + { + ChgColumns( *(const SwFmtCol*)pOld, *(const SwFmtCol*)pNew ); + rInvFlags |= 0x11; + } + break; + + case RES_FTN_AT_TXTEND: + if( !IsInFtn() ) + { + sal_Bool bOld = IsFtnAtEnd(); + CalcFtnAtEndFlag(); + if( bOld != IsFtnAtEnd() ) + { + const SwFmtCol& rNewCol = GetFmt()->GetCol(); + ChgColumns( rNewCol, rNewCol, sal_True ); + rInvFlags |= 0x01; + } + } + break; + + case RES_END_AT_TXTEND: + if( !IsInFtn() ) + { + sal_Bool bOld = IsEndnAtEnd(); + sal_Bool bMyOld = IsEndnoteAtMyEnd(); + CalcEndAtEndFlag(); + if( bOld != IsEndnAtEnd() || bMyOld != IsEndnoteAtMyEnd()) + { + const SwFmtCol& rNewCol = GetFmt()->GetCol(); + ChgColumns( rNewCol, rNewCol, sal_True ); + rInvFlags |= 0x01; + } + } + break; + case RES_COLUMNBALANCE: + rInvFlags |= 0x01; + break; + + case RES_FRAMEDIR : + SetDerivedR2L( sal_False ); + CheckDirChange(); + break; + + case RES_PROTECT: + { + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetLayout()->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this ); + } + break; + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrm::Modify( pOld, pNew ); + } +} + +/*-------------------------------------------------- + * SwSectionFrm::ToMaximize(..): A follow or a ftncontainer at the end of the + * page causes a maximal Size of the sectionframe. + * --------------------------------------------------*/ + +sal_Bool SwSectionFrm::ToMaximize( sal_Bool bCheckFollow ) const +{ + if( HasFollow() ) + { + if( !bCheckFollow ) // Don't check superfluous follows + return sal_True; + const SwSectionFrm* pFoll = GetFollow(); + while( pFoll && pFoll->IsSuperfluous() ) + pFoll = pFoll->GetFollow(); + if( pFoll ) + return sal_True; + } + if( IsFtnAtEnd() ) + return sal_False; + const SwFtnContFrm* pCont = ContainsFtnCont(); + if( !IsEndnAtEnd() ) + return 0 != pCont; + sal_Bool bRet = sal_False; + while( pCont && !bRet ) + { + if( pCont->FindFootNote() ) + bRet = sal_True; + else + pCont = ContainsFtnCont( pCont ); + } + return bRet; +} + +/*-------------------------------------------------- + * sal_Bool SwSectionFrm::ContainsFtnCont() + * checks every Column for FtnContFrms. + * --------------------------------------------------*/ + +SwFtnContFrm* SwSectionFrm::ContainsFtnCont( const SwFtnContFrm* pCont ) const +{ + SwFtnContFrm* pRet = NULL; + const SwLayoutFrm* pLay; + if( pCont ) + { + pLay = pCont->FindFtnBossFrm( 0 ); + OSL_ENSURE( IsAnLower( pLay ), "ConatainsFtnCont: Wrong FtnContainer" ); + pLay = (SwLayoutFrm*)pLay->GetNext(); + } + else if( Lower() && Lower()->IsColumnFrm() ) + pLay = (SwLayoutFrm*)Lower(); + else + pLay = NULL; + while ( !pRet && pLay ) + { + if( pLay->Lower() && pLay->Lower()->GetNext() ) + { + OSL_ENSURE( pLay->Lower()->GetNext()->IsFtnContFrm(), + "ToMaximize: Unexspected Frame" ); + pRet = (SwFtnContFrm*)pLay->Lower()->GetNext(); + } + OSL_ENSURE( !pLay->GetNext() || pLay->GetNext()->IsLayoutFrm(), + "ToMaximize: ColFrm exspected" ); + pLay = (SwLayoutFrm*)pLay->GetNext(); + } + return pRet; +} + +void SwSectionFrm::InvalidateFtnPos() +{ + SwFtnContFrm* pCont = ContainsFtnCont( NULL ); + if( pCont ) + { + SwFrm *pTmp = pCont->ContainsCntnt(); + if( pTmp ) + pTmp->_InvalidatePos(); + } +} + +/*-------------------------------------------------- + * SwSectionFrm::Undersize() liefert den Betrag, um den der Bereich gern + * groesser waere, wenn in ihm Undersized TxtFrms liegen, ansonsten Null. + * Das Undersized-Flag wird ggf. korrigiert. + * --------------------------------------------------*/ + +long SwSectionFrm::Undersize( sal_Bool bOverSize ) +{ + bUndersized = sal_False; + SWRECTFN( this ) + long nRet = InnerHeight() - (Prt().*fnRect->fnGetHeight)(); + if( nRet > 0 ) + bUndersized = sal_True; + else if( !bOverSize ) + nRet = 0; + return nRet; +} + +/// OD 01.04.2003 #108446# - determine next frame for footnote/endnote formatting +/// before format of current one, because current one can move backward. +/// After moving backward to a previous page method <FindNext()> will return +/// the text frame presenting the first page footnote, if it exists. Thus, the +/// rest of the footnote/endnote container would not be formatted. +void SwSectionFrm::CalcFtnCntnt() +{ + SwFtnContFrm* pCont = ContainsFtnCont(); + if( pCont ) + { + SwFrm* pFrm = pCont->ContainsAny(); + if( pFrm ) + pCont->Calc(); + while( pFrm && IsAnLower( pFrm ) ) + { + SwFtnFrm* pFtn = pFrm->FindFtnFrm(); + if( pFtn ) + pFtn->Calc(); + // OD 01.04.2003 #108446# - determine next frame before format current frame. + SwFrm* pNextFrm = 0; + { + if( pFrm->IsSctFrm() ) + { + pNextFrm = static_cast<SwSectionFrm*>(pFrm)->ContainsAny(); + } + if( !pNextFrm ) + { + pNextFrm = pFrm->FindNext(); + } + } + pFrm->Calc(); + pFrm = pNextFrm; + } + } +} + +/* -------------------------------------------------- + * Wenn ein SectionFrm leerlaeuft, z.B. weil sein Inhalt die Seite/Spalte wechselt, + * so wird er nicht sofort zerstoert (es koennte noch jemand auf dem Stack einen Pointer + * auf ihn halten), sondern er traegt sich in eine Liste am RootFrm ein, die spaeter + * abgearbeitet wird (in LayAction::Action u.a.). Seine Groesse wird auf Null gesetzt und + * sein Zeiger auf seine Section ebenfalls. Solche zum Loeschen vorgesehene SectionFrms + * muessen vom Layout/beim Formatieren ignoriert werden. + * + * Mit InsertEmptySct nimmt der RootFrm einen SectionFrm in die Liste auf, + * mit RemoveFromList kann ein SectionFrm wieder aus der Liste entfernt werden (Dtor), + * mit DeleteEmptySct wird die Liste abgearbeitet und die SectionFrms zerstoert + * --------------------------------------------------*/ + +void SwRootFrm::InsertEmptySct( SwSectionFrm* pDel ) +{ + if( !pDestroy ) + pDestroy = new SwDestroyList; + sal_uInt16 nPos; + if( !pDestroy->Seek_Entry( pDel, &nPos ) ) + pDestroy->Insert( pDel ); +} + +void SwRootFrm::_DeleteEmptySct() +{ + OSL_ENSURE( pDestroy, "Keine Liste, keine Kekse" ); + while( pDestroy->Count() ) + { + SwSectionFrm* pSect = (*pDestroy)[0]; + pDestroy->Remove( sal_uInt16(0) ); + OSL_ENSURE( !pSect->IsColLocked() && !pSect->IsJoinLocked(), + "DeleteEmptySct: Locked SectionFrm" ); + if( !pSect->Frm().HasArea() && !pSect->ContainsCntnt() ) + { + SwLayoutFrm* pUp = pSect->GetUpper(); + pSect->Remove(); + delete pSect; + if( pUp && !pUp->Lower() ) + { + if( pUp->IsPageBodyFrm() ) + pUp->getRootFrm()->SetSuperfluous(); + else if( pUp->IsFtnFrm() && !pUp->IsColLocked() && + pUp->GetUpper() ) + { + pUp->Cut(); + delete pUp; + } + } + } + else { + OSL_ENSURE( pSect->GetSection(), "DeleteEmptySct: Halbtoter SectionFrm?!" ); + } + } +} + +void SwRootFrm::_RemoveFromList( SwSectionFrm* pSct ) +{ + OSL_ENSURE( pDestroy, "Where's my list?" ); + sal_uInt16 nPos; + if( pDestroy->Seek_Entry( pSct, &nPos ) ) + pDestroy->Remove( nPos ); +} + +#if OSL_DEBUG_LEVEL > 1 + +sal_Bool SwRootFrm::IsInDelList( SwSectionFrm* pSct ) const +{ + sal_uInt16 nPos; + return ( pDestroy && pDestroy->Seek_Entry( pSct, &nPos ) ); +} + +#endif + +bool SwSectionFrm::IsBalancedSection() const +{ + bool bRet = false; + if ( GetSection() && Lower() && Lower()->IsColumnFrm() && Lower()->GetNext() ) + { + bRet = !GetSection()->GetFmt()->GetBalancedColumns().GetValue(); + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/softpagebreak.cxx b/sw/source/core/layout/softpagebreak.cxx new file mode 100644 index 000000000000..c27bd3753637 --- /dev/null +++ b/sw/source/core/layout/softpagebreak.cxx @@ -0,0 +1,157 @@ +/* -*- 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 "ndtxt.hxx" +#include "txtfrm.hxx" +#include "pagefrm.hxx" +#include "swtable.hxx" +#include "frmfmt.hxx" +#include "rowfrm.hxx" +#include "tabfrm.hxx" +#include "switerator.hxx" + +void SwTxtNode::fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const +{ + SwIterator<SwTxtFrm,SwTxtNode> aIter( *this ); + for( const SwTxtFrm *pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) + { + // No soft page break in header or footer + if( pFrm->FindFooterOrHeader() || pFrm->IsInFly() ) + return; + // No soft page break if I'm not the first frame in my layout frame + if( pFrm->GetIndPrev() ) + continue; + const SwPageFrm* pPage = pFrm->FindPageFrm(); + // No soft page break at the first page + if( pPage && pPage->GetPrev() ) + { + const SwCntntFrm* pFirst2 = pPage->FindFirstBodyCntnt(); + // Special handling for content frame in table frames + if( pFrm->IsInTab() ) + { + // No soft page break if I'm in a table but the first content frame + // at my page is not in a table + if( !pFirst2->IsInTab() ) + continue; + const SwLayoutFrm *pRow = pFrm->GetUpper(); + // Looking for the "most upper" row frame, + // skipping sub tables and/or table in table + while( !pRow->IsRowFrm() || !pRow->GetUpper()->IsTabFrm() || + pRow->GetUpper()->GetUpper()->IsInTab() ) + pRow = pRow->GetUpper(); + const SwTabFrm *pTab = pRow->FindTabFrm(); + // For master tables the soft page break will exported at the table row, + // not at the content frame. + // If the first content is outside my table frame, no soft page break. + if( !pTab->IsFollow() || !pTab->IsAnLower( pFirst2 ) ) + continue; + // Only content of non-heading-rows can get a soft page break + const SwFrm* pFirstRow = pTab->GetFirstNonHeadlineRow(); + // If there's no follow flow line, the soft page break will be + // exported at the row, not at the content. + if( pRow == pFirstRow && + pTab->FindMaster( false )->HasFollowFlowLine() ) + { + // Now we have the row which causes a new page, + // this row is a follow flow line and therefor cannot get + // the soft page break itself. + // Every first content frame of every cell frane in this row + // will get the soft page break + const SwFrm* pCell = pRow->Lower(); + while( pCell ) + { + pFirst2 = static_cast<const SwLayoutFrm*>(pCell)->ContainsCntnt(); + if( pFirst2 == pFrm ) + { // Here we are: a first content inside a cell + // inside the splitted row => soft page break + rBreak.insert( pFrm->GetOfst() ); + break; + } + pCell = pCell->GetNext(); + } + } + } + else // No soft page break if there's a "hard" page break attribute + if( pFirst2 == pFrm && !pFrm->IsPageBreak( sal_True ) ) + rBreak.insert( pFrm->GetOfst() ); + } + } +} + +bool SwTableLine::hasSoftPageBreak() const +{ + // No soft page break for sub tables + if( GetUpper() || !GetFrmFmt() ) + return false; + SwIterator<SwRowFrm,SwFmt> aIter( *GetFrmFmt() ); + for( SwRowFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + { + if( pLast->GetTabLine() == this ) + { + const SwTabFrm* pTab = pLast->FindTabFrm(); + // No soft page break for + // tables with prevs, i.e. if the frame is not the first in its layout frame + // tables in footer or header + // tables in flies + // inner tables of nested tables + // master table frames with "hard" page break attribute + if( pTab->GetIndPrev() || pTab->FindFooterOrHeader() + || pTab->IsInFly() || pTab->GetUpper()->IsInTab() || + ( !pTab->IsFollow() && pTab->IsPageBreak( sal_True ) ) ) + return false; + const SwPageFrm* pPage = pTab->FindPageFrm(); + // No soft page break at the first page of the document + if( pPage && !pPage->GetPrev() ) + return false; + const SwCntntFrm* pFirst = pPage->FindFirstBodyCntnt(); + // No soft page break for + // tables which does not contain the first body content of the page + if( !pFirst || !pTab->IsAnLower( pFirst->FindTabFrm() ) ) + return false; + // The row which could get a soft page break must be either the first + // row of a master table frame or the first "non-headline-row" of a + // follow table frame... + const SwFrm* pRow = pTab->IsFollow() ? + pTab->GetFirstNonHeadlineRow() : pTab->Lower(); + if( pRow == pLast ) + { + // The last check: no soft page break for "follow" table lines + if( pTab->IsFollow() && pTab->FindMaster( false )->HasFollowFlowLine() ) + return false; + return true; + } + return false; + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/sortedobjs.cxx b/sw/source/core/layout/sortedobjs.cxx new file mode 100644 index 000000000000..e984d278f4e7 --- /dev/null +++ b/sw/source/core/layout/sortedobjs.cxx @@ -0,0 +1,79 @@ +/* -*- 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 <sortedobjs.hxx> +#include <sortedobjsimpl.hxx> + +SwSortedObjs::SwSortedObjs() + : mpImpl( new SwSortedObjsImpl ) +{ +} + +SwSortedObjs::~SwSortedObjs() +{ + delete mpImpl; +} + +sal_uInt32 SwSortedObjs::Count() const +{ + return mpImpl->Count(); +} + +SwAnchoredObject* SwSortedObjs::operator[]( sal_uInt32 _nIndex ) const +{ + return (*mpImpl)[ _nIndex ]; +} + +bool SwSortedObjs::Insert( SwAnchoredObject& _rAnchoredObj ) +{ + return mpImpl->Insert( _rAnchoredObj ); +} + +bool SwSortedObjs::Remove( SwAnchoredObject& _rAnchoredObj ) +{ + return mpImpl->Remove( _rAnchoredObj ); +} + +bool SwSortedObjs::Contains( const SwAnchoredObject& _rAnchoredObj ) const +{ + return mpImpl->Contains( _rAnchoredObj ); +} + +bool SwSortedObjs::Update( SwAnchoredObject& _rAnchoredObj ) +{ + return mpImpl->Update( _rAnchoredObj ); +} + +sal_uInt32 SwSortedObjs::ListPosOf( const SwAnchoredObject& _rAnchoredObj ) const +{ + return mpImpl->ListPosOf( _rAnchoredObj ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/sortedobjsimpl.cxx b/sw/source/core/layout/sortedobjsimpl.cxx new file mode 100644 index 000000000000..dc81c71f0355 --- /dev/null +++ b/sw/source/core/layout/sortedobjsimpl.cxx @@ -0,0 +1,312 @@ +/* -*- 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 <sortedobjsimpl.hxx> + +#include <algorithm> +#include <anchoredobject.hxx> +#include <frmfmt.hxx> +#include <svx/svdobj.hxx> +#include <pam.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <fmtsrnd.hxx> +#include <fmtwrapinfluenceonobjpos.hxx> +#include <IDocumentDrawModelAccess.hxx> + + +using namespace ::com::sun::star; + +typedef std::vector< SwAnchoredObject* >::iterator tIter; +typedef std::vector< SwAnchoredObject* >::const_iterator tConstIter; + + +SwSortedObjsImpl::SwSortedObjsImpl() +{ +} + +SwSortedObjsImpl::~SwSortedObjsImpl() +{ +} + +sal_uInt32 SwSortedObjsImpl::Count() const +{ + return maSortedObjLst.size(); +} + +SwAnchoredObject* SwSortedObjsImpl::operator[]( sal_uInt32 _nIndex ) +{ + SwAnchoredObject* pAnchoredObj = 0L; + + if ( _nIndex >= Count() ) + { + OSL_FAIL( "<SwSortedObjsImpl::operator[]> - index out of range" ); + } + else + { + pAnchoredObj = maSortedObjLst[ _nIndex ]; + } + + return pAnchoredObj; +} + +struct ObjAnchorOrder +{ + bool operator()( const SwAnchoredObject* _pListedAnchoredObj, + const SwAnchoredObject* _pNewAnchoredObj ) + { + // get attributes of listed object + const SwFrmFmt& rFmtListed = _pListedAnchoredObj->GetFrmFmt(); + const SwFmtAnchor* pAnchorListed = &(rFmtListed.GetAnchor()); + + // get attributes of new object + const SwFrmFmt& rFmtNew = _pNewAnchoredObj->GetFrmFmt(); + const SwFmtAnchor* pAnchorNew = &(rFmtNew.GetAnchor()); + + // check for to-page anchored objects + if ((pAnchorListed->GetAnchorId() == FLY_AT_PAGE) && + (pAnchorNew ->GetAnchorId() != FLY_AT_PAGE)) + { + return true; + } + else if ((pAnchorListed->GetAnchorId() != FLY_AT_PAGE) && + (pAnchorNew ->GetAnchorId() == FLY_AT_PAGE)) + { + return false; + } + else if ((pAnchorListed->GetAnchorId() == FLY_AT_PAGE) && + (pAnchorNew ->GetAnchorId() == FLY_AT_PAGE)) + { + return pAnchorListed->GetOrder() < pAnchorNew->GetOrder(); + } + + // Both objects aren't anchored to page. + // Thus, check for to-fly anchored objects + if ((pAnchorListed->GetAnchorId() == FLY_AT_FLY) && + (pAnchorNew ->GetAnchorId() != FLY_AT_FLY)) + { + return true; + } + else if ((pAnchorListed->GetAnchorId() != FLY_AT_FLY) && + (pAnchorNew ->GetAnchorId() == FLY_AT_FLY)) + { + return false; + } + else if ((pAnchorListed->GetAnchorId() == FLY_AT_FLY) && + (pAnchorNew ->GetAnchorId() == FLY_AT_FLY)) + { + return pAnchorListed->GetOrder() < pAnchorNew->GetOrder(); + } + + // Both objects aren't anchor to page or to fly + // Thus, compare content anchor nodes, if existing. + const SwPosition* pCntntAnchorListed = pAnchorListed->GetCntntAnchor(); + const SwPosition* pCntntAnchorNew = pAnchorNew->GetCntntAnchor(); + if ( pCntntAnchorListed && pCntntAnchorNew && + pCntntAnchorListed->nNode != pCntntAnchorNew->nNode ) + { + return pCntntAnchorListed->nNode < pCntntAnchorNew->nNode; + } + + // objects anchored at the same content. + // --> OD 2006-11-29 #???# - objects have to be ordered by anchor node position + // Thus, compare content anchor node positions and anchor type, + // if not anchored at-paragraph + if ((pAnchorListed->GetAnchorId() != FLY_AT_PARA) && + (pAnchorNew ->GetAnchorId() != FLY_AT_PARA) && + pCntntAnchorListed && pCntntAnchorNew ) + { + if ( pCntntAnchorListed->nContent != pCntntAnchorNew->nContent ) + { + return pCntntAnchorListed->nContent < pCntntAnchorNew->nContent; + } + else if ((pAnchorListed->GetAnchorId() == FLY_AT_CHAR) && + (pAnchorNew ->GetAnchorId() == FLY_AS_CHAR)) + { + return true; + } + else if ((pAnchorListed->GetAnchorId() == FLY_AS_CHAR) && + (pAnchorNew ->GetAnchorId() == FLY_AT_CHAR)) + { + return false; + } + } + // <-- + + // objects anchored at the same content and at the same content anchor + // node position with the same anchor type + // Thus, compare its wrapping style including its layer + const IDocumentDrawModelAccess* pIDDMA = rFmtListed.getIDocumentDrawModelAccess(); + const SdrLayerID nHellId = pIDDMA->GetHellId(); + const SdrLayerID nInvisibleHellId = pIDDMA->GetInvisibleHellId(); + const bool bWrapThroughOrHellListed = + rFmtListed.GetSurround().GetSurround() == SURROUND_THROUGHT || + _pListedAnchoredObj->GetDrawObj()->GetLayer() == nHellId || + _pListedAnchoredObj->GetDrawObj()->GetLayer() == nInvisibleHellId; + const bool bWrapThroughOrHellNew = + rFmtNew.GetSurround().GetSurround() == SURROUND_THROUGHT || + _pNewAnchoredObj->GetDrawObj()->GetLayer() == nHellId || + _pNewAnchoredObj->GetDrawObj()->GetLayer() == nInvisibleHellId; + if ( bWrapThroughOrHellListed != bWrapThroughOrHellNew ) + { + if ( bWrapThroughOrHellListed ) + return false; + else + return true; + } + else if ( bWrapThroughOrHellListed && bWrapThroughOrHellNew ) + { + return pAnchorListed->GetOrder() < pAnchorNew->GetOrder(); + } + + // objects anchored at the same content with a set text wrapping + // Thus, compare wrap influences on object position + const SwFmtWrapInfluenceOnObjPos* pWrapInfluenceOnObjPosListed = + &(rFmtListed.GetWrapInfluenceOnObjPos()); + const SwFmtWrapInfluenceOnObjPos* pWrapInfluenceOnObjPosNew = + &(rFmtNew.GetWrapInfluenceOnObjPos()); + // --> OD 2004-10-18 #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE + if ( pWrapInfluenceOnObjPosListed->GetWrapInfluenceOnObjPos( true ) != + pWrapInfluenceOnObjPosNew->GetWrapInfluenceOnObjPos( true ) ) + // <-- + { + // --> OD 2004-10-18 #i35017# - constant name has changed + if ( pWrapInfluenceOnObjPosListed->GetWrapInfluenceOnObjPos( true ) + == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) + // <-- + return true; + else + return false; + } + + // objects anchored at the same content position/page/fly with same + // wrap influence. + // Thus, compare anchor order number + return pAnchorListed->GetOrder() < pAnchorNew->GetOrder(); + } +}; + +bool SwSortedObjsImpl::Insert( SwAnchoredObject& _rAnchoredObj ) +{ + // --> OD 2005-08-18 #i51941# + if ( Contains( _rAnchoredObj ) ) + { + // list already contains object +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "<SwSortedObjsImpl::Insert()> - already contains object" ); +#endif + return true; + } + + // find insert position + tIter aInsPosIter = std::lower_bound( maSortedObjLst.begin(), + maSortedObjLst.end(), + &_rAnchoredObj, ObjAnchorOrder() ); + + // insert object into list + maSortedObjLst.insert( aInsPosIter, &_rAnchoredObj ); + + return Contains( _rAnchoredObj ); +} + +bool SwSortedObjsImpl::Remove( SwAnchoredObject& _rAnchoredObj ) +{ + bool bRet = true; + + tIter aDelPosIter = std::find( maSortedObjLst.begin(), + maSortedObjLst.end(), + &_rAnchoredObj ); + + if ( aDelPosIter == maSortedObjLst.end() ) + { + // object not found. + bRet = false; +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "<SwSortedObjsImpl::Remove()> - object not found" ); +#endif + } + else + { + maSortedObjLst.erase( aDelPosIter ); + } + + return bRet; +} + +bool SwSortedObjsImpl::Contains( const SwAnchoredObject& _rAnchoredObj ) const +{ + tConstIter aIter = std::find( maSortedObjLst.begin(), maSortedObjLst.end(), + &_rAnchoredObj ); + + return aIter != maSortedObjLst.end(); +} + +bool SwSortedObjsImpl::Update( SwAnchoredObject& _rAnchoredObj ) +{ + if ( !Contains( _rAnchoredObj ) ) + { + // given anchored object not found in list + OSL_FAIL( "<SwSortedObjsImpl::Update(..) - sorted list doesn't contain given anchored object" ); + return false; + } + + if ( Count() == 1 ) + { + // given anchored object is the only one in the list. + return true; + } + + Remove( _rAnchoredObj ); + Insert( _rAnchoredObj ); + + return Contains( _rAnchoredObj ); +} + +sal_uInt32 SwSortedObjsImpl::ListPosOf( const SwAnchoredObject& _rAnchoredObj ) const +{ + sal_uInt32 nRetLstPos = Count(); + + tConstIter aIter = std::find( maSortedObjLst.begin(), maSortedObjLst.end(), + &_rAnchoredObj ); + + if ( aIter != maSortedObjLst.end() ) + { + // --> OD 2005-08-18 #i51941# +// nRetLstPos = aIter - maSortedObjLst.begin(); + std::vector< SwAnchoredObject* >::difference_type nPos = + aIter - maSortedObjLst.begin(); + nRetLstPos = sal_uInt32( nPos ); + // <-- + } + + return nRetLstPos; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx new file mode 100644 index 000000000000..1bfaa40c7ae8 --- /dev/null +++ b/sw/source/core/layout/ssfrm.cxx @@ -0,0 +1,814 @@ +/* -*- 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 <ftnfrm.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <doc.hxx> +#include <node.hxx> +#include <dview.hxx> +#include <dcontact.hxx> +#include <dflyobj.hxx> +#include <flyfrm.hxx> +#include <txtfrm.hxx> // ClearPara() +#include <cellfrm.hxx> +#include <swtable.hxx> +#include <fmtfsize.hxx> +#include <ftnidx.hxx> +#include <txtftn.hxx> +#include <ndtxt.hxx> +#include <ndindex.hxx> +#include <frmtool.hxx> +#include <pagedesc.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/shaditem.hxx> +#include <fmtclds.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> +#include <sortedobjs.hxx> +#include <hints.hxx> +#include <switerator.hxx> + + // No inline cause we need the function pointers +long SwFrm::GetTopMargin() const + { return Prt().Top(); } +long SwFrm::GetBottomMargin() const + { return Frm().Height() -Prt().Height() -Prt().Top(); } +long SwFrm::GetLeftMargin() const + { return Prt().Left(); } +long SwFrm::GetRightMargin() const + { return Frm().Width() - Prt().Width() - Prt().Left(); } +long SwFrm::GetPrtLeft() const + { return Frm().Left() + Prt().Left(); } +long SwFrm::GetPrtBottom() const + { return Frm().Top() + Prt().Height() + Prt().Top(); } +long SwFrm::GetPrtRight() const + { return Frm().Left() + Prt().Width() + Prt().Left(); } +long SwFrm::GetPrtTop() const + { return Frm().Top() + Prt().Top(); } + +sal_Bool SwFrm::SetMinLeft( long nDeadline ) +{ + SwTwips nDiff = nDeadline - Frm().Left(); + if( nDiff > 0 ) + { + Frm().Left( nDeadline ); + Prt().Width( Prt().Width() - nDiff ); + return sal_True; + } + return sal_False; +} + +sal_Bool SwFrm::SetMaxBottom( long nDeadline ) +{ + SwTwips nDiff = Frm().Top() + Frm().Height() - nDeadline; + if( nDiff > 0 ) + { + Frm().Height( Frm().Height() - nDiff ); + Prt().Height( Prt().Height() - nDiff ); + return sal_True; + } + return sal_False; +} + +sal_Bool SwFrm::SetMinTop( long nDeadline ) +{ + SwTwips nDiff = nDeadline - Frm().Top(); + if( nDiff > 0 ) + { + Frm().Top( nDeadline ); + Prt().Height( Prt().Height() - nDiff ); + return sal_True; + } + return sal_False; +} + +sal_Bool SwFrm::SetMaxRight( long nDeadline ) +{ + SwTwips nDiff = Frm().Left() + Frm().Width() - nDeadline; + if( nDiff > 0 ) + { + Frm().Width( Frm().Width() - nDiff ); + Prt().Width( Prt().Width() - nDiff ); + return sal_True; + } + return sal_False; +} + +void SwFrm::MakeBelowPos( const SwFrm* pUp, const SwFrm* pPrv, sal_Bool bNotify ) +{ + if( pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + aFrm.Pos().Y() += pPrv->Frm().Height(); + } + else + { + aFrm.Pos( pUp->Frm().Pos() ); + aFrm.Pos() += pUp->Prt().Pos(); + } + if( bNotify ) + aFrm.Pos().Y() += 1; +} + +void SwFrm::MakeUpperPos( const SwFrm* pUp, const SwFrm* pPrv, sal_Bool bNotify ) +{ + if( pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + aFrm.Pos().Y() -= Frm().Height(); + } + else + { + aFrm.Pos( pUp->Frm().Pos() ); + aFrm.Pos() += pUp->Prt().Pos(); + aFrm.Pos().Y() += pUp->Prt().Height() - aFrm.Height(); + } + if( bNotify ) + aFrm.Pos().Y() -= 1; +} + +void SwFrm::MakeLeftPos( const SwFrm* pUp, const SwFrm* pPrv, sal_Bool bNotify ) +{ + if( pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + aFrm.Pos().X() -= Frm().Width(); + } + else + { + aFrm.Pos( pUp->Frm().Pos() ); + aFrm.Pos() += pUp->Prt().Pos(); + aFrm.Pos().X() += pUp->Prt().Width() - aFrm.Width(); + } + if( bNotify ) + aFrm.Pos().X() -= 1; +} + +void SwFrm::MakeRightPos( const SwFrm* pUp, const SwFrm* pPrv, sal_Bool bNotify ) +{ + if( pPrv ) + { + aFrm.Pos( pPrv->Frm().Pos() ); + aFrm.Pos().X() += pPrv->Frm().Width(); + } + else + { + aFrm.Pos( pUp->Frm().Pos() ); + aFrm.Pos() += pUp->Prt().Pos(); + } + if( bNotify ) + aFrm.Pos().X() += 1; +} + +void SwFrm::SetTopBottomMargins( long nTop, long nBot ) +{ + Prt().Top( nTop ); + Prt().Height( Frm().Height() - nTop - nBot ); +} + +void SwFrm::SetBottomTopMargins( long nBot, long nTop ) +{ + Prt().Top( nTop ); + Prt().Height( Frm().Height() - nTop - nBot ); +} + +void SwFrm::SetLeftRightMargins( long nLeft, long nRight) +{ + Prt().Left( nLeft ); + Prt().Width( Frm().Width() - nLeft - nRight ); +} + +void SwFrm::SetRightLeftMargins( long nRight, long nLeft) +{ + Prt().Left( nLeft ); + Prt().Width( Frm().Width() - nLeft - nRight ); +} + +const sal_uInt16 nMinVertCellHeight = 1135; + +/*-------------------------------------------------- + * SwFrm::CheckDirChange(..) + * checks the layout direction and + * invalidates the lower frames rekursivly, if necessary. + * --------------------------------------------------*/ + +void SwFrm::CheckDirChange() +{ + sal_Bool bOldVert = GetVerticalFlag(); + sal_Bool bOldRev = IsReverse(); + sal_Bool bOldR2L = GetRightToLeftFlag(); + SetInvalidVert( sal_True ); + SetInvalidR2L( sal_True ); + sal_Bool bChg = bOldR2L != IsRightToLeft(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + sal_Bool bOldVertL2R = IsVertLR(); + if( ( IsVertical() != bOldVert ) || bChg || IsReverse() != bOldRev || bOldVertL2R != IsVertLR() ) + { + InvalidateAll(); + if( IsLayoutFrm() ) + { + // set minimum row height for vertical cells in horizontal table: + if ( IsCellFrm() && GetUpper() ) + { + if ( IsVertical() != GetUpper()->IsVertical() && + ((SwCellFrm*)this)->GetTabBox()->getRowSpan() == 1 ) + { + SwTableLine* pLine = (SwTableLine*)((SwCellFrm*)this)->GetTabBox()->GetUpper(); + SwFrmFmt* pFrmFmt = pLine->GetFrmFmt(); + SwFmtFrmSize aNew( pFrmFmt->GetFrmSize() ); + if ( ATT_FIX_SIZE != aNew.GetHeightSizeType() ) + aNew.SetHeightSizeType( ATT_MIN_SIZE ); + if ( aNew.GetHeight() < nMinVertCellHeight ) + aNew.SetHeight( nMinVertCellHeight ); + SwDoc* pDoc = pFrmFmt->GetDoc(); + pDoc->SetAttr( aNew, *pLine->ClaimFrmFmt() ); + } + } + + SwFrm* pFrm = ((SwLayoutFrm*)this)->Lower(); + const SwFmtCol* pCol = NULL; + SwLayoutFrm* pBody = 0; + if( pFrm ) + { + if( IsPageFrm() ) + { + // If we're a page frame and we change our layout direction, + // we have to look for columns and rearrange them. + pBody = ((SwPageFrm*)this)->FindBodyCont(); + if(pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm()) + pCol = &((SwPageFrm*)this)->GetFmt()->GetCol(); + } + else if( pFrm->IsColumnFrm() ) + { + pBody = ((SwLayoutFrm*)this); + const SwFrmFmt *pFmt = pBody->GetFmt(); + if( pFmt ) + pCol = &pFmt->GetCol(); + } + } + while( pFrm ) + { + pFrm->CheckDirChange(); + pFrm = pFrm->GetNext(); + } + if( pCol ) + pBody->AdjustColumns( pCol, sal_True ); + } + else if( IsTxtFrm() ) + ((SwTxtFrm*)this)->Prepare( PREP_CLEAR ); + + // --> OD 2004-07-27 #i31698# - notify anchored objects also for page frames. + // Remove code above for special handling of page frames + if ( GetDrawObjs() ) + { + const SwSortedObjs *pObjs = GetDrawObjs(); + sal_uInt32 nCnt = pObjs->Count(); + for ( sal_uInt32 i = 0; i < nCnt; ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + if( pAnchoredObj->ISA(SwFlyFrm) ) + static_cast<SwFlyFrm*>(pAnchoredObj)->CheckDirChange(); + else + { + // OD 2004-04-06 #i26791# - direct object + // positioning no longer needed. Instead + // invalidate + pAnchoredObj->InvalidateObjPos(); + } + // --> OD 2004-07-27 #i31698# - update layout direction of + // anchored object + { + ::setContextWritingMode( pAnchoredObj->DrawObj(), pAnchoredObj->GetAnchorFrmContainingAnchPos() ); + pAnchoredObj->UpdateLayoutDir(); + } + // <-- + } + } + } +} + +/*-------------------------------------------------- + * SwFrm::GetFrmAnchorPos(..) + * returns the position for anchors based on frame direction + * --------------------------------------------------*/ +// OD 2004-03-10 #i11860# - consider lower space and line spacing of +// previous frame according to new option 'Use former object positioning' +Point SwFrm::GetFrmAnchorPos( sal_Bool bIgnoreFlysAnchoredAtThisFrame ) const +{ + Point aAnchor = Frm().Pos(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if ( ( IsVertical() && !IsVertLR() ) || IsRightToLeft() ) + aAnchor.X() += Frm().Width(); + + if ( IsTxtFrm() ) + { + SwTwips nBaseOfstForFly = + ((SwTxtFrm*)this)->GetBaseOfstForFly( bIgnoreFlysAnchoredAtThisFrame ); + if ( IsVertical() ) + aAnchor.Y() += nBaseOfstForFly; + else + aAnchor.X() += nBaseOfstForFly; + + // OD 2004-03-10 #i11860# - if option 'Use former object positioning' + // is OFF, consider the lower space and the line spacing of the + // previous frame and the spacing considered for the page grid + const SwTxtFrm* pThisTxtFrm = static_cast<const SwTxtFrm*>(this); + const SwTwips nUpperSpaceAmountConsideredForPrevFrmAndPageGrid = + pThisTxtFrm->GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + if ( IsVertical() ) + { + aAnchor.X() -= nUpperSpaceAmountConsideredForPrevFrmAndPageGrid; + } + else + { + aAnchor.Y() += nUpperSpaceAmountConsideredForPrevFrmAndPageGrid; + } + } + + return aAnchor; +} + + +/************************************************************************* +|* +|* SwFrm::~SwFrm() +|* +|*************************************************************************/ + +SwFrm::~SwFrm() +{ + // accessible objects for fly and cell frames have been already disposed + // by the destructors of the derived classes. + if( IsAccessibleFrm() && !(IsFlyFrm() || IsCellFrm()) && GetDep() ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell *pVSh = pRootFrm->GetCurrShell(); + if( pVSh && pVSh->Imp() ) + { + OSL_ENSURE( !GetLower(), "Lowers should be dispose already!" ); + pVSh->Imp()->DisposeAccessibleFrm( this ); + } + } + } + + if( pDrawObjs ) + { + for ( sal_uInt32 i = pDrawObjs->Count(); i; ) + { + SwAnchoredObject* pAnchoredObj = (*pDrawObjs)[--i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + delete pAnchoredObj; + else + { + SdrObject* pSdrObj = pAnchoredObj->DrawObj(); + SwDrawContact* pContact = + static_cast<SwDrawContact*>(pSdrObj->GetUserCall()); + OSL_ENSURE( pContact, + "<SwFrm::~SwFrm> - missing contact for drawing object" ); + if ( pContact ) + { + pContact->DisconnectObjFromLayout( pSdrObj ); + } + } + } + if ( pDrawObjs ) + delete pDrawObjs; + } + +#if OSL_DEBUG_LEVEL > 1 + // JP 15.10.2001: for detection of access to deleted frames + pDrawObjs = (SwSortedObjs*)0x33333333; +#endif +} + +/*************************************************************************/ + +const SwFrmFmt * SwLayoutFrm::GetFmt() const +{ + return static_cast< const SwFlyFrmFmt * >( GetDep() ); +} + +SwFrmFmt * SwLayoutFrm::GetFmt() +{ + return static_cast< SwFlyFrmFmt * >( GetDep() ); +} + + +/************************************************************************* +|* +|* SwLayoutFrm::SetFrmFmt() +|* +|*************************************************************************/ + + +void SwLayoutFrm::SetFrmFmt( SwFrmFmt *pNew ) +{ + if ( pNew != GetFmt() ) + { + SwFmtChg aOldFmt( GetFmt() ); + pNew->Add( this ); + SwFmtChg aNewFmt( pNew ); + ModifyNotification( &aOldFmt, &aNewFmt ); + } +} + +/************************************************************************* +|* SwCntntFrm::SwCntntFrm() +|*************************************************************************/ +SwCntntFrm::SwCntntFrm( SwCntntNode * const pCntnt, SwFrm* pSib ) : + SwFrm( pCntnt, pSib ), + SwFlowFrm( (SwFrm&)*this ) +{ +} + +/************************************************************************* +|* SwCntntFrm::~SwCntntFrm() +|*************************************************************************/ +SwCntntFrm::~SwCntntFrm() +{ + SwCntntNode* pCNd; + if( 0 != ( pCNd = PTR_CAST( SwCntntNode, GetRegisteredIn() )) && + !pCNd->GetDoc()->IsInDtor() ) + { + //Bei der Root abmelden wenn ich dort noch im Turbo stehe. + SwRootFrm *pRoot = getRootFrm(); + if( pRoot && pRoot->GetTurbo() == this ) + { + pRoot->DisallowTurbo(); + pRoot->ResetTurbo(); + } + if( IsTxtFrm() && ((SwTxtFrm*)this)->HasFtn() ) + { + SwTxtNode *pTxtNd = ((SwTxtFrm*)this)->GetTxtNode(); + const SwFtnIdxs &rFtnIdxs = pCNd->GetDoc()->GetFtnIdxs(); + sal_uInt16 nPos; + sal_uLong nIndex = pCNd->GetIndex(); + rFtnIdxs.SeekEntry( *pTxtNd, &nPos ); + SwTxtFtn* pTxtFtn; + if( nPos < rFtnIdxs.Count() ) + { + while( nPos && pTxtNd == &(rFtnIdxs[ nPos ]->GetTxtNode()) ) + --nPos; + if( nPos || pTxtNd != &(rFtnIdxs[ nPos ]->GetTxtNode()) ) + ++nPos; + } + while( nPos < rFtnIdxs.Count() ) + { + pTxtFtn = rFtnIdxs[ nPos ]; + if( pTxtFtn->GetTxtNode().GetIndex() > nIndex ) + break; + pTxtFtn->DelFrms( this ); + ++nPos; + } + } + } +} + +void SwCntntFrm::RegisterToNode( SwCntntNode& rNode ) +{ + rNode.Add( this ); +} + +void SwCntntFrm::DelFrms( const SwCntntNode& rNode ) +{ + SwIterator<SwCntntFrm,SwCntntNode> aIter( rNode ); + for( SwCntntFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) + { + // --> OD 2005-12-01 #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for current next paragraph will change + // and relation CONTENT_FLOWS_TO for current previous paragraph will change. + if ( pFrm->IsTxtFrm() ) + { + ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) ); + } + } + // <-- + if( pFrm->HasFollow() ) + pFrm->GetFollow()->_SetIsFollow( pFrm->IsFollow() ); + if( pFrm->IsFollow() ) + { + SwCntntFrm* pMaster = (SwTxtFrm*)pFrm->FindMaster(); + pMaster->SetFollow( pFrm->GetFollow() ); + pFrm->_SetIsFollow( sal_False ); + } + pFrm->SetFollow( 0 );//Damit er nicht auf dumme Gedanken kommt. + //Andernfalls kann es sein, dass ein Follow + //vor seinem Master zerstoert wird, der Master + //greift dann ueber den ungueltigen + //Follow-Pointer auf fremdes Memory zu. + //Die Kette darf hier zerknauscht werden, weil + //sowieso alle zerstoert werden. + if( pFrm->GetUpper() && pFrm->IsInFtn() && !pFrm->GetIndNext() && + !pFrm->GetIndPrev() ) + { + SwFtnFrm *pFtn = pFrm->FindFtnFrm(); + OSL_ENSURE( pFtn, "You promised a FtnFrm?" ); + SwCntntFrm* pCFrm; + if( !pFtn->GetFollow() && !pFtn->GetMaster() && + 0 != ( pCFrm = pFtn->GetRefFromAttr()) && pCFrm->IsFollow() ) + { + OSL_ENSURE( pCFrm->IsTxtFrm(), "NoTxtFrm has Footnote?" ); + ((SwTxtFrm*)pCFrm->FindMaster())->Prepare( PREP_FTN_GONE ); + } + } + pFrm->Cut(); + delete pFrm; + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::~SwLayoutFrm +|* +|*************************************************************************/ + + +SwLayoutFrm::~SwLayoutFrm() +{ + SwFrm *pFrm = pLower; + + if( GetFmt() && !GetFmt()->GetDoc()->IsInDtor() ) + { + while ( pFrm ) + { + //Erst die Objs des Frm vernichten, denn diese koennen sich sonst nach + //dem Remove nicht mehr bei der Seite abmelden. + //Falls sich einer nicht abmeldet wollen wir nicht gleich + //endlos schleifen. + + sal_uInt32 nCnt; + while ( pFrm->GetDrawObjs() && pFrm->GetDrawObjs()->Count() ) + { + nCnt = pFrm->GetDrawObjs()->Count(); + // --> OD 2004-06-30 #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[0]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + delete pAnchoredObj; + else + { + SdrObject* pSdrObj = pAnchoredObj->DrawObj(); + SwDrawContact* pContact = + static_cast<SwDrawContact*>(pSdrObj->GetUserCall()); + OSL_ENSURE( pContact, + "<SwFrm::~SwFrm> - missing contact for drawing object" ); + if ( pContact ) + { + pContact->DisconnectObjFromLayout( pSdrObj ); + } + } + if ( pFrm->GetDrawObjs() && + nCnt == pFrm->GetDrawObjs()->Count() ) + { + pFrm->GetDrawObjs()->Remove( *pAnchoredObj ); + } + // <-- + } + pFrm->Remove(); + delete pFrm; + pFrm = pLower; + } + //Fly's vernichten. Der letzte loescht gleich das Array. + sal_uInt32 nCnt; + while ( GetDrawObjs() && GetDrawObjs()->Count() ) + { + nCnt = GetDrawObjs()->Count(); + + // --> OD 2004-06-30 #i28701# + SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[0]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + delete pAnchoredObj; + else + { + SdrObject* pSdrObj = pAnchoredObj->DrawObj(); + SwDrawContact* pContact = + static_cast<SwDrawContact*>(pSdrObj->GetUserCall()); + OSL_ENSURE( pContact, + "<SwFrm::~SwFrm> - missing contact for drawing object" ); + if ( pContact ) + { + pContact->DisconnectObjFromLayout( pSdrObj ); + } + } + if ( GetDrawObjs() && nCnt == GetDrawObjs()->Count() ) + { + GetDrawObjs()->Remove( *pAnchoredObj ); + } + // <-- + } + } + else + { + while( pFrm ) + { + SwFrm *pNxt = pFrm->GetNext(); + delete pFrm; + pFrm = pNxt; + } + } +} + +/************************************************************************* +|* +|* SwFrm::PaintArea() +|* +|* The paintarea is the area, in which the content of a frame is allowed +|* to be displayed. This region could be larger than the printarea (Prt()) +|* of the upper, it includes e.g. often the margin of the page. +|* +|*************************************************************************/ + +const SwRect SwFrm::PaintArea() const +{ + // NEW TABLES + // Cell frames may not leave their upper: + SwRect aRect = IsRowFrm() ? GetUpper()->Frm() : Frm(); + const sal_Bool bVert = IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + long nRight = (aRect.*fnRect->fnGetRight)(); + long nLeft = (aRect.*fnRect->fnGetLeft)(); + const SwFrm* pTmp = this; + sal_Bool bLeft = sal_True; + sal_Bool bRight = sal_True; + long nRowSpan = 0; + while( pTmp ) + { + if( pTmp->IsCellFrm() && pTmp->GetUpper() && + pTmp->GetUpper()->IsVertical() != pTmp->IsVertical() ) + nRowSpan = ((SwCellFrm*)pTmp)->GetTabBox()->getRowSpan(); + long nTmpRight = (pTmp->Frm().*fnRect->fnGetRight)(); + long nTmpLeft = (pTmp->Frm().*fnRect->fnGetLeft)(); + if( pTmp->IsRowFrm() && nRowSpan > 1 ) + { + const SwFrm* pNxt = pTmp; + while( --nRowSpan > 0 && pNxt->GetNext() ) + pNxt = pNxt->GetNext(); + if( pTmp->IsVertical() ) + nTmpLeft = (pNxt->Frm().*fnRect->fnGetLeft)(); + else + nTmpRight = (pNxt->Frm().*fnRect->fnGetRight)(); + } + OSL_ENSURE( pTmp, "PaintArea lost in time and space" ); + if( pTmp->IsPageFrm() || pTmp->IsFlyFrm() || + pTmp->IsCellFrm() || pTmp->IsRowFrm() || //nobody leaves a table! + pTmp->IsRootFrm() ) + { + if( bLeft || nLeft < nTmpLeft ) + nLeft = nTmpLeft; + if( bRight || nTmpRight < nRight ) + nRight = nTmpRight; + if( pTmp->IsPageFrm() || pTmp->IsFlyFrm() || pTmp->IsRootFrm() ) + break; + bLeft = sal_False; + bRight = sal_False; + } + else if( pTmp->IsColumnFrm() ) // nobody enters neightbour columns + { + sal_Bool bR2L = pTmp->IsRightToLeft(); + // the first column has _no_ influence to the left range + if( bR2L ? pTmp->GetNext() : pTmp->GetPrev() ) + { + if( bLeft || nLeft < nTmpLeft ) + nLeft = nTmpLeft; + bLeft = sal_False; + } + // the last column has _no_ influence to the right range + if( bR2L ? pTmp->GetPrev() : pTmp->GetNext() ) + { + if( bRight || nTmpRight < nRight ) + nRight = nTmpRight; + bRight = sal_False; + } + } + else if( bVert && pTmp->IsBodyFrm() ) + { + // Header and footer frames have always horizontal direction and + // limit the body frame. + // A previous frame of a body frame must be a header, + // the next frame of a body frame may be a footnotecontainer or + // a footer. The footnotecontainer has the same direction like + // the body frame. + if( pTmp->GetPrev() && ( bLeft || nLeft < nTmpLeft ) ) + { + nLeft = nTmpLeft; + bLeft = sal_False; + } + if( pTmp->GetNext() && + ( pTmp->GetNext()->IsFooterFrm() || pTmp->GetNext()->GetNext() ) + && ( bRight || nTmpRight < nRight ) ) + { + nRight = nTmpRight; + bRight = sal_False; + } + } + pTmp = pTmp->GetUpper(); + } + (aRect.*fnRect->fnSetLeft)( nLeft ); + (aRect.*fnRect->fnSetRight)( nRight ); + return aRect; +} + +/************************************************************************* +|* +|* SwFrm::UnionFrm() +|* +|* The unionframe is the framearea (Frm()) of a frame expanded by the +|* printarea, if there's a negative margin at the left or right side. +|* +|*************************************************************************/ + +const SwRect SwFrm::UnionFrm( sal_Bool bBorder ) const +{ + sal_Bool bVert = IsVertical(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + long nLeft = (Frm().*fnRect->fnGetLeft)(); + long nWidth = (Frm().*fnRect->fnGetWidth)(); + long nPrtLeft = (Prt().*fnRect->fnGetLeft)(); + long nPrtWidth = (Prt().*fnRect->fnGetWidth)(); + if( nPrtLeft + nPrtWidth > nWidth ) + nWidth = nPrtLeft + nPrtWidth; + if( nPrtLeft < 0 ) + { + nLeft += nPrtLeft; + nWidth -= nPrtLeft; + } + SwTwips nRight = nLeft + nWidth; + long nAdd = 0; + if( bBorder ) + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + const SvxBoxItem &rBox = rAttrs.GetBox(); + if ( rBox.GetLeft() ) + nLeft -= rBox.CalcLineSpace( BOX_LINE_LEFT ); + else if ( rAttrs.IsBorderDist() ) + nLeft -= rBox.GetDistance( BOX_LINE_LEFT ) + 1; + if ( rBox.GetRight() ) + nAdd += rBox.CalcLineSpace( BOX_LINE_RIGHT ); + else if ( rAttrs.IsBorderDist() ) + nAdd += rBox.GetDistance( BOX_LINE_RIGHT ) + 1; + if( rAttrs.GetShadow().GetLocation() != SVX_SHADOW_NONE ) + { + const SvxShadowItem &rShadow = rAttrs.GetShadow(); + nLeft -= rShadow.CalcShadowSpace( SHADOW_LEFT ); + nAdd += rShadow.CalcShadowSpace( SHADOW_RIGHT ); + } + } + if( IsTxtFrm() && ((SwTxtFrm*)this)->HasPara() ) + { + long nTmp = ((SwTxtFrm*)this)->HangingMargin(); + if( nTmp > nAdd ) + nAdd = nTmp; + } + nWidth = nRight + nAdd - nLeft; + SwRect aRet( Frm() ); + (aRet.*fnRect->fnSetPosX)( nLeft ); + (aRet.*fnRect->fnSetWidth)( nWidth ); + return aRet; +} + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/swselectionlist.cxx b/sw/source/core/layout/swselectionlist.cxx new file mode 100644 index 000000000000..e2997db0a6bc --- /dev/null +++ b/sw/source/core/layout/swselectionlist.cxx @@ -0,0 +1,96 @@ +/* -*- 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 <swselectionlist.hxx> +#include <layfrm.hxx> +#include <flyfrm.hxx> +#include <ftnfrm.hxx> + +/** This class is used as parameter for functions to create a rectangular text selection +*/ + +namespace { + + /** Find the context of a given frame + + A context is the environment where text is allowed to flow. + The context is represented by + - the SwRootFrm if the frame is part of a page body + - the SwHeaderFrm if the frame is part of a page header + - the SwFooterFrm if the frame is part of a page footer + - the (master) SwFtnFrm if the frame is part of footnote + - the (first) SwFlyFrm if the frame is part of a (linked) fly frame + + @param pFrm + the given frame + + @return the context of the frame, represented by a SwFrm* + */ + const SwFrm* getContext( const SwFrm* pFrm ) + { + while( pFrm ) + { + if( pFrm->IsRootFrm() || pFrm->IsHeaderFrm() || pFrm->IsFooterFrm() ) + break; + if( pFrm->IsFlyFrm() ) + { + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>( pFrm ); + while( pFly->GetPrevLink() ) + pFly = pFly->GetPrevLink(); + break; + } + if( pFrm->IsFtnFrm() ) + { + const SwFtnFrm* pFtn = static_cast<const SwFtnFrm*>( pFrm ); + while( pFtn->GetMaster() ) + pFtn = pFtn->GetMaster(); + break; + } + pFrm = pFrm->GetUpper(); + } + return pFrm; + } +} + +SwSelectionList::SwSelectionList( const SwFrm* pInitCxt ) : + pContext( getContext( pInitCxt ) ) +{ +} + +bool SwSelectionList::checkContext( const SwFrm* pCheck ) +{ + pCheck = getContext( pCheck ); + if( !pContext ) + pContext = pCheck; + return pContext == pCheck; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx new file mode 100644 index 000000000000..08f756d65b87 --- /dev/null +++ b/sw/source/core/layout/tabfrm.cxx @@ -0,0 +1,5798 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include "pagefrm.hxx" +#include "rootfrm.hxx" +#include "cntfrm.hxx" +#include "viewsh.hxx" +#include "doc.hxx" +#include "docsh.hxx" +#include "viewimp.hxx" +#include "swtable.hxx" +#include "dflyobj.hxx" +#include "flyfrm.hxx" +#include "frmtool.hxx" +#include "frmfmt.hxx" +#include "dcontact.hxx" +#include <anchoreddrawobject.hxx> +#include <fmtanchr.hxx> +#include "viewopt.hxx" +#include "hints.hxx" +#include "dbg_lay.hxx" +#include <ftnidx.hxx> +#include <svl/itemiter.hxx> +#include <docary.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/boxitem.hxx> +#include <vcl/outdev.hxx> +#include <fmtlsplt.hxx> +#include <fmtrowsplt.hxx> +#include <fmtsrnd.hxx> +#include <fmtornt.hxx> +#include <fmtpdsc.hxx> +#include <fmtfsize.hxx> +#include <swtblfmt.hxx> +#include <ndtxt.hxx> +#include "tabfrm.hxx" +#include "rowfrm.hxx" +#include "cellfrm.hxx" +#include "flyfrms.hxx" +#include "txtfrm.hxx" //HasFtn() +#include "htmltbl.hxx" +#include "sectfrm.hxx" //SwSectionFrm +#include <fmtfollowtextflow.hxx> +#include <sortedobjs.hxx> +#include <objectformatter.hxx> +#include <layouter.hxx> +#include <switerator.hxx> + +extern void AppendObjs( const SwSpzFrmFmts *pTbl, sal_uLong nIndex, + SwFrm *pFrm, SwPageFrm *pPage ); + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwTabFrm::SwTabFrm(), ~SwTabFrm() +|* +|*************************************************************************/ +SwTabFrm::SwTabFrm( SwTable &rTab, SwFrm* pSib ): + SwLayoutFrm( rTab.GetFrmFmt(), pSib ), + SwFlowFrm( (SwFrm&)*this ), + pTable( &rTab ) +{ + bComplete = bCalcLowers = bONECalcLowers = bLowersFormatted = bLockBackMove = + bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = + bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; + // --> OD 2004-10-04 #i26945# + bConsiderObjsForMinCellHeight = sal_True; + bObjsDoesFit = sal_True; + // <-- + bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. + nType = FRMC_TAB; + + //Gleich die Zeilen erzeugen und einfuegen. + const SwTableLines &rLines = rTab.GetTabLines(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + SwRowFrm *pNew = new SwRowFrm( *rLines[i], this ); + if( pNew->Lower() ) + { + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } + else + delete pNew; + } + OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "SwTabFrm::SwTabFrm: No rows." ); +} + +SwTabFrm::SwTabFrm( SwTabFrm &rTab ) : + SwLayoutFrm( rTab.GetFmt(), &rTab ), + SwFlowFrm( (SwFrm&)*this ), + pTable( rTab.GetTable() ) +{ + bIsFollow = sal_True; + bLockJoin = bComplete = bONECalcLowers = bCalcLowers = bLowersFormatted = bLockBackMove = + bResizeHTMLTable = bHasFollowFlowLine = bIsRebuildLastLine = + bRestrictTableGrowth = bRemoveFollowFlowLinePending = sal_False; + // --> OD 2004-10-04 #i26945# + bConsiderObjsForMinCellHeight = sal_True; + bObjsDoesFit = sal_True; + // <-- + bFixSize = sal_False; //Nicht nochmal auf die Importfilter hereinfallen. + nType = FRMC_TAB; + + SetFollow( rTab.GetFollow() ); + rTab.SetFollow( this ); +} + +extern const SwTable *pColumnCacheLastTable; +extern const SwTabFrm *pColumnCacheLastTabFrm; +extern const SwFrm *pColumnCacheLastCellFrm; +extern const SwTable *pRowCacheLastTable; +extern const SwTabFrm *pRowCacheLastTabFrm; +extern const SwFrm *pRowCacheLastCellFrm; + +SwTabFrm::~SwTabFrm() +{ + // There is some terrible code in fetab.cxx, that + // makes use of these global pointers. Obviously + // this code did not consider that a TabFrm can be + // deleted. + if ( this == pColumnCacheLastTabFrm ) + { + pColumnCacheLastTable = NULL; + pColumnCacheLastTabFrm = NULL; + pColumnCacheLastCellFrm= NULL; + pRowCacheLastTable = NULL; + pRowCacheLastTabFrm = NULL; + pRowCacheLastCellFrm= NULL; + } +} + +/************************************************************************* +|* +|* SwTabFrm::JoinAndDelFollows() +|* +|*************************************************************************/ +void SwTabFrm::JoinAndDelFollows() +{ + SwTabFrm *pFoll = GetFollow(); + if ( pFoll->HasFollow() ) + pFoll->JoinAndDelFollows(); + pFoll->Cut(); + SetFollow( pFoll->GetFollow() ); + delete pFoll; +} + +/************************************************************************* +|* +|* SwTabFrm::RegistFlys() +|* +|*************************************************************************/ +void SwTabFrm::RegistFlys() +{ + OSL_ENSURE( Lower() && Lower()->IsRowFrm(), "Keine Zeilen." ); + + SwPageFrm *pPage = FindPageFrm(); + if ( pPage ) + { + SwRowFrm *pRow = (SwRowFrm*)Lower(); + do + { + pRow->RegistFlys( pPage ); + pRow = (SwRowFrm*)pRow->GetNext(); + } while ( pRow ); + } +} + +/************************************************************************* +|* Some prototypes +|*************************************************************************/ +void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ); +void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ); +sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ); +// --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control +// that only row and cell frames are formatted. +sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, + long nBottom, + bool _bOnlyRowsAndCells = false ); +// <-- +// OD 2004-02-18 #106629# - correct type of 1st parameter +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to +// control, if floating screen objects have to be considered for the minimal +// cell height. +SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm *pRow, + const sal_Bool _bConsiderObjs ); +// <-- +SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm&, const SwBorderAttrs& ); + +/************************************************************************* +|* START: local helper functions for repeated headlines +|*************************************************************************/ + +SwTwips lcl_GetHeightOfRows( const SwFrm* pStart, long nCount ) +{ + if ( !nCount || !pStart) + return 0; + + SwTwips nRet = 0; + SWRECTFN( pStart ) + while ( pStart && nCount > 0 ) + { + nRet += (pStart->Frm().*fnRect->fnGetHeight)(); + pStart = pStart->GetNext(); + --nCount; + } + + return nRet; +} + +/************************************************************************* +|* END: local helper functions for repeated headlines +|*************************************************************************/ + +/************************************************************************* +|* START: local helper functions for splitting row frames +|*************************************************************************/ + +// +// Local helper function to insert a new follow flow line +// +SwRowFrm* lcl_InsertNewFollowFlowLine( SwTabFrm& rTab, const SwFrm& rTmpRow, bool bRowSpanLine ) +{ + OSL_ENSURE( rTmpRow.IsRowFrm(), "No row frame to copy for FollowFlowLine" ); + const SwRowFrm& rRow = (SwRowFrm&)rTmpRow; + + rTab.SetFollowFlowLine( sal_True ); + SwRowFrm *pFollowFlowLine = new SwRowFrm(*rRow.GetTabLine(), &rTab, false ); + pFollowFlowLine->SetRowSpanLine( bRowSpanLine ); + SwFrm* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow(); + pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow ); + return pFollowFlowLine; +} + +// --> OD 2004-11-05 #i26945# - local helper function to invalidate all lower +// objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if +// additionally the objects are moved 'out of range'. +void lcl_InvalidateLowerObjs( SwLayoutFrm& _rLayoutFrm, + const bool _bMoveObjsOutOfRange = false, + SwPageFrm* _pPageFrm = 0L ) +{ + // determine page frame, if needed + if ( !_pPageFrm ) + { + _pPageFrm = _rLayoutFrm.FindPageFrm(); + OSL_ENSURE( _pPageFrm, + "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" ); + if ( !_pPageFrm ) + { + return; + } + } + + // loop on lower frames + SwFrm* pLowerFrm = _rLayoutFrm.Lower(); + while ( pLowerFrm ) + { + if ( pLowerFrm->IsLayoutFrm() ) + { + ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pLowerFrm)), + _bMoveObjsOutOfRange, _pPageFrm ); + } + if ( pLowerFrm->GetDrawObjs() ) + { + for ( sal_uInt16 i = 0; i < pLowerFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pLowerFrm->GetDrawObjs())[i]; + + // invalidate position of anchored object + pAnchoredObj->SetTmpConsiderWrapInfluence( false ); + pAnchoredObj->SetConsiderForTextWrap( false ); + pAnchoredObj->UnlockPosition(); + pAnchoredObj->InvalidateObjPos(); + + // move anchored object 'out of range' + if ( _bMoveObjsOutOfRange ) + { + // indicate, that positioning is progress to avoid + // modification of the anchored object resp. its attributes + // due to the movement + SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); + pAnchoredObj->SetObjLeft( _pPageFrm->Frm().Right() ); + // --> OD 2004-11-24 #115759# - reset character rectangle, + // top of line and relative position in order to assure, + // that anchored object is correctly positioned. + pAnchoredObj->ClearCharRectAndTopOfLine(); + pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); + if ( pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() + == FLY_AS_CHAR ) + { + pAnchoredObj->AnchorFrm() + ->Prepare( PREP_FLY_ATTR_CHG, + &(pAnchoredObj->GetFrmFmt()) ); + } + // <-- + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + pFly->GetVirtDrawObj()->SetRectsDirty(); + pFly->GetVirtDrawObj()->SetChanged(); + } + } + + // If anchored object is a fly frame, invalidate its lower objects + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrm ); + } + } + } + pLowerFrm = pLowerFrm->GetNext(); + } +} +// <-- +// +// Local helper function to shrink all lowers of rRow to 0 height +// +void lcl_ShrinkCellsAndAllContent( SwRowFrm& rRow ) +{ + SwCellFrm* pCurrMasterCell = static_cast<SwCellFrm*>(rRow.Lower()); + SWRECTFN( pCurrMasterCell ) + + while ( pCurrMasterCell ) + { + // NEW TABLES + SwCellFrm& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ? + const_cast<SwCellFrm&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true, true )) : + *pCurrMasterCell; + + // --> OD 2004-10-04 #i26945# + // all lowers should have the correct position + lcl_ArrangeLowers( &rToAdjust, + (rToAdjust.*fnRect->fnGetPrtTop)(), + sal_False ); + // <-- + // TODO: Optimize number of frames which are set to 0 height + // we have to start with the last lower frame, otherwise + // the shrink will not shrink the current cell + SwFrm* pTmp = rToAdjust.GetLastLower(); + + if ( pTmp && pTmp->IsRowFrm() ) + { + SwRowFrm* pTmpRow = (SwRowFrm*)pTmp; + lcl_ShrinkCellsAndAllContent( *pTmpRow ); + } + else + { + // TODO: Optimize number of frames which are set to 0 height + while ( pTmp ) + { + // the frames have to be shrunk + if ( pTmp && pTmp->IsTabFrm() ) + { + SwRowFrm* pTmpRow = (SwRowFrm*)((SwTabFrm*)pTmp)->Lower(); + while ( pTmpRow ) + { + lcl_ShrinkCellsAndAllContent( *pTmpRow ); + pTmpRow = (SwRowFrm*)pTmpRow->GetNext(); + } + } + else + { + pTmp->Shrink( (pTmp->Frm().*fnRect->fnGetHeight)() ); + (pTmp->Prt().*fnRect->fnSetTop)( 0 ); + (pTmp->Prt().*fnRect->fnSetHeight)( 0 ); + } + + pTmp = pTmp->GetPrev(); + } + + // all lowers should have the correct position + lcl_ArrangeLowers( &rToAdjust, + (rToAdjust.*fnRect->fnGetPrtTop)(), + sal_False ); + } + + pCurrMasterCell = static_cast<SwCellFrm*>(pCurrMasterCell->GetNext()); + } +} + +// +// Local helper function to move the content from rSourceLine to rDestLine +// The content is inserted behind the last content in the corresponding +// cell in rDestLine. +// +void lcl_MoveRowContent( SwRowFrm& rSourceLine, SwRowFrm& rDestLine ) +{ + SwCellFrm* pCurrDestCell = (SwCellFrm*)rDestLine.Lower(); + SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); + + // Move content of follow cells into master cells + while ( pCurrSourceCell ) + { + if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrm() ) + { + SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + while ( pTmpSourceRow ) + { + // --> FME 2006-01-10 #125926# Achtung! It is possible, + // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow + // cannot be found. In this case, we have to move the complete + // row. + SwRowFrm* pTmpDestRow = (SwRowFrm*)pCurrDestCell->Lower(); + // <-- + + if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow ) + { + // move content from follow flow row to pTmpDestRow: + while ( pTmpDestRow->GetNext() ) + pTmpDestRow = (SwRowFrm*)pTmpDestRow->GetNext(); + + OSL_ENSURE( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Knoten in der Tabelle" ); + + lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow ); + pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() ); + pTmpSourceRow->Remove(); + delete pTmpSourceRow; + } + else + { + // move complete row: + pTmpSourceRow->Remove(); + pTmpSourceRow->InsertBefore( pCurrDestCell, 0 ); + } + + pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + } + } + else + { + SwFrm *pTmp = ::SaveCntnt( (SwCellFrm*)pCurrSourceCell ); + if ( pTmp ) + { + // NEW TABLES + SwCellFrm* pDestCell = static_cast<SwCellFrm*>(pCurrDestCell); + if ( pDestCell->GetTabBox()->getRowSpan() < 1 ) + pDestCell = & const_cast<SwCellFrm&>(pDestCell->FindStartEndOfRowSpanCell( true, true )); + + // Find last content + SwFrm* pFrm = pDestCell->GetLastLower(); + ::RestoreCntnt( pTmp, pDestCell, pFrm, true ); + } + } + pCurrDestCell = (SwCellFrm*)pCurrDestCell->GetNext(); + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + } +} + +// +// Local helper function to move all footnotes in rRowFrm from +// the footnote boss of rSource to the footnote boss of rDest. +// +void lcl_MoveFootnotes( SwTabFrm& rSource, SwTabFrm& rDest, SwLayoutFrm& rRowFrm ) +{ + if ( 0 != rSource.GetFmt()->GetDoc()->GetFtnIdxs().Count() ) + { + SwFtnBossFrm* pOldBoss = rSource.FindFtnBossFrm( sal_True ); + SwFtnBossFrm* pNewBoss = rDest.FindFtnBossFrm( sal_True ); + rRowFrm.MoveLowerFtns( 0, pOldBoss, pNewBoss, sal_True ); + } +} + +// +// Local helper function to handle nested table cells before the split process +// +void lcl_PreprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine, + SwRowFrm& rFollowFlowLine, SwTwips nRemain ) +{ + SwCellFrm* pCurrLastLineCell = (SwCellFrm*)rLastLine.Lower(); + SwCellFrm* pCurrFollowFlowLineCell = (SwCellFrm*)rFollowFlowLine.Lower(); + + SWRECTFN( pCurrLastLineCell ) + + // + // Move content of follow cells into master cells + // + while ( pCurrLastLineCell ) + { + if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrm() ) + { + SwTwips nTmpCut = nRemain; + SwRowFrm* pTmpLastLineRow = (SwRowFrm*)pCurrLastLineCell->Lower(); + + // --> OD 2004-10-04 #i26945# + SwTwips nCurrentHeight = + lcl_CalcMinRowHeight( pTmpLastLineRow, + rTab.IsConsiderObjsForMinCellHeight() ); + // <-- + while ( pTmpLastLineRow && pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight ) + { + nTmpCut -= nCurrentHeight; + pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); + // --> OD 2004-10-04 #i26945# + nCurrentHeight = + lcl_CalcMinRowHeight( pTmpLastLineRow, + rTab.IsConsiderObjsForMinCellHeight() ); + // <-- + } + + // + // pTmpLastLineRow does not fit to the line or it is the last line + // + if ( pTmpLastLineRow ) + { + // + // Check if we can move pTmpLastLineRow to the follow table, + // or if we have to split the line: + // + SwFrm* pCell = pTmpLastLineRow->Lower(); + bool bTableLayoutToComplex = false; + long nMinHeight = 0; + + // + // We have to take into account: + // 1. The fixed height of the row + // 2. The borders of the cells inside the row + // 3. The minimum height of the row + // + if ( pTmpLastLineRow->HasFixSize() ) + nMinHeight = (pTmpLastLineRow->Frm().*fnRect->fnGetHeight)(); + else + { + while ( pCell ) + { + if ( ((SwCellFrm*)pCell)->Lower() && + ((SwCellFrm*)pCell)->Lower()->IsRowFrm() ) + { + bTableLayoutToComplex = true; + break; + } + + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nMinHeight = Max( nMinHeight, lcl_CalcTopAndBottomMargin( *(SwLayoutFrm*)pCell, rAttrs ) ); + pCell = pCell->GetNext(); + } + + const SwFmtFrmSize &rSz = pTmpLastLineRow->GetFmt()->GetFrmSize(); + if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE ) + nMinHeight = Max( nMinHeight, rSz.GetHeight() ); + } + + // + // 1. Case: + // The line completely fits into the master table. + // Nevertheless, we build a follow (otherwise painting problems + // with empty cell). + // + // 2. Case: + // The line has to be split, the minimum height still fits into + // the master table, and the table structure is not to complex. + // + if ( nTmpCut > nCurrentHeight || + ( pTmpLastLineRow->IsRowSplitAllowed() && + !bTableLayoutToComplex && nMinHeight < nTmpCut ) ) + { + // The line has to be split: + SwRowFrm* pNewRow = new SwRowFrm( *pTmpLastLineRow->GetTabLine(), &rTab, false ); + pNewRow->SetFollowFlowRow( true ); + pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() ); + pTmpLastLineRow->SetFollowRow( pNewRow ); + pNewRow->InsertBehind( pCurrFollowFlowLineCell, 0 ); + pTmpLastLineRow = (SwRowFrm*)pTmpLastLineRow->GetNext(); + } + + // + // The following lines have to be moved: + // + while ( pTmpLastLineRow ) + { + SwRowFrm* pTmp = (SwRowFrm*)pTmpLastLineRow->GetNext(); + lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow ); + pTmpLastLineRow->Remove(); + pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, 0 ); + pTmpLastLineRow->Shrink( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); + pCurrFollowFlowLineCell->Grow( ( pTmpLastLineRow->Frm().*fnRect->fnGetHeight)() ); + pTmpLastLineRow = pTmp; + } + } + } + + pCurrLastLineCell = (SwCellFrm*)pCurrLastLineCell->GetNext(); + pCurrFollowFlowLineCell = (SwCellFrm*)pCurrFollowFlowLineCell->GetNext(); + } +} + +// +// Local helper function to handle nested table cells after the split process +// +void lcl_PostprocessRowsInCells( SwTabFrm& rTab, SwRowFrm& rLastLine ) +{ + SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); + while ( pCurrMasterCell ) + { + if ( pCurrMasterCell->Lower() && + pCurrMasterCell->Lower()->IsRowFrm() ) + { + SwRowFrm* pRowFrm = static_cast<SwRowFrm*>(pCurrMasterCell->GetLastLower()); + + if ( NULL != pRowFrm->GetPrev() && !pRowFrm->ContainsCntnt() ) + { + OSL_ENSURE( pRowFrm->GetFollowRow(), "Deleting row frame without follow" ); + + // The footnotes have to be moved: + lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrm ); + pRowFrm->Cut(); + SwRowFrm* pFollowRow = pRowFrm->GetFollowRow(); + pRowFrm->Paste( pFollowRow->GetUpper(), pFollowRow ); + pRowFrm->SetFollowRow( pFollowRow->GetFollowRow() ); + lcl_MoveRowContent( *pFollowRow, *pRowFrm ); + pFollowRow->Cut(); + delete pFollowRow; + ::SwInvalidateAll( pCurrMasterCell, LONG_MAX ); + } + } + + pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); + } +} + +// +// Local helper function to re-calculate the split line. +// +inline void TableSplitRecalcLock( SwFlowFrm *pTab ) { pTab->LockJoin(); } +inline void TableSplitRecalcUnlock( SwFlowFrm *pTab ) { pTab->UnlockJoin(); } + +bool lcl_RecalcSplitLine( SwRowFrm& rLastLine, SwRowFrm& rFollowLine, + SwTwips nRemainingSpaceForLastRow ) +{ + bool bRet = true; + + SwTabFrm& rTab = (SwTabFrm&)*rLastLine.GetUpper(); + + // + // If there are nested cells in rLastLine, the recalculation of the last + // line needs some preprocessing. + // + lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow ); + + // + // Here the recalculation process starts: + // + rTab.SetRebuildLastLine( sal_True ); + // --> OD 2004-10-15 #i26945# + rTab.SetDoesObjsFit( sal_True ); + // <-- + SWRECTFN( rTab.GetUpper() ) + + // --> OD 2004-11-05 #i26945# - invalidate and move floating screen + // objects 'out of range' + ::lcl_InvalidateLowerObjs( rLastLine, true ); + // <-- + // + // manipulate row and cell sizes + // + // --> OD 2004-10-04 #i26945# - Do *not* consider floating screen objects + // for the minimal cell height. + rTab.SetConsiderObjsForMinCellHeight( sal_False ); + ::lcl_ShrinkCellsAndAllContent( rLastLine ); + rTab.SetConsiderObjsForMinCellHeight( sal_True ); + // <-- + + // + // invalidate last line + // + ::SwInvalidateAll( &rLastLine, LONG_MAX ); + + // + // Lock this tab frame and its follow + // + bool bUnlockMaster = false; + bool bUnlockFollow = false; + SwTabFrm* pMaster = rTab.IsFollow() ? (SwTabFrm*)rTab.FindMaster() : 0; + if ( pMaster && !pMaster->IsJoinLocked() ) + { + bUnlockMaster = true; + ::TableSplitRecalcLock( pMaster ); + } + if ( !rTab.GetFollow()->IsJoinLocked() ) + { + bUnlockFollow = true; + ::TableSplitRecalcLock( rTab.GetFollow() ); + } + + // + // Do the recalculation + // + lcl_RecalcRow( rLastLine, LONG_MAX ); + // --> OD 2004-11-23 #115759# - force a format of the last line in order to + // get the correct height. + rLastLine.InvalidateSize(); + rLastLine.Calc(); + // <-- + + // + // Unlock this tab frame and its follow + // + if ( bUnlockFollow ) + ::TableSplitRecalcUnlock( rTab.GetFollow() ); + if ( bUnlockMaster ) + ::TableSplitRecalcUnlock( pMaster ); + + // + // If there are nested cells in rLastLine, the recalculation of the last + // line needs some postprocessing. + // + lcl_PostprocessRowsInCells( rTab, rLastLine ); + + // + // Do a couple of checks on the current situation. + // + // If we are not happy with the current situation we return false. + // This will start a new try to split the table, this time we do not + // try to split the table rows. + // + + // + // 1. Check if table fits to its upper. + // --> OD 2004-10-15 #i26945# - include check, if objects fit + // + const SwTwips nDistanceToUpperPrtBottom = + (rTab.Frm().*fnRect->fnBottomDist)( (rTab.GetUpper()->*fnRect->fnGetPrtBottom)()); + if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() ) + bRet = false; + // <-- + + // + // 2. Check if each cell in the last line has at least one content frame. + // + // Note: a FollowFlowRow may contains empty cells! + // + if ( bRet ) + { + if ( !rLastLine.IsInFollowFlowRow() ) + { + SwCellFrm* pCurrMasterCell = (SwCellFrm*)rLastLine.Lower(); + while ( pCurrMasterCell ) + { + if ( !pCurrMasterCell->ContainsCntnt() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 ) + { + bRet = false; + break; + } + pCurrMasterCell = (SwCellFrm*)pCurrMasterCell->GetNext(); + } + } + } + + // + // 3. Check if last line does not contain any content: + // + if ( bRet ) + { + if ( !rLastLine.ContainsCntnt() ) + { + bRet = false; + } + } + + + // + // 4. Check if follow flow line does not contain content: + // + if ( bRet ) + { + if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsCntnt() ) + { + bRet = false; + } + } + + if ( bRet ) + { + // + // Everything looks fine. Splitting seems to be successful. We invalidate + // rFollowLine to force a new formatting. + // + ::SwInvalidateAll( &rFollowLine, LONG_MAX ); + } + else + { + // + // Splitting the table row gave us an unexpected result. + // Everything has to be prepared for a second try to split + // the table, this time without splitting the row. + // + ::SwInvalidateAll( &rLastLine, LONG_MAX ); + } + + rTab.SetRebuildLastLine( sal_False ); + // --> OD 2004-10-15 #i26945# + rTab.SetDoesObjsFit( sal_True ); + // <-- + + return bRet; +} + +// +// Sets the correct height for all spanned cells +// +void lcl_AdjustRowSpanCells( SwRowFrm* pRow ) +{ + SWRECTFN( pRow ) + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pRow->GetLower()); + while ( pCellFrm ) + { + const long nLayoutRowSpan = pCellFrm->GetLayoutRowSpan(); + if ( nLayoutRowSpan > 1 ) + { + // calculate height of cell: + const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan ); + const long nDiff = nNewCellHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); + } + + pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); + } +} + +// +// Returns the maximum layout row span of the row +// Looking for the next row that contains no covered cells: +long lcl_GetMaximumLayoutRowSpan( const SwRowFrm& rRow ) +{ + long nRet = 1; + + const SwRowFrm* pCurrentRowFrm = static_cast<const SwRowFrm*>(rRow.GetNext()); + bool bNextRow = false; + + while ( pCurrentRowFrm ) + { + // if there is any covered cell, we proceed to the next row frame + const SwCellFrm* pLower = static_cast<const SwCellFrm*>( pCurrentRowFrm->Lower()); + while ( pLower ) + { + if ( pLower->GetTabBox()->getRowSpan() < 0 ) + { + ++nRet; + bNextRow = true; + break; + } + pLower = static_cast<const SwCellFrm*>(pLower->GetNext()); + } + pCurrentRowFrm = bNextRow ? + static_cast<const SwRowFrm*>(pCurrentRowFrm->GetNext() ) : + 0; + } + + return nRet; +} + +/************************************************************************* +|* END: local helper functions for splitting row frames +|*************************************************************************/ + +// +// Function to remove the FollowFlowLine of rTab. +// The content of the FollowFlowLine is moved to the associated line in the +// master table. +// +bool SwTabFrm::RemoveFollowFlowLine() +{ + // find FollowFlowLine + SwRowFrm* pFollowFlowLine = static_cast<SwRowFrm*>(GetFollow()->GetFirstNonHeadlineRow()); + + // find last row in master + SwFrm* pLastLine = GetLastLower(); + + OSL_ENSURE( HasFollowFlowLine() && + pFollowFlowLine && + pLastLine, "There should be a flowline in the follow" ); + + // We have to reset the flag here, because lcl_MoveRowContent + // calls a GrowFrm(), which has a different bahavior if + // this flag is set. + SetFollowFlowLine( sal_False ); + + // --> FME 2007-07-19 #140081# Make code robust. + if ( !pFollowFlowLine || !pLastLine ) + return true; + + // Move content + lcl_MoveRowContent( *pFollowFlowLine, *(SwRowFrm*)pLastLine ); + + // NEW TABLES + // If a row span follow flow line is removed, we want to move the whole span + // to the master: + long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine ); + + if ( nRowsToMove > 1 ) + { + SWRECTFN( this ) + SwFrm* pRow = pFollowFlowLine->GetNext(); + SwFrm* pInsertBehind = GetLastLower(); + SwTwips nGrow = 0; + + while ( pRow && nRowsToMove-- > 1 ) + { + SwFrm* pNxt = pRow->GetNext(); + nGrow += (pRow->Frm().*fnRect->fnGetHeight)(); + + // The footnotes have to be moved: + lcl_MoveFootnotes( *GetFollow(), *this, (SwRowFrm&)*pRow ); + + pRow->Remove(); + pRow->InsertBehind( this, pInsertBehind ); + pRow->_InvalidateAll(); + pRow->CheckDirChange(); + pInsertBehind = pRow; + pRow = pNxt; + } + + SwFrm* pFirstRow = Lower(); + while ( pFirstRow ) + { + lcl_AdjustRowSpanCells( static_cast<SwRowFrm*>(pFirstRow) ); + pFirstRow = pFirstRow->GetNext(); + } + + Grow( nGrow ); + GetFollow()->Shrink( nGrow ); + } + + bool bJoin = !pFollowFlowLine->GetNext(); + pFollowFlowLine->Cut(); + delete pFollowFlowLine; + + return bJoin; +} + +// --> OD 2004-10-04 #i26945# - Floating screen objects are no longer searched. +bool lcl_FindSectionsInRow( const SwRowFrm& rRow ) +{ + bool bRet = false; + SwCellFrm* pLower = (SwCellFrm*)rRow.Lower(); + while ( pLower ) + { + if ( pLower->IsVertical() != rRow.IsVertical() ) + return true; + + SwFrm* pTmpFrm = pLower->Lower(); + while ( pTmpFrm ) + { + if ( pTmpFrm->IsRowFrm() ) + { + bRet = lcl_FindSectionsInRow( *(SwRowFrm*)pTmpFrm ); + } + else + { + // --> OD 2004-10-04 #i26945# - search only for sections + bRet = pTmpFrm->IsSctFrm(); + // <-- + } + + if ( bRet ) + return true; + pTmpFrm = pTmpFrm->GetNext(); + } + + pLower = (SwCellFrm*)pLower->GetNext(); + } + return bRet; +} + +/************************************************************************* +|* +|* SwTabFrm::Split(), Join() +|* +|*************************************************************************/ +bool SwTabFrm::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep ) +{ + bool bRet = true; + + SWRECTFN( this ) + + // --> OD 2004-10-14 #i26745# - format row and cell frames of table + { + this->Lower()->_InvalidatePos(); + // --> OD 2005-03-30 #i43913# - correction: + // call method <lcl_InnerCalcLayout> with first lower. + lcl_InnerCalcLayout( this->Lower(), LONG_MAX, true ); + // <-- + } + // <-- + + //Um die Positionen der Zellen mit der CutPos zu vergleichen muessen sie + //ausgehend von der Tabelle nacheinander berechnet werden. Sie koennen + //wg. Positionsaenderungen der Tabelle durchaus ungueltig sein. + SwRowFrm *pRow = static_cast<SwRowFrm*>(Lower()); + if( !pRow ) + return bRet; + + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + sal_uInt16 nRowCount = 0; // pRow currently points to the first row + + SwTwips nRemainingSpaceForLastRow = + (*fnRect->fnYDiff)( nCutPos, (Frm().*fnRect->fnGetTop)() ); + nRemainingSpaceForLastRow -= (this->*fnRect->fnGetTopMargin)(); + + // + // Make pRow point to the line that does not fit anymore: + // + while( pRow->GetNext() && + nRemainingSpaceForLastRow >= ( (pRow->Frm().*fnRect->fnGetHeight)() + + (IsCollapsingBorders() ? + pRow->GetBottomLineSize() : + 0 ) ) ) + { + if( bTryToSplit || !pRow->IsRowSpanLine() || + 0 != (pRow->Frm().*fnRect->fnGetHeight)() ) + ++nRowCount; + nRemainingSpaceForLastRow -= (pRow->Frm().*fnRect->fnGetHeight)(); + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + } + + // + // bSplitRowAllowed: Row may be split according to its attributes. + // bTryToSplit: Row will never be split if bTryToSplit = false. + // This can either be passed as a parameter, indicating + // that we are currently doing the second try to split the + // table, or it will be set to falseunder certain + // conditions that are not suitable for splitting + // the row. + // + bool bSplitRowAllowed = pRow->IsRowSplitAllowed(); + + // --> FME 2004-06-03 #i29438# + // --> OD 2004-10-04 #i26945# - Floating screen objects no longer forbid + // a splitting of the table row. + // Special DoNotSplit case 1: + // Search for sections inside pRow: + // + if ( lcl_FindSectionsInRow( *pRow ) ) + { + bTryToSplit = false; + } + // <-- + + // --> FME 2004-06-07 #i29771# + // To avoid loops, we do some checks before actually trying to split + // the row. Maybe we should keep the next row in this table. + // Note: This is only done if we are at the beginning of our upper + bool bKeepNextRow = false; + if ( nRowCount < nRepeat ) + { + // + // First case: One of the repeated headline does not fit to the page anymore. + // At least one more non-heading row has to stay in this table in + // order to avoid loops: + // + OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" ); + bKeepNextRow = true; + } + else if ( !GetIndPrev() && nRepeat == nRowCount ) + { + // + // Second case: The first non-headline row does not fit to the page. + // If it is not allowed to be split, or it contains a sub-row that + // is not allowed to be split, we keep the row in this table: + // + if ( bTryToSplit && bSplitRowAllowed ) + { + // Check if there are (first) rows inside this row, + // which are not allowed to be split. + SwCellFrm* pLowerCell = pRow ? (SwCellFrm*)pRow->Lower() : 0; + while ( pLowerCell ) + { + if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrm() ) + { + const SwRowFrm* pLowerRow = (SwRowFrm*)pLowerCell->Lower(); + if ( !pLowerRow->IsRowSplitAllowed() && + (pLowerRow->Frm().*fnRect->fnGetHeight)() > + nRemainingSpaceForLastRow ) + { + bKeepNextRow = true; + break; + } + } + pLowerCell = (SwCellFrm*)pLowerCell->GetNext(); + } + } + else + bKeepNextRow = true; + } + + // + // Better keep the next row in this table: + // + if ( bKeepNextRow ) + { + pRow = GetFirstNonHeadlineRow(); + if( pRow && pRow->IsRowSpanLine() && 0 == (pRow->Frm().*fnRect->fnGetHeight)() ) + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + if ( pRow ) + { + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + ++nRowCount; + } + } + + // + // No more row to split or to move to follow table: + // + if ( !pRow ) + return bRet; + + // + // We try to split the row if + // - the attributes of the row are set accordingly and + // - we are allowed to do so + // - the it should not keep with the next row + // + bSplitRowAllowed = bSplitRowAllowed && bTryToSplit && + ( !bTableRowKeep || + !pRow->ShouldRowKeepWithNext() ); + + // Adjust pRow according to the keep-with-next attribute: + if ( !bSplitRowAllowed && bTableRowKeep ) + { + SwRowFrm* pTmpRow = static_cast<SwRowFrm*>(pRow->GetPrev()); + SwRowFrm* pOldRow = pRow; + while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() && + nRowCount > nRepeat ) + { + pRow = pTmpRow; + --nRowCount; + pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetPrev()); + } + + // loop prevention + if ( nRowCount == nRepeat && !GetIndPrev()) + { + pRow = pOldRow; + } + } + + // + // If we do not indent to split pRow, we check if we are + // allowed to move pRow to a follow. Otherwise we return + // false, indicating an error + // + if ( !bSplitRowAllowed ) + { + SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); + if ( pRow == pFirstNonHeadlineRow ) + return false; + + // --> OD 2008-10-21 #i91764# + // Ignore row span lines + SwRowFrm* pTmpRow = pFirstNonHeadlineRow; + while ( pTmpRow && pTmpRow->IsRowSpanLine() ) + { + pTmpRow = static_cast<SwRowFrm*>(pTmpRow->GetNext()); + } + if ( !pTmpRow || pRow == pTmpRow ) + { + return false; + } + // <-- + } + + // + // Build follow table if not already done: + // + sal_Bool bNewFollow; + SwTabFrm *pFoll; + if ( GetFollow() ) + { + pFoll = GetFollow(); + bNewFollow = sal_False; + } + else + { + bNewFollow = sal_True; + pFoll = new SwTabFrm( *this ); + + // + // We give the follow table an initial width. + // + (pFoll->Frm().*fnRect->fnAddWidth)( (Frm().*fnRect->fnGetWidth)() ); + (pFoll->Prt().*fnRect->fnAddWidth)( (Prt().*fnRect->fnGetWidth)() ); + (pFoll->Frm().*fnRect->fnSetLeft)( (Frm().*fnRect->fnGetLeft)() ); + + // + // Insert the new follow table + // + pFoll->InsertBehind( GetUpper(), this ); + + // + // Repeat the headlines. + // + for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount ) + { + // Insert new headlines: + bDontCreateObjects = sal_True; //frmtool + SwRowFrm* pHeadline = new SwRowFrm( + *GetTable()->GetTabLines()[ nRowCount ], this ); + pHeadline->SetRepeatedHeadline( true ); + bDontCreateObjects = sal_False; + pHeadline->InsertBefore( pFoll, 0 ); + + SwPageFrm *pPage = pHeadline->FindPageFrm(); + const SwSpzFrmFmts *pTbl = GetFmt()->GetDoc()->GetSpzFrmFmts(); + if( pTbl->Count() ) + { + sal_uLong nIndex; + SwCntntFrm* pFrm = pHeadline->ContainsCntnt(); + while( pFrm ) + { + nIndex = pFrm->GetNode()->GetIndex(); + AppendObjs( pTbl, nIndex, pFrm, pPage ); + pFrm = pFrm->GetNextCntntFrm(); + if( !pHeadline->IsAnLower( pFrm ) ) + break; + } + } + } + } + + SwRowFrm* pLastRow = 0; // will point to the last remaining line in master + SwRowFrm* pFollowRow = 0; // points to either the follow flow line of the + // first regular line in the follow + + if ( bSplitRowAllowed ) + { + // If the row that does not fit anymore is allowed + // to be split, the next row has to be moved to the follow table. + pLastRow = pRow; + pRow = static_cast<SwRowFrm*>(pRow->GetNext()); + + // new follow flow line for last row of master table + pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false ); + } + else + { + pFollowRow = pRow; + + // NEW TABLES + // check if we will break a row span by moving pFollowRow to the follow: + // In this case we want to reformat the last line. + const SwCellFrm* pCellFrm = static_cast<const SwCellFrm*>(pFollowRow->GetLower()); + while ( pCellFrm ) + { + if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) + { + pLastRow = static_cast<SwRowFrm*>(pRow->GetPrev()); + break; + } + + pCellFrm = static_cast<const SwCellFrm*>(pCellFrm->GetNext()); + } + + // new follow flow line for last row of master table + if ( pLastRow ) + pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true ); + } + + SwTwips nRet = 0; + + //Optimierung beim neuen Follow braucht's kein Paste und dann kann + //das Optimierte Insert verwendet werden (nur dann treten gluecklicher weise + //auch groessere Mengen von Rows auf). + if ( bNewFollow ) + { + SwFrm* pNxt = 0; + SwFrm* pInsertBehind = pFoll->GetLastLower(); + + while ( pRow ) + { + pNxt = pRow->GetNext(); + nRet += (pRow->Frm().*fnRect->fnGetHeight)(); + // The footnotes do not have to be moved, this is done in the + // MoveFwd of the follow table!!! + pRow->Remove(); + pRow->InsertBehind( pFoll, pInsertBehind ); + pRow->_InvalidateAll(); + pInsertBehind = pRow; + pRow = static_cast<SwRowFrm*>(pNxt); + } + } + else + { + SwFrm* pNxt = 0; + SwFrm* pPasteBefore = HasFollowFlowLine() ? + pFollowRow->GetNext() : + pFoll->GetFirstNonHeadlineRow(); + + while ( pRow ) + { + pNxt = pRow->GetNext(); + nRet += (pRow->Frm().*fnRect->fnGetHeight)(); + + // The footnotes have to be moved: + lcl_MoveFootnotes( *this, *GetFollow(), *pRow ); + + pRow->Remove(); + pRow->Paste( pFoll, pPasteBefore ); + + pRow->CheckDirChange(); + pRow = static_cast<SwRowFrm*>(pNxt); + } + } + + Shrink( nRet ); + + // we rebuild the last line to assure that it will be fully formatted + if ( pLastRow ) + { + // recalculate the split line + bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow ); + + // NEW TABLES + // check if each cell in the row span line has a good height + if ( bRet && pFollowRow->IsRowSpanLine() ) + lcl_AdjustRowSpanCells( pFollowRow ); + + // We The RowSplitLine stuff did not work. In this case we conceal the split error: + if ( !bRet && !bSplitRowAllowed ) + { + bRet = true; + } + } + + return bRet; +} + +bool SwTabFrm::Join() +{ + OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" ); + + SwTabFrm *pFoll = GetFollow(); + + if ( !pFoll->IsJoinLocked() ) + { + SWRECTFN( this ) + pFoll->Cut(); //Erst ausschneiden um unuetze Benachrichtigungen zu + //minimieren. + + SwFrm *pRow = pFoll->GetFirstNonHeadlineRow(), + *pNxt; + + SwFrm* pPrv = GetLastLower(); + + SwTwips nHeight = 0; //Gesamthoehe der eingefuegten Zeilen als Return. + while ( pRow ) + { + pNxt = pRow->GetNext(); + nHeight += (pRow->Frm().*fnRect->fnGetHeight)(); + pRow->Remove(); + pRow->_InvalidateAll(); + pRow->InsertBehind( this, pPrv ); + pRow->CheckDirChange(); + pPrv = pRow; + pRow = pNxt; + } + + SetFollow( pFoll->GetFollow() ); + SetFollowFlowLine( pFoll->HasFollowFlowLine() ); + delete pFoll; + + Grow( nHeight ); + } + + return true; +} + +/************************************************************************* +|* +|* SwTabFrm::MakeAll() +|* +|*************************************************************************/ +void MA_FASTCALL SwInvalidatePositions( SwFrm *pFrm, long nBottom ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + SWRECTFN( pFrm ) + do + { pFrm->_InvalidatePos(); + pFrm->_InvalidateSize(); + if( pFrm->IsLayoutFrm() ) + { + if ( ((SwLayoutFrm*)pFrm)->Lower() ) + { + ::SwInvalidatePositions( ((SwLayoutFrm*)pFrm)->Lower(), nBottom); + // --> OD 2004-11-05 #i26945# + ::lcl_InvalidateLowerObjs( *(static_cast<SwLayoutFrm*>(pFrm)) ); + // <-- + } + } + else + pFrm->Prepare( PREP_ADJUST_FRM ); + pFrm = pFrm->GetNext(); + } while ( pFrm && + ( bAll || + (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); +} + +void MA_FASTCALL SwInvalidateAll( SwFrm *pFrm, long nBottom ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + SWRECTFN( pFrm ) + do + { + pFrm->_InvalidatePos(); + pFrm->_InvalidateSize(); + pFrm->_InvalidatePrt(); + if( pFrm->IsLayoutFrm() ) + { + // NEW TABLES + SwLayoutFrm* pToInvalidate = static_cast<SwLayoutFrm*>(pFrm); + SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); + if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) + { + pToInvalidate = & const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); + pToInvalidate->_InvalidatePos(); + pToInvalidate->_InvalidateSize(); + pToInvalidate->_InvalidatePrt(); + } + + if ( pToInvalidate->Lower() ) + ::SwInvalidateAll( pToInvalidate->Lower(), nBottom); + } + else + pFrm->Prepare( PREP_CLEAR ); + + pFrm = pFrm->GetNext(); + } while ( pFrm && + ( bAll || + (*fnRect->fnYDiff)( (pFrm->Frm().*fnRect->fnGetTop)(), nBottom ) < 0 ) ); +} + +// --> collapsing borders FME 2005-05-27 #i29550# +void lcl_InvalidateAllLowersPrt( SwLayoutFrm* pLayFrm ) +{ + pLayFrm->_InvalidatePrt(); + pLayFrm->_InvalidateSize(); + pLayFrm->SetCompletePaint(); + + SwFrm* pFrm = pLayFrm->Lower(); + + while ( pFrm ) + { + if ( pFrm->IsLayoutFrm() ) + lcl_InvalidateAllLowersPrt( (SwLayoutFrm*)pFrm ); + else + { + pFrm->_InvalidatePrt(); + pFrm->_InvalidateSize(); + pFrm->SetCompletePaint(); + } + + pFrm = pFrm->GetNext(); + } +} +// <-- collapsing + +bool SwCntntFrm::CalcLowers( SwLayoutFrm* pLay, const SwLayoutFrm* pDontLeave, + long nBottom, bool bSkipRowSpanCells ) +{ + if ( !pLay ) + return sal_True; + + // LONG_MAX == nBottom means we have to calculate all + bool bAll = LONG_MAX == nBottom; + bool bRet = sal_False; + SwCntntFrm *pCnt = pLay->ContainsCntnt(); + SWRECTFN( pLay ) + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns = 0; + const sal_uInt16 nLoopControlMax = 10; + const SwModify* pLoopControlCond = 0; + + while ( pCnt && pDontLeave->IsAnLower( pCnt ) ) + { + // --> OD 2004-11-23 #115759# - check, if a format of content frame is + // possible. Thus, 'copy' conditions, found at the beginning of + // <SwCntntFrm::MakeAll(..)>, and check these. + const bool bFormatPossible = !pCnt->IsJoinLocked() && + ( !pCnt->IsTxtFrm() || + !static_cast<SwTxtFrm*>(pCnt)->IsLocked() ) && + ( pCnt->IsFollow() || !StackHack::IsLocked() ); + + // NEW TABLES + bool bSkipContent = false; + if ( bSkipRowSpanCells && pCnt->IsInTab() ) + { + const SwFrm* pCell = pCnt->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + if ( pCell && 1 != static_cast<const SwCellFrm*>( pCell )->GetLayoutRowSpan() ) + bSkipContent = true; + } + + if ( bFormatPossible && !bSkipContent ) + { + bRet |= !pCnt->IsValid(); + // --> OD 2004-10-06 #i26945# - no extra invalidation of floating + // screen objects needed. + // Thus, delete call of method <SwFrm::InvalidateObjs( true )> + // <-- + pCnt->Calc(); + // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrm(..)> + // to format the floating screen objects + // --> OD 2005-05-03 #i46941# - frame has to be valid + // Note: frame could be invalid after calling its format, if it's locked. + OSL_ENSURE( !pCnt->IsTxtFrm() || + pCnt->IsValid() || + static_cast<SwTxtFrm*>(pCnt)->IsJoinLocked(), + "<SwCntntFrm::CalcLowers(..)> - text frame invalid and not locked." ); + if ( pCnt->IsTxtFrm() && pCnt->IsValid() ) + { + // --> OD 2004-11-02 #i23129#, #i36347# - pass correct page frame to + // the object formatter + if ( !SwObjectFormatter::FormatObjsAtFrm( *pCnt, + *(pCnt->FindPageFrm()) ) ) + // <-- + { + if ( pCnt->GetRegisteredIn() == pLoopControlCond ) + ++nLoopControlRuns; + else + { + nLoopControlRuns = 0; + pLoopControlCond = pCnt->GetRegisteredIn(); + } + + if ( nLoopControlRuns < nLoopControlMax ) + { + // restart format with first content + pCnt = pLay->ContainsCntnt(); + continue; + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_FAIL( "LoopControl in SwCntntFrm::CalcLowers" ) +#endif + } + } + pCnt->GetUpper()->Calc(); + } + // <-- + if( ! bAll && (*fnRect->fnYDiff)((pCnt->Frm().*fnRect->fnGetTop)(), nBottom) > 0 ) + break; + pCnt = pCnt->GetNextCntntFrm(); + } + return bRet; +} + +// --> OD 2004-10-15 #i26945# - add parameter <_bOnlyRowsAndCells> to control +// that only row and cell frames are formatted. +sal_Bool MA_FASTCALL lcl_InnerCalcLayout( SwFrm *pFrm, + long nBottom, + bool _bOnlyRowsAndCells ) +{ + // LONG_MAX == nBottom means we have to calculate all + sal_Bool bAll = LONG_MAX == nBottom; + sal_Bool bRet = sal_False; + const SwFrm* pOldUp = pFrm->GetUpper(); + SWRECTFN( pFrm ) + do + { + // --> OD 2004-10-15 #i26945# - parameter <_bOnlyRowsAndCells> controls, + // if only row and cell frames are formatted. + if ( pFrm->IsLayoutFrm() && + ( !_bOnlyRowsAndCells || pFrm->IsRowFrm() || pFrm->IsCellFrm() ) ) + // <-- + { + // --> FME 2006-02-23 #130744# An invalid locked table frame will + // not be calculated => It will not become valid => + // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet. + bRet |= !pFrm->IsValid() && ( !pFrm->IsTabFrm() || !static_cast<SwTabFrm*>(pFrm)->IsJoinLocked() ); + // <-- + pFrm->Calc(); + if( static_cast<SwLayoutFrm*>(pFrm)->Lower() ) + bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrm*>(pFrm)->Lower(), nBottom); + + // NEW TABLES + SwCellFrm* pThisCell = dynamic_cast<SwCellFrm*>(pFrm); + if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 ) + { + SwCellFrm& rToCalc = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( true, true )); + bRet |= !rToCalc.IsValid(); + rToCalc.Calc(); + if ( rToCalc.Lower() ) + bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom); + } + } + pFrm = pFrm->GetNext(); + } while( pFrm && + ( bAll || + (*fnRect->fnYDiff)((pFrm->Frm().*fnRect->fnGetTop)(), nBottom) < 0 ) + && pFrm->GetUpper() == pOldUp ); + return bRet; +} + +void MA_FASTCALL lcl_RecalcRow( SwRowFrm& rRow, long nBottom ) +{ + // --> OD 2004-10-05 #i26945# - For correct appliance of the 'straightforward + // object positioning process, it's needed to notify that the page frame, + // on which the given layout frame is in, is in its layout process. + SwPageFrm* pPageFrm = rRow.FindPageFrm(); + if ( pPageFrm && !pPageFrm->IsLayoutInProgress() ) + pPageFrm->SetLayoutInProgress( true ); + else + pPageFrm = 0L; + // <-- + + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_1 = 0; + sal_uInt16 nLoopControlStage_1 = 0; + const sal_uInt16 nLoopControlMax = 10; + + bool bCheck = true; + do + { + // FME 2007-08-30 #i81146# new loop control + sal_uInt16 nLoopControlRuns_2 = 0; + sal_uInt16 nLoopControlStage_2 = 0; + + while( lcl_InnerCalcLayout( &rRow, nBottom ) ) + { + if ( ++nLoopControlRuns_2 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( 0 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 1!" ); + OSL_ENSURE( 1 != nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 2!!" ); + OSL_ENSURE( 2 > nLoopControlStage_2, "LoopControl_2 in lcl_RecalcRow: Stage 3!!!" ); +#endif + rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ ); + nLoopControlRuns_2 = 0; + if( nLoopControlStage_2 > 2 ) + break; + } + + bCheck = true; + } + + if( bCheck ) + { + // --> OD 2004-11-23 #115759# - force another format of the + // lowers, if at least one of it was invalid. + bCheck = SwCntntFrm::CalcLowers( &rRow, rRow.GetUpper(), nBottom, true ); + // <-- + + // NEW TABLES + // First we calculate the cells with row span of < 1, afterwards + // all cells with row span of > 1: + for ( int i = 0; i < 2; ++i ) + { + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(rRow.Lower()); + while ( pCellFrm ) + { + const bool bCalc = 0 == i ? + pCellFrm->GetLayoutRowSpan() < 1 : + pCellFrm->GetLayoutRowSpan() > 1; + + if ( bCalc ) + { + SwCellFrm& rToRecalc = 0 == i ? + const_cast<SwCellFrm&>(pCellFrm->FindStartEndOfRowSpanCell( true, true )) : + *pCellFrm; + bCheck |= SwCntntFrm::CalcLowers( &rToRecalc, &rToRecalc, nBottom, false ); + } + + pCellFrm = static_cast<SwCellFrm*>(pCellFrm->GetNext()); + } + } + + if ( bCheck ) + { + if ( ++nLoopControlRuns_1 > nLoopControlMax ) + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( 0 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 1!" ); + OSL_ENSURE( 1 != nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 2!!" ); + OSL_ENSURE( 2 > nLoopControlStage_1, "LoopControl_1 in lcl_RecalcRow: Stage 3!!!" ); +#endif + rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ ); + nLoopControlRuns_1 = 0; + if( nLoopControlStage_1 > 2 ) + break; + } + + continue; + } + } + break; + } while( true ); + + // --> OD 2004-10-05 #i26945# + if ( pPageFrm ) + pPageFrm->SetLayoutInProgress( false ); + // <-- +} + +void MA_FASTCALL lcl_RecalcTable( SwTabFrm& rTab, + SwLayoutFrm *pFirstRow, + SwLayNotify &rNotify ) +{ + if ( rTab.Lower() ) + { + if ( !pFirstRow ) + { + pFirstRow = (SwLayoutFrm*)rTab.Lower(); + rNotify.SetLowersComplete( sal_True ); + } + ::SwInvalidatePositions( pFirstRow, LONG_MAX ); + lcl_RecalcRow( static_cast<SwRowFrm&>(*pFirstRow), LONG_MAX ); + } +} + +// This is a new function to check the first condition whether +// a tab frame may move backward. It replaces the formerly used +// GetIndPrev(), which did not work correctly for #i5947# +bool lcl_NoPrev( const SwFrm& rFrm ) +{ + // --> OD 2007-09-04 #i79774#, #b6596954# + // skip empty sections on investigation of direct previous frame. + // use information, that at least one empty section is skipped in the following code. + bool bSkippedDirectPrevEmptySection( false ); + if ( rFrm.GetPrev() ) + { + const SwFrm* pPrev( rFrm.GetPrev() ); + while ( pPrev && + pPrev->IsSctFrm() && + !dynamic_cast<const SwSectionFrm*>(pPrev)->GetSection() ) + { + pPrev = pPrev->GetPrev(); + bSkippedDirectPrevEmptySection = true; + } + if ( pPrev ) + { + return false; + } + } + + if ( ( !bSkippedDirectPrevEmptySection && !rFrm.GetIndPrev() ) || + ( bSkippedDirectPrevEmptySection && + ( !rFrm.IsInSct() || !rFrm._GetIndPrev() ) ) ) + { + return true; + } + // <-- + + // I do not have a direct prev, but I have an indirect prev. + // In section frames I have to check if I'm located inside + // the first column: + if ( rFrm.IsInSct() ) + { + const SwFrm* pSct = rFrm.GetUpper(); + if ( pSct && pSct->IsColBodyFrm() && + (pSct = pSct->GetUpper()->GetUpper())->IsSctFrm() ) + { + const SwFrm* pPrevCol = rFrm.GetUpper()->GetUpper()->GetPrev(); + if ( pPrevCol ) + // I'm not inside the first column and do not have a direct + // prev. I can try to go backward. + return true; + } + } + + return false; +} + +#define KEEPTAB ( !GetFollow() && !IsFollow() ) + +// --> OD 2005-09-28 #b6329202# - helper method to find next content frame of +// a table frame and format it to assure keep attribute. +// method return true, if a next content frame is formatted. +// Precondition: The given table frame hasn't a follow and isn't a follow. +SwFrm* lcl_FormatNextCntntForKeep( SwTabFrm* pTabFrm ) +{ + // find next content, table or section + SwFrm* pNxt = pTabFrm->FindNext(); + + // skip empty sections + while ( pNxt && pNxt->IsSctFrm() && + !static_cast<SwSectionFrm*>(pNxt)->GetSection() ) + { + pNxt = pNxt->FindNext(); + } + + // if found next frame is a section, get its first content. + if ( pNxt && pNxt->IsSctFrm() ) + { + pNxt = static_cast<SwSectionFrm*>(pNxt)->ContainsAny(); + } + + // format found next frame. + // if table frame is inside another table, method <SwFrm::MakeAll()> is + // called to avoid that the superior table frame is formatted. + if ( pNxt ) + { + if ( pTabFrm->GetUpper()->IsInTab() ) + pNxt->MakeAll(); + else + pNxt->Calc(); + } + + return pNxt; +} + +void SwTabFrm::MakeAll() +{ + if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) + return; + + if ( HasFollow() ) + { + SwTabFrm* pFollowFrm = (SwTabFrm*)GetFollow(); + OSL_ENSURE( !pFollowFrm->IsJoinLocked() || !pFollowFrm->IsRebuildLastLine(), + "SwTabFrm::MakeAll for master while follow is in RebuildLastLine()" ); + if ( pFollowFrm->IsJoinLocked() && pFollowFrm->IsRebuildLastLine() ) + return; + } + + PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 ) + + LockJoin(); //Ich lass mich nicht unterwegs vernichten. + SwLayNotify aNotify( this ); //uebernimmt im DTor die Benachrichtigung + // If pos is invalid, we have to call a SetInvaKeep at aNotify. + // Otherwise the keep atribute would not work in front of a table. + const sal_Bool bOldValidPos = GetValidPosFlag(); + + //Wenn mein direkter Nachbar gleichzeitig mein Follow ist + //verleibe ich mir das Teil ein. + // OD 09.04.2003 #108698# - join all follows, which are placed on the + // same page/column. + // OD 29.04.2003 #109213# - join follow, only if join for the follow + // is not locked. Otherwise, join will not be performed and this loop + // will be endless. + while ( GetNext() && GetNext() == GetFollow() && + !GetFollow()->IsJoinLocked() + ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + + // The bRemoveFollowFlowLinePending is set if the split attribute of the + // last line is set: + if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() ) + { + if ( RemoveFollowFlowLine() ) + Join(); + SetRemoveFollowFlowLinePending( sal_False ); + } + + if ( bResizeHTMLTable ) //Optimiertes Zusammenspiel mit Grow/Shrink des Inhaltes + { + bResizeHTMLTable = sal_False; + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if ( pLayout ) + bCalcLowers = pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + } + + + sal_Bool bMakePage = sal_True; //solange sal_True kann eine neue Seite + //angelegt werden (genau einmal) + sal_Bool bMovedBwd = sal_False; //Wird sal_True wenn der Frame zurueckfliesst + sal_Bool bMovedFwd = sal_False; //solange sal_False kann der Frm zurueck- + //fliessen (solange, bis er einmal + //vorwaerts ge'moved wurde). + sal_Bool bSplit = sal_False; //Wird sal_True wenn der Frm gesplittet wurde. + const sal_Bool bFtnsInDoc = 0 != GetFmt()->GetDoc()->GetFtnIdxs().Count(); + sal_Bool bMoveable; + const sal_Bool bFly = IsInFly(); + + SwBorderAttrAccess *pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs *pAttrs = pAccess->Get(); + + // The beloved keep attribute + const bool bKeep = IsKeep( pAttrs->GetAttrSet() ); + + // All rows should keep together + // OD 2004-05-25 #i21478# - don't split table, if it has to keep with next + const bool bDontSplit = !IsFollow() && + ( !GetFmt()->GetLayoutSplit().GetValue() || bKeep ); + + // The number of repeated headlines + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + + // This flag indicates that we are allowed to try to split the + // table rows. + bool bTryToSplit = true; + + // --> FME 2006-02-16 #131283# + // Indicates that two individual rows may keep together, based on the keep + // attribute set at the first paragraph in the first cell. + const bool bTableRowKeep = !bDontSplit && GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP); + + // The Magic Move: Used for the table row keep feature. + // If only the last row of the table wants to keep (implicitely by setting + // keep for the first paragraph in the first cell), and this table does + // not have a next, the last line will be cut. Loop prevention: Only + // one try. + bool bLastRowHasToMoveToFollow = false; + bool bLastRowMoveNoMoreTries = false; + + // Join follow table, if this table is not allowed to split: + if ( bDontSplit ) + { + while ( GetFollow() && !GetFollow()->IsJoinLocked() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + // Join follow table, if this does not have enough (repeated) lines: + if ( nRepeat ) + { + if( GetFollow() && !GetFollow()->IsJoinLocked() && + 0 == GetFirstNonHeadlineRow() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + // Join follow table, if last row of this table should keep: + if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() ) + { + const SwRowFrm* pTmpRow = static_cast<const SwRowFrm*>(GetLastLower()); + if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + Join(); + } + } + + //Einen Frischling moven wir gleich schon einmal vorwaerts... + if ( !Frm().Top() && IsFollow() ) + { + SwFrm *pPre = GetPrev(); + if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) + { + if ( !MoveFwd( bMakePage, sal_False ) ) + bMakePage = sal_False; + bMovedFwd = sal_True; + } + } + + int nUnSplitted = 5; // Just another loop control :-( + SWRECTFN( this ) + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + if ( sal_True == (bMoveable = IsMoveable()) ) + if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bMovedBwd ) ) + { + bMovedFwd = sal_True; + bCalcLowers = sal_True; + // --> OD 2009-08-12 #i99267# + // reset <bSplit> after forward move to assure that follows + // can be joined, if further space is available. + bSplit = sal_False; + // <-- + } + + Point aOldPos( (Frm().*fnRect->fnGetPos)() ); + MakePos(); + + if ( aOldPos != (Frm().*fnRect->fnGetPos)() ) + { + if ( aOldPos.Y() != (Frm().*fnRect->fnGetTop)() ) + { + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if( pLayout ) + { + delete pAccess; + bCalcLowers |= pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + + bValidPrtArea = sal_False; + aNotify.SetLowersComplete( sal_False ); + } + SwFrm *pPre; + if ( bKeep || (0 != (pPre = FindPrev()) && + pPre->GetAttrSet()->GetKeep().GetValue()) ) + { + bCalcLowers = sal_True; + // --> OD 2009-03-06 #i99267# + // reset <bSplit> after forward move to assure that follows + // can be joined, if further space is available. + bSplit = sal_False; + // <-- + } + } + + //Wir muessen die Hoehe der ersten Zeile kennen, denn nur wenn diese + //kleiner wird muss ggf. der Master angestossen werden um noetigenfalls + //die Zeile aufzunehmen. + long n1StLineHeight = 0; + if ( IsFollow() ) + { + SwFrm* pFrm = GetFirstNonHeadlineRow(); + if ( pFrm ) + n1StLineHeight = (pFrm->Frm().*fnRect->fnGetHeight)(); + } + + if ( !bValidSize || !bValidPrtArea ) + { + const long nOldPrtWidth = (Prt().*fnRect->fnGetWidth)(); + const long nOldFrmWidth = (Frm().*fnRect->fnGetWidth)(); + const Point aOldPrtPos = (Prt().*fnRect->fnGetPos)(); + Format( pAttrs ); + + SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); + if ( pLayout && + ((Prt().*fnRect->fnGetWidth)() != nOldPrtWidth || + (Frm().*fnRect->fnGetWidth)() != nOldFrmWidth) ) + { + delete pAccess; + bCalcLowers |= pLayout->Resize( + pLayout->GetBrowseWidthByTabFrm( *this ), sal_False ); + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + if ( aOldPrtPos != (Prt().*fnRect->fnGetPos)() ) + aNotify.SetLowersComplete( sal_False ); + } + + //Wenn ich der erste einer Kette bin koennte ich mal sehen ob + //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll). + //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts + //geflosssen sein. + if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) ) + { + //Bei Follows muss der Master benachrichtigt + //werden. Der Follow muss nur dann Moven, wenn er leere Blaetter + //ueberspringen muss. + if ( IsFollow() ) + { + //Nur wenn die Hoehe der ersten Zeile kleiner geworder ist. + SwFrm *pFrm = GetFirstNonHeadlineRow(); + if( pFrm && n1StLineHeight >(pFrm->Frm().*fnRect->fnGetHeight )() ) + { + SwTabFrm *pMaster = (SwTabFrm*)FindMaster(); + sal_Bool bDummy; + if ( ShouldBwdMoved( pMaster->GetUpper(), sal_False, bDummy ) ) + pMaster->InvalidatePos(); + } + } + SwFtnBossFrm *pOldBoss = bFtnsInDoc ? FindFtnBossFrm( sal_True ) : 0; + sal_Bool bReformat; + if ( MoveBwd( bReformat ) ) + { + SWREFRESHFN( this ) + bMovedBwd = sal_True; + aNotify.SetLowersComplete( sal_False ); + if ( bFtnsInDoc ) + MoveLowerFtns( 0, pOldBoss, 0, sal_True ); + if ( bReformat || bKeep ) + { + long nOldTop = (Frm().*fnRect->fnGetTop)(); + MakePos(); + if( nOldTop != (Frm().*fnRect->fnGetTop)() ) + { + SwHTMLTableLayout *pHTMLLayout = + GetTable()->GetHTMLTableLayout(); + if( pHTMLLayout ) + { + delete pAccess; + bCalcLowers |= pHTMLLayout->Resize( + pHTMLLayout->GetBrowseWidthByTabFrm( *this ), + sal_False ); + + pAccess= new SwBorderAttrAccess( + SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + } + + bValidPrtArea = sal_False; + Format( pAttrs ); + } + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + if ( bKeep && KEEPTAB ) + { + // --> OD 2005-09-28 #b6329202# + // Consider case that table is inside another table, + // because it has to be avoided, that superior table + // is formatted. + // Thus, find next content, table or section + // and, if a section is found, get its first + // content. + if ( 0 != lcl_FormatNextCntntForKeep( this ) && !GetNext() ) + { + bValidPos = sal_False; + } + // <-- + } + } + } + } + + //Wieder ein Wert ungueltig? - dann nochmal das ganze... + if ( !bValidPos || !bValidSize || !bValidPrtArea ) + continue; + + // check, if calculation of table frame is ready. + + /// OD 23.10.2002 #103517# - Local variable <nDistanceToUpperPrtBottom> + /// Introduce local variable and init it with the distance from the + /// table frame bottom to the bottom of the upper printing area. + /// Note: negative values denotes the situation that table frame doesn't + /// fit in its upper. + + SwTwips nDistanceToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + + /// OD 23.10.2002 #103517# - In online layout try to grow upper of table + /// frame, if table frame doesn't fit in its upper. + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode ) + { + if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) ) + { + // upper is grown --> recalculate <nDistanceToUpperPrtBottom> + nDistanceToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + } + } + + // If there is still some space left in the upper, we check if we + // can join some rows of the follow. + // Setting bLastRowHasToMoveToFollow to true means we want to force + // the table to be split! Only skip this if condition once. + if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow ) + { + // OD 23.10.2002 - translate german commentary + // If there is space left in the upper printing area, join as for trial + // at least one further row of an existing follow. + if ( !bSplit && GetFollow() ) + { + sal_Bool bDummy; + if ( GetFollow()->ShouldBwdMoved( GetUpper(), sal_False, bDummy ) ) + { + SwFrm *pTmp = GetUpper(); + SwTwips nDeadLine = (pTmp->*fnRect->fnGetPrtBottom)(); + if ( bBrowseMode ) + nDeadLine += pTmp->Grow( LONG_MAX, sal_True ); + if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 ) + { + // + // First, we remove an existing follow flow line. + // + if ( HasFollowFlowLine() ) + { + SwFrm* pLastLine = const_cast<SwFrm*>(GetLastLower()); + RemoveFollowFlowLine(); + // invalidate and rebuild last row + if ( pLastLine ) + { + ::SwInvalidateAll( pLastLine, LONG_MAX ); + SetRebuildLastLine( sal_True ); + lcl_RecalcRow( static_cast<SwRowFrm&>(*pLastLine), LONG_MAX ); + SetRebuildLastLine( sal_False ); + } + + SwFrm* pRow = GetFollow()->GetFirstNonHeadlineRow(); + + if ( !pRow || !pRow->GetNext() ) + //Der Follow wird leer und damit ueberfluessig. + Join(); + + continue; + } + + // + // If there is no follow flow line, we move the first + // row in the follow table to the master table. + // + SwRowFrm *pRow = GetFollow()->GetFirstNonHeadlineRow(); + + //Der Follow wird leer und damit ueberfluessig. + if ( !pRow ) + { + Join(); + continue; + } + + const SwTwips nOld = (Frm().*fnRect->fnGetHeight)(); + long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow ); + SwFrm* pRowToMove = pRow; + + while ( pRowToMove && nRowsToMove-- > 0 ) + { + const sal_Bool bMoveFtns = bFtnsInDoc && !GetFollow()->IsJoinLocked(); + + SwFtnBossFrm *pOldBoss = 0; + if ( bMoveFtns ) + pOldBoss = pRowToMove->FindFtnBossFrm( sal_True ); + + SwFrm* pNextRow = pRowToMove->GetNext(); + + if ( !pNextRow ) + //Der Follow wird leer und damit ueberfluessig. + Join(); + else + { + pRowToMove->Cut(); + pRowToMove->Paste( this ); + } + + //Die Fussnoten verschieben! + if ( bMoveFtns ) + if ( ((SwLayoutFrm*)pRowToMove)->MoveLowerFtns( + 0, pOldBoss, FindFtnBossFrm( sal_True ), sal_True ) ) + GetUpper()->Calc(); + + pRowToMove = pNextRow; + } + + if ( nOld != (Frm().*fnRect->fnGetHeight)() ) + lcl_RecalcTable( *this, (SwLayoutFrm*)pRow, aNotify ); + + continue; + } + } + } + else if ( KEEPTAB ) + { + bool bFormat = false; + if ( bKeep ) + bFormat = true; + else if ( bTableRowKeep && !bLastRowMoveNoMoreTries ) + { + // We only want to give the last row one chance to move + // to the follow table. Set the flag as early as possible: + bLastRowMoveNoMoreTries = true; + + // The last line of the table has to be cut off if: + // 1. The table does not want to keep with its next + // 2. The compatibility option is set and the table is allowed to split + // 3. We did not already cut off the last row + // 4. There is not break after attribute set at the table + // 5. There is no break before attribute set behind the table + // 6. There is no section change behind the table (see IsKeep) + // 7. The last table row wants to keep with its next. + const SwRowFrm* pLastRow = static_cast<const SwRowFrm*>(GetLastLower()); + if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) && + pLastRow->ShouldRowKeepWithNext() ) + bFormat = true; + } + + if ( bFormat ) + { + delete pAccess; + + // --> OD 2005-09-28 #b6329202# + // Consider case that table is inside another table, because + // it has to be avoided, that superior table is formatted. + // Thus, find next content, table or section and, if a section + // is found, get its first content. + const SwFrm* pTmpNxt = lcl_FormatNextCntntForKeep( this ); + // <-- + + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + + // The last row wants to keep with the frame behind the table. + // Check if the next frame is on a different page and valid. + // In this case we do a magic trick: + if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->IsValid() ) + { + bValidPos = sal_False; + bLastRowHasToMoveToFollow = true; + } + } + } + + if ( IsValid() ) + { + if ( bCalcLowers ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } + else if ( bONECalcLowers ) + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bONECalcLowers = sal_False; + } + } + continue; + } + + //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt + //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen + + //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe + //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man + //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und + //zwar mit aller Kraft. + if ( !bMoveable ) + { + if ( bCalcLowers && IsValid() ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } + else if ( bONECalcLowers ) + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bONECalcLowers = sal_False; + } + + // It does not make sense to cut off the last line if we are + // not moveable: + bLastRowHasToMoveToFollow = false; + + continue; + } + + if ( bCalcLowers && IsValid() ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + if( !IsValid() ) + continue; + } + + // + // First try to split the table. Condition: + // 1. We have at least one non headline row + // 2. If this row wants to keep, we need an additional row + // 3. The table is allowed to split or we do not have an pIndPrev: + // + SwFrm* pIndPrev = GetIndPrev(); + const SwRowFrm* pFirstNonHeadlineRow = GetFirstNonHeadlineRow(); + + if ( pFirstNonHeadlineRow && nUnSplitted > 0 && + ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() || !pFirstNonHeadlineRow->ShouldRowKeepWithNext() ) && + ( !bDontSplit || !pIndPrev ) ) + { + // --> FME 2004-06-03 #i29438# + // Special DoNotSplit case: + // We better avoid splitting of a row frame if we are inside a columned + // section which has a height of 0, because this is not growable and thus + // all kinds of unexpected things could happen. + if ( IsInSct() && + (FindSctFrm())->Lower()->IsColumnFrm() && + 0 == (GetUpper()->Frm().*fnRect->fnGetHeight)() ) + { + bTryToSplit = false; + } + // <-- + + // 1. Try: bTryToSplit = true => Try to split the row. + // 2. Try: bTryToSplit = false => Split the table between the rows. + if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit ) + { + SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE) + nDeadLine = (*fnRect->fnYInc)( nDeadLine, + GetUpper()->Grow( LONG_MAX, sal_True ) ); + + ::lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), nDeadLine ); + bLowersFormatted = sal_True; + aNotify.SetLowersComplete( sal_True ); + + // One more check if its really necessary to split the table. + // 1. The table either has to exceed the deadline or + // 2. We explicitly want to cut off the last row. + if( (Frm().*fnRect->fnBottomDist)( nDeadLine ) > 0 && !bLastRowHasToMoveToFollow ) + { + continue; + } + + // Set to false again as early as possible. + bLastRowHasToMoveToFollow = false; + + // --> FME 2005-08-03 #i52781# + // YaSC - Yet another special case: + // If our upper is inside a table cell which is not allowed + // to split, we do not try to split: + if ( GetUpper()->IsInTab() ) + { + const SwFrm* pTmpRow = GetUpper(); + while ( pTmpRow && !pTmpRow->IsRowFrm() ) + pTmpRow = pTmpRow->GetUpper(); + if ( pTmpRow && !static_cast<const SwRowFrm*>(pTmpRow)->IsRowSplitAllowed() ) + continue; + } + // <-- + + sal_uInt16 nMinNumOfLines = nRepeat; + + if ( bTableRowKeep ) + { + const SwRowFrm* pTmpRow = pFirstNonHeadlineRow; + while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() ) + { + ++nMinNumOfLines; + pTmpRow = static_cast<const SwRowFrm*>(pTmpRow->GetNext()); + } + // Check if all lines want to keep together and we + // have a pIndPrev. In this case we set nDeadLine + // to 0, forcing the table to move forward. + if ( !pTmpRow && pIndPrev ) + nDeadLine = 0; + } + + if ( !bTryToSplit ) + ++nMinNumOfLines; + + const SwTwips nBreakLine = (*fnRect->fnYInc)( + (Frm().*fnRect->fnGetTop)(), + (this->*fnRect->fnGetTopMargin)() + + lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) ); + + // Some more checks if we want to call the split algorithm or not: + // The repeating lines / keeping lines still fit into the upper or + // if we do not have an (in)direkt Prev, we split anyway. + if( (*fnRect->fnYDiff)(nDeadLine, nBreakLine) >=0 || !pIndPrev ) + { + aNotify.SetLowersComplete( sal_False ); + bSplit = sal_True; + + // + // An existing follow flow line has to be removed. + // + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + + const bool bSplitError = !Split( nDeadLine, bTryToSplit, bTableRowKeep ); + if( !bTryToSplit && !bSplitError && nUnSplitted > 0 ) + --nUnSplitted; + + // --> FME 2004-06-09 #i29771# Two tries to split the table: + // If an error occurred during splitting. We start a second + // try, this time without splitting of table rows. + if ( bSplitError ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + } + + // --> FME 2005-02-10 #119477# + // If splitting the table was successfull or not, + // we do not want to have 'empty' follow tables. + if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() ) + Join(); + // <-- + + + // We want to restore the situation before the failed + // split operation as good as possible. Therefore we + // do some more calculations. Note: Restricting this + // to nDeadLine may not be enough. + if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426 + { + lcl_RecalcRow( static_cast<SwRowFrm&>(*Lower()), LONG_MAX ); + bValidPos = sal_False; + bTryToSplit = false; + continue; + } + // <-- + + bTryToSplit = !bSplitError; + + //Damit es nicht zu Oszillationen kommt, muss der + //Follow gleich gueltig gemacht werden. + if ( GetFollow() ) + { + // --> OD 2007-11-30 #i80924# + // After a successful split assure that the first row + // is invalid. When graphics are present, this isn't hold. + // Note: defect i80924 could also be fixed, if it is + // assured, that <SwLayNotify::bLowersComplete> is only + // set, if all lower are valid *and* are correct laid out. + if ( !bSplitError && GetFollow()->GetLower() ) + { + GetFollow()->GetLower()->InvalidatePos(); + } + // <-- + SWRECTFNX( GetFollow() ) + + static sal_uInt8 nStack = 0; + if ( !StackHack::IsLocked() && nStack < 4 ) + { + ++nStack; + StackHack aHack; + delete pAccess; + + GetFollow()->MakeAll(); + + pAccess= new SwBorderAttrAccess( SwFrm::GetCache(), this ); + pAttrs = pAccess->Get(); + + ((SwTabFrm*)GetFollow())->SetLowersFormatted(sal_False); + // --> OD 2005-03-30 #i43913# - lock follow table + // to avoid its formatting during the format of + // its content. + const bool bOldJoinLock = GetFollow()->IsJoinLocked(); + GetFollow()->LockJoin(); + // <-- + ::lcl_RecalcRow( static_cast<SwRowFrm&>(*GetFollow()->Lower()), + (GetFollow()->GetUpper()->Frm().*fnRectX->fnGetBottom)() ); + // --> OD 2005-03-30 #i43913# + // --> FME 2006-04-05 #i63632# Do not unlock the + // follow if it wasn't locked before. + if ( !bOldJoinLock ) + GetFollow()->UnlockJoin(); + // <-- + + if ( !GetFollow()->GetFollow() ) + { + SwFrm* pNxt = ((SwFrm*)GetFollow())->FindNext(); + if ( pNxt ) + { + // OD 26.08.2003 #i18103# - no formatting + // of found next frame, if its a follow + // section of the 'ColLocked' section, + // the follow table is in. + bool bCalcNxt = true; + if ( GetFollow()->IsInSct() && pNxt->IsSctFrm() ) + { + SwSectionFrm* pSct = GetFollow()->FindSctFrm(); + if ( pSct->IsColLocked() && + pSct->GetFollow() == pNxt ) + { + bCalcNxt = false; + } + } + if ( bCalcNxt ) + { + pNxt->Calc(); + } + } + } + --nStack; + } + else if ( GetFollow() == GetNext() ) + ((SwTabFrm*)GetFollow())->MoveFwd( sal_True, sal_False ); + } + continue; + } + } + } + + // Set to false again as early as possible. + bLastRowHasToMoveToFollow = false; + + if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrm() && + GetUpper()->GetUpper()->GetUpper()->IsSctFrm() && + ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) && + ((SwSectionFrm*)GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) ) + bMovedFwd = sal_False; + + // --> FME 2004-06-09 #i29771# Reset bTryToSplit flag on change of upper + const SwFrm* pOldUpper = GetUpper(); + // <-- + + //Mal sehen ob ich irgenwo Platz finde... + if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) ) + bMakePage = sal_False; + + // --> FME 2004-06-09 #i29771# Reset bSplitError flag on change of upper + if ( GetUpper() != pOldUpper ) + { + bTryToSplit = true; + nUnSplitted = 5; + } + // <-- + + SWREFRESHFN( this ) + bMovedFwd = bCalcLowers = sal_True; + aNotify.SetLowersComplete( sal_False ); + if ( IsFollow() ) + { //Um Oszillationen zu vermeiden sollte kein ungueltiger Master + //zurueckbleiben. + SwTabFrm *pTab = FindMaster(); + if ( pTab->GetUpper() ) + pTab->GetUpper()->Calc(); + pTab->Calc(); + pTab->SetLowersFormatted( sal_False ); + } + + //Wenn mein direkter Nachbar jetzt gleichzeitig mein Follow ist + //verleibe ich mir das Teil ein. + if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() ) + { + if ( HasFollowFlowLine() ) + RemoveFollowFlowLine(); + if ( GetFollow() ) + Join(); + } + + if ( bMovedBwd && GetUpper() ) + //Beim zurueckfliessen wurde der Upper angeregt sich vollstaendig + //zu Painten, dass koennen wir uns jetzt nach dem hin und her + //fliessen sparen. + GetUpper()->ResetCompletePaint(); + + if ( bCalcLowers && IsValid() ) + { + // --> OD 2005-05-11 #i44910# - format of lower frames unnecessary + // and can cause layout loops, if table doesn't fit and isn't + // allowed to split. + SwTwips nDistToUpperPrtBottom = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->*fnRect->fnGetPrtBottom)()); + if ( nDistToUpperPrtBottom >= 0 || bTryToSplit ) + { + lcl_RecalcTable( *this, 0, aNotify ); + bLowersFormatted = sal_True; + bCalcLowers = sal_False; + } +#if OSL_DEBUG_LEVEL > 1 + else + { + OSL_FAIL( "debug assertion: <SwTabFrm::MakeAll()> - format of table lowers suppressed by fix i44910" ); + } +#endif + // <-- + } + + } //while ( !bValidPos || !bValidSize || !bValidPrtArea ) + + //Wenn mein direkter Vorgaenger jetzt mein Master ist, so kann er mich + //bei der nachstbesten Gelegenheit vernichten. + if ( IsFollow() ) + { + SwFrm *pPre = GetPrev(); + if ( pPre && pPre->IsTabFrm() && ((SwTabFrm*)pPre)->GetFollow() == this) + pPre->InvalidatePos(); + } + + bCalcLowers = bONECalcLowers = sal_False; + delete pAccess; + UnlockJoin(); + if ( bMovedFwd || bMovedBwd || !bOldValidPos ) + aNotify.SetInvaKeep(); +} + +/************************************************************************* +|* +|* SwTabFrm::CalcFlyOffsets() +|* +|* Beschreibung: Berechnet die Offsets, die durch FlyFrames +|* entstehen. +|* +|*************************************************************************/ +sal_Bool SwTabFrm::CalcFlyOffsets( SwTwips& rUpper, + long& rLeftOffset, + long& rRightOffset ) const +{ + sal_Bool bInvalidatePrtArea = sal_False; + const SwPageFrm *pPage = FindPageFrm(); + const SwFlyFrm* pMyFly = FindFlyFrm(); + + // --> #108724# Page header/footer content doesn't have to wrap around + // floating screen objects + + const IDocumentSettingAccess* pIDSA = GetFmt()->getIDocumentSettingAccess(); + const bool bWrapAllowed = pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) || + ( !IsInFtn() && 0 == FindFooterOrHeader() ); + // <-- + + if ( pPage->GetSortedObjs() && bWrapAllowed ) + { + SWRECTFN( this ) + const bool bConsiderWrapOnObjPos = pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION); + long nPrtPos = (Frm().*fnRect->fnGetTop)(); + nPrtPos = (*fnRect->fnYInc)( nPrtPos, rUpper ); + SwRect aRect( Frm() ); + long nYDiff = (*fnRect->fnYDiff)( (Prt().*fnRect->fnGetTop)(), rUpper ); + if( nYDiff > 0 ) + (aRect.*fnRect->fnAddBottom)( -nYDiff ); + for ( sal_uInt16 i = 0; i < pPage->GetSortedObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + const SwRect aFlyRect = pFly->GetObjRectWithSpaces(); + // --> OD 2004-10-07 #i26945# - correction of conditions, + // if Writer fly frame has to be considered: + // - no need to check, if top of Writer fly frame differs + // from WEIT_WECH, because its also check, if the Writer + // fly frame rectangle overlaps with <aRect> + // - no check, if bottom of anchor frame is prior the top of + // the table, because Writer fly frames can be negative positioned. + // - correct check, if the Writer fly frame is an lower of the + // table, because table lines/rows can split and a at-character + // anchored Writer fly frame could be positioned in the follow + // flow line. + // - add condition, that an existing anchor character text frame + // has to be on the same page as the table. + // E.g., it could happen, that the fly frame is still registered + // at the page frame, the table is on, but it's anchor character + // text frame has already changed its page. + const SwTxtFrm* pAnchorCharFrm = pFly->FindAnchorCharFrm(); + bool bConsiderFly = + // --> OD 2005-04-06 #i46807# - do not consider invalid + // Writer fly frames. + pFly->IsValid() && + // <-- + // fly anchored at character + pFly->IsFlyAtCntFrm() && + // fly overlaps with corresponding table rectangle + aFlyRect.IsOver( aRect ) && + // fly isn't lower of table and + // anchor character frame of fly isn't lower of table + ( !IsAnLower( pFly ) && + ( !pAnchorCharFrm || !IsAnLower( pAnchorCharFrm ) ) ) && + // table isn't lower of fly + !pFly->IsAnLower( this ) && + // fly is lower of fly, the table is in + // --> OD 2005-05-31 #123274# - correction: + // assure that fly isn't a lower of a fly, the table isn't in. + // E.g., a table in the body doesn't wrap around a graphic, + // which is inside a frame. + ( ( !pMyFly || + pMyFly->IsAnLower( pFly ) ) && + pMyFly == pFly->GetAnchorFrmContainingAnchPos()->FindFlyFrm() ) && + // <-- + // anchor frame not on following page + pPage->GetPhyPageNum() >= + pFly->GetAnchorFrm()->FindPageFrm()->GetPhyPageNum() && + // anchor character text frame on same page + ( !pAnchorCharFrm || + pAnchorCharFrm->FindPageFrm()->GetPhyPageNum() == + pPage->GetPhyPageNum() ); + + if ( bConsiderFly ) + { + const SwFrm* pFlyHeaderFooterFrm = pFly->GetAnchorFrm()->FindFooterOrHeader(); + const SwFrm* pThisHeaderFooterFrm = FindFooterOrHeader(); + + if ( pFlyHeaderFooterFrm != pThisHeaderFooterFrm && + // --> FME 2007-07-02 #148493# If bConsiderWrapOnObjPos is set, + // we want to consider the fly if it is located in the header and + // the table is located in the body: + ( !bConsiderWrapOnObjPos || 0 != pThisHeaderFooterFrm || !pFlyHeaderFooterFrm->IsHeaderFrm() ) ) + bConsiderFly = false; + // <-- + } + + if ( bConsiderFly ) + // <-- + { + const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround(); + const SwFmtHoriOrient &rHori= pFly->GetFmt()->GetHoriOrient(); + if ( SURROUND_NONE == rSur.GetSurround() ) + { + long nBottom = (aFlyRect.*fnRect->fnGetBottom)(); + if( (*fnRect->fnYDiff)( nPrtPos, nBottom ) < 0 ) + nPrtPos = nBottom; + bInvalidatePrtArea = sal_True; + } + if ( (SURROUND_RIGHT == rSur.GetSurround() || + SURROUND_PARALLEL == rSur.GetSurround())&& + text::HoriOrientation::LEFT == rHori.GetHoriOrient() ) + { + const long nWidth = (*fnRect->fnXDiff)( + (aFlyRect.*fnRect->fnGetRight)(), + (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetLeft)() ); + rLeftOffset = Max( rLeftOffset, nWidth ); + bInvalidatePrtArea = sal_True; + } + if ( (SURROUND_LEFT == rSur.GetSurround() || + SURROUND_PARALLEL == rSur.GetSurround())&& + text::HoriOrientation::RIGHT == rHori.GetHoriOrient() ) + { + const long nWidth = (*fnRect->fnXDiff)( + (pFly->GetAnchorFrm()->Frm().*fnRect->fnGetRight)(), + (aFlyRect.*fnRect->fnGetLeft)() ); + rRightOffset = Max( rRightOffset, nWidth ); + bInvalidatePrtArea = sal_True; + } + } + } + } + rUpper = (*fnRect->fnYDiff)( nPrtPos, (Frm().*fnRect->fnGetTop)() ); + } + + return bInvalidatePrtArea; +} + +/************************************************************************* +|* +|* SwTabFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea +|* Die Fixsize wird hier nicht eingestellt. +|* +|*************************************************************************/ +void SwTabFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "TabFrm::Format, pAttrs ist 0." ); + + SWRECTFN( this ) + if ( !bValidSize ) + { + long nDiff = (GetUpper()->Prt().*fnRect->fnGetWidth)() - + (Frm().*fnRect->fnGetWidth)(); + if( nDiff ) + (aFrm.*fnRect->fnAddRight)( nDiff ); + } + + //VarSize ist immer die Hoehe. + //Fuer den oberen/unteren Rand gelten die selben Regeln wie fuer + //cntfrms (sie MakePrtArea() von diesen). + + SwTwips nUpper = CalcUpperSpace( pAttrs ); + + //Wir wollen Rahmen ausweichen. Zwei Moeglichkeiten: + //1. Es gibt Rahmen mit SurroundNone, diesen wird vollsaendig ausgewichen + //2. Es gibt Rahmen mit Umlauf nur rechts bzw. nur links und diese sind + // rechts bzw. links ausgerichtet, diese geben ein Minimum fuer die + // Raender vor. + long nTmpRight = -1000000, + nLeftOffset = 0; + if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) ) + bValidPrtArea = sal_False; + long nRightOffset = Max( 0L, nTmpRight ); + + SwTwips nLower = pAttrs->CalcBottomLine(); + // --> collapsing borders FME 2005-05-27 #i29550# + if ( IsCollapsingBorders() ) + nLower += GetBottomLineSize(); + // <-- collapsing + + if ( !bValidPrtArea ) + { bValidPrtArea = sal_True; + + //Die Breite der PrtArea wird vom FrmFmt vorgegeben, die Raender + //sind entsprechend einzustellen. + //Mindestraender werden von Umrandung und Schatten vorgegeben. + //Die Rander werden so eingestellt, dass die PrtArea nach dem + //angegebenen Adjustment im Frm ausgerichtet wird. + //Wenn das Adjustment 0 ist, so werden die Rander anhand des + //Randattributes eingestellt. + + const SwTwips nOldHeight = (Prt().*fnRect->fnGetHeight)(); + const SwTwips nMax = (aFrm.*fnRect->fnGetWidth)(); + + // OD 14.03.2003 #i9040# - adjust variable names. + const SwTwips nLeftLine = pAttrs->CalcLeftLine(); + const SwTwips nRightLine = pAttrs->CalcRightLine(); + + //Die Breite ist evtl. eine Prozentangabe. Wenn die Tabelle irgendwo + //'drinsteckt bezieht sie sich auf die Umgebung. Ist es der Body, so + //bezieht sie sich in der BrowseView auf die Bildschirmbreite. + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + // OD 14.03.2003 #i9040# - adjust variable name. + const SwTwips nWishedTableWidth = CalcRel( rSz, sal_True ); + + sal_Bool bCheckBrowseWidth = sal_False; + + // OD 14.03.2003 #i9040# - insert new variables for left/right spacing. + SwTwips nLeftSpacing = 0; + SwTwips nRightSpacing = 0; + switch ( GetFmt()->GetHoriOrient().GetHoriOrient() ) + { + case text::HoriOrientation::LEFT: + { + // left indent: + nLeftSpacing = nLeftLine + nLeftOffset; + // OD 06.03.2003 #i9040# - correct calculation of right indent: + // - Consider right indent given by right line attributes. + // - Consider negative right indent. + // wished right indent determined by wished table width and + // left offset given by surround fly frames on the left: + const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset; + if ( nRightOffset > 0 ) + { + // surrounding fly frames on the right + // -> right indent is maximun of given right offset + // and wished right offset. + nRightSpacing = nRightLine + Max( nRightOffset, nWishRight ); + } + else + { + // no surrounding fly frames on the right + // If intrinsic right indent (intrinsic means not considering + // determined left indent) is negative, + // then hold this intrinsic indent, + // otherwise non negative wished right indent is hold. + nRightSpacing = nRightLine + + ( ( (nWishRight+nLeftOffset) < 0 ) ? + (nWishRight+nLeftOffset) : + Max( 0L, nWishRight ) ); + } + } + break; + case text::HoriOrientation::RIGHT: + { + // right indent: + nRightSpacing = nRightLine + nRightOffset; + // OD 06.03.2003 #i9040# - correct calculation of left indent: + // - Consider left indent given by left line attributes. + // - Consider negative left indent. + // wished left indent determined by wished table width and + // right offset given by surrounding fyl frames on the right: + const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset; + if ( nLeftOffset > 0 ) + { + // surrounding fly frames on the left + // -> right indent is maximun of given left offset + // and wished left offset. + nLeftSpacing = nLeftLine + Max( nLeftOffset, nWishLeft ); + } + else + { + // no surrounding fly frames on the left + // If intrinsic left indent (intrinsic = not considering + // determined right indent) is negative, + // then hold this intrinsic indent, + // otherwise non negative wished left indent is hold. + nLeftSpacing = nLeftLine + + ( ( (nWishLeft+nRightOffset) < 0 ) ? + (nWishLeft+nRightOffset) : + Max( 0L, nWishLeft ) ); + } + } + break; + case text::HoriOrientation::CENTER: + { + // OD 07.03.2003 #i9040# - consider left/right line attribute. + // OD 10.03.2003 #i9040# - + const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2; + nLeftSpacing = nLeftLine + + ( (nLeftOffset > 0) ? + Max( nCenterSpacing, nLeftOffset ) : + nCenterSpacing ); + nRightSpacing = nRightLine + + ( (nRightOffset > 0) ? + Max( nCenterSpacing, nRightOffset ) : + nCenterSpacing ); + } + break; + case text::HoriOrientation::FULL: + //Das Teil dehnt sich ueber die gesamte Breite aus. + //Nur die fuer die Umrandung benoetigten Freiraeume + //werden beruecksichtigt. + //Die Attributwerte von LRSpace werden bewusst missachtet! + bCheckBrowseWidth = sal_True; + nLeftSpacing = nLeftLine + nLeftOffset; + nRightSpacing = nRightLine + nRightOffset; + break; + case text::HoriOrientation::NONE: + { + //Die Raender werden vom Randattribut bestimmt. + nLeftSpacing = pAttrs->CalcLeft( this ); + if( nLeftOffset ) + { + // OD 07.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of left spacing and left offset. + // OD 10.03.2003 #i9040# - consider left line attribute. + nLeftSpacing = Max( nLeftSpacing, ( nLeftOffset + nLeftLine ) ); + } + // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> + nRightSpacing = pAttrs->CalcRight( this ); + if( nRightOffset ) + { + // OD 07.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of right spacing and right offset. + // OD 10.03.2003 #i9040# - consider right line attribute. + nRightSpacing = Max( nRightSpacing, ( nRightOffset + nRightLine ) ); + } + } + break; + case text::HoriOrientation::LEFT_AND_WIDTH: + { + //Linker Rand und die Breite zaehlen (Word-Spezialitaet) + // OD 10.03.2003 #i9040# - no width alignment in online mode. + //bCheckBrowseWidth = sal_True; + nLeftSpacing = pAttrs->CalcLeft( this ); + if( nLeftOffset ) + { + // OD 10.03.2003 #i9040# - surround fly frames only, if + // they overlap with the table. + // Thus, take maximun of right spacing and right offset. + // OD 10.03.2003 #i9040# - consider left line attribute. + nLeftSpacing = Max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) ); + } + // OD 10.03.2003 #i9040# - consider right and left line attribute. + const SwTwips nWishRight = + nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth; + nRightSpacing = nRightLine + + ( (nRightOffset > 0) ? + Max( nWishRight, nRightOffset ) : + nWishRight ); + } + break; + default: + OSL_FAIL( "Ungueltige orientation fuer Table." ); + } + + // --> OD 2004-07-15 #i26250# - extend bottom printing area, if table + // is last content inside a table cell. + if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) && + GetUpper()->IsInTab() && !GetIndNext() ) + { + nLower += pAttrs->GetULSpace().GetLower(); + } + // <-- + (this->*fnRect->fnSetYMargins)( nUpper, nLower ); + if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) ) + (this->*fnRect->fnSetXMargins)( 0, 0 ); + else + (this->*fnRect->fnSetXMargins)( nLeftSpacing, nRightSpacing ); + + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if ( bCheckBrowseWidth && + pSh && pSh->GetViewOptions()->getBrowseMode() && + GetUpper()->IsPageBodyFrm() && // nur PageBodyFrms, nicht etwa ColBodyFrms + pSh->VisArea().Width() ) + { + //Nicht ueber die Kante des sichbaren Bereiches hinausragen. + //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite" + //geben kann (RootFrm::ImplCalcBrowseWidth()) + long nWidth = pSh->GetBrowseWidth(); + nWidth -= Prt().Left(); + nWidth -= pAttrs->CalcRightLine(); + Prt().Width( Min( nWidth, Prt().Width() ) ); + } + + if ( nOldHeight != (Prt().*fnRect->fnGetHeight)() ) + bValidSize = sal_False; + } + + if ( !bValidSize ) + { + bValidSize = sal_True; + + //Die Groesse wird durch den Inhalt plus den Raendern bestimmt. + SwTwips nRemaining = 0, nDiff; + SwFrm *pFrm = pLower; + while ( pFrm ) + { + nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + //Jetzt noch die Raender addieren + nRemaining += nUpper + nLower; + + nDiff = (Frm().*fnRect->fnGetHeight)() - nRemaining; + if ( nDiff > 0 ) + Shrink( nDiff ); + else if ( nDiff < 0 ) + Grow( -nDiff ); + } +} +/************************************************************************* +|* +|* SwTabFrm::GrowFrm() +|* +|*************************************************************************/ +SwTwips SwTabFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + SwTwips nHeight =(Frm().*fnRect->fnGetHeight)(); + if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) ) + nDist = LONG_MAX - nHeight; + + if ( bTst && !IsRestrictTableGrowth() ) + return nDist; + + if ( GetUpper() ) + { + SwRect aOldFrm( Frm() ); + + //Der Upper wird nur soweit wie notwendig gegrowed. In nReal wird erstmal + //die bereits zur Verfuegung stehende Strecke bereitgestellt. + SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)(); + SwFrm *pFrm = GetUpper()->Lower(); + while ( pFrm && GetFollow() != pFrm ) + { + nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + + if ( nReal < nDist ) + { + long nTmp = GetUpper()->Grow( nDist - ( nReal > 0 ? nReal : 0), bTst, bInfo ); + + if ( IsRestrictTableGrowth() ) + { + nTmp = Min( nDist, nReal + nTmp ); + nDist = nTmp < 0 ? 0 : nTmp; + } + } + + if ( !bTst ) + { + (Frm().*fnRect->fnAddBottom)( nDist ); + + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm ); + } + } + } + + if ( !bTst && ( nDist || IsRestrictTableGrowth() ) ) + { + SwPageFrm *pPage = FindPageFrm(); + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + } + // --> OD 2004-07-05 #i28701# - Due to the new object positioning the + // frame on the next page/column can flow backward (e.g. it was moved + // forward due to the positioning of its objects ). Thus, invalivate this + // next frame, if document compatibility option 'Consider wrapping style + // influence on object positioning' is ON. + else if ( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + InvalidateNextPos(); + } + // <-- + _InvalidateAll(); + InvalidatePage( pPage ); + SetComplete(); + + const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos(); + if ( GPOS_NONE != ePos && GPOS_TILED != ePos ) + SetCompletePaint(); + } + + return nDist; +} +/************************************************************************* +|* +|* SwTabFrm::Modify() +|* +|*************************************************************************/ +void SwTabFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + + if( bAttrSetChg ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + if ( nInvFlags & 0x02 ) + _InvalidatePrt(); + if ( nInvFlags & 0x40 ) + _InvalidatePos(); + SwFrm *pTmp; + if ( 0 != (pTmp = GetIndNext()) ) + { + if ( nInvFlags & 0x04 ) + { + pTmp->_InvalidatePrt(); + if ( pTmp->IsCntntFrm() ) + pTmp->InvalidatePage( pPage ); + } + if ( nInvFlags & 0x10 ) + pTmp->SetCompletePaint(); + } + if ( nInvFlags & 0x08 && 0 != (pTmp = GetPrev()) ) + { + pTmp->_InvalidatePrt(); + if ( pTmp->IsCntntFrm() ) + pTmp->InvalidatePage( pPage ); + } + if ( nInvFlags & 0x20 ) + { + if ( pPage && pPage->GetUpper() && !IsFollow() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); + } + if ( nInvFlags & 0x80 ) + InvalidateNextPos(); + } +} + +void SwTabFrm::_UpdateAttr( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { + case RES_TBLHEADLINECHG: + if ( IsFollow() ) + { + // Delete remaining headlines: + SwRowFrm* pLowerRow = 0; + while ( 0 != ( pLowerRow = (SwRowFrm*)Lower() ) && pLowerRow->IsRepeatedHeadline() ) + { + pLowerRow->Cut(); + delete pLowerRow; + } + + // insert new headlines + const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat(); + for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx ) + { + bDontCreateObjects = sal_True; //frmtool + SwRowFrm* pHeadline = new SwRowFrm( *GetTable()->GetTabLines()[ nIdx ], this ); + pHeadline->SetRepeatedHeadline( true ); + bDontCreateObjects = sal_False; + pHeadline->Paste( this, pLowerRow ); + } + } + rInvFlags |= 0x02; + break; + + case RES_FRM_SIZE: + case RES_HORI_ORIENT: + rInvFlags |= 0x22; + break; + + case RES_PAGEDESC: //Attributaenderung (an/aus) + if ( IsInDocBody() ) + { + rInvFlags |= 0x40; + SwPageFrm *pPage = FindPageFrm(); + if ( !GetPrev() ) + CheckPageDescs( pPage ); + if ( pPage && GetFmt()->GetPageDesc().GetNumOffset() ) + ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( sal_True ); + SwDocPosUpdate aMsgHnt( pPage->Frm().Top() ); + GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt ); + } + break; + + case RES_BREAK: + rInvFlags |= 0xC0; + break; + + case RES_LAYOUT_SPLIT: + if ( !IsFollow() ) + rInvFlags |= 0x40; + break; + case RES_FRAMEDIR : + SetDerivedR2L( sal_False ); + CheckDirChange(); + break; + case RES_COLLAPSING_BORDERS : + rInvFlags |= 0x02; + lcl_InvalidateAllLowersPrt( this ); + break; + case RES_UL_SPACE: + rInvFlags |= 0x1C; + /* kein Break hier */ + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrm::Modify( pOld, pNew ); + } +} + +/************************************************************************* +|* +|* SwTabFrm::GetInfo() +|* +|*************************************************************************/ +sal_Bool SwTabFrm::GetInfo( SfxPoolItem &rHnt ) const +{ + if ( RES_VIRTPAGENUM_INFO == rHnt.Which() && IsInDocBody() && !IsFollow() ) + { + SwVirtPageNumInfo &rInfo = (SwVirtPageNumInfo&)rHnt; + const SwPageFrm *pPage = FindPageFrm(); + if ( pPage ) + { + if ( pPage == rInfo.GetOrigPage() && !GetPrev() ) + { + //Das sollte er sein (kann allenfalls temporaer anders sein, + // sollte uns das beunruhigen?) + rInfo.SetInfo( pPage, this ); + return sal_False; + } + if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() && + (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum())) + { + //Das koennte er sein. + rInfo.SetInfo( pPage, this ); + } + } + } + return sal_True; +} + +/************************************************************************* +|* +|* SwTabFrm::FindLastCntnt() +|* +|*************************************************************************/ +SwCntntFrm *SwTabFrm::FindLastCntnt() +{ + SwFrm *pRet = pLower; + + while ( pRet && !pRet->IsCntntFrm() ) + { + SwFrm *pOld = pRet; + + SwFrm *pTmp = pRet; // To skip empty section frames + while ( pRet->GetNext() ) + { + pRet = pRet->GetNext(); + if( !pRet->IsSctFrm() || ((SwSectionFrm*)pRet)->GetSection() ) + pTmp = pRet; + } + pRet = pTmp; + + if ( pRet->GetLower() ) + pRet = pRet->GetLower(); + if ( pRet == pOld ) + { + // Wenn am Ende der letzten Zelle ein spaltiger Bereich steht, + // der eine leere letzte Spalte hat, muessen wir noch die anderen + // Spalten abklappern, dies erledigt SwSectionFrm::FindLastCntnt + if( pRet->IsColBodyFrm() ) + { +#if OSL_DEBUG_LEVEL > 1 + SwSectionFrm* pSect = pRet->FindSctFrm(); + OSL_ENSURE( pSect, "Wo kommt denn die Spalte her?"); + OSL_ENSURE( IsAnLower( pSect ), "Gespaltene Zelle?" ); +#endif + return pRet->FindSctFrm()->FindLastCntnt(); + } + + // + // pRet may be a cell frame without a lower (cell has been split). + // We have to find the last content the hard way: + // + OSL_ENSURE( pRet->IsCellFrm(), "SwTabFrm::FindLastCntnt failed" ); + const SwFrm* pRow = pRet->GetUpper(); + while ( pRow && !pRow->GetUpper()->IsTabFrm() ) + pRow = pRow->GetUpper(); + SwCntntFrm* pCntntFrm = ((SwLayoutFrm*)pRow)->ContainsCntnt(); + pRet = 0; + + while ( pCntntFrm && ((SwLayoutFrm*)pRow)->IsAnLower( pCntntFrm ) ) + { + pRet = pCntntFrm; + pCntntFrm = pCntntFrm->GetNextCntntFrm(); + } + } + } + + // #112929# There actually is a situation, which results in pRet = 0: + // Insert frame, insert table via text <-> table. This gives you a frame + // containing a table without any other content frames. Split the table + // and undo the splitting. This operation gives us a table frame without + // a lower. + if ( pRet ) + { + while ( pRet->GetNext() ) + pRet = pRet->GetNext(); + + if( pRet->IsSctFrm() ) + pRet = ((SwSectionFrm*)pRet)->FindLastCntnt(); + } + + return (SwCntntFrm*)pRet; +} + +/************************************************************************* +|* +|* SwTabFrm::GetLeaf() +|* +|*************************************************************************/ +SwLayoutFrm *SwTabFrm::GetLeaf( MakePageType eMakePage, sal_Bool bFwd ) +{ + SwLayoutFrm *pRet; + if ( bFwd ) + { + pRet = GetNextLeaf( eMakePage ); + while ( IsAnLower( pRet ) ) + pRet = pRet->GetNextLeaf( eMakePage ); + } + else + pRet = GetPrevLeaf(); + if ( pRet ) + pRet->Calc(); + return pRet; +} + +/************************************************************************* +|* +|* SwTabFrm::ShouldBwdMoved() +|* +|* Beschreibung Returnwert sagt ob der Frm verschoben werden sollte +|* +|*************************************************************************/ +sal_Bool SwTabFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, sal_Bool, sal_Bool &rReformat ) +{ + rReformat = sal_False; + if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()) ) + { + //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv. + //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen + //moechte die FixSize die gleiche ist, die der Frm selbst hat. + //In diesem Fall kann einfach geprueft werden, ob der Frm genug + //Platz fuer seine VarSize findet, ist dies nicht der Fall kann + //gleich auf das Verschieben verzichtet werden. + //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst + //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise + //aufspalten kann. + //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind + //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn + //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt + //etwas Platz zur Verfuegung steht). + + //Die FixSize der Umgebungen in denen Tabellen herumlungern ist immer + //Die Breite. + + SwPageFrm *pOldPage = FindPageFrm(), + *pNewPage = pNewUpper->FindPageFrm(); + sal_Bool bMoveAnyway = sal_False; + SwTwips nSpace = 0; + + SWRECTFN( this ) + if ( !SwFlowFrm::IsMoveBwdJump() ) + { + + long nOldWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + SWRECTFNX( pNewUpper ); + long nNewWidth = (pNewUpper->Prt().*fnRectX->fnGetWidth)(); + if( Abs( nNewWidth - nOldWidth ) < 2 ) + { + if( sal_False == + ( bMoveAnyway = BwdMoveNecessary( pOldPage, Frm() ) > 1 ) ) + { + SwRect aRect( pNewUpper->Prt() ); + aRect.Pos() += pNewUpper->Frm().Pos(); + const SwFrm *pPrevFrm = pNewUpper->Lower(); + while ( pPrevFrm && pPrevFrm != this ) + { + (aRect.*fnRectX->fnSetTop)( (pPrevFrm->Frm().*fnRectX-> + fnGetBottom)() ); + pPrevFrm = pPrevFrm->GetNext(); + } + bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1; + + // --> FME 2006-01-20 #i54861# Due to changes made in PrepareMake, + // the tabfrm may not have a correct position. Therefore + // it is possible that pNewUpper->Prt().Height == 0. In this + // case the above calculation of nSpace might give wrong + // results and we really do not want to MoveBackwrd into a + // 0 height frame. If nTmpSpace is already <= 0, we take this + // value: + const SwTwips nTmpSpace = (aRect.*fnRectX->fnGetHeight)(); + if ( (pNewUpper->Prt().*fnRectX->fnGetHeight)() > 0 || nTmpSpace <= 0 ) + nSpace = nTmpSpace; + // <-- + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + nSpace += pNewUpper->Grow( LONG_MAX, sal_True ); + } + } + else if( !bLockBackMove ) + bMoveAnyway = sal_True; + } + else if( !bLockBackMove ) + bMoveAnyway = sal_True; + + if ( bMoveAnyway ) + return rReformat = sal_True; + else if ( !bLockBackMove && nSpace > 0 ) + { + // --> OD 2004-10-05 #i26945# - check, if follow flow line + // contains frame, which are moved forward due to its object + // positioning. + SwRowFrm* pFirstRow = GetFirstNonHeadlineRow(); + if ( pFirstRow && pFirstRow->IsInFollowFlowRow() && + SwLayouter::DoesRowContainMovedFwdFrm( + *(pFirstRow->GetFmt()->GetDoc()), + *(pFirstRow) ) ) + { + return sal_False; + } + // <-- + SwTwips nTmpHeight = CalcHeightOfFirstContentLine(); + + // --> FME 2005-01-17 #118840# + // For some mysterious reason, I changed the good old + // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'. + // This obviously results in problems with table frames in + // sections. Remember: Every twip is sacred. + return nTmpHeight <= nSpace; + // <-- + } + } + return sal_False; +} + +/************************************************************************* +|* +|* SwTabFrm::Cut() +|* +|*************************************************************************/ +void SwTabFrm::Cut() +{ + OSL_ENSURE( GetUpper(), "Cut ohne Upper()." ); + + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + SwFrm *pFrm = GetNext(); + if( pFrm ) + { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger + //berechnet der ist jetzt wo er der erste wird obsolete + pFrm->_InvalidatePrt(); + pFrm->_InvalidatePos(); + if ( pFrm->IsCntntFrm() ) + pFrm->InvalidatePage( pPage ); + if( IsInSct() && !GetPrev() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + } + else + { + InvalidateNextPos(); + //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper + if ( 0 != (pFrm = GetPrev()) ) + { pFrm->SetRetouche(); + pFrm->Prepare( PREP_WIDOWS_ORPHANS ); + pFrm->_InvalidatePos(); + if ( pFrm->IsCntntFrm() ) + pFrm->InvalidatePage( pPage ); + } + //Wenn ich der einzige FlowFrm in meinem Upper bin (war), so muss + //er die Retouche uebernehmen. + //Ausserdem kann eine Leerseite entstanden sein. + else + { SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); + pRoot->SetSuperfluous(); + GetUpper()->SetCompletePaint(); + if( IsInSct() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + } + } + + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + SWRECTFN( this ) + Remove(); + if ( pUp ) + { + OSL_ENSURE( !pUp->IsFtnFrm(), "Tabelle in Fussnote." ); + SwSectionFrm *pSct = 0; + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + if ( !pUp->Lower() && pUp->IsInSct() && + !(pSct = pUp->FindSctFrm())->ContainsCntnt() && + !pSct->ContainsAny( true ) ) + // <-- + { + if ( pUp->GetUpper() ) + { + pSct->DelEmpty( sal_False ); + pSct->_InvalidateSize(); + } + } + else if( (Frm().*fnRect->fnGetHeight)() ) + { + // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section - + // undo changes of fix for #104992# + pUp->Shrink( Frm().Height() ); + } + } + + if ( pPage && !IsFollow() && pPage->GetUpper() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); +} + +/************************************************************************* +|* +|* SwTabFrm::Paste() +|* +|*************************************************************************/ +void SwTabFrm::Paste( SwFrm* pParent, SwFrm* pSibling ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + _InvalidateAll(); + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + GetNext()->_InvalidatePrt(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + } + + SWRECTFN( this ) + if( (Frm().*fnRect->fnGetHeight)() ) + pParent->Grow( (Frm().*fnRect->fnGetHeight)() ); + + if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)() ) + Prepare( PREP_FIXSIZE_CHG ); + if ( GetPrev() ) + { + if ( !IsFollow() ) + { + GetPrev()->InvalidateSize(); + if ( GetPrev()->IsCntntFrm() ) + GetPrev()->InvalidatePage( pPage ); + } + } + else if ( GetNext() ) + //Bei CntntFrm's gilt es den Abstand zum Vorgaenger/Nachfolger + //zu beachten. Faelle (beide treten immer gleichzeitig auf): + //a) Der Cntnt wird der erste einer Kette + //b) Der neue Nachfolger war vorher der erste einer Kette + GetNext()->_InvalidatePrt(); + + if ( pPage && !IsFollow() ) + { + if ( pPage->GetUpper() ) + ((SwRootFrm*)pPage->GetUpper())->InvalidateBrowseWidth(); + + if ( !GetPrev() )//Mindestens fuer HTML mit Tabelle am Anfang notwendig. + { + const SwPageDesc *pDesc = GetFmt()->GetPageDesc().GetPageDesc(); + if ( (pDesc && pDesc != pPage->GetPageDesc()) || + (!pDesc && pPage->GetPageDesc() != + &(const_cast<const SwDoc *>(GetFmt()->GetDoc()) + ->GetPageDesc(0))) ) + CheckPageDescs( pPage, sal_True ); + } + } +} + +/************************************************************************* +|* +|* SwTabFrm::Prepare() +|* +|*************************************************************************/ +void SwTabFrm::Prepare( const PrepareHint eHint, const void *, sal_Bool ) +{ + if( PREP_BOSS_CHGD == eHint ) + CheckDirChange(); +} + +/************************************************************************* +|* +|* SwRowFrm::SwRowFrm(), ~SwRowFrm() +|* +|*************************************************************************/ +SwRowFrm::SwRowFrm( const SwTableLine &rLine, SwFrm* pSib, bool bInsertContent ): + SwLayoutFrm( rLine.GetFrmFmt(), pSib ), + pTabLine( &rLine ), + pFollowRow( 0 ), + // --> collapsing borders FME 2005-05-27 #i29550# + mnTopMarginForLowers( 0 ), + mnBottomMarginForLowers( 0 ), + mnBottomLineSize( 0 ), + // <-- collapsing + // --> split table rows + bIsFollowFlowRow( false ), + // <-- split table rows + bIsRepeatedHeadline( false ), + mbIsRowSpanLine( false ) +{ + nType = FRMC_ROW; + + //Gleich die Boxen erzeugen und einfuegen. + const SwTableBoxes &rBoxes = rLine.GetTabBoxes(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + { + SwCellFrm *pNew = new SwCellFrm( *rBoxes[i], this, bInsertContent ); + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } +} + +SwRowFrm::~SwRowFrm() +{ + SwModify* pMod = GetFmt(); + if( pMod ) + { + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen + } +} + +/************************************************************************* +|* +|* SwRowFrm::RegistFlys() +|* +|*************************************************************************/ +void SwRowFrm::RegistFlys( SwPageFrm *pPage ) +{ + ::RegistFlys( pPage ? pPage : FindPageFrm(), this ); +} + +/************************************************************************* +|* +|* SwRowFrm::Modify() +|* +|*************************************************************************/ +void SwRowFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + const SfxPoolItem *pItem = 0; + + if( bAttrSetChg ) + { + const SwAttrSet* pChgSet = ((SwAttrSetChg*)pNew)->GetChgSet(); + pChgSet->GetItemState( RES_FRM_SIZE, sal_False, &pItem); + if ( !pItem ) + pChgSet->GetItemState( RES_ROW_SPLIT, sal_False, &pItem); + } + else if ( RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which() ) + pItem = pNew; + + if ( pItem ) + { + SwTabFrm *pTab = FindTabFrm(); + if ( pTab ) + { + const bool bInFirstNonHeadlineRow = pTab->IsFollow() && + this == pTab->GetFirstNonHeadlineRow(); + // --> FME 2004-10-27 #i35063# + // Invalidation required is pRow is last row + if ( bInFirstNonHeadlineRow || !GetNext() ) + // <-- + { + if ( bInFirstNonHeadlineRow ) + pTab = pTab->FindMaster(); + pTab->InvalidatePos(); + } + } + } + + SwLayoutFrm::Modify( pOld, pNew ); +} + + + +/************************************************************************* +|* +|* SwRowFrm::MakeAll() +|* +|*************************************************************************/ +void SwRowFrm::MakeAll() +{ + if ( !GetNext() ) + bValidSize = sal_False; + SwLayoutFrm::MakeAll(); +} + +/************************************************************************* +|* +|* SwRowFrm::Format() +|* +|*************************************************************************/ +long MA_FASTCALL CalcHeightWidthFlys( const SwFrm *pFrm ) +{ + SWRECTFN( pFrm ) + long nHeight = 0; + const SwFrm* pTmp = pFrm->IsSctFrm() ? + ((SwSectionFrm*)pFrm)->ContainsCntnt() : pFrm; + while( pTmp ) + { + // --> OD 2004-10-08 #i26945# - consider follow text frames + const SwSortedObjs* pObjs( 0L ); + bool bIsFollow( false ); + if ( pTmp->IsTxtFrm() && static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) + { + const SwFrm* pMaster; + // --> FME 2005-04-01 #i46450# Master does not necessarily have + // to exist if this function is called from JoinFrm() -> + // Cut() -> Shrink() + const SwTxtFrm* pTmpFrm = static_cast<const SwTxtFrm*>(pTmp); + if ( pTmpFrm->GetPrev() && pTmpFrm->GetPrev()->IsTxtFrm() && + static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() && + static_cast<const SwTxtFrm*>(pTmpFrm->GetPrev())->GetFollow() != pTmp ) + pMaster = 0; + else + pMaster = pTmpFrm->FindMaster(); + + if ( pMaster ) + { + pObjs = static_cast<const SwTxtFrm*>(pTmp)->FindMaster()->GetDrawObjs(); + bIsFollow = true; + } + } + else + { + pObjs = pTmp->GetDrawObjs(); + } + if ( pObjs ) + // <-- + { + for ( sal_uInt16 i = 0; i < pObjs->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + // --> OD 2004-10-08 #i26945# - if <pTmp> is follow, the + // anchor character frame has to be <pTmp>. + if ( bIsFollow && + const_cast<SwAnchoredObject*>(pAnchoredObj)->FindAnchorCharFrm() != pTmp ) + { + continue; + } + // <-- + // --> OD 2004-10-04 #i26945# - consider also drawing objects + { + // OD 30.09.2003 #i18732# - only objects, which follow + // the text flow have to be considered. + const SwFrmFmt& rFrmFmt = pAnchoredObj->GetFrmFmt(); + const bool bConsiderObj = + (rFrmFmt.GetAnchor().GetAnchorId() != FLY_AS_CHAR) && + pAnchoredObj->GetObjRect().Top() != WEIT_WECH && + rFrmFmt.GetFollowTextFlow().GetValue() && + pAnchoredObj->GetPageFrm() == pTmp->FindPageFrm(); + if ( bConsiderObj ) + { + const SwFmtFrmSize &rSz = rFrmFmt.GetFrmSize(); + if( !rSz.GetHeightPercent() ) + { + const SwTwips nDistOfFlyBottomToAnchorTop = + (pAnchoredObj->GetObjRect().*fnRect->fnGetHeight)() + + ( bVert ? + pAnchoredObj->GetCurrRelPos().X() : + pAnchoredObj->GetCurrRelPos().Y() ); + + const SwTwips nFrmDiff = + (*fnRect->fnYDiff)( + (pTmp->Frm().*fnRect->fnGetTop)(), + (pFrm->Frm().*fnRect->fnGetTop)() ); + + nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop + nFrmDiff - + (pFrm->Frm().*fnRect->fnGetHeight)() ); + + // --> FME 2006-01-24 #i56115# The first height calculation + // gives wrong results if pFrm->Prt().Y() > 0. We do + // a second calculation based on the actual rectangles of + // pFrm and pAnchoredObj, and use the maximum of the results. + // I do not want to remove the first calculation because + // if clipping has been applied, using the GetCurrRelPos + // might be the better option to calculate nHeight. + const SwTwips nDistOfFlyBottomToAnchorTop2 = (*fnRect->fnYDiff)( + (pAnchoredObj->GetObjRect().*fnRect->fnGetBottom)(), + (pFrm->Frm().*fnRect->fnGetBottom)() ); + + nHeight = Max( nHeight, nDistOfFlyBottomToAnchorTop2 ); + // <-- + } + } + } + // <-- + } + } + if( !pFrm->IsSctFrm() ) + break; + pTmp = pTmp->FindNextCnt(); + if( !((SwSectionFrm*)pFrm)->IsAnLower( pTmp ) ) + break; + } + return nHeight; +} + +SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrm& rCell, const SwBorderAttrs& rAttrs ) +{ + const SwTabFrm* pTab = rCell.FindTabFrm(); + SwTwips nTopSpace = 0; + SwTwips nBottomSpace = 0; + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrm() ) + { + nTopSpace = ((SwRowFrm*)rCell.GetUpper())->GetTopMarginForLowers(); + nBottomSpace = ((SwRowFrm*)rCell.GetUpper())->GetBottomMarginForLowers(); + } + // <-- collapsing + else + { + if ( pTab->IsVertical() != rCell.IsVertical() ) + { + nTopSpace = rAttrs.CalcLeft( &rCell ); + nBottomSpace = rAttrs.CalcRight( &rCell ); + } + else + { + nTopSpace = rAttrs.CalcTop(); + nBottomSpace = rAttrs.CalcBottom(); + } + } + + return nTopSpace + nBottomSpace; +} + + +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to +// control, if floating screen objects have to be considered for the minimal +// cell height. +SwTwips MA_FASTCALL lcl_CalcMinCellHeight( const SwLayoutFrm *_pCell, + const sal_Bool _bConsiderObjs, + const SwBorderAttrs *pAttrs = 0 ) +{ + SWRECTFN( _pCell ) + SwTwips nHeight = 0; + const SwFrm* pLow = _pCell->Lower(); + if ( pLow ) + { + long nFlyAdd = 0; + while ( pLow ) + { + // OD 2004-02-18 #106629# - change condition and switch then-body + // and else-body + if ( pLow->IsRowFrm() ) + { + // --> OD 2004-10-04 #i26945# + nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrm*>(pLow), + _bConsiderObjs ); + // <-- + } + else + { + long nLowHeight = (pLow->Frm().*fnRect->fnGetHeight)(); + nHeight += nLowHeight; + // --> OD 2004-10-04 #i26945# + if ( _bConsiderObjs ) + { + nFlyAdd = Max( 0L, nFlyAdd - nLowHeight ); + nFlyAdd = Max( nFlyAdd, ::CalcHeightWidthFlys( pLow ) ); + } + // <-- + } + + pLow = pLow->GetNext(); + } + if ( nFlyAdd ) + nHeight += nFlyAdd; + } + //Der Border will natuerlich auch mitspielen, er kann leider nicht + //aus PrtArea und Frm errechnet werden, da diese in beliebiger + //Kombination ungueltig sein koennen. + if ( _pCell->Lower() ) + { + if ( pAttrs ) + nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs ); + else + { + SwBorderAttrAccess aAccess( SwFrm::GetCache(), _pCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs ); + } + } + return nHeight; +} + +// OD 2004-02-18 #106629# - correct type of 1st parameter +// --> OD 2004-10-04 #i26945# - add parameter <_bConsiderObjs> in order to control, +// if floating screen objects have to be considered for the minimal cell height +SwTwips MA_FASTCALL lcl_CalcMinRowHeight( const SwRowFrm* _pRow, + const sal_Bool _bConsiderObjs ) +{ + SWRECTFN( _pRow ) + + const SwFmtFrmSize &rSz = _pRow->GetFmt()->GetFrmSize(); + + if ( _pRow->HasFixSize() && !_pRow->IsRowSpanLine() ) + { + OSL_ENSURE( ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size" ); + return rSz.GetHeight(); + } + + SwTwips nHeight = 0; + const SwCellFrm* pLow = static_cast<const SwCellFrm*>(_pRow->Lower()); + while ( pLow ) + { + SwTwips nTmp = 0; + const long nRowSpan = pLow->GetLayoutRowSpan(); + // --> NEW TABLES + // Consider height of + // 1. current cell if RowSpan == 1 + // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1 + // 3. master cell if RowSpan == -1 + if ( 1 == nRowSpan ) + { + nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs ); + } + else if ( -1 == nRowSpan ) + { + // Height of the last cell of a row span is height of master cell + // minus the height of the other rows which are covered by the master + // cell: + const SwCellFrm& rMaster = pLow->FindStartEndOfRowSpanCell( true, true ); + nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs ); + const SwFrm* pMasterRow = rMaster.GetUpper(); + while ( pMasterRow && pMasterRow != _pRow ) + { + nTmp -= (pMasterRow->Frm().*fnRect->fnGetHeight)(); + pMasterRow = pMasterRow->GetNext(); + } + } + // <-- NEW TABLES + + // Do not consider rotated cells: + if ( ( 0 != pLow->IsVertical() ) == ( 0 != bVert ) && nTmp > nHeight ) + nHeight = nTmp; + + pLow = static_cast<const SwCellFrm*>(pLow->GetNext()); + } + if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE && !_pRow->IsRowSpanLine() ) + nHeight = Max( nHeight, rSz.GetHeight() ); + return nHeight; +} + +// --> collapsing borders FME 2005-05-27 #i29550# + +// Calculate the maximum of (TopLineSize + TopLineDist) over all lowers: +sal_uInt16 lcl_GetTopSpace( const SwRowFrm& rRow ) +{ + sal_uInt16 nTopSpace = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpTopSpace = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + nTmpTopSpace = lcl_GetTopSpace( *(SwRowFrm*)pCurrLower->Lower() ); + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpTopSpace = rBoxItem.CalcLineSpace( BOX_LINE_TOP, sal_True ); + } + nTopSpace = Max( nTopSpace, nTmpTopSpace ); + } + return nTopSpace; +} + +// Calculate the maximum of TopLineDist over all lowers: +sal_uInt16 lcl_GetTopLineDist( const SwRowFrm& rRow ) +{ + sal_uInt16 nTopLineDist = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpTopLineDist = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + nTmpTopLineDist = lcl_GetTopLineDist( *(SwRowFrm*)pCurrLower->Lower() ); + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpTopLineDist = rBoxItem.GetDistance( BOX_LINE_TOP ); + } + nTopLineDist = Max( nTopLineDist, nTmpTopLineDist ); + } + return nTopLineDist; +} + +// Calculate the maximum of BottomLineSize over all lowers: +sal_uInt16 lcl_GetBottomLineSize( const SwRowFrm& rRow ) +{ + sal_uInt16 nBottomLineSize = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpBottomLineSize = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + { + const SwFrm* pRow = pCurrLower->GetLastLower(); + nTmpBottomLineSize = lcl_GetBottomLineSize( *(SwRowFrm*)pRow ); + } + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpBottomLineSize = rBoxItem.CalcLineSpace( BOX_LINE_BOTTOM, sal_True ) - + rBoxItem.GetDistance( BOX_LINE_BOTTOM ); + } + nBottomLineSize = Max( nBottomLineSize, nTmpBottomLineSize ); + } + return nBottomLineSize; +} + +// Calculate the maximum of BottomLineDist over all lowers: +sal_uInt16 lcl_GetBottomLineDist( const SwRowFrm& rRow ) +{ + sal_uInt16 nBottomLineDist = 0; + for ( SwCellFrm* pCurrLower = (SwCellFrm*)rRow.Lower(); pCurrLower; + pCurrLower = (SwCellFrm*)pCurrLower->GetNext() ) + { + sal_uInt16 nTmpBottomLineDist = 0; + if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrm() ) + { + const SwFrm* pRow = pCurrLower->GetLastLower(); + nTmpBottomLineDist = lcl_GetBottomLineDist( *(SwRowFrm*)pRow ); + } + else + { + const SwAttrSet& rSet = ((SwCellFrm*)pCurrLower)->GetFmt()->GetAttrSet(); + const SvxBoxItem& rBoxItem = rSet.GetBox(); + nTmpBottomLineDist = rBoxItem.GetDistance( BOX_LINE_BOTTOM ); + } + nBottomLineDist = Max( nBottomLineDist, nTmpBottomLineDist ); + } + return nBottomLineDist; +} + +// <-- collapsing + +void SwRowFrm::Format( const SwBorderAttrs *pAttrs ) +{ + SWRECTFN( this ) + OSL_ENSURE( pAttrs, "SwRowFrm::Format ohne Attrs." ); + + const sal_Bool bFix = bFixSize; + + if ( !bValidPrtArea ) + { + //RowFrms haben keine Umrandung usw. also entspricht die PrtArea immer + //dem Frm. + bValidPrtArea = sal_True; + aPrt.Left( 0 ); + aPrt.Top( 0 ); + aPrt.Width ( aFrm.Width() ); + aPrt.Height( aFrm.Height() ); + + // --> collapsing borders FME 2005-05-27 #i29550# + // Here we calculate the top-printing area for the lower cell frames + SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->IsCollapsingBorders() ) + { + const sal_uInt16 nTopSpace = lcl_GetTopSpace( *this ); + const sal_uInt16 nTopLineDist = lcl_GetTopLineDist( *this ); + const sal_uInt16 nBottomLineSize = lcl_GetBottomLineSize( *this ); + const sal_uInt16 nBottomLineDist = lcl_GetBottomLineDist( *this ); + + + const SwRowFrm* pPreviousRow = 0; + + // --> FME 2004-09-14 #i32456# + // In order to calculate the top printing area for the lower cell + // frames, we have to find the 'previous' row frame and compare + // the bottom values of the 'previous' row with the 'top' values + // of this row. The best way to find the 'previous' row is to + // use the table structure: + const SwTable* pTable = pTabFrm->GetTable(); + const SwTableLine* pPrevTabLine = 0; + const SwRowFrm* pTmpRow = this; + + while ( pTmpRow && !pPrevTabLine ) + { + sal_uInt16 nIdx = 0; + const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ? + pTmpRow->GetTabLine()->GetUpper()->GetTabLines() : + pTable->GetTabLines(); + + while ( rLines[ nIdx ] != pTmpRow->GetTabLine() ) + ++nIdx; + + if ( nIdx > 0 ) + { + // pTmpRow has a 'previous' row in the table structure: + pPrevTabLine = rLines[ nIdx - 1 ]; + } + else + { + // pTmpRow is a first row in the table structue. + // We go up in the table structure: + pTmpRow = pTmpRow->GetUpper()->GetUpper() && + pTmpRow->GetUpper()->GetUpper()->IsRowFrm() ? + static_cast<const SwRowFrm*>( pTmpRow->GetUpper()->GetUpper() ) : + 0; + } + } + + // If we found a 'previous' row, we look for the appropriate row frame: + if ( pPrevTabLine ) + { + SwIterator<SwRowFrm,SwFmt> aIter( *pPrevTabLine->GetFrmFmt() ); + for ( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() ) + { + // --> OD 2004-11-23 #115759# - do *not* take repeated + // headlines, because during split of table it can be + // invalid and thus can't provide correct border values. + if ( pRow->GetTabLine() == pPrevTabLine && + !pRow->IsRepeatedHeadline() ) + // <-- + { + pPreviousRow = pRow; + break; + } + } + } + // <-- + + sal_uInt16 nTopPrtMargin = nTopSpace; + if ( pPreviousRow ) + { + const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist; + if ( nTmpPrtMargin > nTopPrtMargin ) + nTopPrtMargin = nTmpPrtMargin; + } + + // table has to be notified if it has to change its lower + // margin due to changes of nBottomLineSize: + if ( !GetNext() && nBottomLineSize != GetBottomLineSize() ) + pTabFrm->_InvalidatePrt(); + + // If there are rows nested inside this row, the nested rows + // may not have been calculated yet. Therefore the + // ::lcl_CalcMinRowHeight( this ) operation later in this + // function cannot consider the correct border values. We + // have to trigger the invalidation of the outer row frame + // manually: + // Note: If any further invalidations should be necessary, we + // should consider moving the invalidation stuff to the + // appropriate SwNotify object. + if ( GetUpper()->GetUpper()->IsRowFrm() && + ( nBottomLineDist != GetBottomMarginForLowers() || + nTopPrtMargin != GetTopMarginForLowers() ) ) + GetUpper()->GetUpper()->_InvalidateSize(); + + SetBottomMarginForLowers( nBottomLineDist ); // 3. + SetBottomLineSize( nBottomLineSize ); // 4. + SetTopMarginForLowers( nTopPrtMargin ); // 5. + + } +// <-- collapsing + } + + while ( !bValidSize ) + { + bValidSize = sal_True; + +#if OSL_DEBUG_LEVEL > 1 + if ( HasFixSize() ) + { + const SwFmtFrmSize &rFrmSize = GetFmt()->GetFrmSize(); + OSL_ENSURE( rFrmSize.GetSize().Height() > 0, "Hat ihn" ); + } +#endif + const SwTwips nDiff = (Frm().*fnRect->fnGetHeight)() - + ( HasFixSize() && !IsRowSpanLine() + ? pAttrs->GetSize().Height() + // --> OD 2004-10-04 #i26945# + : ::lcl_CalcMinRowHeight( this, + FindTabFrm()->IsConsiderObjsForMinCellHeight() ) ); + // <-- + if ( nDiff ) + { + bFixSize = sal_False; + if ( nDiff > 0 ) + Shrink( nDiff, sal_False, sal_True ); + else if ( nDiff < 0 ) + Grow( -nDiff ); + bFixSize = bFix; + } + } + + // last row will fill the space in its upper. + if ( !GetNext() ) + { + //Der letzte fuellt den verbleibenden Raum im Upper aus. + SwTwips nDiff = (GetUpper()->Prt().*fnRect->fnGetHeight)(); + SwFrm *pSibling = GetUpper()->Lower(); + do + { nDiff -= (pSibling->Frm().*fnRect->fnGetHeight)(); + pSibling = pSibling->GetNext(); + } while ( pSibling ); + if ( nDiff > 0 ) + { + bFixSize = sal_False; + Grow( nDiff ); + bFixSize = bFix; + bValidSize = sal_True; + } + } +} + +/************************************************************************* +|* +|* SwRowFrm::AdjustCells() +|* +|*************************************************************************/ +void SwRowFrm::AdjustCells( const SwTwips nHeight, const sal_Bool bHeight ) +{ + SwFrm *pFrm = Lower(); + if ( bHeight ) + { + SwRootFrm *pRootFrm = getRootFrm(); + SWRECTFN( this ) + SwRect aOldFrm; + + while ( pFrm ) + { + SwFrm* pNotify = 0; + + SwCellFrm* pCellFrm = static_cast<SwCellFrm*>(pFrm); + + // NEW TABLES + // Which cells need to be adjusted if the current row changes + // its height? + + // Current frame is a covered frame: + // Set new height for covered cell and adjust master cell: + if ( pCellFrm->GetTabBox()->getRowSpan() < 1 ) + { + // Set height of current (covered) cell to new line height. + const long nDiff = nHeight - (pCellFrm->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + { + (pCellFrm->Frm().*fnRect->fnAddBottom)( nDiff ); + pCellFrm->_InvalidatePrt(); + } + } + + SwCellFrm* pToAdjust = 0; + SwFrm* pToAdjustRow = 0; + + // If current frame is covered frame, we still want to adjust the + // height of the cell starting the row span + if ( pCellFrm->GetLayoutRowSpan() < 1 ) + { + pToAdjust = const_cast< SwCellFrm*>(&pCellFrm->FindStartEndOfRowSpanCell( true, true )); + pToAdjustRow = pToAdjust->GetUpper(); + } + else + { + pToAdjust = pCellFrm; + pToAdjustRow = this; + } + + // Set height of master cell to height of all lines spanned by this line. + long nRowSpan = pToAdjust->GetLayoutRowSpan(); + SwTwips nSumRowHeight = 0; + while ( pToAdjustRow ) + { + // Use new height for the current row: + nSumRowHeight += pToAdjustRow == this ? + nHeight : + (pToAdjustRow->Frm().*fnRect->fnGetHeight)(); + + if ( nRowSpan-- == 1 ) + break; + + pToAdjustRow = pToAdjustRow->GetNext(); + } + + if ( pToAdjustRow && pToAdjustRow != this ) + pToAdjustRow->_InvalidateSize(); + + const long nDiff = nSumRowHeight - (pToAdjust->Frm().*fnRect->fnGetHeight)(); + if ( nDiff ) + { + aOldFrm = pToAdjust->Frm(); + (pToAdjust->Frm().*fnRect->fnAddBottom)( nDiff ); + pNotify = pToAdjust; + } + + if ( pNotify ) + { + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && pRootFrm->GetCurrShell() ) + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( pNotify, aOldFrm ); + + pNotify->_InvalidatePrt(); + } + + pFrm = pFrm->GetNext(); + } + } + else + { while ( pFrm ) + { + pFrm->_InvalidateAll(); + pFrm = pFrm->GetNext(); + } + } + InvalidatePage(); +} + +/************************************************************************* +|* +|* SwRowFrm::Cut() +|* +|*************************************************************************/ +void SwRowFrm::Cut() +{ + SwTabFrm *pTab = FindTabFrm(); + if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() ) + { + pTab->FindMaster()->InvalidatePos(); + } + + // --> OD 2010-02-17 #i103961# + // notification for accessibility + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell* pVSh = pRootFrm->GetCurrShell(); + if ( pVSh && pVSh->Imp() ) + { + SwFrm* pCellFrm( GetLower() ); + while ( pCellFrm ) + { + OSL_ENSURE( pCellFrm->IsCellFrm(), + "<SwRowFrm::Cut()> - unexpected type of SwRowFrm lower." ); + pVSh->Imp()->DisposeAccessibleFrm( pCellFrm ); + + pCellFrm = pCellFrm->GetNext(); + } + } + } + } + // <-- + + SwLayoutFrm::Cut(); +} + +/************************************************************************* +|* +|* SwRowFrm::GrowFrm() +|* +|*************************************************************************/ + + +SwTwips SwRowFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SwTwips nReal = 0; + + SwTabFrm* pTab = FindTabFrm(); + SWRECTFN( pTab ) + + bool bRestrictTableGrowth; + bool bHasFollowFlowLine = pTab->HasFollowFlowLine(); + + if ( GetUpper()->IsTabFrm() ) + { + const SwRowFrm* pFollowFlowRow = IsInSplitTableRow(); + bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine(); + } + else + { + OSL_ENSURE( GetUpper()->IsCellFrm(), "RowFrm->GetUpper neither table nor cell" ); + bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine; + OSL_ENSURE( !bRestrictTableGrowth || !GetNext(), + "GetFollowRow for row frame that has a Next" ); + + // + // There may still be some space left in my direct upper: + // + const SwTwips nAdditionalSpace = + (Frm().*fnRect->fnBottomDist)( (GetUpper()->GetUpper()->*fnRect->fnGetPrtBottom)() ); + if ( bRestrictTableGrowth && nAdditionalSpace > 0 ) + { + nReal = Min( nAdditionalSpace, nDist ); + nDist -= nReal; + if ( !bTst ) + (Frm().*fnRect->fnAddBottom)( nReal ); + } + } + + if ( bRestrictTableGrowth ) + pTab->SetRestrictTableGrowth( sal_True ); + else + { + // Ok, this looks like a hack, indeed, it is a hack. + // If the current row frame is inside another cell frame, + // and the current row frame has no follow, it should not + // be allowed to grow. In fact, setting bRestrictTableGrowth + // to 'false' does not work, because the surrounding RowFrm + // would set this to 'true'. + pTab->SetFollowFlowLine( sal_False ); + } + + nReal += SwLayoutFrm::GrowFrm( nDist, bTst, bInfo); + + pTab->SetRestrictTableGrowth( sal_False ); + pTab->SetFollowFlowLine( bHasFollowFlowLine ); + + //Hoehe der Zellen auf den neuesten Stand bringen. + if ( !bTst ) + { + SWRECTFNX( this ) + AdjustCells( (Prt().*fnRectX->fnGetHeight)() + nReal, sal_True ); + if ( nReal ) + SetCompletePaint(); + } + + return nReal; +} + +/************************************************************************* +|* +|* SwRowFrm::ShrinkFrm() +|* +|*************************************************************************/ +SwTwips SwRowFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + if( HasFixSize() ) + { + AdjustCells( (Prt().*fnRect->fnGetHeight)(), sal_True ); + return 0L; + } + + //bInfo wird ggf. vom SwRowFrm::Format auf sal_True gesetzt, hier muss dann + //entsprechend reagiert werden + const sal_Bool bShrinkAnyway = bInfo; + + //Nur soweit Shrinken, wie es der Inhalt der groessten Zelle zulaesst. + SwTwips nRealDist = nDist; + { + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? + rSz.GetHeight() : + 0; + + // Only necessary to calculate minimal row height if height + // of pRow is at least nMinHeight. Otherwise nMinHeight is the + // minimum height. + if( nMinHeight < (Frm().*fnRect->fnGetHeight)() ) + { + // --> OD 2004-10-04 #i26945# + OSL_ENSURE( FindTabFrm(), "<SwRowFrm::ShrinkFrm(..)> - no table frame -> crash." ); + const bool bConsiderObjs( FindTabFrm()->IsConsiderObjsForMinCellHeight() ); + // <-- + nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs ); + } + + if ( ((Frm().*fnRect->fnGetHeight)() - nRealDist) < nMinHeight ) + nRealDist = (Frm().*fnRect->fnGetHeight)() - nMinHeight; + } + if ( nRealDist < 0 ) + nRealDist = 0; + + SwTwips nReal = nRealDist; + if ( nReal ) + { + if ( !bTst ) + { + SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( nHeight - nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !bRev ) + Frm().Pos().X() += nReal; + } + + SwTwips nTmp = GetUpper()->Shrink( nReal, bTst ); + if ( !bShrinkAnyway && !GetNext() && nTmp != nReal ) + { + //Der letzte bekommt den Rest im Upper und nimmt deshalb + //ggf. Ruecksichten (sonst: Endlosschleife) + if ( !bTst ) + { + nReal -= nTmp; + SwTwips nHeight = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( nHeight + nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !bRev ) + Frm().Pos().X() -= nReal; + } + nReal = nTmp; + } + } + + //Geeignet invalidieren und die Hoehe der Zellen auf den neuesten + //Stand bringen. + if ( !bTst ) + { + if ( nReal ) + { + if ( GetNext() ) + GetNext()->_InvalidatePos(); + _InvalidateAll(); + SetCompletePaint(); + + SwTabFrm *pTab = FindTabFrm(); + if ( !pTab->IsRebuildLastLine() && pTab->IsFollow() && + this == pTab->GetFirstNonHeadlineRow() ) + { + SwTabFrm* pMasterTab = const_cast< SwTabFrm* >( pTab->FindMaster() ); + pMasterTab->InvalidatePos(); + } + } + AdjustCells( (Prt().*fnRect->fnGetHeight)() - nReal, sal_True ); + } + return nReal; +} + +/************************************************************************* +|* +|* SwRowFrm::IsRowSplitAllowed() +|* +|*************************************************************************/ +bool SwRowFrm::IsRowSplitAllowed() const +{ + // Fixed size rows are never allowed to split: + if ( HasFixSize() ) + { + OSL_ENSURE( ATT_FIX_SIZE == GetFmt()->GetFrmSize().GetHeightSizeType(), "pRow claims to have fixed size" ); + return false; + } + + // Repeated headlines are never allowed to split: + const SwTabFrm* pTabFrm = FindTabFrm(); + if ( pTabFrm->GetTable()->GetRowsToRepeat() > 0 && + pTabFrm->IsInHeadline( *this ) ) + return false; + + const SwTableLineFmt* pFrmFmt = (SwTableLineFmt*)GetTabLine()->GetFrmFmt(); + const SwFmtRowSplit& rLP = pFrmFmt->GetRowSplit(); + return 0 != rLP.GetValue(); +} + +/************************************************************************* +|* +|* SwRowFrm::ShouldRowKeepWithNext() +|* +|*************************************************************************/ +bool SwRowFrm::ShouldRowKeepWithNext() const +{ + bool bRet = false; + + const SwCellFrm* pCell = static_cast<const SwCellFrm*>(Lower()); + const SwFrm* pTxt = pCell->Lower(); + + if ( pTxt && pTxt->IsTxtFrm() ) + { + bRet = static_cast<const SwTxtFrm*>(pTxt)->GetTxtNode()->GetSwAttrSet().GetKeep().GetValue(); + } + return bRet; +} + +/************************************************************************* +|* +|* SwCellFrm::SwCellFrm(), ~SwCellFrm() +|* +|*************************************************************************/ +SwCellFrm::SwCellFrm( const SwTableBox &rBox, SwFrm* pSib, bool bInsertContent ) : + SwLayoutFrm( rBox.GetFrmFmt(), pSib ), + pTabBox( &rBox ) +{ + nType = FRMC_CELL; + + if ( !bInsertContent ) + return; + + //Wenn ein StartIdx vorhanden ist, so werden CntntFrms in der Zelle + //angelegt, andernfalls muessen Rows vorhanden sein und diese werden + //angelegt. + if ( rBox.GetSttIdx() ) + { + sal_uLong nIndex = rBox.GetSttIdx(); + ::_InsertCnt( this, rBox.GetFrmFmt()->GetDoc(), ++nIndex ); + } + else + { + const SwTableLines &rLines = rBox.GetTabLines(); + SwFrm *pTmpPrev = 0; + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + { + SwRowFrm *pNew = new SwRowFrm( *rLines[i], this, bInsertContent ); + pNew->InsertBehind( this, pTmpPrev ); + pTmpPrev = pNew; + } + } +} + +SwCellFrm::~SwCellFrm() +{ + SwModify* pMod = GetFmt(); + if( pMod ) + { + // At this stage the lower frames aren't destroyed already, + // therfor we have to do a recursive dispose. + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->DisposeAccessibleFrm( this, sal_True ); + } + + pMod->Remove( this ); // austragen, + if( !pMod->GetDepends() ) + delete pMod; // und loeschen + } +} + +/************************************************************************* +|* +|* SwCellFrm::Format() +|* +|*************************************************************************/ +sal_Bool lcl_ArrangeLowers( SwLayoutFrm *pLay, long lYStart, sal_Bool bInva ) +{ + sal_Bool bRet = sal_False; + SwFrm *pFrm = pLay->Lower(); + SWRECTFN( pLay ) + while ( pFrm ) + { + long nFrmTop = (pFrm->Frm().*fnRect->fnGetTop)(); + if( nFrmTop != lYStart ) + { + bRet = sal_True; + const long lDiff = (*fnRect->fnYDiff)( lYStart, nFrmTop ); + const long lDiffX = lYStart - nFrmTop; + (pFrm->Frm().*fnRect->fnSubTop)( -lDiff ); + (pFrm->Frm().*fnRect->fnAddBottom)( lDiff ); + pFrm->SetCompletePaint(); + if ( !pFrm->GetNext() ) + pFrm->SetRetouche(); + if( bInva ) + pFrm->Prepare( PREP_POS_CHGD ); + if ( pFrm->IsLayoutFrm() && ((SwLayoutFrm*)pFrm)->Lower() ) + lcl_ArrangeLowers( (SwLayoutFrm*)pFrm, + (((SwLayoutFrm*)pFrm)->Lower()->Frm().*fnRect->fnGetTop)() + + lDiffX, bInva ); + if ( pFrm->GetDrawObjs() ) + { + for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + // --> OD 2004-10-08 #i26945# - check, if anchored object + // is lower of layout frame by checking, if the anchor + // frame, which contains the anchor position, is a lower + // of the layout frame. + if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrmContainingAnchPos() ) ) + { + continue; + } + // <-- + // --> OD 2005-08-08 #i52904# - distinguish between anchored + // objects, whose vertical position depends on its anchor + // frame and whose vertical position is independent + // from its anchor frame. + bool bVertPosDepOnAnchor( true ); + { + SwFmtVertOrient aVert( pAnchoredObj->GetFrmFmt().GetVertOrient() ); + switch ( aVert.GetRelationOrient() ) + { + case text::RelOrientation::PAGE_FRAME: + case text::RelOrientation::PAGE_PRINT_AREA: + bVertPosDepOnAnchor = false; + break; + default: break; + } + } + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + + // OD 2004-05-18 #i28701# - no direct move of objects, + // which are anchored to-paragraph/to-character, if + // the wrapping style influence has to be considered + // on the object positioning. + // --> OD 2005-08-08 #i52904# - no direct move of objects, + // whose vertical position doesn't depend on anchor frame. + const bool bDirectMove = + WEIT_WECH != pFly->Frm().Top() && + bVertPosDepOnAnchor && + !pFly->ConsiderObjWrapInfluenceOnObjPos(); + // <-- + if ( bDirectMove ) + { + (pFly->Frm().*fnRect->fnSubTop)( -lDiff ); + (pFly->Frm().*fnRect->fnAddBottom)( lDiff ); + pFly->GetVirtDrawObj()->SetRectsDirty(); + // --> OD 2004-08-17 - also notify view of <SdrObject> + // instance, which represents the Writer fly frame in + // the drawing layer + pFly->GetVirtDrawObj()->SetChanged(); + // <-- + // --> OD 2006-10-13 #i58280# + pFly->InvalidateObjRectWithSpaces(); + // <-- + } + + if ( pFly->IsFlyInCntFrm() ) + { + static_cast<SwFlyInCntFrm*>(pFly)->AddRefOfst( lDiff ); + // --> OD 2004-12-02 #115759# - reset current relative + // position to get re-positioned, if not directly moved. + if ( !bDirectMove ) + { + pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) ); + } + // <-- + } + else if( pFly->IsAutoPos() ) + { + pFly->AddLastCharY( lDiff ); + // OD 2004-05-18 #i28701# - follow-up of #i22341# + // <mnLastTopOfLine> has also been adjusted. + pFly->AddLastTopOfLineY( lDiff ); + } + // --> OD 2004-11-05 #i26945# - re-registration at + // page frame of anchor frame, if table frame isn't + // a follow table and table frame isn't in its + // rebuild of last line. + const SwTabFrm* pTabFrm = pLay->FindTabFrm(); + // --> OD 2004-11-23 #115759# + // - save: check, if table frame is found. + if ( pTabFrm && + !( pTabFrm->IsFollow() && + pTabFrm->FindMaster()->IsRebuildLastLine() ) && + pFly->IsFlyFreeFrm() ) + // <-- + { + SwPageFrm* pPageFrm = pFly->GetPageFrm(); + SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); + if ( pPageFrm != pPageOfAnchor ) + { + pFly->InvalidatePos(); + if ( pPageFrm ) + pPageFrm->MoveFly( pFly, pPageOfAnchor ); + else + pPageOfAnchor->AppendFlyToPage( pFly ); + } + } + // <-- + // OD 2004-05-11 #i28701# - Because of the introduction + // of new positionings and alignments (e.g. aligned at + // page area, but anchored at-character), the position + // of the Writer fly frame has to be invalidated. + pFly->InvalidatePos(); + + // --> OD 2004-11-04 #i26945# - follow-up of #i3317# + // No arrangement of lowers, if Writer fly frame isn't + // moved + if ( bDirectMove && + ::lcl_ArrangeLowers( pFly, + (pFly->*fnRect->fnGetPrtTop)(), + bInva ) ) + // <-- + { + pFly->SetCompletePaint(); + } + } + else if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) + { + // --> OD 2004-11-05 #i26945# + const SwTabFrm* pTabFrm = pLay->FindTabFrm(); + if ( pTabFrm && + !( pTabFrm->IsFollow() && + pTabFrm->FindMaster()->IsRebuildLastLine() ) && + !pAnchoredObj->GetFrmFmt().GetAnchor().GetAnchorId() + == FLY_AS_CHAR ) + { + SwPageFrm* pPageFrm = pAnchoredObj->GetPageFrm(); + SwPageFrm* pPageOfAnchor = pFrm->FindPageFrm(); + if ( pPageFrm != pPageOfAnchor ) + { + pAnchoredObj->InvalidateObjPos(); + if ( pPageFrm ) + { + pPageFrm->RemoveDrawObjFromPage( *pAnchoredObj ); + } + pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj ); + } + } + // --> OD 2004-07-01 #i28701# - adjust last character + // rectangle and last top of line. + pAnchoredObj->AddLastCharY( lDiff ); + pAnchoredObj->AddLastTopOfLineY( lDiff ); + // --> OD 2005-08-08 #i52904# - re-introduce direct move + // of drawing objects + const bool bDirectMove = + static_cast<const SwDrawFrmFmt&>(pAnchoredObj->GetFrmFmt()).IsPosAttrSet() && + bVertPosDepOnAnchor && + !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos(); + if ( bDirectMove ) + { + SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj ); + if ( bVert ) + { + pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) ); + } + else + { + pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) ); + } + // --> OD 2006-10-13 #i58280# + pAnchoredObj->InvalidateObjRectWithSpaces(); + // <-- + } + // <-- + pAnchoredObj->InvalidateObjPos(); + } + else + { + OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" ); + } + } + } + } + // Columns and cells are ordered horizontal, not vertical + if( !pFrm->IsColumnFrm() && !pFrm->IsCellFrm() ) + lYStart = (*fnRect->fnYInc)( lYStart, + (pFrm->Frm().*fnRect->fnGetHeight)() ); + + // Nowadays, the content inside a cell can flow into the follow table. + // Thus, the cell may only grow up to the end of the environment. + // So the content may have grown, but the cell could not grow. + // Therefore we have to trigger a formatting for the frames, which do + // not fit into the cell anymore: + SwTwips nDistanceToUpperPrtBottom = + (pFrm->Frm().*fnRect->fnBottomDist)( (pLay->*fnRect->fnGetPrtBottom)()); + // --> OD 2006-01-19 #i56146# - Revise fix of issue #i26945# + // do *not* consider content inside fly frames, if it's an undersized paragraph. + // --> OD 2004-10-08 #i26945# - consider content inside fly frames + if ( nDistanceToUpperPrtBottom < 0 && + ( ( pFrm->IsInFly() && + ( !pFrm->IsTxtFrm() || + !static_cast<SwTxtFrm*>(pFrm)->IsUndersized() ) ) || + pFrm->IsInSplitTableRow() ) ) + // <-- + { + pFrm->InvalidatePos(); + } + + pFrm = pFrm->GetNext(); + } + return bRet; +} + +void SwCellFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "CellFrm::Format, pAttrs ist 0." ); + const SwTabFrm* pTab = FindTabFrm(); + SWRECTFN( pTab ) + + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + + //Position einstellen. + if ( Lower() ) + { + SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace; + // --> collapsing borders FME 2005-05-27 #i29550# + if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrm() ) + { + const SvxBoxItem& rBoxItem = pAttrs->GetBox(); + nLeftSpace = rBoxItem.GetDistance( BOX_LINE_LEFT ); + nRightSpace = rBoxItem.GetDistance( BOX_LINE_RIGHT ); + nTopSpace = ((SwRowFrm*)GetUpper())->GetTopMarginForLowers(); + nBottomSpace = ((SwRowFrm*)GetUpper())->GetBottomMarginForLowers(); + } + else + { + // <-- collapsing + // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)> + nLeftSpace = pAttrs->CalcLeft( this ); + nRightSpace = pAttrs->CalcRight( this ); + nTopSpace = pAttrs->CalcTop(); + nBottomSpace = pAttrs->CalcBottom(); + } + (this->*fnRect->fnSetXMargins)( nLeftSpace, nRightSpace ); + (this->*fnRect->fnSetYMargins)( nTopSpace, nBottomSpace ); + } + } + // --> OD 2004-10-04 #i26945# + long nRemaining = GetTabBox()->getRowSpan() >= 1 ? + ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) : + 0; + // <-- + if ( !bValidSize ) + { + bValidSize = sal_True; + + //Die VarSize der CellFrms ist immer die Breite. + //Tatsaechlich ist die Breite jedoch nicht Variabel, sie wird durch das + //Format vorgegeben. Dieser Vorgegebene Wert muss aber nun wiederum + //nicht der tatsaechlichen Breite entsprechen. Die Breite wird auf + //Basis des Attributes errechnet, der Wert im Attribut passt zu dem + //gewuenschten Wert des TabFrms. Anpassungen die dort vorgenommen + //wurden werden hier Proportional beruecksichtigt. + //Wenn die Celle keinen Nachbarn mehr hat beruecksichtigt sie nicht + //die Attribute, sonder greift sich einfach den Rest des + //Uppers + SwTwips nWidth; + if ( GetNext() ) + { + const SwTwips nWish = pTab->GetFmt()->GetFrmSize().GetWidth(); + nWidth = pAttrs->GetSize().Width(); + + OSL_ENSURE( nWish, "Tabelle ohne Breite?" ); + OSL_ENSURE( nWidth <= nWish, "Zelle breiter als Tabelle." ); + OSL_ENSURE( nWidth > 0, "Box without width" ); + + const long nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); + if ( nWish != nPrtWidth ) + { + // Avoid rounding problems, at least for the new table model + if ( pTab->GetTable()->IsNewModel() ) + { + // 1. sum of widths of cells up to this cell (in model) + const SwTableLine* pTabLine = GetTabBox()->GetUpper(); + const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes(); + const SwTableBox* pTmpBox = 0; + + SwTwips nSumWidth = 0; + sal_uInt16 i = 0; + do + { + pTmpBox = rBoxes[ i++ ]; + nSumWidth += pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth(); + } + while ( pTmpBox != GetTabBox() ); + + // 2. calculate actual width of cells up to this one + double nTmpWidth = nSumWidth; + nTmpWidth *= nPrtWidth; + nTmpWidth /= nWish; + nWidth = (SwTwips)nTmpWidth; + + // 3. calculate frame widths of cells up to this one: + const SwFrm* pTmpCell = static_cast<const SwLayoutFrm*>(GetUpper())->Lower(); + SwTwips nSumFrameWidths = 0; + while ( pTmpCell != this ) + { + nSumFrameWidths += (pTmpCell->Frm().*fnRect->fnGetWidth)(); + pTmpCell = pTmpCell->GetNext(); + } + + nWidth = nWidth - nSumFrameWidths; + } + else + { + // #i12092# use double instead of long, + // otherwise this could lead to overflows + double nTmpWidth = nWidth; + nTmpWidth *= nPrtWidth; + nTmpWidth /= nWish; + nWidth = (SwTwips)nTmpWidth; + } + } + } + else + { + OSL_ENSURE( pAttrs->GetSize().Width() > 0, "Box without width" ); + nWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)(); + SwFrm *pPre = GetUpper()->Lower(); + while ( pPre != this ) + { + nWidth -= (pPre->Frm().*fnRect->fnGetWidth)(); + pPre = pPre->GetNext(); + } + } + const long nDiff = nWidth - (Frm().*fnRect->fnGetWidth)(); + if( IsNeighbourFrm() && IsRightToLeft() ) + (Frm().*fnRect->fnSubLeft)( nDiff ); + else + (Frm().*fnRect->fnAddRight)( nDiff ); + (Prt().*fnRect->fnAddRight)( nDiff ); + + //Jetzt die Hoehe einstellen, sie wird vom Inhalt und den Raendern + //bestimmt. + const long nDiffHeight = nRemaining - (Frm().*fnRect->fnGetHeight)(); + if ( nDiffHeight ) + { + if ( nDiffHeight > 0 ) + { + //Wieder validieren wenn kein Wachstum stattgefunden hat. + //Invalidiert wird durch AdjustCells von der Row. + if ( !Grow( nDiffHeight ) ) + bValidSize = bValidPrtArea = sal_True; + } + else + { + //Nur dann invalidiert lassen, wenn tatsaechlich + //geshrinkt wurde; das kann abgelehnt werden, weil alle + //nebeneinanderliegenden Zellen gleichgross sein muessen. + if ( !Shrink( -nDiffHeight ) ) + bValidSize = bValidPrtArea = sal_True; + } + } + } + const SwFmtVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient(); + + if ( !Lower() ) + return; + + // From now on, all operations are related to the table cell. + SWREFRESHFN( this ) + + SwPageFrm* pPg = 0; + if ( !FindTabFrm()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() && + // --> OD 2008-07-16 #158225# no vertical alignment of covered cells + !IsCoveredCell() && + // <-- + // --> FME 2004-06-29 #116532# Do not consider vertical alignment in grid mode + !(pPg = FindPageFrm())->HasGrid() ) + // <-- + { + if ( !Lower()->IsCntntFrm() && !Lower()->IsSctFrm() && !Lower()->IsTabFrm() ) + { + // OSL_ENSURE(fuer HTML-Import! + OSL_ENSURE( !this, "VAlign an Zelle ohne Inhalt" ); + return; + } + sal_Bool bVertDir = sal_True; + // --> OD 2005-03-30 #i43913# - no vertical alignment, if wrapping + // style influence is considered on object positioning and + // an object is anchored inside the cell. + const bool bConsiderWrapOnObjPos( GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ); + // <-- + //Keine Ausrichtung wenn Rahmen mit Umlauf in die Zelle ragen. + if ( pPg->GetSortedObjs() ) + { + SwRect aRect( Prt() ); aRect += Frm().Pos(); + for ( sal_uInt16 i = 0; i < pPg->GetSortedObjs()->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pPg->GetSortedObjs())[i]; + SwRect aTmp( pAnchoredObj->GetObjRect() ); + if ( aTmp.IsOver( aRect ) ) + { + const SwFrmFmt& rAnchoredObjFrmFmt = pAnchoredObj->GetFrmFmt(); + const SwFmtSurround &rSur = rAnchoredObjFrmFmt.GetSurround(); + + if ( SURROUND_THROUGHT != rSur.GetSurround() ) + { + // frames, which the cell is a lower of, aren't relevant + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + const SwFlyFrm *pFly = + static_cast<const SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsAnLower( this ) ) + continue; + } + + const SwFrm* pAnch = pAnchoredObj->GetAnchorFrm(); + // --> OD 2005-03-30 #i43913# + // --> OD 2005-08-08 #i52904# - no vertical alignment, + // if object, anchored inside cell, has temporarly + // consider its wrapping style on object positioning. + // --> FME 2006-02-01 #i58806# - no vertical alignment + // if object does not follow the text flow. + if ( bConsiderWrapOnObjPos || + !IsAnLower( pAnch ) || + pAnchoredObj->IsTmpConsiderWrapInfluence() || + !rAnchoredObjFrmFmt.GetFollowTextFlow().GetValue() ) + // <-- + { + bVertDir = sal_False; + break; + } + } + } + } + } + + long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) || + (Lower()->Frm().*fnRect->fnGetTop)() != (this->*fnRect->fnGetPrtTop)() ) + { + long nDiff = (Prt().*fnRect->fnGetHeight)() - nRemaining; + if ( nDiff >= 0 ) + { + long lTopOfst = 0; + if ( bVertDir ) + { + switch ( rOri.GetVertOrient() ) + { + case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break; + case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break; + default: break; + }; + } + long nTmp = (*fnRect->fnYInc)( + (this->*fnRect->fnGetPrtTop)(), lTopOfst ); + if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) ) + SetCompletePaint(); + } + } + } + else + { + //Ist noch eine alte Ausrichtung beruecksichtigt worden? + if ( Lower()->IsCntntFrm() ) + { + const long lYStart = (this->*fnRect->fnGetPrtTop)(); + lcl_ArrangeLowers( this, lYStart, sal_True ); + } + } +} + +/************************************************************************* +|* +|* SwCellFrm::Modify() +|* +|*************************************************************************/ + +void SwCellFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_Bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which(); + const SfxPoolItem *pItem = 0; + + if( bAttrSetChg ) + ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, sal_False, &pItem); + else if ( RES_VERT_ORIENT == pNew->Which() ) + pItem = pNew; + + if ( pItem ) + { + sal_Bool bInva = sal_True; + if ( text::VertOrientation::NONE == ((SwFmtVertOrient*)pItem)->GetVertOrient() && + // OD 04.11.2003 #112910# + Lower() && Lower()->IsCntntFrm() ) + { + SWRECTFN( this ) + const long lYStart = (this->*fnRect->fnGetPrtTop)(); + bInva = lcl_ArrangeLowers( this, lYStart, sal_False ); + } + if ( bInva ) + { + SetCompletePaint(); + InvalidatePrt(); + } + } + + if ( ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_PROTECT, sal_False ) ) || + RES_PROTECT == pNew->Which() ) + { + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh && pSh->GetLayout()->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleEditableState( sal_True, this ); + } + + if ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, sal_False, &pItem ) ) + { + SetDerivedVert( sal_False ); + CheckDirChange(); + } + + // --> collapsing borders FME 2005-05-27 #i29550# + if ( bAttrSetChg && + SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState( RES_BOX, sal_False, &pItem ) ) + { + SwFrm* pTmpUpper = GetUpper(); + while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrm() ) + pTmpUpper = pTmpUpper->GetUpper(); + + SwTabFrm* pTabFrm = (SwTabFrm*)pTmpUpper->GetUpper(); + if ( pTabFrm->IsCollapsingBorders() ) + { + // Invalidate lowers of this and next row: + lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); + pTmpUpper = pTmpUpper->GetNext(); + if ( pTmpUpper ) + lcl_InvalidateAllLowersPrt( (SwRowFrm*)pTmpUpper ); + else + pTabFrm->InvalidatePrt(); + } + } + // <-- collapsing + + SwLayoutFrm::Modify( pOld, pNew ); +} + +/************************************************************************* +|* SwCellFrm::GetLayoutRowSpan() const +|*************************************************************************/ + +long SwCellFrm::GetLayoutRowSpan() const +{ + long nRet = GetTabBox()->getRowSpan(); + if ( nRet < 1 ) + { + const SwFrm* pRow = GetUpper(); + const SwTabFrm* pTab = static_cast<const SwTabFrm*>(pRow->GetUpper()); + + if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() ) + nRet = -nRet; + } + return nRet; +} + +// --> OD 2010-02-17 #i103961# +void SwCellFrm::Cut() +{ + // notification for accessibility + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() ) + { + ViewShell* pVSh = pRootFrm->GetCurrShell(); + if ( pVSh && pVSh->Imp() ) + { + pVSh->Imp()->DisposeAccessibleFrm( this ); + } + } + } + + SwLayoutFrm::Cut(); +} +// <-- + +// +// Helper functions for repeated headlines: +// + +/* + * SwTabFrm::IsInHeadline( const SwFrm& rFrm ) + */ +bool SwTabFrm::IsInHeadline( const SwFrm& rFrm ) const +{ + OSL_ENSURE( IsAnLower( &rFrm ) && rFrm.IsInTab(), + "SwTabFrm::IsInHeadline called for frame not lower of table" ); + + const SwFrm* pTmp = &rFrm; + while ( !pTmp->GetUpper()->IsTabFrm() ) + pTmp = pTmp->GetUpper(); + + return GetTable()->IsHeadline( *((SwRowFrm*)pTmp)->GetTabLine() ); +} + +/* + * SwTabFrm::GetFirstNonHeadlineRow() + * + * If this is a master table, we can may assume, that there are at least + * nRepeat lines in the table. + * If this is a follow table, there are intermediate states for the table + * layout, e.g., during deletion of rows, which makes it necessary to find + * the first non-headline row by evaluating the headline flag at the row frame. + */ +SwRowFrm* SwTabFrm::GetFirstNonHeadlineRow() const +{ + SwRowFrm* pRet = (SwRowFrm*)Lower(); + if ( pRet ) + { + if ( IsFollow() ) + { + while ( pRet && pRet->IsRepeatedHeadline() ) + pRet = (SwRowFrm*)pRet->GetNext(); + } + else + { + sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + while ( pRet && nRepeat > 0 ) + { + pRet = (SwRowFrm*)pRet->GetNext(); + --nRepeat; + } + } + } + + return (SwRowFrm*)pRet; +} + +/* + * SwTable::IsHeadline() + */ +bool SwTable::IsHeadline( const SwTableLine& rLine ) const +{ + for ( sal_uInt16 i = 0; i < GetRowsToRepeat(); ++i ) + if ( GetTabLines()[ i ] == &rLine ) + return true; + + return false; +} + +bool SwTabFrm::IsLayoutSplitAllowed() const +{ + return GetFmt()->GetLayoutSplit().GetValue(); +} + +// --> collapsing borders FME 2005-05-27 #i29550# + +sal_uInt16 SwTabFrm::GetBottomLineSize() const +{ + OSL_ENSURE( IsCollapsingBorders(), + "BottomLineSize only required for collapsing borders" ); + + OSL_ENSURE( Lower(), "Warning! Trying to prevent a crash, please inform FME" ); + + const SwFrm* pTmp = GetLastLower(); + + // --> FME 2005-12-07 #124755# Try to make code robust: + if ( !pTmp ) return 0; + // <-- + + return static_cast<const SwRowFrm*>(pTmp)->GetBottomLineSize(); +} + +bool SwTabFrm::IsCollapsingBorders() const +{ + return ((SfxBoolItem&)GetFmt()->GetAttrSet().Get( RES_COLLAPSING_BORDERS )).GetValue(); +} + +// <-- collapsing + + +// +// Local helper function to calculate height of first text row +// +SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrm& rSourceLine ) +{ + // Find corresponding split line in master table + const SwTabFrm* pTab = rSourceLine.FindTabFrm(); + SWRECTFN( pTab ) + const SwCellFrm* pCurrSourceCell = (SwCellFrm*)rSourceLine.Lower(); + + // + // 1. Case: rSourceLine is a follow flow line. + // In this case we have to return the minimum of the heights + // of the first lines in rSourceLine. + // + // 2. Case: rSourceLine is not a follow flow line. + // In this case we have to return the maximum of the heights + // of the first lines in rSourceLine. + // + bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow(); + SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0; + + while ( pCurrSourceCell ) + { + // NEW TABLES + // Skip cells which are not responsible for the height of + // the follow flow line: + if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 ) + { + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + continue; + } + + const SwFrm *pTmp = pCurrSourceCell->Lower(); + if ( pTmp ) + { + SwTwips nTmpHeight = USHRT_MAX; + // --> FME 2004-09-14 #i32456# Consider lower row frames + if ( pTmp->IsRowFrm() ) + { + const SwRowFrm* pTmpSourceRow = (SwRowFrm*)pCurrSourceCell->Lower(); + nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow ); + } + // <-- + if ( pTmp->IsTabFrm() ) + { + nTmpHeight = ((SwTabFrm*)pTmp)->CalcHeightOfFirstContentLine(); + } + else if ( pTmp->IsTxtFrm() ) + { + SwTxtFrm* pTxtFrm = (SwTxtFrm*)pTmp; + pTxtFrm->GetFormatted(); + nTmpHeight = pTxtFrm->FirstLineHeight(); + } + + if ( USHRT_MAX != nTmpHeight ) + { + const SwCellFrm* pPrevCell = pCurrSourceCell->GetPreviousCell(); + if ( pPrevCell ) + { + // If we are in a split row, there may be some space + // left in the cell frame of the master row. + // We look for the minimum of all first line heights; + SwTwips nReal = (pPrevCell->Prt().*fnRect->fnGetHeight)(); + const SwFrm* pFrm = pPrevCell->Lower(); + const SwFrm* pLast = pFrm; + while ( pFrm ) + { + nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); + pLast = pFrm; + pFrm = pFrm->GetNext(); + } + + // --> FME, OD 2004-07-15 #i26831#, #i26520# + // The additional lower space of the current last. + // --> OD 2004-11-25 #115759# - do *not* consider the + // additional lower space for 'master' text frames + if ( pLast && pLast->IsFlowFrm() && + ( !pLast->IsTxtFrm() || + !static_cast<const SwTxtFrm*>(pLast)->GetFollow() ) ) + // <-- + { + nReal += SwFlowFrm::CastFlowFrm(pLast)->CalcAddLowerSpaceAsLastInTableCell(); + } + // Don't forget the upper space and lower space, + // --> OD 2004-11-25 #115759# - do *not* consider the upper + // and the lower space for follow text frames. + if ( pTmp->IsFlowFrm() && + ( !pTmp->IsTxtFrm() || + !static_cast<const SwTxtFrm*>(pTmp)->IsFollow() ) ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace( NULL, pLast); + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); + } + // <-- + // --> OD 2004-11-25 #115759# - consider additional lower + // space of <pTmp>, if contains only one line. + // In this case it would be the new last text frame, which + // would have no follow and thus would add this space. + if ( pTmp->IsTxtFrm() && + const_cast<SwTxtFrm*>(static_cast<const SwTxtFrm*>(pTmp)) + ->GetLineCount( STRING_LEN ) == 1 ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp) + ->CalcAddLowerSpaceAsLastInTableCell(); + } + // <-- + if ( nReal > 0 ) + nTmpHeight -= nReal; + } + else + { + // pFirstRow is not a FollowFlowRow. In this case, + // we look for the maximum of all first line heights: + SwBorderAttrAccess aAccess( SwFrm::GetCache(), pCurrSourceCell ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom(); + // --> OD 2004-07-16 #i26250# + // Don't forget the upper space and lower space, + if ( pTmp->IsFlowFrm() ) + { + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcUpperSpace(); + nTmpHeight += SwFlowFrm::CastFlowFrm(pTmp)->CalcLowerSpace(); + } + // <-- + } + } + + if ( bIsInFollowFlowLine ) + { + // minimum + if ( nTmpHeight < nHeight ) + nHeight = nTmpHeight; + } + else + { + // maximum + if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight ) + nHeight = nTmpHeight; + } + } + + pCurrSourceCell = (SwCellFrm*)pCurrSourceCell->GetNext(); + } + + return ( LONG_MAX == nHeight ) ? 0 : nHeight; +} + +// +// Function to calculate height of first text row +// +SwTwips SwTabFrm::CalcHeightOfFirstContentLine() const +{ + SWRECTFN( this ) + + const bool bDontSplit = !IsFollow() && !GetFmt()->GetLayoutSplit().GetValue(); + + if ( bDontSplit ) + { + // Table is not allowed to split: Take the whole height, that's all + return (Frm().*fnRect->fnGetHeight)(); + } + + SwRowFrm* pFirstRow = 0; + SwTwips nTmpHeight = 0; + + pFirstRow = GetFirstNonHeadlineRow(); + OSL_ENSURE( !IsFollow() || pFirstRow, "FollowTable without Lower" ); + + // NEW TABLES + if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() ) + pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); + + // Calculate the height of the headlines: + const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat(); + SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0; + + // Calculate the height of the keeping lines + // (headlines + following keeping lines): + SwTwips nKeepHeight = nRepeatHeight; + if ( GetFmt()->GetDoc()->get(IDocumentSettingAccess::TABLE_ROW_KEEP) ) + { + sal_uInt16 nKeepRows = nRepeat; + + // Check how many rows want to keep together + while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() ) + { + ++nKeepRows; + pFirstRow = static_cast<SwRowFrm*>(pFirstRow->GetNext()); + } + + if ( nKeepRows > nRepeat ) + nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows ); + } + + // For master tables, the height of the headlines + the heigth of the + // keeping lines (if any) has to be considered. For follow tables, we + // only consider the height of the keeping rows without the repeated lines: + if ( !IsFollow() ) + { + nTmpHeight = nKeepHeight; + } + else + { + nTmpHeight = nKeepHeight - nRepeatHeight; + } + + // pFirstRow row is the first non-heading row. + // nTmpHeight is the height of the heading row if we are a follow. + if ( pFirstRow ) + { + const bool bSplittable = pFirstRow->IsRowSplitAllowed(); + const SwTwips nFirstLineHeight = (pFirstRow->Frm().*fnRect->fnGetHeight)(); + + if ( !bSplittable ) + { + // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow + // actually is determined by a lower cell with rowspan = -1. In this case we should not + // just return the height of the first line. Basically we need to get the height of the + // line as it would be on the last page. Since this is quite complicated to calculate, + // we olny calculate the height of the first line. + if ( pFirstRow->GetPrev() && + static_cast<SwRowFrm*>(pFirstRow->GetPrev())->IsRowSpanLine() ) + { + // Calculate maximum height of all cells with rowspan = 1: + SwTwips nMaxHeight = 0; + const SwCellFrm* pLower2 = static_cast<const SwCellFrm*>(pFirstRow->Lower()); + while ( pLower2 ) + { + if ( 1 == pLower2->GetTabBox()->getRowSpan() ) + { + const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, sal_True ); + nMaxHeight = Max( nCellHeight, nMaxHeight ); + } + pLower2 = static_cast<const SwCellFrm*>(pLower2->GetNext()); + } + nTmpHeight += nMaxHeight; + } + else + { + nTmpHeight += nFirstLineHeight; + } + } + + // --> FME 2004-11-18 #118411# + // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger + // a formatting of the row frame (via the GetFormatted()). We don't + // want this formatting if the row does not have a height. + else if ( 0 != nFirstLineHeight ) + // <-- + { + const bool bOldJoinLock = IsJoinLocked(); + ((SwTabFrm*)this)->LockJoin(); + const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *(SwRowFrm*)pFirstRow ); + + // Consider minimum row height: + const SwFmtFrmSize &rSz = static_cast<const SwRowFrm*>(pFirstRow)->GetFmt()->GetFrmSize(); + const SwTwips nMinRowHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? + rSz.GetHeight() : 0; + + nTmpHeight += Max( nHeightOfFirstContentLine, nMinRowHeight ); + + if ( !bOldJoinLock ) + ((SwTabFrm*)this)->UnlockJoin(); + } + } + + return nTmpHeight; +} + +// +// Some more functions for covered/covering cells. This way inclusion of +// SwCellFrm can be avoided +// + +bool SwFrm::IsLeaveUpperAllowed() const +{ + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + return pThisCell && pThisCell->GetLayoutRowSpan() > 1; +} + +bool SwFrm::IsCoveredCell() const +{ + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + return pThisCell && pThisCell->GetLayoutRowSpan() < 1; +} + +bool SwFrm::IsInCoveredCell() const +{ + bool bRet = false; + + const SwFrm* pThis = this; + while ( pThis && !pThis->IsCellFrm() ) + pThis = pThis->GetUpper(); + + if ( pThis ) + bRet = pThis->IsCoveredCell(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx new file mode 100644 index 000000000000..2673082d5468 --- /dev/null +++ b/sw/source/core/layout/trvlfrm.cxx @@ -0,0 +1,2611 @@ +/* -*- 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 <hints.hxx> +#include <tools/bigint.hxx> +#include <editeng/protitem.hxx> +#include <vcl/settings.hxx> +#include <vcl/outdev.hxx> +#include <fmtpdsc.hxx> +#include <fmtsrnd.hxx> +#include <pagedesc.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <ftnfrm.hxx> +#include <flyfrm.hxx> +#include <tabfrm.hxx> +#include <rowfrm.hxx> +#include <cellfrm.hxx> +#include <txtfrm.hxx> +#include <viewsh.hxx> +#include <viewopt.hxx> +#include <doc.hxx> +#include <viscrs.hxx> +#include <frmfmt.hxx> +#include <swtable.hxx> +#include <dflyobj.hxx> +#include <crstate.hxx> +#include <frmtool.hxx> +#include <ndtxt.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + +// FLT_MAX +#include <cfloat> +#include <swselectionlist.hxx> + +//Fuer SwFlyFrm::GetCrsrOfst +class SwCrsrOszControl +{ +public: + // damit schon der Compiler die Klasse initialisieren kann, keinen + // DTOR und member als publics: + const SwFlyFrm *pEntry; + const SwFlyFrm *pStk1; + const SwFlyFrm *pStk2; + +//public: +// SwCrsrOszControl() : pStk1( 0 ), pStk2( 0 ) {}; // ; <- ???? + + sal_Bool ChkOsz( const SwFlyFrm *pFly ) + { + sal_Bool bRet = sal_True; + if ( pFly != pStk1 && pFly != pStk2 ) + { + pStk1 = pStk2; + pStk2 = pFly; + bRet = sal_False; + } + return bRet; + } + void Entry( const SwFlyFrm *pFly ) + { + if ( !pEntry ) + pEntry = pStk1 = pFly; + } + void Exit( const SwFlyFrm *pFly ) + { + if ( pFly == pEntry ) + pEntry = pStk1 = pStk2 = 0; + } +}; + +static SwCrsrOszControl aOszCtrl = { 0, 0, 0 }; + +/************************************************************************* +|* +|* SwLayoutFrm::GetCrsrOfst() +|* +|* Beschreibung: Sucht denjenigen CntntFrm, innerhalb dessen +|* PrtArea der Point liegt. +|* +|*************************************************************************/ +sal_Bool SwLayoutFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + sal_Bool bRet = sal_False; + const SwFrm *pFrm = Lower(); + while ( !bRet && pFrm ) + { + pFrm->Calc(); + + // --> FME 2005-05-13 #i43742# New function: SW_CONTENT_CHECK + const bool bCntntCheck = pFrm->IsTxtFrm() && pCMS && pCMS->bCntntCheck; + const SwRect aPaintRect( bCntntCheck ? + pFrm->UnionFrm() : + pFrm->PaintArea() ); + // <-- + + if ( aPaintRect.IsInside( rPoint ) && + ( bCntntCheck || pFrm->GetCrsrOfst( pPos, rPoint, pCMS ) ) ) + bRet = sal_True; + else + pFrm = pFrm->GetNext(); + if ( pCMS && pCMS->bStop ) + return sal_False; + } + return bRet; +} + +/************************************************************************* +|* +|* SwPageFrm::GetCrsrOfst() +|* +|* Beschreibung: Sucht die Seite, innerhalb der der gesuchte Point +|* liegt. +|* +|*************************************************************************/ + +sal_Bool SwPageFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + sal_Bool bRet = sal_False; + Point aPoint( rPoint ); + + // check, if we have to adjust the point + if ( !Frm().IsInside( aPoint ) ) + { + aPoint.X() = Max( aPoint.X(), Frm().Left() ); + aPoint.X() = Min( aPoint.X(), Frm().Right() ); + aPoint.Y() = Max( aPoint.Y(), Frm().Top() ); + aPoint.Y() = Min( aPoint.Y(), Frm().Bottom() ); + } + + //Wenn kein Cntnt unterhalb der Seite 'antwortet', so korrigieren + //wir den StartPoint und fangen nochmal eine Seite vor der + //aktuellen an. Mit Flys ist es dann allerdings vorbei. + if ( SwLayoutFrm::GetCrsrOfst( pPos, aPoint, pCMS ) ) + bRet = sal_True; + else + { + if ( pCMS && (pCMS->bStop || pCMS->bExactOnly) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = sal_True; + return sal_False; + } + const SwCntntFrm *pCnt = GetCntntPos( aPoint, sal_False, sal_False, sal_False, pCMS, sal_False ); + if ( pCMS && pCMS->bStop ) + return sal_False; + + OSL_ENSURE( pCnt, "Crsr is gone to a Black hole" ); + if( pCMS && pCMS->pFill && pCnt->IsTxtFrm() ) + bRet = pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + else + bRet = pCnt->GetCrsrOfst( pPos, aPoint, pCMS ); + + if ( !bRet ) + { + // Set point to pCnt, delete mark + // this may happen, if pCnt is hidden + *pPos = SwPosition( *pCnt->GetNode(), SwIndex( (SwTxtNode*)pCnt->GetNode(), 0 ) ); + bRet = sal_True; + } + } + + if ( !bRet ) + { + //Koennte ein Freifliegender gemeint sein? + //Wenn sein Inhalt geschuetzt werden soll, so ist nix mit Crsr + //hineinsetzen, dadurch sollten alle Aenderungen unmoeglich sein. + if ( GetSortedObjs() ) + { + SwOrderIter aIter( this ); + aIter.Top(); + while ( aIter() ) + { + const SwVirtFlyDrawObj* pObj = + static_cast<const SwVirtFlyDrawObj*>(aIter()); + const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0; + if ( pFly && + ( ( pCMS ? pCMS->bSetInReadOnly : sal_False ) || + !pFly->IsProtected() ) && + pFly->GetCrsrOfst( pPos, aPoint, pCMS ) ) + { + bRet = sal_True; + break; + } + + if ( pCMS && pCMS->bStop ) + return sal_False; + aIter.Prev(); + } + } + } + + if ( bRet ) + rPoint = aPoint; + + return bRet; +} + +bool SwLayoutFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const +{ + bool bRet = false; + if( rRect.IsOver(PaintArea()) ) + { + const SwFrm* pFrm = Lower(); + while( pFrm ) + { + pFrm->FillSelection( rList, rRect ); + pFrm = pFrm->GetNext(); + } + } + return bRet; +} + +bool SwPageFrm::FillSelection( SwSelectionList& rList, const SwRect& rRect ) const +{ + bool bRet = false; + if( rRect.IsOver(PaintArea()) ) + { + bRet = SwLayoutFrm::FillSelection( rList, rRect ); + if( GetSortedObjs() ) + { + const SwSortedObjs &rObjs = *GetSortedObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = rObjs[i]; + if( !pAnchoredObj->ISA(SwFlyFrm) ) + continue; + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + if( pFly->FillSelection( rList, rRect ) ) + bRet = true; + } + } + } + return bRet; +} + +bool SwRootFrm::FillSelection( SwSelectionList& aSelList, const SwRect& rRect) const +{ + const SwFrm *pPage = Lower(); + const long nBottom = rRect.Bottom(); + while( pPage ) + { + if( pPage->Frm().Top() < nBottom ) + { + if( pPage->Frm().Bottom() > rRect.Top() ) + pPage->FillSelection( aSelList, rRect ); + pPage = pPage->GetNext(); + } + else + pPage = 0; + } + return !aSelList.isEmpty(); +} + +/************************************************************************* +|* +|* SwRootFrm::GetCrsrOfst() +|* +|* Beschreibung: Reicht Primaer den Aufruf an die erste Seite weiter. +|* Wenn der 'reingereichte Point veraendert wird, +|* so wird sal_False zurueckgegeben. +|* +|*************************************************************************/ +sal_Bool SwRootFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + sal_Bool bOldAction = IsCallbackActionEnabled(); + ((SwRootFrm*)this)->SetCallbackActionEnabled( sal_False ); + OSL_ENSURE( (Lower() && Lower()->IsPageFrm()), "Keinen PageFrm gefunden." ); + if( pCMS && pCMS->pFill ) + ((SwCrsrMoveState*)pCMS)->bFillRet = sal_False; + Point aOldPoint = rPoint; + + // PAGES01 + // search for page containing rPoint. The borders around the pages are considerd + const SwPageFrm* pPage = GetPageAtPos( rPoint, 0, true ); + + // --> OD 2008-12-23 #i95626# + // special handling for <rPoint> beyond root frames area + if ( !pPage && + rPoint.X() > Frm().Right() && + rPoint.Y() > Frm().Bottom() ) + { + pPage = dynamic_cast<const SwPageFrm*>(Lower()); + while ( pPage && pPage->GetNext() ) + { + pPage = dynamic_cast<const SwPageFrm*>(pPage->GetNext()); + } + } + // <-- + if ( pPage ) + { + pPage->SwPageFrm::GetCrsrOfst( pPos, rPoint, pCMS ); + } + + ((SwRootFrm*)this)->SetCallbackActionEnabled( bOldAction ); + if( pCMS ) + { + if( pCMS->bStop ) + return sal_False; + if( pCMS->pFill ) + return pCMS->bFillRet; + } + return aOldPoint == rPoint; +} + +/************************************************************************* +|* +|* SwCellFrm::GetCrsrOfst() +|* +|* Beschreibung Wenn es sich um eine Cntnt-tragende Cell handelt wird +|* der Crsr notfalls mit Gewalt in einen der CntntFrms +|* gesetzt. +|* In geschuetzte Zellen gibt es hier keinen Eingang. +|* +|*************************************************************************/ +sal_Bool SwCellFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + // cell frame does not necessarily have a lower (split table cell) + if ( !Lower() ) + return sal_False; + + if ( !(pCMS?pCMS->bSetInReadOnly:sal_False) && + GetFmt()->GetProtect().IsCntntProtected() ) + return sal_False; + + if ( pCMS && pCMS->eState == MV_TBLSEL ) + { + const SwTabFrm *pTab = FindTabFrm(); + if ( pTab->IsFollow() && pTab->IsInHeadline( *this ) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = sal_True; + return sal_False; + } + } + + if ( Lower() ) + { + if ( Lower()->IsLayoutFrm() ) + return SwLayoutFrm::GetCrsrOfst( pPos, rPoint, pCMS ); + else + { + Calc(); + sal_Bool bRet = sal_False; + + const SwFrm *pFrm = Lower(); + while ( pFrm && !bRet ) + { + pFrm->Calc(); + if ( pFrm->Frm().IsInside( rPoint ) ) + { + bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS ); + if ( pCMS && pCMS->bStop ) + return sal_False; + } + pFrm = pFrm->GetNext(); + } + if ( !bRet ) + { + Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; + const SwCntntFrm *pCnt = GetCntntPos( rPoint, sal_True ); + if( pPoint && pCnt->IsTxtFrm() ) + { + pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); + rPoint = *pPoint; + } + else + pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + delete pPoint; + } + return sal_True; + } + } + + return sal_False; +} + +/************************************************************************* +|* +|* SwFlyFrm::GetCrsrOfst() +|* +|*************************************************************************/ +//Problem: Wenn zwei Flys genau gleich gross sind und auf derselben +//Position stehen, so liegt jeder innerhalb des anderen. +//Da jeweils geprueft wird, ob der Point nicht zufaellig innerhalb eines +//anderen Flys liegt, der sich vollstaendig innerhalb des aktuellen befindet +//und ggf. ein rekursiver Aufruf erfolgt wuerde o.g. Situation zu einer +//endlosen Rekursion fuehren. +//Mit der Hilfsklasse SwCrsrOszControl unterbinden wir die Rekursion. Das +//GetCrsrOfst entscheidet sich bei einer Rekursion fuer denjenigen der +//am weitesten oben liegt. + +sal_Bool SwFlyFrm::GetCrsrOfst( SwPosition *pPos, Point &rPoint, + SwCrsrMoveState* pCMS ) const +{ + aOszCtrl.Entry( this ); + + //Wenn der Point innerhalb des Fly sitzt wollen wir energisch + //versuchen den Crsr hineinzusetzen. + //Wenn der Point allerdings in einem Flys sitzt, der sich vollstaendig + //innerhalb des aktuellen befindet, so wird fuer diesen das + //GetCrsrOfst gerufen. + Calc(); + sal_Bool bInside = Frm().IsInside( rPoint ) && Lower(), + bRet = sal_False; + + //Wenn der Frm eine Grafik enthaelt, aber nur Text gewuenscht ist, so + //nimmt er den Crsr grundsaetzlich nicht an. + if ( bInside && pCMS && pCMS->eState == MV_SETONLYTEXT && + (!Lower() || Lower()->IsNoTxtFrm()) ) + bInside = sal_False; + + const SwPageFrm *pPage = FindPageFrm(); + if ( bInside && pPage && pPage->GetSortedObjs() ) + { + SwOrderIter aIter( pPage ); + aIter.Top(); + while ( aIter() && !bRet ) + { + const SwVirtFlyDrawObj* pObj = static_cast<const SwVirtFlyDrawObj*>(aIter()); + const SwFlyFrm* pFly = pObj ? pObj->GetFlyFrm() : 0; + if ( pFly && pFly->Frm().IsInside( rPoint ) && + Frm().IsInside( pFly->Frm() ) ) + { + if ( aOszCtrl.ChkOsz( pFly ) || + sal_True == (bRet = pFly->GetCrsrOfst( pPos, rPoint, pCMS ))) + break; + if ( pCMS && pCMS->bStop ) + return sal_False; + } + aIter.Next(); + } + } + + while ( bInside && !bRet ) + { + const SwFrm *pFrm = Lower(); + while ( pFrm && !bRet ) + { + pFrm->Calc(); + if ( pFrm->Frm().IsInside( rPoint ) ) + { + bRet = pFrm->GetCrsrOfst( pPos, rPoint, pCMS ); + if ( pCMS && pCMS->bStop ) + return sal_False; + } + pFrm = pFrm->GetNext(); + } + if ( !bRet ) + { + Point *pPoint = pCMS && pCMS->pFill ? new Point( rPoint ) : NULL; + const SwCntntFrm *pCnt = GetCntntPos( + rPoint, sal_True, sal_False, sal_False, pCMS ); + if ( pCMS && pCMS->bStop ) + return sal_False; + if( pPoint && pCnt->IsTxtFrm() ) + { + pCnt->GetCrsrOfst( pPos, *pPoint, pCMS ); + rPoint = *pPoint; + } + else + pCnt->GetCrsrOfst( pPos, rPoint, pCMS ); + delete pPoint; + bRet = sal_True; + } + } + aOszCtrl.Exit( this ); + return bRet; +} + +/************************************************************************* +|* +|* Beschreibung Layoutabhaengiges Cursortravelling +|* +|*************************************************************************/ +sal_Bool SwCntntFrm::LeftMargin(SwPaM *pPam) const +{ + if( pPam->GetNode() != (SwCntntNode*)GetNode() ) + return sal_False; + ((SwCntntNode*)GetNode())-> + MakeStartIndex((SwIndex *) &pPam->GetPoint()->nContent); + return sal_True; +} + +sal_Bool SwCntntFrm::RightMargin(SwPaM *pPam, sal_Bool) const +{ + if( pPam->GetNode() != (SwCntntNode*)GetNode() ) + return sal_False; + ((SwCntntNode*)GetNode())-> + MakeEndIndex((SwIndex *) &pPam->GetPoint()->nContent); + return sal_True; +} + +const SwCntntFrm *lcl_GetNxtCnt( const SwCntntFrm* pCnt ) +{ + return pCnt->GetNextCntntFrm(); +} + +const SwCntntFrm *lcl_GetPrvCnt( const SwCntntFrm* pCnt ) +{ + return pCnt->GetPrevCntntFrm(); +} + +typedef const SwCntntFrm *(*GetNxtPrvCnt)( const SwCntntFrm* ); + +//Frame in wiederholter Headline? +sal_Bool lcl_IsInRepeatedHeadline( const SwFrm *pFrm, + const SwTabFrm** ppTFrm = 0 ) +{ + const SwTabFrm *pTab = pFrm->FindTabFrm(); + if( ppTFrm ) + *ppTFrm = pTab; + return pTab && pTab->IsFollow() && pTab->IsInHeadline( *pFrm ); +} + + +//Ueberspringen geschuetzter Tabellenzellen. Optional auch +//Ueberspringen von wiederholten Headlines. +//MA 26. Jan. 98: Chg auch andere Geschuetzte Bereiche ueberspringen. +// FME: Skip follow flow cells +const SwCntntFrm * MA_FASTCALL lcl_MissProtectedFrames( const SwCntntFrm *pCnt, + GetNxtPrvCnt fnNxtPrv, + sal_Bool bMissHeadline, + sal_Bool bInReadOnly, + sal_Bool bMissFollowFlowLine ) +{ + if ( pCnt && pCnt->IsInTab() ) + { + sal_Bool bProtect = sal_True; + while ( pCnt && bProtect ) + { + const SwLayoutFrm *pCell = pCnt->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + if ( !pCell || + (( ( bInReadOnly || !pCell->GetFmt()->GetProtect().IsCntntProtected() ) && + ( !bMissHeadline || !lcl_IsInRepeatedHeadline( pCell ) ) && + ( !bMissFollowFlowLine || !pCell->IsInFollowFlowRow() ) && + !pCell->IsCoveredCell()) ) ) + bProtect = sal_False; + else + pCnt = (*fnNxtPrv)( pCnt ); + } + } + else if ( !bInReadOnly ) + while ( pCnt && pCnt->IsProtected() ) + pCnt = (*fnNxtPrv)( pCnt ); + + return pCnt; +} + +sal_Bool MA_FASTCALL lcl_UpDown( SwPaM *pPam, const SwCntntFrm *pStart, + GetNxtPrvCnt fnNxtPrv, sal_Bool bInReadOnly ) +{ + OSL_ENSURE( pPam->GetNode() == (SwCntntNode*)pStart->GetNode(), + "lcl_UpDown arbeitet nicht fuer andere." ); + + const SwCntntFrm *pCnt = 0; + + //Wenn gerade eine Tabellenselection laeuft muss ein bischen getricktst + //werden: Beim hochlaufen an den Anfang der Zelle gehen, beim runterlaufen + //an das Ende der Zelle gehen. + sal_Bool bTblSel = false; + if ( pStart->IsInTab() && + pPam->GetNode( sal_True )->StartOfSectionNode() != + pPam->GetNode( sal_False )->StartOfSectionNode() ) + { + bTblSel = true; + const SwLayoutFrm *pCell = pStart->GetUpper(); + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + + // + // Check, if cell has a Prev/Follow cell: + // + const bool bFwd = ( fnNxtPrv == lcl_GetNxtCnt ); + const SwLayoutFrm* pTmpCell = bFwd ? + ((SwCellFrm*)pCell)->GetFollowCell() : + ((SwCellFrm*)pCell)->GetPreviousCell(); + + const SwCntntFrm* pTmpStart = pStart; + while ( pTmpCell && 0 != ( pTmpStart = pTmpCell->ContainsCntnt() ) ) + { + pCell = pTmpCell; + pTmpCell = bFwd ? + ((SwCellFrm*)pCell)->GetFollowCell() : + ((SwCellFrm*)pCell)->GetPreviousCell(); + } + const SwCntntFrm *pNxt = pCnt = pTmpStart; + + while ( pCell->IsAnLower( pNxt ) ) + { + pCnt = pNxt; + pNxt = (*fnNxtPrv)( pNxt ); + } + } + + pCnt = (*fnNxtPrv)( pCnt ? pCnt : pStart ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + + + const SwTabFrm *pStTab = pStart->FindTabFrm(); + const SwTabFrm *pTable = 0; + const sal_Bool bTab = pStTab || (pCnt && pCnt->IsInTab()) ? sal_True : sal_False; + sal_Bool bEnd = bTab ? sal_False : sal_True; + + const SwFrm* pVertRefFrm = pStart; + if ( bTblSel && pStTab ) + pVertRefFrm = pStTab; + SWRECTFN( pVertRefFrm ) + + SwTwips nX = 0; + if ( bTab ) + { + // + // pStart or pCnt is inside a table. nX will be used for travelling: + // + SwRect aRect( pStart->Frm() ); + pStart->GetCharRect( aRect, *pPam->GetPoint() ); + Point aCenter = aRect.Center(); + nX = bVert ? aCenter.Y() : aCenter.X(); + + pTable = pCnt ? pCnt->FindTabFrm() : 0; + if ( !pTable ) + pTable = pStTab; + + if ( pStTab && + !pStTab->GetUpper()->IsInTab() && + !pTable->GetUpper()->IsInTab() ) + { + const SwFrm *pCell = pStart->GetUpper(); + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + OSL_ENSURE( pCell, "Zelle nicht gefunden." ); + nX = (pCell->Frm().*fnRect->fnGetLeft)() + + (pCell->Frm().*fnRect->fnGetWidth)() / 2; + + //Der Fluss fuehrt von einer Tabelle in die nachste. Der X-Wert + //muss ausgehend von der Mitte der Startzelle um die Verschiebung + //der Tabellen korrigiert werden. + if ( pStTab != pTable ) + { + nX += (pTable->Frm().*fnRect->fnGetLeft)() - + (pStTab->Frm().*fnRect->fnGetLeft)(); + } + } + + // + // Restrict nX to the left and right borders of pTab: + // (is this really necessary?) + // + if ( !pTable->GetUpper()->IsInTab() ) + { + const sal_Bool bRTL = pTable->IsRightToLeft(); + const long nPrtLeft = bRTL ? + (pTable->*fnRect->fnGetPrtRight)() : + (pTable->*fnRect->fnGetPrtLeft)(); + if ( bRTL != (nX < nPrtLeft) ) + nX = nPrtLeft; + else + { + const long nPrtRight = bRTL ? + (pTable->*fnRect->fnGetPrtLeft)() : + (pTable->*fnRect->fnGetPrtRight)(); + if ( bRTL != (nX > nPrtRight) ) + nX = nPrtRight; + } + } + } + + do + { + //Wenn ich im DokumentBody bin, so will ich da auch bleiben + if ( pStart->IsInDocBody() ) + { + while ( pCnt && (!pCnt->IsInDocBody() || + (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()))) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + } + } + + //Wenn ich im Fussnotenbereich bin, so versuche ich notfalls den naechsten + //Fussnotenbereich zu erreichen. + else if ( pStart->IsInFtn() ) + { + while ( pCnt && (!pCnt->IsInFtn() || + (pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow()))) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + } + } + + //In Flys kann es Blind weitergehen solange ein Cntnt + //gefunden wird. + else if ( pStart->IsInFly() ) + { + if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + } + } + + //Andernfalls weigere ich mich einfach den derzeitigen Bereich zu + //verlassen. + else if ( pCnt ) + { + const SwFrm *pUp = pStart->GetUpper(); //Head/Foot + while ( pUp && pUp->GetUpper() && !(pUp->GetType() & 0x0018 ) ) + pUp = pUp->GetUpper(); + sal_Bool bSame = sal_False; + const SwFrm *pCntUp = pCnt->GetUpper(); + while ( pCntUp && !bSame ) + { if ( pUp == pCntUp ) + bSame = sal_True; + else + pCntUp = pCntUp->GetUpper(); + } + if ( !bSame ) + pCnt = 0; + else if ( pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow() ) // i73332 + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + } + } + + if ( bTab ) + { + if ( !pCnt ) + bEnd = sal_True; + else + { const SwTabFrm *pTab = pCnt->FindTabFrm(); + if( !pTab ) + bEnd = sal_True; + else + { + if ( pTab != pTable ) + { + //Der Fluss fuehrt von einer Tabelle in die nachste. Der + //X-Wert muss um die Verschiebung der Tabellen korrigiert + //werden. + if ( pTable && + !pTab->GetUpper()->IsInTab() && + !pTable->GetUpper()->IsInTab() ) + nX += pTab->Frm().Left() - pTable->Frm().Left(); + pTable = pTab; + } + const SwLayoutFrm *pCell = pTable ? pCnt->GetUpper() : 0; + while ( pCell && !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + + Point aInsideCell; + Point aInsideCnt; + if ( pCell ) + { + long nTmpTop = (pCell->Frm().*fnRect->fnGetTop)(); + if ( bVert ) + { + if ( nTmpTop ) + --nTmpTop; + + aInsideCell = Point( nTmpTop, nX ); + } + else + aInsideCell = Point( nX, nTmpTop ); + } + + long nTmpTop = (pCnt->Frm().*fnRect->fnGetTop)(); + if ( bVert ) + { + if ( nTmpTop ) + --nTmpTop; + + aInsideCnt = Point( nTmpTop, nX ); + } + else + aInsideCnt = Point( nX, nTmpTop ); + + if ( pCell && pCell->Frm().IsInside( aInsideCell ) ) + { + bEnd = sal_True; + //Jetzt noch schnell den richtigen Cntnt in der Zelle + //greifen. + if ( !pCnt->Frm().IsInside( aInsideCnt ) ) + { + pCnt = pCell->ContainsCntnt(); + if ( fnNxtPrv == lcl_GetPrvCnt ) + while ( pCell->IsAnLower(pCnt->GetNextCntntFrm()) ) + pCnt = pCnt->GetNextCntntFrm(); + } + } + else if ( pCnt->Frm().IsInside( aInsideCnt ) ) + bEnd = sal_True; + } + } + if ( !bEnd ) + { + pCnt = (*fnNxtPrv)( pCnt ); + pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, sal_True, bInReadOnly, bTblSel ); + } + } + + } while ( !bEnd || + (pCnt && pCnt->IsTxtFrm() && ((SwTxtFrm*)pCnt)->IsHiddenNow())); + + if( pCnt ) + { // setze den Point auf den Content-Node + SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode(); + pPam->GetPoint()->nNode = *pCNd; + if ( fnNxtPrv == lcl_GetPrvCnt ) + pCNd->MakeEndIndex( (SwIndex*)&pPam->GetPoint()->nContent ); + else + pCNd->MakeStartIndex( (SwIndex*)&pPam->GetPoint()->nContent ); + return sal_True; + } + return sal_False; +} + +sal_Bool SwCntntFrm::UnitUp( SwPaM* pPam, const SwTwips, sal_Bool bInReadOnly ) const +{ + return ::lcl_UpDown( pPam, this, lcl_GetPrvCnt, bInReadOnly ); +} + +sal_Bool SwCntntFrm::UnitDown( SwPaM* pPam, const SwTwips, sal_Bool bInReadOnly ) const +{ + return ::lcl_UpDown( pPam, this, lcl_GetNxtCnt, bInReadOnly ); +} + +/************************************************************************* +|* +|* SwRootFrm::GetCurrPage() +|* +|* Beschreibung: Liefert die Nummer der aktuellen Seite. +|* Wenn die Methode einen PaM bekommt, so ist die aktuelle Seite +|* diejenige in der der PaM sitzt. Anderfalls ist die aktuelle +|* Seite die erste Seite innerhalb der VisibleArea. +|* Es wird nur auf den vorhandenen Seiten gearbeitet! +|* +|*************************************************************************/ +sal_uInt16 SwRootFrm::GetCurrPage( const SwPaM *pActualCrsr ) const +{ + OSL_ENSURE( pActualCrsr, "Welche Seite soll's denn sein?" ); + SwFrm const*const pActFrm = pActualCrsr->GetPoint()->nNode.GetNode(). + GetCntntNode()->getLayoutFrm( this, 0, + pActualCrsr->GetPoint(), + sal_False ); + return pActFrm->FindPageFrm()->GetPhyPageNum(); +} + +/************************************************************************* +|* +|* SwRootFrm::SetCurrPage() +|* +|* Beschreibung: Liefert einen PaM der am Anfang der gewuenschten +|* Seite sitzt. +|* Formatiert wird soweit notwendig +|* Liefert Null, wenn die Operation nicht moeglich ist. +|* Der PaM sitzt in der letzten Seite, wenn die Seitenzahl zu gross +|* gewaehlt wurde. +|* +|*************************************************************************/ +sal_uInt16 SwRootFrm::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum ) +{ + OSL_ENSURE( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); + + SwPageFrm *pPage = (SwPageFrm*)Lower(); + sal_Bool bEnd =sal_False; + while ( !bEnd && pPage->GetPhyPageNum() != nPageNum ) + { if ( pPage->GetNext() ) + pPage = (SwPageFrm*)pPage->GetNext(); + else + { //Ersten CntntFrm Suchen, und solange Formatieren bis + //eine neue Seite angefangen wird oder bis die CntntFrm's alle + //sind. + const SwCntntFrm *pCntnt = pPage->ContainsCntnt(); + while ( pCntnt && pPage->IsAnLower( pCntnt ) ) + { + pCntnt->Calc(); + pCntnt = pCntnt->GetNextCntntFrm(); + } + //Jetzt ist entweder eine neue Seite da, oder die letzte Seite + //ist gefunden. + if ( pPage->GetNext() ) + pPage = (SwPageFrm*)pPage->GetNext(); + else + bEnd = sal_True; + } + } + //pPage zeigt jetzt auf die 'gewuenschte' Seite. Jetzt muss noch der + //PaM auf den Anfang des ersten CntntFrm im Body-Text erzeugt werden. + //Wenn es sich um eine Fussnotenseite handelt, wird der PaM in die erste + //Fussnote gesetzt. + const SwCntntFrm *pCntnt = pPage->ContainsCntnt(); + if ( pPage->IsFtnPage() ) + while ( pCntnt && !pCntnt->IsInFtn() ) + pCntnt = pCntnt->GetNextCntntFrm(); + else + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + if ( pCntnt ) + { + SwCntntNode* pCNd = (SwCntntNode*)pCntnt->GetNode(); + pToSet->GetPoint()->nNode = *pCNd; + pCNd->MakeStartIndex( (SwIndex*)&pToSet->GetPoint()->nContent ); + pToSet->GetPoint()->nContent = ((SwTxtFrm*)pCntnt)->GetOfst(); + + SwShellCrsr* pSCrsr = dynamic_cast<SwShellCrsr*>(pToSet); + if( pSCrsr ) + { + Point &rPt = pSCrsr->GetPtPos(); + rPt = pCntnt->Frm().Pos(); + rPt += pCntnt->Prt().Pos(); + } + return pPage->GetPhyPageNum(); + } + return 0; +} + +/************************************************************************* +|* +|* SwCntntFrm::StartxxPage(), EndxxPage() +|* +|* Beschreibung Cursor an Anfang/Ende der aktuellen/vorherigen/ +|* naechsten Seite. Alle sechs Methoden rufen GetFrmInPage() mit der +|* entsprechenden Parametrisierung. +|* Zwei Parameter steuern die Richtung: einer bestimmt die Seite, der +|* andere Anfang/Ende. +|* Fuer die Bestimmung der Seite und des Cntnt (Anfang/Ende) werden +|* die im folgenden definierten Funktionen benutzt. +|* +|*************************************************************************/ +SwCntntFrm *GetFirstSub( const SwLayoutFrm *pLayout ) +{ + return ((SwPageFrm*)pLayout)->FindFirstBodyCntnt(); +} + +SwCntntFrm *GetLastSub( const SwLayoutFrm *pLayout ) +{ + return ((SwPageFrm*)pLayout)->FindLastBodyCntnt(); +} + +SwLayoutFrm *GetNextFrm( const SwLayoutFrm *pFrm ) +{ + SwLayoutFrm *pNext = + (pFrm->GetNext() && pFrm->GetNext()->IsLayoutFrm()) ? + (SwLayoutFrm*)pFrm->GetNext() : 0; + // #i39402# in case of an empty page + if(pNext && !pNext->ContainsCntnt()) + pNext = (pNext->GetNext() && pNext->GetNext()->IsLayoutFrm()) ? + (SwLayoutFrm*)pNext->GetNext() : 0; + return pNext; +} + +SwLayoutFrm *GetThisFrm( const SwLayoutFrm *pFrm ) +{ + return (SwLayoutFrm*)pFrm; +} + +SwLayoutFrm *GetPrevFrm( const SwLayoutFrm *pFrm ) +{ + SwLayoutFrm *pPrev = + (pFrm->GetPrev() && pFrm->GetPrev()->IsLayoutFrm()) ? + (SwLayoutFrm*)pFrm->GetPrev() : 0; + // #i39402# in case of an empty page + if(pPrev && !pPrev->ContainsCntnt()) + pPrev = (pPrev->GetPrev() && pPrev->GetPrev()->IsLayoutFrm()) ? + (SwLayoutFrm*)pPrev->GetPrev() : 0; + return pPrev; +} + +//Jetzt koennen auch die Funktionspointer initalisiert werden; +//sie sind in cshtyp.hxx declariert. +SwPosPage fnPageStart = GetFirstSub; +SwPosPage fnPageEnd = GetLastSub; +SwWhichPage fnPagePrev = GetPrevFrm; +SwWhichPage fnPageCurr = GetThisFrm; +SwWhichPage fnPageNext = GetNextFrm; + +//Liefert den ersten/den letzten Contentframe (gesteuert ueber +//den Parameter fnPosPage) in der +//aktuellen/vorhergehenden/folgenden Seite (gesteuert durch den +//Parameter fnWhichPage). +sal_Bool GetFrmInPage( const SwCntntFrm *pCnt, SwWhichPage fnWhichPage, + SwPosPage fnPosPage, SwPaM *pPam ) +{ + //Erstmal die gewuenschte Seite besorgen, anfangs die aktuelle, dann + //die die per fnWichPage gewuenscht wurde + const SwLayoutFrm *pLayoutFrm = pCnt->FindPageFrm(); + if ( !pLayoutFrm || (0 == (pLayoutFrm = (*fnWhichPage)(pLayoutFrm))) ) + return sal_False; + + //Jetzt den gewuenschen CntntFrm unterhalb der Seite + if( 0 == (pCnt = (*fnPosPage)(pLayoutFrm)) ) + return sal_False; + else + { + // repeated headlines in tables + if ( pCnt->IsInTab() && fnPosPage == GetFirstSub ) + { + const SwTabFrm* pTab = pCnt->FindTabFrm(); + if ( pTab->IsFollow() ) + { + if ( pTab->IsInHeadline( *pCnt ) ) + { + SwLayoutFrm* pRow = pTab->GetFirstNonHeadlineRow(); + if ( pRow ) + { + // We are in the first line of a follow table + // with repeated headings. + // To actually make a "real" move we take the first content + // of the next row + pCnt = pRow->ContainsCntnt(); + if ( ! pCnt ) + return sal_False; + } + } + } + } + + SwCntntNode *pCNd = (SwCntntNode*)pCnt->GetNode(); + pPam->GetPoint()->nNode = *pCNd; + xub_StrLen nIdx; + if( fnPosPage == GetFirstSub ) + nIdx = ((SwTxtFrm*)pCnt)->GetOfst(); + else + nIdx = pCnt->GetFollow() ? + ((SwTxtFrm*)pCnt)->GetFollow()->GetOfst()-1 : pCNd->Len(); + pPam->GetPoint()->nContent.Assign( pCNd, nIdx ); + return sal_True; + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::GetCntntPos() +|* +|* Beschreibung Es wird der nachstliegende Cntnt zum uebergebenen +|* gesucht. Betrachtet werden die vorhergehende, die +|* aktuelle und die folgende Seite. +|* Wenn kein Inhalt gefunden wird, so wird der Bereich + * erweitert bis einer gefunden wird. +|* Zurueckgegeben wird die 'Semantisch richtige' Position +|* innerhalb der PrtArea des gefundenen CntntFrm +|* +|*************************************************************************/ +sal_uLong CalcDiff( const Point &rPt1, const Point &rPt2 ) +{ + //Jetzt die Entfernung zwischen den beiden Punkten berechnen. + //'Delta' X^2 + 'Delta'Y^2 = 'Entfernung'^2 + sal_uInt32 dX = Max( rPt1.X(), rPt2.X() ) - + Min( rPt1.X(), rPt2.X() ), + dY = Max( rPt1.Y(), rPt2.Y() ) - + Min( rPt1.Y(), rPt2.Y() ); + BigInt dX1( dX ), dY1( dY ); + dX1 *= dX1; dY1 *= dY1; + return ::SqRt( dX1 + dY1 ); +} + +// lcl_Inside ueberprueft, ob der Punkt innerhalb des Seitenteils liegt, in dem +// auch der CntntFrame liegt. Als Seitenteile gelten in diesem Zusammenhang +// Kopfzeile, Seitenbody, Fusszeile und FussnotenContainer. +// Dies dient dazu, dass ein CntntFrm, der im "richtigen" Seitenteil liegt, +// eher akzeptiert wird als ein anderer, der nicht dort liegt, auch wenn +// dessen Abstand zum Punkt geringer ist. + +const SwLayoutFrm* lcl_Inside( const SwCntntFrm *pCnt, Point& rPt ) +{ + const SwLayoutFrm* pUp = pCnt->GetUpper(); + while( pUp ) + { + if( pUp->IsPageBodyFrm() || pUp->IsFooterFrm() || pUp->IsHeaderFrm() ) + { + if( rPt.Y() >= pUp->Frm().Top() && rPt.Y() <= pUp->Frm().Bottom() ) + return pUp; + return NULL; + } + if( pUp->IsFtnContFrm() ) + return pUp->Frm().IsInside( rPt ) ? pUp : NULL; + pUp = pUp->GetUpper(); + } + return NULL; +} + +const SwCntntFrm *SwLayoutFrm::GetCntntPos( Point& rPoint, + const sal_Bool bDontLeave, + const sal_Bool bBodyOnly, + const sal_Bool bCalc, + const SwCrsrMoveState *pCMS, + const sal_Bool bDefaultExpand ) const +{ + //Ersten CntntFrm ermitteln. + const SwLayoutFrm *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ? + (SwLayoutFrm*)GetPrev() : this; + const SwCntntFrm *pCntnt = pStart->ContainsCntnt(); + + if ( !pCntnt && (GetPrev() && !bDontLeave) ) + pCntnt = ContainsCntnt(); + + if ( bBodyOnly && pCntnt && !pCntnt->IsInDocBody() ) + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + + const SwCntntFrm *pActual= pCntnt; + const SwLayoutFrm *pInside = NULL; + sal_uInt16 nMaxPage = GetPhyPageNum() + (bDefaultExpand ? 1 : 0); + Point aPoint = rPoint; + sal_uLong nDistance = ULONG_MAX; + + while ( sal_True ) //Sicherheitsschleifchen, damit immer einer gefunden wird. + { + while ( pCntnt && + ((!bDontLeave || IsAnLower( pCntnt )) && + (pCntnt->GetPhyPageNum() <= nMaxPage)) ) + { + if ( ( bCalc || pCntnt->Frm().Width() ) && + ( !bBodyOnly || pCntnt->IsInDocBody() ) ) + { + //Wenn der Cntnt in einem geschuetzen Bereich (Zelle, Ftn, Section) + //liegt, wird der nachste Cntnt der nicht geschuetzt ist gesucht. + const SwCntntFrm *pComp = pCntnt; + pCntnt = ::lcl_MissProtectedFrames( pCntnt, lcl_GetNxtCnt, sal_False, + pCMS ? pCMS->bSetInReadOnly : sal_False, sal_False ); + if ( pComp != pCntnt ) + continue; + + if ( !pCntnt->IsTxtFrm() || !((SwTxtFrm*)pCntnt)->IsHiddenNow() ) + { + if ( bCalc ) + pCntnt->Calc(); + + SwRect aCntFrm( pCntnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPoint ) ) + { + pActual = pCntnt; + aPoint = rPoint; + break; + } + //Die Strecke von rPoint zum dichtesten Punkt von pCntnt wird + //jetzt berechnet. + Point aCntntPoint( rPoint ); + + //Erst die Vertikale Position einstellen + if ( aCntFrm.Top() > aCntntPoint.Y() ) + aCntntPoint.Y() = aCntFrm.Top(); + else if ( aCntFrm.Bottom() < aCntntPoint.Y() ) + aCntntPoint.Y() = aCntFrm.Bottom(); + + //Jetzt die Horizontale Position + if ( aCntFrm.Left() > aCntntPoint.X() ) + aCntntPoint.X() = aCntFrm.Left(); + else if ( aCntFrm.Right() < aCntntPoint.X() ) + aCntntPoint.X() = aCntFrm.Right(); + + // pInside ist ein Seitenbereich, in dem der Punkt liegt, + // sobald pInside!=0 ist, werden nur noch Frames akzeptiert, + // die innerhalb liegen. + if( !pInside || ( pInside->IsAnLower( pCntnt ) && + ( !pCntnt->IsInFtn() || pInside->IsFtnContFrm() ) ) ) + { + const sal_uLong nDiff = ::CalcDiff( aCntntPoint, rPoint ); + sal_Bool bBetter = nDiff < nDistance; // Dichter dran + if( !pInside ) + { + pInside = lcl_Inside( pCntnt, rPoint ); + if( pInside ) // Im "richtigen" Seitenteil + bBetter = sal_True; + } + if( bBetter ) + { + aPoint = aCntntPoint; + nDistance = nDiff; + pActual = pCntnt; + } + } + } + } + pCntnt = pCntnt->GetNextCntntFrm(); + if ( bBodyOnly ) + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + } + if ( !pActual ) + { //Wenn noch keiner gefunden wurde muss der Suchbereich erweitert + //werden, irgenwann muessen wir einen Finden! + //MA 09. Jan. 97: Opt fuer viele leere Seiten, wenn wir nur im + //Body suchen, koennen wir den Suchbereich gleich in einem + //Schritt hinreichend erweitern. + if ( bBodyOnly ) + { + while ( !pCntnt && pStart->GetPrev() ) + { + ++nMaxPage; + if( !pStart->GetPrev()->IsLayoutFrm() ) + return 0; + pStart = (SwLayoutFrm*)pStart->GetPrev(); + pCntnt = pStart->IsInDocBody() + ? pStart->ContainsCntnt() + : pStart->FindPageFrm()->FindFirstBodyCntnt(); + } + if ( !pCntnt ) //irgendwann muessen wir mit irgendeinem Anfangen! + { + pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt(); + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + if ( !pCntnt ) + return 0; //Es gibt noch keine Dokumentinhalt! + } + } + else + { + ++nMaxPage; + if ( pStart->GetPrev() ) + { + if( !pStart->GetPrev()->IsLayoutFrm() ) + return 0; + pStart = (SwLayoutFrm*)pStart->GetPrev(); + pCntnt = pStart->ContainsCntnt(); + } + else //irgendwann muessen wir mit irgendeinem Anfangen! + pCntnt = pStart->FindPageFrm()->GetUpper()->ContainsCntnt(); + } + pActual = pCntnt; + } + else + break; + } + +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( pActual, "Keinen Cntnt gefunden." ); + if ( bBodyOnly ) + OSL_ENSURE( pActual->IsInDocBody(), "Cnt nicht im Body." ); +#endif + + //Spezialfall fuer das selektieren von Tabellen, nicht in wiederholte + //TblHedlines. + if ( pActual->IsInTab() && pCMS && pCMS->eState == MV_TBLSEL ) + { + const SwTabFrm *pTab = pActual->FindTabFrm(); + if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) ) + { + ((SwCrsrMoveState*)pCMS)->bStop = sal_True; + return 0; + } + } + + //Jetzt noch eine kleine Korrektur beim ersten/letzten + Size aActualSize( pActual->Prt().SSize() ); + if ( aActualSize.Height() > pActual->GetUpper()->Prt().Height() ) + aActualSize.Height() = pActual->GetUpper()->Prt().Height(); + + SWRECTFN( pActual ) + if ( !pActual->GetPrev() && + (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtTop)(), + bVert ? rPoint.X() : rPoint.Y() ) > 0 ) + { + aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Top(); + aPoint.X() = pActual->Frm().Left() + + ( pActual->IsRightToLeft() || bVert ? + pActual->Prt().Right() : + pActual->Prt().Left() ); + } + else if ( !pActual->GetNext() && + (*fnRect->fnYDiff)( (pActual->*fnRect->fnGetPrtBottom)(), + bVert ? rPoint.X() : rPoint.Y() ) < 0 ) + { + aPoint.Y() = pActual->Frm().Top() + pActual->Prt().Bottom(); + aPoint.X() = pActual->Frm().Left() + + ( pActual->IsRightToLeft() || bVert ? + pActual->Prt().Left() : + pActual->Prt().Right() ); + } + + //Und den Point in die PrtArea bringen + if ( bCalc ) + pActual->Calc(); + const SwRect aRect( pActual->Frm().Pos() + pActual->Prt().Pos(), + aActualSize ); + if ( aPoint.Y() < aRect.Top() ) + aPoint.Y() = aRect.Top(); + else if ( aPoint.Y() > aRect.Bottom() ) + aPoint.Y() = aRect.Bottom(); + if ( aPoint.X() < aRect.Left() ) + aPoint.X() = aRect.Left(); + else if ( aPoint.X() > aRect.Right() ) + aPoint.X() = aRect.Right(); + rPoint = aPoint; + return pActual; +} + +/************************************************************************* +|* +|* SwPageFrm::GetCntntPosition() +|* +|* Beschreibung Analog zu SwLayoutFrm::GetCntntPos(). +|* Spezialisiert fuer Felder in Rahmen. +|* +|*************************************************************************/ +void SwPageFrm::GetCntntPosition( const Point &rPt, SwPosition &rPos ) const +{ + //Ersten CntntFrm ermitteln. + const SwCntntFrm *pCntnt = ContainsCntnt(); + if ( pCntnt ) + { + //Einen weiter zurueck schauen (falls moeglich). + const SwCntntFrm *pTmp = pCntnt->GetPrevCntntFrm(); + while ( pTmp && !pTmp->IsInDocBody() ) + pTmp = pTmp->GetPrevCntntFrm(); + if ( pTmp ) + pCntnt = pTmp; + } + else + pCntnt = GetUpper()->ContainsCntnt(); + + const SwCntntFrm *pAct = pCntnt; + Point aAct = rPt; + sal_uLong nDist = ULONG_MAX; + + while ( pCntnt ) + { + SwRect aCntFrm( pCntnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPt ) ) + { + //dichter gehts nimmer. + pAct = pCntnt; + break; + } + + //Die Strecke von rPt zum dichtesten Punkt von pCntnt berechnen. + Point aPoint( rPt ); + + //Erst die vertikale Position einstellen + if ( aCntFrm.Top() > rPt.Y() ) + aPoint.Y() = aCntFrm.Top(); + else if ( aCntFrm.Bottom() < rPt.Y() ) + aPoint.Y() = aCntFrm.Bottom(); + + //Jetzt die horizontale Position + if ( aCntFrm.Left() > rPt.X() ) + aPoint.X() = aCntFrm.Left(); + else if ( aCntFrm.Right() < rPt.X() ) + aPoint.X() = aCntFrm.Right(); + + const sal_uLong nDiff = ::CalcDiff( aPoint, rPt ); + if ( nDiff < nDist ) + { + aAct = aPoint; + nDist = nDiff; + pAct = pCntnt; + } + else if ( aCntFrm.Top() > Frm().Bottom() ) + //Dichter wirds im Sinne der Felder nicht mehr! + break; + + pCntnt = pCntnt->GetNextCntntFrm(); + while ( pCntnt && !pCntnt->IsInDocBody() ) + pCntnt = pCntnt->GetNextCntntFrm(); + } + + //Und den Point in die PrtArea bringen + const SwRect aRect( pAct->Frm().Pos() + pAct->Prt().Pos(), pAct->Prt().SSize() ); + if ( aAct.Y() < aRect.Top() ) + aAct.Y() = aRect.Top(); + else if ( aAct.Y() > aRect.Bottom() ) + aAct.Y() = aRect.Bottom(); + if ( aAct.X() < aRect.Left() ) + aAct.X() = aRect.Left(); + else if ( aAct.X() > aRect.Right() ) + aAct.X() = aRect.Right(); + + if( !pAct->IsValid() ) + { + // CntntFrm nicht formatiert -> immer auf Node-Anfang + SwCntntNode* pCNd = (SwCntntNode*)pAct->GetNode(); + OSL_ENSURE( pCNd, "Wo ist mein CntntNode?" ); + rPos.nNode = *pCNd; + rPos.nContent.Assign( pCNd, 0 ); + } + else + { + SwCrsrMoveState aTmpState( MV_SETONLYTEXT ); + pAct->GetCrsrOfst( &rPos, aAct, &aTmpState ); + } +} + +/************************************************************************* +|* +|* SwRootFrm::GetNextPrevCntntPos() +|* +|* Beschreibung Es wird der naechstliegende Cntnt zum uebergebenen +|* Point gesucht. Es wird nur im BodyText gesucht. +|* +|*************************************************************************/ + +// --> OD 2005-05-25 #123110# - helper class to disable creation of an action +// by a callback event - e.g., change event from a drawing object +class DisableCallbackAction +{ + private: + SwRootFrm& mrRootFrm; + sal_Bool mbOldCallbackActionState; + + public: + DisableCallbackAction( const SwRootFrm& _rRootFrm ) : + mrRootFrm( const_cast<SwRootFrm&>(_rRootFrm) ), + mbOldCallbackActionState( _rRootFrm.IsCallbackActionEnabled() ) + { + mrRootFrm.SetCallbackActionEnabled( sal_False ); + } + + ~DisableCallbackAction() + { + mrRootFrm.SetCallbackActionEnabled( mbOldCallbackActionState ); + } +}; +// <-- + +//!!!!! Es wird nur der vertikal naechstliegende gesucht. +//JP 11.10.2001: only in tables we try to find the right column - Bug 72294 +Point SwRootFrm::GetNextPrevCntntPos( const Point& rPoint, sal_Bool bNext ) const +{ + // --> OD 2005-05-25 #123110# - disable creation of an action by a callback + // event during processing of this method. Needed because formatting is + // triggered by this method. + DisableCallbackAction aDisableCallbackAction( *this ); + // <-- + //Ersten CntntFrm und seinen Nachfolger im Body-Bereich suchen + //Damit wir uns nicht tot suchen (und vor allem nicht zuviel formatieren) + //gehen wir schon mal von der richtigen Seite aus. + SwLayoutFrm *pPage = (SwLayoutFrm*)Lower(); + if( pPage ) + while( pPage->GetNext() && pPage->Frm().Bottom() < rPoint.Y() ) + pPage = (SwLayoutFrm*)pPage->GetNext(); + + const SwCntntFrm *pCnt = pPage ? pPage->ContainsCntnt() : ContainsCntnt(); + while ( pCnt && !pCnt->IsInDocBody() ) + pCnt = pCnt->GetNextCntntFrm(); + + if ( !pCnt ) + return Point( 0, 0 ); + + pCnt->Calc(); + if( !bNext ) + { + // Solange der Point vor dem ersten CntntFrm liegt und es noch + // vorhergehende Seiten gibt gehe ich jeweils eine Seite nach vorn. + while ( rPoint.Y() < pCnt->Frm().Top() && pPage->GetPrev() ) + { + pPage = (SwLayoutFrm*)pPage->GetPrev(); + pCnt = pPage->ContainsCntnt(); + while ( !pCnt ) + { + pPage = (SwLayoutFrm*)pPage->GetPrev(); + if ( pPage ) + pCnt = pPage->ContainsCntnt(); + else + return ContainsCntnt()->UnionFrm().Pos(); + } + pCnt->Calc(); + } + } + + //Liegt der Point ueber dem ersten CntntFrm? + if ( rPoint.Y() < pCnt->Frm().Top() && !lcl_IsInRepeatedHeadline( pCnt ) ) + return pCnt->UnionFrm().Pos(); + + while ( pCnt ) + { + //Liegt der Point im aktuellen CntntFrm? + SwRect aCntFrm( pCnt->UnionFrm() ); + if ( aCntFrm.IsInside( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt )) + return rPoint; + + //Ist der aktuelle der letzte CntntFrm? || + //Wenn der naechste CntntFrm hinter dem Point liegt, ist der + //aktuelle der gesuchte. + const SwCntntFrm *pNxt = pCnt->GetNextCntntFrm(); + while ( pNxt && !pNxt->IsInDocBody() ) + pNxt = pNxt->GetNextCntntFrm(); + + //Liegt der Point hinter dem letzten CntntFrm? + if ( !pNxt ) + return Point( aCntFrm.Right(), aCntFrm.Bottom() ); + + //Wenn der naechste CntntFrm hinter dem Point liegt ist er der + //gesuchte. + const SwTabFrm* pTFrm; + pNxt->Calc(); + if( pNxt->Frm().Top() > rPoint.Y() && + !lcl_IsInRepeatedHeadline( pCnt, &pTFrm ) && + ( !pTFrm || pNxt->Frm().Left() > rPoint.X() )) + { + if( bNext ) + return pNxt->Frm().Pos(); + return Point( aCntFrm.Right(), aCntFrm.Bottom() ); + } + pCnt = pNxt; + } + return Point( 0, 0 ); +} + +/************************************************************************* +|* +|* SwRootFrm::GetPagePos() +|* +|* Beschreibung: Liefert die absolute Dokumentpositon der gewuenschten +|* Seite. +|* Formatiert wird nur soweit notwendig und nur dann wenn bFormat=sal_True +|* Liefert Null, wenn die Operation nicht moeglich ist. +|* Die Pos ist die der letzten Seite, wenn die Seitenzahl zu gross +|* gewaehlt wurde. +|* +|*************************************************************************/ +Point SwRootFrm::GetPagePos( sal_uInt16 nPageNum ) const +{ + OSL_ENSURE( Lower() && Lower()->IsPageFrm(), "Keine Seite vorhanden." ); + + const SwPageFrm *pPage = (const SwPageFrm*)Lower(); + while ( sal_True ) + { + if ( pPage->GetPhyPageNum() >= nPageNum || !pPage->GetNext() ) + break; + pPage = (const SwPageFrm*)pPage->GetNext(); + } + return pPage->Frm().Pos(); +} + +/** get page frame by phyiscal page number + + OD 14.01.2003 #103492# + + @return pointer to the page frame with the given physical page number +*/ +SwPageFrm* SwRootFrm::GetPageByPageNum( sal_uInt16 _nPageNum ) const +{ + const SwPageFrm* pPageFrm = static_cast<const SwPageFrm*>( Lower() ); + while ( pPageFrm && pPageFrm->GetPhyPageNum() < _nPageNum ) + { + pPageFrm = static_cast<const SwPageFrm*>( pPageFrm->GetNext() ); + } + + if ( pPageFrm && pPageFrm->GetPhyPageNum() == _nPageNum ) + { + return const_cast<SwPageFrm*>( pPageFrm ); + } + else + { + return 0; + } +} + +/************************************************************************* +|* +|* SwRootFrm::IsDummyPage(sal_uInt16) +|* +|* Description: Returns sal_True, when the given physical pagenumber does't exist +|* or this page is an empty page. +|*************************************************************************/ +sal_Bool SwRootFrm::IsDummyPage( sal_uInt16 nPageNum ) const +{ + if( !Lower() || !nPageNum || nPageNum > GetPageNum() ) + return sal_True; + + const SwPageFrm *pPage = (const SwPageFrm*)Lower(); + while( pPage && nPageNum < pPage->GetPhyPageNum() ) + pPage = (const SwPageFrm*)pPage->GetNext(); + return pPage ? pPage->IsEmptyPage() : sal_True; +} + + +/************************************************************************* +|* +|* SwFrm::IsProtected() +|* +|* Beschreibung Ist der Frm bzw. die Section in der er steht +|* geschuetzt? +|* Auch Fly in Fly in ... und Fussnoten +|* +|* +|*************************************************************************/ +sal_Bool SwFrm::IsProtected() const +{ + if (this->IsCntntFrm() && ((SwCntntFrm*)this)->GetNode()) + { + const SwDoc *pDoc=((SwCntntFrm*)this)->GetNode()->GetDoc(); + bool isFormProtected=pDoc->get(IDocumentSettingAccess::PROTECT_FORM ); + if (isFormProtected) + { + return sal_False; // TODO a hack for now, well deal with it laster, I we return true here we have a "double" locking + } + } + //Der Frm kann in Rahmen, Zellen oder Bereichen geschuetzt sein. + //Geht auch FlyFrms rekursiv hoch. Geht auch von Fussnoten zum Anker. + const SwFrm *pFrm = this; + do + { + if ( pFrm->IsCntntFrm() ) + { + if ( ((SwCntntFrm*)pFrm)->GetNode() && + ((SwCntntFrm*)pFrm)->GetNode()->IsInProtectSect() ) + return sal_True; + } + else + { + if ( ((SwLayoutFrm*)pFrm)->GetFmt() && + ((SwLayoutFrm*)pFrm)->GetFmt()-> + GetProtect().IsCntntProtected() ) + return sal_True; + if ( pFrm->IsCoveredCell() ) + return sal_True; + } + if ( pFrm->IsFlyFrm() ) + { + //Der Schutz des Inhaltes kann bei Verkettung vom Master der Kette + //vorgegeben werden. + if ( ((SwFlyFrm*)pFrm)->GetPrevLink() ) + { + SwFlyFrm *pMaster = (SwFlyFrm*)pFrm; + do + { pMaster = pMaster->GetPrevLink(); + } while ( pMaster->GetPrevLink() ); + if ( pMaster->IsProtected() ) + return sal_True; + } + pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm(); + } + else if ( pFrm->IsFtnFrm() ) + pFrm = ((SwFtnFrm*)pFrm)->GetRef(); + else + pFrm = pFrm->GetUpper(); + + } while ( pFrm ); + + return sal_False; +} + +/************************************************************************* +|* +|* SwFrm::GetPhyPageNum() +|* Beschreibung: Liefert die physikalische Seitennummer +|* +|* +|*************************************************************************/ +sal_uInt16 SwFrm::GetPhyPageNum() const +{ + const SwPageFrm *pPage = FindPageFrm(); + return pPage ? pPage->GetPhyPageNum() : 0; +} + +/*-------------------------------------------------- + * SwFrm::WannaRightPage() + * decides if the page want to be a rightpage or not. + * If the first content of the page has a page descriptor, + * we take the follow of the page descriptor of the last not empty page. + * If this descriptor allows only right(left) pages and the page + * isn't an empty page then it wanna be such right(left) page. + * If the descriptor allows right and left pages, we look for a number offset + * in the first content. If there is one, odd number results right pages, + * even number results left pages. + * If there is no number offset, we take the physical page number instead, + * but a previous empty page don't count. + * --------------------------------------------------*/ + +sal_Bool SwFrm::WannaRightPage() const +{ + const SwPageFrm *pPage = FindPageFrm(); + if ( !pPage || !pPage->GetUpper() ) + return sal_True; + + const SwFrm *pFlow = pPage->FindFirstBodyCntnt(); + SwPageDesc *pDesc = 0; + sal_uInt16 nPgNum = 0; + if ( pFlow ) + { + if ( pFlow->IsInTab() ) + pFlow = pFlow->FindTabFrm(); + const SwFlowFrm *pTmp = SwFlowFrm::CastFlowFrm( pFlow ); + if ( !pTmp->IsFollow() ) + { + const SwFmtPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc(); + pDesc = (SwPageDesc*)rPgDesc.GetPageDesc(); + nPgNum = rPgDesc.GetNumOffset(); + } + } + if ( !pDesc ) + { + SwPageFrm *pPrv = (SwPageFrm*)pPage->GetPrev(); + if( pPrv && pPrv->IsEmptyPage() ) + pPrv = (SwPageFrm*)pPrv->GetPrev(); + if( pPrv ) + pDesc = pPrv->GetPageDesc()->GetFollow(); + else + { + const SwDoc* pDoc = pPage->GetFmt()->GetDoc(); + pDesc = (SwPageDesc*)&pDoc->GetPageDesc( 0 ); + } + } + OSL_ENSURE( pDesc, "No pagedescriptor" ); + sal_Bool bOdd; + if( nPgNum ) + bOdd = nPgNum % 2 ? sal_True : sal_False; + else + { + bOdd = pPage->OnRightPage(); + if( pPage->GetPrev() && ((SwPageFrm*)pPage->GetPrev())->IsEmptyPage() ) + bOdd = !bOdd; + } + if( !pPage->IsEmptyPage() ) + { + if( !pDesc->GetRightFmt() ) + bOdd = sal_False; + else if( !pDesc->GetLeftFmt() ) + bOdd = sal_True; + } + return bOdd; +} + +/************************************************************************* +|* +|* SwFrm::GetVirtPageNum() +|* Beschreibung: Liefert die virtuelle Seitennummer mit Offset +|* +|*************************************************************************/ +sal_uInt16 SwFrm::GetVirtPageNum() const +{ + const SwPageFrm *pPage = FindPageFrm(); + if ( !pPage || !pPage->GetUpper() ) + return 0; + + sal_uInt16 nPhyPage = pPage->GetPhyPageNum(); + if ( !((SwRootFrm*)pPage->GetUpper())->IsVirtPageNum() ) + return nPhyPage; + + //Den am naechsten stehenden Absatz mit virtueller Seitennummer suchen. + //Da das rueckwaertsuchen insgesamt sehr viel Zeit verschlingt suchen + //wir jetzt gezielt ueber die Abhaengigkeiten. + //von den PageDescs bekommen wir die Attribute, von den Attributen + //wiederum bekommen wir die Absaetze. + const SwPageFrm *pVirtPage = 0; + const SwFrm *pFrm = 0; + const SfxItemPool &rPool = pPage->GetFmt()->GetDoc()->GetAttrPool(); + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = rPool.GetItemCount2( RES_PAGEDESC ); + for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + { + if( 0 == (pItem = rPool.GetItem2( RES_PAGEDESC, n ) )) + continue; + + const SwFmtPageDesc *pDesc = (SwFmtPageDesc*)pItem; + if ( pDesc->GetNumOffset() && pDesc->GetDefinedIn() ) + { + const SwModify *pMod = pDesc->GetDefinedIn(); + SwVirtPageNumInfo aInfo( pPage ); + pMod->GetInfo( aInfo ); + if ( aInfo.GetPage() ) + { + if( !pVirtPage || ( pVirtPage && aInfo.GetPage()-> + GetPhyPageNum() > pVirtPage->GetPhyPageNum() ) ) + { + pVirtPage = aInfo.GetPage(); + pFrm = aInfo.GetFrm(); + } + } + } + } + if ( pFrm ) + return nPhyPage - pFrm->GetPhyPageNum() + + pFrm->GetAttrSet()->GetPageDesc().GetNumOffset(); + return nPhyPage; +} + +/************************************************************************* +|* +|* SwRootFrm::MakeTblCrsrs() +|* +|*************************************************************************/ +//Ermitteln und einstellen derjenigen Zellen die von der Selektion +//eingeschlossen sind. + +bool SwRootFrm::MakeTblCrsrs( SwTableCursor& rTblCrsr ) +{ + //Union-Rects und Tabellen (Follows) der Selektion besorgen. + OSL_ENSURE( rTblCrsr.GetCntntNode() && rTblCrsr.GetCntntNode( sal_False ), + "Tabselection nicht auf Cnt." ); + + bool bRet = false; + + // For new table models there's no need to ask the layout.. + if( rTblCrsr.NewTableSelection() ) + return true; + + Point aPtPt, aMkPt; + { + SwShellCrsr* pShCrsr = dynamic_cast<SwShellCrsr*>(&rTblCrsr); + + if( pShCrsr ) + { + aPtPt = pShCrsr->GetPtPos(); + aMkPt = pShCrsr->GetMkPos(); + } + } + + // --> FME 2008-01-14 #151012# Made code robust here: + const SwCntntNode* pTmpStartNode = rTblCrsr.GetCntntNode(); + const SwCntntNode* pTmpEndNode = rTblCrsr.GetCntntNode(sal_False); + + const SwFrm* pTmpStartFrm = pTmpStartNode ? pTmpStartNode->getLayoutFrm( this, &aPtPt, 0, sal_False ) : 0; + const SwFrm* pTmpEndFrm = pTmpEndNode ? pTmpEndNode->getLayoutFrm( this, &aMkPt, 0, sal_False ) : 0; + + const SwLayoutFrm* pStart = pTmpStartFrm ? pTmpStartFrm->GetUpper() : 0; + const SwLayoutFrm* pEnd = pTmpEndFrm ? pTmpEndFrm->GetUpper() : 0; + + OSL_ENSURE( pStart && pEnd, "MakeTblCrsrs: Good to have the code robust here!" ); + // <-- + + /* #109590# Only change table boxes if the frames are + valid. Needed because otherwise the table cursor after moving + table cells by dnd resulted in an empty tables cursor. */ + if ( pStart && pEnd && pStart->IsValid() && pEnd->IsValid()) + { + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + SwSelBoxes aNew; + + const sal_Bool bReadOnlyAvailable = rTblCrsr.IsReadOnlyAvailable(); + + for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + const SwTabFrm *pTable = pUnion->GetTable(); + + // Skip any repeated headlines in the follow: + SwLayoutFrm* pRow = pTable->IsFollow() ? + pTable->GetFirstNonHeadlineRow() : + (SwLayoutFrm*)pTable->Lower(); + + while ( pRow ) + { + if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) + { + const SwLayoutFrm *pCell = pRow->FirstCell(); + + while ( pCell && pRow->IsAnLower( pCell ) ) + { + OSL_ENSURE( pCell->IsCellFrm(), "Frame ohne Celle" ); + if( IsFrmInTblSel( pUnion->GetUnion(), pCell ) && + (bReadOnlyAvailable || + !pCell->GetFmt()->GetProtect().IsCntntProtected())) + { + SwTableBox* pInsBox = (SwTableBox*) + ((SwCellFrm*)pCell)->GetTabBox(); + aNew.Insert( pInsBox ); + } + if ( pCell->GetNext() ) + { + pCell = (const SwLayoutFrm*)pCell->GetNext(); + if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) + pCell = pCell->FirstCell(); + } + else + { + const SwLayoutFrm* pLastCell = pCell; + do + { + pCell = pCell->GetNextLayoutLeaf(); + } while ( pCell && pLastCell->IsAnLower( pCell ) ); + // Fuer (spaltige) Bereiche... + if( pCell && pCell->IsInTab() ) + { + while( !pCell->IsCellFrm() ) + { + pCell = pCell->GetUpper(); + OSL_ENSURE( pCell, "Where's my cell?" ); + } + } + } + } + } + pRow = (SwLayoutFrm*)pRow->GetNext(); + } + } + + rTblCrsr.ActualizeSelection( aNew ); + bRet = true; + } + + return bRet; +} + + +/************************************************************************* +|* +|* SwRootFrm::CalcFrmRects +|* +|*************************************************************************/ + +/* + * nun koennen folgende Situationen auftreten: + * 1. Start und Ende liegen in einer Bildschirm - Zeile und im + * gleichen Node + * -> aus Start und End ein Rectangle, dann Ok + * 2. Start und Ende liegen in einem Frame (dadurch im gleichen Node!) + * -> Start nach rechts, End nach links erweitern, + * und bei mehr als 2 Bildschirm - Zeilen, das dazwischen + * liegende berechnen + * 3. Start und Ende liegen in verschiedenen Frames + * -> Start nach rechts erweitern, bis Frame-Ende Rect berechnen + * Ende nach links erweitern, bis Frame-Start Rect berechnen + * und bei mehr als 2 Frames von allen dazwischen liegenden + * Frames die PrtArea dazu. + * 4. Wenn es sich um eine Tabellenselektion handelt wird fuer jeden + * PaM im Ring der CellFrm besorgt, dessen PrtArea wird zu den + * Rechtecken addiert. + * + * Grosser Umbau wg. der FlyFrm; denn diese muessen ausgespart werden. + * Ausnahmen: - Der Fly in dem die Selektion stattfindet (wenn sie in einem Fly + * stattfindet). + * - Die Flys, die vom Text unterlaufen werden. + * Arbeitsweise: Zuerst wird eine SwRegion mit der Root initialisiert. + * Aus der Region werden die zu invertierenden Bereiche + * ausgestantzt. Die Region wird Komprimiert und letztlich + * invertiert. Damit liegen dann die zu invertierenden + * Rechtecke vor. + * Am Ende werden die Flys aus der Region ausgestanzt. + */ + +inline void Sub( SwRegionRects& rRegion, const SwRect& rRect ) +{ + if( rRect.Width() > 1 && rRect.Height() > 1 && + rRect.IsOver( rRegion.GetOrigin() )) + rRegion -= rRect; +} + +void SwRootFrm::CalcFrmRects( SwShellCrsr &rCrsr, sal_Bool bIsTblMode ) +{ + SwPosition *pStartPos = rCrsr.Start(), + *pEndPos = rCrsr.GetPoint() == pStartPos ? + rCrsr.GetMark() : rCrsr.GetPoint(); + + ViewShell *pSh = GetCurrShell(); + +// --> FME 2004-06-08 #i12836# enhanced pdf + SwRegionRects aRegion( pSh && !pSh->GetViewOptions()->IsPDFExport() ? + pSh->VisArea() : + Frm() ); +// <-- + if( !pStartPos->nNode.GetNode().IsCntntNode() || + !pStartPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) || + ( pStartPos->nNode != pEndPos->nNode && + ( !pEndPos->nNode.GetNode().IsCntntNode() || + !pEndPos->nNode.GetNode().GetCntntNode()->getLayoutFrm(this) ) ) ) + { + return; + } + + //Erstmal die CntntFrms zum Start und End besorgen, die brauch ich auf + //jedenfall. + SwCntntFrm const* pStartFrm = pStartPos->nNode.GetNode(). + GetCntntNode()->getLayoutFrm( this, &rCrsr.GetSttPos(), pStartPos ); + + SwCntntFrm const* pEndFrm = pEndPos->nNode.GetNode(). + GetCntntNode()->getLayoutFrm( this, &rCrsr.GetEndPos(), pEndPos ); + + OSL_ENSURE( (pStartFrm && pEndFrm), "Keine CntntFrms gefunden." ); + + //Damit die FlyFrms, in denen selektierte Frames stecken, nicht + //abgezogen werden + SwSortedObjs aSortObjs; + if ( pStartFrm->IsInFly() ) + { + const SwAnchoredObject* pObj = pStartFrm->FindFlyFrm(); + OSL_ENSURE( pObj, "No Start Object." ); + if (pObj) aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) ); + const SwAnchoredObject* pObj2 = pEndFrm->FindFlyFrm(); + OSL_ENSURE( pObj2, "No Start Object." ); + if (pObj2) aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj2)) ); + } + + //Fall 4: Tabellenselection + if( bIsTblMode ) + { + const SwFrm *pCell = pStartFrm->GetUpper(); + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + SwRect aTmp( pCell->Prt() ); + aTmp.Pos() += pCell->Frm().Pos(); + aRegion.ChangeOrigin( aTmp ); + aRegion.Remove( 0, aRegion.Count() ); + aRegion.Insert( aTmp, 0 ); + } + else + { + // falls eine nicht erlaubte Selection besteht, dann korrigiere das + // nicht erlaubt ist Header/Footer/TableHeadline ueber 2 Seiten + do { // middle check loop + const SwLayoutFrm* pSttLFrm = pStartFrm->GetUpper(); + const sal_uInt16 cHdFtTblHd = FRM_HEADER | FRM_FOOTER | FRM_TAB; + while( pSttLFrm && + ! (cHdFtTblHd & pSttLFrm->GetType() )) + pSttLFrm = pSttLFrm->GetUpper(); + if( !pSttLFrm ) + break; + const SwLayoutFrm* pEndLFrm = pEndFrm->GetUpper(); + while( pEndLFrm && + ! (cHdFtTblHd & pEndLFrm->GetType() )) + pEndLFrm = pEndLFrm->GetUpper(); + if( !pEndLFrm ) + break; + + OSL_ENSURE( pEndLFrm->GetType() == pSttLFrm->GetType(), + "Selection ueber unterschiedliche Inhalte" ); + switch( pSttLFrm->GetType() ) + { + case FRM_HEADER: + case FRM_FOOTER: + // auf unterschiedlichen Seiten ?? + // dann immer auf die Start-Seite + if( pEndLFrm->FindPageFrm() != pSttLFrm->FindPageFrm() ) + { + // End- auf den Start-CntntFrame setzen + if( pStartPos == rCrsr.GetPoint() ) + pEndFrm = pStartFrm; + else + pStartFrm = pEndFrm; + } + break; + case FRM_TAB: + // auf unterschiedlichen Seiten ?? + // existiert + // dann teste auf Tabelle-Headline + { + const SwTabFrm* pTabFrm = (SwTabFrm*)pSttLFrm; + if( ( pTabFrm->GetFollow() || + ((SwTabFrm*)pEndLFrm)->GetFollow() ) && + pTabFrm->GetTable()->GetRowsToRepeat() > 0 && + pTabFrm->GetLower() != ((SwTabFrm*)pEndLFrm)->GetLower() && + ( lcl_IsInRepeatedHeadline( pStartFrm ) || + lcl_IsInRepeatedHeadline( pEndFrm ) ) ) + { + // End- auf den Start-CntntFrame setzen + if( pStartPos == rCrsr.GetPoint() ) + pEndFrm = pStartFrm; + else + pStartFrm = pEndFrm; + } + } + break; + } + } while( sal_False ); + + SwCrsrMoveState aTmpState( MV_NONE ); + aTmpState.b2Lines = sal_True; + aTmpState.bNoScroll = sal_True; + aTmpState.nCursorBidiLevel = pStartFrm->IsRightToLeft() ? 1 : 0; + + //CntntRects zu Start- und EndFrms. + SwRect aStRect, aEndRect; + pStartFrm->GetCharRect( aStRect, *pStartPos, &aTmpState ); + Sw2LinesPos *pSt2Pos = aTmpState.p2Lines; + aTmpState.p2Lines = NULL; + aTmpState.nCursorBidiLevel = pEndFrm->IsRightToLeft() ? 1 : 0; + + pEndFrm->GetCharRect ( aEndRect, *pEndPos, &aTmpState ); + Sw2LinesPos *pEnd2Pos = aTmpState.p2Lines; + + SwRect aStFrm ( pStartFrm->UnionFrm( sal_True ) ); + aStFrm.Intersection( pStartFrm->PaintArea() ); + SwRect aEndFrm( pStartFrm == pEndFrm ? aStFrm : + pEndFrm->UnionFrm( sal_True ) ); + if( pStartFrm != pEndFrm ) + aEndFrm.Intersection( pEndFrm->PaintArea() ); + SWRECTFN( pStartFrm ) + const sal_Bool bR2L = pStartFrm->IsRightToLeft(); + const sal_Bool bEndR2L = pEndFrm->IsRightToLeft(); + + // If there's no doubleline portion involved or start and end are both + // in the same doubleline portion, all works fine, but otherwise + // we need the following... + if( pSt2Pos != pEnd2Pos && ( !pSt2Pos || !pEnd2Pos || + pSt2Pos->aPortion != pEnd2Pos->aPortion ) ) + { + // If we have a start(end) position inside a doubleline portion + // the surrounded part of the doubleline portion is subtracted + // from the region and the aStRect(aEndRect) is set to the + // end(start) of the doubleline portion. + if( pSt2Pos ) + { + SwRect aTmp( aStRect ); + + // BiDi-Portions are swimming against the current. + const sal_Bool bPorR2L = ( MT_BIDI == pSt2Pos->nMultiType ) ? + ! bR2L : + bR2L; + + if( MT_BIDI == pSt2Pos->nMultiType && + (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() ) + { + // nested bidi portion + long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)(); + + (aTmp.*fnRect->fnSetRight)( nRightAbs ); + + if ( ! pEnd2Pos || pEnd2Pos->aPortion != pSt2Pos->aPortion ) + { + SwRect aTmp2( pSt2Pos->aPortion ); + (aTmp2.*fnRect->fnSetRight)( nLeftAbs ); + aTmp2.Intersection( aEndFrm ); + Sub( aRegion, aTmp2 ); + } + } + else + { + if( bPorR2L ) + (aTmp.*fnRect->fnSetLeft)( + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() ); + else + (aTmp.*fnRect->fnSetRight)( + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + } + + if( MT_ROT_90 == pSt2Pos->nMultiType || + (pSt2Pos->aPortion.*fnRect->fnGetTop)() == + (aTmp.*fnRect->fnGetTop)() ) + { + (aTmp.*fnRect->fnSetTop)( + (pSt2Pos->aLine.*fnRect->fnGetTop)() ); + } + + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + + SwTwips nTmp = (pSt2Pos->aLine.*fnRect->fnGetBottom)(); + if( MT_ROT_90 != pSt2Pos->nMultiType && + (aStRect.*fnRect->fnBottomDist)( nTmp ) > 0 ) + { + (aTmp.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetBottom)() ); + (aTmp.*fnRect->fnSetBottom)( nTmp ); + if( (aStRect.*fnRect->fnBottomDist)( + (pSt2Pos->aPortion.*fnRect->fnGetBottom)() ) > 0 ) + { + if( bPorR2L ) + (aTmp.*fnRect->fnSetRight)( + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + else + (aTmp.*fnRect->fnSetLeft)( + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() ); + } + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + } + + aStRect = pSt2Pos->aLine; + (aStRect.*fnRect->fnSetLeft)( bR2L ? + (pSt2Pos->aPortion.*fnRect->fnGetLeft)() : + (pSt2Pos->aPortion.*fnRect->fnGetRight)() ); + (aStRect.*fnRect->fnSetWidth)( 1 ); + } + + if( pEnd2Pos ) + { + SWRECTFNX( pEndFrm ) + SwRect aTmp( aEndRect ); + + // BiDi-Portions are swimming against the current. + const sal_Bool bPorR2L = ( MT_BIDI == pEnd2Pos->nMultiType ) ? + ! bEndR2L : + bEndR2L; + + if( MT_BIDI == pEnd2Pos->nMultiType && + (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() ) + { + // nested bidi portion + long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)(); + nRightAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)(); + + (aTmp.*fnRectX->fnSetLeft)( nLeftAbs ); + + if ( ! pSt2Pos || pSt2Pos->aPortion != pEnd2Pos->aPortion ) + { + SwRect aTmp2( pEnd2Pos->aPortion ); + (aTmp2.*fnRectX->fnSetLeft)( nRightAbs ); + aTmp2.Intersection( aEndFrm ); + Sub( aRegion, aTmp2 ); + } + } + else + { + if ( bPorR2L ) + (aTmp.*fnRectX->fnSetRight)( + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() ); + else + (aTmp.*fnRectX->fnSetLeft)( + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + } + + if( MT_ROT_90 == pEnd2Pos->nMultiType || + (pEnd2Pos->aPortion.*fnRectX->fnGetBottom)() == + (aEndRect.*fnRectX->fnGetBottom)() ) + { + (aTmp.*fnRectX->fnSetBottom)( + (pEnd2Pos->aLine.*fnRectX->fnGetBottom)() ); + } + + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + + // The next statement means neither ruby nor rotate(90): + if( !( MT_RUBY & pEnd2Pos->nMultiType ) ) + { + SwTwips nTmp = (pEnd2Pos->aLine.*fnRectX->fnGetTop)(); + if( (aEndRect.*fnRectX->fnGetTop)() != nTmp ) + { + (aTmp.*fnRectX->fnSetBottom)( + (aTmp.*fnRectX->fnGetTop)() ); + (aTmp.*fnRectX->fnSetTop)( nTmp ); + if( (aEndRect.*fnRectX->fnGetTop)() != + (pEnd2Pos->aPortion.*fnRectX->fnGetTop)() ) + { + if( bPorR2L ) + (aTmp.*fnRectX->fnSetLeft)( + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + else + (aTmp.*fnRectX->fnSetRight)( + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() ); + } + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + } + } + + aEndRect = pEnd2Pos->aLine; + (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? + (pEnd2Pos->aPortion.*fnRectX->fnGetRight)() : + (pEnd2Pos->aPortion.*fnRectX->fnGetLeft)() ); + (aEndRect.*fnRectX->fnSetWidth)( 1 ); + } + } + else if( pSt2Pos && pEnd2Pos && + MT_BIDI == pSt2Pos->nMultiType && + MT_BIDI == pEnd2Pos->nMultiType && + pSt2Pos->aPortion == pEnd2Pos->aPortion && + pSt2Pos->aPortion2 != pEnd2Pos->aPortion2 ) + { + // This is the ugly special case, where the selection starts and + // ends in the same bidi portion but one start or end is inside a + // nested bidi portion. + + if ( (pSt2Pos->aPortion2.*fnRect->fnGetWidth)() ) + { + SwRect aTmp( aStRect ); + long nRightAbs = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + nRightAbs -= (pSt2Pos->aPortion2.*fnRect->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pSt2Pos->aPortion2.*fnRect->fnGetWidth)(); + + (aTmp.*fnRect->fnSetRight)( nRightAbs ); + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + + aStRect = pSt2Pos->aLine; + (aStRect.*fnRect->fnSetLeft)( bR2L ? nRightAbs : nLeftAbs ); + (aStRect.*fnRect->fnSetWidth)( 1 ); + } + + SWRECTFNX( pEndFrm ) + if ( (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)() ) + { + SwRect aTmp( aEndRect ); + long nRightAbs = (pEnd2Pos->aPortion.*fnRectX->fnGetRight)(); + nRightAbs -= (pEnd2Pos->aPortion2.*fnRectX->fnGetLeft)(); + long nLeftAbs = nRightAbs - (pEnd2Pos->aPortion2.*fnRectX->fnGetWidth)(); + + (aTmp.*fnRectX->fnSetLeft)( nLeftAbs ); + aTmp.Intersection( aEndFrm ); + Sub( aRegion, aTmp ); + + aEndRect = pEnd2Pos->aLine; + (aEndRect.*fnRectX->fnSetLeft)( bEndR2L ? nLeftAbs : nRightAbs ); + (aEndRect.*fnRectX->fnSetWidth)( 1 ); + } + } + + // The charrect may be outside the paintarea (for cursortravelling) + // but the selection has to be restricted to the paintarea + if( aStRect.Left() < aStFrm.Left() ) + aStRect.Left( aStFrm.Left() ); + else if( aStRect.Left() > aStFrm.Right() ) + aStRect.Left( aStFrm.Right() ); + SwTwips nTmp = aStRect.Right(); + if( nTmp < aStFrm.Left() ) + aStRect.Right( aStFrm.Left() ); + else if( nTmp > aStFrm.Right() ) + aStRect.Right( aStFrm.Right() ); + if( aEndRect.Left() < aEndFrm.Left() ) + aEndRect.Left( aEndFrm.Left() ); + else if( aEndRect.Left() > aEndFrm.Right() ) + aEndRect.Left( aEndFrm.Right() ); + nTmp = aEndRect.Right(); + if( nTmp < aEndFrm.Left() ) + aEndRect.Right( aEndFrm.Left() ); + else if( nTmp > aEndFrm.Right() ) + aEndRect.Right( aEndFrm.Right() ); + + if( pStartFrm == pEndFrm ) + { + sal_Bool bSameRotatedOrBidi = pSt2Pos && pEnd2Pos && + ( MT_BIDI & pSt2Pos->nMultiType ) && + pSt2Pos->aPortion == pEnd2Pos->aPortion; + //case 1: (Same frame and same row) + if( bSameRotatedOrBidi || + (aStRect.*fnRect->fnGetTop)() == (aEndRect.*fnRect->fnGetTop)() ) + { + Point aTmpSt( aStRect.Pos() ); + Point aTmpEnd( aEndRect.Right(), aEndRect.Bottom() ); + if( bSameRotatedOrBidi || bR2L ) + { + if( aTmpSt.Y() > aTmpEnd.Y() ) + { + long nTmpY = aTmpEnd.Y(); + aTmpEnd.Y() = aTmpSt.Y(); + aTmpSt.Y() = nTmpY; + } + if( aTmpSt.X() > aTmpEnd.X() ) + { + long nTmpX = aTmpEnd.X(); + aTmpEnd.X() = aTmpSt.X(); + aTmpSt.X() = nTmpX; + } + } + + SwRect aTmp = SwRect( aTmpSt, aTmpEnd ); + // Bug 34888: falls Inhalt selektiert ist, der keinen Platz + // einnimmt (z.B. PostIts,RefMarks, TOXMarks), + // dann mindestens die Breite des Crsr setzen. + if( 1 == (aTmp.*fnRect->fnGetWidth)() && + pStartPos->nContent.GetIndex() != + pEndPos->nContent.GetIndex() ) + { + OutputDevice* pOut = pSh->GetOut(); + long nCrsrWidth = pOut->GetSettings().GetStyleSettings(). + GetCursorSize(); + (aTmp.*fnRect->fnSetWidth)( pOut->PixelToLogic( + Size( nCrsrWidth, 0 ) ).Width() ); + } + aTmp.Intersection( aStFrm ); + Sub( aRegion, aTmp ); + } + //case 2: (Same frame, but not the same line) + else + { + SwTwips lLeft, lRight; + if( pSt2Pos && pEnd2Pos && pSt2Pos->aPortion == pEnd2Pos->aPortion ) + { + lLeft = (pSt2Pos->aPortion.*fnRect->fnGetLeft)(); + lRight = (pSt2Pos->aPortion.*fnRect->fnGetRight)(); + } + else + { + lLeft = (pStartFrm->Frm().*fnRect->fnGetLeft)() + + (pStartFrm->Prt().*fnRect->fnGetLeft)(); + lRight = (pStartFrm->Frm().*fnRect->fnGetLeft)() + + (pStartFrm->Prt().*fnRect->fnGetRight)(); + } + if( lLeft < (aStFrm.*fnRect->fnGetLeft)() ) + lLeft = (aStFrm.*fnRect->fnGetLeft)(); + if( lRight > (aStFrm.*fnRect->fnGetRight)() ) + lRight = (aStFrm.*fnRect->fnGetRight)(); + SwRect aSubRect( aStRect ); + //First line + if( bR2L ) + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + else + (aSubRect.*fnRect->fnSetRight)( lRight ); + Sub( aRegion, aSubRect ); + + //If there's at least a twips between start- and endline, + //so the whole area between will be added. + SwTwips aTmpBottom = (aStRect.*fnRect->fnGetBottom)(); + SwTwips aTmpTop = (aEndRect.*fnRect->fnGetTop)(); + if( aTmpBottom != aTmpTop ) + { + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + (aSubRect.*fnRect->fnSetRight)( lRight ); + (aSubRect.*fnRect->fnSetTop)( aTmpBottom ); + (aSubRect.*fnRect->fnSetBottom)( aTmpTop ); + Sub( aRegion, aSubRect ); + } + //and the last line + aSubRect = aEndRect; + if( bR2L ) + (aSubRect.*fnRect->fnSetRight)( lRight ); + else + (aSubRect.*fnRect->fnSetLeft)( lLeft ); + Sub( aRegion, aSubRect ); + } + } + //case 3: (Different frames, maybe with ohther frames between + else + { + //The startframe first... + SwRect aSubRect( aStRect ); + if( bR2L ) + (aSubRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)()); + else + (aSubRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)()); + Sub( aRegion, aSubRect ); + SwTwips nTmpTwips = (aStRect.*fnRect->fnGetBottom)(); + if( (aStFrm.*fnRect->fnGetBottom)() != nTmpTwips ) + { + aSubRect = aStFrm; + (aSubRect.*fnRect->fnSetTop)( nTmpTwips ); + Sub( aRegion, aSubRect ); + } + + //Now the frames between, if there are any + sal_Bool bBody = pStartFrm->IsInDocBody(); + const SwTableBox* pCellBox = pStartFrm->GetUpper()->IsCellFrm() ? + ((SwCellFrm*)pStartFrm->GetUpper())->GetTabBox() : 0; + const SwCntntFrm *pCntnt = pStartFrm->GetNextCntntFrm(); + SwRect aPrvRect; + + // --> OD 2006-01-24 #123908# - introduce robust code: + // The stacktrace issue reveals that <pCntnt> could be NULL. + // One root cause found by AMA - see #130650# + OSL_ENSURE( pCntnt, + "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" ); + while ( pCntnt && pCntnt != pEndFrm ) + // <-- + { + if ( pCntnt->IsInFly() ) + { + const SwAnchoredObject* pObj = pCntnt->FindFlyFrm(); + aSortObjs.Insert( *(const_cast<SwAnchoredObject*>(pObj)) ); + } + + // Consider only frames which have the same IsInDocBody value like pStartFrm + // If pStartFrm is inside a SwCellFrm, consider only frames which are inside the + // same cell frame (or its follow cell) + const SwTableBox* pTmpCellBox = pCntnt->GetUpper()->IsCellFrm() ? + ((SwCellFrm*)pCntnt->GetUpper())->GetTabBox() : 0; + if ( bBody == pCntnt->IsInDocBody() && + ( !pCellBox || pCellBox == pTmpCellBox ) ) + { + SwRect aCRect( pCntnt->UnionFrm( sal_True ) ); + aCRect.Intersection( pCntnt->PaintArea() ); + if( aCRect.IsOver( aRegion.GetOrigin() )) + { + SwRect aTmp( aPrvRect ); + aTmp.Union( aCRect ); + if ( (aPrvRect.Height() * aPrvRect.Width() + + aCRect.Height() * aCRect.Width()) == + (aTmp.Height() * aTmp.Width()) ) + { + aPrvRect.Union( aCRect ); + } + else + { + if ( aPrvRect.HasArea() ) + Sub( aRegion, aPrvRect ); + aPrvRect = aCRect; + } + } + } + pCntnt = pCntnt->GetNextCntntFrm(); + // --> OD 2006-01-24 #123908# + OSL_ENSURE( pCntnt, + "<SwRootFrm::CalcFrmRects(..)> - no content frame. This is a serious defect -> please inform OD" ); + // <-- + } + if ( aPrvRect.HasArea() ) + Sub( aRegion, aPrvRect ); + + //At least the endframe... + bVert = pEndFrm->IsVertical(); + bRev = pEndFrm->IsReverse(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + fnRect = bVert ? ( bRev ? fnRectVL2R : ( pEndFrm->IsVertLR() ? fnRectVertL2R : fnRectVert ) ) : + ( bRev ? fnRectB2T : fnRectHori ); + nTmpTwips = (aEndRect.*fnRect->fnGetTop)(); + if( (aEndFrm.*fnRect->fnGetTop)() != nTmpTwips ) + { + aSubRect = aEndFrm; + (aSubRect.*fnRect->fnSetBottom)( nTmpTwips ); + Sub( aRegion, aSubRect ); + } + aSubRect = aEndRect; + if( bEndR2L ) + (aSubRect.*fnRect->fnSetRight)((aEndFrm.*fnRect->fnGetRight)()); + else + (aSubRect.*fnRect->fnSetLeft)( (aEndFrm.*fnRect->fnGetLeft)() ); + Sub( aRegion, aSubRect ); + } + +// aRegion.Compress( sal_False ); + aRegion.Invert(); + delete pSt2Pos; + delete pEnd2Pos; + } + + //Flys mit Durchlauf ausstanzen. Nicht ausgestanzt werden Flys: + //- die Lower des StartFrm/EndFrm sind (FlyInCnt und alle Flys die wiederum + // darin sitzen) + //- in der Z-Order ueber denjenigen Flys stehen in denen sich der StartFrm + // befindet. + const SwPageFrm *pPage = pStartFrm->FindPageFrm(); + const SwPageFrm *pEndPage = pEndFrm->FindPageFrm(); + + while ( pPage ) + { + if ( pPage->GetSortedObjs() ) + { + const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( !pAnchoredObj->ISA(SwFlyFrm) ) + continue; + const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj); + const SwVirtFlyDrawObj* pObj = pFly->GetVirtDrawObj(); + const SwFmtSurround &rSur = pFly->GetFmt()->GetSurround(); + if ( !pFly->IsAnLower( pStartFrm ) && + (rSur.GetSurround() != SURROUND_THROUGHT && + !rSur.IsContour()) ) + { + if ( aSortObjs.Contains( *pAnchoredObj ) ) + continue; + + sal_Bool bSub = sal_True; + const sal_uInt32 nPos = pObj->GetOrdNum(); + for ( sal_uInt16 k = 0; bSub && k < aSortObjs.Count(); ++k ) + { + OSL_ENSURE( aSortObjs[k]->ISA(SwFlyFrm), + "<SwRootFrm::CalcFrmRects(..)> - object in <aSortObjs> of unexcepted type" ); + const SwFlyFrm* pTmp = static_cast<SwFlyFrm*>(aSortObjs[k]); + do + { if ( nPos < pTmp->GetVirtDrawObj()->GetOrdNumDirect() ) + bSub = sal_False; + else + pTmp = pTmp->GetAnchorFrm()->FindFlyFrm(); + } while ( bSub && pTmp ); + } + if ( bSub ) + Sub( aRegion, pFly->Frm() ); + } + } + } + if ( pPage == pEndPage ) + break; + else + pPage = (SwPageFrm*)pPage->GetNext(); + } + + //Weil's besser aussieht noch die DropCaps ausschliessen. + SwRect aDropRect; + if ( pStartFrm->IsTxtFrm() ) + { + if ( ((SwTxtFrm*)pStartFrm)->GetDropRect( aDropRect ) ) + Sub( aRegion, aDropRect ); + } + if ( pEndFrm != pStartFrm && pEndFrm->IsTxtFrm() ) + { + if ( ((SwTxtFrm*)pEndFrm)->GetDropRect( aDropRect ) ) + Sub( aRegion, aDropRect ); + } + + rCrsr.Remove( 0, rCrsr.Count() ); + rCrsr.Insert( &aRegion, 0 ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/unusedf.cxx b/sw/source/core/layout/unusedf.cxx new file mode 100644 index 000000000000..7c38aaa4430e --- /dev/null +++ b/sw/source/core/layout/unusedf.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "rootfrm.hxx" +#include "cntfrm.hxx" +#include "flyfrm.hxx" + + +void SwFrm::Format( const SwBorderAttrs * ) +{ + OSL_FAIL( "Format() der Basisklasse gerufen." ); +} + +void SwFrm::Paint(SwRect const&, SwPrintData const*const) const +{ + OSL_FAIL( "Paint() der Basisklasse gerufen." ); +} + +sal_Bool SwCntntFrm::WouldFit( SwTwips &, sal_Bool&, sal_Bool ) +{ + OSL_FAIL( "WouldFit des CntntFrm gerufen." ); + return sal_False; +} + +bool SwFrm::FillSelection( SwSelectionList& , const SwRect& ) const +{ + OSL_FAIL( "Don't call this function at the base class!" ); + return false; +} + +sal_Bool SwFrm::GetCrsrOfst( SwPosition *, Point&, SwCrsrMoveState* ) const +{ + OSL_FAIL( "GetCrsrOfst der Basisklasse, hi!" ); + return sal_False; +} + +#if OSL_DEBUG_LEVEL > 1 + +void SwRootFrm::Cut() +{ + OSL_FAIL( "Cut() des RootFrm gerufen." ); +} + +void SwRootFrm::Paste( SwFrm *, SwFrm * ) +{ + OSL_FAIL( "Paste() des RootFrm gerufen." ); +} + +void SwFlyFrm::Paste( SwFrm *, SwFrm * ) +{ + OSL_FAIL( "Paste() des FlyFrm gerufen." ); +} + +#endif + +sal_Bool SwFrm::GetCharRect( SwRect&, const SwPosition&, + SwCrsrMoveState* ) const +{ + OSL_FAIL( "GetCharRect() der Basis gerufen." ); + return sal_False; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/virtoutp.cxx b/sw/source/core/layout/virtoutp.cxx new file mode 100644 index 000000000000..d769f3c4987a --- /dev/null +++ b/sw/source/core/layout/virtoutp.cxx @@ -0,0 +1,258 @@ +/* -*- 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 <vcl/window.hxx> + +#include "hintids.hxx" +#include "viewsh.hxx" +#include "virtoutp.hxx" +#include "viewopt.hxx" +#include "rootfrm.hxx" +// OD 12.11.2002 #96272# - include declaration for <SetMappingForVirtDev> +#include "setmapvirtdev.hxx" + +#if OSL_DEBUG_LEVEL > 1 + +/************************************************************************* + * class DbgRect + *************************************************************************/ + +class DbgRect +{ + OutputDevice *pOut; +public: + DbgRect( OutputDevice *pOut, const Rectangle &rRect, + const ColorData eColor = COL_LIGHTBLUE ); +}; + +inline DbgRect::DbgRect( OutputDevice *pOutDev, const Rectangle &rRect, + const ColorData eColor ) + :pOut( pOutDev ) +{ + if( pOut ) + { + pOut->Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + pOut->SetLineColor( eColor ); + pOut->SetFillColor(); + pOut->DrawRect( rRect ); + pOut->Pop(); + } +} + +#endif + +/* class SwLayVout verwaltet das virtuelle Outputdevice + * Es gibt von dieser Klasse einen statischen Member am RootFrm, + * dieser wird in _FrmInit angelegt und in _FrmFinit zerstoert. + * */ + +sal_Bool SwRootFrm::FlushVout() +{ + if( SwRootFrm::pVout->IsFlushable() ) + { + SwRootFrm::pVout->_Flush(); + return sal_True; + } + return sal_False; +} + +sal_Bool SwRootFrm::HasSameRect( const SwRect& rRect ) +{ + if( SwRootFrm::pVout->IsFlushable() ) + return ( rRect == SwRootFrm::pVout->GetOrgRect() ); + return sal_False; +} + +/** method to set mapping/pixel offset for virtual output device + + OD 12.11.2002 #96272# - method implements two solutions for the mapping of + the virtual output device: + The old solution set the origin of the mapping mode, which will be used in + the virtual output device. This causes several paint errors, because of the + different roundings in the virtual output device and the original output device. + The new solution avoids the rounding differences between virtual and original + output device by setting a pixel offset at the virtual output device. + A define controls, which solution is used, in order to switch in escalation + back to old solution. + + @author OD + + @param _pOrgOutDev + input parameter - constant instance of the original output device, for which + the virtual output device is created. + + @param _pVirDev + input/output parameter - instance of the virtual output device. + + @param _pMapMode + input/output parameter - instance of the mapping mode, which will be set + at the virtual output device. + + @param _rNewOrigin + input parameter - constant instance of the origin, which will be used in + the virtual output device +*/ +// define to control, if old or new solution for setting the mapping for +// an virtual output device is used. +void SetMappingForVirtDev( const Point& _rNewOrigin, + MapMode* , + const OutputDevice* _pOrgOutDev, + VirtualDevice* _pVirDev ) +{ + // new solution: set pixel offset at virtual output device + Point aPixelOffset = _pOrgOutDev->LogicToPixel( _rNewOrigin ); + _pVirDev->SetPixelOffset( Size( -aPixelOffset.X(), -aPixelOffset.Y() ) ); +} + + +/************************************************************************* + * SwVOut::DoesFit() + *************************************************************************/ + +// rSize muss in Pixel-Koordinaten vorliegen! +sal_Bool SwLayVout::DoesFit( const Size &rNew ) +{ + if( rNew.Height() > VIRTUALHEIGHT ) + return sal_False; + if( rNew.Width() <= 0 || rNew.Height() <= 0 ) + return sal_False; + if( rNew.Width() <= aSize.Width() ) + return sal_True; + if( !pVirDev ) + { + pVirDev = new VirtualDevice(); + pVirDev->SetLineColor(); + if( pOut ) + { + if( pVirDev->GetFillColor() != pOut->GetFillColor() ) + pVirDev->SetFillColor( pOut->GetFillColor() ); + } + } + + if( rNew.Width() > aSize.Width() ) + { + aSize.Width() = rNew.Width(); + if( !pVirDev->SetOutputSizePixel( aSize ) ) + { + delete pVirDev; + pVirDev = NULL; + aSize.Width() = 0; + return sal_False; + } + } + return sal_True; +} + +/************************************************************************* + * SwLayVout::Enter + *************************************************************************/ +/// OD 27.09.2002 #103636# - change 2nd parameter <rRect> - no longer <const> +/// in order to return value of class member variable <aRect>, if virtual +/// output is used. +/// <aRect> contains the rectangle that represents the area the virtual +/// output device is used for and that is flushed at the end. +void SwLayVout::Enter( ViewShell *pShell, SwRect &rRect, sal_Bool bOn ) +{ + Flush(); + +#if OSL_DEBUG_LEVEL > 1 + if( pShell->GetViewOptions()->IsTest3() ) + { + ++nCount; + return; + } +#endif + + bOn = bOn && !nCount && rRect.HasArea() && pShell->GetWin(); + ++nCount; + if( bOn ) + { + pSh = pShell; + pOut = NULL; + OutputDevice *pO = pSh->GetOut(); +// Auf dem Drucker oder einem virt. Outputdevice wird nicht getrickst... + if( OUTDEV_WINDOW != pO->GetOutDevType() ) + return; + + pOut = pO; + Size aPixSz( pOut->PixelToLogic( Size( 1,1 )) ); + SwRect aTmp( rRect ); + aTmp.SSize().Width() += aPixSz.Width()/2 + 1; + aTmp.SSize().Height()+= aPixSz.Height()/2 + 1; + Rectangle aTmpRect( pO->LogicToPixel( aTmp.SVRect() ) ); + + OSL_ENSURE( !pSh->GetWin()->IsReallyVisible() || + aTmpRect.GetWidth() <= pSh->GetWin()->GetOutputSizePixel().Width() + 2, + "Paintwidth bigger than visarea?" ); + // Passt das Rechteck in unseren Buffer ? + if( !DoesFit( aTmpRect.GetSize() ) ) + { + pOut = NULL; + return; + } + + aRect = SwRect( pO->PixelToLogic( aTmpRect ) ); + + SetOutDev( pSh, pVirDev ); + + if( pVirDev->GetFillColor() != pOut->GetFillColor() ) + pVirDev->SetFillColor( pOut->GetFillColor() ); + + MapMode aMapMode( pOut->GetMapMode() ); + // OD 12.11.2002 #96272# - use method to set mapping + //aMapMode.SetOrigin( Point(0,0) - aRect.Pos() ); + ::SetMappingForVirtDev( aRect.Pos(), &aMapMode, pOut, pVirDev ); + + if( aMapMode != pVirDev->GetMapMode() ) + pVirDev->SetMapMode( aMapMode ); + + /// OD 27.09.2002 #103636# - set value of parameter <rRect> + rRect = aRect; + } +} + +/************************************************************************* + * SwLayVout::Flush() + *************************************************************************/ + +void SwLayVout::_Flush() +{ + OSL_ENSURE( pVirDev, "SwLayVout::DrawOut: nothing left Toulouse" ); + Rectangle aTmp( aRect.SVRect() ); + pOut->DrawOutDev( aRect.Pos(), aRect.SSize(), + aRect.Pos(), aRect.SSize(), *pVirDev ); + SetOutDev( pSh, pOut ); + pOut = NULL; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/virtoutp.hxx b/sw/source/core/layout/virtoutp.hxx new file mode 100644 index 000000000000..f3f27a184150 --- /dev/null +++ b/sw/source/core/layout/virtoutp.hxx @@ -0,0 +1,77 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _VIRTOUTP_HXX +#define _VIRTOUTP_HXX + +#include <vcl/virdev.hxx> + +#include "swtypes.hxx" // UCHAR +#include "swrect.hxx" // SwRect + +class ViewShell; +#define VIRTUALHEIGHT 64 + +/************************************************************************* + * class SwTxtVout + *************************************************************************/ + +class SwLayVout +{ + friend void _FrmFinit(); //loescht das Vout +private: + ViewShell* pSh; + OutputDevice* pOut; + VirtualDevice* pVirDev; + SwRect aRect; + SwRect aOrgRect; + Size aSize; + sal_uInt16 nCount; + + sal_Bool DoesFit( const Size &rOut ); + +public: + SwLayVout() : pSh(0), pOut(0), pVirDev(0), aSize(0, VIRTUALHEIGHT), nCount(0) {} + ~SwLayVout() { delete pVirDev; } + + /// OD 27.09.2002 #103636# - change 2nd parameter <rRect> - no longer <const> + void Enter( ViewShell *pShell, SwRect &rRect, sal_Bool bOn ); + void Leave() { --nCount; Flush(); } + + void SetOrgRect( SwRect &rRect ) { aOrgRect = rRect; } + const SwRect& GetOrgRect() const { return aOrgRect; } + + sal_Bool IsFlushable() { return 0 != pOut; } + void _Flush(); + void Flush() { if( pOut ) _Flush(); } +}; + + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx new file mode 100644 index 000000000000..0d9f04e62d9c --- /dev/null +++ b/sw/source/core/layout/wsfrm.cxx @@ -0,0 +1,3967 @@ +/* -*- 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 <hints.hxx> +#include <tools/pstm.hxx> +#include <vcl/outdev.hxx> +#include <svl/itemiter.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/brkitem.hxx> +#include <fmtornt.hxx> +#include <pagefrm.hxx> +#include <section.hxx> +#include <rootfrm.hxx> +#include <cntfrm.hxx> +#include <dcontact.hxx> +#include <anchoreddrawobject.hxx> +#include <fmtanchr.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> +#include "viewopt.hxx" +#include <doc.hxx> +#include <fesh.hxx> +#include <docsh.hxx> +#include <flyfrm.hxx> +#include <frmtool.hxx> +#include <ftninfo.hxx> +#include <dflyobj.hxx> +#include <fmtclbl.hxx> +#include <fmtfordr.hxx> +#include <fmtfsize.hxx> +#include <fmtpdsc.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <fmtsrnd.hxx> +#include <ftnfrm.hxx> +#include <tabfrm.hxx> +#include <htmltbl.hxx> +#include <flyfrms.hxx> +#include <sectfrm.hxx> +#include <fmtclds.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> +#include <bodyfrm.hxx> +#include <cellfrm.hxx> +#include <dbg_lay.hxx> +#include <editeng/frmdiritem.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + + +using namespace ::com::sun::star; + + +/************************************************************************* +|* +|* SwFrm::SwFrm() +|* +|*************************************************************************/ + +SwFrm::SwFrm( SwModify *pMod, SwFrm* pSib ) : + SwClient( pMod ), + // --> OD 2006-05-10 #i65250# + mnFrmId( SwFrm::mnLastFrmId++ ), + // <-- + mpRoot( pSib ? pSib->getRootFrm() : 0 ), + pUpper( 0 ), + pNext( 0 ), + pPrev( 0 ), + pDrawObjs( 0 ) + , bInfBody( sal_False ) + , bInfTab ( sal_False ) + , bInfFly ( sal_False ) + , bInfFtn ( sal_False ) + , bInfSct ( sal_False ) +{ +#if OSL_DEBUG_LEVEL > 1 + bFlag01 = bFlag02 = bFlag03 = bFlag04 = bFlag05 = 0; +#endif + + OSL_ENSURE( pMod, "Kein Frameformat uebergeben." ); + bInvalidR2L = bInvalidVert = 1; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + bDerivedR2L = bDerivedVert = bRightToLeft = bVertical = bReverse = bVertLR = 0; + + bValidPos = bValidPrtArea = bValidSize = bValidLineNum = bRetouche = + bFixSize = bColLocked = sal_False; + bCompletePaint = bInfInvalid = sal_True; +} + +const IDocumentDrawModelAccess* SwFrm::getIDocumentDrawModelAccess() +{ + return GetUpper()->GetFmt()->getIDocumentDrawModelAccess(); +} + +bool SwFrm::KnowsFormat( const SwFmt& rFmt ) const +{ + return GetRegisteredIn() == &rFmt; +} + +void SwFrm::RegisterToFormat( SwFmt& rFmt ) +{ + rFmt.Add( this ); +} + +void SwFrm::CheckDir( sal_uInt16 nDir, sal_Bool bVert, sal_Bool bOnlyBiDi, sal_Bool bBrowse ) +{ + if( FRMDIR_ENVIRONMENT == nDir || ( bVert && bOnlyBiDi ) ) + { + bDerivedVert = 1; + if( FRMDIR_ENVIRONMENT == nDir ) + bDerivedR2L = 1; + SetDirFlags( bVert ); + } + else if( bVert ) + { + bInvalidVert = 0; + if( FRMDIR_HORI_LEFT_TOP == nDir || FRMDIR_HORI_RIGHT_TOP == nDir + || bBrowse ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + { + bVertical = 0; + bVertLR = 0; + } + else + { + bVertical = 1; + if(FRMDIR_VERT_TOP_RIGHT == nDir) + bVertLR = 0; + else if(FRMDIR_VERT_TOP_LEFT==nDir) + bVertLR = 1; + } + } + else + { + bInvalidR2L = 0; + if( FRMDIR_HORI_RIGHT_TOP == nDir ) + bRightToLeft = 1; + else + bRightToLeft = 0; + } +} + +void SwFrm::CheckDirection( sal_Bool bVert ) +{ + if( bVert ) + { + if( !IsHeaderFrm() && !IsFooterFrm() ) + { + bDerivedVert = 1; + SetDirFlags( bVert ); + } + } + else + { + bDerivedR2L = 1; + SetDirFlags( bVert ); + } +} + +void SwSectionFrm::CheckDirection( sal_Bool bVert ) +{ + const SwFrmFmt* pFmt = GetFmt(); + if( pFmt ) + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + CheckDir(((SvxFrameDirectionItem&)pFmt->GetFmtAttr(RES_FRAMEDIR)).GetValue(), + bVert, sal_True, bBrowseMode ); + } + else + SwFrm::CheckDirection( bVert ); +} + +void SwFlyFrm::CheckDirection( sal_Bool bVert ) +{ + const SwFrmFmt* pFmt = GetFmt(); + if( pFmt ) + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + CheckDir(((SvxFrameDirectionItem&)pFmt->GetFmtAttr(RES_FRAMEDIR)).GetValue(), + bVert, sal_False, bBrowseMode ); + } + else + SwFrm::CheckDirection( bVert ); +} + +void SwTabFrm::CheckDirection( sal_Bool bVert ) +{ + const SwFrmFmt* pFmt = GetFmt(); + if( pFmt ) + { + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + CheckDir(((SvxFrameDirectionItem&)pFmt->GetFmtAttr(RES_FRAMEDIR)).GetValue(), + bVert, sal_True, bBrowseMode ); + } + else + SwFrm::CheckDirection( bVert ); +} + +void SwCellFrm::CheckDirection( sal_Bool bVert ) +{ + const SwFrmFmt* pFmt = GetFmt(); + const SfxPoolItem* pItem; + // --> FME 2006-03-30 #b6402837# Check if the item is set, before actually + // using it. Otherwise the dynamic pool default is used, which may be set + // to LTR in case of OOo 1.0 documents. + // <-- + if( pFmt && SFX_ITEM_SET == pFmt->GetItemState( RES_FRAMEDIR, sal_True, &pItem ) ) + { + const SvxFrameDirectionItem* pFrmDirItem = static_cast<const SvxFrameDirectionItem*>(pItem); + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + CheckDir( pFrmDirItem->GetValue(), bVert, sal_False, bBrowseMode ); + } + else + SwFrm::CheckDirection( bVert ); +} + +void SwTxtFrm::CheckDirection( sal_Bool bVert ) +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + CheckDir( GetTxtNode()->GetSwAttrSet().GetFrmDir().GetValue(), bVert, + sal_True, bBrowseMode ); +} + +/*************************************************************************/ +void SwFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + + if( pNew && RES_ATTRSET_CHG == pNew->Which() ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + while( sal_True ) + { + _UpdateAttrFrm( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + } + else + _UpdateAttrFrm( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + if ( nInvFlags & 0x01 ) + { + _InvalidatePrt(); + if( !GetPrev() && IsTabFrm() && IsInSct() ) + FindSctFrm()->_InvalidatePrt(); + } + if ( nInvFlags & 0x02 ) + _InvalidateSize(); + if ( nInvFlags & 0x04 ) + _InvalidatePos(); + if ( nInvFlags & 0x08 ) + SetCompletePaint(); + SwFrm *pNxt; + if ( nInvFlags & 0x30 && 0 != (pNxt = GetNext()) ) + { + pNxt->InvalidatePage( pPage ); + if ( nInvFlags & 0x10 ) + pNxt->_InvalidatePos(); + if ( nInvFlags & 0x20 ) + pNxt->SetCompletePaint(); + } + } +} + +void SwFrm::_UpdateAttrFrm( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags ) +{ + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { + case RES_BOX: + case RES_SHADOW: + Prepare( PREP_FIXSIZE_CHG ); + // hier kein break ! + case RES_LR_SPACE: + case RES_UL_SPACE: + rInvFlags |= 0x0B; + break; + + case RES_HEADER_FOOTER_EAT_SPACING: + rInvFlags |= 0x03; + break; + + case RES_BACKGROUND: + rInvFlags |= 0x28; + break; + + case RES_KEEP: + rInvFlags |= 0x04; + break; + + case RES_FRM_SIZE: + ReinitializeFrmSizeAttrFlags(); + rInvFlags |= 0x13; + break; + + case RES_FMT_CHG: + rInvFlags |= 0x0F; + break; + + case RES_ROW_SPLIT: + { + if ( IsRowFrm() ) + { + sal_Bool bInFollowFlowRow = 0 != IsInFollowFlowRow(); + if ( bInFollowFlowRow || 0 != IsInSplitTableRow() ) + { + SwTabFrm* pTab = FindTabFrm(); + if ( bInFollowFlowRow ) + pTab = pTab->FindMaster(); + pTab->SetRemoveFollowFlowLinePending( sal_True ); + } + } + break; + } + case RES_COL: + OSL_FAIL( "Spalten fuer neuen FrmTyp?" ); + break; + + default: + /* do Nothing */; + } +} + +/************************************************************************* +|* +|* SwFrm::Prepare() +|* +|*************************************************************************/ +void SwFrm::Prepare( const PrepareHint, const void *, sal_Bool ) +{ + /* Do nothing */ +} + +/************************************************************************* +|* +|* SwFrm::InvalidatePage() +|* Beschreibung: Invalidiert die Seite, in der der Frm gerade steht. +|* Je nachdem ob es ein Layout, Cntnt oder FlyFrm ist wird die Seite +|* entsprechend Invalidiert. +|* +|*************************************************************************/ +void SwFrm::InvalidatePage( const SwPageFrm *pPage ) const +{ + if ( !pPage ) + { + pPage = FindPageFrm(); + // --> OD 2004-07-02 #i28701# - for at-character and as-character + // anchored Writer fly frames additionally invalidate also page frame + // its 'anchor character' is on. + if ( pPage && pPage->GetUpper() && IsFlyFrm() ) + { + const SwFlyFrm* pFlyFrm = static_cast<const SwFlyFrm*>(this); + if ( pFlyFrm->IsAutoPos() || pFlyFrm->IsFlyInCntFrm() ) + { + // --> OD 2004-09-23 #i33751#, #i34060# - method <GetPageFrmOfAnchor()> + // is replaced by method <FindPageFrmOfAnchor()>. It's return value + // have to be checked. + SwPageFrm* pPageFrmOfAnchor = + const_cast<SwFlyFrm*>(pFlyFrm)->FindPageFrmOfAnchor(); + if ( pPageFrmOfAnchor && pPageFrmOfAnchor != pPage ) + // <-- + { + InvalidatePage( pPageFrmOfAnchor ); + } + } + } + // <-- + } + + if ( pPage && pPage->GetUpper() ) + { + if ( pPage->GetFmt()->GetDoc()->IsInDtor() ) + return; + + SwRootFrm *pRoot = (SwRootFrm*)pPage->GetUpper(); + const SwFlyFrm *pFly = FindFlyFrm(); + if ( IsCntntFrm() ) + { + if ( pRoot->IsTurboAllowed() ) + { + // JP 21.09.95: wenn sich der ContentFrame 2 mal eintragen + // will, kann es doch eine TurboAction bleiben. + // ODER???? + if ( !pRoot->GetTurbo() || this == pRoot->GetTurbo() ) + pRoot->SetTurbo( (const SwCntntFrm*)this ); + else + { + pRoot->DisallowTurbo(); + //Die Seite des Turbo koennte eine andere als die meinige + //sein, deshalb muss sie invalidiert werden. + const SwFrm *pTmp = pRoot->GetTurbo(); + pRoot->ResetTurbo(); + pTmp->InvalidatePage(); + } + } + if ( !pRoot->GetTurbo() ) + { + if ( pFly ) + { if( !pFly->IsLocked() ) + { + if ( pFly->IsFlyInCntFrm() ) + { pPage->InvalidateFlyInCnt(); + ((SwFlyInCntFrm*)pFly)->InvalidateCntnt(); + pFly->GetAnchorFrm()->InvalidatePage(); + } + else + pPage->InvalidateFlyCntnt(); + } + } + else + pPage->InvalidateCntnt(); + } + } + else + { + pRoot->DisallowTurbo(); + if ( pFly ) + { + if ( !pFly->IsLocked() ) + { + if ( pFly->IsFlyInCntFrm() ) + { + pPage->InvalidateFlyInCnt(); + ((SwFlyInCntFrm*)pFly)->InvalidateLayout(); + pFly->GetAnchorFrm()->InvalidatePage(); + } + else + pPage->InvalidateFlyLayout(); + } + } + else + pPage->InvalidateLayout(); + + if ( pRoot->GetTurbo() ) + { const SwFrm *pTmp = pRoot->GetTurbo(); + pRoot->ResetTurbo(); + pTmp->InvalidatePage(); + } + } + pRoot->SetIdleFlags(); + + const SwTxtFrm *pTxtFrm = dynamic_cast< const SwTxtFrm * >(this); + if (pTxtFrm) + { + const SwTxtNode *pTxtNode = pTxtFrm->GetTxtNode(); + if (pTxtNode && pTxtNode->IsGrammarCheckDirty()) + pRoot->SetNeedGrammarCheck( sal_True ); + } + } +} + +/************************************************************************* +|* +|* SwFrm::ChgSize() +|* +|*************************************************************************/ +Size SwFrm::ChgSize( const Size& aNewSize ) +{ + bFixSize = sal_True; + const Size aOldSize( Frm().SSize() ); + if ( aNewSize == aOldSize ) + return aOldSize; + + if ( GetUpper() ) + { + SWRECTFN2( this ) + SwRect aNew( Point(0,0), aNewSize ); + (aFrm.*fnRect->fnSetWidth)( (aNew.*fnRect->fnGetWidth)() ); + long nNew = (aNew.*fnRect->fnGetHeight)(); + long nDiff = nNew - (aFrm.*fnRect->fnGetHeight)(); + if( nDiff ) + { + if ( GetUpper()->IsFtnBossFrm() && HasFixSize() && + NA_GROW_SHRINK != + ((SwFtnBossFrm*)GetUpper())->NeighbourhoodAdjustment( this ) ) + { + (aFrm.*fnRect->fnSetHeight)( nNew ); + SwTwips nReal = ((SwLayoutFrm*)this)->AdjustNeighbourhood(nDiff); + if ( nReal != nDiff ) + (aFrm.*fnRect->fnSetHeight)( nNew - nDiff + nReal ); + } + else + { + // OD 24.10.2002 #97265# - grow/shrink not for neighbour frames + // NOTE: neighbour frames are cell and column frames. + if ( !bNeighb ) + { + if ( nDiff > 0 ) + Grow( nDiff ); + else + Shrink( -nDiff ); + + if ( GetUpper() && (aFrm.*fnRect->fnGetHeight)() != nNew ) + GetUpper()->_InvalidateSize(); + } + + // Auch wenn das Grow/Shrink noch nicht die gewuenschte Breite eingestellt hat, + // wie z.B. beim Aufruf durch ChgColumns, um die Spaltenbreiten einzustellen, + // wird die Breite jetzt gesetzt. + (aFrm.*fnRect->fnSetHeight)( nNew ); + } + } + } + else + aFrm.SSize( aNewSize ); + + if ( Frm().SSize() != aOldSize ) + { + SwPageFrm *pPage = FindPageFrm(); + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + GetNext()->InvalidatePage( pPage ); + } + if( IsLayoutFrm() ) + { + if( IsRightToLeft() ) + _InvalidatePos(); + if( ((SwLayoutFrm*)this)->Lower() ) + ((SwLayoutFrm*)this)->Lower()->_InvalidateSize(); + } + _InvalidatePrt(); + _InvalidateSize(); + InvalidatePage( pPage ); + } + + return aFrm.SSize(); +} + +/************************************************************************* +|* +|* SwFrm::InsertBefore() +|* +|* Beschreibung SwFrm wird in eine bestehende Struktur eingefuegt +|* Eingefuegt wird unterhalb des Parent und entweder +|* vor pBehind oder am Ende der Kette wenn pBehind +|* leer ist. +|* +|*************************************************************************/ +void SwFrm::InsertBefore( SwLayoutFrm* pParent, SwFrm* pBehind ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Insert." ); + OSL_ENSURE( (!pBehind || (pBehind && pParent == pBehind->GetUpper())), + "Framebaum inkonsistent." ); + + pUpper = pParent; + pNext = pBehind; + if( pBehind ) + { //Einfuegen vor pBehind. + if( 0 != (pPrev = pBehind->pPrev) ) + pPrev->pNext = this; + else + pUpper->pLower = this; + pBehind->pPrev = this; + } + else + { //Einfuegen am Ende, oder als ersten Node im Unterbaum + pPrev = pUpper->Lower(); + if ( pPrev ) + { + while( pPrev->pNext ) + pPrev = pPrev->pNext; + pPrev->pNext = this; + } + else + pUpper->pLower = this; + } +} + +/************************************************************************* +|* +|* SwFrm::InsertBehind() +|* +|* Beschreibung SwFrm wird in eine bestehende Struktur eingefuegt +|* Eingefuegt wird unterhalb des Parent und entweder +|* hinter pBefore oder am Anfang der Kette wenn pBefore +|* leer ist. +|* +|*************************************************************************/ +void SwFrm::InsertBehind( SwLayoutFrm *pParent, SwFrm *pBefore ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Insert." ); + OSL_ENSURE( (!pBefore || (pBefore && pParent == pBefore->GetUpper())), + "Framebaum inkonsistent." ); + + pUpper = pParent; + pPrev = pBefore; + if ( pBefore ) + { + //Einfuegen hinter pBefore + if ( 0 != (pNext = pBefore->pNext) ) + pNext->pPrev = this; + pBefore->pNext = this; + } + else + { + //Einfuegen am Anfang der Kette + pNext = pParent->Lower(); + if ( pParent->Lower() ) + pParent->Lower()->pPrev = this; + pParent->pLower = this; + } +} + +/************************************************************************* +|* +|* SwFrm::InsertGroup() +|* +|* Beschreibung Eine Kette von SwFrms wird in eine bestehende Struktur +|* eingefuegt +|* +|* Bisher wird dies genutzt, um einen SectionFrame, der ggf. schon Geschwister +|* mit sich bringt, in eine bestehende Struktur einzufuegen. +|* +|* Wenn man den dritten Parameter als NULL uebergibt, entspricht +|* diese Methode dem SwFrm::InsertBefore(..), nur eben mit Geschwistern. +|* +|* Wenn man einen dritten Parameter uebergibt, passiert folgendes: +|* this wird pNext von pParent, +|* pSct wird pNext vom Letzten der this-Kette, +|* pBehind wird vom pParent an den pSct umgehaengt. +|* Dies dient dazu: ein SectionFrm (this) wird nicht als +|* Kind an einen anderen SectionFrm (pParent) gehaengt, sondern pParent +|* wird in zwei Geschwister aufgespalten (pParent+pSct) und this dazwischen +|* eingebaut. +|* +|*************************************************************************/ +void SwFrm::InsertGroupBefore( SwFrm* pParent, SwFrm* pBehind, SwFrm* pSct ) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Insert." ); + OSL_ENSURE( (!pBehind || ( (pBehind && (pParent == pBehind->GetUpper())) + || ((pParent->IsSctFrm() && pBehind->GetUpper()->IsColBodyFrm())) ) ), + "Framebaum inkonsistent." ); + if( pSct ) + { + pUpper = pParent->GetUpper(); + SwFrm *pLast = this; + while( pLast->GetNext() ) + { + pLast = pLast->GetNext(); + pLast->pUpper = GetUpper(); + } + if( pBehind ) + { + pLast->pNext = pSct; + pSct->pPrev = pLast; + pSct->pNext = pParent->GetNext(); + } + else + { + pLast->pNext = pParent->GetNext(); + if( pLast->GetNext() ) + pLast->GetNext()->pPrev = pLast; + } + pParent->pNext = this; + pPrev = pParent; + if( pSct->GetNext() ) + pSct->GetNext()->pPrev = pSct; + while( pLast->GetNext() ) + { + pLast = pLast->GetNext(); + pLast->pUpper = GetUpper(); + } + if( pBehind ) + { //Einfuegen vor pBehind. + if( pBehind->GetPrev() ) + pBehind->GetPrev()->pNext = NULL; + else + pBehind->GetUpper()->pLower = NULL; + pBehind->pPrev = NULL; + SwLayoutFrm* pTmp = (SwLayoutFrm*)pSct; + if( pTmp->Lower() ) + { + OSL_ENSURE( pTmp->Lower()->IsColumnFrm(), "InsertGrp: Used SectionFrm" ); + pTmp = (SwLayoutFrm*)((SwLayoutFrm*)pTmp->Lower())->Lower(); + OSL_ENSURE( pTmp, "InsertGrp: Missing ColBody" ); + } + pBehind->pUpper = pTmp; + pBehind->GetUpper()->pLower = pBehind; + pLast = pBehind->GetNext(); + while ( pLast ) + { + pLast->pUpper = pBehind->GetUpper(); + pLast = pLast->GetNext(); + }; + } + else + { + OSL_ENSURE( pSct->IsSctFrm(), "InsertGroup: For SectionFrms only" ); + delete ((SwSectionFrm*)pSct); + } + } + else + { + pUpper = (SwLayoutFrm*)pParent; + SwFrm *pLast = this; + while( pLast->GetNext() ) + { + pLast = pLast->GetNext(); + pLast->pUpper = GetUpper(); + } + pLast->pNext = pBehind; + if( pBehind ) + { //Einfuegen vor pBehind. + if( 0 != (pPrev = pBehind->pPrev) ) + pPrev->pNext = this; + else + pUpper->pLower = this; + pBehind->pPrev = pLast; + } + else + { //Einfuegen am Ende, oder des ersten Nodes im Unterbaum + pPrev = pUpper->Lower(); + if ( pPrev ) + { + while( pPrev->pNext ) + pPrev = pPrev->pNext; + pPrev->pNext = this; + } + else + pUpper->pLower = this; + } + } +} + +/************************************************************************* +|* +|* SwFrm::Remove() +|* +|*************************************************************************/ +void SwFrm::Remove() +{ + OSL_ENSURE( pUpper, "Removen ohne Upper?" ); + + if( pPrev ) + // einer aus der Mitte wird removed + pPrev->pNext = pNext; + else + { // der erste in einer Folge wird removed + OSL_ENSURE( pUpper->pLower == this, "Layout inkonsistent." ); + pUpper->pLower = pNext; + } + if( pNext ) + pNext->pPrev = pPrev; + + // Verbindung kappen. + pNext = pPrev = 0; + pUpper = 0; +} +/************************************************************************* +|* +|* SwCntntFrm::Paste() +|* +|*************************************************************************/ +void SwCntntFrm::Paste( SwFrm* pParent, SwFrm* pSibling) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + OSL_ENSURE( !pSibling || pSibling->IsFlowFrm(), + "<SwCntntFrm::Paste(..)> - sibling not of expected type." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + SwPageFrm *pPage = FindPageFrm(); + _InvalidateAll(); + InvalidatePage( pPage ); + + if( pPage ) + { + pPage->InvalidateSpelling(); + pPage->InvalidateSmartTags(); // SMARTTAGS + pPage->InvalidateAutoCompleteWords(); + pPage->InvalidateWordCount(); + } + + if ( GetNext() ) + { + SwFrm* pNxt = GetNext(); + pNxt->_InvalidatePrt(); + pNxt->_InvalidatePos(); + pNxt->InvalidatePage( pPage ); + if( pNxt->IsSctFrm() ) + pNxt = ((SwSectionFrm*)pNxt)->ContainsCntnt(); + if( pNxt && pNxt->IsTxtFrm() && pNxt->IsInFtn() ) + pNxt->Prepare( PREP_FTN, 0, sal_False ); + } + + if ( Frm().Height() ) + pParent->Grow( Frm().Height() ); + + if ( Frm().Width() != pParent->Prt().Width() ) + Prepare( PREP_FIXSIZE_CHG ); + + if ( GetPrev() ) + { + if ( IsFollow() ) + //Ich bin jetzt direkter Nachfolger meines Masters geworden + ((SwCntntFrm*)GetPrev())->Prepare( PREP_FOLLOW_FOLLOWS ); + else + { + if ( GetPrev()->Frm().Height() != + GetPrev()->Prt().Height() + GetPrev()->Prt().Top() ) + //Umrandung zu beruecksichtigen? + GetPrev()->_InvalidatePrt(); + // OD 18.02.2003 #104989# - force complete paint of previous frame, + // if frame is inserted at the end of a section frame, in order to + // get subsidiary lines repainted for the section. + if ( pParent->IsSctFrm() && !GetNext() ) + { + // force complete paint of previous frame, if new inserted frame + // in the section is the last one. + GetPrev()->SetCompletePaint(); + } + GetPrev()->InvalidatePage( pPage ); + } + } + if ( IsInFtn() ) + { + SwFrm* pFrm = GetIndPrev(); + if( pFrm && pFrm->IsSctFrm() ) + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pFrm ) + pFrm->Prepare( PREP_QUOVADIS, 0, sal_False ); + if( !GetNext() ) + { + pFrm = FindFtnFrm()->GetNext(); + if( pFrm && 0 != (pFrm=((SwLayoutFrm*)pFrm)->ContainsAny()) ) + pFrm->_InvalidatePrt(); + } + } + + _InvalidateLineNum(); + SwFrm *pNxt = FindNextCnt(); + if ( pNxt ) + { + while ( pNxt && pNxt->IsInTab() ) + { + if( 0 != (pNxt = pNxt->FindTabFrm()) ) + pNxt = pNxt->FindNextCnt(); + } + if ( pNxt ) + { + pNxt->_InvalidateLineNum(); + if ( pNxt != GetNext() ) + pNxt->InvalidatePage(); + } + } +} + +/************************************************************************* +|* +|* SwCntntFrm::Cut() +|* +|*************************************************************************/ +void SwCntntFrm::Cut() +{ + OSL_ENSURE( GetUpper(), "Cut ohne Upper()." ); + + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + SwFrm *pFrm = GetIndPrev(); + if( pFrm ) + { + if( pFrm->IsSctFrm() ) + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if ( pFrm && pFrm->IsCntntFrm() ) + { + pFrm->_InvalidatePrt(); + if( IsInFtn() ) + pFrm->Prepare( PREP_QUOVADIS, 0, sal_False ); + } + // --> OD 2004-07-15 #i26250# - invalidate printing area of previous + // table frame. + else if ( pFrm && pFrm->IsTabFrm() ) + { + pFrm->InvalidatePrt(); + } + // <-- + } + + SwFrm *pNxt = FindNextCnt(); + if ( pNxt ) + { + while ( pNxt && pNxt->IsInTab() ) + { + if( 0 != (pNxt = pNxt->FindTabFrm()) ) + pNxt = pNxt->FindNextCnt(); + } + if ( pNxt ) + { + pNxt->_InvalidateLineNum(); + if ( pNxt != GetNext() ) + pNxt->InvalidatePage(); + } + } + + if( 0 != (pFrm = GetIndNext()) ) + { //Der alte Nachfolger hat evtl. einen Abstand zum Vorgaenger + //berechnet, der ist jetzt, wo er der erste wird obsolet bzw. anders. + pFrm->_InvalidatePrt(); + pFrm->_InvalidatePos(); + pFrm->InvalidatePage( pPage ); + if( pFrm->IsSctFrm() ) + { + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pFrm ) + { + pFrm->_InvalidatePrt(); + pFrm->_InvalidatePos(); + pFrm->InvalidatePage( pPage ); + } + } + if( pFrm && IsInFtn() ) + pFrm->Prepare( PREP_ERGOSUM, 0, sal_False ); + if( IsInSct() && !GetPrev() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + } + else + { + InvalidateNextPos(); + //Einer muss die Retusche uebernehmen: Vorgaenger oder Upper + if ( 0 != (pFrm = GetPrev()) ) + { pFrm->SetRetouche(); + pFrm->Prepare( PREP_WIDOWS_ORPHANS ); + pFrm->_InvalidatePos(); + pFrm->InvalidatePage( pPage ); + } + //Wenn ich der einzige CntntFrm in meinem Upper bin (war), so muss + //er die Retouche uebernehmen. + //Ausserdem kann eine Leerseite entstanden sein. + else + { SwRootFrm *pRoot = getRootFrm(); + if ( pRoot ) + { + pRoot->SetSuperfluous(); + GetUpper()->SetCompletePaint(); + GetUpper()->InvalidatePage( pPage ); + } + if( IsInSct() ) + { + SwSectionFrm* pSct = FindSctFrm(); + if( !pSct->IsFollow() ) + { + pSct->_InvalidatePrt(); + pSct->InvalidatePage( pPage ); + } + } + // --> FME 2005-08-03 #i52253# The master table should take care + // of removing the follow flow line. + if ( IsInTab() ) + { + SwTabFrm* pThisTab = FindTabFrm(); + SwTabFrm* pMasterTab = pThisTab && pThisTab->IsFollow() ? pThisTab->FindMaster() : 0; + if ( pMasterTab ) + { + pMasterTab->_InvalidatePos(); + pMasterTab->SetRemoveFollowFlowLinePending( sal_True ); + } + } + // <-- + } + } + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + Remove(); + if ( pUp ) + { + SwSectionFrm *pSct = 0; + if ( !pUp->Lower() && + ( ( pUp->IsFtnFrm() && !pUp->IsColLocked() ) || + ( pUp->IsInSct() && + // --> FME 2004-06-03 #i29438# + // We have to consider the case that the section may be "empty" + // except from a temporary empty table frame. + // This can happen due to the new cell split feature. + !pUp->IsCellFrm() && + // <-- + // --> OD 2006-01-04 #126020# - adjust check for empty section + // --> OD 2006-02-01 #130797# - correct fix #126020# + !(pSct = pUp->FindSctFrm())->ContainsCntnt() && + !pSct->ContainsAny( true ) ) ) ) + // <-- + { + if ( pUp->GetUpper() ) + { + // --> OD 2006-09-25 #b6448963# + // prevent delete of <ColLocked> footnote frame + if ( pUp->IsFtnFrm() && !pUp->IsColLocked()) + // <-- + { + if( pUp->GetNext() && !pUp->GetPrev() ) + { + SwFrm* pTmp = ((SwLayoutFrm*)pUp->GetNext())->ContainsAny(); + if( pTmp ) + pTmp->_InvalidatePrt(); + } + pUp->Cut(); + delete pUp; + } + else + { + // --> OD 2006-09-25 #b6448963# + if ( pSct->IsColLocked() || !pSct->IsInFtn() || + ( pUp->IsFtnFrm() && pUp->IsColLocked() ) ) + // <-- + { + pSct->DelEmpty( sal_False ); + // Wenn ein gelockter Bereich nicht geloescht werden darf, + // so ist zumindest seine Groesse durch das Entfernen seines + // letzten Contents ungueltig geworden. + pSct->_InvalidateSize(); + } + else + { + pSct->DelEmpty( sal_True ); + delete pSct; + } + } + } + } + else + { + SWRECTFN( this ) + long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if( nFrmHeight ) + pUp->Shrink( nFrmHeight ); + } + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::Paste() +|* +|*************************************************************************/ +void SwLayoutFrm::Paste( SwFrm* pParent, SwFrm* pSibling) +{ + OSL_ENSURE( pParent, "Kein Parent fuer Paste." ); + OSL_ENSURE( pParent->IsLayoutFrm(), "Parent ist CntntFrm." ); + OSL_ENSURE( pParent != this, "Bin selbst der Parent." ); + OSL_ENSURE( pSibling != this, "Bin mein eigener Nachbar." ); + OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(), + "Bin noch irgendwo angemeldet." ); + + //In den Baum einhaengen. + InsertBefore( (SwLayoutFrm*)pParent, pSibling ); + + // OD 24.10.2002 #103517# - correct setting of variable <fnRect> + // <fnRect> is used for the following: + // (1) To invalidate the frame's size, if its size, which has to be the + // same as its upper/parent, differs from its upper's/parent's. + // (2) To adjust/grow the frame's upper/parent, if it has a dimension in its + // size, which is not determined by its upper/parent. + // Which size is which depends on the frame type and the layout direction + // (vertical or horizontal). + // There are the following cases: + // (A) Header and footer frames both in vertical and in horizontal layout + // have to size the width to the upper/parent. A dimension in the height + // has to cause a adjustment/grow of the upper/parent. + // --> <fnRect> = fnRectHori + // (B) Cell and column frames in vertical layout, the width has to be the + // same as upper/parent and a dimension in height causes adjustment/grow + // of the upper/parent. + // --> <fnRect> = fnRectHori + // in horizontal layout the other way around + // --> <fnRect> = fnRectVert + // (C) Other frames in vertical layout, the height has to be the + // same as upper/parent and a dimension in width causes adjustment/grow + // of the upper/parent. + // --> <fnRect> = fnRectVert + // in horizontal layout the other way around + // --> <fnRect> = fnRectHori + //SwRectFn fnRect = IsVertical() ? fnRectHori : fnRectVert; + SwRectFn fnRect; + if ( IsHeaderFrm() || IsFooterFrm() ) + fnRect = fnRectHori; + else if ( IsCellFrm() || IsColumnFrm() ) + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert ); + else + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + + + if( (Frm().*fnRect->fnGetWidth)() != (pParent->Prt().*fnRect->fnGetWidth)()) + _InvalidateSize(); + _InvalidatePos(); + const SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + SwFrm *pFrm; + if( !IsColumnFrm() ) + { + if( 0 != ( pFrm = GetIndNext() ) ) + { + pFrm->_InvalidatePos(); + if( IsInFtn() ) + { + if( pFrm->IsSctFrm() ) + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pFrm ) + pFrm->Prepare( PREP_ERGOSUM, 0, sal_False ); + } + } + if ( IsInFtn() && 0 != ( pFrm = GetIndPrev() ) ) + { + if( pFrm->IsSctFrm() ) + pFrm = ((SwSectionFrm*)pFrm)->ContainsAny(); + if( pFrm ) + pFrm->Prepare( PREP_QUOVADIS, 0, sal_False ); + } + } + + if( (Frm().*fnRect->fnGetHeight)() ) + { + // AdjustNeighbourhood wird jetzt auch in Spalten aufgerufen, + // die sich nicht in Rahmen befinden + sal_uInt8 nAdjust = GetUpper()->IsFtnBossFrm() ? + ((SwFtnBossFrm*)GetUpper())->NeighbourhoodAdjustment( this ) + : NA_GROW_SHRINK; + SwTwips nGrow = (Frm().*fnRect->fnGetHeight)(); + if( NA_ONLY_ADJUST == nAdjust ) + AdjustNeighbourhood( nGrow ); + else + { + SwTwips nReal = 0; + if( NA_ADJUST_GROW == nAdjust ) + nReal = AdjustNeighbourhood( nGrow ); + if( nReal < nGrow ) + nReal += pParent->Grow( nGrow - nReal ); + if( NA_GROW_ADJUST == nAdjust && nReal < nGrow ) + AdjustNeighbourhood( nGrow - nReal ); + } + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::Cut() +|* +|*************************************************************************/ +void SwLayoutFrm::Cut() +{ + if ( GetNext() ) + GetNext()->_InvalidatePos(); + + SWRECTFN( this ) + SwTwips nShrink = (Frm().*fnRect->fnGetHeight)(); + + //Erst removen, dann Upper Shrinken. + SwLayoutFrm *pUp = GetUpper(); + + // AdjustNeighbourhood wird jetzt auch in Spalten aufgerufen, + // die sich nicht in Rahmen befinden + + // Remove must not be called before a AdjustNeighbourhood, but it has to + // be called before the upper-shrink-call, if the upper-shrink takes care + // of his content + if ( pUp && nShrink ) + { + if( pUp->IsFtnBossFrm() ) + { + sal_uInt8 nAdjust= ((SwFtnBossFrm*)pUp)->NeighbourhoodAdjustment( this ); + if( NA_ONLY_ADJUST == nAdjust ) + AdjustNeighbourhood( -nShrink ); + else + { + SwTwips nReal = 0; + if( NA_ADJUST_GROW == nAdjust ) + nReal = -AdjustNeighbourhood( -nShrink ); + if( nReal < nShrink ) + { + SwTwips nOldHeight = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( 0 ); + nReal += pUp->Shrink( nShrink - nReal ); + (Frm().*fnRect->fnSetHeight)( nOldHeight ); + } + if( NA_GROW_ADJUST == nAdjust && nReal < nShrink ) + AdjustNeighbourhood( nReal - nShrink ); + } + Remove(); + } + else + { + Remove(); + pUp->Shrink( nShrink ); + } + } + else + Remove(); + + if( pUp && !pUp->Lower() ) + { + pUp->SetCompletePaint(); + pUp->InvalidatePage(); + } +} + +/************************************************************************* +|* +|* SwFrm::Grow() +|* +|*************************************************************************/ +SwTwips SwFrm::Grow( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + OSL_ENSURE( nDist >= 0, "Negatives Wachstum?" ); + + PROTOCOL_ENTER( this, bTst ? PROT_GROW_TST : PROT_GROW, 0, &nDist ) + + if ( nDist ) + { + SWRECTFN( this ) + + SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) ) + nDist = LONG_MAX - nPrtHeight; + + if ( IsFlyFrm() ) + return ((SwFlyFrm*)this)->_Grow( nDist, bTst ); + else if( IsSctFrm() ) + return ((SwSectionFrm*)this)->_Grow( nDist, bTst ); + else + { + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + if ( pThisCell ) + { + const SwTabFrm* pTab = FindTabFrm(); + + // NEW TABLES + if ( ( 0 != pTab->IsVertical() ) != ( 0 != IsVertical() ) || + pThisCell->GetLayoutRowSpan() < 1 ) + return 0; + } + + const SwTwips nReal = GrowFrm( nDist, bTst, bInfo ); + if( !bTst ) + { + nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + (Prt().*fnRect->fnSetHeight)( nPrtHeight + + ( IsCntntFrm() ? nDist : nReal ) ); + } + return nReal; + } + } + return 0L; +} + +/************************************************************************* +|* +|* SwFrm::Shrink() +|* +|*************************************************************************/ +SwTwips SwFrm::Shrink( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + OSL_ENSURE( nDist >= 0, "Negative Verkleinerung?" ); + + PROTOCOL_ENTER( this, bTst ? PROT_SHRINK_TST : PROT_SHRINK, 0, &nDist ) + + if ( nDist ) + { + if ( IsFlyFrm() ) + return ((SwFlyFrm*)this)->_Shrink( nDist, bTst ); + else if( IsSctFrm() ) + return ((SwSectionFrm*)this)->_Shrink( nDist, bTst ); + else + { + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + if ( pThisCell ) + { + const SwTabFrm* pTab = FindTabFrm(); + + // NEW TABLES + if ( ( 0 != pTab->IsVertical() ) != ( 0 != IsVertical() ) || + pThisCell->GetLayoutRowSpan() < 1 ) + return 0; + } + + SWRECTFN( this ) + SwTwips nReal = (Frm().*fnRect->fnGetHeight)(); + ShrinkFrm( nDist, bTst, bInfo ); + nReal -= (Frm().*fnRect->fnGetHeight)(); + if( !bTst ) + { + const SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + (Prt().*fnRect->fnSetHeight)( nPrtHeight - + ( IsCntntFrm() ? nDist : nReal ) ); + } + return nReal; + } + } + return 0L; +} + +/************************************************************************* +|* +|* SwFrm::AdjustNeighbourhood() +|* +|* Beschreibung Wenn sich die Groesse eines Frm's direkt unterhalb +|* eines Fussnotenbosses (Seite/Spalte) veraendert hat, so muss dieser +|* "Normalisiert" werden. +|* Es gibt dort immer einen Frame, der den "maximal moeglichen" Raum +|* einnimmt (der Frame, der den Body.Text enhaelt) und keinen oder +|* mehrere Frames die den Platz einnehmen den sie halt brauchen +|* (Kopf-/Fussbereich, Fussnoten). +|* Hat sich einer der Frames veraendert, so muss der Body-Text-Frame +|* entsprechen wachsen oder schrumpfen; unabhaegig davon, dass er fix ist. +|* !! Ist es moeglich dies allgemeiner zu loesen, also nicht auf die +|* Seite beschraenkt und nicht auf einen Speziellen Frame, der den +|* maximalen Platz einnimmt (gesteuert ueber Attribut FrmSize)? Probleme: +|* Was ist wenn mehrere Frames nebeneinander stehen, die den maximalen +|* Platz einnehmen? +|* Wie wird der Maximale Platz berechnet? +|* Wie klein duerfen diese Frames werden? +|* +|* Es wird auf jeden Fall nur so viel Platz genehmigt, dass ein +|* Minimalwert fuer die Hoehe des Bodys nicht unterschritten wird. +|* +|* Parameter: nDiff ist der Betrag, um den Platz geschaffen werden muss +|* +|*************************************************************************/ +SwTwips SwFrm::AdjustNeighbourhood( SwTwips nDiff, sal_Bool bTst ) +{ + PROTOCOL_ENTER( this, PROT_ADJUSTN, 0, &nDiff ); + + if ( !nDiff || !GetUpper()->IsFtnBossFrm() ) // nur innerhalb von Seiten/Spalten + return 0L; + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + + //Der (Page)Body veraendert sich nur im BrowseMode, aber nicht wenn er + //Spalten enthaelt. + if ( IsPageBodyFrm() && (!bBrowse || + (((SwLayoutFrm*)this)->Lower() && + ((SwLayoutFrm*)this)->Lower()->IsColumnFrm())) ) + return 0L; + + //In der BrowseView kann der PageFrm selbst ersteinmal einiges von den + //Wuenschen abfangen. + long nBrowseAdd = 0; + if ( bBrowse && GetUpper()->IsPageFrm() ) // nur (Page)BodyFrms + { + ViewShell *pViewShell = getRootFrm()->GetCurrShell(); + SwLayoutFrm *pUp = GetUpper(); + long nChg; + const long nUpPrtBottom = pUp->Frm().Height() - + pUp->Prt().Height() - pUp->Prt().Top(); + SwRect aInva( pUp->Frm() ); + if ( pViewShell ) + { + aInva.Pos().X() = pViewShell->VisArea().Left(); + aInva.Width( pViewShell->VisArea().Width() ); + } + if ( nDiff > 0 ) + { + nChg = BROWSE_HEIGHT - pUp->Frm().Height(); + nChg = Min( nDiff, nChg ); + + if ( !IsBodyFrm() ) + { + SetCompletePaint(); + if ( !pViewShell || pViewShell->VisArea().Height() >= pUp->Frm().Height() ) + { + //Ersteinmal den Body verkleinern. Der waechst dann schon + //wieder. + SwFrm *pBody = ((SwFtnBossFrm*)pUp)->FindBodyCont(); + const long nTmp = nChg - pBody->Prt().Height(); + if ( !bTst ) + { + pBody->Frm().Height(Max( 0L, pBody->Frm().Height() - nChg )); + pBody->_InvalidatePrt(); + pBody->_InvalidateSize(); + if ( pBody->GetNext() ) + pBody->GetNext()->_InvalidatePos(); + if ( !IsHeaderFrm() ) + pBody->SetCompletePaint(); + } + nChg = nTmp <= 0 ? 0 : nTmp; + } + } + + const long nTmp = nUpPrtBottom + 20; + aInva.Top( aInva.Bottom() - nTmp ); + aInva.Height( nChg + nTmp ); + } + else + { + //Die Seite kann bis auf 0 schrumpfen. Die erste Seite bleibt + //mindestens so gross wie die VisArea. + nChg = nDiff; + long nInvaAdd = 0; + if ( pViewShell && !pUp->GetPrev() && + pUp->Frm().Height() + nDiff < pViewShell->VisArea().Height() ) + { + //Das heisst aber wiederum trotzdem, das wir geeignet invalidieren + //muessen. + nChg = pViewShell->VisArea().Height() - pUp->Frm().Height(); + nInvaAdd = -(nDiff - nChg); + } + + //Invalidieren inklusive unterem Rand. + long nBorder = nUpPrtBottom + 20; + nBorder -= nChg; + aInva.Top( aInva.Bottom() - (nBorder+nInvaAdd) ); + if ( !IsBodyFrm() ) + { + SetCompletePaint(); + if ( !IsHeaderFrm() ) + ((SwFtnBossFrm*)pUp)->FindBodyCont()->SetCompletePaint(); + } + //Wegen der Rahmen die Seite invalidieren. Dadurch wird die Seite + //wieder entsprechend gross wenn ein Rahmen nicht passt. Das + //funktioniert anderfalls nur zufaellig fuer absatzgebundene Rahmen + //(NotifyFlys). + pUp->InvalidateSize(); + } + if ( !bTst ) + { + //Unabhaengig von nChg + if ( pViewShell && aInva.HasArea() && pUp->GetUpper() ) + pViewShell->InvalidateWindows( aInva ); + } + if ( !bTst && nChg ) + { + const SwRect aOldRect( pUp->Frm() ); + pUp->Frm().SSize().Height() += nChg; + pUp->Prt().SSize().Height() += nChg; + if ( pViewShell ) + pViewShell->Imp()->SetFirstVisPageInvalid(); + + if ( GetNext() ) + GetNext()->_InvalidatePos(); + + //Ggf. noch ein Repaint ausloesen. + const SvxGraphicPosition ePos = pUp->GetFmt()->GetBackground().GetGraphicPos(); + if ( ePos != GPOS_NONE && ePos != GPOS_TILED ) + pViewShell->InvalidateWindows( pUp->Frm() ); + + if ( pUp->GetUpper() ) + { + if ( pUp->GetNext() ) + pUp->GetNext()->InvalidatePos(); + + //Mies aber wahr: im Notify am ViewImp wird evtl. ein Calc + //auf die Seite und deren Lower gerufen. Die Werte sollten + //unverandert bleiben, weil der Aufrufer bereits fuer die + //Anpassung von Frm und Prt sorgen wird. + const long nOldFrmHeight = Frm().Height(); + const long nOldPrtHeight = Prt().Height(); + const sal_Bool bOldComplete = IsCompletePaint(); + if ( IsBodyFrm() ) + Prt().SSize().Height() = nOldFrmHeight; + + // PAGES01 + if ( pUp->GetUpper() ) + static_cast<SwRootFrm*>(pUp->GetUpper())->CheckViewLayout( 0, 0 ); + //((SwPageFrm*)pUp)->AdjustRootSize( CHG_CHGPAGE, &aOldRect ); + + Frm().SSize().Height() = nOldFrmHeight; + Prt().SSize().Height() = nOldPrtHeight; + bCompletePaint = bOldComplete; + } + if ( !IsBodyFrm() ) + pUp->_InvalidateSize(); + InvalidatePage( (SwPageFrm*)pUp ); + } + nDiff -= nChg; + if ( !nDiff ) + return nChg; + else + nBrowseAdd = nChg; + } + + const SwFtnBossFrm *pBoss = (SwFtnBossFrm*)GetUpper(); + + SwTwips nReal = 0, + nAdd = 0; + SwFrm *pFrm = 0; + SWRECTFN( this ) + + if( IsBodyFrm() ) + { + if( IsInSct() ) + { + SwSectionFrm *pSect = FindSctFrm(); + if( nDiff > 0 && pSect->IsEndnAtEnd() && GetNext() && + GetNext()->IsFtnContFrm() ) + { + SwFtnContFrm* pCont = (SwFtnContFrm*)GetNext(); + SwTwips nMinH = 0; + SwFtnFrm* pFtn = (SwFtnFrm*)pCont->Lower(); + sal_Bool bFtn = sal_False; + while( pFtn ) + { + if( !pFtn->GetAttr()->GetFtn().IsEndNote() ) + { + nMinH += (pFtn->Frm().*fnRect->fnGetHeight)(); + bFtn = sal_True; + } + pFtn = (SwFtnFrm*)pFtn->GetNext(); + } + if( bFtn ) + nMinH += (pCont->Prt().*fnRect->fnGetTop)(); + nReal = (pCont->Frm().*fnRect->fnGetHeight)() - nMinH; + if( nReal > nDiff ) + nReal = nDiff; + if( nReal > 0 ) + pFrm = GetNext(); + else + nReal = 0; + } + if( !bTst && !pSect->IsColLocked() ) + pSect->InvalidateSize(); + } + if( !pFrm ) + return nBrowseAdd; + } + else + { + const sal_Bool bFtnPage = pBoss->IsPageFrm() && ((SwPageFrm*)pBoss)->IsFtnPage(); + if ( bFtnPage && !IsFtnContFrm() ) + pFrm = (SwFrm*)pBoss->FindFtnCont(); + if ( !pFrm ) + pFrm = (SwFrm*)pBoss->FindBodyCont(); + + if ( !pFrm ) + return 0; + + //Wenn ich keinen finde eruebrigt sich alles weitere. + nReal = (pFrm->Frm().*fnRect->fnGetHeight)(); + if( nReal > nDiff ) + nReal = nDiff; + if( !bFtnPage ) + { + //Minimalgrenze beachten! + if( nReal ) + { + const SwTwips nMax = pBoss->GetVarSpace(); + if ( nReal > nMax ) + nReal = nMax; + } + if( !IsFtnContFrm() && nDiff > nReal && + pFrm->GetNext() && pFrm->GetNext()->IsFtnContFrm() + && ( pFrm->GetNext()->IsVertical() == IsVertical() ) + ) + { + //Wenn der Body nicht genuegend her gibt, kann ich noch mal + //schauen ob es eine Fussnote gibt, falls ja kann dieser + //entsprechend viel gemopst werden. + const SwTwips nAddMax = (pFrm->GetNext()->Frm().*fnRect-> + fnGetHeight)(); + nAdd = nDiff - nReal; + if ( nAdd > nAddMax ) + nAdd = nAddMax; + if ( !bTst ) + { + (pFrm->GetNext()->Frm().*fnRect->fnSetHeight)(nAddMax-nAdd); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bVert && !bVertL2R && !bRev ) + pFrm->GetNext()->Frm().Pos().X() += nAdd; + pFrm->GetNext()->InvalidatePrt(); + if ( pFrm->GetNext()->GetNext() ) + pFrm->GetNext()->GetNext()->_InvalidatePos(); + } + } + } + } + + if ( !bTst && nReal ) + { + SwTwips nTmp = (pFrm->Frm().*fnRect->fnGetHeight)(); + (pFrm->Frm().*fnRect->fnSetHeight)( nTmp - nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bVert && !bVertL2R && !bRev ) + pFrm->Frm().Pos().X() += nReal; + pFrm->InvalidatePrt(); + if ( pFrm->GetNext() ) + pFrm->GetNext()->_InvalidatePos(); + if( nReal < 0 && pFrm->IsInSct() ) + { + SwLayoutFrm* pUp = pFrm->GetUpper(); + if( pUp && 0 != ( pUp = pUp->GetUpper() ) && pUp->IsSctFrm() && + !pUp->IsColLocked() ) + pUp->InvalidateSize(); + } + if( ( IsHeaderFrm() || IsFooterFrm() ) && pBoss->GetDrawObjs() ) + { + const SwSortedObjs &rObjs = *pBoss->GetDrawObjs(); + OSL_ENSURE( pBoss->IsPageFrm(), "Header/Footer out of page?" ); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + OSL_ENSURE( !pFly->IsFlyInCntFrm(), "FlyInCnt at Page?" ); + const SwFmtVertOrient &rVert = + pFly->GetFmt()->GetVertOrient(); + // Wann muss invalidiert werden? + // Wenn ein Rahmen am SeitenTextBereich ausgerichtet ist, + // muss bei Aenderung des Headers ein TOP, MIDDLE oder NONE, + // bei Aenderung des Footers ein BOTTOM oder MIDDLE + // ausgerichteter Rahmen seine Position neu berechnen. + if( ( rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA || + rVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) && + ((IsHeaderFrm() && rVert.GetVertOrient()!=text::VertOrientation::BOTTOM) || + (IsFooterFrm() && rVert.GetVertOrient()!=text::VertOrientation::NONE && + rVert.GetVertOrient() != text::VertOrientation::TOP)) ) + { + pFly->_InvalidatePos(); + pFly->_Invalidate(); + } + } + } + } + } + return (nBrowseAdd + nReal + nAdd); +} + +/************************************************************************* +|* +|* SwFrm::ImplInvalidateSize(), ImplInvalidatePrt(), ImplInvalidatePos(), +|* ImplInvalidateLineNum() +|* +|*************************************************************************/ +/** method to perform additional actions on an invalidation + + OD 2004-05-19 #i28701# + + @author OD +*/ +void SwFrm::_ActionOnInvalidation( const InvalidationType ) +{ + // default behaviour is to perform no additional action +} + +/** method to determine, if an invalidation is allowed. + + OD 2004-05-19 #i28701# + + @author OD +*/ +bool SwFrm::_InvalidationAllowed( const InvalidationType ) const +{ + // default behaviour is to allow invalidation + return true; +} + +void SwFrm::ImplInvalidateSize() +{ + if ( _InvalidationAllowed( INVALID_SIZE ) ) + { + bValidSize = sal_False; + if ( IsFlyFrm() ) + ((SwFlyFrm*)this)->_Invalidate(); + else + InvalidatePage(); + + // OD 2004-05-19 #i28701# + _ActionOnInvalidation( INVALID_SIZE ); + } +} + +void SwFrm::ImplInvalidatePrt() +{ + if ( _InvalidationAllowed( INVALID_PRTAREA ) ) + { + bValidPrtArea = sal_False; + if ( IsFlyFrm() ) + ((SwFlyFrm*)this)->_Invalidate(); + else + InvalidatePage(); + + // OD 2004-05-19 #i28701# + _ActionOnInvalidation( INVALID_PRTAREA ); + } +} + +void SwFrm::ImplInvalidatePos() +{ + if ( _InvalidationAllowed( INVALID_POS ) ) + { + bValidPos = sal_False; + if ( IsFlyFrm() ) + { + ((SwFlyFrm*)this)->_Invalidate(); + } + else + { + InvalidatePage(); + } + + // OD 2004-05-19 #i28701# + _ActionOnInvalidation( INVALID_POS ); + } +} + +void SwFrm::ImplInvalidateLineNum() +{ + if ( _InvalidationAllowed( INVALID_LINENUM ) ) + { + bValidLineNum = sal_False; + OSL_ENSURE( IsTxtFrm(), "line numbers are implemented for text only" ); + InvalidatePage(); + + // OD 2004-05-19 #i28701# + _ActionOnInvalidation( INVALID_LINENUM ); + } +} + +/************************************************************************* +|* +|* SwFrm::ReinitializeFrmSizeAttrFlags +|* +|*************************************************************************/ +void SwFrm::ReinitializeFrmSizeAttrFlags() +{ + const SwFmtFrmSize &rFmtSize = GetAttrSet()->GetFrmSize(); + if ( ATT_VAR_SIZE == rFmtSize.GetHeightSizeType() || + ATT_MIN_SIZE == rFmtSize.GetHeightSizeType()) + { + bFixSize = sal_False; + if ( GetType() & (FRM_HEADER | FRM_FOOTER | FRM_ROW) ) + { + SwFrm *pFrm = ((SwLayoutFrm*)this)->Lower(); + while ( pFrm ) + { pFrm->_InvalidateSize(); + pFrm->_InvalidatePrt(); + pFrm = pFrm->GetNext(); + } + SwCntntFrm *pCnt = ((SwLayoutFrm*)this)->ContainsCntnt(); + // --> OD 2004-12-20 #i36991# - be save. + // E.g., a row can contain *no* content. + if ( pCnt ) + { + pCnt->InvalidatePage(); + do + { + pCnt->Prepare( PREP_ADJUST_FRM ); + pCnt->_InvalidateSize(); + pCnt = pCnt->GetNextCntntFrm(); + } while ( ((SwLayoutFrm*)this)->IsAnLower( pCnt ) ); + } + // <-- + } + } + else if ( rFmtSize.GetHeightSizeType() == ATT_FIX_SIZE ) + { + if( IsVertical() ) + ChgSize( Size( rFmtSize.GetWidth(), Frm().Height())); + else + ChgSize( Size( Frm().Width(), rFmtSize.GetHeight())); + } +} + +/************************************************************************* +|* SwFrm::ValidateThisAndAllLowers() + * + * FME 2007-08-30 #i81146# new loop control +|*************************************************************************/ +void SwFrm::ValidateThisAndAllLowers( const sal_uInt16 nStage ) +{ + // Stage 0: Only validate frames. Do not process any objects. + // Stage 1: Only validate fly frames and all of their contents. + // Stage 2: Validate all. + + const bool bOnlyObject = 1 == nStage; + const bool bIncludeObjects = 1 <= nStage; + + if ( !bOnlyObject || ISA(SwFlyFrm) ) + { + bValidSize = sal_True; + bValidPrtArea = sal_True; + bValidPos = sal_True; + } + + if ( bIncludeObjects ) + { + const SwSortedObjs* pObjs = GetDrawObjs(); + if ( pObjs ) + { + const sal_uInt32 nCnt = pObjs->Count(); + for ( sal_uInt32 i = 0; i < nCnt; ++i ) + { + SwAnchoredObject* pAnchObj = (*pObjs)[i]; + if ( pAnchObj->ISA(SwFlyFrm) ) + static_cast<SwFlyFrm*>(pAnchObj)->ValidateThisAndAllLowers( 2 ); + else if ( pAnchObj->ISA(SwAnchoredDrawObject) ) + static_cast<SwAnchoredDrawObject*>(pAnchObj)->ValidateThis(); + } + } + } + + if ( IsLayoutFrm() ) + { + SwFrm* pLower = static_cast<SwLayoutFrm*>(this)->Lower(); + while ( pLower ) + { + pLower->ValidateThisAndAllLowers( nStage ); + pLower = pLower->GetNext(); + } + } +} + +/************************************************************************* +|* +|* SwCntntFrm::GrowFrm() +|* +|*************************************************************************/ +SwTwips SwCntntFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + + SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if( nFrmHeight > 0 && + nDist > (LONG_MAX - nFrmHeight ) ) + nDist = LONG_MAX - nFrmHeight; + + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + const sal_uInt16 nTmpType = bBrowse ? 0x2084: 0x2004; //Row+Cell, Browse mit Body + if( !(GetUpper()->GetType() & nTmpType) && GetUpper()->HasFixSize() ) + { + if ( !bTst ) + { + (Frm().*fnRect->fnSetHeight)( nFrmHeight + nDist ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() && !IsReverse() ) + Frm().Pos().X() -= nDist; + if ( GetNext() ) + { + GetNext()->InvalidatePos(); + } + // --> OD 2004-07-05 #i28701# - Due to the new object positioning the + // frame on the next page/column can flow backward (e.g. it was moved forward + // due to the positioning of its objects ). Thus, invalivate this next frame, + // if document compatibility option 'Consider wrapping style influence on + // object positioning' is ON. + else if ( GetUpper()->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + InvalidateNextPos(); + } + // <-- + } + return 0; + } + + SwTwips nReal = (GetUpper()->Prt().*fnRect->fnGetHeight)(); + SwFrm *pFrm = GetUpper()->Lower(); + while( pFrm && nReal > 0 ) + { nReal -= (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + + if ( !bTst ) + { + //Cntnts werden immer auf den gewuenschten Wert gebracht. + long nOld = (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnSetHeight)( nOld + nDist ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical()&& !IsVertLR() && !IsReverse() ) + Frm().Pos().X() -= nDist; + if ( nOld && IsInTab() ) + { + SwTabFrm *pTab = FindTabFrm(); + if ( pTab->GetTable()->GetHTMLTableLayout() && + !pTab->IsJoinLocked() && + !pTab->GetFmt()->GetDoc()->GetDocShell()->IsReadOnly() ) + { + pTab->InvalidatePos(); + pTab->SetResizeHTMLTable(); + } + } + } + + //Upper nur growen wenn notwendig. + if ( nReal < nDist ) + { + if( GetUpper() ) + { + if( bTst || !GetUpper()->IsFooterFrm() ) + nReal = GetUpper()->Grow( nDist - (nReal > 0 ? nReal : 0), + bTst, bInfo ); + else + { + nReal = 0; + GetUpper()->InvalidateSize(); + } + } + else + nReal = 0; + } + else + nReal = nDist; + + // --> OD 2004-07-05 #i28701# - Due to the new object positioning the + // frame on the next page/column can flow backward (e.g. it was moved forward + // due to the positioning of its objects ). Thus, invalivate this next frame, + // if document compatibility option 'Consider wrapping style influence on + // object positioning' is ON. + if ( !bTst ) + { + if ( GetNext() ) + { + GetNext()->InvalidatePos(); + } + else if ( GetUpper()->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + InvalidateNextPos(); + } + } + // <-- + + return nReal; +} + +/************************************************************************* +|* +|* SwCntntFrm::ShrinkFrm() +|* +|*************************************************************************/ +SwTwips SwCntntFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + SWRECTFN( this ) + OSL_ENSURE( nDist >= 0, "nDist < 0" ); + OSL_ENSURE( nDist <= (Frm().*fnRect->fnGetHeight)(), + "nDist > als aktuelle Grosse." ); + + if ( !bTst ) + { + SwTwips nRstHeight; + if( GetUpper() ) + nRstHeight = (Frm().*fnRect->fnBottomDist) + ( (GetUpper()->*fnRect->fnGetPrtBottom)() ); + else + nRstHeight = 0; + if( nRstHeight < 0 ) + { + SwTwips nNextHeight = 0; + if( GetUpper()->IsSctFrm() && nDist > LONG_MAX/2 ) + { + SwFrm *pNxt = GetNext(); + while( pNxt ) + { + nNextHeight += (pNxt->Frm().*fnRect->fnGetHeight)(); + pNxt = pNxt->GetNext(); + } + } + nRstHeight = nDist + nRstHeight - nNextHeight; + } + else + nRstHeight = nDist; + (Frm().*fnRect->fnSetHeight)( (Frm().*fnRect->fnGetHeight)() - nDist ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( IsVertical() && !IsVertLR() ) + Frm().Pos().X() += nDist; + nDist = nRstHeight; + if ( IsInTab() ) + { + SwTabFrm *pTab = FindTabFrm(); + if ( pTab->GetTable()->GetHTMLTableLayout() && + !pTab->IsJoinLocked() && + !pTab->GetFmt()->GetDoc()->GetDocShell()->IsReadOnly() ) + { + pTab->InvalidatePos(); + pTab->SetResizeHTMLTable(); + } + } + } + + SwTwips nReal; + if( GetUpper() && nDist > 0 ) + { + if( bTst || !GetUpper()->IsFooterFrm() ) + nReal = GetUpper()->Shrink( nDist, bTst, bInfo ); + else + { + nReal = 0; + + // #108745# Sorry, dear old footer friend, I'm not gonna invalidate you, + // if there are any objects anchored inside your content, which + // overlap with the shrinking frame. + // This may lead to a footer frame that is too big, but this is better + // than looping. + // #109722# : The fix for #108745# was too strict. + + bool bInvalidate = true; + const SwRect aRect( Frm() ); + const SwPageFrm* pPage = FindPageFrm(); + const SwSortedObjs* pSorted = pPage ? pPage->GetSortedObjs() : 0; + if( pSorted ) + { + for ( sal_uInt16 i = 0; i < pSorted->Count(); ++i ) + { + const SwAnchoredObject* pAnchoredObj = (*pSorted)[i]; + const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() ); + + if( aBound.Left() > aRect.Right() ) + continue; + + if( aBound.IsOver( aRect ) ) + { + const SwFrmFmt& rFmt = pAnchoredObj->GetFrmFmt(); + if( SURROUND_THROUGHT != rFmt.GetSurround().GetSurround() ) + { + const SwFrm* pAnchor = pAnchoredObj->GetAnchorFrm(); + if ( pAnchor && pAnchor->FindFooterOrHeader() == GetUpper() ) + { + bInvalidate = false; + break; + } + } + } + } + } + + if ( bInvalidate ) + GetUpper()->InvalidateSize(); + } + } + else + nReal = 0; + + if ( !bTst ) + { + //Die Position des naechsten Frm's veraendert sich auf jeden Fall. + InvalidateNextPos(); + + //Wenn ich keinen Nachfolger habe, so muss ich mich eben selbst um + //die Retusche kuemmern. + if ( !GetNext() ) + SetRetouche(); + } + return nReal; +} + +/************************************************************************* +|* +|* SwCntntFrm::Modify() +|* +|*************************************************************************/ +void SwCntntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + + if( pNew && RES_ATTRSET_CHG == pNew->Which() ) + { + SfxItemIter aNIter( *((SwAttrSetChg*)pNew)->GetChgSet() ); + SfxItemIter aOIter( *((SwAttrSetChg*)pOld)->GetChgSet() ); + SwAttrSetChg aOldSet( *(SwAttrSetChg*)pOld ); + SwAttrSetChg aNewSet( *(SwAttrSetChg*)pNew ); + while( sal_True ) + { + _UpdateAttr( (SfxPoolItem*)aOIter.GetCurItem(), + (SfxPoolItem*)aNIter.GetCurItem(), nInvFlags, + &aOldSet, &aNewSet ); + if( aNIter.IsAtEnd() ) + break; + aNIter.NextItem(); + aOIter.NextItem(); + } + if ( aOldSet.Count() || aNewSet.Count() ) + SwFrm::Modify( &aOldSet, &aNewSet ); + } + else + _UpdateAttr( pOld, pNew, nInvFlags ); + + if ( nInvFlags != 0 ) + { + SwPageFrm *pPage = FindPageFrm(); + InvalidatePage( pPage ); + if ( nInvFlags & 0x01 ) + SetCompletePaint(); + if ( nInvFlags & 0x02 ) + _InvalidatePos(); + if ( nInvFlags & 0x04 ) + _InvalidateSize(); + if ( nInvFlags & 0x88 ) + { + if( IsInSct() && !GetPrev() ) + { + SwSectionFrm *pSect = FindSctFrm(); + if( pSect->ContainsAny() == this ) + { + pSect->_InvalidatePrt(); + pSect->InvalidatePage( pPage ); + } + } + _InvalidatePrt(); + } + SwFrm* pNextFrm = GetIndNext(); + if ( pNextFrm && nInvFlags & 0x10) + { + pNextFrm->_InvalidatePrt(); + pNextFrm->InvalidatePage( pPage ); + } + if ( pNextFrm && nInvFlags & 0x80 ) + { + pNextFrm->SetCompletePaint(); + } + if ( nInvFlags & 0x20 ) + { + SwFrm* pPrevFrm = GetPrev(); + if ( pPrevFrm ) + { + pPrevFrm->_InvalidatePrt(); + pPrevFrm->InvalidatePage( pPage ); + } + } + if ( nInvFlags & 0x40 ) + InvalidateNextPos(); + } +} + +void SwCntntFrm::_UpdateAttr( const SfxPoolItem* pOld, const SfxPoolItem* pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + sal_Bool bClear = sal_True; + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch ( nWhich ) + { + case RES_FMT_CHG: + rInvFlags = 0xFF; + /* kein break hier */ + + case RES_PAGEDESC: //Attributaenderung (an/aus) + if ( IsInDocBody() && !IsInTab() ) + { + rInvFlags |= 0x02; + SwPageFrm *pPage = FindPageFrm(); + if ( !GetPrev() ) + CheckPageDescs( pPage ); + if ( pPage && GetAttrSet()->GetPageDesc().GetNumOffset() ) + ((SwRootFrm*)pPage->GetUpper())->SetVirtPageNum( sal_True ); + SwDocPosUpdate aMsgHnt( pPage->Frm().Top() ); + pPage->GetFmt()->GetDoc()->UpdatePageFlds( &aMsgHnt ); + } + break; + + case RES_UL_SPACE: + { + // OD 2004-02-18 #106629# - correction + // Invalidation of the printing area of next frame, not only + // for footnote content. + if ( !GetIndNext() ) + { + SwFrm* pNxt = FindNext(); + if ( pNxt ) + { + SwPageFrm* pPg = pNxt->FindPageFrm(); + pNxt->InvalidatePage( pPg ); + pNxt->_InvalidatePrt(); + if( pNxt->IsSctFrm() ) + { + SwFrm* pCnt = ((SwSectionFrm*)pNxt)->ContainsAny(); + if( pCnt ) + { + pCnt->_InvalidatePrt(); + pCnt->InvalidatePage( pPg ); + } + } + pNxt->SetCompletePaint(); + } + } + // OD 2004-03-17 #i11860# + if ( GetIndNext() && + !GetUpper()->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::USE_FORMER_OBJECT_POS) ) + { + // OD 2004-07-01 #i28701# - use new method <InvalidateObjs(..)> + GetIndNext()->InvalidateObjs( true ); + } + Prepare( PREP_UL_SPACE ); //TxtFrm muss Zeilenabst. korrigieren. + rInvFlags |= 0x80; + /* kein Break hier */ + } + case RES_LR_SPACE: + case RES_BOX: + case RES_SHADOW: + Prepare( PREP_FIXSIZE_CHG ); + SwFrm::Modify( pOld, pNew ); + rInvFlags |= 0x30; + break; + + case RES_BREAK: + { + rInvFlags |= 0x42; + const IDocumentSettingAccess* pIDSA = GetUpper()->GetFmt()->getIDocumentSettingAccess(); + if( pIDSA->get(IDocumentSettingAccess::PARA_SPACE_MAX) || + pIDSA->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES) ) + { + rInvFlags |= 0x1; + SwFrm* pNxt = FindNext(); + if( pNxt ) + { + SwPageFrm* pPg = pNxt->FindPageFrm(); + pNxt->InvalidatePage( pPg ); + pNxt->_InvalidatePrt(); + if( pNxt->IsSctFrm() ) + { + SwFrm* pCnt = ((SwSectionFrm*)pNxt)->ContainsAny(); + if( pCnt ) + { + pCnt->_InvalidatePrt(); + pCnt->InvalidatePage( pPg ); + } + } + pNxt->SetCompletePaint(); + } + } + } + break; + + // OD 2004-02-26 #i25029# + case RES_PARATR_CONNECT_BORDER: + { + rInvFlags |= 0x01; + if ( IsTxtFrm() ) + { + InvalidateNextPrtArea(); + } + if ( !GetIndNext() && IsInTab() && IsInSplitTableRow() ) + { + FindTabFrm()->InvalidateSize(); + } + } + break; + + case RES_PARATR_TABSTOP: + case RES_CHRATR_PROPORTIONALFONTSIZE: + case RES_CHRATR_SHADOWED: + case RES_CHRATR_AUTOKERN: + case RES_CHRATR_UNDERLINE: + case RES_CHRATR_OVERLINE: + case RES_CHRATR_KERNING: + case RES_CHRATR_FONT: + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_ESCAPEMENT: + case RES_CHRATR_CONTOUR: + case RES_PARATR_NUMRULE: + rInvFlags |= 0x01; + break; + + + case RES_FRM_SIZE: + rInvFlags |= 0x01; + /* no break here */ + + default: + bClear = sal_False; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwFrm::Modify( pOld, pNew ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::SwLayoutFrm() +|* +|*************************************************************************/ +SwLayoutFrm::SwLayoutFrm( SwFrmFmt* pFmt, SwFrm* pSib ): + SwFrm( pFmt, pSib ), + pLower( 0 ) +{ + const SwFmtFrmSize &rFmtSize = pFmt->GetFrmSize(); + if ( rFmtSize.GetHeightSizeType() == ATT_FIX_SIZE ) + bFixSize = sal_True; +} + +// --> OD 2004-06-29 #i28701# +TYPEINIT1(SwLayoutFrm,SwFrm); +// <-- +/*-------------------------------------------------- + * SwLayoutFrm::InnerHeight() + * --------------------------------------------------*/ + +SwTwips SwLayoutFrm::InnerHeight() const +{ + if( !Lower() ) + return 0; + SwTwips nRet = 0; + const SwFrm* pCnt = Lower(); + SWRECTFN( this ) + if( pCnt->IsColumnFrm() || pCnt->IsCellFrm() ) + { + do + { + SwTwips nTmp = ((SwLayoutFrm*)pCnt)->InnerHeight(); + if( pCnt->GetValidPrtAreaFlag() ) + nTmp += (pCnt->Frm().*fnRect->fnGetHeight)() - + (pCnt->Prt().*fnRect->fnGetHeight)(); + if( nRet < nTmp ) + nRet = nTmp; + pCnt = pCnt->GetNext(); + } while ( pCnt ); + } + else + { + do + { + nRet += (pCnt->Frm().*fnRect->fnGetHeight)(); + if( pCnt->IsCntntFrm() && ((SwTxtFrm*)pCnt)->IsUndersized() ) + nRet += ((SwTxtFrm*)pCnt)->GetParHeight() - + (pCnt->Prt().*fnRect->fnGetHeight)(); + if( pCnt->IsLayoutFrm() && !pCnt->IsTabFrm() ) + nRet += ((SwLayoutFrm*)pCnt)->InnerHeight() - + (pCnt->Prt().*fnRect->fnGetHeight)(); + pCnt = pCnt->GetNext(); + } while( pCnt ); + + } + return nRet; +} + +/************************************************************************* +|* +|* SwLayoutFrm::GrowFrm() +|* +|*************************************************************************/ +SwTwips SwLayoutFrm::GrowFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + const sal_uInt16 nTmpType = bBrowse ? 0x2084: 0x2004; //Row+Cell, Browse mit Body + if( !(GetType() & nTmpType) && HasFixSize() ) + return 0; + + SWRECTFN( this ) + const SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + const SwTwips nFrmPos = Frm().Pos().X(); + + if ( nFrmHeight > 0 && nDist > (LONG_MAX - nFrmHeight) ) + nDist = LONG_MAX - nFrmHeight; + + SwTwips nMin = 0; + if ( GetUpper() && !IsCellFrm() ) + { + SwFrm *pFrm = GetUpper()->Lower(); + while( pFrm ) + { nMin += (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + nMin = (GetUpper()->Prt().*fnRect->fnGetHeight)() - nMin; + if ( nMin < 0 ) + nMin = 0; + } + + SwRect aOldFrm( Frm() ); + sal_Bool bMoveAccFrm = sal_False; + + sal_Bool bChgPos = IsVertical() && !IsReverse(); + if ( !bTst ) + { + (Frm().*fnRect->fnSetHeight)( nFrmHeight + nDist ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bChgPos && !IsVertLR() ) + Frm().Pos().X() -= nDist; + bMoveAccFrm = sal_True; + } + + SwTwips nReal = nDist - nMin; + if ( nReal > 0 ) + { + if ( GetUpper() ) + { // AdjustNeighbourhood jetzt auch in Spalten (aber nicht in Rahmen) + sal_uInt8 nAdjust = GetUpper()->IsFtnBossFrm() ? + ((SwFtnBossFrm*)GetUpper())->NeighbourhoodAdjustment( this ) + : NA_GROW_SHRINK; + if( NA_ONLY_ADJUST == nAdjust ) + nReal = AdjustNeighbourhood( nReal, bTst ); + else + { + if( NA_ADJUST_GROW == nAdjust ) + nReal += AdjustNeighbourhood( nReal, bTst ); + + SwTwips nGrow = 0; + if( 0 < nReal ) + { + SwFrm* pToGrow = GetUpper(); + // NEW TABLES + // A cell with a row span of > 1 is allowed to grow the + // line containing the end of the row span if it is + // located in the same table frame: + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 ) + { + SwCellFrm& rEndCell = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( false, true )); + if ( -1 == rEndCell.GetTabBox()->getRowSpan() ) + pToGrow = rEndCell.GetUpper(); + else + pToGrow = 0; + } + + nGrow = pToGrow ? pToGrow->Grow( nReal, bTst, bInfo ) : 0; + } + + if( NA_GROW_ADJUST == nAdjust && nGrow < nReal ) + nReal += AdjustNeighbourhood( nReal - nGrow, bTst ); + + if ( IsFtnFrm() && (nGrow != nReal) && GetNext() ) + { + //Fussnoten koennen ihre Nachfolger verdraengen. + SwTwips nSpace = bTst ? 0 : -nDist; + const SwFrm *pFrm = GetUpper()->Lower(); + do + { nSpace += (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } while ( pFrm != GetNext() ); + nSpace = (GetUpper()->Prt().*fnRect->fnGetHeight)() -nSpace; + if ( nSpace < 0 ) + nSpace = 0; + nSpace += nGrow; + if ( nReal > nSpace ) + nReal = nSpace; + if ( nReal && !bTst ) + ((SwFtnFrm*)this)->InvalidateNxtFtnCnts( FindPageFrm() ); + } + else + nReal = nGrow; + } + } + else + nReal = 0; + + nReal += nMin; + } + else + nReal = nDist; + + if ( !bTst ) + { + if( nReal != nDist && + // NEW TABLES + ( !IsCellFrm() || static_cast<SwCellFrm*>(this)->GetLayoutRowSpan() > 1 ) ) + { + (Frm().*fnRect->fnSetHeight)( nFrmHeight + nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bChgPos && !IsVertLR() ) + Frm().Pos().X() = nFrmPos - nReal; + bMoveAccFrm = sal_True; + } + + if ( nReal ) + { + SwPageFrm *pPage = FindPageFrm(); + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + } + if ( !IsPageBodyFrm() ) + { + _InvalidateAll(); + InvalidatePage( pPage ); + } + if ( !(GetType() & 0x1823) ) //Tab, Row, FtnCont, Root, Page + NotifyLowerObjs(); + + if( IsCellFrm() ) + InvaPercentLowers( nReal ); + + const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos(); + if ( GPOS_NONE != ePos && GPOS_TILED != ePos ) + SetCompletePaint(); + } + } + + if( bMoveAccFrm && IsAccessibleFrm() ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm ); + } + } + return nReal; +} + +/************************************************************************* +|* +|* SwLayoutFrm::ShrinkFrm() +|* +|*************************************************************************/ +SwTwips SwLayoutFrm::ShrinkFrm( SwTwips nDist, sal_Bool bTst, sal_Bool bInfo ) +{ + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode(); + const sal_uInt16 nTmpType = bBrowse ? 0x2084: 0x2004; //Row+Cell, Browse mit Body + if( !(GetType() & nTmpType) && HasFixSize() ) + return 0; + + OSL_ENSURE( nDist >= 0, "nDist < 0" ); + SWRECTFN( this ) + SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if ( nDist > nFrmHeight ) + nDist = nFrmHeight; + + SwTwips nMin = 0; + sal_Bool bChgPos = IsVertical() && !IsReverse(); + if ( Lower() ) + { + if( !Lower()->IsNeighbourFrm() ) + { const SwFrm *pFrm = Lower(); + const long nTmp = (Prt().*fnRect->fnGetHeight)(); + while( pFrm && nMin < nTmp ) + { nMin += (pFrm->Frm().*fnRect->fnGetHeight)(); + pFrm = pFrm->GetNext(); + } + } + } + SwTwips nReal = nDist; + SwTwips nMinDiff = (Prt().*fnRect->fnGetHeight)() - nMin; + if( nReal > nMinDiff ) + nReal = nMinDiff; + if( nReal <= 0 ) + return nDist; + + SwRect aOldFrm( Frm() ); + sal_Bool bMoveAccFrm = sal_False; + + SwTwips nRealDist = nReal; + if ( !bTst ) + { + (Frm().*fnRect->fnSetHeight)( nFrmHeight - nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bChgPos && !IsVertLR() ) + Frm().Pos().X() += nReal; + bMoveAccFrm = sal_True; + } + + sal_uInt8 nAdjust = GetUpper() && GetUpper()->IsFtnBossFrm() ? + ((SwFtnBossFrm*)GetUpper())->NeighbourhoodAdjustment( this ) + : NA_GROW_SHRINK; + + // AdjustNeighbourhood auch in Spalten (aber nicht in Rahmen) + if( NA_ONLY_ADJUST == nAdjust ) + { + if ( IsPageBodyFrm() && !bBrowse ) + nReal = nDist; + else + { nReal = AdjustNeighbourhood( -nReal, bTst ); + nReal *= -1; + if ( !bTst && IsBodyFrm() && nReal < nRealDist ) + { + (Frm().*fnRect->fnSetHeight)( (Frm().*fnRect->fnGetHeight)() + + nRealDist - nReal ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bChgPos && !IsVertLR() ) + Frm().Pos().X() += nRealDist - nReal; + OSL_ENSURE( !IsAccessibleFrm(), "bMoveAccFrm has to be set!" ); + } + } + } + else if( IsColumnFrm() || IsColBodyFrm() ) + { + SwTwips nTmp = GetUpper()->Shrink( nReal, bTst, bInfo ); + if ( nTmp != nReal ) + { + (Frm().*fnRect->fnSetHeight)( (Frm().*fnRect->fnGetHeight)() + + nReal - nTmp ); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + if( bChgPos && !IsVertLR() ) + Frm().Pos().X() += nTmp - nReal; + OSL_ENSURE( !IsAccessibleFrm(), "bMoveAccFrm has to be set!" ); + nReal = nTmp; + } + } + else + { + SwTwips nShrink = nReal; + SwFrm* pToShrink = GetUpper(); + const SwCellFrm* pThisCell = dynamic_cast<const SwCellFrm*>(this); + // NEW TABLES + if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 ) + { + SwCellFrm& rEndCell = const_cast<SwCellFrm&>(pThisCell->FindStartEndOfRowSpanCell( false, true )); + pToShrink = rEndCell.GetUpper(); + } + + nReal = pToShrink ? pToShrink->Shrink( nShrink, bTst, bInfo ) : 0; + if( ( NA_GROW_ADJUST == nAdjust || NA_ADJUST_GROW == nAdjust ) + && nReal < nShrink ) + AdjustNeighbourhood( nReal - nShrink ); + } + + if( bMoveAccFrm && IsAccessibleFrm() ) + { + SwRootFrm *pRootFrm = getRootFrm(); + if( pRootFrm && pRootFrm->IsAnyShellAccessible() && + pRootFrm->GetCurrShell() ) + { + pRootFrm->GetCurrShell()->Imp()->MoveAccessibleFrm( this, aOldFrm ); + } + } + if ( !bTst && (IsCellFrm() || IsColumnFrm() ? nReal : nRealDist) ) + { + SwPageFrm *pPage = FindPageFrm(); + if ( GetNext() ) + { + GetNext()->_InvalidatePos(); + if ( GetNext()->IsCntntFrm() ) + GetNext()->InvalidatePage( pPage ); + if ( IsTabFrm() ) + ((SwTabFrm*)this)->SetComplete(); + } + else + { if ( IsRetoucheFrm() ) + SetRetouche(); + if ( IsTabFrm() ) + { + if( IsTabFrm() ) + ((SwTabFrm*)this)->SetComplete(); + if ( Lower() ) //Kann auch im Join stehen und leer sein! + InvalidateNextPos(); + } + } + if ( !IsBodyFrm() ) + { + _InvalidateAll(); + InvalidatePage( pPage ); + const SvxGraphicPosition ePos = GetFmt()->GetBackground().GetGraphicPos(); + if ( GPOS_NONE != ePos && GPOS_TILED != ePos ) + SetCompletePaint(); + } + + if ( !(GetType() & 0x1823) ) //Tab, Row, FtnCont, Root, Page + NotifyLowerObjs(); + + if( IsCellFrm() ) + InvaPercentLowers( nReal ); + + SwCntntFrm *pCnt; + if( IsFtnFrm() && !((SwFtnFrm*)this)->GetAttr()->GetFtn().IsEndNote() && + ( GetFmt()->GetDoc()->GetFtnInfo().ePos != FTNPOS_CHAPTER || + ( IsInSct() && FindSctFrm()->IsFtnAtEnd() ) ) && + 0 != (pCnt = ((SwFtnFrm*)this)->GetRefFromAttr() ) ) + { + if ( pCnt->IsFollow() ) + { // Wenn wir sowieso schon in einer anderen Spalte/Seite sitzen + // als der Frame mit der Referenz, dann brauchen wir nicht + // auch noch seinen Master zu invalidieren. + SwFrm *pTmp = pCnt->FindFtnBossFrm(sal_True) == FindFtnBossFrm(sal_True) + ? pCnt->FindMaster()->GetFrm() : pCnt; + pTmp->Prepare( PREP_ADJUST_FRM ); + pTmp->InvalidateSize(); + } + else + pCnt->InvalidatePos(); + } + } + return nReal; +} +/************************************************************************* +|* +|* SwLayoutFrm::ChgLowersProp() +|* +|* Beschreibung Aendert die Grosse der direkt untergeordneten Frm's +|* die eine Fixe Groesse haben, proportional zur Groessenaenderung der +|* PrtArea des Frm's. +|* Die Variablen Frm's werden auch proportional angepasst; sie werden +|* sich schon wieder zurechtwachsen/-schrumpfen. +|* +|*************************************************************************/ +void SwLayoutFrm::ChgLowersProp( const Size& rOldSize ) +{ + // no change of lower properties for root frame or if no lower exists. + if ( IsRootFrm() || !Lower() ) + return; + + // declare and init <SwFrm* pLowerFrm> with first lower + SwFrm *pLowerFrm = Lower(); + + // declare and init const booleans <bHeightChgd> and <bWidthChg> + const bool bHeightChgd = rOldSize.Height() != Prt().Height(); + const bool bWidthChgd = rOldSize.Width() != Prt().Width(); + + // declare and init variables <bVert>, <bRev> and <fnRect> + SWRECTFN( this ) + + // This shortcut basically tries to handle only lower frames that + // are affected by the size change. Otherwise much more lower frames + // are invalidated. + if ( !( bVert ? bHeightChgd : bWidthChgd ) && + ! Lower()->IsColumnFrm() && + ( ( IsBodyFrm() && IsInDocBody() && ( !IsInSct() || !FindSctFrm()->IsColLocked() ) ) || + // --> FME 2004-07-21 #i10826# Section frames without columns should not + // invalidate all lowers! + IsSctFrm() ) ) + // <-- + { + // Determine page frame the body frame resp. the section frame belongs to. + SwPageFrm *pPage = FindPageFrm(); + // Determine last lower by traveling through them using <GetNext()>. + // During travel check each section frame, if it will be sized to + // maximum. If Yes, invalidate size of section frame and set + // corresponding flags at the page. + do + { + if( pLowerFrm->IsSctFrm() &&((SwSectionFrm*)pLowerFrm)->_ToMaximize() ) + { + pLowerFrm->_InvalidateSize(); + pLowerFrm->InvalidatePage( pPage ); + } + if( pLowerFrm->GetNext() ) + pLowerFrm = pLowerFrm->GetNext(); + else + break; + } while( sal_True ); + // If found last lower is a section frame containing no section + // (section frame isn't valid and will be deleted in the future), + // travel backwards. + while( pLowerFrm->IsSctFrm() && !((SwSectionFrm*)pLowerFrm)->GetSection() && + pLowerFrm->GetPrev() ) + pLowerFrm = pLowerFrm->GetPrev(); + // If found last lower is a section frame, set <pLowerFrm> to its last + // content, if the section frame is valid and is not sized to maximum. + // Otherwise set <pLowerFrm> to NULL - In this case body frame only + // contains invalid section frames. + if( pLowerFrm->IsSctFrm() ) + pLowerFrm = ((SwSectionFrm*)pLowerFrm)->GetSection() && + !((SwSectionFrm*)pLowerFrm)->ToMaximize( sal_False ) ? + ((SwSectionFrm*)pLowerFrm)->FindLastCntnt() : NULL; + + // continue with found last lower, probably the last content of a section + if ( pLowerFrm ) + { + // If <pLowerFrm> is in a table frame, set <pLowerFrm> to this table + // frame and continue. + if ( pLowerFrm->IsInTab() ) + { + // OD 28.10.2002 #97265# - safeguard for setting <pLowerFrm> to + // its table frame - check, if the table frame is also a lower + // of the body frame, in order to assure that <pLowerFrm> is not + // set to a frame, which is an *upper* of the body frame. + SwFrm* pTableFrm = pLowerFrm->FindTabFrm(); + if ( IsAnLower( pTableFrm ) ) + { + pLowerFrm = pTableFrm; + } + } + // Check, if variable size of body frame resp. section frame has grown + // OD 28.10.2002 #97265# - correct check, if variable size has grown. + SwTwips nOldHeight = bVert ? rOldSize.Width() : rOldSize.Height(); + if( nOldHeight < (Prt().*fnRect->fnGetHeight)() ) + { + // If variable size of body|section frame has grown, only found + // last lower and the position of the its next have to be invalidated. + pLowerFrm->_InvalidateAll(); + pLowerFrm->InvalidatePage( pPage ); + if( !pLowerFrm->IsFlowFrm() || + !SwFlowFrm::CastFlowFrm( pLowerFrm )->HasFollow() ) + pLowerFrm->InvalidateNextPos( sal_True ); + if ( pLowerFrm->IsTxtFrm() ) + ((SwCntntFrm*)pLowerFrm)->Prepare( PREP_ADJUST_FRM ); + } + else + { + // variable size of body|section frame has shrinked. Thus, + // invalidate all lowers not matching the new body|section size + // and the dedicated new last lower. + if( bVert ) + { + SwTwips nBot = Frm().Left() + Prt().Left(); + while ( pLowerFrm->GetPrev() && pLowerFrm->Frm().Left() < nBot ) + { + pLowerFrm->_InvalidateAll(); + pLowerFrm->InvalidatePage( pPage ); + pLowerFrm = pLowerFrm->GetPrev(); + } + } + else + { + SwTwips nBot = Frm().Top() + Prt().Bottom(); + while ( pLowerFrm->GetPrev() && pLowerFrm->Frm().Top() > nBot ) + { + pLowerFrm->_InvalidateAll(); + pLowerFrm->InvalidatePage( pPage ); + pLowerFrm = pLowerFrm->GetPrev(); + } + } + if ( pLowerFrm ) + { + pLowerFrm->_InvalidateSize(); + pLowerFrm->InvalidatePage( pPage ); + if ( pLowerFrm->IsTxtFrm() ) + ((SwCntntFrm*)pLowerFrm)->Prepare( PREP_ADJUST_FRM ); + } + } + // --> OD 2005-01-31 #i41694# - improvement by removing duplicates + if ( pLowerFrm ) + { + if ( pLowerFrm->IsInSct() ) + { + // --> OD 2005-01-31 #i41694# - follow-up of issue #i10826#: + // No invalidation of section frame, if it's the this. + SwFrm* pSectFrm = pLowerFrm->FindSctFrm(); + if( pSectFrm != this && IsAnLower( pSectFrm ) ) + { + pSectFrm->_InvalidateSize(); + pSectFrm->InvalidatePage( pPage ); + } + // <-- + } + } + // <-- + } + return; + } // end of { special case } + + + // Invalidate page for content only once. + bool bInvaPageForCntnt = true; + + // Declare booleans <bFixChgd> and <bVarChgd>, indicating for text frame + // adjustment, if fixed/variable size has changed. + bool bFixChgd, bVarChgd; + if( bVert == pLowerFrm->IsNeighbourFrm() ) + { + bFixChgd = bWidthChgd; + bVarChgd = bHeightChgd; + } + else + { + bFixChgd = bHeightChgd; + bVarChgd = bWidthChgd; + } + + // Declare const unsigned short <nFixWidth> and init it this frame types + // which has fixed width in vertical respectively horizontal layout. + // In vertical layout these are neighbour frames (cell and column frames), + // header frames and footer frames. + // In horizontal layout these are all frames, which aren't neighbour frames. + const sal_uInt16 nFixWidth = bVert ? (FRM_NEIGHBOUR | FRM_HEADFOOT) + : ~FRM_NEIGHBOUR; + + // Declare const unsigned short <nFixHeight> and init it this frame types + // which has fixed height in vertical respectively horizontal layout. + // In vertical layout these are all frames, which aren't neighbour frames, + // header frames, footer frames, body frames or foot note container frames. + // In horizontal layout these are neighbour frames. + const sal_uInt16 nFixHeight= bVert ? ~(FRM_NEIGHBOUR | FRM_HEADFOOT | FRM_BODYFTNC) + : FRM_NEIGHBOUR; + + // Travel through all lowers using <GetNext()> + while ( pLowerFrm ) + { + if ( pLowerFrm->IsTxtFrm() ) + { + // Text frames will only be invalidated - prepare invalidation + if ( bFixChgd ) + static_cast<SwCntntFrm*>(pLowerFrm)->Prepare( PREP_FIXSIZE_CHG ); + if ( bVarChgd ) + static_cast<SwCntntFrm*>(pLowerFrm)->Prepare( PREP_ADJUST_FRM ); + } + else + { + // If lower isn't a table, row, cell or section frame, adjust its + // frame size. + const sal_uInt16 nLowerType = pLowerFrm->GetType(); + if ( !(nLowerType & (FRM_TAB|FRM_ROW|FRM_CELL|FRM_SECTION)) ) + { + if ( bWidthChgd ) + { + if( nLowerType & nFixWidth ) + { + // Considering previous conditions: + // In vertical layout set width of column, header and + // footer frames to its upper width. + // In horizontal layout set width of header, footer, + // foot note container, foot note, body and no-text + // frames to its upper width. + pLowerFrm->Frm().Width( Prt().Width() ); + } + else if( rOldSize.Width() && !pLowerFrm->IsFtnFrm() ) + { + // Adjust frame width proportional, if lower isn't a + // foot note frame and condition <nLowerType & nFixWidth> + // isn't true. + // Considering previous conditions: + // In vertical layout these are foot note container, + // body and no-text frames. + // In horizontal layout these are column and no-text frames. + // OD 24.10.2002 #97265# - <double> calculation + // Perform <double> calculation of new width, if + // one of the coefficients is greater than 50000 + SwTwips nNewWidth; + if ( (pLowerFrm->Frm().Width() > 50000) || + (Prt().Width() > 50000) ) + { + double nNewWidthTmp = + ( double(pLowerFrm->Frm().Width()) + * double(Prt().Width()) ) + / double(rOldSize.Width()); + nNewWidth = SwTwips(nNewWidthTmp); + } + else + { + nNewWidth = + (pLowerFrm->Frm().Width() * Prt().Width()) / rOldSize.Width(); + } + pLowerFrm->Frm().Width( nNewWidth ); + } + } + if ( bHeightChgd ) + { + if( nLowerType & nFixHeight ) + { + // Considering previous conditions: + // In vertical layout set height of foot note and + // no-text frames to its upper height. + // In horizontal layout set height of column frames + // to its upper height. + pLowerFrm->Frm().Height( Prt().Height() ); + } + // OD 01.10.2002 #102211# + // add conditions <!pLowerFrm->IsHeaderFrm()> and + // <!pLowerFrm->IsFooterFrm()> in order to avoid that + // the <Grow> of header or footer are overwritten. + // NOTE: Height of header/footer frame is determined by contents. + else if ( rOldSize.Height() && + !pLowerFrm->IsFtnFrm() && + !pLowerFrm->IsHeaderFrm() && + !pLowerFrm->IsFooterFrm() + ) + { + // Adjust frame height proportional, if lower isn't a + // foot note, a header or a footer frame and + // condition <nLowerType & nFixHeight> isn't true. + // Considering previous conditions: + // In vertical layout these are column, foot note container, + // body and no-text frames. + // In horizontal layout these are column, foot note + // container, body and no-text frames. + + // OD 29.10.2002 #97265# - special case for page lowers + // The page lowers that have to be adjusted on page height + // change are the body frame and the foot note container + // frame. + // In vertical layout the height of both is directly + // adjusted to the page height change. + // In horizontal layout the height of the body frame is + // directly adjsuted to the page height change and the + // foot note frame height isn't touched, because its + // determined by its content. + // OD 31.03.2003 #108446# - apply special case for page + // lowers - see description above - also for section columns. + if ( IsPageFrm() || + ( IsColumnFrm() && IsInSct() ) + ) + { + OSL_ENSURE( pLowerFrm->IsBodyFrm() || pLowerFrm->IsFtnContFrm(), + "ChgLowersProp - only for body or foot note container" ); + if ( pLowerFrm->IsBodyFrm() || pLowerFrm->IsFtnContFrm() ) + { + if ( IsVertical() || pLowerFrm->IsBodyFrm() ) + { + SwTwips nNewHeight = + pLowerFrm->Frm().Height() + + ( Prt().Height() - rOldSize.Height() ); + if ( nNewHeight < 0) + { + // OD 01.04.2003 #108446# - adjust assertion condition and text + OSL_ENSURE( !( IsPageFrm() && + (pLowerFrm->Frm().Height()>0) && + (pLowerFrm->IsValid()) ), + "ChgLowersProg - negative height for lower."); + nNewHeight = 0; + } + pLowerFrm->Frm().Height( nNewHeight ); + } + } + } + else + { + SwTwips nNewHeight; + // OD 24.10.2002 #97265# - <double> calculation + // Perform <double> calculation of new height, if + // one of the coefficients is greater than 50000 + if ( (pLowerFrm->Frm().Height() > 50000) || + (Prt().Height() > 50000) ) + { + double nNewHeightTmp = + ( double(pLowerFrm->Frm().Height()) + * double(Prt().Height()) ) + / double(rOldSize.Height()); + nNewHeight = SwTwips(nNewHeightTmp); + } + else + { + nNewHeight = ( pLowerFrm->Frm().Height() + * Prt().Height() ) / rOldSize.Height(); + } + if( !pLowerFrm->GetNext() ) + { + SwTwips nSum = Prt().Height(); + SwFrm* pTmp = Lower(); + while( pTmp->GetNext() ) + { + if( !pTmp->IsFtnContFrm() || !pTmp->IsVertical() ) + nSum -= pTmp->Frm().Height(); + pTmp = pTmp->GetNext(); + } + if( nSum - nNewHeight == 1 && + nSum == pLowerFrm->Frm().Height() ) + nNewHeight = nSum; + } + pLowerFrm->Frm().Height( nNewHeight ); + } + } + } + } + } // end of else { NOT text frame } + + pLowerFrm->_InvalidateAll(); + if ( bInvaPageForCntnt && pLowerFrm->IsCntntFrm() ) + { + pLowerFrm->InvalidatePage(); + bInvaPageForCntnt = false; + } + + if ( !pLowerFrm->GetNext() && pLowerFrm->IsRetoucheFrm() ) + { + //Wenn ein Wachstum stattgefunden hat, und die untergeordneten + //zur Retouche faehig sind (derzeit Tab, Section und Cntnt), so + //trigger ich sie an. + if ( rOldSize.Height() < Prt().SSize().Height() || + rOldSize.Width() < Prt().SSize().Width() ) + pLowerFrm->SetRetouche(); + } + pLowerFrm = pLowerFrm->GetNext(); + } + + // Finally adjust the columns if width is set to auto + // Possible optimisation: execute this code earlier in this function and + // return??? + if ( ( (bVert && bHeightChgd) || (! bVert && bWidthChgd) ) && + Lower()->IsColumnFrm() ) + { + // get column attribute + const SwFmtCol* pColAttr = NULL; + if ( IsPageBodyFrm() ) + { + OSL_ENSURE( GetUpper()->IsPageFrm(), "Upper is not page frame" ); + pColAttr = &GetUpper()->GetFmt()->GetCol(); + } + else + { + OSL_ENSURE( IsFlyFrm() || IsSctFrm(), "Columns not in fly or section" ); + pColAttr = &GetFmt()->GetCol(); + } + + if ( pColAttr->IsOrtho() && pColAttr->GetNumCols() > 1 ) + AdjustColumns( pColAttr, sal_False ); + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::Format() +|* +|* Beschreibung: "Formatiert" den Frame; Frm und PrtArea. +|* Die Fixsize wird hier nicht eingestellt. +|* +|*************************************************************************/ +void SwLayoutFrm::Format( const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "LayoutFrm::Format, pAttrs ist 0." ); + + if ( bValidPrtArea && bValidSize ) + return; + + const sal_uInt16 nLeft = (sal_uInt16)pAttrs->CalcLeft( this ); + const sal_uInt16 nUpper = pAttrs->CalcTop(); + + const sal_uInt16 nRight = (sal_uInt16)((SwBorderAttrs*)pAttrs)->CalcRight( this ); + const sal_uInt16 nLower = pAttrs->CalcBottom(); + sal_Bool bVert = IsVertical() && !IsPageFrm(); + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; + if ( !bValidPrtArea ) + { + bValidPrtArea = sal_True; + (this->*fnRect->fnSetXMargins)( nLeft, nRight ); + (this->*fnRect->fnSetYMargins)( nUpper, nLower ); + } + + if ( !bValidSize ) + { + if ( !HasFixSize() ) + { + const SwTwips nBorder = nUpper + nLower; + const SwFmtFrmSize &rSz = GetFmt()->GetFrmSize(); + SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? rSz.GetHeight() : 0; + do + { bValidSize = sal_True; + + //Die Groesse in der VarSize wird durch den Inhalt plus den + //Raendern bestimmt. + SwTwips nRemaining = 0; + SwFrm *pFrm = Lower(); + while ( pFrm ) + { nRemaining += (pFrm->Frm().*fnRect->fnGetHeight)(); + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsUndersized() ) + // Dieser TxtFrm waere gern ein bisschen groesser + nRemaining += ((SwTxtFrm*)pFrm)->GetParHeight() + - (pFrm->Prt().*fnRect->fnGetHeight)(); + else if( pFrm->IsSctFrm() && ((SwSectionFrm*)pFrm)->IsUndersized() ) + nRemaining += ((SwSectionFrm*)pFrm)->Undersize(); + pFrm = pFrm->GetNext(); + } + nRemaining += nBorder; + nRemaining = Max( nRemaining, nMinHeight ); + const SwTwips nDiff = nRemaining-(Frm().*fnRect->fnGetHeight)(); + const long nOldLeft = (Frm().*fnRect->fnGetLeft)(); + const long nOldTop = (Frm().*fnRect->fnGetTop)(); + if ( nDiff ) + { + if ( nDiff > 0 ) + Grow( nDiff ); + else + Shrink( -nDiff ); + //Schnell auf dem kurzen Dienstweg die Position updaten. + MakePos(); + } + //Unterkante des Uppers nicht ueberschreiten. + if ( GetUpper() && (Frm().*fnRect->fnGetHeight)() ) + { + const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)(); + if( (this->*fnRect->fnSetLimit)( nLimit ) && + nOldLeft == (Frm().*fnRect->fnGetLeft)() && + nOldTop == (Frm().*fnRect->fnGetTop)() ) + bValidSize = bValidPrtArea = sal_True; + } + } while ( !bValidSize ); + } + else if ( GetType() & 0x0018 ) + { + do + { if ( Frm().Height() != pAttrs->GetSize().Height() ) + ChgSize( Size( Frm().Width(), pAttrs->GetSize().Height())); + bValidSize = sal_True; + MakePos(); + } while ( !bValidSize ); + } + else + bValidSize = sal_True; + } +} + +/************************************************************************* +|* +|* SwLayoutFrm::InvalidatePercentLowers() +|* +|*************************************************************************/ +static void InvaPercentFlys( SwFrm *pFrm, SwTwips nDiff ) +{ + OSL_ENSURE( pFrm->GetDrawObjs(), "Can't find any Objects" ); + for ( sal_uInt16 i = 0; i < pFrm->GetDrawObjs()->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + const SwFmtFrmSize &rSz = pFly->GetFmt()->GetFrmSize(); + if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() ) + { + sal_Bool bNotify = sal_True; + // If we've a fly with more than 90% relative height... + if( rSz.GetHeightPercent() > 90 && pFly->GetAnchorFrm() && + rSz.GetHeightPercent() != 0xFF && nDiff ) + { + const SwFrm *pRel = pFly->IsFlyLayFrm() ? pFly->GetAnchorFrm(): + pFly->GetAnchorFrm()->GetUpper(); + // ... and we have already more than 90% height and we + // not allow the text to go through... + // then a notifycation could cause an endless loop, e.g. + // 100% height and no text wrap inside a cell of a table. + if( pFly->Frm().Height()*10 > + ( nDiff + pRel->Prt().Height() )*9 && + pFly->GetFmt()->GetSurround().GetSurround() != + SURROUND_THROUGHT ) + bNotify = sal_False; + } + if( bNotify ) + pFly->InvalidateSize(); + } + } + } +} + +void SwLayoutFrm::InvaPercentLowers( SwTwips nDiff ) +{ + if ( GetDrawObjs() ) + ::InvaPercentFlys( this, nDiff ); + + SwFrm *pFrm = ContainsCntnt(); + if ( pFrm ) + do + { + if ( pFrm->IsInTab() && !IsTabFrm() ) + { + SwFrm *pTmp = pFrm->FindTabFrm(); + OSL_ENSURE( pTmp, "Where's my TabFrm?" ); + if( IsAnLower( pTmp ) ) + pFrm = pTmp; + } + + if ( pFrm->IsTabFrm() ) + { + const SwFmtFrmSize &rSz = ((SwLayoutFrm*)pFrm)->GetFmt()->GetFrmSize(); + if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() ) + pFrm->InvalidatePrt(); + } + else if ( pFrm->GetDrawObjs() ) + ::InvaPercentFlys( pFrm, nDiff ); + pFrm = pFrm->FindNextCnt(); + } while ( pFrm && IsAnLower( pFrm ) ) ; +} + +/************************************************************************* +|* +|* SwLayoutFrm::CalcRel() +|* +|*************************************************************************/ +long SwLayoutFrm::CalcRel( const SwFmtFrmSize &rSz, sal_Bool ) const +{ + long nRet = rSz.GetWidth(), + nPercent = rSz.GetWidthPercent(); + + if ( nPercent ) + { + const SwFrm *pRel = GetUpper(); + long nRel = LONG_MAX; + const ViewShell *pSh = getRootFrm()->GetCurrShell(); + const sal_Bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode(); + if( pRel->IsPageBodyFrm() && pSh && bBrowseMode && pSh->VisArea().Width() ) + { + nRel = pSh->GetBrowseWidth(); + long nDiff = nRel - pRel->Prt().Width(); + if ( nDiff > 0 ) + nRel -= nDiff; + } + nRel = Min( nRel, pRel->Prt().Width() ); + nRet = nRel * nPercent / 100; + } + return nRet; +} + +/************************************************************************* +|* Local helpers for SwLayoutFrm::FormatWidthCols() +|*************************************************************************/ +long MA_FASTCALL lcl_CalcMinColDiff( SwLayoutFrm *pLayFrm ) +{ + long nDiff = 0, nFirstDiff = 0; + SwLayoutFrm *pCol = (SwLayoutFrm*)pLayFrm->Lower(); + OSL_ENSURE( pCol, "Where's the columnframe?" ); + SwFrm *pFrm = pCol->Lower(); + do + { + if( pFrm && pFrm->IsBodyFrm() ) + pFrm = ((SwBodyFrm*)pFrm)->Lower(); + if ( pFrm && pFrm->IsTxtFrm() ) + { + const long nTmp = ((SwTxtFrm*)pFrm)->FirstLineHeight(); + if ( nTmp != USHRT_MAX ) + { + if ( pCol == pLayFrm->Lower() ) + nFirstDiff = nTmp; + else + nDiff = nDiff ? Min( nDiff, nTmp ) : nTmp; + } + } + //Leere Spalten ueberspringen! + pCol = (SwLayoutFrm*)pCol->GetNext(); + while ( pCol && 0 == (pFrm = pCol->Lower()) ) + pCol = (SwLayoutFrm*)pCol->GetNext(); + + } while ( pFrm && pCol ); + + return nDiff ? nDiff : nFirstDiff ? nFirstDiff : 240; +} + +sal_Bool lcl_IsFlyHeightClipped( SwLayoutFrm *pLay ) +{ + SwFrm *pFrm = pLay->ContainsCntnt(); + while ( pFrm ) + { + if ( pFrm->IsInTab() ) + pFrm = pFrm->FindTabFrm(); + + if ( pFrm->GetDrawObjs() ) + { + sal_uInt32 nCnt = pFrm->GetDrawObjs()->Count(); + for ( sal_uInt16 i = 0; i < nCnt; ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pFrm->GetDrawObjs())[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsHeightClipped() && + ( !pFly->IsFlyFreeFrm() || pFly->GetPageFrm() ) ) + return sal_True; + } + } + } + pFrm = pFrm->FindNextCnt(); + } + return sal_False; +} + +/************************************************************************* +|* SwLayoutFrm::FormatWidthCols() +|*************************************************************************/ +void SwLayoutFrm::FormatWidthCols( const SwBorderAttrs &rAttrs, + const SwTwips nBorder, const SwTwips nMinHeight ) +{ + //Wenn Spalten im Spiel sind, so wird die Groesse an der + //letzten Spalte ausgerichtet. + //1. Inhalt formatieren. + //2. Hoehe der letzten Spalte ermitteln, wenn diese zu + // zu gross ist muss der Fly wachsen. + // Der Betrag um den der Fly waechst ist aber nicht etwa + // der Betrag des Ueberhangs, denn wir muessen davon + // ausgehen, dass etwas Masse zurueckfliesst und so + // zusaetzlicher Platz geschaffen wird. + // Im Ersten Ansatz ist der Betrag um den gewachsen wird + // der Ueberhang geteilt durch die Spaltenanzahl oder + // der Ueberhang selbst wenn er kleiner als die Spalten- + // anzahl ist. + //3. Weiter mit 1. bis zur Stabilitaet. + + const SwFmtCol &rCol = rAttrs.GetAttrSet().GetCol(); + const sal_uInt16 nNumCols = rCol.GetNumCols(); + + sal_Bool bEnd = sal_False; + sal_Bool bBackLock = sal_False; + ViewShell *pSh = getRootFrm()->GetCurrShell(); + SwViewImp *pImp = pSh ? pSh->Imp() : 0; + { + // Zugrunde liegender Algorithmus + // Es wird versucht, eine optimale Hoehe fuer die Spalten zu finden. + // nMinimum beginnt mit der uebergebenen Mindesthoehe und wird dann als + // Maximum der Hoehen gepflegt, bei denen noch Spalteninhalt aus einer + // Spalte herausragt. + // nMaximum beginnt bei LONG_MAX und wird als Minimum der Hoehen gepflegt, + // bei denen der Inhalt gepasst hat. + // Bei spaltigen Bereichen beginnt nMaximum bei dem maximalen Wert, den + // die Umgebung vorgibt, dies kann natuerlich ein Wert sein, bei dem noch + // Inhalt heraushaengt. + // Es werden die Spalten formatiert, wenn Inhalt heraushaengt, wird nMinimum + // ggf. angepasst, dann wird gewachsen, mindestens um nMinDiff, aber nicht ueber + // ein groesseres nMaximum hinaus. Wenn kein Inhalt heraushaengt, sondern + // noch Luft in einer Spalte ist, schrumpfen wir entsprechend, mindestens um + // nMinDiff, aber nicht unter das nMinimum. + // Abgebrochen wird, wenn kein Inhalt mehr heraushaengt und das Minimum sich auf + // weniger als ein MinDiff dem Maximum angenaehert hat oder das von der + // Umgebung vorgegebene Maximum erreicht ist und trotzdem Inhalt heraus- + // haengt. + + // Kritik an der Implementation + // 1. Es kann theoretisch Situationen geben, in denen der Inhalt in einer geringeren + // Hoehe passt und in einer groesseren Hoehe nicht passt. Damit der Code robust + // gegen solche Verhaeltnisse ist, sind ein paar Abfragen bezgl. Minimum und Maximum + // drin, die wahrscheinlich niemals zuschlagen koennen. + // 2. Es wird fuer das Schrumpfen das gleiche nMinDiff benutzt wie fuer das Wachstum, + // das nMinDiff ist allerdings mehr oder weniger die kleinste erste Zeilenhoehe und + // als Mindestwert fuer das Schrumpfen nicht unbedingt optimal. + + long nMinimum = nMinHeight; + long nMaximum; + sal_Bool bNoBalance = sal_False; + SWRECTFN( this ) + if( IsSctFrm() ) + { + nMaximum = (Frm().*fnRect->fnGetHeight)() - nBorder + + (Frm().*fnRect->fnBottomDist)( + (GetUpper()->*fnRect->fnGetPrtBottom)() ); + nMaximum += GetUpper()->Grow( LONG_MAX, sal_True ); + if( nMaximum < nMinimum ) + { + if( nMaximum < 0 ) + nMinimum = nMaximum = 0; + else + nMinimum = nMaximum; + } + if( nMaximum > BROWSE_HEIGHT ) + nMaximum = BROWSE_HEIGHT; + + bNoBalance = ((SwSectionFrm*)this)->GetSection()->GetFmt()-> + GetBalancedColumns().GetValue(); + SwFrm* pAny = ContainsAny(); + if( bNoBalance || + ( !(Frm().*fnRect->fnGetHeight)() && pAny ) ) + { + long nTop = (this->*fnRect->fnGetTopMargin)(); + // --> OD 2004-11-01 #i23129# - correction: enlarge section + // to the calculated maximum height. + (Frm().*fnRect->fnAddBottom)( nMaximum - + (Frm().*fnRect->fnGetHeight)() ); + // <-- + if( nTop > nMaximum ) + nTop = nMaximum; + (this->*fnRect->fnSetYMargins)( nTop, 0 ); + } + if( !pAny && !((SwSectionFrm*)this)->IsFtnLock() ) + { + SwFtnContFrm* pFtnCont = ((SwSectionFrm*)this)->ContainsFtnCont(); + if( pFtnCont ) + { + SwFrm* pFtnAny = pFtnCont->ContainsAny(); + if( pFtnAny && pFtnAny->IsValid() ) + { + bBackLock = sal_True; + ((SwSectionFrm*)this)->SetFtnLock( sal_True ); + } + } + } + } + else + nMaximum = LONG_MAX; + + // --> OD 2004-08-25 #i3317# - reset temporarly consideration + // of wrapping style influence + SwPageFrm* pPageFrm = FindPageFrm(); + SwSortedObjs* pObjs = pPageFrm ? pPageFrm->GetSortedObjs() : 0L; + if ( pObjs ) + { + sal_uInt32 i = 0; + for ( i = 0; i < pObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pObjs)[i]; + + if ( IsAnLower( pAnchoredObj->GetAnchorFrm() ) ) + { + pAnchoredObj->SetTmpConsiderWrapInfluence( false ); + } + } + } + // <-- + do + { + //Kann eine Weile dauern, deshalb hier auf Waitcrsr pruefen. + if ( pImp ) + pImp->CheckWaitCrsr(); + + bValidSize = sal_True; + //Erstmal die Spalten formatieren, das entlastet den + //Stack ein wenig. + //Bei der Gelegenheit stellen wir auch gleich mal die + //Breiten und Hoehen der Spalten ein (so sie denn falsch sind). + SwLayoutFrm *pCol = (SwLayoutFrm*)Lower(); + + // --> FME 2004-07-19 #i27399# + // Simply setting the column width based on the values returned by + // CalcColWidth does not work for automatic column width. + AdjustColumns( &rCol, sal_False ); + // <-- + + for ( sal_uInt16 i = 0; i < nNumCols; ++i ) + { + pCol->Calc(); + // ColumnFrms besitzen jetzt einen BodyFrm, der auch kalkuliert werden will + pCol->Lower()->Calc(); + if( pCol->Lower()->GetNext() ) + pCol->Lower()->GetNext()->Calc(); // SwFtnCont + pCol = (SwLayoutFrm*)pCol->GetNext(); + } + + ::CalcCntnt( this ); + + pCol = (SwLayoutFrm*)Lower(); + OSL_ENSURE( pCol && pCol->GetNext(), ":-( Spalten auf Urlaub?"); + // bMinDiff wird gesetzt, wenn es keine leere Spalte gibt + sal_Bool bMinDiff = sal_True; + // OD 28.03.2003 #108446# - check for all column content and all columns + while ( bMinDiff && pCol ) + { + bMinDiff = 0 != pCol->ContainsCntnt(); + pCol = (SwLayoutFrm*)pCol->GetNext(); + } + pCol = (SwLayoutFrm*)Lower(); + // OD 28.03.2003 #108446# - initialize local variable + SwFrm *pLow = NULL; + SwTwips nDiff = 0; + SwTwips nMaxFree = 0; + SwTwips nAllFree = LONG_MAX; + // bFoundLower wird gesetzt, wenn es mind. eine nichtleere Spalte gibt + sal_Bool bFoundLower = sal_False; + while( pCol ) + { + SwLayoutFrm* pLay = (SwLayoutFrm*)pCol->Lower(); + SwTwips nInnerHeight = (pLay->Frm().*fnRect->fnGetHeight)() - + (pLay->Prt().*fnRect->fnGetHeight)(); + if( pLay->Lower() ) + { + bFoundLower = sal_True; + nInnerHeight += pLay->InnerHeight(); + } + else if( nInnerHeight < 0 ) + nInnerHeight = 0; + + if( pLay->GetNext() ) + { + bFoundLower = sal_True; + pLay = (SwLayoutFrm*)pLay->GetNext(); + OSL_ENSURE( pLay->IsFtnContFrm(),"FtnContainer exspected" ); + nInnerHeight += pLay->InnerHeight(); + nInnerHeight += (pLay->Frm().*fnRect->fnGetHeight)() - + (pLay->Prt().*fnRect->fnGetHeight)(); + } + nInnerHeight -= (pCol->Prt().*fnRect->fnGetHeight)(); + if( nInnerHeight > nDiff ) + { + nDiff = nInnerHeight; + nAllFree = 0; + } + else + { + if( nMaxFree < -nInnerHeight ) + nMaxFree = -nInnerHeight; + if( nAllFree > -nInnerHeight ) + nAllFree = -nInnerHeight; + } + pCol = (SwLayoutFrm*)pCol->GetNext(); + } + + if ( bFoundLower || ( IsSctFrm() && ((SwSectionFrm*)this)->HasFollow() ) ) + { + SwTwips nMinDiff = ::lcl_CalcMinColDiff( this ); + // Hier wird entschieden, ob wir wachsen muessen, naemlich wenn + // ein Spalteninhalt (nDiff) oder ein Fly herausragt. + // Bei spaltigen Bereichen wird beruecksichtigt, dass mit dem + // Besitz eines nichtleeren Follows die Groesse festgelegt ist. + if ( nDiff || ::lcl_IsFlyHeightClipped( this ) || + ( IsSctFrm() && ((SwSectionFrm*)this)->CalcMinDiff( nMinDiff ) ) ) + { + long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + // Das Minimum darf nicht kleiner sein als unsere PrtHeight, + // solange noch etwas herausragt. + if( nMinimum < nPrtHeight ) + nMinimum = nPrtHeight; + // Es muss sichergestellt sein, dass das Maximum nicht kleiner + // als die PrtHeight ist, wenn noch etwas herausragt + if( nMaximum < nPrtHeight ) + nMaximum = nPrtHeight; // Robust, aber kann das ueberhaupt eintreten? + if( !nDiff ) // wenn nur Flys herausragen, wachsen wir um nMinDiff + nDiff = nMinDiff; + // Wenn wir um mehr als nMinDiff wachsen wollen, wird dies auf die + // Spalten verteilt + if ( Abs(nDiff - nMinDiff) > nNumCols && nDiff > (long)nNumCols ) + nDiff /= nNumCols; + + if ( bMinDiff ) + { // Wenn es keinen leeren Spalten gibt, wollen wir mind. um nMinDiff + // wachsen. Sonderfall: Wenn wir kleiner als die minimale Frmhoehe + // sind und die PrtHeight kleiner als nMinDiff ist, wachsen wir so, + // dass die PrtHeight hinterher genau nMinDiff ist. + long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); + if ( nFrmHeight > nMinHeight || nPrtHeight >= nMinDiff ) + nDiff = Max( nDiff, nMinDiff ); + else if( nDiff < nMinDiff ) + nDiff = nMinDiff - nPrtHeight + 1; + } + // nMaximum ist eine Groesse, in der der Inhalt gepasst hat, + // oder der von der Umgebung vorgegebene Wert, deshalb + // brauchen wir nicht ueber diesen Wrt hinauswachsen. + if( nDiff + nPrtHeight > nMaximum ) + nDiff = nMaximum - nPrtHeight; + } + else if( nMaximum > nMinimum ) // Wir passen, haben wir auch noch Spielraum? + { + long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); + if ( nMaximum < nPrtHeight ) + nDiff = nMaximum - nPrtHeight; // wir sind ueber eine funktionierende + // Hoehe hinausgewachsen und schrumpfen wieder auf diese zurueck, + // aber kann das ueberhaupt eintreten? + else + { // Wir haben ein neues Maximum, eine Groesse, fuer die der Inhalt passt. + nMaximum = nPrtHeight; + // Wenn der Freiraum in den Spalten groesser ist als nMinDiff und wir + // nicht dadurch wieder unter das Minimum rutschen, wollen wir ein wenig + // Luft herauslassen. + if ( !bNoBalance && + // --> OD 2004-11-04 #i23129# - <nMinDiff> can be + // big, because of an object at the beginning of + // a column. Thus, decrease optimization here. + //nMaxFree >= nMinDiff && + nMaxFree > 0 && + // <-- + ( !nAllFree || + nMinimum < nPrtHeight - nMinDiff ) ) + { + nMaxFree /= nNumCols; // auf die Spalten verteilen + nDiff = nMaxFree < nMinDiff ? -nMinDiff : -nMaxFree; // mind. nMinDiff + if( nPrtHeight + nDiff <= nMinimum ) // Unter das Minimum? + nDiff = ( nMinimum - nMaximum ) / 2; // dann lieber die Mitte + } + else if( nAllFree ) + { + nDiff = -nAllFree; + if( nPrtHeight + nDiff <= nMinimum ) // Less than minimum? + nDiff = ( nMinimum - nMaximum ) / 2; // Take the center + } + } + } + if( nDiff ) // jetzt wird geschrumpft oder gewachsen.. + { + Size aOldSz( Prt().SSize() ); + long nTop = (this->*fnRect->fnGetTopMargin)(); + nDiff = (Prt().*fnRect->fnGetHeight)() + nDiff + nBorder - + (Frm().*fnRect->fnGetHeight)(); + (Frm().*fnRect->fnAddBottom)( nDiff ); + // --> OD 2006-08-16 #i68520# + if ( dynamic_cast<SwFlyFrm*>(this) ) + { + dynamic_cast<SwFlyFrm*>(this)->InvalidateObjRectWithSpaces(); + } + // <-- + (this->*fnRect->fnSetYMargins)( nTop, nBorder - nTop ); + ChgLowersProp( aOldSz ); + NotifyLowerObjs(); + + // --> OD 2004-08-25 #i3317# - reset temporarly consideration + // of wrapping style influence + SwPageFrm* pTmpPageFrm = FindPageFrm(); + SwSortedObjs* pTmpObjs = pTmpPageFrm ? pTmpPageFrm->GetSortedObjs() : 0L; + if ( pTmpObjs ) + { + sal_uInt32 i = 0; + for ( i = 0; i < pTmpObjs->Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = (*pTmpObjs)[i]; + + if ( IsAnLower( pAnchoredObj->GetAnchorFrm() ) ) + { + pAnchoredObj->SetTmpConsiderWrapInfluence( false ); + } + } + } + // <-- + //Es muss geeignet invalidiert werden, damit + //sich die Frms huebsch ausbalancieren + //- Der jeweils erste ab der zweiten Spalte bekommt + // ein InvalidatePos(); + pCol = (SwLayoutFrm*)Lower()->GetNext(); + while ( pCol ) + { + pLow = pCol->Lower(); + if ( pLow ) + pLow->_InvalidatePos(); + pCol = (SwLayoutFrm*)pCol->GetNext(); + } + if( IsSctFrm() && ((SwSectionFrm*)this)->HasFollow() ) + { + // Wenn wir einen Follow erzeugt haben, muessen wir + // seinem Inhalt die Chance geben, im CalcCntnt + // zurueckzufliessen + SwCntntFrm* pTmpCntnt = + ((SwSectionFrm*)this)->GetFollow()->ContainsCntnt(); + if( pTmpCntnt ) + pTmpCntnt->_InvalidatePos(); + } + } + else + bEnd = sal_True; + } + else + bEnd = sal_True; + + } while ( !bEnd || !bValidSize ); + } + // OD 01.04.2003 #108446# - Don't collect endnotes for sections. Thus, set + // 2nd parameter to <true>. + ::CalcCntnt( this, true ); + if( IsSctFrm() ) + { + // OD 14.03.2003 #i11760# - adjust 2nd parameter - sal_True --> true + ::CalcCntnt( this, true ); + if( bBackLock ) + ((SwSectionFrm*)this)->SetFtnLock( sal_False ); + } +} + + +/************************************************************************* +|* +|* SwRootFrm::InvalidateAllCntnt() +|* +|*************************************************************************/ + +SwCntntFrm* lcl_InvalidateSection( SwFrm *pCnt, sal_uInt8 nInv ) +{ + SwSectionFrm* pSect = pCnt->FindSctFrm(); + // Wenn unser CntntFrm in einer Tabelle oder Fussnote steht, sind nur + // Bereiche gemeint, die ebenfalls innerhalb liegen. + // Ausnahme: Wenn direkt eine Tabelle uebergeben wird. + if( ( ( pCnt->IsInTab() && !pSect->IsInTab() ) || + ( pCnt->IsInFtn() && !pSect->IsInFtn() ) ) && !pCnt->IsTabFrm() ) + return NULL; + if( nInv & INV_SIZE ) + pSect->_InvalidateSize(); + if( nInv & INV_POS ) + pSect->_InvalidatePos(); + if( nInv & INV_PRTAREA ) + pSect->_InvalidatePrt(); + SwFlowFrm *pFoll = pSect->GetFollow(); + // Temporary separation from follow + pSect->SetFollow( NULL ); + SwCntntFrm* pRet = pSect->FindLastCntnt(); + pSect->SetFollow( pFoll ); + return pRet; +} + +SwCntntFrm* lcl_InvalidateTable( SwTabFrm *pTable, sal_uInt8 nInv ) +{ + if( ( nInv & INV_SECTION ) && pTable->IsInSct() ) + lcl_InvalidateSection( pTable, nInv ); + if( nInv & INV_SIZE ) + pTable->_InvalidateSize(); + if( nInv & INV_POS ) + pTable->_InvalidatePos(); + if( nInv & INV_PRTAREA ) + pTable->_InvalidatePrt(); + return pTable->FindLastCntnt(); +} + +void lcl_InvalidateAllCntnt( SwCntntFrm *pCnt, sal_uInt8 nInv ); + +void lcl_InvalidateCntnt( SwCntntFrm *pCnt, sal_uInt8 nInv ) +{ + SwCntntFrm *pLastTabCnt = NULL; + SwCntntFrm *pLastSctCnt = NULL; + while ( pCnt ) + { + if( nInv & INV_SECTION ) + { + if( pCnt->IsInSct() ) + { + // Siehe oben bei Tabellen + if( !pLastSctCnt ) + pLastSctCnt = lcl_InvalidateSection( pCnt, nInv ); + if( pLastSctCnt == pCnt ) + pLastSctCnt = NULL; + } +#if OSL_DEBUG_LEVEL > 1 + else + OSL_ENSURE( !pLastSctCnt, "Where's the last SctCntnt?" ); +#endif + } + if( nInv & INV_TABLE ) + { + if( pCnt->IsInTab() ) + { + // Um nicht fuer jeden CntntFrm einer Tabelle das FindTabFrm() zu rufen + // und wieder die gleiche Tabelle zu invalidieren, merken wir uns den letzten + // CntntFrm der Tabelle und reagieren erst wieder auf IsInTab(), wenn wir + // an diesem vorbei sind. + // Beim Eintritt in die Tabelle wird der LastSctCnt auf Null gesetzt, + // damit Bereiche im Innern der Tabelle richtig invalidiert werden. + // Sollte die Tabelle selbst in einem Bereich stehen, so wird an + // diesem die Invalidierung bis zu dreimal durchgefuehrt, das ist vertretbar. + if( !pLastTabCnt ) + { + pLastTabCnt = lcl_InvalidateTable( pCnt->FindTabFrm(), nInv ); + pLastSctCnt = NULL; + } + if( pLastTabCnt == pCnt ) + { + pLastTabCnt = NULL; + pLastSctCnt = NULL; + } + } +#if OSL_DEBUG_LEVEL > 1 + else + OSL_ENSURE( !pLastTabCnt, "Where's the last TabCntnt?" ); +#endif + } + + if( nInv & INV_SIZE ) + pCnt->Prepare( PREP_CLEAR, 0, sal_False ); + if( nInv & INV_POS ) + pCnt->_InvalidatePos(); + if( nInv & INV_PRTAREA ) + pCnt->_InvalidatePrt(); + if ( nInv & INV_LINENUM ) + pCnt->InvalidateLineNum(); + if ( pCnt->GetDrawObjs() ) + lcl_InvalidateAllCntnt( pCnt, nInv ); + pCnt = pCnt->GetNextCntntFrm(); + } +} + +void lcl_InvalidateAllCntnt( SwCntntFrm *pCnt, sal_uInt8 nInv ) +{ + SwSortedObjs &rObjs = *pCnt->GetDrawObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + if ( pFly->IsFlyInCntFrm() ) + { + ::lcl_InvalidateCntnt( pFly->ContainsCntnt(), nInv ); + if( nInv & INV_DIRECTION ) + pFly->CheckDirChange(); + } + } + } +} + +void SwRootFrm::InvalidateAllCntnt( sal_uInt8 nInv ) +{ + // Erst werden alle Seitengebundenen FlyFrms abgearbeitet. + SwPageFrm *pPage = (SwPageFrm*)Lower(); + while( pPage ) + { + pPage->InvalidateFlyLayout(); + pPage->InvalidateFlyCntnt(); + pPage->InvalidateFlyInCnt(); + pPage->InvalidateLayout(); + pPage->InvalidateCntnt(); + pPage->InvalidatePage( pPage ); //Damit ggf. auch der Turbo verschwindet + + if ( pPage->GetSortedObjs() ) + { + const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + { + SwFlyFrm* pFly = static_cast<SwFlyFrm*>(pAnchoredObj); + ::lcl_InvalidateCntnt( pFly->ContainsCntnt(), nInv ); + if ( nInv & INV_DIRECTION ) + pFly->CheckDirChange(); + } + } + } + if( nInv & INV_DIRECTION ) + pPage->CheckDirChange(); + pPage = (SwPageFrm*)(pPage->GetNext()); + } + + //Hier den gesamten Dokumentinhalt und die zeichengebundenen Flys. + ::lcl_InvalidateCntnt( ContainsCntnt(), nInv ); + + if( nInv & INV_PRTAREA ) + { + ViewShell *pSh = getRootFrm()->GetCurrShell(); + if( pSh ) + pSh->InvalidateWindows( Frm() ); + } +} + +/** method to invalidate/re-calculate the position of all floating + screen objects (Writer fly frames and drawing objects), which are + anchored to paragraph or to character. + + OD 2004-03-16 #i11860# + + @author OD +*/ +void SwRootFrm::InvalidateAllObjPos() +{ + const SwPageFrm* pPageFrm = static_cast<const SwPageFrm*>(Lower()); + while( pPageFrm ) + { + pPageFrm->InvalidateFlyLayout(); + + if ( pPageFrm->GetSortedObjs() ) + { + const SwSortedObjs& rObjs = *(pPageFrm->GetSortedObjs()); + for ( sal_uInt8 i = 0; i < rObjs.Count(); ++i ) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + const SwFmtAnchor& rAnch = pAnchoredObj->GetFrmFmt().GetAnchor(); + if ((rAnch.GetAnchorId() != FLY_AT_PARA) && + (rAnch.GetAnchorId() != FLY_AT_CHAR)) + { + // only to paragraph and to character anchored objects are considered. + continue; + } + // --> OD 2004-07-07 #i28701# - special invalidation for anchored + // objects, whose wrapping style influence has to be considered. + if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() ) + pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence( true ); + else + pAnchoredObj->InvalidateObjPos(); + // <-- + } + } + + pPageFrm = static_cast<const SwPageFrm*>(pPageFrm->GetNext()); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |