/* -*- 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 && " - 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( " - unknown nested 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( " - 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(!" - 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
--> --------------------
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.