/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
namespace
{ /** unary function used to find a 'virtual' drawing object anchored at a given frame */ struct VirtObjAnchoredAtFramePred
{ const SwFrame* m_pAnchorFrame;
/** The Get reverse way: seeks the format to the specified object. * If the object is a SwVirtFlyDrawObj then the format of this * will be acquired. * Otherwise it is just a simple drawing object. This has a * UserCall and is the client of the searched format.
*/
SwFrameFormat *FindFrameFormat( SdrObject *pObj )
{ if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj)) return pFlyDrawObj->GetFormat();
if (SwContact* pContact = GetUserCall(pObj)) return pContact->GetFormat();
/// returns the BoundRect _inclusive_ distance of the object.
SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
{
SwRect aRet( pObj->GetCurrentBoundRect() ); // #i68520# - call cache of <SwAnchoredObject>
SwContact* pContact( GetUserCall( pObj ) ); if ( pContact )
{ const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) ); if ( pAnchoredObj )
{
aRet = pAnchoredObj->GetObjRectWithSpaces();
}
} return aRet;
}
/// Returns the UserCall if applicable from the group object
SwContact* GetUserCall( const SdrObject* pObj )
{ for (; pObj; pObj = pObj->getParentSdrObjectFromSdrObject())
{ if (auto pUserCall = pObj->GetUserCall())
{
assert(dynamic_cast<SwContact*>(pUserCall)
&& "<::GetUserCall(..)> - wrong type of found object user call."); returnstatic_cast<SwContact*>(pUserCall);
}
} return nullptr;
}
/// Returns true if the SrdObject is a Marquee-Object (scrolling text) bool IsMarqueeTextObj( const SdrObject& rObj )
{ if (SdrInventor::Default != rObj.GetObjInventor() ||
SdrObjKind::Text != rObj.GetObjIdentifier()) returnfalse;
SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind(); return ( SdrTextAniKind::Scroll == eTKind
|| SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
}
/// method to move drawing object to corresponding visible layer void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
{ // #i46297# - notify background about the arriving of // the object and invalidate its position. constbool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
MoveObjToLayer( true, _pDrawObj );
// #i46297# if ( !bNotify ) return;
SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
assert(pAnchoredObj);
::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() ); // Note: as-character anchored objects aren't registered at a page frame and // a notification of its background isn't needed. if ( pAnchoredObj->GetPageFrame() )
{
::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameArrive, true );
}
pAnchoredObj->InvalidateObjPos();
}
/// method to move drawing object to corresponding invisible layer - #i18447# void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
{ // #i46297# - notify background about the leaving of the object. constbool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
MoveObjToLayer( false, _pDrawObj );
// #i46297# if ( bNotify )
{
SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
assert(pAnchoredObj); // Note: as-character anchored objects aren't registered at a page frame and // a notification of its background isn't needed. if (pAnchoredObj->GetPageFrame())
{
::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
pAnchoredObj->GetObjRect(), PrepareHint::FlyFrameLeave, true );
}
}
}
/** method to move object to visible/invisible layer - #i18447#
implementation for the public method <MoveObjToVisibleLayer(..)> and <MoveObjToInvisibleLayer(..)>
*/ void SwContact::MoveObjToLayer( constbool _bToVisible,
SdrObject* _pDrawObj )
{ if ( !_pDrawObj )
{
OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" ); return;
}
if ( !GetRegisteredIn() )
{
OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" ); return;
}
if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) != nullptr )
{ // determine layer for group object
{ // proposed layer of a group object is the hell layer
SdrLayerID nNewLayerId = nToHellLayerId; if ( ::CheckControlLayer( _pDrawObj ) )
{ // it has to be the control layer, if one of the member // is a control
nNewLayerId = nToControlLayerId;
} elseif ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
_pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
{ // it has to be the heaven layer, if method <GetLayer()> reveals // a heaven layer
nNewLayerId = nToHeavenLayerId;
} // set layer at group object, but do *not* broadcast and // no propagation to the members. // Thus, call <NbcSetLayer(..)> at super class
_pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
}
/// get minimum order number of anchored objects handled by with contact
sal_uInt32 SwContact::GetMinOrdNum() const
{
sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
namespace
{
Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, constbool bFollowTextFlow, sw::WW8AnchorConv& reConv)
{ switch(reConv)
{ case sw::WW8AnchorConv::CONV2PG:
{ bool bRelToTableCell(false);
Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell)); if(bRelToTableCell)
reConv = sw::WW8AnchorConv::RELTOTABLECELL; return aPos;
} case sw::WW8AnchorConv::CONV2COL_OR_PARA: return pAnchoredObj->GetRelPosToAnchorFrame(); case sw::WW8AnchorConv::CONV2CHAR: return pAnchoredObj->GetRelPosToChar(); case sw::WW8AnchorConv::CONV2LINE: return pAnchoredObj->GetRelPosToLine(); default: ;
} return Point();
}
} void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{ // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional? if (rHint.GetId() == SfxHintId::SwFindSdrObject)
{ auto pFindSdrObjectHint = static_cast<const sw::FindSdrObjectHint*>(&rHint); if(!pFindSdrObjectHint->m_rpObject)
pFindSdrObjectHint->m_rpObject = GetMaster();
} elseif (rHint.GetId() == SfxHintId::SwWW8AnchorConv)
{ auto pWW8AnchorConvHint = static_cast<const sw::WW8AnchorConvHint*>(&rHint); // determine anchored object
SwAnchoredObject* pAnchoredObj(nullptr);
{
std::vector<SwAnchoredObject*> aAnchoredObjs;
GetAnchoredObjs(aAnchoredObjs); if(!aAnchoredObjs.empty())
pAnchoredObj = aAnchoredObjs.front();
} // no anchored object found. Thus, the needed layout information can't // be determined. --> no conversion if(!pAnchoredObj) return; // no conversion for anchored drawing object, which aren't attached to an // anchor frame. // This is the case for drawing objects, which are anchored inside a page // header/footer of an *unused* page style. if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame()) return; constbool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult); // No distinction between layout directions, because of missing // information about WW8 in vertical layout.
rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
rResult.m_bConverted = true;
}
}
SwFlyDrawContact::SwFlyDrawContact(
SwFlyFrameFormat *pToRegisterIn,
SdrModel& rTargetModel)
: SwContact(pToRegisterIn),
mpMasterObj(new SwFlyDrawObj(rTargetModel))
{ // #i26791# - class <SwFlyDrawContact> contains the 'master' // drawing object of type <SwFlyDrawObj> on its own.
mpMasterObj->SetOrdNum( 0xFFFFFFFE );
mpMasterObj->SetUserCall( this );
}
SwFlyDrawContact::~SwFlyDrawContact()
{ if ( mpMasterObj )
{
mpMasterObj->SetUserCall( nullptr ); if ( mpMasterObj->getSdrPageFromSdrObject() )
mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
}
}
sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
SwFrame const& rAnchorFrame)
{ // maintain invariant that a shape's textbox immediately follows the shape // also for the multiple SdrVirtObj created for shapes in header/footer if (SwFrameFormat const*const pDrawFormat =
SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
{ // assume that the draw SdrVirtObj is always created before the flyframe one if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
{ for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
{ if (pAnchoredObj->GetFrameFormat() == pDrawFormat)
{ return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
}
}
} // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
SAL_INFO("sw", "GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
} // search for another Writer fly frame registered at same frame format
SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat()); const SwFlyFrame* pFlyFrame(nullptr); for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
{ if(pFlyFrame != pFly) break;
}
if(pFlyFrame)
{ // another Writer fly frame found. Take its order number return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
} // no other Writer fly frame found. Take order number of 'master' object // #i35748# - use method <GetOrdNumDirect()> instead // of method <GetOrdNum()> to avoid a recalculation of the order number, // which isn't intended. return GetMaster()->GetOrdNumDirect();
}
SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
{ // Find ContactObject from the Format. If there's already one, we just // need to create a new Ref, else we create the Contact now.
// The Reader creates the Masters and inserts them into the Page in // order to transport the z-order. // After creating the first Reference the Masters are removed from the // List and are not important anymore.
SdrPage* pPg = pContact->GetMaster()->getSdrPageFromSdrObject(); if(nullptr != pPg)
{ const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
pPg->ReplaceObject(pDrawObj.get(), nOrdNum);
} // #i27030# - insert new <SwVirtFlyDrawObj> instance // into drawing page with correct order number else
rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj.get(), pContact->GetOrdNumForNewRef(pFly, rAnchorFrame)); // #i38889# - assure, that new <SwVirtFlyDrawObj> instance // is in a visible layer.
pContact->MoveObjToVisibleLayer(pDrawObj.get()); return pDrawObj.get();
}
// #i26791# const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
{
assert(pSdrObj);
assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
assert(GetUserCall(pSdrObj) == this && "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
/** * @note Overriding method to control Writer fly frames, which are linked, and * to assure that all objects anchored at/inside the Writer fly frame are * also made visible.
*/ void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
{
assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
{ // nothing to do return;
}
// #i44464# - consider, that Writer fly frame content // already exists - (e.g. WW8 document is inserted into an existing document). if ( !pFlyFrame->Lower() )
{
pFlyFrame->InsertColumns();
pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
pFlyFrame->InsertCnt();
} if ( pFlyFrame->GetDrawObjs() )
{ for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
{ // #i28701# - consider type of objects in sorted object list.
SdrObject* pObj = i->DrawObj();
SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
pContact->MoveObjToVisibleLayer( pObj );
}
}
// make fly frame visible
SwContact::MoveObjToVisibleLayer( _pDrawObj );
}
/** * @note Override method to control Writer fly frames, which are linked, and * to assure that all objects anchored at/inside the Writer fly frame are * also made invisible.
*/ void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
{
assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
{ // nothing to do return;
}
pFlyFrame->Unchain();
pFlyFrame->DeleteCnt(); if ( pFlyFrame->GetDrawObjs() )
{ for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
{ // #i28701# - consider type of objects in sorted object list.
SdrObject* pObj = i->DrawObj();
SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
pContact->MoveObjToInvisibleLayer( pObj );
}
}
// make fly frame invisible
SwContact::MoveObjToInvisibleLayer( _pDrawObj );
}
/// get data collection of anchored objects, handled by with contact void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
{ const SwFrameFormat* pFormat = GetFormat();
SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
} void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
SwContact::SwClientNotify(rMod, rHint); if(rHint.GetId() == SfxHintId::SwGetZOrder)
{ auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint); // #i11176# // This also needs to work when no layout exists. Thus, for // FlyFrames an alternative method is used now in that case. auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod)); if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
}
}
SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
SwContact( pToRegisterIn ),
mbMasterObjCleared( false ),
mbDisconnectInProgress( false ),
mbUserCallActive( false ), // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because // <mbUserCallActive> is false.
meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
{ // --> #i33909# - assure, that drawing object is inserted // in the drawing page. if ( !pObj->IsInserted() )
{
pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
InsertObject( pObj, pObj->GetOrdNumDirect() );
}
// Controls have to be always in the Control-Layer. This is also true for // group objects, if they contain controls. if ( ::CheckControlLayer( pObj ) )
{ // set layer of object to corresponding invisible layer.
pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
}
// #i26791#
pObj->SetUserCall( this );
maAnchoredDrawObj.SetDrawObj( *pObj );
// if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject // #i99056#
SwXShape::AddExistingShapeToFormat( *pObj );
}
SwDrawContact::~SwDrawContact()
{
SetInDTOR();
DisconnectFromLayout();
// remove 'master' from drawing page
RemoveMasterFromDrawPage();
// remove and destroy 'virtual' drawing objects.
RemoveAllVirtObjs();
if ( !mbMasterObjCleared )
maAnchoredDrawObj.ClearDrawObj();
}
void SwDrawContact::Changed( const SdrObject& rObj,
SdrUserCallType eType, const tools::Rectangle& rOldBoundRect )
{ // #i26791# - no event handling, if existing <SwViewShell> // is in construction
SwDoc& rDoc = GetFormat()->GetDoc(); if ( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() &&
rDoc.getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
{ return;
}
// #i44339# // no event handling, if document is in destruction. // Exception: It's the SdrUserCallType::Delete event if ( rDoc.IsInDtor() && eType != SdrUserCallType::Delete )
{ return;
}
//Put on Action, but not if presently anywhere an action runs. bool bHasActions(true);
SwRootFrame *pTmpRoot = rDoc.getIDocumentLayoutAccess().GetCurrentLayout(); if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
{
SwViewShell* const pSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell(); if ( pSh )
{ for(SwViewShell& rShell : pSh->GetRingContainer() )
{ if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
{
bHasActions = true; break;
}
bHasActions = false;
}
} if(!bHasActions)
pTmpRoot->StartAllAction();
}
SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
Changed_( rObj, eType, &rOldBoundRect ); //Attention, possibly suicidal!
if(!bHasActions)
pTmpRoot->EndAllAction();
}
/// helper class for method <SwDrawContact::Changed_(..)> for handling nested /// <SdrObjUserCall> events class NestedUserCallHdl
{ private:
SwDrawContact* mpDrawContact; bool mbParentUserCallActive;
SdrUserCallType meParentUserCallEventType;
void AssertNestedUserCall()
{ if ( !IsNestedUserCall() ) return;
bool bTmpAssert( true ); // Currently its known, that a nested event SdrUserCallType::Resize // could occur during parent user call SdrUserCallType::Inserted, // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects. // Also possible are nested SdrUserCallType::ChildResize events for // edge objects // Thus, assert all other combinations if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
meParentUserCallEventType == SdrUserCallType::Delete ||
meParentUserCallEventType == SdrUserCallType::Resize ) &&
mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
{
bTmpAssert = false;
} elseif ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
{
bTmpAssert = false;
}
if ( bTmpAssert )
{
OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious.");
}
}
};
/// Notify the format's textbox that it should reconsider its position / size. staticvoid lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
{ if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
{ // Just notify the textbox that the size has changed, the actual object size is not interesting.
SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aResizeSet(pFormat->GetDoc().GetAttrPool());
SwFormatFrameSize aSize;
aResizeSet.Put(aSize);
SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet, pFormat->FindRealSdrObject());
}
}
// !!!ATTENTION!!! The object may commit suicide!!!
void SwDrawContact::Changed_( const SdrObject& rObj,
SdrUserCallType eType, const tools::Rectangle* pOldBoundRect )
{ // suppress handling of nested <SdrObjUserCall> events
NestedUserCallHdl aNestedUserCallHdl( this, eType ); if ( aNestedUserCallHdl.IsNestedUserCall() )
{
aNestedUserCallHdl.AssertNestedUserCall(); return;
} // do *not* notify, if document is destructing // #i35912# - do *not* notify for as-character anchored // drawing objects. // #i35007# // improvement: determine as-character anchored object flag only once. constbool bAnchoredAsChar = ObjAnchoredAsChar(); constbool bNotify = !(GetFormat()->GetDoc().IsInDtor()) &&
( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
!bAnchoredAsChar; switch( eType )
{ case SdrUserCallType::Delete:
{ if ( bNotify )
{
lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect ); // --> #i36181# - background of 'virtual' // drawing objects have also been notified.
NotifyBackgroundOfAllVirtObjs( pOldBoundRect );
}
DisconnectFromLayout( false );
mbMasterObjCleared = true; deletethis; // --> #i65784# Prevent memory corruption
aNestedUserCallHdl.DrawContactDeleted(); break;
} case SdrUserCallType::Inserted:
{ if ( mbDisconnectInProgress )
{
OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
} else
{
ConnectToLayout(); if ( bNotify )
{
lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
}
} break;
} case SdrUserCallType::Removed:
{ if ( bNotify )
{
lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
}
DisconnectFromLayout( false ); break;
} case SdrUserCallType::ChildInserted : case SdrUserCallType::ChildRemoved :
{ // --> #i113730# // force layer of controls for group objects containing control objects if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
{ if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
{ const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess(); const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer()); const SdrLayerID aControlLayerID(rIDDMA.GetControlsId()); const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
{ if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
{
maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
} else
{
maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
}
}
}
}
[[fallthrough]];
} case SdrUserCallType::MoveOnly: case SdrUserCallType::Resize: case SdrUserCallType::ChildMoveOnly : case SdrUserCallType::ChildResize : case SdrUserCallType::ChildChangeAttr : case SdrUserCallType::ChildDelete :
{ // #i31698# - improvement // get instance <SwAnchoredDrawObject> only once const SwAnchoredDrawObject* pAnchoredDrawObj = static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
// #i26791# - adjust positioning and alignment attributes, // if positioning of drawing object isn't in progress. // #i53320# - no adjust of positioning attributes, // if drawing object isn't positioned. if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
!pAnchoredDrawObj->NotYetPositioned() )
{ // #i34748# - If no last object rectangle is // provided by the anchored object, use parameter <pOldBoundRect>. const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
? *(pAnchoredDrawObj->GetLastObjRect())
: *pOldBoundRect; // #i79400# // always invalidate object rectangle inclusive spaces
pAnchoredDrawObj->InvalidateObjRectWithSpaces(); // #i41324# - notify background before // adjusting position if ( bNotify )
{ // #i31573# - correction // background of given drawing object.
lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
} // #i31698# - determine layout direction // via draw frame format.
SwFrameFormat::tLayoutDir eLayoutDir =
pAnchoredDrawObj->GetFrameFormat()->GetLayoutDir(); // use geometry of drawing object
tools::Rectangle aObjRect( rObj.GetSnapRect() ); // If drawing object is a member of a group, the adjustment // of the positioning and the alignment attributes has to // be done for the top group object. if ( rObj.getParentSdrObjectFromSdrObject() )
{ const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject(); while ( pGroupObj->getParentSdrObjectFromSdrObject() )
{
pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
} // use geometry of drawing object
aObjRect = pGroupObj->GetSnapRect();
if ( nYPosDiff ||
( !bAnchoredAsChar && nXPosDiff != 0 ) )
{
GetFormat()->GetDoc().SetFlyFrameAttr( *(GetFormat()), aSet ); // keep new object rectangle, to avoid multiple // changes of the attributes by multiple event from // the drawing layer - e.g. group objects and its members // #i34748# - use new method // <SwAnchoredDrawObject::SetLastObjRect(..)>. const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
->SetLastObjRect( aObjRect );
} elseif ( aObjRect.GetSize() != aOldObjRect.GetSize() )
{
InvalidateObjs_(); // #i35007# - notify anchor frame // of as-character anchored object if ( bAnchoredAsChar )
{
SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame(); if(pAnchorFrame)
{
pAnchorFrame->Prepare( PrepareHint::FlyFrameAttributesChanged, GetFormat() );
}
}
lcl_textBoxSizeNotify(GetFormat());
} elseif (eType == SdrUserCallType::Resize) // Even if the bounding box of the shape didn't change, // notify about the size change, as an adjustment change // may affect the size of the underlying textbox.
lcl_textBoxSizeNotify(GetFormat());
}
// tdf#135198: keep text box together with its shape const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame(); if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && GetFormat()
&& GetFormat()->GetOtherTextBoxFormats())
{
SwDoc& rDoc = GetFormat()->GetDoc();
// hide any artificial "changes" made by synchronizing the textbox position constbool bEnableSetModified = rDoc.getIDocumentState().IsEnableSetModified();
rDoc.getIDocumentState().SetEnableSetModified(false);
const SwFormatAnchor* pNewAnchorFormat = nullptr; const SwFormatAnchor* pOldAnchorFormat = nullptr; if (rHint.GetId() == SfxHintId::SwLegacyModify)
{ auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint); if (pLegacyHint->m_pNew)
pNewAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pNew); if (pLegacyHint->m_pOld)
pOldAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pOld);
} elseif (rHint.GetId() == SfxHintId::SwAttrSetChange)
{ auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint); if (pChangeHint->m_pNew)
pNewAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pNew); if (pChangeHint->m_pOld)
pOldAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pOld);
}
if(pNewAnchorFormat)
{ // Do not respond to a Reset Anchor! if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
{ // no connect to layout during disconnection if(!mbDisconnectInProgress)
{ // determine old object rectangle of 'master' drawing object // for notification const tools::Rectangle* pOldRect = nullptr;
tools::Rectangle aOldRect; if(GetAnchorFrame())
{ // --> #i36181# - include spacing in object // rectangle for notification.
aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
pOldRect = &aOldRect;
} // re-connect to layout due to anchor format change
ConnectToLayout(pNewAnchorFormat); // notify background of drawing objects
lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
NotifyBackgroundOfAllVirtObjs(pOldRect);
if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
{ if(maAnchoredDrawObj.DrawObj())
{ // --> #i102752# // assure that a ShapePropertyChangeNotifier exists
maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(u"AnchorType"_ustr);
} else
SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
}
}
} else
DisconnectFromLayout();
} // --> #i62875# - no further notification, if not connected to Writer layout elseif ( maAnchoredDrawObj.GetAnchorFrame() &&
maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
{ bool bUpdateSortedObjsList(false); if (rHint.GetId() == SfxHintId::SwLegacyModify)
{ auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
sal_uInt16 nWhich = pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0; switch(nWhich)
{ case RES_UL_SPACE: case RES_LR_SPACE: case RES_HORI_ORIENT: case RES_VERT_ORIENT: case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow' break; case RES_SURROUND: case RES_OPAQUE: case RES_WRAP_INFLUENCE_ON_OBJPOS: // --> #i28701# - on change of wrapping style, hell|heaven layer, // or wrapping style influence an update of the <SwSortedObjs> list, // the drawing object is registered in, has to be performed. This is triggered // by the 1st parameter of method call <InvalidateObjs_(..)>.
bUpdateSortedObjsList = true; break; default:
assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
}
} elseif (rHint.GetId() == SfxHintId::SwAttrSetChange)
{ // #i35443# auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint); auto pChgSet = pChangeHint->m_pNew ? pChangeHint->m_pNew->GetChgSet() : nullptr; if(pChgSet && (pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET))
bUpdateSortedObjsList = true;
}
lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
NotifyBackgroundOfAllVirtObjs(nullptr);
InvalidateObjs_(bUpdateSortedObjsList);
}
// #i51474#
GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
} elseif (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
{ auto pDrawFrameFormatHint = static_cast<const sw::DrawFrameFormatHint*>(&rHint); switch(pDrawFrameFormatHint->m_eId)
{ case sw::DrawFrameFormatHintId::DYING: deletethis; break; case sw::DrawFrameFormatHintId::PREPPASTING:
MoveObjToVisibleLayer(GetMaster()); break; case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
InsertMasterIntoDrawPage(); // #i40845# - follow-up of #i35635# // move object to visible layer
MoveObjToVisibleLayer(GetMaster()); // tdf#135661 InsertMasterIntoDrawPage may have created a new // SwXShape with null m_pFormat; fix that
SwXShape::AddExistingShapeToFormat(*GetMaster()); break; case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
RemoveMasterFromDrawPage(); break; case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS: case sw::DrawFrameFormatHintId::DELETE_FRAMES:
DisconnectFromLayout(); break; case sw::DrawFrameFormatHintId::MAKE_FRAMES:
ConnectToLayout(); break; case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
GetAnchoredObj(GetMaster())->MakeObjPos(); break; default:
;
}
} elseif (rHint.GetId() == SfxHintId::SwCheckDrawFrameFormatLayer)
{ auto pCheckDrawFrameFormatLayerHint = static_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint);
*(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
} elseif (rHint.GetId() == SfxHintId::SwContactChanged)
{ auto pContactChangedHint = static_cast<const sw::ContactChangedHint*>(&rHint); if(!*pContactChangedHint->m_ppObject)
*pContactChangedHint->m_ppObject = GetMaster(); auto pObject = *pContactChangedHint->m_ppObject;
Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
} elseif (rHint.GetId() == SfxHintId::SwDrawFormatLayoutCopy)
{ auto pDrawFormatLayoutCopyHint = static_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint); const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
rtl::Reference<SdrObject> xNewObj =
pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
*GetMaster(),
pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == &rFormat.GetDoc()); new SwDrawContact(
&pDrawFormatLayoutCopyHint->m_rDestFormat, xNewObj.get() ); // #i49730# - notify draw frame format that position attributes are // already set, if the position attributes are already set at the // source draw frame format. if(rFormat.IsPosAttrSet())
pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
} elseif (rHint.GetId() == SfxHintId::SwRestoreFlyAnchor)
{ auto pRestoreFlyAnchorHint = static_cast<const sw::RestoreFlyAnchorHint*>(&rHint);
SdrObject* pObj = GetMaster(); if(GetAnchorFrame() && !pObj->IsInserted())
{ auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc().getIDocumentDrawModelAccess().GetDrawModel();
assert(pDrawModel);
pDrawModel->GetPage(0)->InsertObject(pObj);
}
pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
} elseif (rHint.GetId() == SfxHintId::SwCreatePortion)
{ auto pCreatePortionHint = static_cast<const sw::CreatePortionHint*>(&rHint); if(*pCreatePortionHint->m_ppContact) return;
*pCreatePortionHint->m_ppContact = this; // This is kind of ridiculous: the FrameFormat doesn't even hold a pointer to the contact itself, but here we are leaking it out randomly if(!GetAnchorFrame())
{ // No direct positioning needed any more
ConnectToLayout(); // Move object to visible layer
MoveObjToVisibleLayer(GetMaster());
}
} elseif (rHint.GetId() == SfxHintId::SwCollectTextObjects)
{ auto pCollectTextObjectsHint = static_cast<const sw::CollectTextObjectsHint*>(&rHint); auto pSdrO = GetMaster(); if(!pSdrO) return; if(dynamic_cast<const SdrObjGroup*>(pSdrO))
{
SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups); //iterate inside of a grouped object while(aListIter.IsMore())
{
SdrTextObj* pTextObj = DynCastSdrTextObj(aListIter.Next()); if(pTextObj && pTextObj->HasText())
pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
}
} elseif(SdrTextObj* pTextObj = DynCastSdrTextObj(pSdrO))
{ if(pTextObj->HasText())
pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
}
} elseif (rHint.GetId() == SfxHintId::SwGetZOrder)
{ auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint); auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod)); if (pFormat && pFormat->Which() == RES_DRAWFRMFMT)
pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
} elseif (rHint.GetId() == SfxHintId::SwGetObjectConnected)
{ auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
}
}
// #i26791# // #i28701# - added parameter <_bUpdateSortedObjsList> void SwDrawContact::InvalidateObjs_( constbool _bUpdateSortedObjsList )
{ for(constauto& rpDrawVirtObj : maDrawVirtObjs) // invalidate position of existing 'virtual' drawing objects
{
SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get()); // #i33313# - invalidation only for connected // 'virtual' drawing objects if ( pDrawVirtObj->IsConnected() )
{
pDrawVirtObj->AnchoredObj().InvalidateObjPos(); // #i28701# if ( _bUpdateSortedObjsList )
{
pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
}
}
}
// invalidate position of 'master' drawing object
SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
pAnchoredObj->InvalidateObjPos(); // #i28701# if ( _bUpdateSortedObjsList )
{
pAnchoredObj->UpdateObjInSortedList();
}
}
// Instead of removing 'master' object from drawing page, move the // 'master' drawing object into the corresponding invisible layer.
{ //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)-> // RemoveObject( GetMaster()->GetOrdNum() ); // #i18447# - in order to consider group object correct // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
MoveObjToInvisibleLayer( GetMaster() );
}
}
mbDisconnectInProgress = false;
}
/// method to remove 'master' drawing object from drawing page. void SwDrawContact::RemoveMasterFromDrawPage()
{ if ( GetMaster() )
{
GetMaster()->SetUserCall( nullptr ); if ( GetMaster()->IsInserted() )
{ static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
RemoveObject( GetMaster()->GetOrdNum() );
}
}
}
// disconnect for a dedicated drawing object - could be 'master' or 'virtual'. // a 'master' drawing object will disconnect a 'virtual' drawing object // in order to take its place. // #i19919# - no special case, if drawing object isn't in // page header/footer, in order to get drawing objects in repeating table headers // also working. void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
{ if ( auto pSwDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( _pDrawObj) )
{
pSwDrawVirtObj->RemoveFromWriterLayout();
pSwDrawVirtObj->RemoveFromDrawingPage();
} else
{ constauto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
[] (const rtl::Reference<SwDrawVirtObj>& pObj) { return pObj->IsConnected(); }));
if(ppVirtDrawObj != maDrawVirtObjs.end())
{ // replace found 'virtual' drawing object by 'master' drawing // object and disconnect the 'virtual' one
SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame(); // disconnect 'virtual' drawing object
pDrawVirtObj->RemoveFromWriterLayout();
pDrawVirtObj->RemoveFromDrawingPage(); // disconnect 'master' drawing object from current frame
GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj ); // re-connect 'master' drawing object to frame of found 'virtual' // drawing object.
pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
} else
{ // no connected 'virtual' drawing object found. Thus, disconnect // completely from layout.
DisconnectFromLayout();
}
}
}
void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
{ // *no* connect to layout during disconnection from layout. if ( mbDisconnectInProgress )
{
OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection."); return;
}
// --> #i33909# - *no* connect to layout, if 'master' drawing // object isn't inserted in the drawing page if ( !GetMaster()->IsInserted() )
{
OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" ); return;
}
// remove 'virtual' drawing objects from writer // layout and from drawing page, and remove 'master' drawing object from // writer layout - 'master' object will remain in drawing page.
DisconnectFromLayout( false );
if ( !pAnch )
{
pAnch = &(pDrawFrameFormat->GetAnchor());
}
for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
{
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
if ( pPage )
{
pPage->AppendDrawObj( maAnchoredDrawObj );
} else //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
pRoot->SetAssertFlyPages();
} break;
case RndStdIds::FLY_AT_CHAR: case RndStdIds::FLY_AT_PARA: case RndStdIds::FLY_AT_FLY: case RndStdIds::FLY_AS_CHAR:
{ if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
{
ClrContourCache( GetMaster() );
} // support drawing objects in header/footer, // but not control objects: // anchor at first found frame the 'master' object and // at the following frames 'virtual' drawing objects. // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
sw::BroadcastingModify *pModify = nullptr; if( pAnch->GetAnchorNode() )
{ if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
{
SwNodeIndex aIdx( *pAnch->GetAnchorNode() );
SwContentNode* pCNd = SwNodes::GoNext(&aIdx); if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
pModify = pCNd; else
{ const SwNode& rIdx = *pAnch->GetAnchorNode(); for(sw::SpzFrameFormat* pFlyFormat :*(pDrawFrameFormat->GetDoc().GetSpzFrameFormats()))
{ if( pFlyFormat->GetContent().GetContentIdx() &&
rIdx == pFlyFormat->GetContent().GetContentIdx()->GetNode() )
{
pModify = pFlyFormat; break;
}
}
}
} else
{
pModify = pAnch->GetAnchorNode()->GetContentNode();
}
}
// #i29199# - It is possible, that // the anchor doesn't exist - E.g., reordering the // sub-documents in a master document. // Note: The anchor will be inserted later. if ( !pModify )
{ // break to end of the current switch case. break;
}
// (2) drawing object isn't a control object to be anchored // in header/footer. constbool bControlInHF = ::CheckControlLayer(GetMaster()) && pFrame->FindFooterOrHeader(); // tdf#129542 but make an exception for control objects so they can get added to just the first frame, // the Master Anchor Frame and not the others if (bControlInHF && pAnchorFrameOfMaster) continue;
if (pFlyFormat)
{ // This is a master draw object and it has an associated fly format. // See if a fly frame is already inserted to the layout: if so, this // master draw object should be ordered directly before the fly one. if (const SwSortedObjs* pObjs = pFrame->GetDrawObjs())
{ for (const SwAnchoredObject* pAnchoredObj : *pObjs)
{ if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
{
SdrPage* pDrawPage = pAnchoredObj->GetDrawObj()->getSdrPageFromSdrObject(); if (pDrawPage)
{
sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum(); if (maAnchoredDrawObj.GetDrawObj()->GetOrdNum() >= nOrdNum)
{
pDrawPage->SetObjectOrdNum(maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect(), nOrdNum);
} else
{
pDrawPage->SetObjectOrdNum(nOrdNum, maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect() + 1);
} break;
}
}
}
}
}
void SwDrawContact::ChkPage()
{ if ( mbDisconnectInProgress )
{
OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." ); return;
}
// --> #i28701# // tdf#156287: use anchor page, not current bound rectangle's page, // because an object can't move to a page other than its anchor anyway
SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
? GetPageFrame()
: maAnchoredDrawObj.FindPageFrameOfAnchor(); if ( GetPageFrame() == pPg ) return;
// if drawing object is anchor in header/footer a change of the page // is a dramatic change. Thus, completely re-connect to the layout if ( maAnchoredDrawObj.GetAnchorFrame() &&
maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
{
ConnectToLayout();
} else
{ // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
maAnchoredDrawObj.RegisterAtPage(*pPg);
maAnchoredDrawObj.SetPageFrame( pPg );
}
}
// Important note: // method is called by method <SwDPage::ReplaceObject(..)>, which called its // corresponding superclass method <FmFormPage::ReplaceObject(..)>. // Note: 'master' drawing object *has* to be connected to layout triggered // by the caller of this, if method is called. void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
{
DisconnectFromLayout( false ); // consider 'virtual' drawing objects
RemoveAllVirtObjs();
/// get data collection of anchored objects, handled by with contact void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
{
o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
// AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj. // For paint, that offset is used by setting at the OutputDevice; for primitives this is // not possible since we have no OutputDevice, but define the geometry itself.
namespace sdr::contact
{ namespace {
class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
{ protected: /** * This method is responsible for creating the graphical visualisation data which is * stored/cached in the local primitive. Default gets view-independent Primitive from * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes * care of visibility, handles glue and ghosted. * * This method will not handle included hierarchies and not check geometric visibility.
*/ virtualvoid createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
class VCOfDrawVirtObj : public ViewContactOfVirtObj
{ protected: /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact. * * Always needs to return something. Default is to create a standard ViewObjectContact * containing the given ObjectContact and *this.
*/ virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
public: /// basic constructor, used from SdrObject. explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
: ViewContactOfVirtObj(rObj)
{
}
void VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
{ // this may be called for painting where it's a precondition that // isPrimitiveVisible() is true, or for e.g. getObjectRange() (even // during layout) where there are no preconditions... // nasty corner case: override to clear page frame to disable the // sub-objects' anchor check, because their anchor is always on // the first page that the page style is applied to
DisplayInfo aDisplayInfo(rDisplayInfo);
aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle()); const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact()); const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
drawinglayer::primitive2d::Primitive2DContainer xRetval;
// create offset transformation
basegfx::B2DHomMatrix aOffsetMatrix; const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) != nullptr)
{ // group object. Since the VOC/OC/VC hierarchy does not represent the // hierarchy virtual objects when they have group objects // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose) // to avoid multiple usages of VOCs (which would not work), the primitives // for the sub-hierarchy need to be collected here
// Get the VOC of the referenced object (the Group) and fetch primitives from it const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
} else
{ // single object, use method from referenced object to get the Primitive2DSequence
rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
}
const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
{ // #i26791# - use new member <maAnchoredDrawObj> return maAnchoredDrawObj.GetAnchorFrame();
}
SwFrame* SwDrawVirtObj::AnchorFrame()
{ // #i26791# - use new member <maAnchoredDrawObj> return maAnchoredDrawObj.AnchorFrame();
}
void SwDrawVirtObj::RemoveFromWriterLayout()
{ // remove contact object from frame for 'virtual' drawing object // #i26791# - use new member <maAnchoredDrawObj> if ( maAnchoredDrawObj.GetAnchorFrame() )
{
maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
}
}
// insert 'virtual' drawing object into page, set layer and user call.
SdrPage* pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject(); // default: insert before master object auto nOrdNum(GetReferencedObj().GetOrdNum());
// maintain invariant that a shape's textbox immediately follows the shape // also for the multiple SdrDrawVirtObj created for shapes in header/footer if (SwFrameFormat const*const pFlyFormat =
SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
{ // this is for the case when the flyframe SdrVirtObj is created before the draw one if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
{ for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
{ if (pAnchoredObj->GetFrameFormat() == pFlyFormat)
{
assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
if (pAnchoredObj->GetDrawObj()->GetOrdNum() >= GetReferencedObj().GetOrdNum())
{ // This virtual draw object has an associated fly one, but the fly's index // is not below the masters, fix it up. if (pDrawPg)
{
pDrawPg->SetObjectOrdNum(pAnchoredObj->GetDrawObj()->GetOrdNumDirect(), GetReferencedObj().GetOrdNum());
}
}
nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum(); // the master SdrObj should have the highest index
assert(nOrdNum < GetReferencedObj().GetOrdNum()); break;
}
}
} // this happens on initial insertion, the draw object is created first
SAL_INFO_IF(GetReferencedObj().GetOrdNum() == nOrdNum, "sw", "AddToDrawingPage: cannot find SdrObject for text box's shape");
}
// #i27030# - apply order number of referenced object if ( nullptr != pDrawPg )
{ // #i27030# - apply order number of referenced object
pDrawPg->InsertObject(this, nOrdNum);
} else
{
pDrawPg = getSdrPageFromSdrObject(); if ( pDrawPg )
{
pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), nOrdNum);
} else
{
SetOrdNum(nOrdNum);
}
}
SetUserCall( &mrDrawContact );
}
Point SwDrawVirtObj::GetOffset() const
{ // do NOT use IsEmpty() here, there is already a useful offset // in the position if (getOutRectangle() == tools::Rectangle())
{ return Point();
} else
{ return getOutRectangle().TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
}
}
void SwDrawVirtObj::SetBoundRectDirty()
{ // do nothing to not lose model information in aOutRect
}
void SwDrawVirtObj::RecalcBoundRect()
{ // #i26791# - switch order of calling <GetOffset()> and // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates // its value by the 'BoundRect' of the referenced object.
const Point aOffset(GetOffset());
setOutRectangle(ReferencedObj().GetCurrentBoundRect() + aOffset);
}
// override 'layer' methods for 'virtual' drawing object to assure // that layer of 'virtual' object is the layer of the referenced object.
SdrLayerID SwDrawVirtObj::GetLayer() const
{ return GetReferencedObj().GetLayer();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.