diff options
Diffstat (limited to 'sw/source/core/objectpositioning')
6 files changed, 3090 insertions, 0 deletions
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx new file mode 100644 index 000000000000..78b9ba86e362 --- /dev/null +++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx @@ -0,0 +1,1129 @@ +/* -*- 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 <anchoredobjectposition.hxx> +#ifndef _ENVIRONMENTOFANCHOREDOBJECT +#include <environmentofanchoredobject.hxx> +#endif +#include <flyfrm.hxx> +#include <flyfrms.hxx> +#include <txtfrm.hxx> +#include <pagefrm.hxx> +#include <frmtool.hxx> +#include <svx/svdobj.hxx> +#include <dflyobj.hxx> +#include <dcontact.hxx> +#include <frmfmt.hxx> +#include <fmtornt.hxx> +// --> OD 2006-03-15 #i62875# +#include <fmtfollowtextflow.hxx> +// <-- +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <ndtxt.hxx> +#include <IDocumentSettingAccess.hxx> + +using namespace ::com::sun::star; +using namespace objectpositioning; + +// ************************************************************************** +// constructor, destructor, initialization +// ************************************************************************** +SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject& _rDrawObj ) + : mrDrawObj( _rDrawObj ), + mbIsObjFly( false ), + mpAnchoredObj( 0 ), + mpAnchorFrm( 0 ), + mpContact( 0 ), + // --> OD 2006-03-15 #i62875# + mbFollowTextFlow( false ), + mbDoNotCaptureAnchoredObj( false ) + // <-- +{ +#if OSL_DEBUG_LEVEL > 1 + // assert, if object isn't of excepted type + const bool bObjOfExceptedType = + mrDrawObj.ISA(SwVirtFlyDrawObj) || // object representing fly frame + mrDrawObj.ISA(SwDrawVirtObj) || // 'virtual' drawing object + ( !mrDrawObj.ISA(SdrVirtObj) && // 'master' drawing object + !mrDrawObj.ISA(SwFlyDrawObj) ); // - indirectly checked + (void) bObjOfExceptedType; + OSL_ENSURE( bObjOfExceptedType, + "SwAnchoredObjectPosition(..) - object of unexcepted type!" ); +#endif + + _GetInfoAboutObj(); +} + +/** determine information about object + + OD 30.07.2003 #110978# + members <mbIsObjFly>, <mpFrmOfObj>, <mpAnchorFrm>, <mpContact>, + <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set + + @author OD +*/ +void SwAnchoredObjectPosition::_GetInfoAboutObj() +{ + // determine, if object represents a fly frame + { + mbIsObjFly = mrDrawObj.ISA(SwVirtFlyDrawObj); + } + + // determine contact object + { + mpContact = static_cast<SwContact*>(GetUserCall( &mrDrawObj )); + OSL_ENSURE( mpContact, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing SwContact-object." ); + } + + // determine anchored object, the object belongs to + { + // OD 2004-03-30 #i26791# + mpAnchoredObj = mpContact->GetAnchoredObj( &mrDrawObj ); + OSL_ENSURE( mpAnchoredObj, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing anchored object." ); + } + + // determine frame, the object is anchored at + { + // OD 2004-03-23 #i26791# + mpAnchorFrm = mpAnchoredObj->AnchorFrm(); + OSL_ENSURE( mpAnchorFrm, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing anchor frame." ); + } + + // determine format the object belongs to + { + // --> OD 2004-07-01 #i28701# + mpFrmFmt = &mpAnchoredObj->GetFrmFmt(); + OSL_ENSURE( mpFrmFmt, + "<SwAnchoredObjectPosition::_GetInfoAboutObj() - missing frame format." ); + } + + // --> OD 2006-03-15 #i62875# + // determine attribute value of <Follow-Text-Flow> + { + mbFollowTextFlow = mpFrmFmt->GetFollowTextFlow().GetValue(); + } + + // determine, if anchored object has not to be captured on the page. + // the following conditions must be hold to *not* capture it: + // - corresponding document compatibility flag is set + // - it's a drawing object + // - it doesn't follow the text flow + { + mbDoNotCaptureAnchoredObj = !mbIsObjFly && !mbFollowTextFlow && + mpFrmFmt->getIDocumentSettingAccess()->get(IDocumentSettingAccess::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE); + } + // <-- +} + +SwAnchoredObjectPosition::~SwAnchoredObjectPosition() +{} + +bool SwAnchoredObjectPosition::IsAnchoredToChar() const +{ + return false; +} + +const SwFrm* SwAnchoredObjectPosition::ToCharOrientFrm() const +{ + return NULL; +} + +const SwRect* SwAnchoredObjectPosition::ToCharRect() const +{ + return NULL; +} + +// OD 12.11.2003 #i22341# +SwTwips SwAnchoredObjectPosition::ToCharTopOfLine() const +{ + return 0L; +} + +/** helper method to determine top of a frame for the vertical + object positioning + + OD 2004-03-11 #i11860# + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_GetTopForObjPos( const SwFrm& _rFrm, + const SwRectFn& _fnRect, + const bool _bVert ) const +{ + SwTwips nTopOfFrmForObjPos = (_rFrm.Frm().*_fnRect->fnGetTop)(); + + if ( _rFrm.IsTxtFrm() ) + { + const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(_rFrm); + if ( _bVert ) + { + nTopOfFrmForObjPos -= + rTxtFrm.GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + } + else + { + nTopOfFrmForObjPos += + rTxtFrm.GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + } + } + + return nTopOfFrmForObjPos; +} + +void SwAnchoredObjectPosition::_GetVertAlignmentValues( + const SwFrm& _rVertOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eRelOrient, + SwTwips& _orAlignAreaHeight, + SwTwips& _orAlignAreaOffset ) const +{ + SwTwips nHeight = 0; + SwTwips nOffset = 0; + SWRECTFN( (&_rVertOrientFrm) ) + // OD 2004-03-11 #i11860# - top of <_rVertOrientFrm> for object positioning + const SwTwips nVertOrientTop = _GetTopForObjPos( _rVertOrientFrm, fnRect, bVert ); + // OD 2004-03-11 #i11860# - upper space amount of <_rVertOrientFrm> considered + // for previous frame + const SwTwips nVertOrientUpperSpaceForPrevFrmAndPageGrid = + _rVertOrientFrm.IsTxtFrm() + ? static_cast<const SwTxtFrm&>(_rVertOrientFrm). + GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() + : 0; + switch ( _eRelOrient ) + { + case text::RelOrientation::FRAME: + { + // OD 2004-03-11 #i11860# - consider upper space of previous frame + nHeight = (_rVertOrientFrm.Frm().*fnRect->fnGetHeight)() - + nVertOrientUpperSpaceForPrevFrmAndPageGrid; + nOffset = 0; + } + break; + case text::RelOrientation::PRINT_AREA: + { + nHeight = (_rVertOrientFrm.Prt().*fnRect->fnGetHeight)(); + // OD 2004-03-11 #i11860# - consider upper space of previous frame + nOffset = (_rVertOrientFrm.*fnRect->fnGetTopMargin)() - + nVertOrientUpperSpaceForPrevFrmAndPageGrid; + // if aligned to page in horizontal layout, consider header and + // footer frame height appropriately. + if( _rVertOrientFrm.IsPageFrm() && !bVert ) + { + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rVertOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + } + break; + case text::RelOrientation::PAGE_FRAME: + { + nHeight = (_rPageAlignLayFrm.Frm().*fnRect->fnGetHeight)(); + nOffset = (*fnRect->fnYDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetTop)(), + nVertOrientTop ); + } + break; + case text::RelOrientation::PAGE_PRINT_AREA: + { + nHeight = (_rPageAlignLayFrm.Prt().*fnRect->fnGetHeight)(); + nOffset = (_rPageAlignLayFrm.*fnRect->fnGetTopMargin)() + + (*fnRect->fnYDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetTop)(), + nVertOrientTop ); + // if aligned to page in horizontal layout, consider header and + // footer frame height appropriately. + if( _rPageAlignLayFrm.IsPageFrm() && !bVert ) + { + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rPageAlignLayFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + } + break; + // OD 12.11.2003 #i22341# - vertical alignment at top of line + case text::RelOrientation::TEXT_LINE: + { + if ( IsAnchoredToChar() ) + { + nHeight = 0; + nOffset = (*fnRect->fnYDiff)( ToCharTopOfLine(), nVertOrientTop ); + } + else + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + break; + case text::RelOrientation::CHAR: + { + if ( IsAnchoredToChar() ) + { + nHeight = (ToCharRect()->*fnRect->fnGetHeight)(); + nOffset = (*fnRect->fnYDiff)( (ToCharRect()->*fnRect->fnGetTop)(), + nVertOrientTop ); + } + else + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + break; + // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar + default: + //case text::RelOrientation::PAGE_LEFT: not valid for vertical alignment + //case text::RelOrientation::PAGE_RIGHT: not valid for vertical alignment + //case text::RelOrientation::FRAME_LEFT: not valid for vertical alignment + //case text::RelOrientation::FRAME_RIGHT: not valid for vertical alignment + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + + _orAlignAreaHeight = nHeight; + _orAlignAreaOffset = nOffset; +} + +// --> OD 2004-06-17 #i26791# - add output parameter <_roVertOffsetToFrmAnchorPos> +SwTwips SwAnchoredObjectPosition::_GetVertRelPos( + const SwFrm& _rVertOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eVertOrient, + const sal_Int16 _eRelOrient, + const SwTwips _nVertPos, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + SwTwips& _roVertOffsetToFrmAnchorPos ) const +{ + SwTwips nRelPosY = 0; + SWRECTFN( (&_rVertOrientFrm) ); + + SwTwips nAlignAreaHeight; + SwTwips nAlignAreaOffset; + _GetVertAlignmentValues( _rVertOrientFrm, _rPageAlignLayFrm, + _eRelOrient, nAlignAreaHeight, nAlignAreaOffset ); + + nRelPosY = nAlignAreaOffset; + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + const SwTwips nObjHeight = (aObjBoundRect.*fnRect->fnGetHeight)(); + + switch ( _eVertOrient ) + { + case text::VertOrientation::NONE: + { + // 'manual' vertical position + nRelPosY += _nVertPos; + } + break; + case text::VertOrientation::TOP: + { + nRelPosY += bVert ? _rLRSpacing.GetRight() : _rULSpacing.GetUpper(); + } + break; + case text::VertOrientation::CENTER: + { + nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2); + } + break; + case text::VertOrientation::BOTTOM: + { + nRelPosY += nAlignAreaHeight - + ( nObjHeight + ( bVert ? _rLRSpacing.GetLeft() : _rULSpacing.GetLower() ) ); + } + break; + default: + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertRelPos(..) - invalid vertical positioning" ); + } + } + + // --> OD 2004-06-17 #i26791# + _roVertOffsetToFrmAnchorPos = nAlignAreaOffset; + + return nRelPosY; +} + +/** adjust calculated vertical in order to keep object inside + 'page' alignment layout frame. + + OD 2004-07-01 #i28701# - parameter <_nTopOfAnch> and <_bVert> added + OD 2004-07-22 #i31805# - add parameter <_bCheckBottom> + OD 2004-10-08 #i26945# - add parameter <_bFollowTextFlow> + OD 2006-03-15 #i62875# - method now private and renamed. + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_ImplAdjustVertRelPos( const SwTwips _nTopOfAnch, + const bool _bVert, + const SwFrm& _rPageAlignLayFrm, + const SwTwips _nProposedRelPosY, + const bool _bFollowTextFlow, + const bool _bCheckBottom ) const +{ + SwTwips nAdjustedRelPosY = _nProposedRelPosY; + + const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() ); + + // determine the area of 'page' alignment frame, to which the vertical + // position is restricted. + // --> OD 2004-07-06 #i28701# - Extend restricted area for the vertical + // position to area of the page frame, if wrapping style influence is + // considered on object positioning. Needed to avoid layout loops in the + // object positioning algorithm considering the wrapping style influence + // caused by objects, which follow the text flow and thus are restricted + // to its environment (e.g. page header/footer). + SwRect aPgAlignArea; + { + // --> OD 2004-10-08 #i26945# - no extension of restricted area, if + // object's attribute follow text flow is set and its inside a table + if ( GetFrmFmt().getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) && + ( !_bFollowTextFlow || + !GetAnchoredObj().GetAnchorFrm()->IsInTab() ) ) + { + aPgAlignArea = _rPageAlignLayFrm.FindPageFrm()->Frm(); + } + else + { + aPgAlignArea = _rPageAlignLayFrm.Frm(); + } + } + + if ( _bVert ) + { + // OD 2004-07-22 #i31805# - consider value of <_bCheckBottom> + if ( _bCheckBottom && + _nTopOfAnch - nAdjustedRelPosY - aObjSize.Width() < + aPgAlignArea.Left() ) + { + nAdjustedRelPosY = aPgAlignArea.Left() + + _nTopOfAnch - + aObjSize.Width(); + } + // --> OD 2004-08-13 #i32964# - correction + if ( _nTopOfAnch - nAdjustedRelPosY > aPgAlignArea.Right() ) + { + nAdjustedRelPosY = _nTopOfAnch - aPgAlignArea.Right(); + } + // <-- + } + else + { + // OD 2004-07-22 #i31805# - consider value of <_bCheckBottom> + if ( _bCheckBottom && + _nTopOfAnch + nAdjustedRelPosY + aObjSize.Height() > + // --> OD 2006-01-13 #129959# + // Do not mix usage of <top + height> and <bottom> +// aPgAlignArea.Bottom() ) + aPgAlignArea.Top() + aPgAlignArea.Height() ) + // <-- + { + // --> OD 2006-01-13 #129959# + // Do not mix usage of <top + height> and <bottom> +// nAdjustedRelPosY = aPgAlignArea.Bottom() - + nAdjustedRelPosY = aPgAlignArea.Top() + aPgAlignArea.Height() - + // <-- + _nTopOfAnch - + aObjSize.Height(); + } + if ( _nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Top() ) + { + nAdjustedRelPosY = aPgAlignArea.Top() - _nTopOfAnch; + } + } + + return nAdjustedRelPosY; +} + +/** adjust calculated horizontal in order to keep object inside + 'page' alignment layout frame. + + OD 2006-03-15 #i62875# - method now private and renamed. + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_ImplAdjustHoriRelPos( + const SwFrm& _rPageAlignLayFrm, + const SwTwips _nProposedRelPosX ) const +{ + SwTwips nAdjustedRelPosX = _nProposedRelPosX; + + const SwFrm& rAnchorFrm = GetAnchorFrm(); + const bool bVert = rAnchorFrm.IsVertical(); + + const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() ); + + if( bVert ) + { + if ( rAnchorFrm.Frm().Top() + nAdjustedRelPosX + aObjSize.Height() > + _rPageAlignLayFrm.Frm().Bottom() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Bottom() - + rAnchorFrm.Frm().Top() - + aObjSize.Height(); + } + if ( rAnchorFrm.Frm().Top() + nAdjustedRelPosX < + _rPageAlignLayFrm.Frm().Top() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Top() - + rAnchorFrm.Frm().Top(); + } + } + else + { + if ( rAnchorFrm.Frm().Left() + nAdjustedRelPosX + aObjSize.Width() > + _rPageAlignLayFrm.Frm().Right() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Right() - + rAnchorFrm.Frm().Left() - + aObjSize.Width(); + } + if ( rAnchorFrm.Frm().Left() + nAdjustedRelPosX < + _rPageAlignLayFrm.Frm().Left() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Left() - + rAnchorFrm.Frm().Left(); + } + } + + return nAdjustedRelPosX; +} + +/** determine alignment value for horizontal position of object + + @author OD +*/ +void SwAnchoredObjectPosition::_GetHoriAlignmentValues( const SwFrm& _rHoriOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eRelOrient, + const bool _bObjWrapThrough, + SwTwips& _orAlignAreaWidth, + SwTwips& _orAlignAreaOffset, + bool& _obAlignedRelToPage ) const +{ + SwTwips nWidth = 0; + SwTwips nOffset = 0; + SWRECTFN( (&_rHoriOrientFrm) ) + switch ( _eRelOrient ) + { + case text::RelOrientation::PRINT_AREA: + { + nWidth = (_rHoriOrientFrm.Prt().*fnRect->fnGetWidth)(); + nOffset = (_rHoriOrientFrm.*fnRect->fnGetLeftMargin)(); + if ( _rHoriOrientFrm.IsTxtFrm() ) + { + // consider movement of text frame left + nOffset += static_cast<const SwTxtFrm&>(_rHoriOrientFrm).GetBaseOfstForFly( !_bObjWrapThrough ); + } + else if ( _rHoriOrientFrm.IsPageFrm() && bVert ) + { + // for to-page anchored objects, consider header/footer frame + // in vertical layout + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rHoriOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + break; + } + case text::RelOrientation::PAGE_LEFT: + { + // align at left border of page frame/fly frame/cell frame + nWidth = (_rPageAlignLayFrm.*fnRect->fnGetLeftMargin)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + } + break; + case text::RelOrientation::PAGE_RIGHT: + { + // align at right border of page frame/fly frame/cell frame + nWidth = (_rPageAlignLayFrm.*fnRect->fnGetRightMargin)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.*fnRect->fnGetPrtRight)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + } + break; + case text::RelOrientation::FRAME_LEFT: + { + // align at left border of anchor frame + nWidth = (_rHoriOrientFrm.*fnRect->fnGetLeftMargin)(); + nOffset = 0; + } + break; + case text::RelOrientation::FRAME_RIGHT: + { + // align at right border of anchor frame + // OD 19.08.2003 #110978# - unify and simplify + nWidth = (_rHoriOrientFrm.*fnRect->fnGetRightMargin)(); + //nOffset = (_rHoriOrientFrm.Frm().*fnRect->fnGetWidth)() - + // nWidth; + nOffset = (_rHoriOrientFrm.Prt().*fnRect->fnGetRight)(); + } + break; + case text::RelOrientation::CHAR: + { + // alignment relative to character - assure, that corresponding + // character rectangle is set. + if ( IsAnchoredToChar() ) + { + nWidth = 0; + nOffset = (*fnRect->fnXDiff)( + (ToCharRect()->*fnRect->fnGetLeft)(), + (ToCharOrientFrm()->Frm().*fnRect->fnGetLeft)() ); + break; + } + // no break! + } + case text::RelOrientation::PAGE_PRINT_AREA: + { + nWidth = (_rPageAlignLayFrm.Prt().*fnRect->fnGetWidth)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.*fnRect->fnGetPrtLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + if ( _rHoriOrientFrm.IsPageFrm() && bVert ) + { + // for to-page anchored objects, consider header/footer frame + // in vertical layout + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rHoriOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + _obAlignedRelToPage = true; + break; + } + case text::RelOrientation::PAGE_FRAME: + { + nWidth = (_rPageAlignLayFrm.Frm().*fnRect->fnGetWidth)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + break; + } + default: + // case text::RelOrientation::FRAME: + { + nWidth = (_rHoriOrientFrm.Frm().*fnRect->fnGetWidth)(); + nOffset = _rHoriOrientFrm.IsTxtFrm() ? + static_cast<const SwTxtFrm&>(_rHoriOrientFrm).GetBaseOfstForFly( !_bObjWrapThrough ) : + 0; + break; + } + } + + _orAlignAreaWidth = nWidth; + _orAlignAreaOffset = nOffset; +} + +/** toggle given horizontal orientation and relative alignment + + @author OD +*/ +void SwAnchoredObjectPosition::_ToggleHoriOrientAndAlign( + const bool _bToggleLeftRight, + sal_Int16& _ioeHoriOrient, + sal_Int16& _iopeRelOrient + ) const +{ + if( _bToggleLeftRight ) + { + // toggle orientation + switch ( _ioeHoriOrient ) + { + case text::HoriOrientation::RIGHT : + { + _ioeHoriOrient = text::HoriOrientation::LEFT; + } + break; + case text::HoriOrientation::LEFT : + { + _ioeHoriOrient = text::HoriOrientation::RIGHT; + } + break; + default: + break; + } + + // toggle relative alignment + switch ( _iopeRelOrient ) + { + case text::RelOrientation::PAGE_RIGHT : + { + _iopeRelOrient = text::RelOrientation::PAGE_LEFT; + } + break; + case text::RelOrientation::PAGE_LEFT : + { + _iopeRelOrient = text::RelOrientation::PAGE_RIGHT; + } + break; + case text::RelOrientation::FRAME_RIGHT : + { + _iopeRelOrient = text::RelOrientation::FRAME_LEFT; + } + break; + case text::RelOrientation::FRAME_LEFT : + { + _iopeRelOrient = text::RelOrientation::FRAME_RIGHT; + } + break; + default: + break; + } + } +} + +/** calculate relative horizontal position + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_CalcRelPosX( + const SwFrm& _rHoriOrientFrm, + const SwEnvironmentOfAnchoredObject& _rEnvOfObj, + const SwFmtHoriOrient& _rHoriOrient, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + const bool _bObjWrapThrough, + const SwTwips _nRelPosY, + SwTwips& _roHoriOffsetToFrmAnchorPos + ) const +{ + // determine 'page' alignment layout frame + const SwFrm& rPageAlignLayFrm = + _rEnvOfObj.GetHoriEnvironmentLayoutFrm( _rHoriOrientFrm ); + + const bool bEvenPage = !rPageAlignLayFrm.OnRightPage(); + const bool bToggle = _rHoriOrient.IsPosToggle() && bEvenPage; + + // determine orientation and relative alignment + sal_Int16 eHoriOrient = _rHoriOrient.GetHoriOrient(); + sal_Int16 eRelOrient = _rHoriOrient.GetRelationOrient(); + // toggle orientation and relative alignment + _ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient ); + + // determine alignment parameter + // <nWidth>: 'width' of alignment area + // <nOffset>: offset of alignment area, relative to 'left' of anchor frame + SwTwips nWidth = 0; + SwTwips nOffset = 0; + bool bAlignedRelToPage = false; + _GetHoriAlignmentValues( _rHoriOrientFrm, rPageAlignLayFrm, + eRelOrient, _bObjWrapThrough, + nWidth, nOffset, bAlignedRelToPage ); + + const SwFrm& rAnchorFrm = GetAnchorFrm(); + SWRECTFN( (&_rHoriOrientFrm) ) + SwTwips nObjWidth = (GetAnchoredObj().GetObjRect().*fnRect->fnGetWidth)(); + SwTwips nRelPosX = nOffset; + if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE ) + { + // 'manual' horizonal position + const bool bR2L = rAnchorFrm.IsRightToLeft(); + if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient ) + { + if( bR2L ) + nRelPosX -= _rHoriOrient.GetPos(); + else + nRelPosX += _rHoriOrient.GetPos(); + } + else if ( bToggle || ( !_rHoriOrient.IsPosToggle() && bR2L ) ) + { + // OD 04.08.2003 #110978# - correction: consider <nOffset> also for + // toggling from left to right. + nRelPosX += nWidth - nObjWidth - _rHoriOrient.GetPos(); + } + else + { + nRelPosX += _rHoriOrient.GetPos(); + } + } + else if ( text::HoriOrientation::CENTER == eHoriOrient ) + nRelPosX += (nWidth / 2) - (nObjWidth / 2); + else if ( text::HoriOrientation::RIGHT == eHoriOrient ) + nRelPosX += nWidth - + ( nObjWidth + + ( bVert ? _rULSpacing.GetLower() : _rLRSpacing.GetRight() ) ); + else + nRelPosX += bVert ? _rULSpacing.GetUpper() : _rLRSpacing.GetLeft(); + + // adjust relative position by distance between anchor frame and + // the frame, the object is oriented at. + if ( &rAnchorFrm != &_rHoriOrientFrm ) + { + SwTwips nLeftOrient = (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)(); + SwTwips nLeftAnchor = (rAnchorFrm.Frm().*fnRect->fnGetLeft)(); + nRelPosX += (*fnRect->fnXDiff)( nLeftOrient, nLeftAnchor ); + } + + // OD 2004-05-21 #i28701# - deactivate follow code +// // adjust relative horizontal position, if object is manual horizontal +// // positioned (not 'page' aligned) and orients not at the anchor frame, +// // but it overlaps anchor frame. +// if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE && !bAlignedRelToPage && +// &rAnchorFrm != &_rHoriOrientFrm ) +// { +// // E.g.: consider a columned page/section with an horizontal +// // negative positioned object. +// // OD 2004-03-23 #i26791# +// const SwRect& rObjRect = GetAnchoredObj().GetObjRect(); +// if( bVert ) +// { +// if( _rHoriOrientFrm.Frm().Top() > rAnchorFrm.Frm().Bottom() && +// rObjRect.Right() > rAnchorFrm.Frm().Left() ) +// { +// const SwTwips nProposedPosX = nRelPosX + rAnchorFrm.Frm().Top(); +// if ( nProposedPosX < rAnchorFrm.Frm().Bottom() ) +// nRelPosX = rAnchorFrm.Frm().Height() + 1; +// } +// } +// else +// { +// if( _rHoriOrientFrm.Frm().Left() > rAnchorFrm.Frm().Right() && +// rObjRect.Top() < rAnchorFrm.Frm().Bottom() ) +// { +// // OD 04.08.2003 #110978# - correction: use <nRelPosX> +// // instead of <aRelPos.X()> +// const SwTwips nProposedPosX = nRelPosX + rAnchorFrm.Frm().Left(); +// if ( nProposedPosX < rAnchorFrm.Frm().Right() ) +// nRelPosX = rAnchorFrm.Frm().Width() + 1; +// } +// } +// } + // adjust calculated relative horizontal position, in order to + // keep object inside 'page' alignment layout frame + const SwFrm& rEnvironmentLayFrm = + _rEnvOfObj.GetHoriEnvironmentLayoutFrm( _rHoriOrientFrm ); + nRelPosX = _AdjustHoriRelPos( rEnvironmentLayFrm, nRelPosX ); + + // if object is a Writer fly frame and it's anchored to a content and + // it is horizontal positioned left or right, but not relative to character, + // it has to be drawn aside another object, which have the same horizontal + // position and lay below it. + if ( GetAnchoredObj().ISA(SwFlyFrm) && + ( GetContact().ObjAnchoredAtPara() || GetContact().ObjAnchoredAtChar() ) && + ( eHoriOrient == text::HoriOrientation::LEFT || eHoriOrient == text::HoriOrientation::RIGHT ) && + eRelOrient != text::RelOrientation::CHAR ) + { + nRelPosX = _AdjustHoriRelPosForDrawAside( _rHoriOrientFrm, + nRelPosX, _nRelPosY, + eHoriOrient, eRelOrient, + _rLRSpacing, _rULSpacing, + bEvenPage ); + } + + // --> OD 2004-06-17 #i26791# + _roHoriOffsetToFrmAnchorPos = nOffset; + + return nRelPosX; +} + +// ************************************************************************** +// method incl. helper methods for adjusting proposed horizontal position, +// if object has to draw aside another object. +// ************************************************************************** +/** adjust calculated horizontal position in order to draw object + aside other objects with same positioning + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_AdjustHoriRelPosForDrawAside( + const SwFrm& _rHoriOrientFrm, + const SwTwips _nProposedRelPosX, + const SwTwips _nRelPosY, + const sal_Int16 _eHoriOrient, + const sal_Int16 _eRelOrient, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + const bool _bEvenPage + ) const +{ + // OD 2004-03-23 #i26791# + if ( !GetAnchorFrm().ISA(SwTxtFrm) || + !GetAnchoredObj().ISA(SwFlyAtCntFrm) ) + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" ); + return _nProposedRelPosX; + } + + const SwTxtFrm& rAnchorTxtFrm = static_cast<const SwTxtFrm&>(GetAnchorFrm()); + // OD 2004-03-23 #i26791# + const SwFlyAtCntFrm& rFlyAtCntFrm = + static_cast<const SwFlyAtCntFrm&>(GetAnchoredObj()); + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + SWRECTFN( (&_rHoriOrientFrm) ) + + SwTwips nAdjustedRelPosX = _nProposedRelPosX; + + // determine proposed object bound rectangle + Point aTmpPos = (rAnchorTxtFrm.Frm().*fnRect->fnGetPos)(); + if( bVert ) + { + aTmpPos.X() -= _nRelPosY + aObjBoundRect.Width(); + aTmpPos.Y() += nAdjustedRelPosX; + } + else + { + aTmpPos.X() += nAdjustedRelPosX; + aTmpPos.Y() += _nRelPosY; + } + SwRect aTmpObjRect( aTmpPos, aObjBoundRect.SSize() ); + + const UINT32 nObjOrdNum = GetObject().GetOrdNum(); + const SwPageFrm* pObjPage = rFlyAtCntFrm.FindPageFrm(); + const SwFrm* pObjContext = ::FindKontext( &rAnchorTxtFrm, FRM_COLUMN ); + ULONG nObjIndex = rAnchorTxtFrm.GetTxtNode()->GetIndex(); + SwOrderIter aIter( pObjPage, TRUE ); + const SwFlyFrm* pFly = ((SwVirtFlyDrawObj*)aIter.Bottom())->GetFlyFrm(); + while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() ) + { + if ( _DrawAsideFly( pFly, aTmpObjRect, pObjContext, nObjIndex, + _bEvenPage, _eHoriOrient, _eRelOrient ) ) + { + if( bVert ) + { + const SvxULSpaceItem& rOtherUL = pFly->GetFmt()->GetULSpace(); + const SwTwips nOtherTop = pFly->Frm().Top() - rOtherUL.GetUpper(); + const SwTwips nOtherBot = pFly->Frm().Bottom() + rOtherUL.GetLower(); + if ( nOtherTop <= aTmpObjRect.Bottom() + _rULSpacing.GetLower() && + nOtherBot >= aTmpObjRect.Top() - _rULSpacing.GetUpper() ) + { + if ( _eHoriOrient == text::HoriOrientation::LEFT ) + { + SwTwips nTmp = nOtherBot + 1 + _rULSpacing.GetUpper() - + rAnchorTxtFrm.Frm().Top(); + if ( nTmp > nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Top() + nTmp + + aObjBoundRect.Height() + _rULSpacing.GetLower() + <= pObjPage->Frm().Height() + pObjPage->Frm().Top() ) + { + nAdjustedRelPosX = nTmp; + } + } + else if ( _eHoriOrient == text::HoriOrientation::RIGHT ) + { + SwTwips nTmp = nOtherTop - 1 - _rULSpacing.GetLower() - + aObjBoundRect.Height() - + rAnchorTxtFrm.Frm().Top(); + if ( nTmp < nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Top() + nTmp - _rULSpacing.GetUpper() + >= pObjPage->Frm().Top() ) + { + nAdjustedRelPosX = nTmp; + } + } + aTmpObjRect.Pos().Y() = rAnchorTxtFrm.Frm().Top() + + nAdjustedRelPosX; + } + } + else + { + const SvxLRSpaceItem& rOtherLR = pFly->GetFmt()->GetLRSpace(); + const SwTwips nOtherLeft = pFly->Frm().Left() - rOtherLR.GetLeft(); + const SwTwips nOtherRight = pFly->Frm().Right() + rOtherLR.GetRight(); + if( nOtherLeft <= aTmpObjRect.Right() + _rLRSpacing.GetRight() && + nOtherRight >= aTmpObjRect.Left() - _rLRSpacing.GetLeft() ) + { + if ( _eHoriOrient == text::HoriOrientation::LEFT ) + { + SwTwips nTmp = nOtherRight + 1 + _rLRSpacing.GetLeft() - + rAnchorTxtFrm.Frm().Left(); + if ( nTmp > nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Left() + nTmp + + aObjBoundRect.Width() + _rLRSpacing.GetRight() + <= pObjPage->Frm().Width() + pObjPage->Frm().Left() ) + { + nAdjustedRelPosX = nTmp; + } + } + else if ( _eHoriOrient == text::HoriOrientation::RIGHT ) + { + SwTwips nTmp = nOtherLeft - 1 - _rLRSpacing.GetRight() - + aObjBoundRect.Width() - + rAnchorTxtFrm.Frm().Left(); + if ( nTmp < nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Left() + nTmp - _rLRSpacing.GetLeft() + >= pObjPage->Frm().Left() ) + { + nAdjustedRelPosX = nTmp; + } + } + aTmpObjRect.Pos().X() = rAnchorTxtFrm.Frm().Left() + + nAdjustedRelPosX; + } + } // end of <if (bVert)> + } // end of <if _DrawAsideFly(..)> + + pFly = ((SwVirtFlyDrawObj*)aIter.Next())->GetFlyFrm(); + } // end of <loop on fly frames + + return nAdjustedRelPosX; +} + +/** detemine, if object has to draw aside given fly frame + + method used by <_AdjustHoriRelPosForDrawAside(..)> + + @author OD +*/ +bool SwAnchoredObjectPosition::_DrawAsideFly( const SwFlyFrm* _pFly, + const SwRect& _rObjRect, + const SwFrm* _pObjContext, + const ULONG _nObjIndex, + const bool _bEvenPage, + const sal_Int16 _eHoriOrient, + const sal_Int16 _eRelOrient + ) const +{ + bool bRetVal = false; + + SWRECTFN( (&GetAnchorFrm()) ) + + if ( _pFly->IsFlyAtCntFrm() && + (_pFly->Frm().*fnRect->fnBottomDist)( (_rObjRect.*fnRect->fnGetTop)() ) < 0 && + (_rObjRect.*fnRect->fnBottomDist)( (_pFly->Frm().*fnRect->fnGetTop)() ) < 0 && + ::FindKontext( _pFly->GetAnchorFrm(), FRM_COLUMN ) == _pObjContext ) + { + ULONG nOtherIndex = + static_cast<const SwTxtFrm*>(_pFly->GetAnchorFrm())->GetTxtNode()->GetIndex(); + if( _nObjIndex >= nOtherIndex ) + { + const SwFmtHoriOrient& rHori = _pFly->GetFmt()->GetHoriOrient(); + sal_Int16 eOtherRelOrient = rHori.GetRelationOrient(); + if( text::RelOrientation::CHAR != eOtherRelOrient ) + { + sal_Int16 eOtherHoriOrient = rHori.GetHoriOrient(); + _ToggleHoriOrientAndAlign( _bEvenPage && rHori.IsPosToggle(), + eOtherHoriOrient, + eOtherRelOrient ); + if ( eOtherHoriOrient == _eHoriOrient && + _Minor( _eRelOrient, eOtherRelOrient, text::HoriOrientation::LEFT == _eHoriOrient ) ) + { + bRetVal = true; + } + } + } + } + + return bRetVal; +} + +/** determine, if object has to draw aside another object + + the different alignments of the objects determines, if one has + to draw aside another one. Thus, the given alignment are checked + against each other, which one has to be drawn aside the other one. + depending on parameter _bLeft check is done for left or right + positioning. + method used by <_DrawAsideFly(..)> + + @author OD +*/ +bool SwAnchoredObjectPosition::_Minor( sal_Int16 _eRelOrient1, + sal_Int16 _eRelOrient2, + bool _bLeft ) const +{ + bool bRetVal; + + // draw aside order for left horizontal position + //! one array entry for each value in text::RelOrientation + static USHORT __READONLY_DATA aLeft[ 10 ] = + { 5, 6, 0, 1, 8, 4, 7, 2, 3, 9 }; + // draw aside order for right horizontal position + //! one array entry for each value in text::RelOrientation + static USHORT __READONLY_DATA aRight[ 10 ] = + { 5, 6, 0, 8, 1, 7, 4, 2, 3, 9 }; + + // decide depending on given order, which frame has to draw aside another frame + if( _bLeft ) + bRetVal = aLeft[ _eRelOrient1 ] >= aLeft[ _eRelOrient2 ]; + else + bRetVal = aRight[ _eRelOrient1 ] >= aRight[ _eRelOrient2 ]; + + return bRetVal; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx b/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx new file mode 100644 index 000000000000..be6723d5bafa --- /dev/null +++ b/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx @@ -0,0 +1,458 @@ +/* -*- 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 <ascharanchoredobjectposition.hxx> +#include <frame.hxx> +#include <txtfrm.hxx> +#include <flyfrms.hxx> +#include <svx/svdobj.hxx> +#include <dcontact.hxx> +#include <frmfmt.hxx> +#include <frmatr.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <fmtornt.hxx> + +#include <com/sun/star/text/HoriOrientation.hpp> + + +using namespace ::com::sun::star; +using namespace objectpositioning; + +/** constructor + + @author OD +*/ +SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition( + SdrObject& _rDrawObj, + const Point& _rProposedAnchorPos, + const AsCharFlags _nFlags, + const SwTwips _nLineAscent, + const SwTwips _nLineDescent, + const SwTwips _nLineAscentInclObjs, + const SwTwips _nLineDescentInclObjs ) + : SwAnchoredObjectPosition( _rDrawObj ), + mrProposedAnchorPos( _rProposedAnchorPos ), + mnFlags( _nFlags ), + mnLineAscent( _nLineAscent ), + mnLineDescent( _nLineDescent ), + mnLineAscentInclObjs( _nLineAscentInclObjs ), + mnLineDescentInclObjs( _nLineDescentInclObjs ), + maAnchorPos ( Point() ), + mnRelPos ( 0 ), + maObjBoundRect ( SwRect() ), + mnLineAlignment ( 0 ) +{} + +/** destructor + + @author OD +*/ +SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition() +{} + +/** method to cast <SwAnchoredObjectPosition::GetAnchorFrm()> to needed type + + @author OD +*/ +const SwTxtFrm& SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() const +{ + OSL_ENSURE( GetAnchorFrm().ISA(SwTxtFrm), + "SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() - wrong anchor frame type" ); + + return static_cast<const SwTxtFrm&>(GetAnchorFrm()); +} + +/** calculate position for object + + OD 30.07.2003 #110978# + members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and + <mnLineAlignment> are calculated. + calculated position is set at the given object. + + @author OD +*/ +void SwAsCharAnchoredObjectPosition::CalcPosition() +{ + const SwTxtFrm& rAnchorFrm = GetAnchorTxtFrm(); + // swap anchor frame, if swapped. Note: destructor takes care of the 'undo' + SwFrmSwapper aFrmSwapper( &rAnchorFrm, false ); + + SWRECTFN( ( &rAnchorFrm ) ) + + Point aAnchorPos( mrProposedAnchorPos ); + + const SwFrmFmt& rFrmFmt = GetFrmFmt(); + + SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + SwTwips nObjWidth = (aObjBoundRect.*fnRect->fnGetWidth)(); + + // determine spacing values considering layout-/text-direction + const SvxLRSpaceItem& rLRSpace = rFrmFmt.GetLRSpace(); + const SvxULSpaceItem& rULSpace = rFrmFmt.GetULSpace(); + SwTwips nLRSpaceLeft, nLRSpaceRight, nULSpaceUpper, nULSpaceLower; + { + if ( rAnchorFrm.IsVertical() ) + { + // Seems to be easier to do it all the horizontal way + // So, from now on think horizontal. + rAnchorFrm.SwitchVerticalToHorizontal( aObjBoundRect ); + rAnchorFrm.SwitchVerticalToHorizontal( aAnchorPos ); + + // convert the spacing values + nLRSpaceLeft = rULSpace.GetUpper(); + nLRSpaceRight = rULSpace.GetLower(); + nULSpaceUpper = rLRSpace.GetRight(); + nULSpaceLower = rLRSpace.GetLeft(); + } + else + { + if ( rAnchorFrm.IsRightToLeft() ) + { + nLRSpaceLeft = rLRSpace.GetRight(); + nLRSpaceRight = rLRSpace.GetLeft(); + } + else + { + nLRSpaceLeft = rLRSpace.GetLeft(); + nLRSpaceRight = rLRSpace.GetRight(); + } + + nULSpaceUpper = rULSpace.GetUpper(); + nULSpaceLower = rULSpace.GetLower(); + } + } + + // consider left and upper spacing by adjusting anchor position. + // left spacing is only considered, if requested. + if( mnFlags & AS_CHAR_ULSPACE ) + { + aAnchorPos.X() += nLRSpaceLeft; + } + aAnchorPos.Y() += nULSpaceUpper; + + // for drawing objects: consider difference between its bounding rectangle + // and its snapping rectangle by adjusting anchor position. + // left difference is only considered, if requested. + if( !IsObjFly() ) + { + SwRect aSnapRect = GetObject().GetSnapRect(); + if ( rAnchorFrm.IsVertical() ) + { + rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect ); + } + + if( mnFlags & AS_CHAR_ULSPACE ) + { + aAnchorPos.X() += aSnapRect.Left() - aObjBoundRect.Left(); + } + aAnchorPos.Y() += aSnapRect.Top() - aObjBoundRect.Top(); + } + + // enlarge bounding rectangle of object by its spacing. + aObjBoundRect.Left( aObjBoundRect.Left() - nLRSpaceLeft ); + aObjBoundRect.Width( aObjBoundRect.Width() + nLRSpaceRight ); + aObjBoundRect.Top( aObjBoundRect.Top() - nULSpaceUpper ); + aObjBoundRect.Height( aObjBoundRect.Height() + nULSpaceLower ); + + // calculate relative position to given base line. + const SwFmtVertOrient& rVert = rFrmFmt.GetVertOrient(); + const SwTwips nObjBoundHeight = ( mnFlags & AS_CHAR_ROTATE ) + ? aObjBoundRect.Width() + : aObjBoundRect.Height(); + const SwTwips nRelPos = _GetRelPosToBase( nObjBoundHeight, rVert ); + + // for initial positioning: + // adjust the proposed anchor position by difference between + // calculated relative position to base line and current maximal line ascent. + // Note: In the following line formatting the base line will be adjusted + // by the same difference. + if( mnFlags & AS_CHAR_INIT && nRelPos < 0 && mnLineAscentInclObjs < -nRelPos ) + { + if( mnFlags & AS_CHAR_ROTATE ) + aAnchorPos.X() -= mnLineAscentInclObjs + nRelPos; + else + aAnchorPos.Y() -= mnLineAscentInclObjs + nRelPos; + } + + // consider BIDI-multiportion by adjusting proposed anchor position + if( mnFlags & AS_CHAR_BIDI ) + aAnchorPos.X() -= aObjBoundRect.Width(); + + // calculate relative position considering rotation and inside rotation + // reverse direction. + Point aRelPos; + { + if( mnFlags & AS_CHAR_ROTATE ) + { + if( mnFlags & AS_CHAR_REVERSE ) + aRelPos.X() = -nRelPos - aObjBoundRect.Width(); + else + { + aRelPos.X() = nRelPos; + aRelPos.Y() = -aObjBoundRect.Height(); + } + } + else + aRelPos.Y() = nRelPos; + } + + if( !IsObjFly() ) + { + if( !( mnFlags & AS_CHAR_QUICK ) ) + { + // save calculated Y-position value for 'automatic' vertical positioning, + // in order to avoid a switch to 'manual' vertical positioning in + // <SwDrawContact::_Changed(..)>. + const sal_Int16 eVertOrient = rVert.GetVertOrient(); + if( rVert.GetPos() != nRelPos && eVertOrient != text::VertOrientation::NONE ) + { + SwFmtVertOrient aVert( rVert ); + aVert.SetPos( nRelPos ); + const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); + const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert ); + const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); + } + + // determine absolute anchor position considering layout directions. + // Note: Use copy of <aAnchorPos>, because it's needed for + // setting relative position. + Point aAbsAnchorPos( aAnchorPos ); + if ( rAnchorFrm.IsRightToLeft() ) + { + rAnchorFrm.SwitchLTRtoRTL( aAbsAnchorPos ); + aAbsAnchorPos.X() -= nObjWidth; + } + if ( rAnchorFrm.IsVertical() ) + rAnchorFrm.SwitchHorizontalToVertical( aAbsAnchorPos ); + + // set proposed anchor position at the drawing object. + // OD 2004-04-06 #i26791# - distinction between 'master' drawing + // object and 'virtual' drawing object no longer needed. + GetObject().SetAnchorPos( aAbsAnchorPos ); + + // move drawing object to set its correct relative position. + { + SwRect aSnapRect = GetObject().GetSnapRect(); + if ( rAnchorFrm.IsVertical() ) + rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect ); + + Point aDiff; + if ( rAnchorFrm.IsRightToLeft() ) + aDiff = aRelPos + aAbsAnchorPos - aSnapRect.TopLeft(); + else + aDiff = aRelPos + aAnchorPos - aSnapRect.TopLeft(); + + if ( rAnchorFrm.IsVertical() ) + aDiff = Point( -aDiff.Y(), aDiff.X() ); + + // OD 2004-04-06 #i26791# - distinction between 'master' drawing + // object and 'virtual' drawing object no longer needed. + GetObject().Move( Size( aDiff.X(), aDiff.Y() ) ); + } + } + + // switch horizontal, LTR anchor position to absolute values. + if ( rAnchorFrm.IsRightToLeft() ) + { + rAnchorFrm.SwitchLTRtoRTL( aAnchorPos ); + aAnchorPos.X() -= nObjWidth; + } + if ( rAnchorFrm.IsVertical() ) + rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos ); + + // --> OD 2005-03-09 #i44347# - keep last object rectangle at anchored object + OSL_ENSURE( GetAnchoredObj().ISA(SwAnchoredDrawObject), + "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." ); + SwAnchoredDrawObject& rAnchoredDrawObj = + static_cast<SwAnchoredDrawObject&>( GetAnchoredObj() ); + rAnchoredDrawObj.SetLastObjRect( rAnchoredDrawObj.GetObjRect().SVRect() ); + // <-- + } + else + { + // determine absolute anchor position and calculate corresponding + // relative position and its relative position attribute. + // Note: The relative position contains the spacing values. + Point aRelAttr; + if ( rAnchorFrm.IsRightToLeft() ) + { + rAnchorFrm.SwitchLTRtoRTL( aAnchorPos ); + aAnchorPos.X() -= nObjWidth; + } + if ( rAnchorFrm.IsVertical() ) + { + rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos ); + aRelAttr = Point( -nRelPos, 0 ); + aRelPos = Point( -aRelPos.Y(), aRelPos.X() ); + } + else + aRelAttr = Point( 0, nRelPos ); + + // OD 2004-03-23 #i26791# + OSL_ENSURE( GetAnchoredObj().ISA(SwFlyInCntFrm), + "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." ); + const SwFlyInCntFrm& rFlyInCntFrm = + static_cast<const SwFlyInCntFrm&>(GetAnchoredObj()); + if ( !(mnFlags & AS_CHAR_QUICK) && + ( aAnchorPos != rFlyInCntFrm.GetRefPoint() || + aRelAttr != rFlyInCntFrm.GetCurrRelPos() ) ) + { + // set new anchor position and relative position + SwFlyInCntFrm* pFlyInCntFrm = &(const_cast<SwFlyInCntFrm&>(rFlyInCntFrm)); + pFlyInCntFrm->SetRefPoint( aAnchorPos, aRelAttr, aRelPos ); + if( nObjWidth != (pFlyInCntFrm->Frm().*fnRect->fnGetWidth)() ) + { + // recalculate object bound rectangle, if object width has changed. + aObjBoundRect = GetAnchoredObj().GetObjRect(); + aObjBoundRect.Left( aObjBoundRect.Left() - rLRSpace.GetLeft() ); + aObjBoundRect.Width( aObjBoundRect.Width() + rLRSpace.GetRight() ); + aObjBoundRect.Top( aObjBoundRect.Top() - rULSpace.GetUpper() ); + aObjBoundRect.Height( aObjBoundRect.Height() + rULSpace.GetLower() ); + } + } + OSL_ENSURE( (rFlyInCntFrm.Frm().*fnRect->fnGetHeight)(), + "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" ); + } + + // keep calculated values + maAnchorPos = aAnchorPos; + mnRelPos = nRelPos; + maObjBoundRect = aObjBoundRect; +} + +/** determine the relative position to base line for object position type AS_CHAR + + OD 29.07.2003 #110978# + Note about values set at member <mnLineAlignment> - + value gives feedback for the line formatting. + 0 - no feedback; 1|2|3 - proposed formatting of characters + at top|at center|at bottom of line. + + @author OD +*/ +SwTwips SwAsCharAnchoredObjectPosition::_GetRelPosToBase( + const SwTwips _nObjBoundHeight, + const SwFmtVertOrient& _rVert ) +{ + SwTwips nRelPosToBase = 0; + + mnLineAlignment = 0; + + const sal_Int16 eVertOrient = _rVert.GetVertOrient(); + + if ( eVertOrient == text::VertOrientation::NONE ) + nRelPosToBase = _rVert.GetPos(); + else + { + if ( eVertOrient == text::VertOrientation::CENTER ) + nRelPosToBase -= _nObjBoundHeight / 2; + else if ( eVertOrient == text::VertOrientation::TOP ) + nRelPosToBase -= _nObjBoundHeight; + else if ( eVertOrient == text::VertOrientation::BOTTOM ) + nRelPosToBase = 0; + else if ( eVertOrient == text::VertOrientation::CHAR_CENTER ) + nRelPosToBase -= ( _nObjBoundHeight + mnLineAscent - mnLineDescent ) / 2; + else if ( eVertOrient == text::VertOrientation::CHAR_TOP ) + nRelPosToBase -= mnLineAscent; + else if ( eVertOrient == text::VertOrientation::CHAR_BOTTOM ) + nRelPosToBase += mnLineDescent - _nObjBoundHeight; + else + { + if( _nObjBoundHeight >= mnLineAscentInclObjs + mnLineDescentInclObjs ) + { + // object is at least as high as the line. Thus, no more is + // positioning necessary. Also, the max. ascent isn't changed. + nRelPosToBase -= mnLineAscentInclObjs; + if ( eVertOrient == text::VertOrientation::LINE_CENTER ) + mnLineAlignment = 2; + else if ( eVertOrient == text::VertOrientation::LINE_TOP ) + mnLineAlignment = 1; + else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM ) + mnLineAlignment = 3; + } + else if ( eVertOrient == text::VertOrientation::LINE_CENTER ) + { + nRelPosToBase -= ( _nObjBoundHeight + mnLineAscentInclObjs - mnLineDescentInclObjs ) / 2; + mnLineAlignment = 2; + } + else if ( eVertOrient == text::VertOrientation::LINE_TOP ) + { + nRelPosToBase -= mnLineAscentInclObjs; + mnLineAlignment = 1; + } + else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM ) + { + nRelPosToBase += mnLineDescentInclObjs - _nObjBoundHeight; + mnLineAlignment = 3; + } + } + } + + return nRelPosToBase; +} + +/** calculated anchored position for object position + + @author OD +*/ +Point SwAsCharAnchoredObjectPosition::GetAnchorPos() const +{ + return maAnchorPos; +} + +/** calculated relative position to base line for object position + + @author OD +*/ +SwTwips SwAsCharAnchoredObjectPosition::GetRelPosY() const +{ + return mnRelPos; +} + +/** determined object rectangle including spacing for object + + @author OD +*/ +SwRect SwAsCharAnchoredObjectPosition::GetObjBoundRectInclSpacing() const +{ + return maObjBoundRect; +} + +/** determined line alignment + + @author OD +*/ +sal_uInt8 SwAsCharAnchoredObjectPosition::GetLineAlignment() const +{ + return mnLineAlignment; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/environmentofanchoredobject.cxx b/sw/source/core/objectpositioning/environmentofanchoredobject.cxx new file mode 100644 index 000000000000..e9ad9ce59415 --- /dev/null +++ b/sw/source/core/objectpositioning/environmentofanchoredobject.cxx @@ -0,0 +1,124 @@ +/* -*- 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" +#ifndef _ENVIRONMENTOFANCHOREDOBJECT +#include <environmentofanchoredobject.hxx> +#endif +#include <frame.hxx> +#include <pagefrm.hxx> +#include <flyfrm.hxx> + +using namespace objectpositioning; + +SwEnvironmentOfAnchoredObject::SwEnvironmentOfAnchoredObject( + const bool _bFollowTextFlow ) + : mbFollowTextFlow( _bFollowTextFlow ) +{} + +SwEnvironmentOfAnchoredObject::~SwEnvironmentOfAnchoredObject() +{} + +/** determine environment layout frame for possible horizontal object positions + + OD 05.11.2003 + + @author OD +*/ +const SwLayoutFrm& SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrm( + const SwFrm& _rHoriOrientFrm ) const +{ + const SwFrm* pHoriEnvironmentLayFrm = &_rHoriOrientFrm; + + if ( !mbFollowTextFlow ) + { + // --> OD 2005-01-20 #118546# - no exception any more for page alignment. + // the page frame determines the horizontal layout environment. + pHoriEnvironmentLayFrm = _rHoriOrientFrm.FindPageFrm(); + // <-- + } + else + { + while ( !pHoriEnvironmentLayFrm->IsCellFrm() && + !pHoriEnvironmentLayFrm->IsFlyFrm() && + !pHoriEnvironmentLayFrm->IsPageFrm() ) + { + pHoriEnvironmentLayFrm = pHoriEnvironmentLayFrm->GetUpper(); + OSL_ENSURE( pHoriEnvironmentLayFrm, + "SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrm(..) - no page|fly|cell frame found" ); + } + } + + OSL_ENSURE( pHoriEnvironmentLayFrm->ISA(SwLayoutFrm), + "SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrm(..) - found frame isn't a layout frame" ); + + return static_cast<const SwLayoutFrm&>(*pHoriEnvironmentLayFrm); +} + +/** determine environment layout frame for possible vertical object positions + + OD 05.11.2003 + + @author OD +*/ +const SwLayoutFrm& SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrm( + const SwFrm& _rVertOrientFrm ) const +{ + const SwFrm* pVertEnvironmentLayFrm = &_rVertOrientFrm; + + if ( !mbFollowTextFlow ) + { + // --> OD 2005-01-20 #118546# - no exception any more for page alignment. + // the page frame determines the vertical layout environment. + pVertEnvironmentLayFrm = _rVertOrientFrm.FindPageFrm(); + // <-- + } + else + { + while ( !pVertEnvironmentLayFrm->IsCellFrm() && + !pVertEnvironmentLayFrm->IsFlyFrm() && + !pVertEnvironmentLayFrm->IsHeaderFrm() && + !pVertEnvironmentLayFrm->IsFooterFrm() && + !pVertEnvironmentLayFrm->IsFtnFrm() && + !pVertEnvironmentLayFrm->IsPageBodyFrm() && + !pVertEnvironmentLayFrm->IsPageFrm() ) + { + pVertEnvironmentLayFrm = pVertEnvironmentLayFrm->GetUpper(); + OSL_ENSURE( pVertEnvironmentLayFrm, + "SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrm(..) - proposed frame not found" ); + } + } + + OSL_ENSURE( pVertEnvironmentLayFrm->ISA(SwLayoutFrm), + "SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrm(..) - found frame isn't a layout frame" ); + + return static_cast<const SwLayoutFrm&>(*pVertEnvironmentLayFrm); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/makefile.mk b/sw/source/core/objectpositioning/makefile.mk new file mode 100644 index 000000000000..4192414d9b73 --- /dev/null +++ b/sw/source/core/objectpositioning/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sw +TARGET=objectpositioning + +# --- Settings ----------------------------------------------------- + +.INCLUDE : $(PRJ)$/inc$/swpre.mk +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/inc$/sw.mk + +.IF "$(mydebug)" != "" +CDEFS+=-Dmydebug +.ENDIF + +.IF "$(madebug)" != "" +CDEFS+=-DDEBUG +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/anchoredobjectposition.obj \ + $(SLO)$/ascharanchoredobjectposition.obj \ + $(SLO)$/tolayoutanchoredobjectposition.obj \ + $(SLO)$/tocntntanchoredobjectposition.obj \ + $(SLO)$/environmentofanchoredobject.obj + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx new file mode 100644 index 000000000000..b1a96bf97078 --- /dev/null +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -0,0 +1,1075 @@ +/* -*- 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 <tocntntanchoredobjectposition.hxx> +#include <anchoredobject.hxx> +#include <frame.hxx> +#include <txtfrm.hxx> +#include <pagefrm.hxx> +#include <sectfrm.hxx> +// --> OD 2004-10-15 #i26945# +#include <tabfrm.hxx> +// <-- +#include <frmfmt.hxx> +#include <IDocumentSettingAccess.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <svx/svdobj.hxx> +#include <pam.hxx> +#include <environmentofanchoredobject.hxx> +#include <frmtool.hxx> +#include <ndtxt.hxx> +#include <dflyobj.hxx> + +using namespace objectpositioning; +using namespace ::com::sun::star; + + +SwToCntntAnchoredObjectPosition::SwToCntntAnchoredObjectPosition( SdrObject& _rDrawObj ) + : SwAnchoredObjectPosition ( _rDrawObj ), + mpVertPosOrientFrm( 0 ), + // --> OD 2004-06-17 #i26791# + maOffsetToFrmAnchorPos( Point() ), + mbAnchorToChar ( false ), + mpToCharOrientFrm( 0 ), + mpToCharRect( 0 ), + // OD 12.11.2003 #i22341# + mnToCharTopOfLine( 0 ) +{} + +SwToCntntAnchoredObjectPosition::~SwToCntntAnchoredObjectPosition() +{} + +bool SwToCntntAnchoredObjectPosition::IsAnchoredToChar() const +{ + return mbAnchorToChar; +} + +const SwFrm* SwToCntntAnchoredObjectPosition::ToCharOrientFrm() const +{ + return mpToCharOrientFrm; +} + +const SwRect* SwToCntntAnchoredObjectPosition::ToCharRect() const +{ + return mpToCharRect; +} + +// OD 12.11.2003 #i22341# +SwTwips SwToCntntAnchoredObjectPosition::ToCharTopOfLine() const +{ + return mnToCharTopOfLine; +} + +SwTxtFrm& SwToCntntAnchoredObjectPosition::GetAnchorTxtFrm() const +{ + OSL_ENSURE( GetAnchorFrm().ISA(SwTxtFrm), + "SwToCntntAnchoredObjectPosition::GetAnchorTxtFrm() - wrong anchor frame type" ); + + return static_cast<SwTxtFrm&>(GetAnchorFrm()); +} + +// --> OD 2004-07-20 #i23512# +bool lcl_DoesVertPosFits( const SwTwips _nRelPosY, + const SwTwips _nAvail, + const SwLayoutFrm* _pUpperOfOrientFrm, + const bool _bBrowse, + const bool _bGrowInTable, + SwLayoutFrm*& _orpLayoutFrmToGrow ) +{ + bool bVertPosFits = false; + + if ( _nRelPosY <= _nAvail ) + { + bVertPosFits = true; + } + else if ( _bBrowse ) + { + if ( _pUpperOfOrientFrm->IsInSct() ) + { + SwSectionFrm* pSctFrm = + const_cast<SwSectionFrm*>(_pUpperOfOrientFrm->FindSctFrm()); + bVertPosFits = pSctFrm->GetUpper()->Grow( _nRelPosY - _nAvail, TRUE ) > 0; + // Note: do not provide a layout frame for a grow. + } + else + { + bVertPosFits = const_cast<SwLayoutFrm*>(_pUpperOfOrientFrm)-> + Grow( _nRelPosY - _nAvail, TRUE ) > 0; + if ( bVertPosFits ) + _orpLayoutFrmToGrow = const_cast<SwLayoutFrm*>(_pUpperOfOrientFrm); + } + } + else if ( _pUpperOfOrientFrm->IsInTab() && _bGrowInTable ) + { + // --> OD 2005-06-08 #i45085# - check, if upper frame would grow the + // excepted amount of twips. + const SwTwips nTwipsGrown = const_cast<SwLayoutFrm*>(_pUpperOfOrientFrm)-> + Grow( _nRelPosY - _nAvail, TRUE ) > 0; + bVertPosFits = ( nTwipsGrown == ( _nRelPosY - _nAvail ) ); + // <-- + if ( bVertPosFits ) + _orpLayoutFrmToGrow = const_cast<SwLayoutFrm*>(_pUpperOfOrientFrm); + } + + return bVertPosFits; +} +// <-- + +void SwToCntntAnchoredObjectPosition::CalcPosition() +{ + // get format of object + const SwFrmFmt& rFrmFmt = GetFrmFmt(); + + // declare and set <pFooter> to footer frame, if object is anchored + // at a frame belonging to the footer. + const SwFrm* pFooter = GetAnchorFrm().FindFooterOrHeader(); + if ( pFooter && !pFooter->IsFooterFrm() ) + pFooter = NULL; + + // declare and set <bBrowse> to true, if document is in browser mode and + // object is anchored at the body, but not at frame belonging to a table. + const bool bBrowse = GetAnchorFrm().IsInDocBody() && + !GetAnchorFrm().IsInTab() + ? rFrmFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) + : false; + + // determine left/right and its upper/lower spacing. + const SvxLRSpaceItem &rLR = rFrmFmt.GetLRSpace(); + const SvxULSpaceItem &rUL = rFrmFmt.GetULSpace(); + + // determine, if object has no surrounding. + const SwFmtSurround& rSurround = rFrmFmt.GetSurround(); + const bool bNoSurround = rSurround.GetSurround() == SURROUND_NONE; + const bool bWrapThrough = rSurround.GetSurround() == SURROUND_THROUGHT; + + // OD 29.10.2003 #110978# - new class <SwEnvironmentOfAnchoredObject> + SwEnvironmentOfAnchoredObject aEnvOfObj( DoesObjFollowsTextFlow() ); + + // OD 30.09.2003 #i18732# - grow only, if object has to follow the text flow + const bool bGrow = DoesObjFollowsTextFlow() && + ( !GetAnchorFrm().IsInTab() || + !rFrmFmt.GetFrmSize().GetHeightPercent() ); + + // get text frame the object is anchored at + const SwTxtFrm& rAnchorTxtFrm = GetAnchorTxtFrm(); + SWRECTFN( (&rAnchorTxtFrm) ) + + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + + // local variable keeping the calculated relative position; initialized with + // current relative position. + // OD 2004-03-24 #i26791# - use new object instance of <SwAnchoredObject> + Point aRelPos( GetAnchoredObj().GetCurrRelPos() ); + + SwTwips nRelDiff = 0; + + bool bMoveable = rAnchorTxtFrm.IsMoveable(); + + // determine frame the object position has to be oriented at. + const SwTxtFrm* pOrientFrm = &rAnchorTxtFrm; + const SwTxtFrm* pAnchorFrmForVertPos = &rAnchorTxtFrm; + { + // if object is at-character anchored, determine character-rectangle + // and frame, position has to be oriented at. + mbAnchorToChar = (FLY_AT_CHAR == rFrmFmt.GetAnchor().GetAnchorId()); + if ( mbAnchorToChar ) + { + const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor(); + // OD 2004-03-24 #i26791# - use new object instance of <SwAnchoredObject> + // OD 2005-01-12 - Due to table break algorithm the character + // rectangle can have no height. Thus, check also the width + if ( ( !GetAnchoredObj().GetLastCharRect().Height() && + !GetAnchoredObj().GetLastCharRect().Width() ) || + !GetAnchoredObj().GetLastTopOfLine() ) + { + // --> OD 2010-07-02 #i111886# + // Check existence of paragraph portion information in order + // to avoid formatting which could cause deletion of follow frames. + GetAnchoredObj().CheckCharRectAndTopOfLine(); + // <-- + // OD 2005-01-12 - Due to table break algorithm the character + // rectangle can have no height. Thus, check also the width + if ( ( !GetAnchoredObj().GetLastCharRect().Height() && + !GetAnchoredObj().GetLastCharRect().Width() ) || + !GetAnchoredObj().GetLastTopOfLine() ) + { + // --> OD 2005-01-12 - get default for <mpVertPosOrientFrm>, + // if it's not set. + if ( !mpVertPosOrientFrm ) + { + mpVertPosOrientFrm = rAnchorTxtFrm.GetUpper(); + } + // <-- + return; + } + } + mpToCharRect = &(GetAnchoredObj().GetLastCharRect()); + // OD 12.11.2003 #i22341# - get top of line, in which the anchor + // character is. + mnToCharTopOfLine = GetAnchoredObj().GetLastTopOfLine(); + pOrientFrm = &(const_cast<SwTxtFrm&>(rAnchorTxtFrm).GetFrmAtOfst( + rAnch.GetCntntAnchor()->nContent.GetIndex() ) ); + mpToCharOrientFrm = pOrientFrm; + } + } + SWREFRESHFN( pOrientFrm ) + + // determine vertical position + { + + // determine vertical positioning and alignment attributes + SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() ); + + // OD 22.09.2003 #i18732# - determine layout frame for vertical + // positions aligned to 'page areas'. + const SwLayoutFrm& rPageAlignLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pOrientFrm ); + + if ( aVert.GetVertOrient() != text::VertOrientation::NONE ) + { + // OD 22.09.2003 #i18732# - adjustments for follow text flow or not + // AND vertical alignment at 'page areas'. + SwTwips nAlignAreaHeight; + SwTwips nAlignAreaOffset; + _GetVertAlignmentValues( *pOrientFrm, rPageAlignLayFrm, + aVert.GetRelationOrient(), + nAlignAreaHeight, nAlignAreaOffset ); + + // determine relative vertical position + SwTwips nRelPosY = nAlignAreaOffset; + SwTwips nObjHeight = (aObjBoundRect.*fnRect->fnGetHeight)(); + SwTwips nUpperSpace = bVert ? rLR.GetRight() : rUL.GetUpper(); + SwTwips nLowerSpace = bVert ? rLR.GetLeft() : rUL.GetLower(); + switch ( aVert.GetVertOrient() ) + { + case text::VertOrientation::CHAR_BOTTOM: + { + if ( mbAnchorToChar ) + { + // bottom (to character anchored) + nRelPosY += nAlignAreaHeight + nUpperSpace; + if ( bVert ) + nRelPosY += nObjHeight; + break; + } + } + // no break here + case text::VertOrientation::TOP: + { + // OD 12.11.2003 #i22341# - special case for vertical + // alignment at top of line + if ( mbAnchorToChar && + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + nRelPosY -= (nObjHeight + nLowerSpace); + } + else + { + nRelPosY += nUpperSpace; + } + } + break; + // OD 14.11.2003 #i22341# + case text::VertOrientation::LINE_TOP: + { + if ( mbAnchorToChar && + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + nRelPosY -= (nObjHeight + nLowerSpace); + } + else + { + OSL_ENSURE( false, + "<SwToCntntAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." ); + } + } + break; + case text::VertOrientation::CENTER: + { + nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2); + } + break; + // OD 14.11.2003 #i22341# + case text::VertOrientation::LINE_CENTER: + { + if ( mbAnchorToChar && + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2); + } + else + { + OSL_ENSURE( false, + "<SwToCntntAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." ); + } + } + break; + case text::VertOrientation::BOTTOM: + { + if ( ( aVert.GetRelationOrient() == text::RelOrientation::FRAME || + aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) && + bNoSurround ) + { + // bottom (aligned to 'paragraph areas') + nRelPosY += nAlignAreaHeight + nUpperSpace; + } + else + { + // OD 12.11.2003 #i22341# - special case for vertical + // alignment at top of line + if ( mbAnchorToChar && + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + nRelPosY += nUpperSpace; + } + else + { + nRelPosY += nAlignAreaHeight - + ( nObjHeight + nLowerSpace ); + } + } + } + break; + // OD 14.11.2003 #i22341# + case text::VertOrientation::LINE_BOTTOM: + { + if ( mbAnchorToChar && + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) + { + nRelPosY += nUpperSpace; + } + else + { + OSL_ENSURE( false, + "<SwToCntntAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." ); + } + } + break; + default: + break; + } + + // adjust relative position by distance between anchor frame and + // the frame, the object is oriented at. + // OD 2004-05-21 #i28701# - correction: adjust relative position, + // only if the floating screen object has to follow the text flow. + if ( DoesObjFollowsTextFlow() && pOrientFrm != &rAnchorTxtFrm ) + { + // OD 2004-03-11 #i11860# - use new method <_GetTopForObjPos> + // to get top of frame for object positioning. + const SwTwips nTopOfOrient = _GetTopForObjPos( *pOrientFrm, fnRect, bVert ); + nRelPosY += (*fnRect->fnYDiff)( nTopOfOrient, + _GetTopForObjPos( rAnchorTxtFrm, fnRect, bVert ) ); + } + + // --> OD 2005-02-07 #i42124# - capture object inside vertical + // layout environment. + { + const SwTwips nTopOfAnch = + _GetTopForObjPos( *pOrientFrm, fnRect, bVert ); + const SwLayoutFrm& rVertEnvironLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( + *(pOrientFrm->GetUpper()) ); + const bool bCheckBottom = !DoesObjFollowsTextFlow(); + nRelPosY = _AdjustVertRelPos( nTopOfAnch, bVert, + rVertEnvironLayFrm, nRelPosY, + DoesObjFollowsTextFlow(), + bCheckBottom ); + } + // <-- + // keep calculated relative vertical position - needed for filters + // (including the xml-filter) + { + // determine position + SwTwips nAttrRelPosY = nRelPosY - nAlignAreaOffset; + // set + if ( nAttrRelPosY != aVert.GetPos() ) + { + aVert.SetPos( nAttrRelPosY ); + const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); + const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert ); + const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); + } + } + + // determine absolute 'vertical' position, depending on layout-direction + // --> OD 2004-06-17 #i26791# - determine offset to 'vertical' frame + // anchor position, depending on layout-direction + if ( bVert ) + { + aRelPos.X() = nRelPosY; + maOffsetToFrmAnchorPos.X() = nAlignAreaOffset; + } + else + { + aRelPos.Y() = nRelPosY; + maOffsetToFrmAnchorPos.Y() = nAlignAreaOffset; + } + } + + // OD 29.10.2003 #110978# - determine upper of frame vertical position + // is oriented at. + // OD 2004-05-21 #i28701# - determine 'virtual' anchor frame. + // This frame is used in the following instead of the 'real' anchor + // frame <rAnchorTxtFrm> for the 'vertical' position in all cases. + const SwLayoutFrm* pUpperOfOrientFrm = 0L; + { + // OD 2004-05-21 #i28701# - As long as the anchor frame is on the + // same page as <pOrientFrm> and the vertical position isn't aligned + // automatic at the anchor character or the top of the line of the + // anchor character, the anchor frame determines the vertical position. + if ( &rAnchorTxtFrm == pOrientFrm || + ( rAnchorTxtFrm.FindPageFrm() == pOrientFrm->FindPageFrm() && + aVert.GetVertOrient() == text::VertOrientation::NONE && + aVert.GetRelationOrient() != text::RelOrientation::CHAR && + aVert.GetRelationOrient() != text::RelOrientation::TEXT_LINE ) ) + { + pUpperOfOrientFrm = rAnchorTxtFrm.GetUpper(); + pAnchorFrmForVertPos = &rAnchorTxtFrm; + } + else + { + pUpperOfOrientFrm = pOrientFrm->GetUpper(); + pAnchorFrmForVertPos = pOrientFrm; + } + } + + // ignore one-column sections. + // --> OD 2004-07-20 #i23512# - correction: also ignore one-columned + // sections with footnotes/endnotes + if ( pUpperOfOrientFrm->IsInSct() ) + { + const SwSectionFrm* pSctFrm = pUpperOfOrientFrm->FindSctFrm(); + const bool bIgnoreSection = pUpperOfOrientFrm->IsSctFrm() || + ( pSctFrm->Lower()->IsColumnFrm() && + !pSctFrm->Lower()->GetNext() ); + if ( bIgnoreSection ) + pUpperOfOrientFrm = pSctFrm->GetUpper(); + } + + if ( aVert.GetVertOrient() == text::VertOrientation::NONE ) + { + // local variable <nRelPosY> for calculation of relative vertical + // distance to anchor. + SwTwips nRelPosY = 0; + // --> OD 2004-06-17 #i26791# - local variable <nVertOffsetToFrmAnchorPos> + // for determination of the 'vertical' offset to the frame anchor + // position + SwTwips nVertOffsetToFrmAnchorPos( 0L ); + // OD 12.11.2003 #i22341# - add special case for vertical alignment + // at top of line. + if ( mbAnchorToChar && + ( aVert.GetRelationOrient() == text::RelOrientation::CHAR || + aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) ) + { + // OD 2004-03-11 #i11860# - use new method <_GetTopForObjPos> + // to get top of frame for object positioning. + SwTwips nTopOfOrient = _GetTopForObjPos( *pOrientFrm, fnRect, bVert ); + if ( aVert.GetRelationOrient() == text::RelOrientation::CHAR ) + { + nVertOffsetToFrmAnchorPos = (*fnRect->fnYDiff)( + (ToCharRect()->*fnRect->fnGetBottom)(), + nTopOfOrient ); + } + else + { + nVertOffsetToFrmAnchorPos = (*fnRect->fnYDiff)( ToCharTopOfLine(), + nTopOfOrient ); + } + nRelPosY = nVertOffsetToFrmAnchorPos - aVert.GetPos(); + } + else + { + // OD 2004-05-21 #i28701# - correction: use <pAnchorFrmForVertPos> + // instead of <pOrientFrm> and do not adjust relative position + // to get correct vertical position. + nVertOffsetToFrmAnchorPos = 0L; + // OD 2004-03-11 #i11860# - use new method <_GetTopForObjPos> + // to get top of frame for object positioning. + const SwTwips nTopOfOrient = + _GetTopForObjPos( *pAnchorFrmForVertPos, fnRect, bVert ); + // OD 02.10.2002 #102646# - increase <nRelPosY> by margin height, + // if position is vertical aligned to "paragraph text area" + if ( aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) + { + // OD 2004-03-11 #i11860# - consider upper space amount + // of previous frame + SwTwips nTopMargin = (pAnchorFrmForVertPos->*fnRect->fnGetTopMargin)(); + if ( pAnchorFrmForVertPos->IsTxtFrm() ) + { + nTopMargin -= static_cast<const SwTxtFrm*>(pAnchorFrmForVertPos)-> + GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + } + nVertOffsetToFrmAnchorPos += nTopMargin; + } + // OD 22.09.2003 #i18732# - adjust <nRelPosY> by difference + // between 'page area' and 'anchor' frame, if position is + // vertical aligned to 'page areas' + else if ( aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ) + { + nVertOffsetToFrmAnchorPos += (*fnRect->fnYDiff)( + (rPageAlignLayFrm.Frm().*fnRect->fnGetTop)(), + nTopOfOrient ); + } + else if ( aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) + { + SwRect aPgPrtRect( rPageAlignLayFrm.Frm() ); + if ( rPageAlignLayFrm.IsPageFrm() ) + { + aPgPrtRect = + static_cast<const SwPageFrm&>(rPageAlignLayFrm).PrtWithoutHeaderAndFooter(); + } + nVertOffsetToFrmAnchorPos += (*fnRect->fnYDiff)( + (aPgPrtRect.*fnRect->fnGetTop)(), + nTopOfOrient ); + } + nRelPosY = nVertOffsetToFrmAnchorPos + aVert.GetPos(); + } + + // <pUpperOfOrientFrm>: layout frame, at which the position has to + // is oriented at + // <nRelPosY>: rest of the relative distance in the current + // layout frame + // <nAvail>: space, which is available in the current + // layout frame + + // --> OD 2004-06-17 #i26791# - determine offset to 'vertical' + // frame anchor position, depending on layout-direction + if ( bVert ) + maOffsetToFrmAnchorPos.X() = nVertOffsetToFrmAnchorPos; + else + maOffsetToFrmAnchorPos.Y() = nVertOffsetToFrmAnchorPos; + // <-- + // OD 2004-03-11 #i11860# - use new method <_GetTopForObjPos> + // to get top of frame for object positioning. + const SwTwips nTopOfAnch = _GetTopForObjPos( *pAnchorFrmForVertPos, fnRect, bVert ); + if( nRelPosY <= 0 ) + { + // OD 08.09.2003 #110354# - allow negative position, but keep it + // inside environment layout frame. + const SwLayoutFrm& rVertEnvironLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pUpperOfOrientFrm ); + // --> OD 2004-07-22 #i31805# - do not check, if bottom of + // anchored object would fit into environment layout frame, if + // anchored object has to follow the text flow. + const bool bCheckBottom = !DoesObjFollowsTextFlow(); + nRelPosY = _AdjustVertRelPos( nTopOfAnch, bVert, + rVertEnvironLayFrm, nRelPosY, + DoesObjFollowsTextFlow(), + bCheckBottom ); + // <-- + if ( bVert ) + aRelPos.X() = nRelPosY; + else + aRelPos.Y() = nRelPosY; + } + else + { + SWREFRESHFN( pAnchorFrmForVertPos ) + SwTwips nAvail = + (*fnRect->fnYDiff)( (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)(), + nTopOfAnch ); + const bool bInFtn = pAnchorFrmForVertPos->IsInFtn(); + while ( nRelPosY ) + { + // --> OD 2004-07-20 #i23512# - correction: + // consider section frame for grow in online layout. + // use new local method <lcl_DoesVertPosFits(..)> + SwLayoutFrm* pLayoutFrmToGrow = 0L; + const bool bDoesVertPosFits = lcl_DoesVertPosFits( + nRelPosY, nAvail, pUpperOfOrientFrm, bBrowse, + bGrow, pLayoutFrmToGrow ); + + if ( bDoesVertPosFits ) + { + SwTwips nTmpRelPosY = + (*fnRect->fnYDiff)( (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)(), + nTopOfAnch ) - + nAvail + nRelPosY; + // --> OD 2004-07-06 #i28701# - adjust calculated + // relative vertical position to object's environment. + const SwFrm& rVertEnvironLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pUpperOfOrientFrm ); + // --> OD 2004-08-20 - do not check, if bottom of + // anchored object would fit into environment layout + // frame, if anchored object has to follow the text flow. + const bool bCheckBottom = !DoesObjFollowsTextFlow(); + nTmpRelPosY = _AdjustVertRelPos( nTopOfAnch, bVert, + rVertEnvironLayFrm, + nTmpRelPosY, + DoesObjFollowsTextFlow(), + bCheckBottom ); + // <-- + if ( bVert ) + aRelPos.X() = nTmpRelPosY; + else + aRelPos.Y() = nTmpRelPosY; + + // --> OD 2004-07-20 #i23512# - use local variable + // <pLayoutFrmToGrow> provided by new method + // <lcl_DoesVertPosFits(..)>. + if ( pLayoutFrmToGrow ) + { + pLayoutFrmToGrow->Grow( nRelPosY - nAvail ); + } + // <-- + nRelPosY = 0; + } + else + { + // --> OD 2004-10-04 #i26495# - floating screen objects, + // which are anchored inside a table, doesn't follow + // the text flow. + if ( DoesObjFollowsTextFlow() && + !( aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME || + aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) && + !GetAnchorFrm().IsInTab() ) + // <-- + { + if ( bMoveable ) + { + // follow the text flow + nRelPosY -= nAvail; + MakePageType eMakePage = bInFtn ? MAKEPAGE_NONE + : MAKEPAGE_APPEND; + const bool bInSct = pUpperOfOrientFrm->IsInSct(); + if( bInSct ) + eMakePage = MAKEPAGE_NOSECTION; + + const SwLayoutFrm* pTmp = + pUpperOfOrientFrm->GetLeaf( eMakePage, TRUE, &rAnchorTxtFrm ); + if ( pTmp && + ( !bInSct || + pUpperOfOrientFrm->FindSctFrm()->IsAnFollow( pTmp->FindSctFrm() ) ) ) + { + pUpperOfOrientFrm = pTmp; + bMoveable = rAnchorTxtFrm.IsMoveable( (SwLayoutFrm*)pUpperOfOrientFrm ); + SWREFRESHFN( pUpperOfOrientFrm ) + nAvail = (pUpperOfOrientFrm->Prt().*fnRect->fnGetHeight)(); + } + else + { + // if there isn't enough space in the (colmuned) + // section, leave it and set available space <nAvail> + // to the space below the section. + // if the new available space isn't also enough, + // new pages can be created. + if( bInSct ) + { + const SwFrm* pSct = pUpperOfOrientFrm->FindSctFrm(); + pUpperOfOrientFrm = pSct->GetUpper(); + nAvail = (*fnRect->fnYDiff)( + (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)(), + (pSct->*fnRect->fnGetPrtBottom)() ); + } + else + { +#if OSL_DEBUG_LEVEL > 1 + OSL_ENSURE( false, "<SwToCntntAnchoredObjectPosition::CalcPosition()> - code under investigation by OD, please inform OD about this assertion!" ); +#endif + nRelDiff = nRelPosY; + nRelPosY = 0; + } + } + } + else + { + nRelPosY = 0; + } + } + else + { + // OD 06.10.2003 #i18732# - do not follow text flow respectively + // align at 'page areas', but stay inside given environment + const SwFrm& rVertEnvironLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pUpperOfOrientFrm ); + nRelPosY = _AdjustVertRelPos( nTopOfAnch, bVert, + rVertEnvironLayFrm, + nRelPosY, + DoesObjFollowsTextFlow() ); + if( bVert ) + aRelPos.X() = nRelPosY; + else + aRelPos.Y() = nRelPosY; + nRelPosY = 0; + } + } + } // end of <while ( nRelPosY )> + } // end of else <nRelPosY <= 0> + } // end of <aVert.GetVertOrient() == text::VertOrientation::NONE> + + //Damit das Teil ggf. auf die richtige Seite gestellt und in die + //PrtArea des LayLeaf gezogen werden kann, muss hier seine + //absolute Position berechnet werden. + const SwTwips nTopOfAnch = _GetTopForObjPos( *pAnchorFrmForVertPos, fnRect, bVert ); + if( bVert ) + { + GetAnchoredObj().SetObjLeft( nTopOfAnch - + ( aRelPos.X() - nRelDiff ) - + aObjBoundRect.Width() ); + } + else + { + GetAnchoredObj().SetObjTop( nTopOfAnch + + ( aRelPos.Y() - nRelDiff ) ); + } + + // grow environment under certain conditions + // ignore one-column sections. + // --> OD 2004-07-20 #i23512# - correction: also ignore one-columned + // sections with footnotes/endnotes + if ( pUpperOfOrientFrm->IsInSct() ) + { + const SwSectionFrm* pSctFrm = pUpperOfOrientFrm->FindSctFrm(); + const bool bIgnoreSection = pUpperOfOrientFrm->IsSctFrm() || + ( pSctFrm->Lower()->IsColumnFrm() && + !pSctFrm->Lower()->GetNext() ); + if ( bIgnoreSection ) + pUpperOfOrientFrm = pSctFrm->GetUpper(); + } + SwTwips nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)() ); + if( nDist < 0 ) + { + // --> OD 2004-07-20 #i23512# - correction: + // consider section frame for grow in online layout and + // consider page alignment for grow in table. + SwLayoutFrm* pLayoutFrmToGrow = 0L; + if ( bBrowse && rAnchorTxtFrm.IsMoveable() ) + { + if ( pUpperOfOrientFrm->IsInSct() ) + { + pLayoutFrmToGrow = const_cast<SwLayoutFrm*>( + pUpperOfOrientFrm->FindSctFrm()->GetUpper()); + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pLayoutFrmToGrow->*fnRect->fnGetPrtBottom)() ); + if ( nDist >= 0 ) + { + pLayoutFrmToGrow = 0L; + } + } + else + { + pLayoutFrmToGrow = + const_cast<SwLayoutFrm*>(pUpperOfOrientFrm); + } + } + else if ( rAnchorTxtFrm.IsInTab() && bGrow ) + { + pLayoutFrmToGrow = const_cast<SwLayoutFrm*>(pUpperOfOrientFrm); + } + if ( pLayoutFrmToGrow ) + { + pLayoutFrmToGrow->Grow( -nDist ); + } + // <-- + } + + if ( DoesObjFollowsTextFlow() && + !( aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME || + aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) ) + { + + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)() ); + // --> OD 2004-10-04 #i26945# - floating screen objects, which are + // anchored inside a table, doesn't follow the text flow. But, they + // have to stay inside its layout environment. + if ( nDist < 0 && pOrientFrm->IsInTab() ) + { + // If the anchor frame is the first content of the table cell + // and has no follow, the table frame is notified, + // that the object doesn't fit into the table cell. + // Adjustment of position isn't needed in this case. + if ( pOrientFrm == &rAnchorTxtFrm && + !pOrientFrm->GetFollow() && + !pOrientFrm->GetIndPrev() ) + { + const_cast<SwTabFrm*>(pOrientFrm->FindTabFrm()) + ->SetDoesObjsFit( FALSE ); + } + else + { + SwTwips nTmpRelPosY( 0L ); + if ( bVert ) + nTmpRelPosY = aRelPos.X() - nDist; + else + nTmpRelPosY = aRelPos.Y() + nDist; + const SwLayoutFrm& rVertEnvironLayFrm = + aEnvOfObj.GetVertEnvironmentLayoutFrm( *pUpperOfOrientFrm ); + nTmpRelPosY = _AdjustVertRelPos( nTopOfAnch, bVert, + rVertEnvironLayFrm, + nTmpRelPosY, + DoesObjFollowsTextFlow(), + false ); + if ( bVert ) + { + aRelPos.X() = nTmpRelPosY; + GetAnchoredObj().SetObjLeft( nTopOfAnch - + aRelPos.X() - + aObjBoundRect.Width() ); + } + else + { + aRelPos.Y() = nTmpRelPosY; + GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() ); + } + // If the anchor frame is the first content of the table cell + // and the object still doesn't fit, the table frame is notified, + // that the object doesn't fit into the table cell. + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)() ); + if ( nDist < 0 && + pOrientFrm == &rAnchorTxtFrm && !pOrientFrm->GetIndPrev() ) + { + const_cast<SwTabFrm*>(pOrientFrm->FindTabFrm()) + ->SetDoesObjsFit( FALSE ); + } + } + } + else + { + // <-- + // follow text flow + const bool bInFtn = rAnchorTxtFrm.IsInFtn(); + while( bMoveable && nDist < 0 ) + { + bool bInSct = pUpperOfOrientFrm->IsInSct(); + if ( bInSct ) + { + const SwLayoutFrm* pTmp = pUpperOfOrientFrm->FindSctFrm()->GetUpper(); + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pTmp->*fnRect->fnGetPrtBottom)() ); + // --> OD 2004-11-01 #i23129# - Try to flow into next + // section|section column. Thus, do *not* leave section + // area, if anchored object doesn't fit into upper of section. + // But the anchored object is allowed to overlap bottom + // section|section column. + if ( nDist >= 0 ) + { + break; + } + // <-- + } + if ( !bInSct && + (GetAnchoredObj().GetObjRect().*fnRect->fnGetTop)() == + (pUpperOfOrientFrm->*fnRect->fnGetPrtTop)() ) + //Das teil passt nimmer, da hilft auch kein moven. + break; + + const SwLayoutFrm* pNextLay = pUpperOfOrientFrm->GetLeaf( + ( bInSct + ? MAKEPAGE_NOSECTION + : ( bInFtn ? MAKEPAGE_NONE : MAKEPAGE_APPEND ) ), + TRUE, &rAnchorTxtFrm ); + // OD 06.10.2003 #110978# - correction: + // If anchor is in footnote and proposed next layout environment + // isn't a footnote frame, object can't follow the text flow + if ( bInFtn && pNextLay && !pNextLay->IsFtnFrm() ) + { + pNextLay = 0L; + } + if ( pNextLay ) + { + SWRECTFNX( pNextLay ) + if ( !bInSct || + ( pUpperOfOrientFrm->FindSctFrm()->IsAnFollow( pNextLay->FindSctFrm() ) && + (pNextLay->Prt().*fnRectX->fnGetHeight)() ) ) + { + SwTwips nTmpRelPosY = + (*fnRect->fnYDiff)( (pNextLay->*fnRect->fnGetPrtTop)(), + nTopOfAnch ); + if ( bVert ) + aRelPos.X() = nTmpRelPosY; + else + aRelPos.Y() = nTmpRelPosY; + pUpperOfOrientFrm = pNextLay; + SWREFRESHFN( pUpperOfOrientFrm ) + bMoveable = rAnchorTxtFrm.IsMoveable( (SwLayoutFrm*)pUpperOfOrientFrm ); + if( bVertX ) + GetAnchoredObj().SetObjLeft( nTopOfAnch - + aRelPos.X() - + aObjBoundRect.Width() ); + else + GetAnchoredObj().SetObjTop( nTopOfAnch + + aRelPos.Y() ); + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pUpperOfOrientFrm->*fnRect->fnGetPrtBottom)() ); + } + // --> OD 2004-11-01 #i23129# - leave section area + else if ( bInSct ) + { + const SwLayoutFrm* pTmp = pUpperOfOrientFrm->FindSctFrm()->GetUpper(); + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pTmp->*fnRect->fnGetPrtBottom)() ); + if( nDist < 0 ) + pUpperOfOrientFrm = pTmp; + else + break; + } + // <-- + } + else if ( bInSct ) + { + // Wenn wir innerhalb des Bereich nicht genug Platz haben, gucken + // wir uns mal die Seite an. + const SwLayoutFrm* pTmp = pUpperOfOrientFrm->FindSctFrm()->GetUpper(); + nDist = (GetAnchoredObj().GetObjRect().*fnRect->fnBottomDist)( + (pTmp->*fnRect->fnGetPrtBottom)() ); + if( nDist < 0 ) + pUpperOfOrientFrm = pTmp; + else + break; + } + else + bMoveable = false; + } + } + } + + // keep layout frame vertical position is oriented at. + mpVertPosOrientFrm = pUpperOfOrientFrm; + + } + + // determine 'horizontal' position + { + // determine horizontal positioning and alignment attributes + SwFmtHoriOrient aHori( rFrmFmt.GetHoriOrient() ); + + // set calculated vertical position in order to determine correct + // frame, the horizontal position is oriented at. + const SwTwips nTopOfAnch = _GetTopForObjPos( *pAnchorFrmForVertPos, fnRect, bVert ); + if( bVert ) + GetAnchoredObj().SetObjLeft( nTopOfAnch - + aRelPos.X() - aObjBoundRect.Width() ); + else + GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() ); + + // determine frame, horizontal position is oriented at. + // OD 2004-05-21 #i28701# - If floating screen object doesn't follow + // the text flow, its horizontal position is oriented at <pOrientFrm>. + const SwFrm* pHoriOrientFrm = DoesObjFollowsTextFlow() + ? &_GetHoriVirtualAnchor( *mpVertPosOrientFrm ) + : pOrientFrm; + + // --> OD 2004-06-17 #i26791# - get 'horizontal' offset to frame anchor position. + SwTwips nHoriOffsetToFrmAnchorPos( 0L ); + SwTwips nRelPosX = _CalcRelPosX( *pHoriOrientFrm, aEnvOfObj, + aHori, rLR, rUL, bWrapThrough, + ( bVert ? aRelPos.X() : aRelPos.Y() ), + nHoriOffsetToFrmAnchorPos ); + + // --> OD 2004-06-17 #i26791# - determine offset to 'horizontal' frame + // anchor position, depending on layout-direction + if ( bVert ) + { + aRelPos.Y() = nRelPosX; + maOffsetToFrmAnchorPos.Y() = nHoriOffsetToFrmAnchorPos; + } + else + { + aRelPos.X() = nRelPosX; + maOffsetToFrmAnchorPos.X() = nHoriOffsetToFrmAnchorPos; + } + + // save calculated horizontal position - needed for filters + // (including the xml-filter) + { + SwTwips nAttrRelPosX = nRelPosX - nHoriOffsetToFrmAnchorPos; + if ( aHori.GetHoriOrient() != text::HoriOrientation::NONE && + aHori.GetPos() != nAttrRelPosX ) + { + aHori.SetPos( nAttrRelPosX ); + const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); + const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aHori ); + const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); + } + } + } + + // set absolute position at object + const SwTwips nTopOfAnch = _GetTopForObjPos( *pAnchorFrmForVertPos, fnRect, bVert ); + if( bVert ) + { + GetAnchoredObj().SetObjLeft( nTopOfAnch - + aRelPos.X() - aObjBoundRect.Width() ); + GetAnchoredObj().SetObjTop( rAnchorTxtFrm.Frm().Top() + + aRelPos.Y() ); + } + else + { + GetAnchoredObj().SetObjLeft( rAnchorTxtFrm.Frm().Left() + + aRelPos.X() ); + GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() ); + } + + // set relative position at object + GetAnchoredObj().SetCurrRelPos( aRelPos ); +} + +/** determine frame for horizontal position + + @author OD +*/ +const SwFrm& SwToCntntAnchoredObjectPosition::_GetHoriVirtualAnchor( + const SwLayoutFrm& _rProposedFrm ) const +{ + const SwFrm* pHoriVirtAnchFrm = &_rProposedFrm; + + // Search for first lower content frame, which is the anchor or a follow + // of the anchor (Note: <Anchor.IsAnFollow( Anchor )> is true) + // If none found, <_rProposedFrm> is returned. + const SwFrm* pFrm = _rProposedFrm.Lower(); + while ( pFrm ) + { + if ( pFrm->IsCntntFrm() && + GetAnchorTxtFrm().IsAnFollow( static_cast<const SwCntntFrm*>(pFrm) ) ) + { + pHoriVirtAnchFrm = pFrm; + break; + } + pFrm = pFrm->GetNext(); + } + + return *pHoriVirtAnchFrm; +} + +const SwLayoutFrm& SwToCntntAnchoredObjectPosition::GetVertPosOrientFrm() const +{ + return *mpVertPosOrientFrm; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx new file mode 100644 index 000000000000..c98e773b2f21 --- /dev/null +++ b/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx @@ -0,0 +1,245 @@ +/* -*- 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 <tolayoutanchoredobjectposition.hxx> +#include <anchoredobject.hxx> +#include <frame.hxx> +#include <pagefrm.hxx> +#include <svx/svdobj.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <IDocumentSettingAccess.hxx> +#include <frmatr.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> + +using namespace objectpositioning; +using namespace ::com::sun::star; + + +SwToLayoutAnchoredObjectPosition::SwToLayoutAnchoredObjectPosition( SdrObject& _rDrawObj ) + : SwAnchoredObjectPosition( _rDrawObj ), + maRelPos( Point() ), + // --> OD 2004-06-17 #i26791# + maOffsetToFrmAnchorPos( Point() ) +{} + +SwToLayoutAnchoredObjectPosition::~SwToLayoutAnchoredObjectPosition() +{} + +/** calculate position for object position type TO_LAYOUT + + @author OD +*/ +void SwToLayoutAnchoredObjectPosition::CalcPosition() +{ + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + + SWRECTFN( (&GetAnchorFrm()) ); + + const SwFrmFmt& rFrmFmt = GetFrmFmt(); + const SvxLRSpaceItem &rLR = rFrmFmt.GetLRSpace(); + const SvxULSpaceItem &rUL = rFrmFmt.GetULSpace(); + + const bool bFlyAtFly = FLY_AT_FLY == rFrmFmt.GetAnchor().GetAnchorId(); + + // determine position. + // 'vertical' and 'horizontal' position are calculated separately + Point aRelPos; + + // calculate 'vertical' position + SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() ); + { + // to-frame anchored objects are *only* vertical positioned centered or + // bottom, if its wrap mode is 'throught' and its anchor frame has fixed + // size. Otherwise, it's positioned top. + sal_Int16 eVertOrient = aVert.GetVertOrient(); + if ( ( bFlyAtFly && + ( eVertOrient == text::VertOrientation::CENTER || + eVertOrient == text::VertOrientation::BOTTOM ) && + SURROUND_THROUGHT != rFrmFmt.GetSurround().GetSurround() && + !GetAnchorFrm().HasFixSize() ) ) + { + eVertOrient = text::VertOrientation::TOP; + } + // --> OD 2004-06-17 #i26791# - get vertical offset to frame anchor position. + SwTwips nVertOffsetToFrmAnchorPos( 0L ); + SwTwips nRelPosY = + _GetVertRelPos( GetAnchorFrm(), GetAnchorFrm(), eVertOrient, + aVert.GetRelationOrient(), aVert.GetPos(), + rLR, rUL, nVertOffsetToFrmAnchorPos ); + + + // keep the calculated relative vertical position - needed for filters + // (including the xml-filter) + { + SwTwips nAttrRelPosY = nRelPosY - nVertOffsetToFrmAnchorPos; + if ( aVert.GetVertOrient() != text::VertOrientation::NONE && + aVert.GetPos() != nAttrRelPosY ) + { + aVert.SetPos( nAttrRelPosY ); + const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); + const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert ); + const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); + } + } + + // determine absolute 'vertical' position, depending on layout-direction + // --> OD 2004-06-17 #i26791# - determine offset to 'vertical' frame + // anchor position, depending on layout-direction + if( bVert ) + { + OSL_ENSURE( !bRev, "<SwToLayoutAnchoredObjectPosition::CalcPosition()> - reverse layout set." ); + aRelPos.X() = -nRelPosY - aObjBoundRect.Width(); + maOffsetToFrmAnchorPos.X() = nVertOffsetToFrmAnchorPos; + } + else + { + aRelPos.Y() = nRelPosY; + maOffsetToFrmAnchorPos.Y() = nVertOffsetToFrmAnchorPos; + } + + // if in online-layout the bottom of to-page anchored object is beyond + // the page bottom, the page frame has to grow by growing its body frame. + if ( !bFlyAtFly && GetAnchorFrm().IsPageFrm() && + rFrmFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) ) + { + const long nAnchorBottom = GetAnchorFrm().Frm().Bottom(); + const long nBottom = GetAnchorFrm().Frm().Top() + + aRelPos.Y() + aObjBoundRect.Height(); + if ( nAnchorBottom < nBottom ) + { + static_cast<SwPageFrm&>(GetAnchorFrm()). + FindBodyCont()->Grow( nBottom - nAnchorBottom ); + } + } + } // end of determination of vertical position + + // calculate 'horizontal' position + SwFmtHoriOrient aHori( rFrmFmt.GetHoriOrient() ); + { + // consider toggle of horizontal position for even pages. + const bool bToggle = aHori.IsPosToggle() && + !GetAnchorFrm().FindPageFrm()->OnRightPage(); + sal_Int16 eHoriOrient = aHori.GetHoriOrient(); + sal_Int16 eRelOrient = aHori.GetRelationOrient(); + // toggle orientation + _ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient ); + + // determine alignment values: + // <nWidth>: 'width' of the alignment area + // <nOffset>: offset of alignment area, relative to 'left' of + // frame anchor position + SwTwips nWidth, nOffset; + { + bool bDummy; // in this context irrelevant output parameter + _GetHoriAlignmentValues( GetAnchorFrm(), GetAnchorFrm(), + eRelOrient, false, + nWidth, nOffset, bDummy ); + } + + SwTwips nObjWidth = (aObjBoundRect.*fnRect->fnGetWidth)(); + + // determine relative horizontal position + SwTwips nRelPosX; + if ( text::HoriOrientation::NONE == eHoriOrient ) + { + if( bToggle || + ( !aHori.IsPosToggle() && GetAnchorFrm().IsRightToLeft() ) ) + { + nRelPosX = nWidth - nObjWidth - aHori.GetPos(); + } + else + { + nRelPosX = aHori.GetPos(); + } + } + else if ( text::HoriOrientation::CENTER == eHoriOrient ) + nRelPosX = (nWidth / 2) - (nObjWidth / 2); + else if ( text::HoriOrientation::RIGHT == eHoriOrient ) + nRelPosX = nWidth - ( nObjWidth + + ( bVert ? rUL.GetLower() : rLR.GetRight() ) ); + else + nRelPosX = bVert ? rUL.GetUpper() : rLR.GetLeft(); + nRelPosX += nOffset; + + // no 'negative' relative horizontal position + // OD 06.11.2003 #FollowTextFlowAtFrame# - negative positions allow for + // to frame anchored objects. + if ( !bFlyAtFly && nRelPosX < 0 ) + { + nRelPosX = 0; + } + + // determine absolute 'horizontal' position, depending on layout-direction + // --> OD 2004-06-17 #i26791# - determine offset to 'horizontal' frame + // anchor position, depending on layout-direction + if ( bVert ) + { + aRelPos.Y() = nRelPosX; + maOffsetToFrmAnchorPos.Y() = nOffset; + } + else + { + aRelPos.X() = nRelPosX; + maOffsetToFrmAnchorPos.X() = nOffset; + } + + // keep the calculated relative horizontal position - needed for filters + // (including the xml-filter) + { + SwTwips nAttrRelPosX = nRelPosX - nOffset; + if ( text::HoriOrientation::NONE != aHori.GetHoriOrient() && + aHori.GetPos() != nAttrRelPosX ) + { + aHori.SetPos( nAttrRelPosX ); + const_cast<SwFrmFmt&>(rFrmFmt).LockModify(); + const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aHori ); + const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify(); + } + } + } // end of determination of horizontal position + + // keep calculate relative position + maRelPos = aRelPos; +} + +/** calculated relative position for object position + + @author OD +*/ +Point SwToLayoutAnchoredObjectPosition::GetRelPos() const +{ + return maRelPos; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |