Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/draw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 101 kB image not shown  

Quelle  dcontact.cxx   Sprache: C

 
/* -*- 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 <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 rtl::Reference<SwDrawVirtObj>& 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 )
{
    if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
       return pFlyDrawObj->GetFormat();

    if (SwContact* pContact = GetUserCall(pObj))
        return pContact->GetFormat();

    return nullptr;
}

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 )
{
    for (; pObj; pObj = pObj->getParentSdrObjectFromSdrObject())
    {
        if (auto pUserCall = pObj->GetUserCall())
        {
            assert(dynamic_cast<SwContact*>(pUserCall)
                   && "<::GetUserCall(..)> - wrong type of found object user call.");
            return static_cast<SwContact*>(pUserCall);
        }
    }
    return nullptr;
}

/// Returns true if the SrdObject is a Marquee-Object (scrolling text)
bool IsMarqueeTextObj( const SdrObject& rObj )
{
    if (SdrInventor::Default != rObj.GetObjInventor() ||
        SdrObjKind::Text != rObj.GetObjIdentifier())
        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 (const rtl::Reference<SdrObject>& pObj : *pLst)
            {
                MoveObjToLayer( _bToVisible, pObj.get() );
            }
        }
    }
    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,
            " - 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 (rHint.GetId() == SfxHintId::SwFindSdrObject)
    {
        auto pFindSdrObjectHint = static_cast<const sw::FindSdrObjectHint*>(&rHint);
        if(!pFindSdrObjectHint->m_rpObject)
            pFindSdrObjectHint->m_rpObject = GetMaster();
    }
    else if (rHint.GetId() == SfxHintId::SwWW8AnchorConv)
    {
        auto pWW8AnchorConvHint = static_cast<const sw::WW8AnchorConvHint*>(&rHint);
        // determine anchored object
        SwAnchoredObject* pAnchoredObj(nullptr);
        {
            std::vector<SwAnchoredObject*> aAnchoredObjs;
            GetAnchoredObjs(aAnchoredObjs);
            if(!aAnchoredObjs.empty())
                pAnchoredObj = aAnchoredObjs.front();
        }
        // no anchored object found. Thus, the needed layout information can't
        // be determined. --> no conversion
        if(!pAnchoredObj)
            return;
        // no conversion for anchored drawing object, which aren't attached to an
        // anchor frame.
        // This is the case for drawing objects, which are anchored inside a page
        // header/footer of an *unused* page style.
        if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
            return;
        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();
    rtl::Reference<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.get(), nOrdNum);
    }
    // #i27030# - insert new <SwVirtFlyDrawObj> instance
    // into drawing page with correct order number
    else
        rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj.get(), pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
    // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
    // is in a visible layer.
    pContact->MoveObjToVisibleLayer(pDrawObj.get());
    return pDrawObj.get();
}

// #i26791#
const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
{
    assert(pSdrObj);
    assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
    assert(GetUserCall(pSdrObj) == this &&
        " - provided object doesn't belong to this contact");

    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(rHint.GetId() == SfxHintId::SwGetZOrder)
    {
        auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
        // #i11176#
        // This also needs to work when no layout exists. Thus, for
        // FlyFrames an alternative method is used now in that case.
        auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
        if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
            pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
    }
}

// SwDrawContact

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 (const rtl::Reference<SdrObject>& pChildObj : *pLst)
        {
            if ( ::CheckControlLayer( pChildObj.get() ) )
            {
                // #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 )
        maAnchoredDrawObj.ClearDrawObj();
}

void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc& rDoc)
{
    for(sw::SpzFrameFormat* pFly: *rDoc.GetSpzFrameFormats())
    {
        if(pFly->Which() == RES_DRAWFRMFMT) // ie. SwDrawFrameFormat*
            pFly->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()) &&
            " - 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(
            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();
        // to break the reference cycle
        rpDrawVirtObj->AnchoredObj().ClearDrawObj();
    }
    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& rDoc = GetFormat()->GetDoc();
    if ( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() &&
         rDoc.getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
    {
        return;
    }

    // #i44339#
    // no event handling, if document is in destruction.
    // Exception: It's the SdrUserCallType::Delete event
    if ( rDoc.IsInDtor() && eType != SdrUserCallType::Delete )
    {
        return;
    }

    //Put on Action, but not if presently anywhere an action runs.
    bool bHasActions(true);
    SwRootFrame *pTmpRoot = rDoc.getIDocumentLayoutAccess().GetCurrentLayout();
    if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
    {
        SwViewShell* const pSh = rDoc.getIDocumentLayoutAccess().GetCurrentViewShell();
        if ( pSh )
        {
            for(SwViewShell& rShell : pSh->GetRingContainer() )
            {
                if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
                {
                    bHasActions = true;
                    break;
                }
                bHasActions = false;
            }
        }
        if(!bHasActions)
            pTmpRoot->StartAllAction();
    }
    SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
    Changed_( rObj, eType, &rOldBoundRect );    //Attention, possibly suicidal!

    if(!bHasActions)
        pTmpRoot->EndAllAction();
}

/// helper class for method <SwDrawContact::Changed_(..)> for handling nested
/// <SdrObjUserCall> events
class NestedUserCallHdl
{
    private:
        SwDrawContact* mpDrawContact;
        bool mbParentUserCallActive;
        SdrUserCallType meParentUserCallEventType;

    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( " - unknown nested 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( " - 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(!" - 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& rDoc = GetFormat()->GetDoc();

                // avoid Undo creation
                ::sw::UndoGuard const ug(rDoc.GetIDocumentUndoRedo());

                // hide any artificial "changes" made by synchronizing the textbox position
                const bool bEnableSetModified = rDoc.getIDocumentState().IsEnableSetModified();
                rDoc.getIDocumentState().SetEnableSetModified(false);

                SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>
                    aSyncSet( rDoc.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( rDoc.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());

                rDoc.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_ANCHOR == nWhich )
        {
            pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
        }
        return pAnchorFormat;
    }
    const SwFormatAnchor* lcl_getAnchorFormat( const SwAttrSetChg& _rItem )
    {
        return _rItem.GetChgSet()->GetItemIfSet( RES_ANCHOR, false );
    }
}

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(SfxHintId::SwRemoveUnoObject == rHint.GetId())
    {
        // nothing to do
        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if(SfxHintId::SwFormatChange == rHint.GetId()
            || SfxHintId::SwUpdateAttr == rHint.GetId())
    {
        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if (rHint.GetId() == SfxHintId::SwLegacyModify
            || rHint.GetId() == SfxHintId::SwAttrSetChange
            || rHint.GetId() == SfxHintId::SwObjectDying)
    {
        SAL_WARN_IF(mbDisconnectInProgress, "sw.core"" called during disconnection.");

        const SwFormatAnchor* pNewAnchorFormat = nullptr;
        const SwFormatAnchor* pOldAnchorFormat = nullptr;
        if (rHint.GetId() == SfxHintId::SwLegacyModify)
        {
            auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
            if (pLegacyHint->m_pNew)
                pNewAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pNew);
            if (pLegacyHint->m_pOld)
                pOldAnchorFormat = lcl_getAnchorFormat(*pLegacyHint->m_pOld);
        }
        else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
        {
            auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
            if (pChangeHint->m_pNew)
                pNewAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pNew);
            if (pChangeHint->m_pOld)
                pOldAnchorFormat = lcl_getAnchorFormat(*pChangeHint->m_pOld);
        }

        if(pNewAnchorFormat)
        {
            // Do not respond to a Reset Anchor!
            if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
            {
                // no connect to layout during disconnection
                if(!mbDisconnectInProgress)
                {
                    // determine old object rectangle of 'master' drawing object
                    // for notification
                    const tools::Rectangle* pOldRect = nullptr;
                    tools::Rectangle aOldRect;
                    if(GetAnchorFrame())
                    {
                        // --> #i36181# - include spacing in object
                        // rectangle for notification.
                        aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
                        pOldRect = &aOldRect;
                    }
                    // re-connect to layout due to anchor format change
                    ConnectToLayout(pNewAnchorFormat);
                    // notify background of drawing objects
                    lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
                    NotifyBackgroundOfAllVirtObjs(pOldRect);

                    if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
                    {
                        if(maAnchoredDrawObj.DrawObj())
                        {
                            // --> #i102752#
                            // assure that a ShapePropertyChangeNotifier exists
                            maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(u"AnchorType"_ustr);
                        }
                        else
                            SAL_WARN("sw.core""SwDrawContact::Modify: no draw object here?");
                    }
                }
            }
            else
                DisconnectFromLayout();
        }
        // --> #i62875# - no further notification, if not connected to Writer layout
        else if ( maAnchoredDrawObj.GetAnchorFrame() &&
                  maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
        {
            bool bUpdateSortedObjsList(false);
            if (rHint.GetId() == SfxHintId::SwLegacyModify)
            {
                auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
                sal_uInt16 nWhich = pLegacyHint->m_pNew ? pLegacyHint->m_pNew->Which() : 0;
                switch(nWhich)
                {
                    case RES_UL_SPACE:
                    case RES_LR_SPACE:
                    case RES_HORI_ORIENT:
                    case RES_VERT_ORIENT:
                    case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
                        break;
                    case RES_SURROUND:
                    case RES_OPAQUE:
                    case RES_WRAP_INFLUENCE_ON_OBJPOS:
                        // --> #i28701# - on change of wrapping style, hell|heaven layer,
                        // or wrapping style influence an update of the <SwSortedObjs> list,
                        // the drawing object is registered in, has to be performed. This is triggered
                        // by the 1st parameter of method call <InvalidateObjs_(..)>.
                        bUpdateSortedObjsList = true;
                        break;
                    default:
                        assert(!" - unhandled attribute?");
                }
            }
            else if (rHint.GetId() == SfxHintId::SwAttrSetChange)
            {
                // #i35443#
                auto pChangeHint = static_cast<const sw::AttrSetChangeHint*>(&rHint);
                auto pChgSet = pChangeHint->m_pNew ? pChangeHint->m_pNew->GetChgSet() : nullptr;
                if(pChgSet && (pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
                        pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
                        pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET))
                    bUpdateSortedObjsList = true;
            }
            lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
            NotifyBackgroundOfAllVirtObjs(nullptr);
            InvalidateObjs_(bUpdateSortedObjsList);
        }

        // #i51474#
        GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
    }
    else if (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
    {
        auto pDrawFrameFormatHint = static_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 (rHint.GetId() == SfxHintId::SwCheckDrawFrameFormatLayer)
    {
        auto pCheckDrawFrameFormatLayerHint = static_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint);
        *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
    }
    else if (rHint.GetId() == SfxHintId::SwContactChanged)
    {
        auto pContactChangedHint = static_cast<const sw::ContactChangedHint*>(&rHint);
        if(!*pContactChangedHint->m_ppObject)
            *pContactChangedHint->m_ppObject = GetMaster();
        auto pObject = *pContactChangedHint->m_ppObject;
        Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
    }
    else if (rHint.GetId() == SfxHintId::SwDrawFormatLayoutCopy)
    {
        auto pDrawFormatLayoutCopyHint = static_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint);
        const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
        rtl::Reference<SdrObject> xNewObj =
                pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
                        *GetMaster(),
                        pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == &rFormat.GetDoc());
        new SwDrawContact(
                &pDrawFormatLayoutCopyHint->m_rDestFormat, xNewObj.get() );
        // #i49730# - notify draw frame format that position attributes are
        // already set, if the position attributes are already set at the
        // source draw frame format.
        if(rFormat.IsPosAttrSet())
            pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
    }
    else if (rHint.GetId() == SfxHintId::SwRestoreFlyAnchor)
    {
        auto pRestoreFlyAnchorHint = static_cast<const sw::RestoreFlyAnchorHint*>(&rHint);
        SdrObject* pObj = GetMaster();
        if(GetAnchorFrame() && !pObj->IsInserted())
        {
            auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&&gt;(rMod)).GetDoc().getIDocumentDrawModelAccess().GetDrawModel();
            assert(pDrawModel);
            pDrawModel->GetPage(0)->InsertObject(pObj);
        }
        pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
    }
    else if (rHint.GetId() == SfxHintId::SwCreatePortion)
    {
        auto pCreatePortionHint = static_cast<const sw::CreatePortionHint*>(&rHint);
        if(*pCreatePortionHint->m_ppContact)
            return;
        *pCreatePortionHint->m_ppContact = this// This is kind of ridiculous: the FrameFormat doesn't even hold a pointer to the contact itself,  but here we are leaking it out randomly
        if(!GetAnchorFrame())
        {
            // No direct positioning needed any more
            ConnectToLayout();
            // Move object to visible layer
            MoveObjToVisibleLayer(GetMaster());
        }
    }
    else if (rHint.GetId() == SfxHintId::SwCollectTextObjects)
    {
        auto pCollectTextObjectsHint = static_cast<const sw::CollectTextObjectsHint*>(&rHint);
        auto pSdrO = GetMaster();
        if(!pSdrO)
            return;
        if(dynamic_cast<const SdrObjGroup*>(pSdrO))
        {
            SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
            //iterate inside of a grouped object
            while(aListIter.IsMore())
            {
                SdrTextObj* pTextObj = DynCastSdrTextObj(aListIter.Next());
                if(pTextObj && pTextObj->HasText())
                    pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
            }
        }
        else if(SdrTextObj* pTextObj = DynCastSdrTextObj(pSdrO))
        {
            if(pTextObj->HasText())
                pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
        }
    }
    else if (rHint.GetId() == SfxHintId::SwGetZOrder)
    {
        auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint);
        auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
        if (pFormat && pFormat->Which() == RES_DRAWFRMFMT)
            pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
    }
    else if (rHint.GetId() == SfxHintId::SwGetObjectConnected)
    {
        auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint);
        pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
    }
}

// #i26791#
// #i28701# - added parameter <_bUpdateSortedObjsList>
void SwDrawContact::InvalidateObjs_( 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
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.18 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.