summaryrefslogtreecommitdiffstats
path: root/sw/source/core/draw
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sw/source/core/draw
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/draw')
-rw-r--r--sw/source/core/draw/dcontact.cxx2632
-rw-r--r--sw/source/core/draw/dflyobj.cxx1295
-rw-r--r--sw/source/core/draw/dobjfac.cxx39
-rw-r--r--sw/source/core/draw/dpage.cxx262
-rw-r--r--sw/source/core/draw/drawdoc.cxx137
-rw-r--r--sw/source/core/draw/dview.cxx1019
6 files changed, 5384 insertions, 0 deletions
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
new file mode 100644
index 000000000..54e156710
--- /dev/null
+++ b/sw/source/core/draw/dcontact.cxx
@@ -0,0 +1,2632 @@
+/* -*- 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 .
+ */
+
+#include <memory>
+#include <hintids.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdviter.hxx>
+#include <svx/svdview.hxx>
+#include <svx/sdr/contact/displayinfo.hxx>
+#include <svx/sdr/contact/objectcontact.hxx>
+#include <svx/shapepropertynotifier.hxx>
+#include <drawdoc.hxx>
+#include <fmtornt.hxx>
+#include <viewimp.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtanchr.hxx>
+#include <node.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtfsize.hxx>
+#include <pam.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <frmtool.hxx>
+#include <flyfrm.hxx>
+#include <textboxhelper.hxx>
+#include <frmfmt.hxx>
+#include <fmtfollowtextflow.hxx>
+#include <dflyobj.hxx>
+#include <dcontact.hxx>
+#include <unodraw.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <doc.hxx>
+#include <hints.hxx>
+#include <txtfrm.hxx>
+#include <frameformats.hxx>
+#include <sortedobjs.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <calbck.hxx>
+#include <algorithm>
+#include <txtfly.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+ /** unary function used to find a 'virtual' drawing object anchored at a given frame */
+ struct VirtObjAnchoredAtFramePred
+ {
+ const SwFrame* m_pAnchorFrame;
+
+ // #i26791# - compare with master frame
+ static const SwFrame* FindFrame(const SwFrame* pFrame)
+ {
+ if(!pFrame || !pFrame->IsContentFrame())
+ return pFrame;
+ auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
+ while(pContentFrame->IsFollow())
+ pContentFrame = pContentFrame->FindMaster();
+ return pContentFrame;
+ }
+
+ VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
+ : m_pAnchorFrame(FindFrame(pAnchorFrame))
+ {}
+
+ bool operator()(const SwDrawVirtObjPtr& rpDrawVirtObj)
+ {
+ return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
+ }
+ };
+}
+
+void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
+{
+ if(!pObj || !pAnchor)
+ return;
+ short nWritingDirection =
+ pAnchor->IsVertical() ? text::WritingMode2::TB_RL :
+ pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
+ text::WritingMode2::LR_TB;
+ pObj->SetContextWritingMode(nWritingDirection);
+}
+
+
+/** 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 )
+{
+ SwFrameFormat* pRetval = nullptr;
+
+ if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
+ {
+ pRetval = pFlyDrawObj->GetFormat();
+ }
+ else
+ {
+ SwContact* pContact = GetUserCall(pObj);
+ if ( pContact )
+ {
+ pRetval = pContact->GetFormat();
+ }
+ }
+ return pRetval;
+}
+
+bool HasWrap( const SdrObject* pObj )
+{
+ if ( pObj )
+ {
+ const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
+ if ( pFormat )
+ {
+ return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
+ }
+ }
+
+ return false;
+}
+
+/// 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 )
+{
+ SdrObject *pTmp;
+ while ( !pObj->GetUserCall() && nullptr != (pTmp = pObj->getParentSdrObjectFromSdrObject()) )
+ pObj = pTmp;
+ assert((!pObj->GetUserCall() || nullptr != dynamic_cast<const SwContact*>(pObj->GetUserCall())) &&
+ "<::GetUserCall(..)> - wrong type of found object user call." );
+ return static_cast<SwContact*>(pObj->GetUserCall());
+}
+
+/// 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())
+ return false;
+ SdrTextAniKind eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind();
+ return ( SdrTextAniKind::Scroll == eTKind
+ || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
+}
+
+SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
+ SwClient( pToRegisterIn ),
+ mbInDTOR( false )
+{}
+
+SwContact::~SwContact()
+{
+ SetInDTOR();
+}
+
+
+void SwContact::SetInDTOR()
+{
+ mbInDTOR = true;
+}
+
+/// 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.
+ const bool 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.
+ const bool 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( const bool _bToVisible,
+ SdrObject* _pDrawObj )
+{
+ if ( !_pDrawObj )
+ {
+ OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
+ return;
+ }
+
+ if ( !GetRegisteredIn() )
+ {
+ OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
+ return;
+ }
+
+ const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
+
+ SdrLayerID nToHellLayerId =
+ _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
+ SdrLayerID nToHeavenLayerId =
+ _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
+ SdrLayerID nToControlLayerId =
+ _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
+ SdrLayerID nFromHellLayerId =
+ _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
+ SdrLayerID nFromHeavenLayerId =
+ _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
+ SdrLayerID nFromControlLayerId =
+ _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
+
+ 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;
+ }
+ else if ( _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 );
+ }
+
+ // call method recursively for group object members
+ const SdrObjList* pLst =
+ static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
+ if ( pLst )
+ {
+ for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
+ {
+ MoveObjToLayer( _bToVisible, pLst->GetObj( i ) );
+ }
+ }
+ }
+ else
+ {
+ const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
+ if ( nLayerIdOfObj == nFromHellLayerId )
+ {
+ _pDrawObj->SetLayer( nToHellLayerId );
+ }
+ else if ( nLayerIdOfObj == nFromHeavenLayerId )
+ {
+ _pDrawObj->SetLayer( nToHeavenLayerId );
+ }
+ else if ( nLayerIdOfObj == nFromControlLayerId )
+ {
+ _pDrawObj->SetLayer( nToControlLayerId );
+ }
+ }
+}
+
+/// get minimum order number of anchored objects handled by with contact
+sal_uInt32 SwContact::GetMinOrdNum() const
+{
+ sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
+
+ std::vector< SwAnchoredObject* > aObjs;
+ GetAnchoredObjs( aObjs );
+
+ while ( !aObjs.empty() )
+ {
+ sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
+
+ if ( nTmpOrdNum < nMinOrdNum )
+ {
+ nMinOrdNum = nTmpOrdNum;
+ }
+
+ aObjs.pop_back();
+ }
+
+ OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
+ "<SwContact::GetMinOrdNum()> - no order number found." );
+ return nMinOrdNum;
+}
+
+/// get maximum order number of anchored objects handled by with contact
+sal_uInt32 SwContact::GetMaxOrdNum() const
+{
+ sal_uInt32 nMaxOrdNum( 0 );
+
+ std::vector< SwAnchoredObject* > aObjs;
+ GetAnchoredObjs( aObjs );
+
+ while ( !aObjs.empty() )
+ {
+ sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
+
+ if ( nTmpOrdNum > nMaxOrdNum )
+ {
+ nMaxOrdNum = nTmpOrdNum;
+ }
+
+ aObjs.pop_back();
+ }
+
+ return nMaxOrdNum;
+}
+
+namespace
+{
+ Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool 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 (auto pFindSdrObjectHint = dynamic_cast<const sw::FindSdrObjectHint*>(&rHint))
+ {
+ if(!pFindSdrObjectHint->m_rpObject)
+ pFindSdrObjectHint->m_rpObject = GetMaster();
+ }
+ else if (auto pWW8AnchorConvHint = dynamic_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;
+ const bool 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.
+
+ IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
+ SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
+ SwVirtFlyDrawObj* pDrawObj(
+ new SwVirtFlyDrawObj(
+ pContact->GetMaster()->getSdrModelFromSdrObject(),
+ *pContact->GetMaster(),
+ pFly));
+ pDrawObj->SetUserCall(pContact);
+
+ // 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, nOrdNum);
+ }
+ // #i27030# - insert new <SwVirtFlyDrawObj> instance
+ // into drawing page with correct order number
+ else
+ rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
+ // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
+ // is in a visible layer.
+ pContact->MoveObjToVisibleLayer(pDrawObj);
+ return pDrawObj;
+}
+
+// #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");
+
+ const SwAnchoredObject *const pRetAnchoredObj =
+ static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
+
+ return pRetAnchoredObj;
+}
+
+SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
+{
+ return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
+}
+
+SdrObject* SwFlyDrawContact::GetMaster()
+{
+ return mpMasterObj.get();
+}
+
+/**
+ * @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;
+ }
+
+ SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
+
+ // #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;
+ }
+
+ SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
+
+ 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(auto pGetZOrdnerHint = dynamic_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
+
+bool CheckControlLayer( const SdrObject *pObj )
+{
+ if ( SdrInventor::FmForm == pObj->GetObjInventor() )
+ return true;
+ if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
+ {
+ const SdrObjList *pLst = pObjGroup->GetSubList();
+ for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
+ {
+ if ( ::CheckControlLayer( pLst->GetObj( i ) ) )
+ {
+ // #i18447# - return correct value ;-)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+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 )
+ {
+ SdrObject* pObject = const_cast< SdrObject* >( maAnchoredDrawObj.GetDrawObj() );
+ SdrObject::Free( pObject );
+ }
+}
+
+void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
+{
+ for(auto& rpFly : *rDoc.GetSpzFrameFormats())
+ {
+ if(dynamic_cast<const SwDrawFrameFormat*>(rpFly))
+ rpFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
+ }
+}
+
+// #i26791#
+const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
+{
+ // handle default parameter value
+ if (!pSdrObj)
+ {
+ pSdrObj = GetMaster();
+ }
+
+ assert(pSdrObj);
+ assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
+ dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
+ assert((GetUserCall(pSdrObj) == this ||
+ pSdrObj == GetMaster()) &&
+ "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
+
+ const SwAnchoredObject* pRetAnchoredObj = nullptr;
+
+ if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
+ {
+ pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
+ }
+ else
+ {
+ assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
+ pRetAnchoredObj = &maAnchoredDrawObj;
+ }
+
+ return pRetAnchoredObj;
+}
+
+SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
+{
+ return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
+}
+
+SdrObject* SwDrawContact::GetMaster()
+{
+ return !mbMasterObjCleared
+ ? maAnchoredDrawObj.DrawObj()
+ : nullptr;
+}
+
+const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
+{
+ const SwFrame* pAnchorFrame = nullptr;
+ if ( !_pDrawObj ||
+ _pDrawObj == GetMaster() ||
+ ( !_pDrawObj->GetUserCall() &&
+ GetUserCall( _pDrawObj ) == this ) )
+ {
+ pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
+ }
+ else
+ {
+ assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) != nullptr);
+ pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
+ }
+
+ return pAnchorFrame;
+}
+
+SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
+{
+ return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
+}
+
+/** add a 'virtual' drawing object to drawing page.
+ */
+SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
+{
+ maDrawVirtObjs.push_back(
+ SwDrawVirtObjPtr(
+ new SwDrawVirtObj(
+ GetMaster()->getSdrModelFromSdrObject(),
+ *GetMaster(),
+ *this)));
+ maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
+ return maDrawVirtObjs.back().get();
+}
+
+/// remove 'virtual' drawing objects and destroy them.
+void SwDrawContact::RemoveAllVirtObjs()
+{
+ for(auto& rpDrawVirtObj : maDrawVirtObjs)
+ {
+ // remove and destroy 'virtual object'
+ rpDrawVirtObj->RemoveFromWriterLayout();
+ rpDrawVirtObj->RemoveFromDrawingPage();
+ }
+ maDrawVirtObjs.clear();
+}
+
+
+/// get drawing object ('master' or 'virtual') by frame.
+SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
+{
+ SdrObject* pRetDrawObj = nullptr;
+
+ // #i26791# - compare master frames instead of direct frames
+ const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
+ if ( pProposedAnchorFrame->IsContentFrame() )
+ {
+ const SwContentFrame* pTmpFrame =
+ static_cast<const SwContentFrame*>( pProposedAnchorFrame );
+ while ( pTmpFrame->IsFollow() )
+ {
+ pTmpFrame = pTmpFrame->FindMaster();
+ }
+ pProposedAnchorFrame = pTmpFrame;
+ }
+
+ const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
+ if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
+ {
+ const SwContentFrame* pTmpFrame =
+ static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
+ while ( pTmpFrame->IsFollow() )
+ {
+ pTmpFrame = pTmpFrame->FindMaster();
+ }
+ pMasterObjAnchorFrame = pTmpFrame;
+ }
+
+ if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
+ {
+ pRetDrawObj = GetMaster();
+ }
+ else
+ {
+ const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
+ VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
+ if(ppFoundVirtObj != maDrawVirtObjs.end())
+ pRetDrawObj = ppFoundVirtObj->get();
+ }
+
+ return pRetDrawObj;
+}
+
+void SwDrawContact::NotifyBackgroundOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
+{
+ for(const auto& rpDrawVirtObj : maDrawVirtObjs)
+ {
+ SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
+ if ( pDrawVirtObj->GetAnchorFrame() )
+ {
+ // #i34640# - determine correct page frame
+ SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
+ if( pOldBoundRect && pPage )
+ {
+ SwRect aOldRect( *pOldBoundRect );
+ aOldRect.Pos() += pDrawVirtObj->GetOffset();
+ if( aOldRect.HasArea() )
+ ::Notify_Background( pDrawVirtObj, pPage,
+ aOldRect, PrepareHint::FlyFrameLeave,true);
+ }
+ // #i34640# - include spacing for wrapping
+ SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
+ if (aRect.HasArea() && pPage)
+ {
+ SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
+ if ( pPg )
+ ::Notify_Background( pDrawVirtObj, pPg, aRect,
+ PrepareHint::FlyFrameArrive, true );
+ }
+ ::ClrContourCache( pDrawVirtObj );
+ }
+ }
+}
+
+/// local method to notify the background for a drawing object - #i26791#
+static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
+ const SdrObject& _rObj,
+ const tools::Rectangle* _pOldObjRect )
+{
+ // #i34640#
+ SwAnchoredObject* pAnchoredObj =
+ const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
+ if ( !(pAnchoredObj && pAnchoredObj->GetAnchorFrame()) )
+ return;
+
+ // #i34640# - determine correct page frame
+ SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
+ if( _pOldObjRect && pPageFrame )
+ {
+ SwRect aOldRect( *_pOldObjRect );
+ if( aOldRect.HasArea() )
+ {
+ // #i34640# - determine correct page frame
+ SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
+ ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
+ PrepareHint::FlyFrameLeave, true);
+ }
+ }
+ // #i34640# - include spacing for wrapping
+ SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
+ if( aNewRect.HasArea() && pPageFrame )
+ {
+ pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
+ ::Notify_Background( &_rObj, pPageFrame, aNewRect,
+ PrepareHint::FlyFrameArrive, true );
+ }
+ ClrContourCache( &_rObj );
+}
+
+void SwDrawContact::Changed( const SdrObject& rObj,
+ SdrUserCallType eType,
+ const tools::Rectangle& rOldBoundRect )
+{
+ // #i26791# - no event handling, if existing <SwViewShell>
+ // is in construction
+ SwDoc* pDoc = GetFormat()->GetDoc();
+ if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
+ pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
+ {
+ return;
+ }
+
+ // #i44339#
+ // no event handling, if document is in destruction.
+ // Exception: It's the SdrUserCallType::Delete event
+ if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
+ {
+ return;
+ }
+
+ //Put on Action, but not if presently anywhere an action runs.
+ bool bHasActions(true);
+ SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+ if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
+ {
+ SwViewShell* const pSh = pDoc->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;
+
+ public:
+ NestedUserCallHdl( SwDrawContact* _pDrawContact,
+ SdrUserCallType _eEventType )
+ : mpDrawContact( _pDrawContact ),
+ mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
+ meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
+ {
+ mpDrawContact->mbUserCallActive = true;
+ mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
+ }
+
+ ~NestedUserCallHdl()
+ {
+ if ( mpDrawContact )
+ {
+ mpDrawContact->mbUserCallActive = mbParentUserCallActive;
+ mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
+ }
+ }
+
+ void DrawContactDeleted()
+ {
+ mpDrawContact = nullptr;
+ }
+
+ bool IsNestedUserCall() const
+ {
+ return mbParentUserCallActive;
+ }
+
+ 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;
+ }
+ else if ( 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.
+static void 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.
+ const bool bAnchoredAsChar = ObjAnchoredAsChar();
+ const bool 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;
+ delete this;
+ // --> #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 ) );
+
+ /* protect against NULL pointer dereferencing */
+ if(!pAnchoredDrawObj)
+ {
+ break;
+ }
+
+ // #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();
+
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::changeAnchor, GetFormat(), &const_cast<SdrObject&>(rObj));
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::syncTextBoxSize, GetFormat(), &const_cast<SdrObject&>(rObj));
+
+ }
+ SwTwips nXPosDiff(0);
+ SwTwips nYPosDiff(0);
+ switch ( eLayoutDir )
+ {
+ case SwFrameFormat::HORI_L2R:
+ {
+ nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
+ nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
+ }
+ break;
+ case SwFrameFormat::HORI_R2L:
+ {
+ nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
+ nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
+ }
+ break;
+ case SwFrameFormat::VERT_R2L:
+ {
+ nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
+ nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
+ }
+ break;
+ default:
+ {
+ assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
+ }
+ }
+ SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> aSet( GetFormat()->GetDoc()->GetAttrPool() );
+ const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
+ if ( nYPosDiff != 0 )
+ {
+ if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
+ rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nYPosDiff = -nYPosDiff;
+ }
+ aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
+ text::VertOrientation::NONE,
+ rVert.GetRelationOrient() ) );
+ }
+
+ const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
+ if ( !bAnchoredAsChar && nXPosDiff != 0 )
+ {
+ aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
+ text::HoriOrientation::NONE,
+ rHori.GetRelationOrient() ) );
+ }
+
+ 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 );
+ }
+ else if ( 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());
+ }
+ else if (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* const pDoc = GetFormat()->GetDoc();
+
+ // avoid Undo creation
+ ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
+
+ // hide any artificial "changes" made by synchronizing the textbox position
+ const bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
+ pDoc->getIDocumentState().SetEnableSetModified(false);
+
+ SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>
+ aSyncSet( pDoc->GetAttrPool() );
+ aSyncSet.Put(GetFormat()->GetHoriOrient());
+ bool bRelToTableCell(false);
+ aSyncSet.Put(SwFormatVertOrient(pAnchoredDrawObj->GetRelPosToPageFrame(false, bRelToTableCell).getY(),
+ text::VertOrientation::NONE,
+ text::RelOrientation::PAGE_FRAME));
+ aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, rPageFrame->GetPhyPageNum()));
+
+ auto pSdrObj = const_cast<SdrObject*>(&rObj);
+ if (pSdrObj != GetFormat()->FindRealSdrObject())
+ {
+ SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet( pDoc->GetAttrPool() );
+
+ aSet.Put(aSyncSet);
+ aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
+ SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);
+
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(
+ &SwTextBoxHelper::changeAnchor, GetFormat(),
+ GetFormat()->FindRealSdrObject());
+ SwTextBoxHelper::synchronizeGroupTextBoxProperty(
+ &SwTextBoxHelper::syncTextBoxSize, GetFormat(),
+ GetFormat()->FindRealSdrObject());
+ }
+ else
+ SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());
+
+ pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
+ }
+ }
+ break;
+ case SdrUserCallType::ChangeAttr:
+ if ( bNotify )
+ {
+ lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+namespace
+{
+ const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
+ {
+ sal_uInt16 nWhich = _rItem.Which();
+ const SwFormatAnchor* pAnchorFormat = nullptr;
+ if ( RES_ATTRSET_CHG == nWhich )
+ {
+ pAnchorFormat = static_cast<const SwAttrSetChg&>(_rItem).GetChgSet()->
+ GetItemIfSet( RES_ANCHOR, false );
+ }
+ else if ( RES_ANCHOR == nWhich )
+ {
+ pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
+ }
+ return pAnchorFormat;
+ }
+}
+
+void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
+{
+ SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
+ SwContact::SwClientNotify(rMod, rHint);
+ if (rHint.GetId() == SfxHintId::SwLegacyModify)
+ {
+ auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
+ SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
+
+ const SfxPoolItem* pNew = pLegacyHint->m_pNew;
+ sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
+ if(const SwFormatAnchor* pNewAnchorFormat = pNew ? lcl_getAnchorFormat(*pNew) : nullptr)
+ {
+ // 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);
+
+ const SwFormatAnchor* pOldAnchorFormat = pLegacyHint->m_pOld ? lcl_getAnchorFormat(*pLegacyHint->m_pOld) : nullptr;
+ if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
+ {
+ if(maAnchoredDrawObj.DrawObj())
+ {
+ // --> #i102752#
+ // assure that a ShapePropertyChangeNotifier exists
+ maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(svx::ShapePropertyProviderId::TextDocAnchor);
+ }
+ else
+ SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
+ }
+ }
+ }
+ else
+ DisconnectFromLayout();
+ }
+ else if (nWhich == RES_REMOVE_UNO_OBJECT)
+ {} // nothing to do
+ // --> #i62875# - no further notification, if not connected to Writer layout
+ else if ( maAnchoredDrawObj.GetAnchorFrame() &&
+ maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
+ {
+ bool bUpdateSortedObjsList(false);
+ 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;
+ case RES_ATTRSET_CHG: // #i35443#
+ {
+ auto pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
+ if(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;
+ }
+ break;
+ default:
+ assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
+ }
+ lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
+ NotifyBackgroundOfAllVirtObjs(nullptr);
+ InvalidateObjs_(bUpdateSortedObjsList);
+ }
+
+ // #i51474#
+ GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
+ }
+ else if (auto pDrawFrameFormatHint = dynamic_cast<const sw::DrawFrameFormatHint*>(&rHint))
+ {
+ switch(pDrawFrameFormatHint->m_eId)
+ {
+ case sw::DrawFrameFormatHintId::DYING:
+ delete this;
+ 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:
+ ;
+ }
+ }
+ else if (auto pCheckDrawFrameFormatLayerHint = dynamic_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint))
+ {
+ *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
+ }
+ else if (auto pContactChangedHint = dynamic_cast<const sw::ContactChangedHint*>(&rHint))
+ {
+ if(!*pContactChangedHint->m_ppObject)
+ *pContactChangedHint->m_ppObject = GetMaster();
+ auto pObject = *pContactChangedHint->m_ppObject;
+ Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
+ }
+ else if (auto pDrawFormatLayoutCopyHint = dynamic_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint))
+ {
+ const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
+ new SwDrawContact(
+ &pDrawFormatLayoutCopyHint->m_rDestFormat,
+ pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
+ *GetMaster(),
+ pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc()));
+ // #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();
+ }
+ else if (auto pRestoreFlyAnchorHint = dynamic_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);
+ }
+ else if (auto pCreatePortionHint = dynamic_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());
+ }
+ }
+ else if (auto pCollectTextObjectsHint = dynamic_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())
+ {
+ SdrObject* pSdrOElement = aListIter.Next();
+ auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrOElement));
+ if(pTextObj && pTextObj->HasText())
+ pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
+ }
+ }
+ else if(auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrO)))
+ {
+ if(pTextObj->HasText())
+ pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
+ }
+ }
+ else if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
+ {
+ auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
+ if(pFormat->Which() == RES_DRAWFRMFMT)
+ pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
+ }
+ else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint))
+ {
+ pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
+ }
+}
+
+// #i26791#
+// #i28701# - added parameter <_bUpdateSortedObjsList>
+void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
+{
+ for(const auto& 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();
+ }
+}
+
+void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
+{
+ mbDisconnectInProgress = true;
+
+ // --> #i36181# - notify background of drawing object
+ if ( _bMoveMasterToInvisibleLayer &&
+ !(GetFormat()->GetDoc()->IsInDtor()) &&
+ GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
+ {
+ const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
+ lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
+ NotifyBackgroundOfAllVirtObjs( &aOldRect );
+ }
+
+ // remove 'virtual' drawing objects from writer
+ // layout and from drawing page
+ for(auto& rpVirtDrawObj : maDrawVirtObjs)
+ {
+ rpVirtDrawObj->RemoveFromWriterLayout();
+ rpVirtDrawObj->RemoveFromDrawingPage();
+ }
+
+ if ( maAnchoredDrawObj.GetAnchorFrame() )
+ {
+ maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
+ }
+
+ if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
+ {
+ SdrViewIter aIter( GetMaster() );
+ for( SdrView* pView = aIter.FirstView(); pView;
+ pView = aIter.NextView() )
+ {
+ pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
+ }
+
+ // 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
+ {
+ const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
+ [] (const SwDrawVirtObjPtr& 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();
+ }
+ }
+}
+
+static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
+ SwPosition const& rAnchorPos)
+{
+ SwTextFrame* pAct = _pProposedAnchorFrame;
+ SwTextFrame* pTmp;
+ TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
+ do
+ {
+ pTmp = pAct;
+ pAct = pTmp->GetFollow();
+ }
+ while (pAct && nTextOffset >= pAct->GetOffset());
+ return pTmp;
+}
+
+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;
+ }
+
+ SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
+
+ if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
+ 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());
+ }
+
+ switch ( pAnch->GetAnchorId() )
+ {
+ case RndStdIds::FLY_AT_PAGE:
+ {
+ sal_uInt16 nPgNum = pAnch->GetPageNum();
+ SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
+ if( !pShell )
+ break;
+ SwRootFrame* pRoot = pShell->GetLayout();
+ SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
+
+ 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->GetContentAnchor() )
+ {
+ if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
+ {
+ SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
+ SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
+ if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
+ pModify = pCNd;
+ else
+ {
+ const SwNodeIndex& rIdx = pAnch->GetContentAnchor()->nNode;
+ SwFrameFormats& rFormats = *(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats());
+ for( auto pFlyFormat : rFormats )
+ {
+ if( pFlyFormat->GetContent().GetContentIdx() &&
+ rIdx == *(pFlyFormat->GetContent().GetContentIdx()) )
+ {
+ pModify = pFlyFormat;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ pModify = pAnch->GetContentAnchor()->nNode.GetNode().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;
+ }
+
+ SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
+ SwFrame* pAnchorFrameOfMaster = nullptr;
+ for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
+ {
+ // append drawing object, if
+ // (1) proposed anchor frame isn't a follow and...
+ const bool bFollow = pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->IsFollow();
+ if (bFollow)
+ continue;
+
+ // (2) drawing object isn't a control object to be anchored
+ // in header/footer.
+ const bool 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;
+
+ bool bAdd;
+ if (RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId())
+ bAdd = true;
+ else
+ {
+ assert(pFrame->IsTextFrame());
+ bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
+ }
+
+ if( bAdd )
+ {
+ if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
+ {
+ pFrame = pFrame->FindFlyFrame();
+ assert(pFrame);
+ }
+
+ // find correct follow for as character anchored objects
+ if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
+ pFrame->IsTextFrame() )
+ {
+ pFrame = lcl_GetFlyInContentAnchor(
+ static_cast<SwTextFrame*>(pFrame),
+ *pAnch->GetContentAnchor());
+ }
+
+ if ( !pAnchorFrameOfMaster )
+ {
+ // append 'master' drawing object
+ pAnchorFrameOfMaster = pFrame;
+ pFrame->AppendDrawObj( maAnchoredDrawObj );
+ }
+ else
+ {
+ // append 'virtual' drawing object
+ SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
+ if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
+ {
+ ClrContourCache( pDrawVirtObj );
+ }
+ pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
+
+ pDrawVirtObj->ActionChanged();
+ }
+
+ if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
+ {
+ pFrame->InvalidatePrt();
+ }
+ }
+ }
+ }
+ break;
+ default:
+ assert(!"Unknown Anchor.");
+ break;
+ }
+ if ( GetAnchorFrame() )
+ {
+ ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
+ // #i26791# - invalidate objects instead of direct positioning
+ InvalidateObjs_();
+ }
+}
+
+/// insert 'master' drawing object into drawing page
+void SwDrawContact::InsertMasterIntoDrawPage()
+{
+ if ( !GetMaster()->IsInserted() )
+ {
+ GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
+ ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
+ }
+ GetMaster()->SetUserCall( this );
+}
+
+SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
+{
+ // --> #i28701# - use method <GetPageFrame()>
+ SwPageFrame* pPg = GetPageFrame();
+ if ( !pPg && GetAnchorFrame() )
+ pPg = GetAnchorFrame()->FindPageFrame();
+ if ( pPg )
+ pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
+ return pPg;
+}
+
+void SwDrawContact::ChkPage()
+{
+ if ( mbDisconnectInProgress )
+ {
+ OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
+ return;
+ }
+
+ // --> #i28701#
+ SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
+ maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
+ ? GetPageFrame()
+ : FindPage( SwRect(GetMaster()->GetCurrentBoundRect()) );
+ 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>
+ if ( GetPageFrame() )
+ GetPageFrame()->RemoveDrawObjFromPage( maAnchoredDrawObj );
+ pPg->AppendDrawObjToPage( maAnchoredDrawObj );
+ 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();
+
+ GetMaster()->SetUserCall( nullptr );
+ if(pNewMaster)
+ maAnchoredDrawObj.SetDrawObj(*pNewMaster);
+ else
+ mbMasterObjCleared = true;
+ GetMaster()->SetUserCall( this );
+
+ InvalidateObjs_();
+}
+
+/// 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));
+
+ for(auto& rpDrawVirtObj : maDrawVirtObjs)
+ o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
+}
+
+// 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.
+ */
+ virtual void createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
+ : ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
+ {
+ }
+ };
+
+ 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)
+ {
+ }
+
+ /// access to SwDrawVirtObj
+ SwDrawVirtObj& GetSwDrawVirtObj() const
+ {
+ return static_cast<SwDrawVirtObj&>(mrObject);
+ }
+ };
+
+ }
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+{
+ /// recursively collect primitive data from given VOC with given offset
+ static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
+ {
+ const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
+
+ for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
+ {
+ const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
+
+ if(rCandidate.GetViewContact().GetObjectCount())
+ {
+ // is a group object itself, call recursively
+ impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
+ }
+ else
+ {
+ // single object, add primitives; check model-view visibility
+ if(rCandidate.isPrimitiveVisible(rDisplayInfo))
+ {
+ drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
+
+ if(!aNewSequence.empty())
+ {
+ // get ranges
+ const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
+ const basegfx::B2DRange& aViewRange(rViewInformation2D.getViewport());
+ basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
+
+ // correct with virtual object's offset
+ aObjectRange.transform(rOffsetMatrix);
+
+ // check geometrical visibility (with offset)
+ if(!aViewRange.overlaps(aObjectRange))
+ {
+ // not visible, release
+ aNewSequence.clear();
+ }
+ }
+
+ if(!aNewSequence.empty())
+ {
+ rxTarget.append(aNewSequence);
+ }
+ }
+ }
+ }
+ }
+
+ void VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ // tdf#91260 have already checked top-level one is on the right page
+ assert(isPrimitiveVisible(rDisplayInfo));
+ // 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(aLocalOffset.X() || aLocalOffset.Y())
+ {
+ aOffsetMatrix.set(0, 2, aLocalOffset.X());
+ aOffsetMatrix.set(1, 2, aLocalOffset.Y());
+ }
+
+ 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);
+ }
+
+ if(!xRetval.empty())
+ {
+ // create transform primitive
+ drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, std::move(xRetval)));
+ xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
+ }
+
+ rVisitor.visit(xRetval);
+ }
+
+ ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
+ {
+ return *(new VOCOfDrawVirtObj(rObjectContact, *this));
+ }
+
+} // end of namespace sdr::contact
+
+/// implementation of class <SwDrawVirtObj>
+std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
+}
+
+SwDrawVirtObj::SwDrawVirtObj(
+ SdrModel& rSdrModel,
+ SdrObject& _rNewObj,
+ SwDrawContact& _rDrawContact)
+: SdrVirtObj(rSdrModel, _rNewObj ),
+ mrDrawContact(_rDrawContact)
+{
+ // #i26791#
+ maAnchoredDrawObj.SetDrawObj( *this );
+
+ // #i35635# - set initial position out of sight
+ NbcMove( Size( -16000, -16000 ) );
+}
+
+SwDrawVirtObj::SwDrawVirtObj(
+ SdrModel& rSdrModel,
+ SwDrawVirtObj const & rSource)
+: SdrVirtObj(rSdrModel, rSource),
+ mrDrawContact(rSource.mrDrawContact)
+{
+ // #i26791#
+ maAnchoredDrawObj.SetDrawObj( *this );
+
+ // #i35635# - set initial position out of sight
+ NbcMove( Size( -16000, -16000 ) );
+
+ // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
+ // haven't to be considered.
+}
+
+SwDrawVirtObj::~SwDrawVirtObj()
+{
+}
+
+SwDrawVirtObj* SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SwDrawVirtObj(rTargetModel, *this);
+}
+
+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 );
+ }
+}
+
+void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
+{
+ // determine 'master'
+ SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
+
+ // 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));
+ 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 );
+}
+
+void SwDrawVirtObj::RemoveFromDrawingPage()
+{
+ SetUserCall( nullptr );
+ if ( getSdrPageFromSdrObject() )
+ {
+ getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
+ }
+}
+
+/// Is 'virtual' drawing object connected to writer layout and to drawing layer?
+bool SwDrawVirtObj::IsConnected() const
+{
+ bool bRetVal = GetAnchorFrame() &&
+ ( getSdrPageFromSdrObject() && GetUserCall() );
+
+ return bRetVal;
+}
+
+void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
+{
+ SdrObject::NbcSetAnchorPos( rPnt );
+}
+
+// #i97197#
+// the methods relevant for positioning
+
+const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
+{
+ if(m_aOutRect.IsEmpty())
+ {
+ const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
+ }
+
+ return m_aOutRect;
+}
+
+const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
+{
+ return m_aOutRect;
+}
+
+Point SwDrawVirtObj::GetOffset() const
+{
+ // do NOT use IsEmpty() here, there is already a useful offset
+ // in the position
+ if(m_aOutRect == tools::Rectangle())
+ {
+ return Point();
+ }
+ else
+ {
+ return m_aOutRect.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());
+ m_aOutRect = ReferencedObj().GetCurrentBoundRect() + aOffset;
+}
+
+basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
+{
+ basegfx::B2DPolyPolygon aRetval(rRefObj.TakeXorPoly());
+ aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
+
+ return aRetval;
+}
+
+basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
+{
+ basegfx::B2DPolyPolygon aRetval(rRefObj.TakeContour());
+ aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
+
+ return aRetval;
+}
+
+void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrHdlList tmpList(nullptr);
+ rRefObj.AddToHdlList(tmpList);
+
+ size_t cnt = tmpList.GetHdlCount();
+ for(size_t i=0; i < cnt; ++i)
+ {
+ SdrHdl* pHdl = tmpList.GetHdl(i);
+ Point aP(pHdl->GetPos() + GetOffset());
+ pHdl->SetPos(aP);
+ }
+ tmpList.MoveTo(rHdlList);
+}
+
+void SwDrawVirtObj::NbcMove(const Size& rSiz)
+{
+ SdrObject::NbcMove( rSiz );
+}
+
+void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ rRefObj.NbcResize(rRef - GetOffset(), xFact, yFact);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SwDrawVirtObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ rRefObj.NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ rRefObj.NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
+ SetBoundAndSnapRectsDirty();
+}
+
+void SwDrawVirtObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ rRefObj.NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
+ SetBoundAndSnapRectsDirty();
+}
+
+void SwDrawVirtObj::Move(const Size& rSiz)
+{
+ SdrObject::Move( rSiz );
+}
+
+void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
+{
+ if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
+ {
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ rRefObj.Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+ }
+}
+
+void SwDrawVirtObj::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
+{
+ if(nAngle)
+ {
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ rRefObj.Rotate(rRef - GetOffset(), nAngle, sn, cs);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+ }
+}
+
+void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
+{
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ rRefObj.Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+}
+
+void SwDrawVirtObj::Shear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
+{
+ if(nAngle)
+ {
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ rRefObj.Shear(rRef - GetOffset(), nAngle, tn, bVShear);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+ }
+}
+
+void SwDrawVirtObj::RecalcSnapRect()
+{
+ aSnapRect = rRefObj.GetSnapRect();
+ aSnapRect += GetOffset();
+}
+
+const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
+{
+ const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetSnapRect();
+ const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
+
+ return aSnapRect;
+}
+
+void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ tools::Rectangle aR(rRect);
+ aR -= GetOffset();
+ rRefObj.SetSnapRect(aR);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+}
+
+void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aR(rRect);
+ aR -= GetOffset();
+ SetBoundAndSnapRectsDirty();
+ rRefObj.NbcSetSnapRect(aR);
+}
+
+const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
+{
+ const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetLogicRect();
+ const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
+
+ return aSnapRect;
+}
+
+void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aBoundRect0; if(m_pUserCall) aBoundRect0 = GetLastBoundRect();
+ tools::Rectangle aR(rRect);
+ aR -= GetOffset();
+ rRefObj.SetLogicRect(aR);
+ SetBoundAndSnapRectsDirty();
+ SendUserCall(SdrUserCallType::Resize, aBoundRect0);
+}
+
+void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
+{
+ tools::Rectangle aR(rRect);
+ aR -= GetOffset();
+ rRefObj.NbcSetLogicRect(aR);
+ SetBoundAndSnapRectsDirty();
+}
+
+Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
+{
+ Point aP(rRefObj.GetSnapPoint(i));
+ aP += GetOffset();
+
+ return aP;
+}
+
+Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
+{
+ return rRefObj.GetPoint(i) + GetOffset();
+}
+
+void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
+{
+ Point aP(rPnt);
+ aP -= GetOffset();
+ rRefObj.SetPoint(aP, i);
+ SetBoundAndSnapRectsDirty();
+}
+
+bool SwDrawVirtObj::HasTextEdit() const
+{
+ return rRefObj.HasTextEdit();
+}
+
+// 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();
+}
+
+void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
+{
+ ReferencedObj().NbcSetLayer( nLayer );
+ SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
+}
+
+void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
+{
+ ReferencedObj().SetLayer( nLayer );
+ SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
new file mode 100644
index 000000000..3203bbc8d
--- /dev/null
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -0,0 +1,1295 @@
+/* -*- 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 .
+ */
+
+#include <hintids.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <svx/svdhdl.hxx>
+#include <svx/svdtrans.hxx>
+#include <editeng/protitem.hxx>
+#include <svx/svdpage.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/ptrstyle.hxx>
+
+#include <fmtclds.hxx>
+#include <fmtornt.hxx>
+#include <fmtfsize.hxx>
+#include <fmturl.hxx>
+#include <viewsh.hxx>
+#include <frmatr.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <dflyobj.hxx>
+#include <flyfrm.hxx>
+#include <frmfmt.hxx>
+#include <viewopt.hxx>
+#include <frmtool.hxx>
+#include <flyfrms.hxx>
+#include <ndnotxt.hxx>
+#include <grfatr.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <textboxhelper.hxx>
+#include <wrtsh.hxx>
+#include <ndgrf.hxx>
+#include <frmmgr.hxx>
+
+#include <svx/sdr/properties/defaultproperties.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+// AW: For VCOfDrawVirtObj and stuff
+#include <svx/sdr/contact/viewcontactofvirtobj.hxx>
+#include <drawinglayer/primitive2d/BufferedDecompositionPrimitive2D.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <sw_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <notxtfrm.hxx>
+
+using namespace ::com::sun::star;
+
+static bool bInResize = false;
+
+
+namespace sdr::contact
+{
+ namespace {
+
+ /**
+ * @see #i95264#
+ *
+ * currently needed since createViewIndependentPrimitive2DSequence() is called when
+ * RecalcBoundRect() is used. There should currently no VOCs being constructed since it
+ * gets not visualized (instead the corresponding SwVirtFlyDrawObj's referencing this one
+ * are visualized).
+ */
+ class VCOfSwFlyDrawObj : public ViewContactOfSdrObj
+ {
+ protected:
+ /** This method is responsible for creating the graphical visualisation data
+ *
+ * @note ONLY based on model data
+ */
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ /// basic constructor, used from SdrObject.
+ explicit VCOfSwFlyDrawObj(SwFlyDrawObj& rObj)
+ : ViewContactOfSdrObj(rObj)
+ {
+ }
+ };
+
+ }
+
+ void VCOfSwFlyDrawObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor&) const
+ {
+ // currently gets not visualized, return empty sequence
+ }
+
+} // end of namespace sdr::contact
+
+std::unique_ptr<sdr::properties::BaseProperties> SwFlyDrawObj::CreateObjectSpecificProperties()
+{
+ // create default properties
+ return std::make_unique<sdr::properties::DefaultProperties>(*this);
+}
+
+std::unique_ptr<sdr::contact::ViewContact> SwFlyDrawObj::CreateObjectSpecificViewContact()
+{
+ // needs an own VC since createViewIndependentPrimitive2DSequence()
+ // is called when RecalcBoundRect() is used
+ return std::make_unique<sdr::contact::VCOfSwFlyDrawObj>(*this);
+}
+
+SwFlyDrawObj::SwFlyDrawObj(SdrModel& rSdrModel)
+: SdrObject(rSdrModel),
+ mbIsTextBox(false)
+{
+}
+
+SwFlyDrawObj::~SwFlyDrawObj()
+{
+}
+
+// SwFlyDrawObj - Factory-Methods
+SdrInventor SwFlyDrawObj::GetObjInventor() const
+{
+ return SdrInventor::Swg;
+}
+
+SdrObjKind SwFlyDrawObj::GetObjIdentifier() const
+{
+ return SdrObjKind::SwFlyDrawObjIdentifier;
+}
+
+// TODO: Need own primitive to get the FlyFrame paint working
+namespace drawinglayer::primitive2d
+{
+ namespace {
+
+ class SwVirtFlyDrawObjPrimitive : public BufferedDecompositionPrimitive2D
+ {
+ private:
+ const SwVirtFlyDrawObj& mrSwVirtFlyDrawObj;
+ const basegfx::B2DRange maOuterRange;
+
+ protected:
+ /// method which is to be used to implement the local decomposition of a 2D primitive
+ virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ public:
+ SwVirtFlyDrawObjPrimitive(
+ const SwVirtFlyDrawObj& rSwVirtFlyDrawObj,
+ const basegfx::B2DRange &rOuterRange)
+ : mrSwVirtFlyDrawObj(rSwVirtFlyDrawObj),
+ maOuterRange(rOuterRange)
+ {
+ }
+
+ virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
+
+ virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override;
+
+ // override to allow callbacks to wrap_DoPaintObject
+ virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
+
+ // data read access
+ const SwVirtFlyDrawObj& getSwVirtFlyDrawObj() const { return mrSwVirtFlyDrawObj; }
+ const basegfx::B2DRange& getOuterRange() const { return maOuterRange; }
+
+ /// provide unique ID
+ virtual sal_uInt32 getPrimitive2DID() const override;
+ };
+
+ }
+} // end of namespace drawinglayer::primitive2d
+
+namespace drawinglayer::primitive2d
+{
+ void SwVirtFlyDrawObjPrimitive::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ if(getOuterRange().isEmpty())
+ return;
+
+ // currently this SW object has no primitive representation. As long as this is the case,
+ // create invisible geometry to allow correct HitTest and BoundRect calculations for the
+ // object. Use a filled primitive to get 'inside' as default object hit. The special cases from
+ // the old SwVirtFlyDrawObj::CheckHit implementation are handled now in SwDrawView::PickObj;
+ // this removed the 'hack' to get a view from inside model data or to react on null-tolerance
+ // as it was done in the old implementation
+ rContainer.push_back(
+ createHiddenGeometryPrimitives2D(
+ true,
+ getOuterRange()));
+ }
+
+ bool SwVirtFlyDrawObjPrimitive::operator==(const BasePrimitive2D& rPrimitive) const
+ {
+ if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+ {
+ const SwVirtFlyDrawObjPrimitive& rCompare = static_cast<const SwVirtFlyDrawObjPrimitive&>(rPrimitive);
+
+ return (&getSwVirtFlyDrawObj() == &rCompare.getSwVirtFlyDrawObj()
+ && getOuterRange() == rCompare.getOuterRange());
+ }
+
+ return false;
+ }
+
+ basegfx::B2DRange SwVirtFlyDrawObjPrimitive::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
+ {
+ return getOuterRange();
+ }
+
+ void SwVirtFlyDrawObjPrimitive::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
+ {
+ // This is the callback to keep the FlyFrame painting in SW alive as long as it
+ // is not changed to primitives. This is the method which will be called by the processors
+ // when they do not know this primitive (and they do not). Inside wrap_DoPaintObject
+ // there needs to be a test that paint is only done during SW repaints (see there).
+ // Using this mechanism guarantees the correct Z-Order of the VirtualObject-based FlyFrames.
+ getSwVirtFlyDrawObj().wrap_DoPaintObject(rViewInformation);
+
+ // call parent
+ BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
+ }
+
+ // provide unique ID
+ sal_uInt32 SwVirtFlyDrawObjPrimitive::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_SWVIRTFLYDRAWOBJPRIMITIVE2D;
+ }
+
+} // end of namespace drawinglayer::primitive2d
+
+// 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 VCOfSwVirtFlyDrawObj : public ViewContactOfVirtObj
+ {
+ protected:
+ /** This method is responsible for creating the graphical visualisation data
+ *
+ * @note ONLY based on model data
+ */
+ virtual void createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const override;
+
+ public:
+ /// basic constructor, used from SdrObject.
+ explicit VCOfSwVirtFlyDrawObj(SwVirtFlyDrawObj& rObj)
+ : ViewContactOfVirtObj(rObj)
+ {
+ }
+
+ /// access to SwVirtFlyDrawObj
+ SwVirtFlyDrawObj& GetSwVirtFlyDrawObj() const
+ {
+ return static_cast<SwVirtFlyDrawObj&>(mrObject);
+ }
+ };
+
+ }
+} // end of namespace sdr::contact
+
+namespace sdr::contact
+{
+ void VCOfSwVirtFlyDrawObj::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) const
+ {
+ const SdrObject& rReferencedObject = GetSwVirtFlyDrawObj().GetReferencedObj();
+
+ if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
+ {
+ // create an own specialized primitive which is used as repaint callpoint and HitTest
+ // for HitTest processor (see primitive implementation above)
+ const basegfx::B2DRange aOuterRange(GetSwVirtFlyDrawObj().getOuterBound());
+
+ if(!aOuterRange.isEmpty())
+ {
+ const drawinglayer::primitive2d::Primitive2DReference xPrimitive(
+ new drawinglayer::primitive2d::SwVirtFlyDrawObjPrimitive(
+ GetSwVirtFlyDrawObj(),
+ aOuterRange));
+
+ rVisitor.visit(xPrimitive);
+ }
+ }
+ }
+
+} // end of namespace sdr::contact
+
+basegfx::B2DRange SwVirtFlyDrawObj::getOuterBound() const
+{
+ basegfx::B2DRange aOuterRange;
+ const SdrObject& rReferencedObject = GetReferencedObj();
+
+ if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
+ {
+ const SwFlyFrame* pFlyFrame = GetFlyFrame();
+
+ if(pFlyFrame)
+ {
+ const tools::Rectangle aOuterRectangle(pFlyFrame->getFrameArea().Pos(), pFlyFrame->getFrameArea().SSize());
+
+ if(!aOuterRectangle.IsEmpty())
+ {
+ aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Left(), aOuterRectangle.Top()));
+ aOuterRange.expand(basegfx::B2DTuple(aOuterRectangle.Right(), aOuterRectangle.Bottom()));
+ }
+ }
+ }
+
+ return aOuterRange;
+}
+
+basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const
+{
+ basegfx::B2DRange aInnerRange;
+ const SdrObject& rReferencedObject = GetReferencedObj();
+
+ if(dynamic_cast<const SwFlyDrawObj*>( &rReferencedObject) != nullptr)
+ {
+ const SwFlyFrame* pFlyFrame = GetFlyFrame();
+
+ if(pFlyFrame)
+ {
+ const tools::Rectangle aInnerRectangle(pFlyFrame->getFrameArea().Pos() + pFlyFrame->getFramePrintArea().Pos(), pFlyFrame->getFramePrintArea().SSize());
+
+ if(!aInnerRectangle.IsEmpty())
+ {
+ aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Left(), aInnerRectangle.Top()));
+ aInnerRange.expand(basegfx::B2DTuple(aInnerRectangle.Right(), aInnerRectangle.Bottom()));
+ }
+ }
+ }
+
+ return aInnerRange;
+}
+
+bool SwVirtFlyDrawObj::ContainsSwGrfNode() const
+{
+ // RotGrfFlyFrame: Check if this is a SwGrfNode
+ const SwFlyFrame* pFlyFrame(GetFlyFrame());
+
+ if(nullptr != pFlyFrame && pFlyFrame->Lower() && pFlyFrame->Lower()->IsNoTextFrame())
+ {
+ const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pFlyFrame->Lower()));
+
+ const SwGrfNode *const pGrfNd(pNTF->GetNode()->GetGrfNode());
+
+ return nullptr != pGrfNd;
+ }
+
+ return false;
+}
+
+bool SwVirtFlyDrawObj::HasLimitedRotation() const
+{
+ // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation.
+ // This is the case for SwGrfNode instances
+ return ContainsSwGrfNode();
+}
+
+void SwVirtFlyDrawObj::Rotate(const Point& rRef, Degree100 nAngle100, double sn, double cs)
+{
+ if(ContainsSwGrfNode())
+ {
+ // RotGrfFlyFrame: Here is where the positively completed rotate interaction is executed.
+ // Rotation is in 1/100th degree and may be signed (!)
+ Degree10 nAngle10 = to<Degree10>(nAngle100);
+
+ while(nAngle10 < 0_deg10)
+ {
+ nAngle10 += 3600_deg10;
+ }
+
+ SwWrtShell *pShForAngle = nAngle10 ? dynamic_cast<SwWrtShell*>(GetFlyFrame()->getRootFrame()->GetCurrShell()) : nullptr;
+ if (pShForAngle)
+ {
+ // RotGrfFlyFrame: Add transformation to placeholder object
+ Size aSize;
+ const Degree10 nOldRot(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
+ SwFlyFrameAttrMgr aMgr(false, pShForAngle, Frmmgr_Type::NONE, nullptr);
+
+ aMgr.SetRotation(nOldRot, (nOldRot + nAngle10) % 3600_deg10, aSize);
+ }
+ }
+ else
+ {
+ // call parent
+ SdrVirtObj::Rotate(rRef, nAngle100, sn, cs);
+ }
+}
+
+std::unique_ptr<sdr::contact::ViewContact> SwVirtFlyDrawObj::CreateObjectSpecificViewContact()
+{
+ // need an own ViewContact (VC) to allow creation of a specialized primitive
+ // for being able to visualize the FlyFrames in primitive renderers
+ return std::make_unique<sdr::contact::VCOfSwVirtFlyDrawObj>(*this);
+}
+
+SwVirtFlyDrawObj::SwVirtFlyDrawObj(
+ SdrModel& rSdrModel,
+ SdrObject& rNew,
+ SwFlyFrame* pFly)
+: SdrVirtObj(rSdrModel, rNew),
+ m_pFlyFrame(pFly)
+{
+ const SvxProtectItem &rP = m_pFlyFrame->GetFormat()->GetProtect();
+ m_bMovProt = rP.IsPosProtected();
+ m_bSizProt = rP.IsSizeProtected();
+}
+
+SwVirtFlyDrawObj::~SwVirtFlyDrawObj()
+{
+ if ( getSdrPageFromSdrObject() ) //Withdraw SdrPage the responsibility.
+ getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
+}
+
+const SwFrameFormat *SwVirtFlyDrawObj::GetFormat() const
+{
+ return GetFlyFrame()->GetFormat();
+}
+SwFrameFormat *SwVirtFlyDrawObj::GetFormat()
+{
+ return GetFlyFrame()->GetFormat();
+}
+
+// --> OD #i102707#
+namespace
+{
+ class RestoreMapMode
+ {
+ public:
+ explicit RestoreMapMode( SwViewShell const * pViewShell )
+ : mbMapModeRestored( false )
+ , mpOutDev( pViewShell->GetOut() )
+ {
+ if ( pViewShell->getPrePostMapMode() == mpOutDev->GetMapMode() )
+ return;
+
+ mpOutDev->Push(vcl::PushFlags::MAPMODE);
+
+ GDIMetaFile* pMetaFile = mpOutDev->GetConnectMetaFile();
+ if ( pMetaFile &&
+ pMetaFile->IsRecord() && !pMetaFile->IsPause() )
+ {
+ OSL_FAIL( "MapMode restoration during meta file creation is somehow suspect - using <SetRelativeMapMode(..)>, but not sure, if correct." );
+ mpOutDev->SetRelativeMapMode( pViewShell->getPrePostMapMode() );
+ }
+ else
+ {
+ mpOutDev->SetMapMode( pViewShell->getPrePostMapMode() );
+ }
+
+ mbMapModeRestored = true;
+ };
+
+ ~RestoreMapMode()
+ {
+ if ( mbMapModeRestored )
+ {
+ mpOutDev->Pop();
+ }
+ };
+
+ private:
+ bool mbMapModeRestored;
+ VclPtr<OutputDevice> mpOutDev;
+ };
+}
+// <--
+
+void SwVirtFlyDrawObj::wrap_DoPaintObject(
+ drawinglayer::geometry::ViewInformation2D const& rViewInformation) const
+{
+ SwViewShell* pShell = m_pFlyFrame->getRootFrame()->GetCurrShell();
+
+ // Only paint when we have a current shell and a DrawingLayer paint is in progress.
+ // This avoids evtl. problems with renderers which do processing stuff,
+ // but no paints. IsPaintInProgress() depends on SW repaint, so, as long
+ // as SW paints self and calls DrawLayer() for Heaven and Hell, this will
+ // be correct
+ if ( !(pShell && pShell->IsDrawingLayerPaintInProgress()) )
+ return;
+
+ bool bDrawObject(true);
+
+ if ( !SwFlyFrame::IsPaint( const_cast<SwVirtFlyDrawObj*>(this), pShell ) )
+ {
+ bDrawObject = false;
+ }
+
+ if ( !bDrawObject )
+ return;
+
+ // if there's no viewport set, all fly-frames will be painted,
+ // which is slow, wastes memory, and can cause other trouble.
+ (void) rViewInformation; // suppress "unused parameter" warning
+ assert(comphelper::LibreOfficeKit::isActive() || !rViewInformation.getViewport().isEmpty());
+ if ( m_pFlyFrame->IsFlyInContentFrame() )
+ return;
+
+ // it is also necessary to restore the VCL MapMode from ViewInformation since e.g.
+ // the VCL PixelRenderer resets it at the used OutputDevice. Unfortunately, this
+ // excludes shears and rotates which are not expressible in MapMode.
+ // OD #i102707#
+ // new helper class to restore MapMode - restoration, only if
+ // needed and consideration of paint for meta file creation .
+ RestoreMapMode aRestoreMapModeIfNeeded( pShell );
+
+ // paint the FlyFrame (use standard VCL-Paint)
+ m_pFlyFrame->PaintSwFrame( *pShell->GetOut(), m_pFlyFrame->GetPageFrame()->getFrameArea());
+}
+
+void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
+{
+ rInfo.bMoveAllowed =
+ rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = true;
+
+ // RotGrfFlyFrame: Some rotation may be allowed
+ rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = HasLimitedRotation();
+
+ rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed =
+ rInfo.bMirror90Allowed = rInfo.bShearAllowed =
+ rInfo.bCanConvToPath = rInfo.bCanConvToPoly =
+ rInfo.bCanConvToPathLineToArea = rInfo.bCanConvToPolyLineToArea = false;
+}
+
+// SwVirtFlyDrawObj - Size Determination
+
+void SwVirtFlyDrawObj::SetRect() const
+{
+ if ( GetFlyFrame()->getFrameArea().HasArea() )
+ const_cast<SwVirtFlyDrawObj*>(this)->m_aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+ else
+ const_cast<SwVirtFlyDrawObj*>(this)->m_aOutRect = tools::Rectangle();
+}
+
+const tools::Rectangle& SwVirtFlyDrawObj::GetCurrentBoundRect() const
+{
+ SetRect();
+ return m_aOutRect;
+}
+
+const tools::Rectangle& SwVirtFlyDrawObj::GetLastBoundRect() const
+{
+ return GetCurrentBoundRect();
+}
+
+void SwVirtFlyDrawObj::RecalcBoundRect()
+{
+ SetRect();
+}
+
+void SwVirtFlyDrawObj::RecalcSnapRect()
+{
+ SetRect();
+}
+
+const tools::Rectangle& SwVirtFlyDrawObj::GetSnapRect() const
+{
+ SetRect();
+ return m_aOutRect;
+}
+
+void SwVirtFlyDrawObj::SetSnapRect(const tools::Rectangle& )
+{
+ tools::Rectangle aTmp( GetLastBoundRect() );
+ SetRect();
+ SetChanged();
+ BroadcastObjectChange();
+ if (m_pUserCall!=nullptr)
+ m_pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
+}
+
+void SwVirtFlyDrawObj::NbcSetSnapRect(const tools::Rectangle& )
+{
+ SetRect();
+}
+
+const tools::Rectangle& SwVirtFlyDrawObj::GetLogicRect() const
+{
+ SetRect();
+ return m_aOutRect;
+}
+
+void SwVirtFlyDrawObj::SetLogicRect(const tools::Rectangle& )
+{
+ tools::Rectangle aTmp( GetLastBoundRect() );
+ SetRect();
+ SetChanged();
+ BroadcastObjectChange();
+ if (m_pUserCall!=nullptr)
+ m_pUserCall->Changed(*this, SdrUserCallType::Resize, aTmp);
+}
+
+void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
+{
+ SetRect();
+}
+
+::basegfx::B2DPolyPolygon SwVirtFlyDrawObj::TakeXorPoly() const
+{
+ const tools::Rectangle aSourceRectangle(GetFlyFrame()->getFrameArea().SVRect());
+ const ::basegfx::B2DRange aSourceRange = vcl::unotools::b2DRectangleFromRectangle(aSourceRectangle);
+ ::basegfx::B2DPolyPolygon aRetval;
+
+ aRetval.append(::basegfx::utils::createPolygonFromRect(aSourceRange));
+
+ return aRetval;
+}
+
+// SwVirtFlyDrawObj::Move() and Resize()
+void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
+{
+ if(GetFlyFrame()->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame())
+ {
+ // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
+ // we need to fall back to the un-transformed state to keep the old code below
+ // working properly. Restore FrameArea and use aOutRect from old FrameArea.
+ TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+ pTransformableSwFrame->restoreFrameAreas();
+ m_aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+ }
+
+ m_aOutRect.Move( rSiz );
+ const Point aOldPos( GetFlyFrame()->getFrameArea().Pos() );
+ const Point aNewPos( m_aOutRect.TopLeft() );
+ const SwRect aFlyRect( m_aOutRect );
+
+ //If the Fly has an automatic align (right or top),
+ //so preserve the automatic.
+ SwFrameFormat *pFormat = GetFlyFrame()->GetFormat();
+ const sal_Int16 eHori = pFormat->GetHoriOrient().GetHoriOrient();
+ const sal_Int16 eVert = pFormat->GetVertOrient().GetVertOrient();
+ const sal_Int16 eRelHori = pFormat->GetHoriOrient().GetRelationOrient();
+ const sal_Int16 eRelVert = pFormat->GetVertOrient().GetRelationOrient();
+ //On paragraph bound Flys starting from the new position a new
+ //anchor must be set. Anchor and the new RelPos is calculated and
+ //placed by the Fly itself.
+ if( GetFlyFrame()->IsFlyAtContentFrame() )
+ {
+ static_cast<SwFlyAtContentFrame*>(GetFlyFrame())->SetAbsPos( aNewPos );
+ }
+ else
+ {
+ const SwFrameFormat *pTmpFormat = GetFormat();
+ const SwFormatVertOrient &rVert = pTmpFormat->GetVertOrient();
+ const SwFormatHoriOrient &rHori = pTmpFormat->GetHoriOrient();
+ tools::Long lXDiff = aNewPos.X() - aOldPos.X();
+ if( rHori.IsPosToggle() && text::HoriOrientation::NONE == eHori &&
+ !GetFlyFrame()->FindPageFrame()->OnRightPage() )
+ lXDiff = -lXDiff;
+
+ if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
+ text::HoriOrientation::NONE == eHori )
+ lXDiff = -lXDiff;
+
+ tools::Long lYDiff = aNewPos.Y() - aOldPos.Y();
+ if( GetFlyFrame()->GetAnchorFrame()->IsVertical() )
+ {
+ //lXDiff -= rVert.GetPos();
+ //lYDiff += rHori.GetPos();
+
+ if ( GetFlyFrame()->GetAnchorFrame()->IsVertLR() )
+ {
+ lXDiff += rVert.GetPos();
+ lXDiff = -lXDiff;
+ }
+ else
+ {
+ lXDiff -= rVert.GetPos();
+ lYDiff += rHori.GetPos();
+ }
+ }
+ else
+ {
+ lXDiff += rHori.GetPos();
+ lYDiff += rVert.GetPos();
+ }
+
+ if( GetFlyFrame()->GetAnchorFrame()->IsRightToLeft() &&
+ text::HoriOrientation::NONE != eHori )
+ lXDiff = GetFlyFrame()->GetAnchorFrame()->getFrameArea().Width() -
+ aFlyRect.Width() - lXDiff;
+
+ const Point aTmp( lXDiff, lYDiff );
+ GetFlyFrame()->ChgRelPos( aTmp );
+ }
+
+ SwAttrSet aSet( pFormat->GetDoc()->GetAttrPool(),
+ RES_VERT_ORIENT, RES_HORI_ORIENT );
+ SwFormatHoriOrient aHori( pFormat->GetHoriOrient() );
+ SwFormatVertOrient aVert( pFormat->GetVertOrient() );
+ bool bPut = false;
+
+ if( !GetFlyFrame()->IsFlyLayFrame() &&
+ ::GetHtmlMode(pFormat->GetDoc()->GetDocShell()) )
+ {
+ //In HTML-Mode only automatic aligns are allowed.
+ //Only we can try a snap to left/right respectively left-/right border
+ const SwFrame* pAnch = GetFlyFrame()->GetAnchorFrame();
+ bool bNextLine = false;
+
+ if( !GetFlyFrame()->IsAutoPos() || text::RelOrientation::PAGE_FRAME != aHori.GetRelationOrient() )
+ {
+ if( text::RelOrientation::CHAR == eRelHori )
+ {
+ aHori.SetHoriOrient( text::HoriOrientation::LEFT );
+ aHori.SetRelationOrient( text::RelOrientation::CHAR );
+ }
+ else
+ {
+ bNextLine = true;
+ //Horizontal Align:
+ const bool bLeftFrame =
+ aFlyRect.Left() < pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Left(),
+ bLeftPrt = aFlyRect.Left() + aFlyRect.Width() <
+ pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width()/2;
+ if ( bLeftFrame || bLeftPrt )
+ {
+ aHori.SetHoriOrient( text::HoriOrientation::LEFT );
+ aHori.SetRelationOrient( bLeftFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
+ }
+ else
+ {
+ const bool bRightFrame = aFlyRect.Left() >
+ pAnch->getFrameArea().Left() + pAnch->getFramePrintArea().Width();
+ aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
+ aHori.SetRelationOrient( bRightFrame ? text::RelOrientation::FRAME : text::RelOrientation::PRINT_AREA );
+ }
+ }
+ aSet.Put( aHori );
+ }
+ //Vertical alignment simply is retained principally,
+ //only on manual align will be switched over.
+ bool bRelChar = text::RelOrientation::CHAR == eRelVert;
+ aVert.SetVertOrient( eVert != text::VertOrientation::NONE ? eVert :
+ GetFlyFrame()->IsFlyInContentFrame() ? text::VertOrientation::CHAR_CENTER :
+ bRelChar && bNextLine ? text::VertOrientation::CHAR_TOP : text::VertOrientation::TOP );
+ if( bRelChar )
+ aVert.SetRelationOrient( text::RelOrientation::CHAR );
+ else
+ aVert.SetRelationOrient( text::RelOrientation::PRINT_AREA );
+ aSet.Put( aVert );
+ bPut = true;
+ }
+
+ //We want preferably not to lose the automatic alignments.
+ if ( !bPut && bInResize )
+ {
+ if ( text::HoriOrientation::NONE != eHori )
+ {
+ aHori.SetHoriOrient( eHori );
+ aHori.SetRelationOrient( eRelHori );
+ aSet.Put( aHori );
+ bPut = true;
+ }
+ if ( text::VertOrientation::NONE != eVert )
+ {
+ aVert.SetVertOrient( eVert );
+ aVert.SetRelationOrient( eRelVert );
+ aSet.Put( aVert );
+ bPut = true;
+ }
+ }
+ if ( bPut )
+ pFormat->SetFormatAttr( aSet );
+}
+
+
+void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
+{
+ // Get Wrt Shell
+ SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
+
+ if (!pSh)
+ {
+ return;
+ }
+
+ GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
+
+ if (!pGraphicObject)
+ {
+ return;
+ }
+
+ // Get graphic object size in 100th of mm
+ const MapMode aMapMode100thmm(MapUnit::Map100thMM);
+ Size aGraphicSize(pGraphicObject->GetPrefSize());
+
+ if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
+ {
+ aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
+ }
+ else
+ {
+ aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
+ }
+
+ if( aGraphicSize.IsEmpty() )
+ {
+ return ;
+ }
+
+ const bool bIsTransformableSwFrame(
+ GetFlyFrame()->IsFlyFreeFrame() &&
+ static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
+
+ if(bIsTransformableSwFrame)
+ {
+ // When we have a change and are in transformed state (e.g. rotation used),
+ // we need to fall back to the un-transformed state to keep the old code below
+ // working properly. Restore FrameArea and use aOutRect from old FrameArea.
+ TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+ pTransformableSwFrame->restoreFrameAreas();
+ m_aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+ }
+
+ // Compute old and new rect. This will give us the deformation to apply to
+ // the object to crop. OldRect is the inner frame, see getFullDragClone()
+ // below where getFramePrintAreaTransformation is used as object geometry for Crop
+ const tools::Rectangle aOldRect(
+ GetFlyFrame()->getFrameArea().TopLeft() + GetFlyFrame()->getFramePrintArea().TopLeft(),
+ GetFlyFrame()->getFramePrintArea().SSize());
+ const tools::Long nOldWidth(aOldRect.GetWidth());
+ const tools::Long nOldHeight(aOldRect.GetHeight());
+
+ if (!nOldWidth || !nOldHeight)
+ {
+ return;
+ }
+
+ // rRef is relative to the Crop-Action, si in X/Y-Ranges of [0.0 .. 1.0],
+ // to get the correct absolute position, transform using the old Rect
+ const Point aRef(
+ aOldRect.Left() + basegfx::fround(aOldRect.GetWidth() * rRef.getX()),
+ aOldRect.Top() + basegfx::fround(aOldRect.GetHeight() * rRef.getY()));
+
+ // apply transformation, use old ResizeRect for now
+ tools::Rectangle aNewRect( aOldRect );
+ ResizeRect(
+ aNewRect,
+ aRef,
+ Fraction(fxFact),
+ Fraction(fyFact));
+
+ // Get old values for crop in 10th of mm
+ SfxItemSetFixed<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF> aSet( pSh->GetAttrPool() );
+ pSh->GetCurAttr( aSet );
+ SwCropGrf aCrop( aSet.Get(RES_GRFATR_CROPGRF) );
+
+ tools::Rectangle aCropRectangle(
+ convertTwipToMm100(aCrop.GetLeft()),
+ convertTwipToMm100(aCrop.GetTop()),
+ convertTwipToMm100(aCrop.GetRight()),
+ convertTwipToMm100(aCrop.GetBottom()) );
+
+ // Compute delta to apply
+ double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / static_cast<double>(nOldWidth);
+ double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / static_cast<double>(nOldHeight);
+
+ sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
+ sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
+ sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
+ sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
+
+ // Compute new values in 10th of mm
+ sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
+ sal_Int32 nTopCrop = static_cast<sal_Int32>( aCropRectangle.Top() + nDiffTop * fScaleY );
+ sal_Int32 nRightCrop = static_cast<sal_Int32>( aCropRectangle.Right() - nDiffRight * fScaleX );
+ sal_Int32 nBottomCrop = static_cast<sal_Int32>( aCropRectangle.Bottom() - nDiffBottom * fScaleY );
+
+ // Apply values
+ pSh->StartAllAction();
+ // pSh->StartUndo(SwUndoId::START);
+
+ // Set new crop values in twips
+ aCrop.SetLeft (o3tl::toTwips(nLeftCrop, o3tl::Length::mm100));
+ aCrop.SetTop (o3tl::toTwips(nTopCrop, o3tl::Length::mm100));
+ aCrop.SetRight (o3tl::toTwips(nRightCrop, o3tl::Length::mm100));
+ aCrop.SetBottom(o3tl::toTwips(nBottomCrop, o3tl::Length::mm100));
+ pSh->SetAttrItem(aCrop);
+
+ // Set new frame size
+ SwFrameFormat *pFormat = GetFormat();
+ SwFormatFrameSize aSz( pFormat->GetFrameSize() );
+ const tools::Long aNewWidth(aNewRect.GetWidth() + (m_aOutRect.GetWidth() - aOldRect.GetWidth()));
+ const tools::Long aNewHeight(aNewRect.GetHeight() + (m_aOutRect.GetHeight() - aOldRect.GetHeight()));
+ aSz.SetWidth(aNewWidth);
+ aSz.SetHeight(aNewHeight);
+ pFormat->GetDoc()->SetAttr( aSz, *pFormat );
+
+ // add move - to make result look better. Fill with defaults
+ // for the untransformed case
+ Point aNewTopLeft(aNewRect.TopLeft());
+ const Point aOldTopLeft(aOldRect.TopLeft());
+
+ if(bIsTransformableSwFrame)
+ {
+ // Need to correct the NewTopLeft position in transformed state to make
+ // the interaction look correct. First, extract rotation
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // calc the center of the unchanged object
+ const basegfx::B2DPoint aFormerCenter(
+ GetFlyFrame()->getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+
+ // define the existing rotation around that former center
+ const basegfx::B2DHomMatrix aRotFormerCenter(
+ basegfx::utils::createRotateAroundPoint(
+ aFormerCenter.getX(),
+ aFormerCenter.getY(),
+ fRotate));
+
+ // use the new center of the unrotated object, rotate it around the
+ // former center
+ const Point aNewCenter(aNewRect.Center());
+ const basegfx::B2DPoint aRotNewCenter(
+ aRotFormerCenter * basegfx::B2DPoint(aNewCenter.X(), aNewCenter.Y()));
+
+ // Create the new TopLeft of the unrotated, cropped object by creating
+ // as if re-creating the unrotated geometry
+ aNewTopLeft = Point(
+ basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
+ basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
+ }
+
+ // check if we have movement and execute if yes
+ const Size aDeltaMove(
+ aNewTopLeft.X() - aOldTopLeft.X(),
+ aNewTopLeft.Y() - aOldTopLeft.Y());
+
+ if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
+ {
+ NbcMove(aDeltaMove);
+ }
+
+ // pSh->EndUndo(SwUndoId::END);
+ pSh->EndAllAction();
+}
+
+void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ const SwFrame* pTmpFrame = GetFlyFrame()->GetAnchorFrame();
+
+ if( !pTmpFrame )
+ {
+ pTmpFrame = GetFlyFrame();
+ }
+
+ const bool bVertX(pTmpFrame->IsVertical());
+ const bool bRTL(pTmpFrame->IsRightToLeft());
+ const bool bVertL2RX(pTmpFrame->IsVertLR());
+ const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
+ const bool bIsTransformableSwFrame(
+ GetFlyFrame()->IsFlyFreeFrame() &&
+ static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
+
+ if(bIsTransformableSwFrame)
+ {
+ // When we have a change in transformed state, we need to fall back to the
+ // state without possible transformations.
+ // In the Resize case to correctly handle the changes, apply to the transformation
+ // and extract the new, untransformed state from that modified transformation
+ basegfx::B2DHomMatrix aNewMat(GetFlyFrame()->getFrameAreaTransformation());
+ const basegfx::B2DPoint aRef(rRef.X(), rRef.Y());
+
+ // apply state to already valid transformation
+ aNewMat.translate(-aRef.getX(), -aRef.getY());
+ aNewMat.scale(double(xFact), double(yFact));
+ aNewMat.translate(aRef.getX(), aRef.getY());
+
+ // get center of transformed state
+ const basegfx::B2DPoint aCenter(aNewMat * basegfx::B2DPoint(0.5, 0.5));
+
+ // decompose to extract scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
+ const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
+
+ // create new modified, but untransformed OutRect
+ m_aOutRect = tools::Rectangle(
+ basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
+ basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
+ basegfx::fround(aCenter.getX() + (0.5 * aAbsScale.getX())),
+ basegfx::fround(aCenter.getY() + (0.5 * aAbsScale.getY())));
+
+ // restore FrameAreas so that actions below not adapted to new
+ // full transformations take the correct actions
+ TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+ pTransformableSwFrame->restoreFrameAreas();
+ }
+ else
+ {
+ ResizeRect( m_aOutRect, rRef, xFact, yFact );
+ }
+
+ // Position may also change, remember old one. This is now already
+ // the one in the unrotated, old coordinate system
+ Point aOldPos(bUseRightEdge ? GetFlyFrame()->getFrameArea().TopRight() : GetFlyFrame()->getFrameArea().Pos());
+
+ // get target size in old coordinate system
+ Size aSz( m_aOutRect.Right() - m_aOutRect.Left() + 1, m_aOutRect.Bottom()- m_aOutRect.Top() + 1 );
+
+ // compare with restored FrameArea
+ if( aSz != GetFlyFrame()->getFrameArea().SSize() )
+ {
+ //The width of the columns should not be too narrow
+ if ( GetFlyFrame()->Lower() && GetFlyFrame()->Lower()->IsColumnFrame() )
+ {
+ SwBorderAttrAccess aAccess( SwFrame::GetCache(), GetFlyFrame() );
+ const SwBorderAttrs &rAttrs = *aAccess.Get();
+ tools::Long nMin = rAttrs.CalcLeftLine()+rAttrs.CalcRightLine();
+ const SwFormatCol& rCol = rAttrs.GetAttrSet().GetCol();
+ if ( rCol.GetColumns().size() > 1 )
+ {
+ for ( const auto &rC : rCol.GetColumns() )
+ {
+ nMin += rC.GetLeft() + rC.GetRight() + MINFLY;
+ }
+ nMin -= MINFLY;
+ }
+ aSz.setWidth( std::max( aSz.Width(), nMin ) );
+ }
+
+ SwFrameFormat *pFormat = GetFormat();
+ const SwFormatFrameSize aOldFrameSz( pFormat->GetFrameSize() );
+ GetFlyFrame()->ChgSize( aSz );
+ SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
+
+ if ( aFrameSz.GetWidthPercent() || aFrameSz.GetHeightPercent() )
+ {
+ tools::Long nRelWidth, nRelHeight;
+ const SwFrame *pRel = GetFlyFrame()->IsFlyLayFrame() ?
+ GetFlyFrame()->GetAnchorFrame() :
+ GetFlyFrame()->GetAnchorFrame()->GetUpper();
+ const SwViewShell *pSh = GetFlyFrame()->getRootFrame()->GetCurrShell();
+
+ if ( pSh && pRel->IsBodyFrame() &&
+ pSh->GetViewOptions()->getBrowseMode() &&
+ pSh->VisArea().HasArea() )
+ {
+ nRelWidth = pSh->GetBrowseWidth();
+ nRelHeight = pSh->VisArea().Height();
+ const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
+ nRelHeight -= 2*aBorder.Height();
+ }
+ else
+ {
+ nRelWidth = pRel->getFramePrintArea().Width();
+ nRelHeight = pRel->getFramePrintArea().Height();
+ }
+
+ if ( aFrameSz.GetWidthPercent() && aFrameSz.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
+ aOldFrameSz.GetWidth() != aFrameSz.GetWidth() )
+ {
+ aFrameSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100.0 / nRelWidth + 0.5) );
+ }
+
+ if ( aFrameSz.GetHeightPercent() && aFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
+ aOldFrameSz.GetHeight() != aFrameSz.GetHeight() )
+ {
+ aFrameSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100.0 / nRelHeight + 0.5) );
+ }
+
+ pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
+ }
+ }
+
+ //Position can also be changed, get new one
+ const Point aNewPos(bUseRightEdge ? m_aOutRect.Right() + 1 : m_aOutRect.Left(), m_aOutRect.Top());
+
+ if ( aNewPos == aOldPos )
+ return;
+
+ // Former late change in aOutRect by ChgSize
+ // is now taken into account directly by calculating
+ // aNewPos *after* calling ChgSize (see old code).
+ // Still need to adapt aOutRect since the 'Move' is already applied
+ // here (see ResizeRect) and it's the same SdrObject
+ const Size aDeltaMove(
+ aNewPos.X() - aOldPos.X(),
+ aNewPos.Y() - aOldPos.Y());
+ m_aOutRect.Move(-aDeltaMove.Width(), -aDeltaMove.Height());
+
+ // Now, move as needed (no empty delta which was a hack anyways)
+ if(bIsTransformableSwFrame)
+ {
+ // need to save aOutRect to FrameArea, will be restored to aOutRect in
+ // SwVirtFlyDrawObj::NbcMove currently for TransformableSwFrames
+ SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*GetFlyFrame());
+ aFrm.setSwRect(SwRect(m_aOutRect));
+ }
+
+ // keep old hack - not clear what happens here
+ bInResize = true;
+ NbcMove(aDeltaMove);
+ bInResize = false;
+}
+
+void SwVirtFlyDrawObj::Move(const Size& rSiz)
+{
+ NbcMove( rSiz );
+ SetChanged();
+ GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
+}
+
+void SwVirtFlyDrawObj::Resize(const Point& rRef,
+ const Fraction& xFact, const Fraction& yFact, bool /*bUnsetRelative*/)
+{
+ NbcResize( rRef, xFact, yFact );
+ SetChanged();
+ GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
+}
+
+void SwVirtFlyDrawObj::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
+{
+ NbcCrop( rRef, fxFact, fyFact );
+ SetChanged();
+ GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
+}
+
+// RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame
+Degree10 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(Size& rSize) const
+{
+ Degree10 nRetval;
+ const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower());
+
+ if(pNoTx)
+ {
+ SwNoTextNode& rNoTNd = const_cast< SwNoTextNode& >(*static_cast<const SwNoTextNode*>(pNoTx->GetNode()));
+ SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
+
+ if(nullptr != pGrfNd)
+ {
+ const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
+ const SwRotationGrf& rRotation = rSet.GetRotationGrf();
+
+ rSize = rRotation.GetUnrotatedSize();
+ nRetval = rRotation.GetValue();
+ }
+ }
+
+ return nRetval;
+}
+
+Degree100 SwVirtFlyDrawObj::GetRotateAngle() const
+{
+ if(ContainsSwGrfNode())
+ {
+ Size aSize;
+ return to<Degree100>(getPossibleRotationFromFraphicFrame(aSize));
+ }
+ else
+ {
+ return SdrVirtObj::GetRotateAngle();
+ }
+}
+
+SdrObjectUniquePtr SwVirtFlyDrawObj::getFullDragClone() const
+{
+ // call parent
+ SdrObjectUniquePtr pRetval = SdrVirtObj::getFullDragClone();
+
+ if(pRetval && GetFlyFrame() && ContainsSwGrfNode())
+ {
+ // RotGrfFlyFrame3: get inner bounds/transformation
+ const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
+
+ pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
+ }
+
+ return pRetval;
+}
+
+void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
+{
+ // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
+ if(!GetFlyFrame()->getFrameArea().HasArea())
+ return;
+
+ // Use InnerBound, OuterBound (same as GetFlyFrame()->getFrameArea().SVRect())
+ // may have a distance to InnerBound which needs to be taken into account.
+ // The Graphic is mapped to InnerBound, as is the rotated Graphic.
+ const basegfx::B2DRange aTargetRange(getInnerBound());
+
+ if(aTargetRange.isEmpty())
+ return;
+
+ // RotGrfFlyFrame3: get inner bounds/transformation
+ const basegfx::B2DHomMatrix aTargetTransform(GetFlyFrame()->getFramePrintAreaTransformation());
+
+ // break up matrix
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+ double fRotate(0.0);
+ double fShearX(0.0);
+ aTargetTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+ basegfx::B2DPoint aPos;
+
+ aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(0.5, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(0.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(0.5, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate));
+ aPos = aTargetTransform * basegfx::B2DPoint(1.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate));
+}
+
+// Macro
+
+PointerStyle SwVirtFlyDrawObj::GetMacroPointer(
+ const SdrObjMacroHitRec& ) const
+{
+ return PointerStyle::RefHand;
+}
+
+bool SwVirtFlyDrawObj::HasMacro() const
+{
+ const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
+ return rURL.GetMap() || !rURL.GetURL().isEmpty();
+}
+
+SdrObject* SwVirtFlyDrawObj::CheckMacroHit( const SdrObjMacroHitRec& rRec ) const
+{
+ const SwFormatURL &rURL = m_pFlyFrame->GetFormat()->GetURL();
+ if( rURL.GetMap() || !rURL.GetURL().isEmpty() )
+ {
+ SwRect aRect;
+ if ( m_pFlyFrame->Lower() && m_pFlyFrame->Lower()->IsNoTextFrame() )
+ {
+ aRect = m_pFlyFrame->getFramePrintArea();
+ aRect += m_pFlyFrame->getFrameArea().Pos();
+ }
+ else
+ aRect = m_pFlyFrame->getFrameArea();
+
+ if( aRect.Contains( rRec.aPos ) )
+ {
+ aRect.Pos().setX(aRect.Pos().getX() + rRec.nTol);
+ aRect.Pos().setY(aRect.Pos().getY() + rRec.nTol);
+ aRect.AddHeight( -(2 * rRec.nTol) );
+ aRect.AddWidth( -(2 * rRec.nTol) );
+
+ if( aRect.Contains( rRec.aPos ) )
+ {
+ if( !rURL.GetMap() ||
+ m_pFlyFrame->GetFormat()->GetIMapObject( rRec.aPos, m_pFlyFrame ))
+ return const_cast<SwVirtFlyDrawObj*>(this);
+
+ return nullptr;
+ }
+ }
+ }
+ return SdrObject::CheckMacroHit( rRec );
+}
+
+bool SwVirtFlyDrawObj::IsTextBox() const
+{
+ return SwTextBoxHelper::isTextBox(GetFormat(), RES_FLYFRMFMT, this);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dobjfac.cxx b/sw/source/core/draw/dobjfac.cxx
new file mode 100644
index 000000000..818b870da
--- /dev/null
+++ b/sw/source/core/draw/dobjfac.cxx
@@ -0,0 +1,39 @@
+/* -*- 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 .
+ */
+
+#include <dobjfac.hxx>
+#include <dflyobj.hxx>
+#include <osl/diagnose.h>
+
+SwObjectFactory aSwObjectFactory;
+
+IMPL_STATIC_LINK(
+ SwObjectFactory, MakeObject, SdrObjCreatorParams, aParams, SdrObject* )
+{
+ if ( aParams.nInventor == SdrInventor::Swg )
+ {
+ // No switch, there's only one at the moment
+ OSL_ENSURE( aParams.nObjIdentifier == SdrObjKind::SwFlyDrawObjIdentifier,
+ "Wrong inventor or identifier" );
+ return new SwFlyDrawObj(aParams.rSdrModel);
+ }
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dpage.cxx b/sw/source/core/draw/dpage.cxx
new file mode 100644
index 000000000..fc1c1ebb7
--- /dev/null
+++ b/sw/source/core/draw/dpage.cxx
@@ -0,0 +1,262 @@
+/* -*- 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 .
+ */
+
+#include <editeng/flditem.hxx>
+#include <vcl/imapobj.hxx>
+#include <svl/urihelper.hxx>
+#include <sfx2/sfxhelp.hxx>
+#include <vcl/help.hxx>
+#include <svx/svdview.hxx>
+#include <osl/diagnose.h>
+#include <fmturl.hxx>
+#include <frmfmt.hxx>
+#include <doc.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <viewimp.hxx>
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <viewsh.hxx>
+#include <drawdoc.hxx>
+#include <dpage.hxx>
+#include <dcontact.hxx>
+#include <dflyobj.hxx>
+#include <docsh.hxx>
+#include <flyfrm.hxx>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::frame;
+
+SwDPage::SwDPage(SwDrawModel& rNewModel, bool bMasterPage)
+: FmFormPage(rNewModel, bMasterPage),
+ m_pDoc(&rNewModel.GetDoc())
+{
+}
+
+SwDPage::~SwDPage()
+{
+}
+
+void SwDPage::lateInit(const SwDPage& rSrcPage)
+{
+ FmFormPage::lateInit( rSrcPage );
+
+ if ( rSrcPage.m_pGridLst )
+ {
+ m_pGridLst.reset( new SdrPageGridFrameList );
+ for ( sal_uInt16 i = 0; i != rSrcPage.m_pGridLst->GetCount(); ++i )
+ m_pGridLst->Insert( ( *rSrcPage.m_pGridLst )[ i ] );
+ }
+}
+
+rtl::Reference<SdrPage> SwDPage::CloneSdrPage(SdrModel& rTargetModel) const
+{
+ SwDrawModel& rSwDrawModel(static_cast< SwDrawModel& >(rTargetModel));
+ rtl::Reference<SwDPage> pClonedSwDPage(
+ new SwDPage(
+ rSwDrawModel,
+ IsMasterPage()));
+ pClonedSwDPage->lateInit(*this);
+ return pClonedSwDPage;
+}
+
+SdrObject* SwDPage::ReplaceObject( SdrObject* pNewObj, size_t nObjNum )
+{
+ SdrObject *pOld = GetObj( nObjNum );
+ OSL_ENSURE( pOld, "Oups, Object not replaced" );
+ SdrObjUserCall* pContact;
+ if ( nullptr != ( pContact = GetUserCall(pOld) ) &&
+ RES_DRAWFRMFMT == static_cast<SwContact*>(pContact)->GetFormat()->Which())
+ static_cast<SwDrawContact*>(pContact)->ChangeMasterObject( pNewObj );
+ return FmFormPage::ReplaceObject( pNewObj, nObjNum );
+}
+
+static void InsertGridFrame( SdrPageGridFrameList *pLst, const SwFrame *pPg )
+{
+ SwRect aPrt( pPg->getFramePrintArea() );
+ aPrt += pPg->getFrameArea().Pos();
+ const tools::Rectangle aUser( aPrt.SVRect() );
+ const tools::Rectangle aPaper( pPg->getFrameArea().SVRect() );
+ pLst->Insert( SdrPageGridFrame( aPaper, aUser ) );
+}
+
+const SdrPageGridFrameList* SwDPage::GetGridFrameList(
+ const SdrPageView* pPV, const tools::Rectangle *pRect ) const
+{
+ SwViewShell* pSh = static_cast< SwDrawModel& >(getSdrModelFromSdrPage()).GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
+ if(pSh)
+ {
+ for(SwViewShell& rShell : pSh->GetRingContainer())
+ {
+ if(rShell.Imp()->GetPageView() == pPV)
+ {
+ pSh = &rShell;
+ break;
+ }
+ }
+ if ( m_pGridLst )
+ const_cast<SwDPage*>(this)->m_pGridLst->Clear();
+ else
+ const_cast<SwDPage*>(this)->m_pGridLst.reset( new SdrPageGridFrameList );
+
+ if ( pRect )
+ {
+ //The drawing demands all pages which overlap with the rest.
+ const SwRect aRect( *pRect );
+ const SwFrame *pPg = pSh->GetLayout()->Lower();
+ do
+ { if ( pPg->getFrameArea().Overlaps( aRect ) )
+ ::InsertGridFrame( const_cast<SwDPage*>(this)->m_pGridLst.get(), pPg );
+ pPg = pPg->GetNext();
+ } while ( pPg );
+ }
+ else
+ {
+ //The drawing demands all visible pages
+ const SwFrame *pPg = pSh->Imp()->GetFirstVisPage(pSh->GetOut());
+ if ( pPg )
+ do
+ { ::InsertGridFrame( const_cast<SwDPage*>(this)->m_pGridLst.get(), pPg );
+ pPg = pPg->GetNext();
+ } while ( pPg && pPg->getFrameArea().Overlaps( pSh->VisArea() ) );
+ }
+ }
+ return m_pGridLst.get();
+}
+
+bool SwDPage::RequestHelp( vcl::Window* pWindow, SdrView const * pView,
+ const HelpEvent& rEvt )
+{
+ assert( m_pDoc );
+
+ bool bContinue = true;
+
+ if( rEvt.GetMode() & ( HelpEventMode::QUICK | HelpEventMode::BALLOON ))
+ {
+ Point aPos( rEvt.GetMousePosPixel() );
+ aPos = pWindow->ScreenToOutputPixel( aPos );
+ aPos = pWindow->PixelToLogic( aPos );
+
+ SdrPageView* pPV;
+ SdrObject* pObj = pView->PickObj(aPos, 0, pPV, SdrSearchOptions::PICKMACRO);
+ SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
+ OUString sText;
+ tools::Rectangle aPixRect;
+ bool bTooltip = false;
+ if (pDrawObj)
+ {
+ SwFlyFrame *pFly = pDrawObj->GetFlyFrame();
+
+ aPixRect = pWindow->LogicToPixel(pFly->getFrameArea().SVRect());
+
+ const SwFormatURL &rURL = pFly->GetFormat()->GetURL();
+ if (!pFly->GetFormat()->GetObjTooltip().isEmpty())
+ {
+ // Tooltips have priority over URLs.
+ sText = pFly->GetFormat()->GetObjTooltip();
+ bTooltip = true;
+ }
+ else if( rURL.GetMap() )
+ {
+ IMapObject *pTmpObj = pFly->GetFormat()->GetIMapObject( aPos, pFly );
+ if( pTmpObj )
+ {
+ sText = pTmpObj->GetAltText();
+ if ( sText.isEmpty() )
+ sText = URIHelper::removePassword( pTmpObj->GetURL(),
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous);
+ }
+ }
+ else if ( !rURL.GetURL().isEmpty() )
+ {
+ sText = URIHelper::removePassword( rURL.GetURL(),
+ INetURLObject::EncodeMechanism::WasEncoded,
+ INetURLObject::DecodeMechanism::Unambiguous);
+
+ if( rURL.IsServerMap() )
+ {
+ // then append the relative pixel position!!
+ Point aPt( aPos );
+ aPt -= pFly->getFrameArea().Pos();
+ // without MapMode-Offset !!!!!
+ // without MapMode-Offset, without Offset, w ... !!!!!
+ aPt = pWindow->LogicToPixel(
+ aPt, MapMode( MapUnit::MapTwip ) );
+ sText += "?" + OUString::number( aPt.getX() )
+ + "," + OUString::number( aPt.getY() );
+ }
+ }
+ }
+ else
+ {
+ SdrViewEvent aVEvt;
+ MouseEvent aMEvt(pWindow->ScreenToOutputPixel(rEvt.GetMousePosPixel()), 1,
+ MouseEventModifiers::NONE, MOUSE_LEFT);
+ pView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
+ {
+ sText = aVEvt.mpURLField->GetURL();
+ aPixRect = pWindow->LogicToPixel(aVEvt.mpObj->GetLogicRect());
+ }
+ }
+
+ if (!sText.isEmpty())
+ {
+ // #i80029#
+ bool bExecHyperlinks = m_pDoc->GetDocShell()->IsReadOnly();
+ if (!bExecHyperlinks && !bTooltip)
+ sText = SfxHelp::GetURLHelpText(sText);
+
+ // then display the help:
+ tools::Rectangle aScreenRect(pWindow->OutputToScreenPixel(aPixRect.TopLeft()),
+ pWindow->OutputToScreenPixel(aPixRect.BottomRight()));
+
+ if (rEvt.GetMode() & HelpEventMode::BALLOON)
+ Help::ShowBalloon(pWindow, rEvt.GetMousePosPixel(), aScreenRect, sText);
+ else
+ Help::ShowQuickHelp(pWindow, aScreenRect, sText);
+ bContinue = false;
+ }
+ }
+
+ if( bContinue )
+ bContinue = !FmFormPage::RequestHelp( pWindow, pView, rEvt );
+
+ return bContinue;
+}
+
+Reference< XInterface > SwDPage::createUnoPage()
+{
+ assert( m_pDoc );
+
+ Reference < XInterface > xRet;
+ SwDocShell* pDocShell = m_pDoc->GetDocShell();
+ if ( pDocShell )
+ {
+ Reference<XModel> xModel = pDocShell->GetBaseModel();
+ Reference<XDrawPageSupplier> xPageSupp(xModel, UNO_QUERY);
+ xRet = xPageSupp->getDrawPage();
+ }
+ return xRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/drawdoc.cxx b/sw/source/core/draw/drawdoc.cxx
new file mode 100644
index 000000000..4c3050ebf
--- /dev/null
+++ b/sw/source/core/draw/drawdoc.cxx
@@ -0,0 +1,137 @@
+/* -*- 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 .
+ */
+
+#include <svx/svxids.hrc>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <svx/drawitem.hxx>
+#include <osl/diagnose.h>
+#include <doc.hxx>
+#include <drawdoc.hxx>
+#include <dpage.hxx>
+#include <docsh.hxx>
+#include <hintids.hxx>
+#include <DocumentSettingManager.hxx>
+
+using namespace com::sun::star;
+
+// Constructor
+SwDrawModel::SwDrawModel(SwDoc& rDoc)
+ : FmFormModel(&rDoc.GetAttrPool(), rDoc.GetDocShell())
+ , m_rDoc(rDoc)
+{
+ SetScaleUnit( MapUnit::MapTwip );
+ SetSwapGraphics();
+
+ // use common InitDrawModelAndDocShell which will set the associations as needed,
+ // including SvxColorTableItem with WhichID SID_COLOR_TABLE
+ InitDrawModelAndDocShell(m_rDoc.GetDocShell(), this);
+
+ // copy all the default values to the SdrModel
+ SfxItemPool* pSdrPool = m_rDoc.GetAttrPool().GetSecondaryPool();
+ if( pSdrPool )
+ {
+ const sal_uInt16 aWhichRanges[] =
+ {
+ RES_CHRATR_BEGIN, RES_CHRATR_END,
+ RES_PARATR_BEGIN, RES_PARATR_END,
+ 0
+ };
+
+ SfxItemPool& rDocPool = m_rDoc.GetAttrPool();
+ sal_uInt16 nEdtWhich, nSlotId;
+ const SfxPoolItem* pItem;
+ for( const sal_uInt16* pRangeArr = aWhichRanges;
+ *pRangeArr; pRangeArr += 2 )
+ for( sal_uInt16 nW = *pRangeArr, nEnd = *(pRangeArr+1);
+ nW < nEnd; ++nW )
+ if( nullptr != (pItem = rDocPool.GetPoolDefaultItem( nW )) &&
+ 0 != (nSlotId = rDocPool.GetSlotId( nW ) ) &&
+ nSlotId != nW &&
+ 0 != (nEdtWhich = pSdrPool->GetWhich( nSlotId )) &&
+ nSlotId != nEdtWhich )
+ {
+ std::unique_ptr<SfxPoolItem> pCpy(pItem->Clone());
+ pCpy->SetWhich( nEdtWhich );
+ pSdrPool->SetPoolDefaultItem( *pCpy );
+ }
+ }
+
+ SetForbiddenCharsTable(m_rDoc.GetDocumentSettingManager().getForbiddenCharacterTable());
+ // Implementation for asian compression
+ SetCharCompressType( m_rDoc.GetDocumentSettingManager().getCharacterCompressionType() );
+}
+
+// Destructor
+
+SwDrawModel::~SwDrawModel()
+{
+ Broadcast(SdrHint(SdrHintKind::ModelCleared));
+
+ ClearModel(true);
+}
+
+/** Create a new page (SdPage) and return a pointer to it back.
+ *
+ * The drawing engine is using this method while loading for the creating of
+ * pages (whose type it not even know, because they are inherited from SdrPage).
+ *
+ * @return Pointer to the new page.
+ */
+rtl::Reference<SdrPage> SwDrawModel::AllocPage(bool bMasterPage)
+{
+ rtl::Reference<SwDPage> pPage = new SwDPage(*this, bMasterPage);
+ pPage->SetName("Controls");
+ return pPage;
+}
+
+uno::Reference<embed::XStorage> SwDrawModel::GetDocumentStorage() const
+{
+ return m_rDoc.GetDocStorage();
+}
+
+uno::Reference< uno::XInterface > SwDrawModel::createUnoModel()
+{
+ uno::Reference< uno::XInterface > xModel;
+
+ try
+ {
+ if ( GetDoc().GetDocShell() )
+ {
+ xModel = GetDoc().GetDocShell()->GetModel();
+ }
+ }
+ catch( uno::RuntimeException& )
+ {
+ OSL_FAIL( "<SwDrawModel::createUnoModel()> - could *not* retrieve model at <SwDocShell>" );
+ }
+
+ return xModel;
+}
+
+void SwDrawModel::PutAreaListItems(SfxItemSet& rSet) const
+{
+ rSet.Put(SvxColorListItem(GetColorList(), SID_COLOR_TABLE));
+ rSet.Put(SvxGradientListItem(GetGradientList(), SID_GRADIENT_LIST));
+ rSet.Put(SvxHatchListItem(GetHatchList(), SID_HATCH_LIST));
+ rSet.Put(SvxBitmapListItem(GetBitmapList(), SID_BITMAP_LIST));
+ rSet.Put(SvxPatternListItem(GetPatternList(), SID_PATTERN_LIST));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
new file mode 100644
index 000000000..93b787c91
--- /dev/null
+++ b/sw/source/core/draw/dview.cxx
@@ -0,0 +1,1019 @@
+/* -*- 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 .
+ */
+
+#include <config_wasm_strip.h>
+
+#include <hintids.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/fmmodel.hxx>
+#include <sot/exchange.hxx>
+#include <svx/sdrundomanager.hxx>
+#include <tools/globname.hxx>
+#include <editeng/outliner.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <pagefrm.hxx>
+#include <rootfrm.hxx>
+#include <cntfrm.hxx>
+#include <notxtfrm.hxx>
+#include <flyfrm.hxx>
+#include <frmfmt.hxx>
+#include <dflyobj.hxx>
+#include <dcontact.hxx>
+#include <textboxhelper.hxx>
+#include <viewsh.hxx>
+#include <viewimp.hxx>
+#include <dview.hxx>
+#include <doc.hxx>
+#include <mdiexp.hxx>
+#include <ndole.hxx>
+#include <ndgrf.hxx>
+#include <fmtanchr.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <DocumentSettingManager.hxx>
+#include <IDocumentLayoutAccess.hxx>
+
+#include <com/sun/star/embed/Aspects.hpp>
+
+#include <vector>
+
+#include <sortedobjs.hxx>
+
+using namespace com::sun::star;
+
+namespace {
+
+class SwSdrHdl : public SdrHdl
+{
+public:
+ SwSdrHdl(const Point& rPnt, bool bTopRight ) :
+ SdrHdl( rPnt, bTopRight ? SdrHdlKind::Anchor_TR : SdrHdlKind::Anchor ) {}
+ virtual bool IsFocusHdl() const override;
+};
+
+}
+
+bool SwSdrHdl::IsFocusHdl() const
+{
+ if( SdrHdlKind::Anchor == eKind || SdrHdlKind::Anchor_TR == eKind )
+ return true;
+ return SdrHdl::IsFocusHdl();
+}
+
+static const SwFrame *lcl_FindAnchor( const SdrObject *pObj, bool bAll )
+{
+ const SwVirtFlyDrawObj *pVirt = dynamic_cast< const SwVirtFlyDrawObj *>( pObj );
+ if ( pVirt )
+ {
+ if ( bAll || !pVirt->GetFlyFrame()->IsFlyInContentFrame() )
+ return pVirt->GetFlyFrame()->GetAnchorFrame();
+ }
+ else
+ {
+ const SwDrawContact *pCont = static_cast<const SwDrawContact*>(GetUserCall(pObj));
+ if ( pCont )
+ return pCont->GetAnchorFrame( pObj );
+ }
+ return nullptr;
+}
+
+SwDrawView::SwDrawView(
+ SwViewShellImp& rI,
+ FmFormModel& rFmFormModel,
+ OutputDevice* pOutDev)
+: FmFormView(rFmFormModel, pOutDev),
+ m_rImp( rI )
+{
+ SetPageVisible( false );
+ SetBordVisible( false );
+ SetGridVisible( false );
+ SetHlplVisible( false );
+ SetGlueVisible( false );
+ SetFrameDragSingles();
+ SetSwapAsynchron();
+
+ EnableExtendedKeyInputDispatcher( false );
+ EnableExtendedMouseEventDispatcher( false );
+
+ SetHitTolerancePixel( GetMarkHdlSizePixel()/2 );
+
+ SetPrintPreview( rI.GetShell()->IsPreview() );
+
+ // #i73602# Use default from the configuration
+ SetBufferedOverlayAllowed(SvtOptionsDrawinglayer::IsOverlayBuffer_Writer());
+
+ // #i74769#, #i75172# Use default from the configuration
+ SetBufferedOutputAllowed(SvtOptionsDrawinglayer::IsPaintBuffer_Writer());
+}
+
+// #i99665#
+bool SwDrawView::IsAntiAliasing()
+{
+ return SvtOptionsDrawinglayer::IsAntiAliasing();
+}
+
+static SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol, const SdrMarkList &rMrkList)
+{
+ if(!nTol)
+ {
+ // the old method forced back to outer bounds test when nTol == 0, so
+ // do not try to correct when nTol is not set (used from HelpContent)
+ }
+ else
+ {
+ // rebuild logic from former SwVirtFlyDrawObj::CheckSdrObjectHit. This is needed since
+ // the SdrObject-specific CheckHit implementations are now replaced with primitives and
+ // 'tricks' like in the old implementation (e.g. using a view from a model-data class to
+ // detect if object is selected) are no longer valid.
+ // The standard primitive hit-test for SwVirtFlyDrawObj now is the outer bound. The old
+ // implementation reduced this excluding the inner bound when the object was not selected.
+ SwVirtFlyDrawObj* pSwVirtFlyDrawObj = dynamic_cast< SwVirtFlyDrawObj* >(pRetval);
+
+ if(pSwVirtFlyDrawObj)
+ {
+ if(pSwVirtFlyDrawObj->GetFlyFrame()->Lower() && pSwVirtFlyDrawObj->GetFlyFrame()->Lower()->IsNoTextFrame())
+ {
+ // the old method used IsNoTextFrame (should be for SW's own OLE and
+ // graphic's) to accept hit only based on outer bounds; nothing to do
+ }
+ else
+ {
+ // check if the object is selected in this view
+ const size_t nMarkCount(rMrkList.GetMarkCount());
+ bool bSelected(false);
+
+ for(size_t a = 0; !bSelected && a < nMarkCount; ++a)
+ {
+ if(pSwVirtFlyDrawObj == rMrkList.GetMark(a)->GetMarkedSdrObj())
+ {
+ bSelected = true;
+ }
+ }
+
+ if(!bSelected)
+ {
+ // when not selected, the object is not hit when hit position is inside
+ // inner range. Get and shrink inner range
+ basegfx::B2DRange aInnerBound(pSwVirtFlyDrawObj->getInnerBound());
+
+ aInnerBound.grow(-1.0 * nTol);
+
+ if(aInnerBound.isInside(basegfx::B2DPoint(rPnt.X(), rPnt.Y())))
+ {
+ // exclude this hit
+ pRetval = nullptr;
+ }
+ }
+ }
+ }
+ }
+
+ return pRetval;
+}
+
+SdrObject* SwDrawView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const
+{
+ // call parent
+ SdrObject* pRetval = FmFormView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay);
+
+ if(pRetval)
+ {
+ // override to allow extra handling when picking SwVirtFlyDrawObj's
+ pRetval = impLocalHitCorrection(pRetval, rPnt, nTol, GetMarkedObjectList());
+ }
+
+ return pRetval;
+}
+
+/// Gets called every time the handles need to be build
+void SwDrawView::AddCustomHdl()
+{
+ const SdrMarkList &rMrkList = GetMarkedObjectList();
+
+ if(rMrkList.GetMarkCount() != 1 || !GetUserCall(rMrkList.GetMark( 0 )->GetMarkedSdrObj()))
+ return;
+
+ SdrObject *pObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
+ // make code robust
+ SwFrameFormat* pFrameFormat( ::FindFrameFormat( pObj ) );
+ if ( !pFrameFormat )
+ {
+ OSL_FAIL( "<SwDrawView::AddCustomHdl()> - missing frame format!" );
+ return;
+ }
+ const SwFormatAnchor &rAnchor = pFrameFormat->GetAnchor();
+
+ if (RndStdIds::FLY_AS_CHAR == rAnchor.GetAnchorId())
+ return;
+
+ const SwFrame* pAnch = CalcAnchor();
+ if(nullptr == pAnch)
+ return;
+
+ Point aPos(m_aAnchorPoint);
+
+ if ( RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() )
+ {
+ // #i28701# - use last character rectangle saved at object
+ // in order to avoid a format of the anchor frame
+ SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
+
+ // Invalidate/recalc LastCharRect which can contain invalid frame offset because
+ // of later frame changes
+ pAnchoredObj->CheckCharRectAndTopOfLine(false);
+
+ SwRect aAutoPos = pAnchoredObj->GetLastCharRect();
+ if ( aAutoPos.Height() )
+ {
+ aPos = aAutoPos.Pos();
+ }
+ }
+
+ // add anchor handle:
+ std::unique_ptr<SdrHdl> hdl = std::make_unique<SwSdrHdl>( aPos, ( pAnch->IsVertical() && !pAnch->IsVertLR() ) ||
+ pAnch->IsRightToLeft() );
+ hdl->SetObjHdlNum(maHdlList.GetHdlCount());
+ maHdlList.AddHdl(std::move(hdl));
+}
+
+SdrObject* SwDrawView::GetMaxToTopObj( SdrObject* pObj ) const
+{
+ if ( GetUserCall(pObj) )
+ {
+ const SwFrame *pAnch = ::lcl_FindAnchor( pObj, false );
+ if ( pAnch )
+ {
+ //The topmost Obj within the anchor must not be overtaken.
+ const SwFlyFrame *pFly = pAnch->FindFlyFrame();
+ if ( pFly )
+ {
+ const SwPageFrame *pPage = pFly->FindPageFrame();
+ if ( pPage->GetSortedObjs() )
+ {
+ size_t nOrdNum = 0;
+ for (SwAnchoredObject* i : *pPage->GetSortedObjs())
+ {
+ const SdrObject *pO = i->GetDrawObj();
+
+ if ( pO->GetOrdNumDirect() > nOrdNum )
+ {
+ const SwFrame *pTmpAnch = ::lcl_FindAnchor( pO, false );
+ if ( pFly->IsAnLower( pTmpAnch ) )
+ {
+ nOrdNum = pO->GetOrdNumDirect();
+ }
+ }
+ }
+ if ( nOrdNum )
+ {
+ SdrPage *pTmpPage = GetModel()->GetPage( 0 );
+ ++nOrdNum;
+ if ( nOrdNum < pTmpPage->GetObjCount() )
+ {
+ return pTmpPage->GetObj( nOrdNum );
+ }
+ }
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+SdrObject* SwDrawView::GetMaxToBtmObj(SdrObject* pObj) const
+{
+ if ( GetUserCall(pObj) )
+ {
+ const SwFrame *pAnch = ::lcl_FindAnchor( pObj, false );
+ if ( pAnch )
+ {
+ //The Fly of the anchor must not be "flying under".
+ const SwFlyFrame *pFly = pAnch->FindFlyFrame();
+ if ( pFly )
+ {
+ SdrObject *pRet = const_cast<SdrObject*>(static_cast<SdrObject const *>(pFly->GetVirtDrawObj()));
+ return pRet != pObj ? pRet : nullptr;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/// determine maximal order number for a 'child' object of given 'parent' object
+sal_uInt32 SwDrawView::GetMaxChildOrdNum( const SwFlyFrame& _rParentObj,
+ const SdrObject* _pExclChildObj )
+{
+ sal_uInt32 nMaxChildOrdNum = _rParentObj.GetDrawObj()->GetOrdNum();
+
+ const SdrPage* pDrawPage = _rParentObj.GetDrawObj()->getSdrPageFromSdrObject();
+ OSL_ENSURE( pDrawPage,
+ "<SwDrawView::GetMaxChildOrdNum(..) - missing drawing page at parent object - crash!" );
+
+ const size_t nObjCount = pDrawPage->GetObjCount();
+ for ( size_t i = nObjCount-1; i > _rParentObj.GetDrawObj()->GetOrdNum() ; --i )
+ {
+ const SdrObject* pObj = pDrawPage->GetObj( i );
+
+ // Don't consider 'child' object <_pExclChildObj>
+ if ( pObj == _pExclChildObj )
+ {
+ continue;
+ }
+
+ if ( pObj->GetOrdNum() > nMaxChildOrdNum &&
+ _rParentObj.IsAnLower( lcl_FindAnchor( pObj, true ) ) )
+ {
+ nMaxChildOrdNum = pObj->GetOrdNum();
+ break;
+ }
+ }
+
+ return nMaxChildOrdNum;
+}
+
+/// method to move 'repeated' objects of the given moved object to the according level
+void SwDrawView::MoveRepeatedObjs( const SwAnchoredObject& _rMovedAnchoredObj,
+ const std::vector<SdrObject*>& _rMovedChildObjs ) const
+{
+ // determine 'repeated' objects of already moved object <_rMovedAnchoredObj>
+ std::vector<SwAnchoredObject*> aAnchoredObjs;
+ {
+ const SwContact* pContact = ::GetUserCall( _rMovedAnchoredObj.GetDrawObj() );
+ assert(pContact && "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
+ pContact->GetAnchoredObjs( aAnchoredObjs );
+ }
+
+ // check, if 'repeated' objects exists.
+ if ( aAnchoredObjs.size() <= 1 )
+ return;
+
+ SdrPage* pDrawPage = GetModel()->GetPage( 0 );
+
+ // move 'repeated' ones to the same order number as the already moved one.
+ const size_t nNewPos = _rMovedAnchoredObj.GetDrawObj()->GetOrdNum();
+ while ( !aAnchoredObjs.empty() )
+ {
+ SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
+ if ( pAnchoredObj != &_rMovedAnchoredObj )
+ {
+ pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
+ nNewPos );
+ pDrawPage->RecalcObjOrdNums();
+ // adjustments for accessibility API
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if ( auto pTmpFlyFrame = pAnchoredObj->DynCastFlyFrame() )
+ {
+ m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
+ m_rImp.AddAccessibleFrame( pTmpFlyFrame );
+ }
+ else
+ {
+ m_rImp.DisposeAccessibleObj(pAnchoredObj->GetDrawObj(), true);
+ m_rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
+ }
+#endif
+ }
+ aAnchoredObjs.pop_back();
+ }
+
+ // move 'repeated' ones of 'child' objects
+ for ( SdrObject* pChildObj : _rMovedChildObjs )
+ {
+ {
+ const SwContact* pContact = ::GetUserCall( pChildObj );
+ assert(pContact && "SwDrawView::MoveRepeatedObjs(..) - missing contact object -> crash.");
+ pContact->GetAnchoredObjs( aAnchoredObjs );
+ }
+ // move 'repeated' ones to the same order number as the already moved one.
+ const size_t nTmpNewPos = pChildObj->GetOrdNum();
+ while ( !aAnchoredObjs.empty() )
+ {
+ SwAnchoredObject* pAnchoredObj = aAnchoredObjs.back();
+ if ( pAnchoredObj->GetDrawObj() != pChildObj )
+ {
+ pDrawPage->SetObjectOrdNum( pAnchoredObj->GetDrawObj()->GetOrdNum(),
+ nTmpNewPos );
+ pDrawPage->RecalcObjOrdNums();
+ // adjustments for accessibility API
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if ( auto pTmpFlyFrame = pAnchoredObj->DynCastFlyFrame() )
+ {
+ m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
+ m_rImp.AddAccessibleFrame( pTmpFlyFrame );
+ }
+ else
+ {
+ m_rImp.DisposeAccessibleObj(pAnchoredObj->GetDrawObj(), true);
+ m_rImp.AddAccessibleObj( pAnchoredObj->GetDrawObj() );
+ }
+#endif
+ }
+ aAnchoredObjs.pop_back();
+ }
+ }
+}
+
+// --> adjustment and re-factoring of method
+void SwDrawView::ObjOrderChanged( SdrObject* pObj, size_t nOldPos,
+ size_t nNewPos )
+{
+ // nothing to do for group members
+ if ( pObj->getParentSdrObjectFromSdrObject() )
+ {
+ return;
+ }
+
+ // determine drawing page and assure that the order numbers are correct.
+ SdrPage* pDrawPage = GetModel()->GetPage( 0 );
+ if ( pDrawPage->IsObjOrdNumsDirty() )
+ pDrawPage->RecalcObjOrdNums();
+ const size_t nObjCount = pDrawPage->GetObjCount();
+
+ SwAnchoredObject* pMovedAnchoredObj =
+ ::GetUserCall( pObj )->GetAnchoredObj( pObj );
+ const SwFlyFrame* pParentAnchoredObj =
+ pMovedAnchoredObj->GetAnchorFrame()->FindFlyFrame();
+
+ const bool bMovedForward = nOldPos < nNewPos;
+
+ // assure for a 'child' object, that it doesn't exceed the limits of its 'parent'
+ if ( pParentAnchoredObj )
+ {
+ if ( bMovedForward )
+ {
+ const size_t nMaxChildOrdNumWithoutMoved =
+ GetMaxChildOrdNum( *pParentAnchoredObj, pMovedAnchoredObj->GetDrawObj() );
+ if ( nNewPos > nMaxChildOrdNumWithoutMoved+1 )
+ {
+ // set position to the top of the 'child' object group
+ pDrawPage->SetObjectOrdNum( nNewPos, nMaxChildOrdNumWithoutMoved+1 );
+ nNewPos = nMaxChildOrdNumWithoutMoved+1;
+ }
+ }
+ else
+ {
+ const size_t nParentOrdNum = pParentAnchoredObj->GetDrawObj()->GetOrdNum();
+ if ( nNewPos < nParentOrdNum )
+ {
+ // set position to the bottom of the 'child' object group
+ pDrawPage->SetObjectOrdNum( nNewPos, nParentOrdNum );
+ nNewPos = nParentOrdNum;
+ }
+ }
+ if ( pDrawPage->IsObjOrdNumsDirty() )
+ pDrawPage->RecalcObjOrdNums();
+ }
+
+ // Assure, that object isn't positioned between 'repeated' ones
+ if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
+ ( !bMovedForward && nNewPos > 0 ) )
+ {
+ const SdrObject* pTmpObj =
+ pDrawPage->GetObj( bMovedForward ? nNewPos - 1 : nNewPos + 1 );
+ if ( pTmpObj )
+ {
+ size_t nTmpNewPos( nNewPos );
+ if ( bMovedForward )
+ {
+ // move before the top 'repeated' object
+ const sal_uInt32 nTmpMaxOrdNum =
+ ::GetUserCall( pTmpObj )->GetMaxOrdNum();
+ if ( nTmpMaxOrdNum > nNewPos )
+ nTmpNewPos = nTmpMaxOrdNum;
+ }
+ else
+ {
+ // move behind the bottom 'repeated' object
+ const sal_uInt32 nTmpMinOrdNum =
+ ::GetUserCall( pTmpObj )->GetMinOrdNum();
+ if ( nTmpMinOrdNum < nNewPos )
+ nTmpNewPos = nTmpMinOrdNum;
+ }
+ if ( nTmpNewPos != nNewPos )
+ {
+ pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
+ nNewPos = nTmpNewPos;
+ pDrawPage->RecalcObjOrdNums();
+ }
+ }
+ }
+
+ // On move forward, assure that object is moved before its own children.
+ // Only Writer fly frames can have children.
+ if ( pMovedAnchoredObj->DynCastFlyFrame() &&
+ bMovedForward && nNewPos < nObjCount - 1 )
+ {
+ sal_uInt32 nMaxChildOrdNum =
+ GetMaxChildOrdNum( *static_cast<const SwFlyFrame*>(pMovedAnchoredObj) );
+ if ( nNewPos < nMaxChildOrdNum )
+ {
+ // determine position before the object before its top 'child' object
+ const SdrObject* pTmpObj = pDrawPage->GetObj( nMaxChildOrdNum );
+ size_t nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum() + 1;
+ if ( nTmpNewPos >= nObjCount )
+ {
+ --nTmpNewPos;
+ }
+ // assure, that determined position isn't between 'repeated' objects
+ pTmpObj = pDrawPage->GetObj( nTmpNewPos );
+ nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
+ // apply new position
+ pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
+ nNewPos = nTmpNewPos;
+ pDrawPage->RecalcObjOrdNums();
+ }
+ }
+
+ // Assure, that object isn't positioned between nested objects
+ if ( ( bMovedForward && nNewPos < nObjCount - 1 ) ||
+ ( !bMovedForward && nNewPos > 0 ) )
+ {
+ size_t nTmpNewPos( nNewPos );
+ const SwFrameFormat* pParentFrameFormat =
+ pParentAnchoredObj ? &(pParentAnchoredObj->GetFrameFormat()) : nullptr;
+ const SdrObject* pTmpObj = pDrawPage->GetObj( nNewPos + 1 );
+ while ( pTmpObj )
+ {
+ // #i38563# - assure, that anchor frame exists.
+ // If object is anchored inside an invisible part of the document
+ // (e.g. page header, whose page style isn't applied, or hidden
+ // section), no anchor frame exists.
+ const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
+ const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
+ ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
+ if ( pTmpParentObj &&
+ &(pTmpParentObj->GetFrameFormat()) != pParentFrameFormat )
+ {
+ if ( bMovedForward )
+ {
+ nTmpNewPos = ::GetUserCall( pTmpObj )->GetMaxOrdNum();
+ pTmpObj = pDrawPage->GetObj( nTmpNewPos + 1 );
+ }
+ else
+ {
+ nTmpNewPos = ::GetUserCall( pTmpParentObj->GetDrawObj() )
+ ->GetMinOrdNum();
+ pTmpObj = pTmpParentObj->GetDrawObj();
+ }
+ }
+ else
+ break;
+ }
+ if ( nTmpNewPos != nNewPos )
+ {
+ pDrawPage->SetObjectOrdNum( nNewPos, nTmpNewPos );
+ nNewPos = nTmpNewPos;
+ pDrawPage->RecalcObjOrdNums();
+ }
+ }
+
+ // setup collection of moved 'child' objects to move its 'repeated' objects.
+ std::vector< SdrObject* > aMovedChildObjs;
+
+ // move 'children' accordingly
+ if ( auto pFlyFrame = pMovedAnchoredObj->DynCastFlyFrame() )
+ {
+ // adjustments for accessibility API
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ m_rImp.DisposeAccessibleFrame( pFlyFrame );
+ m_rImp.AddAccessibleFrame( pFlyFrame );
+#endif
+
+ const sal_uInt32 nChildNewPos = bMovedForward ? nNewPos : nNewPos+1;
+ size_t i = bMovedForward ? nOldPos : nObjCount-1;
+ do
+ {
+ SdrObject* pTmpObj = pDrawPage->GetObj( i );
+ if ( pTmpObj == pObj )
+ break;
+
+ // #i38563# - assure, that anchor frame exists.
+ // If object is anchored inside an invisible part of the document
+ // (e.g. page header, whose page style isn't applied, or hidden
+ // section), no anchor frame exists.
+ const SwFrame* pTmpAnchorFrame = lcl_FindAnchor( pTmpObj, true );
+ const SwFlyFrame* pTmpParentObj = pTmpAnchorFrame
+ ? pTmpAnchorFrame->FindFlyFrame() : nullptr;
+ if ( pTmpParentObj &&
+ ( ( pTmpParentObj == pFlyFrame ) ||
+ ( pFlyFrame->IsUpperOf( *pTmpParentObj ) ) ) )
+ {
+ // move child object.,
+ pDrawPage->SetObjectOrdNum( i, nChildNewPos );
+ pDrawPage->RecalcObjOrdNums();
+ // collect 'child' object
+ aMovedChildObjs.push_back( pTmpObj );
+ // adjustments for accessibility API
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ if ( auto pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj *>( pTmpObj ) )
+ {
+ const SwFlyFrame *pTmpFlyFrame = pFlyDrawObj->GetFlyFrame();
+ m_rImp.DisposeAccessibleFrame( pTmpFlyFrame );
+ m_rImp.AddAccessibleFrame( pTmpFlyFrame );
+ }
+ else
+ {
+ m_rImp.DisposeAccessibleObj(pTmpObj, true);
+ m_rImp.AddAccessibleObj( pTmpObj );
+ }
+#endif
+ }
+ else
+ {
+ // adjust loop counter
+ if ( bMovedForward )
+ ++i;
+ else if (i > 0)
+ --i;
+ }
+
+ } while ( ( bMovedForward && i < ( nObjCount - aMovedChildObjs.size() ) ) ||
+ ( !bMovedForward && i > ( nNewPos + aMovedChildObjs.size() ) ) );
+ }
+#if !ENABLE_WASM_STRIP_ACCESSIBILITY
+ else
+ {
+ // adjustments for accessibility API
+ m_rImp.DisposeAccessibleObj(pObj, true);
+ m_rImp.AddAccessibleObj( pObj );
+ }
+#endif
+
+ MoveRepeatedObjs( *pMovedAnchoredObj, aMovedChildObjs );
+}
+
+bool SwDrawView::TakeDragLimit( SdrDragMode eMode,
+ tools::Rectangle& rRect ) const
+{
+ const SdrMarkList &rMrkList = GetMarkedObjectList();
+ bool bRet = false;
+ if( 1 == rMrkList.GetMarkCount() )
+ {
+ const SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
+ SwRect aRect;
+ if( ::CalcClipRect( pObj, aRect, eMode == SdrDragMode::Move ) )
+ {
+ rRect = aRect.SVRect();
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+const SwFrame* SwDrawView::CalcAnchor()
+{
+ const SdrMarkList &rMrkList = GetMarkedObjectList();
+ if ( rMrkList.GetMarkCount() != 1 )
+ return nullptr;
+
+ SdrObject* pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ //Search for paragraph bound objects, otherwise only the
+ //current anchor. Search only if we currently drag.
+ const SwFrame* pAnch;
+ tools::Rectangle aMyRect;
+ auto pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj *>( pObj );
+ if ( pFlyDrawObj )
+ {
+ pAnch = pFlyDrawObj->GetFlyFrame()->GetAnchorFrame();
+ aMyRect = pFlyDrawObj->GetFlyFrame()->getFrameArea().SVRect();
+ }
+ else
+ {
+ SwDrawContact *pC = static_cast<SwDrawContact*>(GetUserCall(pObj));
+ // determine correct anchor position for 'virtual' drawing objects.
+ // #i26791#
+ pAnch = pC->GetAnchorFrame( pObj );
+ if( !pAnch )
+ {
+ pC->ConnectToLayout();
+ // determine correct anchor position for 'virtual' drawing objects.
+ // #i26791#
+ pAnch = pC->GetAnchorFrame( pObj );
+ }
+ aMyRect = pObj->GetSnapRect();
+ }
+
+ const bool bTopRight = pAnch && ( ( pAnch->IsVertical() &&
+ !pAnch->IsVertLR() ) ||
+ pAnch->IsRightToLeft() );
+ const Point aMyPt = bTopRight ? aMyRect.TopRight() : aMyRect.TopLeft();
+
+ Point aPt;
+ if ( IsAction() )
+ {
+ if ( !TakeDragObjAnchorPos( aPt, bTopRight ) )
+ return nullptr;
+ }
+ else
+ {
+ tools::Rectangle aRect = pObj->GetSnapRect();
+ aPt = bTopRight ? aRect.TopRight() : aRect.TopLeft();
+ }
+
+ if ( aPt != aMyPt )
+ {
+ if ( pAnch && pAnch->IsContentFrame() )
+ {
+ // allow drawing objects in header/footer,
+ // but exclude control objects.
+ bool bBodyOnly = CheckControlLayer( pObj );
+ pAnch = ::FindAnchor( static_cast<const SwContentFrame*>(pAnch), aPt, bBodyOnly );
+ }
+ else if ( !pFlyDrawObj )
+ {
+ const SwRect aRect( aPt.getX(), aPt.getY(), 1, 1 );
+
+ SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
+ if ( pContact->GetAnchorFrame( pObj ) &&
+ pContact->GetAnchorFrame( pObj )->IsPageFrame() )
+ pAnch = pContact->GetPageFrame();
+ else
+ pAnch = pContact->FindPage( aRect );
+ }
+ }
+ if( pAnch && !pAnch->IsProtected() )
+ m_aAnchorPoint = pAnch->GetFrameAnchorPos( ::HasWrap( pObj ) );
+ else
+ pAnch = nullptr;
+ return pAnch;
+}
+
+void SwDrawView::ShowDragAnchor()
+{
+ SdrHdl* pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor);
+ if ( ! pHdl )
+ pHdl = maHdlList.GetHdl(SdrHdlKind::Anchor_TR);
+
+ if(pHdl)
+ {
+ CalcAnchor();
+ pHdl->SetPos(m_aAnchorPoint);
+ }
+}
+
+void SwDrawView::MarkListHasChanged()
+{
+ Imp().GetShell()->DrawSelChanged();
+ FmFormView::MarkListHasChanged();
+}
+
+// #i7672#
+void SwDrawView::ModelHasChanged()
+{
+ // The ModelHasChanged() call in DrawingLayer also updates
+ // an eventually active text edit view (OutlinerView). This also leads
+ // to newly setting the background color for that edit view. Thus,
+ // this method rescues the current background color if an OutlinerView
+ // exists and re-establishes it then. To be more safe, the OutlinerView
+ // will be fetched again (maybe textedit has ended).
+ OutlinerView* pView = GetTextEditOutlinerView();
+ Color aBackColor;
+ bool bColorWasSaved(false);
+
+ if(pView)
+ {
+ aBackColor = pView->GetBackgroundColor();
+ bColorWasSaved = true;
+ }
+
+ // call parent
+ FmFormView::ModelHasChanged();
+
+ if(bColorWasSaved)
+ {
+ pView = GetTextEditOutlinerView();
+
+ if(pView)
+ {
+ pView->SetBackgroundColor(aBackColor);
+ }
+ }
+}
+
+void SwDrawView::MakeVisible( const tools::Rectangle &rRect, vcl::Window & )
+{
+ OSL_ENSURE( m_rImp.GetShell()->GetWin(), "MakeVisible, unknown Window");
+ m_rImp.GetShell()->MakeVisible( SwRect( rRect ) );
+}
+
+void SwDrawView::CheckPossibilities()
+{
+ FmFormView::CheckPossibilities();
+
+ //In addition to the existing flags of the objects themselves,
+ //which are evaluated by the DrawingEngine, other circumstances
+ //lead to a protection.
+ //Objects that are anchored in frames need to be protected
+ //if the content of the frame is protected.
+ //OLE-Objects may themselves wish a resize protection (StarMath)
+
+ const SdrMarkList &rMrkList = GetMarkedObjectList();
+ bool bProtect = false;
+ bool bSzProtect = false;
+ bool bRotate(false);
+
+ for ( size_t i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i )
+ {
+ const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
+ const SwFrame *pFrame = nullptr;
+ if ( auto pVirtFlyDrawObj = dynamic_cast< const SwVirtFlyDrawObj *>( pObj ) )
+ {
+ const SwFlyFrame *pFly = pVirtFlyDrawObj->GetFlyFrame();
+ if ( pFly )
+ {
+ pFrame = pFly->GetAnchorFrame();
+ if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
+ {
+ const SwNoTextFrame *const pNTF(static_cast<const SwNoTextFrame*>(pFly->Lower()));
+ const SwOLENode *const pOLENd = pNTF->GetNode()->GetOLENode();
+ const SwGrfNode *const pGrfNd = pNTF->GetNode()->GetGrfNode();
+
+ if ( pOLENd )
+ {
+ const uno::Reference < embed::XEmbeddedObject > xObj = const_cast< SwOLEObj& >(pOLENd->GetOLEObj()).GetOleRef();
+
+ if ( xObj.is() )
+ {
+ // --> improvement for the future, when more
+ // than one Writer fly frame can be selected.
+
+ // TODO/LATER: retrieve Aspect - from where?!
+ bSzProtect |= ( embed::EmbedMisc::EMBED_NEVERRESIZE & xObj->getStatus( embed::Aspects::MSOLE_CONTENT ) ) != 0;
+
+ // #i972: protect position if it is a Math object anchored 'as char' and baseline alignment is activated
+ SwDoc* pDoc = Imp().GetShell()->GetDoc();
+ const bool bProtectMathPos = SotExchange::IsMath( xObj->getClassID() )
+ && RndStdIds::FLY_AS_CHAR == pFly->GetFormat()->GetAnchor().GetAnchorId()
+ && pDoc->GetDocumentSettingManager().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT );
+ if (bProtectMathPos)
+ m_bMoveProtect = true;
+ }
+ }
+ else if(pGrfNd)
+ {
+ // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops
+ // as soon as bMoveProtect is set, but since rotation is valid only with
+ // a single object selected this makes no difference
+ bRotate = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ SwDrawContact *pC = static_cast<SwDrawContact*>(GetUserCall(pObj));
+ if ( pC )
+ pFrame = pC->GetAnchorFrame( pObj );
+ }
+ if ( pFrame )
+ bProtect = pFrame->IsProtected(); //Frames, areas etc.
+ {
+ SwFrameFormat* pFrameFormat( ::FindFrameFormat( const_cast<SdrObject*>(pObj) ) );
+ if ( !pFrameFormat )
+ {
+ OSL_FAIL( "<SwDrawView::CheckPossibilities()> - missing frame format" );
+ bProtect = true;
+ }
+ else if ((RndStdIds::FLY_AS_CHAR == pFrameFormat->GetAnchor().GetAnchorId()) &&
+ rMrkList.GetMarkCount() > 1 )
+ {
+ bProtect = true;
+ }
+ }
+ }
+ m_bMoveProtect |= bProtect;
+ m_bResizeProtect |= bProtect || bSzProtect;
+
+ // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected
+ m_bRotateFreeAllowed |= bRotate && !bProtect;
+ m_bRotate90Allowed |= m_bRotateFreeAllowed;
+}
+
+/// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects.
+void SwDrawView::ReplaceMarkedDrawVirtObjs( SdrMarkView& _rMarkView )
+{
+ SdrPageView* pDrawPageView = _rMarkView.GetSdrPageView();
+ const SdrMarkList& rMarkList = _rMarkView.GetMarkedObjectList();
+
+ if( !rMarkList.GetMarkCount() )
+ return;
+
+ // collect marked objects in a local data structure
+ std::vector<SdrObject*> aMarkedObjs;
+ for( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
+ {
+ SdrObject* pMarkedObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ aMarkedObjs.push_back( pMarkedObj );
+ }
+ // unmark all objects
+ _rMarkView.UnmarkAllObj();
+ // re-mark objects, but for marked <SwDrawVirtObj>-objects marked its
+ // reference object.
+ while ( !aMarkedObjs.empty() )
+ {
+ SdrObject* pMarkObj = aMarkedObjs.back();
+ if ( auto pVirtObj = dynamic_cast<SwDrawVirtObj *>( pMarkObj ) )
+ {
+ SdrObject* pRefObj = &(pVirtObj->ReferencedObj());
+ if ( !_rMarkView.IsObjMarked( pRefObj ) )
+ {
+ _rMarkView.MarkObj( pRefObj, pDrawPageView );
+ }
+ }
+ else
+ {
+ _rMarkView.MarkObj( pMarkObj, pDrawPageView );
+ }
+
+ aMarkedObjs.pop_back();
+ }
+ // sort marked list in order to assure consistent state in drawing layer
+ _rMarkView.SortMarkedObjects();
+}
+
+SfxViewShell* SwDrawView::GetSfxViewShell() const
+{
+ return m_rImp.GetShell()->GetSfxViewShell();
+}
+
+void SwDrawView::DeleteMarked()
+{
+ SwDoc* pDoc = Imp().GetShell()->GetDoc();
+ SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+ if ( pTmpRoot )
+ pTmpRoot->StartAllAction();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+ // replace marked <SwDrawVirtObj>-objects by its reference objects.
+ if (SdrPageView* pDrawPageView = m_rImp.GetPageView())
+ {
+ ReplaceMarkedDrawVirtObjs(pDrawPageView->GetView());
+ }
+
+ // Check what textboxes have to be deleted afterwards.
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ std::vector<SwFrameFormat*> aTextBoxesToDelete;
+ for (size_t i = 0; i < rMarkList.GetMarkCount(); ++i)
+ {
+ SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ SwContact* pContact = GetUserCall(pObject);
+ SwFrameFormat* pFormat = pContact->GetFormat();
+ if (pObject->getChildrenOfSdrObject())
+ {
+ auto pChildTextBoxes = SwTextBoxHelper::CollectTextBoxes(pObject, pFormat);
+ for (auto& rChildTextBox : pChildTextBoxes)
+ aTextBoxesToDelete.push_back(rChildTextBox);
+ }
+ else
+ if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
+ aTextBoxesToDelete.push_back(pTextBox);
+ }
+
+ if ( pDoc->DeleteSelection( *this ) )
+ {
+ FmFormView::DeleteMarked();
+ ::FrameNotify( Imp().GetShell(), FLY_DRAG_END );
+ }
+
+ // Only delete these now: earlier deletion would clear the mark list as well.
+ // Delete in reverse order, assuming that the container is sorted by anchor positions.
+ for (int i = aTextBoxesToDelete.size() - 1; i >= 0; --i)
+ {
+ SwFrameFormat*& rpTextBox = aTextBoxesToDelete[i];
+ pDoc->getIDocumentLayoutAccess().DelLayoutFormat(rpTextBox);
+ }
+
+ pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
+ if( pTmpRoot )
+ pTmpRoot->EndAllAction();
+}
+
+// Create a new view-local UndoManager manager for Writer
+std::unique_ptr<SdrUndoManager> SwDrawView::createLocalTextUndoManager()
+{
+ std::unique_ptr<SdrUndoManager> pUndoManager(new SdrUndoManager);
+ pUndoManager->SetDocShell(SfxObjectShell::Current());
+ return pUndoManager;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */