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

Quelle  feshview.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 <hintids.hxx>
#include <svx/constructhelper.hxx>
#include <svx/strings.hrc>
#include <svx/sdrobjectfilter.hxx>
#include <svx/svddrgmt.hxx>
#include <svx/svditer.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdouno.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdocirc.hxx>
#include <svx/svdopath.hxx>
#include <svx/sxciaitm.hxx>
#include <svx/svdocapt.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnedit.hxx>
#include <svx/xlnstit.hxx>
#include <svx/svdomeas.hxx>
#include <svx/sdtagitm.hxx>
#include <svx/sdtacitm.hxx>
#include <svx/sdtaaitm.hxx>
#include <editeng/opaqitem.hxx>
#include <editeng/protitem.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/dialmgr.hxx>
#include <tools/globname.hxx>
#include <sot/exchange.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentSettingAccess.hxx>
#include <DocumentSettingManager.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <drawdoc.hxx>
#include <textboxhelper.hxx>
#include <frmfmt.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <fmtfsize.hxx>
#include <fmtanchr.hxx>
#include <fmtornt.hxx>
#include <fmtsrnd.hxx>
#include <fmtcntnt.hxx>
#include <fmtflcnt.hxx>
#include <fmtcnct.hxx>
#include <swmodule.hxx>
#include <fesh.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <sectfrm.hxx>
#include <cellfrm.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <dview.hxx>
#include <dflyobj.hxx>
#include <dcontact.hxx>
#include <viewimp.hxx>
#include <flyfrm.hxx>
#include <pam.hxx>
#include <ndole.hxx>
#include <ndgrf.hxx>
#include <ndtxt.hxx>
#include <viewopt.hxx>
#include <swundo.hxx>
#include <notxtfrm.hxx>
#include <txtfrm.hxx>
#include <mdiexp.hxx>
#include <sortedobjs.hxx>
#include <HandleAnchorNodeChg.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <calbck.hxx>
#include <PostItMgr.hxx>
#include <AnnotationWin.hxx>
#include <flyfrms.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svx/svxids.hrc>
#include <osl/diagnose.h>

#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>

#include <svx/srchdlg.hxx>

#define SCROLLVAL 75

using namespace com::sun::star;

SwFlyFrame *GetFlyFromMarked( const SdrMarkList *pLst, SwViewShell *pSh )
{
    if ( !pLst )
        pLst = pSh->HasDrawView() ? &pSh->Imp()->GetDrawView()->GetMarkedObjectList():nullptr;

    if ( pLst && pLst->GetMarkCount() == 1 )
    {
        SdrObject *pO = pLst->GetMark( 0 )->GetMarkedSdrObj();
        if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
            return pVirtO->GetFlyFrame();
    }
    return nullptr;
}

static void lcl_GrabCursor( SwFEShell* pSh, SwFlyFrame* pOldSelFly, const SwFrameFormat* pNewDrawFormat = nullptr)
{
    const SwFrameFormat *pFlyFormat = pSh->SelFlyGrabCursor();
    if( pFlyFormat && !pSh->ActionPend() &&
                        (!pOldSelFly || pOldSelFly->GetFormat() != pFlyFormat) )
    {
        // now call set macro if applicable
        pSh->GetFlyMacroLnk().Call( static_cast<const SwFlyFrameFormat*>(pFlyFormat) );
        // if a dialog was started inside a macro, then
        // MouseButtonUp arrives at macro and not to us. Therefore
        // flag is always set here and will never be switched to
        // respective Shell !!!!!!!

        g_bNoInterrupt = false;
    }
    else if( !pFlyFormat || RES_DRAWFRMFMT == pFlyFormat->Which() )
    {
        // --> assure consistent cursor
        pSh->KillPams();
        pSh->ClearMark();
        if (pNewDrawFormat)
        {
            // If we selected a draw shape format, move the cursor to its anchor position.
            // SetCursor() may pick something inside, which is not wanted: code later assumes that
            // the cursor is at the anchor point if a shape is selected.
            const SwPosition* pContentAnchor = pNewDrawFormat->GetAnchor().GetContentAnchor();
            if (pContentAnchor)
            {
                pSh->SetSelection(SwPaM(*pContentAnchor));
            }
        }
        else
        {
            pSh->SetCursor( pSh->Imp()->GetDrawView()->GetAllMarkedRect().TopLeft(), true);
        }
    }
}

bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
{
    SwDrawView *pDView = Imp()->GetDrawView();
    if(!pDView)
        return false;
    CurrShell aCurr( this );
    StartAction();    // action is necessary to assure only one AttrChgdNotify
                      // (e.g. due to Unmark->MarkListHasChgd) arrives

    const SdrMarkList &rMrkList = pDView->GetMarkedObjectList();
    const bool bHadSelection = rMrkList.GetMarkCount();
    const bool bAddSelect = 0 != (SW_ADD_SELECT & nFlag);
    const bool bEnterGroup = 0 != (SW_ENTER_GROUP & nFlag);
    SwFlyFrame* pOldSelFly = nullptr;
    const Point aOldPos( pDView->GetAllMarkedRect().TopLeft() );

    if( bHadSelection )
    {
        // call Unmark when !bAddSelect or if fly was selected
        bool bUnmark = !bAddSelect;

        if ( rMrkList.GetMarkCount() == 1 )
        {
            // if fly was selected, deselect it first
            pOldSelFly = ::GetFlyFromMarked( &rMrkList, this );
            if ( pOldSelFly )
            {
                const sal_uInt16 nType = GetCntType();
                if( nType != CNT_TXT || (SW_LEAVE_FRAME & nFlag) ||
                    ( pOldSelFly->GetFormat()->GetProtect().IsContentProtected()
                     && !IsReadOnlyAvailable() ))
                {
                    SdrObject *pOldObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
                    // If a fly is deselected, which contains graphic, OLE or
                    // otherwise, the cursor should be removed from it.
                    // Similar if a fly with protected content is deselected.
                    // For simplicity we put the cursor next to the upper-left
                    // corner.
                    Point aPt( pOldSelFly->getFrameArea().Pos() );
                    aPt.setX(aPt.getX() - 1);
                    bool bUnLockView = !IsViewLocked();
                    LockView( true );
                    SetCursor( aPt, true );

                    // in tables, fix lost position, when the selected image was
                    // anchored as character at beginning of the table row:
                    // in this case, the text cursor was positionated after the
                    // floating table, and not before the image, as in other positions
                    // in the table row (and if the table wasn't a floating one,
                    // the text cursor lost completely)
                    if ( SW_LEAVE_FRAME & nFlag )
                    {
                        const SwContact* pContact = GetUserCall(pOldObj);
                        if ( pContact && pContact->ObjAnchoredAsChar() &&
                                pOldSelFly->GetAnchorFrame() &&
                                pOldSelFly->GetAnchorFrame()->GetUpper() )
                        {
                            const SwNode * pOldNd = pContact->GetAnchorNode().FindTableNode();
                            const SwNode * pNewNd = GetCursor()->GetPointNode().FindTableNode();
                            // the original image was in a table, but the cursor is not in that
                            if ( pOldNd && pOldNd != pNewNd )
                            {
                                const SwRect& rCellFrame =
                                    pOldSelFly->GetAnchorFrame()->GetUpper()->getFrameArea();
                                Point aPtCellTopRight( rCellFrame.Pos() );
                                aPtCellTopRight.setX( aPtCellTopRight.X() + rCellFrame.Width() );
                                if ( SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(this) )
                                    // put the text cursor in the same cell
                                    pWrtShell->SelectTableRowCol( aPtCellTopRight );
                            }
                            // same table, but not in the same cell
                            else if ( pOldNd && pOldNd == pNewNd &&
                                    GetCursor()->GetPointNode().GetTextNode() &&
                                    pContact->GetAnchorNode().GetTableBox() !=
                                    GetCursor()->GetPointNode().GetTextNode()->GetTableBox() )
                            {
                                aPt.setX( aPt.getX() + 2 + pOldSelFly->getFrameArea().Width() );
                                // put the text cursor after the object
                                SetCursor( aPt, true );
                            }
                        }
                    }

                    if( bUnLockView )
                        LockView( false );
                }
                if ( nType & CNT_GRF &&
                     static_cast<SwNoTextFrame*>(pOldSelFly->Lower())->HasAnimation() )
                {
                    GetWin()->Invalidate( pOldSelFly->getFrameArea().SVRect() );
                }

                // Cancel crop mode
                if ( SdrDragMode::Crop == GetDragMode() )
                    SetDragMode( SdrDragMode::Move );

                bUnmark = true;
            }
        }
        if ( bUnmark )
        {
            pDView->UnmarkAll();
            if (pOldSelFly)
                pOldSelFly->SelectionHasChanged(this);
        }
    }
    else
    {
        KillPams();
        ClearMark();
        if (pObj && dynamic_cast<SwWrtShell*>(this)) // ensure it's own mgr
        {
            if (::sw::annotation::SwAnnotationWin *const pAnnotation{
                    GetPostItMgr()->GetActiveSidebarWin()})
            {
                pAnnotation->UnsetActiveSidebarWin();
            }
        }
    }

    if ( pObj )
    {
        OSL_ENSURE( !bEnterGroup, "SW_ENTER_GROUP is not supported" );
        pDView->MarkObj( pObj, Imp()->GetPageView() );
    }
    else
    {
        // tolerance limit of Drawing-SS
        const auto nHdlSizePixel = Imp()->GetDrawView()->GetMarkHdlSizePixel();
        short nMinMove;
        if (comphelper::LibreOfficeKit::isActive())
            nMinMove = static_cast<short>(OutputDevice::LogicToLogic(Size(nHdlSizePixel/2,0), MapMode(MapUnit::MapPixel), GetOut()->GetMapMode()).Width());
        else
            nMinMove = static_cast<short>(GetOut()->PixelToLogic(Size(nHdlSizePixel/2, 0)).Width());

        pDView->MarkObj( rPt, nMinMove, bAddSelect, bEnterGroup );
    }

    const bool bRet = 0 != rMrkList.GetMarkCount();

    if ( rMrkList.GetMarkCount() > 1 )
    {
        // It sucks if Drawing objects were selected and now
        // additionally a fly is selected.
        for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
        {
            SdrObject *pTmpObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
            bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) !=  nullptr;
            if( bForget )
            {
                pDView->UnmarkAll();
                pDView->MarkObj( pTmpObj, Imp()->GetPageView(), bAddSelect, bEnterGroup );
                break;
            }
        }
    }

    if (rMrkList.GetMarkCount() == 1)
    {
        SwFlyFrame* pSelFly = ::GetFlyFromMarked(&rMrkList, this);
        if (pSelFly && pSelFly->IsFlySplitAllowed())
        {
            auto pMaster = static_cast<SwFlyAtContentFrame*>(pSelFly);
            while (pMaster->IsFollow())
            {
                pMaster = pMaster->GetPrecede();
            }
            if (pMaster != pSelFly)
            {
                // A follow fly frame is selected, select the master instead. Selection of a follow
                // would not be ideal, since one can't customize its vertical position (always
                // starts at the top of the page).
                pDView->UnmarkAll();
                pDView->MarkObj(pMaster->DrawObj(), Imp()->GetPageView(), bAddSelect, bEnterGroup);
            }
        }
    }

    if ( rMrkList.GetMarkCount() == 1 )
    {
        SwFlyFrame *pSelFly = ::GetFlyFromMarked( &rMrkList, this );
        if (pSelFly)
            pSelFly->SelectionHasChanged(this);
    }

    SwFrameFormat* pNewDrawFormat = nullptr;
    if (!(nFlag & SW_ALLOW_TEXTBOX))
    {
        // If the fly frame is a textbox of a shape, then select the shape instead.
        for (size_t i = 0; i < rMrkList.GetMarkCount(); ++i)
        {
            SdrObject* pObject = rMrkList.GetMark(i)->GetMarkedSdrObj();
            SwContact* pContact = GetUserCall(pObject);
            if (!pContact)
            {
                continue;
            }

            SwFrameFormat* pFormat = pContact->GetFormat();
            if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
            {
                SdrObject* pShape = pShapeFormat->FindSdrObject();
                pDView->UnmarkAll();
                pDView->MarkObj(pShape, Imp()->GetPageView(), bAddSelect, bEnterGroup);
                // Remember that this frame format was marked for selection.
                pNewDrawFormat = pShapeFormat;
                break;
            }
        }
    }

    if ( bRet )
    {
        ::lcl_GrabCursor(this, pOldSelFly, pNewDrawFormat);
        if ( GetCntType() & CNT_GRF )
        {
            const SwFlyFrame *pTmp = GetFlyFromMarked( &rMrkList, this );
            OSL_ENSURE( pTmp, "Graphic without Fly" );
            if ( pTmp && static_cast<const SwNoTextFrame*>(pTmp->Lower())->HasAnimation() )
                static_cast<const SwNoTextFrame*>(pTmp->Lower())->StopAnimation( GetOut() );
        }
    }
    else if ( !pOldSelFly && bHadSelection )
        SetCursor( aOldPos, true);

    if( bRet || !bHadSelection )
        CallChgLnk();

    // update status line
    ::FrameNotify( this, bRet ? FLY_DRAG_START : FLY_DRAG_END );

    EndAction();
    return bRet;
}

/*
 *  Description: MoveAnchor( nDir ) looked for an another Anchor for
 *  the selected drawing object (or fly frame) in the given direction.
 *  An object "as character" doesn't moves anyway.
 *  A page bounded object could move to the previous/next page with up/down,
 *  an object bounded "at paragraph" moves to the previous/next paragraph, too.
 *  An object bounded "at character" moves to the previous/next paragraph
 *  with up/down and to the previous/next character with left/right.
 *  If the anchor for at paragraph/character bounded objects has vertical or
 *  right_to_left text direction, the directions for up/down/left/right will
 *  interpreted accordingly.
 *  An object bounded "at fly" takes the center of the actual anchor and looks
 *  for the nearest fly frame in the given direction.
 */


static bool LessX( Point const & aPt1, Point const & aPt2, bool bOld )
{
    return aPt1.getX() < aPt2.getX()
            || ( aPt1.getX() == aPt2.getX()
                && ( aPt1.getY() < aPt2.getY()
                    || ( aPt1.getY() == aPt2.getY() && bOld ) ) );
}
static bool LessY( Point const & aPt1, Point const & aPt2, bool bOld )
{
    return aPt1.getY() < aPt2.getY()
            || ( aPt1.getY() == aPt2.getY()
                && ( aPt1.getX() < aPt2.getX()
                    || ( aPt1.getX() == aPt2.getX() && bOld ) ) );
}

bool SwFEShell::MoveAnchor( SwMove nDir )
{
    if (!Imp()->GetDrawView())
        return false;
    const SdrMarkList& pMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    if (1 != pMrkList.GetMarkCount())
        return false;

    SdrObject *pObj = pMrkList.GetMark( 0 )->GetMarkedSdrObj();
    SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
    if (!pContact)
        return false;

    SwFrame* pOld;
    SwFlyFrame* pFly = nullptr;
    if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
    {
        pFly = pVirtO->GetFlyFrame();
        pOld = pFly->AnchorFrame();
    }
    else
        pOld = pContact->GetAnchorFrame( pObj );
    bool bRet = false;
    if( pOld )
    {
        SwFrame* pNew = pOld;
        // #i28701#
        SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
        SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
        SwFormatAnchor aAnch( pFormat->GetAnchor() );
        RndStdIds nAnchorId = aAnch.GetAnchorId();
        if ( RndStdIds::FLY_AS_CHAR == nAnchorId )
            return false;
        if( pOld->IsVertical() )
        {
            if( pOld->IsTextFrame() )
            {
                switch( nDir ) {
                    case SwMove::UP: nDir = SwMove::LEFT; break;
                    case SwMove::DOWN: nDir = SwMove::RIGHT; break;
                    case SwMove::LEFT: nDir = SwMove::DOWN; break;
                    case SwMove::RIGHT: nDir = SwMove::UP; break;
                }
                if( pOld->IsRightToLeft() )
                {
                    if( nDir == SwMove::LEFT )
                        nDir = SwMove::RIGHT;
                    else if( nDir == SwMove::RIGHT )
                        nDir = SwMove::LEFT;
                }
            }
        }
        switch ( nAnchorId ) {
            case RndStdIds::FLY_AT_PAGE:
            {
                OSL_ENSURE( pOld->IsPageFrame(), "Wrong anchor, page expected." );
                if( SwMove::UP == nDir )
                    pNew = pOld->GetPrev();
                else if( SwMove::DOWN == nDir )
                    pNew = pOld->GetNext();
                if( pNew && pNew != pOld )
                {
                    aAnch.SetPageNum( static_cast<SwPageFrame*>(pNew)->GetPhyPageNum() );
                    bRet = true;
                }
                break;
            }
            case RndStdIds::FLY_AT_CHAR:
            {
                OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
                if( SwMove::LEFT == nDir || SwMove::RIGHT == nDir )
                {
                    SwPosition pos = *aAnch.GetContentAnchor();
                    SwTextFrame *const pOldFrame(static_cast<SwTextFrame*>(pOld));
                    TextFrameIndex const nAct(pOldFrame->MapModelToViewPos(pos));
                    if( SwMove::LEFT == nDir )
                    {
                        bRet = true;
                        if( nAct )
                        {
                            pos = pOldFrame->MapViewToModelPos(nAct - TextFrameIndex(1));
                        }
                        else
                            nDir = SwMove::UP;
                    }
                    else
                    {
                        TextFrameIndex const nMax(pOldFrame->GetText().getLength());
                        if( nAct < nMax )
                        {
                            bRet = true;
                            pos = pOldFrame->MapViewToModelPos(nAct + TextFrameIndex(1));
                        }
                        else
                            nDir = SwMove::DOWN;
                    }
                    if( pos != *aAnch.GetContentAnchor())
                        aAnch.SetAnchor( &pos );
                }
                [[fallthrough]];
            }
            case RndStdIds::FLY_AT_PARA:
            {
                OSL_ENSURE(pOld->IsTextFrame(), "Wrong anchor, text frame expected.");
                if( SwMove::UP == nDir )
                    pNew = pOld->FindPrev();
                else if( SwMove::DOWN == nDir )
                    pNew = pOld->FindNext();
                if( pNew && pNew != pOld && pNew->IsContentFrame() )
                {
                    SwTextFrame *const pNewFrame(static_cast<SwTextFrame*>(pNew));
                    SwPosition const pos = pNewFrame->MapViewToModelPos(
                        TextFrameIndex(
                            (bRet && pNewFrame->GetText().getLength() != 0)
                                ? pNewFrame->GetText().getLength() - 1
                                : 0));
                    aAnch.SetAnchor( &pos );
                    bRet = true;
                }
                else if( SwMove::UP == nDir || SwMove::DOWN == nDir )
                    bRet = false;
                break;
            }
            case RndStdIds::FLY_AT_FLY:
            {
                OSL_ENSURE( pOld->IsFlyFrame(), "Wrong anchor, fly frame expected.");
                SwPageFrame* pPage = pOld->FindPageFrame();
                OSL_ENSURE( pPage, "Where's my page?" );
                SwFlyFrame* pNewFly = nullptr;
                if( pPage->GetSortedObjs() )
                {
                    bool bOld = false;
                    Point aCenter( pOld->getFrameArea().Left() + pOld->getFrameArea().Width()/2,
                                   pOld->getFrameArea().Top() + pOld->getFrameArea().Height()/2 );
                    Point aBest;
                    for(SwAnchoredObject* pAnchObj : *pPage->GetSortedObjs())
                    {
                        ifauto pTmp = pAnchObj->DynCastFlyFrame() )
                        {
                            if( pTmp == pOld )
                                bOld = true;
                            else
                            {
                                const SwFlyFrame* pCheck = pFly ? pTmp : nullptr;
                                while( pCheck )
                                {
                                    if( pCheck == pFly )
                                        break;
                                    const SwFrame *pNxt = pCheck->GetAnchorFrame();
                                    pCheck = pNxt ? pNxt->FindFlyFrame() : nullptr;
                                }
                                if( pCheck || pTmp->IsProtected() )
                                    continue;
                                Point aNew( pTmp->getFrameArea().Left() +
                                            pTmp->getFrameArea().Width()/2,
                                            pTmp->getFrameArea().Top() +
                                            pTmp->getFrameArea().Height()/2 );
                                bool bAccept = false;
                                switch( nDir ) {
                                    case SwMove::RIGHT:
                                    {
                                        bAccept = LessX( aCenter, aNew, bOld )
                                             && ( !pNewFly ||
                                             LessX( aNew, aBest, false ) );
                                        break;
                                    }
                                    case SwMove::LEFT:
                                    {
                                        bAccept = LessX( aNew, aCenter, !bOld )
                                             && ( !pNewFly ||
                                             LessX( aBest, aNew, true ) );
                                        break;
                                    }
                                    case SwMove::UP:
                                    {
                                        bAccept = LessY( aNew, aCenter, !bOld )
                                             && ( !pNewFly ||
                                             LessY( aBest, aNew, true ) );
                                        break;
                                    }
                                    case SwMove::DOWN:
                                    {
                                        bAccept = LessY( aCenter, aNew, bOld )
                                             && ( !pNewFly ||
                                             LessY( aNew, aBest, false ) );
                                        break;
                                    }
                                }
                                if( bAccept )
                                {
                                    pNewFly = pTmp;
                                    aBest = aNew;
                                }
                            }
                        }
                    }
                }

                if( pNewFly )
                {
                    SwPosition aPos( *pNewFly->GetFormat()->
                                        GetContent().GetContentIdx());
                    aAnch.SetAnchor( &aPos );
                    bRet = true;
                }
                break;
            }
            defaultbreak;
        }
        if( bRet )
        {
            StartAllAction();
            // --> handle change of anchor node:
            // if count of the anchor frame also change, the fly frames have to be
            // re-created. Thus, delete all fly frames except the <this> before the
            // anchor attribute is change and re-create them afterwards.
            {
                std::unique_ptr<SwHandleAnchorNodeChg> pHandleAnchorNodeChg;
                SwFlyFrameFormat* pFlyFrameFormat( dynamic_cast<SwFlyFrameFormat*>(pFormat) );
                if ( pFlyFrameFormat )
                {
                    pHandleAnchorNodeChg.reset(
                        new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
                }
                pFormat->GetDoc().SetAttr( aAnch, *pFormat );
            }
            // #i28701# - no call of method
            // <CheckCharRectAndTopOfLine()> for to-character anchored
            // Writer fly frame needed. This method call can cause a
            // format of the anchor frame, which is no longer intended.
                    // Instead clear the anchor character rectangle and
                    // the top of line values for all to-character anchored objects.
            pAnchoredObj->ClearCharRectAndTopOfLine();
            EndAllAction();
        }
    }
    return bRet;
}

const SdrMarkList* SwFEShell::GetMarkList_() const
{
    const SdrMarkList* pMarkList = nullptr;
    if( Imp()->GetDrawView() != nullptr )
        pMarkList = &Imp()->GetDrawView()->GetMarkedObjectList();
    return pMarkList;
}

FrameTypeFlags SwFEShell::GetSelFrameType() const
{
    FrameTypeFlags eType;

    // get marked frame list, and check if anything is selected
    const SdrMarkList* pMarkList = GetMarkList_();
    if( pMarkList == nullptr  ||  pMarkList->GetMarkCount() == 0 )
        eType = FrameTypeFlags::NONE;
    else
    {
        // obtain marked item as fly frame; if no fly frame, it must
        // be a draw object
        const SwFlyFrame* pFly = ::GetFlyFromMarked(pMarkList, const_cast<SwFEShell*>(this));
        if ( pFly != nullptr )
        {
            if( pFly->IsFlyLayFrame() )
                eType = FrameTypeFlags::FLY_FREE;
            else if( pFly->IsFlyAtContentFrame() )
                eType = FrameTypeFlags::FLY_ATCNT;
            else
            {
                OSL_ENSURE( pFly->IsFlyInContentFrame(), "New frametype?" );
                eType = FrameTypeFlags::FLY_INCNT;
            }
        }
        else
            eType = FrameTypeFlags::DRAWOBJ;
    }

    return eType;
}

// does the draw selection contain a control?
bool SwFEShell::IsSelContainsControl() const
{
    bool bRet = false;

    // basically, copy the mechanism from GetSelFrameType(), but call
    // CheckControl... if you get a drawing object
    const SdrMarkList* pMarkList = GetMarkList_();
    if( pMarkList != nullptr  &&  pMarkList->GetMarkCount() == 1 )
    {
        // if we have one marked object, get the SdrObject and check
        // whether it contains a control
        const SdrObject* pSdrObject = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
        bRet = pSdrObject && ::CheckControlLayer( pSdrObject );
    }
    return bRet;
}

void SwFEShell::ScrollTo( const Point &rPt )
{
    const SwRect aRect( rPt, rPt );
    if ( IsScrollMDI( *this, aRect ) &&
         (!Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() ||
          Imp()->IsDragPossible( rPt )) )
    {
        ScrollMDI( *this, aRect, SCROLLVAL, SCROLLVAL );
    }
}

void SwFEShell::SetDragMode( SdrDragMode eDragMode )
{
    if ( Imp()->HasDrawView() )
        Imp()->GetDrawView()->SetDragMode( eDragMode );
}

SdrDragMode SwFEShell::GetDragMode() const
{
    SdrDragMode nRet = SdrDragMode(0);
    if ( Imp()->HasDrawView() )
    {
        nRet = Imp()->GetDrawView()->GetDragMode();
    }
    return nRet;
}

void SwFEShell::StartCropImage()
{
    if ( !Imp()->HasDrawView() )
    {
        return;
    }
    SdrView *pView = Imp()->GetDrawView();
    if (!pView) return;

    const SdrMarkList &rMarkList = pView->GetMarkedObjectList();
    if( 0 == rMarkList.GetMarkCount() ) {
        // No object selected
        return;
    }

    // If more than a single SwVirtFlyDrawObj is selected, select only the first SwVirtFlyDrawObj
    if ( rMarkList.GetMarkCount() > 1 )
    {
        for ( size_t i = 0; i < rMarkList.GetMarkCount(); ++i )
        {
            SdrObject *pTmpObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
            bool bForget = dynamic_cast<const SwVirtFlyDrawObj*>( pTmpObj) !=  nullptr;
            if( bForget )
            {
                pView->UnmarkAll();
                pView->MarkObj( pTmpObj, Imp()->GetPageView() );
                break;
            }
        }
    }

    // Activate CROP mode
    pView->SetEditMode( SdrViewEditMode::Edit );
    SetDragMode( SdrDragMode::Crop );
}

void SwFEShell::BeginDrag( const Point* pPt, bool bIsShift)
{
    SdrView *pView = Imp()->GetDrawView();
    if ( pView && pView->GetMarkedObjectList().GetMarkCount() != 0 )
    {
        m_pChainFrom.reset();
        m_pChainTo.reset();
        SdrHdl* pHdl = pView->PickHandle( *pPt );
        if (pView->BegDragObj( *pPt, nullptr, pHdl ))
            pView->GetDragMethod()->SetShiftPressed( bIsShift );
        ::FrameNotify( this );
    }
}

void SwFEShell::Drag( const Point *pPt, bool )
{
    OSL_ENSURE( Imp()->HasDrawView(), "Drag without DrawView?" );
    if ( HasDrawViewDrag() )
    {
        ScrollTo( *pPt );
        Imp()->GetDrawView()->MovDragObj( *pPt );
        Imp()->GetDrawView()->ShowDragAnchor();
        ::FrameNotify( this );
    }
}

void SwFEShell::EndDrag()
{
    OSL_ENSURE( Imp()->HasDrawView(), "EndDrag without DrawView?" );
    SdrView *pView = Imp()->GetDrawView();
    if ( !pView->IsDragObj() )
        return;

    for(SwViewShell& rSh : GetRingContainer())
        rSh.StartAction();

    StartUndo( SwUndoId::START );

    // #50778# Bug during dragging: In StartAction a HideShowXor is called.
    // In EndDragObj() this is reversed, for no reason and even wrong.
    // To restore consistency we should bring up the Xor again.

    // Reanimation from the hack #50778 to fix bug #97057
    // May be not the best solution, but the one with lowest risc at the moment.
    // pView->ShowShownXor( GetOut() );

    pView->EndDragObj();

    // DrawUndo on to flyframes are not stored
    //             The flys change the flag.
    GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(true);
    ChgAnchor( RndStdIds::FLY_AT_PARA, true );

    EndUndo( SwUndoId::END );

    for(SwViewShell& rSh : GetRingContainer())
    {
        rSh.EndAction();
        ifauto pCursorShell = dynamic_cast<SwCursorShell *>(&rSh) )
            pCursorShell->CallChgLnk();
    }

    GetDoc()->getIDocumentState().SetModified();
    ::FrameNotify( this );
}

void SwFEShell::BreakDrag()
{
    OSL_ENSURE( Imp()->HasDrawView(), "BreakDrag without DrawView?" );
    if( HasDrawViewDrag() )
        Imp()->GetDrawView()->BrkDragObj();
    SetChainMarker();
}

// If a fly is selected, pulls the crsr in the first ContentFrame
const SwFrameFormat* SwFEShell::SelFlyGrabCursor()
{
    if ( Imp()->HasDrawView() )
    {
        const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
        SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );

        if( pFly )
        {
            SwContentFrame *pCFrame = pFly->ContainsContent();
            if ( pCFrame )
            {
                // --> assure, that the cursor is consistent.
                KillPams();
                ClearMark();
                SwPaM       *pCursor  = GetCursor();

                if (pCFrame->IsTextFrame())
                {
                    *pCursor->GetPoint() = static_cast<SwTextFrame *>(pCFrame)
                        ->MapViewToModelPos(TextFrameIndex(0));
                }
                else
                {
                    assert(pCFrame->IsNoTextFrame());
                    SwContentNode *const pCNode = static_cast<SwNoTextFrame *>(pCFrame)->GetNode();
                    pCursor->GetPoint()->Assign(*pCNode);
                }

                SwRect& rChrRect = const_cast<SwRect&>(GetCharRect());
                rChrRect = pFly->getFramePrintArea();
                rChrRect.Pos() += pFly->getFrameArea().Pos();
                GetCursorDocPos() = rChrRect.Pos();
            }
            return pFly->GetFormat();
        }
    }
    return nullptr;
}

// Selection to above/below (Z-Order)
static void lcl_NotifyNeighbours( const SdrMarkList *pLst )
{
    // Rules for evasion have changed.
    // 1. The environment of the fly and everything inside should be notified
    // 2. The content of the frame itself has to be notified
    // 3. Frames displaced by the frame have to be notified
    // 4. Also Drawing objects can displace frames
    for( size_t j = 0; j < pLst->GetMarkCount(); ++j )
    {
        SwPageFrame *pPage;
        bool bCheckNeighbours = false;
        sal_Int16 aHori = text::HoriOrientation::NONE;
        SwRect aRect;
        SdrObject *pO = pLst->GetMark( j )->GetMarkedSdrObj();
        if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pO))
        {
            SwFlyFrame *pFly = pVirtO->GetFlyFrame();

            const SwFormatHoriOrient &rHori = pFly->GetFormat()->GetHoriOrient();
            aHori = rHori.GetHoriOrient();
            if( text::HoriOrientation::NONE != aHori && text::HoriOrientation::CENTER != aHori &&
                pFly->IsFlyAtContentFrame() )
            {
                bCheckNeighbours = true;
                pFly->InvalidatePos();
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFly);
                aFrm.Pos().AdjustY(1 );
            }

            pPage = pFly->FindPageFrame();
            aRect = pFly->getFrameArea();
        }
        else
        {
            SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pO));
            if (!pContact)
                continue;

            SwFrame* pAnch = pContact->GetAnchorFrame( pO );
            if( !pAnch )
                continue;
            pPage = pAnch->FindPageFrame();
            // #i68520# - naming changed
            aRect = GetBoundRectOfAnchoredObj( pO );
        }

        const size_t nCount = pPage->GetSortedObjs() ? pPage->GetSortedObjs()->size() : 0;
        for ( size_t i = 0; i < nCount; ++i )
        {
            SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
            SwFlyFrame* pAct = pAnchoredObj->DynCastFlyFrame();
            if ( !pAct )
                continue;

            SwRect aTmpCalcPnt( pAct->getFramePrintArea() );
            aTmpCalcPnt += pAct->getFrameArea().Pos();
            if ( aRect.Overlaps( aTmpCalcPnt ) )
            {
                SwContentFrame *pCnt = pAct->ContainsContent();
                while ( pCnt )
                {
                    aTmpCalcPnt = pCnt->getFramePrintArea();
                    aTmpCalcPnt += pCnt->getFrameArea().Pos();
                    if ( aRect.Overlaps( aTmpCalcPnt ) )
                        static_cast<SwFrame*>(pCnt)->Prepare( PrepareHint::FlyFrameAttributesChanged );
                    pCnt = pCnt->GetNextContentFrame();
                }
            }
            if ( bCheckNeighbours && pAct->IsFlyAtContentFrame() )
            {
                const SwFormatHoriOrient &rH = pAct->GetFormat()->GetHoriOrient();
                if ( rH.GetHoriOrient() == aHori &&
                     pAct->getFrameArea().Top()    <= aRect.Bottom() &&
                     pAct->getFrameArea().Bottom() >= aRect.Top() )
                {
                    pAct->InvalidatePos();
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pAct);
                    aFrm.Pos().AdjustY(1 );
                }
            }
        }
    }
}

void SwFEShell::SetLineEnds(SfxItemSet& rAttr, SdrObject const & rObj, sal_uInt16 nSlotId)
{
    ConstructHelper::SetLineEnds(rAttr, rObj, nSlotId, 100);
}

void SwFEShell::SelectionToTop( bool bTop )
{
    OSL_ENSURE( Imp()->HasDrawView(), "SelectionToTop without DrawView?" );
    const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );

    SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
    if ( pFly && pFly->IsFlyInContentFrame() )
        return;

    StartAllAction();
    if ( bTop )
        Imp()->GetDrawView()->PutMarkedToTop();
    else
        Imp()->GetDrawView()->MovMarkedToTop();
    ::lcl_NotifyNeighbours( &rMrkList );

    // Does the selection contain a textbox?
    for (size_t i = 0; i < rMrkList.GetMarkCount(); i++)
        if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
            // Get the textbox-shape
            if (auto pFormat = FindFrameFormat(pObj))
            {
                // If it has not textframe skip...
                if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
                    continue;
                // If it has a textframe so it is a textbox, get its page
                if (auto pDrwModel
                    = pFormat->GetDoc().getIDocumentDrawModelAccess().GetDrawModel())
                    // Not really understood why everything is on page 0...
                    // but it is easier to handle sdrobjects, that's true
                    if (auto pPage = pDrwModel->GetPage(0))
                    {
                        // nShift: it means how many layers the pObj have to be shifted up,
                        // in order not to interfere with other shapes and textboxes.
                        // Situations:
                        // - The next shape has textframe: This shape have to shifted with
                        //   two layers.
                        // - The next shape has not got textframe: This shape have to be
                        //   shifted only one layer up.
                        // - The next shape is null:
                        //      - This shape is already at heaven: Only the textframe have
                        //        to be adjusted.
                        sal_uInt32 nShift = 0;
                        // Get the one level higher object (note: can be nullptr!)
                        const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() + 1, pObj->GetOrdNum() + 1);
                        // If there is a higher object (not null)...
                        if (pNextObj)
                        {
                            // One level shift is necessary
                            nShift++;
                            // If this object is a textbox, two level increasing needed
                            // (one for the shape and one for the frame)
                            if (auto pNextFormat = FindFrameFormat(pNextObj))
                                if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
                                    || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
                                    nShift++;
                        }
                        // Set the new z-order.
                        pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
                    }
                // The shape is on the right level, correct the layer of the frame
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
            }

    GetDoc()->getIDocumentState().SetModified();
    EndAllAction();
}

void SwFEShell::SelectionToBottom( bool bBottom )
{
    OSL_ENSURE( Imp()->HasDrawView(), "SelectionToBottom without DrawView?" );
    const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    OSL_ENSURE( rMrkList.GetMarkCount(), "No object selected." );

    SwFlyFrame *pFly = ::GetFlyFromMarked( &rMrkList, this );
    if ( pFly && pFly->IsFlyInContentFrame() )
        return;

    StartAllAction();
    if ( bBottom )
        Imp()->GetDrawView()->PutMarkedToBtm();
    else
        Imp()->GetDrawView()->MovMarkedToBtm();
    ::lcl_NotifyNeighbours( &rMrkList );

    // If the selection has textbox
    for(size_t i = 0; i < rMrkList.GetMarkCount(); i++)
        if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
            // Get the shape of the textbox
            if (auto pFormat = FindFrameFormat(pObj))
            {
                // If the shape has not textframes skip.
                if (!SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, pObj))
                    continue;
                // If has, move the shape to correct level with...
                if (auto pDrwModel
                    = pFormat->GetDoc().getIDocumentDrawModelAccess().GetDrawModel())
                    if (auto pPage = pDrwModel->GetPage(0))
                    {
                        sal_uInt32 nOrdNum = pObj->GetOrdNum();
                        assert(nOrdNum > 0);
                        const auto pNextObj = pPage->SetObjectOrdNum(nOrdNum - 1, nOrdNum - 1);
                        // If there is a lower object (not null)...
                        if (pNextObj)
                        {
                            // If the lower has no textframe, just do nothing, else move by one lower
                            if (auto pNextFormat = FindFrameFormat(pNextObj))
                                if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT, pNextObj)
                                    || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
                                    pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() - 1);
                        }
                    }
                // And set correct layer for the selected textbox.
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
            }

    GetDoc()->getIDocumentState().SetModified();
    EndAllAction();
}

// Object above/below the document? 2 Controls, 1 Heaven, 0 Hell,
// SDRLAYER_NOTFOUND Ambiguous
SdrLayerID SwFEShell::GetLayerId() const
{
    if ( !Imp()->HasDrawView() )
        return SDRLAYER_NOTFOUND;

    SdrLayerID nRet = SDRLAYER_NOTFOUND;
    const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
    {
        const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
        if( !pObj )
            continue;
        if ( nRet == SDRLAYER_NOTFOUND )
            nRet = pObj->GetLayer();
        else if ( nRet != pObj->GetLayer() )
        {
            return SDRLAYER_NOTFOUND;
        }
    }
    return nRet;
}

// Object above/below the document
// Note: only visible objects can be marked. Thus, objects with invisible
//       layer IDs have not to be considered.
//       If <SwFEShell> exists, layout exists!!
void SwFEShell::ChangeOpaque( SdrLayerID nLayerId )
{
    if ( !Imp()->HasDrawView() )
        return;

    const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
    // correct type of <nControls>
    for ( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
    {
        SdrObject* pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
        if( !pObj )
            continue;
        // or group objects containing controls.
        // --> #i113730#
        // consider that a member of a drawing group has been selected.
        const SwContact* pContact = ::GetUserCall( pObj );
        OSL_ENSURE( pContact && pContact->GetMaster(), " - missing contact or missing master object at contact!" );
        const bool bControlObj = ( pContact && pContact->GetMaster() )
                                 ? ::CheckControlLayer( pContact->GetMaster() )
                                 : ::CheckControlLayer( pObj );
        if ( !bControlObj && pObj->GetLayer() != nLayerId )
        {
            pObj->SetLayer( nLayerId );
            InvalidateWindows( SwRect( pObj->GetCurrentBoundRect() ) );
            if (SwVirtFlyDrawObj* pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
            {
                SwFormat *pFormat = pVirtO->GetFlyFrame()->GetFormat();
                SvxOpaqueItem aOpa( pFormat->GetOpaque() );
                aOpa.SetValue(  nLayerId == rIDDMA.GetHellId() );
                pFormat->SetFormatAttr( aOpa );
                // If pObj has textframe, put its textframe to the right level
                if (auto pTextBx = FindFrameFormat(pObj))
                    SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx, pObj);
            }
        }
    }
    GetDoc()->getIDocumentState().SetModified();
}

void SwFEShell::SelectionToHeaven()
{
    ChangeOpaque( getIDocumentDrawModelAccess().GetHeavenId() );
}

void SwFEShell::SelectionToHell()
{
    ChangeOpaque( getIDocumentDrawModelAccess().GetHellId() );
}

size_t SwFEShell::GetSelectedObjCount() const
{
    if ( IsFrameSelected() || !Imp()->HasDrawView() )
        return 0;

    return Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount();
}

bool SwFEShell::IsFrameSelected() const
{
    if ( !Imp()->HasDrawView() )
        return false;
    else
        return nullptr != ::GetFlyFromMarked( &Imp()->GetDrawView()->GetMarkedObjectList(),
                                        const_cast<SwFEShell*>(this) );
}

bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
{
    if ( IsFrameSelected() || !Imp()->HasDrawView() )
        return false;
    else
        return Imp()->GetDrawView()->IsObjMarked( &rObj );
}

bool SwFEShell::IsRotationOfSwGrfNodePossible() const
{
    // RotGrfFlyFrame: check if RotationMode is possible
    const SdrView *pSdrView = Imp()->GetDrawView();

    if(pSdrView)
    {
        const SdrMarkList& rList(pSdrView->GetMarkedObjectList());

        if(1 == rList.GetMarkCount())
        {
            const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_castconst SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj()));

            if(nullptr != pVirtFlyDraw)
            {
                return pVirtFlyDraw->ContainsSwGrfNode();
            }
        }
    }

    return false;
}

bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const
{
    if (pObj)
    {
        const SdrMarkList& aMarkList = Imp()->GetDrawView()->GetMarkedObjectList();
        if (aMarkList.GetMarkCount() == 0)
        {
            return true;
        }
        SdrMark* pM=aMarkList.GetMark(0);
        if (pM)
        {
            SdrObject* pMarkObj = pM->GetMarkedSdrObj();
            if (pMarkObj && pMarkObj->getParentSdrObjectFromSdrObject() == pObj->getParentSdrObjectFromSdrObject())
                return true;
        }
    }
    return false;
}

void SwFEShell::EndTextEdit()
{
    // Terminate the TextEditMode. If required (default if the object
    // does not contain any more text and does not carry attributes) the object
    // is deleted. All other objects marked are preserved.

    OSL_ENSURE( Imp()->HasDrawView() && Imp()->GetDrawView()->IsTextEdit(),
            "EndTextEdit a no Object" );

    StartAllAction();
    SdrView *pView = Imp()->GetDrawView();
    SdrObject *pObj = pView->GetTextEditObject();
    SdrObjUserCall* pUserCall = GetUserCall(pObj);
    if( nullptr != pUserCall )
    {
        SdrObject *pTmp = static_cast<SwContact*>(pUserCall)->GetMaster();
        if( !pTmp )
            pTmp = pObj;
        pUserCall->Changed( *pTmp, SdrUserCallType::Resize, pTmp->GetLastBoundRect() );
    }
    if ( !pObj->getParentSdrObjectFromSdrObject() )
    {
        if ( SdrEndTextEditKind::ShouldBeDeleted == pView->SdrEndTextEdit(true) )
        {
            if ( pView->GetMarkedObjectList().GetMarkCount() > 1 )
            {
                SdrMarkList aSave( pView->GetMarkedObjectList() );
                aSave.DeleteMark( aSave.FindObject( pObj ) );
                if ( aSave.GetMarkCount() )
                {
                    pView->UnmarkAll();
                    pView->MarkObj( pObj, Imp()->GetPageView() );
                }
                DelSelectedObj();
                for ( size_t i = 0; i < aSave.GetMarkCount(); ++i )
                    pView->MarkObj( aSave.GetMark( i )->GetMarkedSdrObj(), Imp()->GetPageView() );
            }
            else
                DelSelectedObj();
        }
    }
    else
        pView->SdrEndTextEdit();

    if (comphelper::LibreOfficeKit::isActive())
        SfxLokHelper::notifyOtherViews(GetSfxViewShell(), LOK_CALLBACK_VIEW_LOCK, "rectangle""EMPTY"_ostr);

    EndAllAction();
}

bool SwFEShell::IsInsideSelectedObj( const Point &rPt )
{
    if( Imp()->HasDrawView() )
    {
        SwDrawView *pDView = Imp()->GetDrawView();

        if( pDView->GetMarkedObjectList().GetMarkCount() &&
            pDView->IsMarkedObjHit( rPt ) )
        {
            return true;
        }
    }
    return false;
}

bool SwFEShell::IsObjSelectable( const Point& rPt )
{
    CurrShell aCurr(this);
    SwDrawView *pDView = Imp()->GetDrawView();
    bool bRet = false;
    if( pDView )
    {
        SdrPageView* pPV;
        const auto nOld = pDView->GetHitTolerancePixel();
        pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );

        bRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE) != nullptr;
        pDView->SetHitTolerancePixel( nOld );
    }
    return bRet;
}

SdrObject* SwFEShell::GetObjAt( const Point& rPt )
{
    SdrObject* pRet = nullptr;
    CurrShell aCurr(this);
    SwDrawView *pDView = Imp()->GetDrawView();
    if( pDView )
    {
        SdrPageView* pPV;
        const auto nOld = pDView->GetHitTolerancePixel();
        pDView->SetHitTolerancePixel( pDView->GetMarkHdlSizePixel()/2 );

        pRet = pDView->PickObj(rPt, pDView->getHitTolLog(), pPV, SdrSearchOptions::PICKMARKABLE);
        pDView->SetHitTolerancePixel( nOld );
    }
    return pRet;
}

// Test if there is an object at that position and if it should be selected.
bool SwFEShell::ShouldObjectBeSelected(const Point& rPt, bool *pSelectFrameInsteadOfCroppedImage)
{
    CurrShell aCurr(this);
    SwDrawView *pDrawView = Imp()->GetDrawView();
    bool bRet(false);

    if(pDrawView)
    {
        SdrPageView* pPV;
        const auto nOld(pDrawView->GetHitTolerancePixel());
        sal_uInt16 nHitTol = pDrawView->getHitTolLog();

        pDrawView->SetHitTolerancePixel(pDrawView->GetMarkHdlSizePixel()/2);
        SdrObject* pObj = pDrawView->PickObj(rPt, nHitTol, pPV, SdrSearchOptions::PICKMARKABLE);
        pDrawView->SetHitTolerancePixel(nOld);

        if (pObj)
        {
            bRet = true;
            const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
            // #i89920#
            // Do not select object in background which is overlapping this text
            // at the given position.
            bool bObjInBackground( false );
            {
                if ( pObj->GetLayer() == rIDDMA.GetHellId() )
                {
                    if (const SwContact* pContact = ::GetUserCall( pObj ))
                    {
                        const SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( pObj );
                        const SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
                        const SwFormatSurround& rSurround = pFormat->GetSurround();
                        if ( rSurround.GetSurround() == css::text::WrapTextMode_THROUGH )
                        {
                            bObjInBackground = true;
                        }
                    }
                }
            }
            if ( bObjInBackground )
            {
                const SwPageFrame* pPageFrame = GetLayout()->GetPageAtPos( rPt );
                if( pPageFrame )
                {
                    const SwContentFrame* pContentFrame( pPageFrame->ContainsContent() );
                    while ( pContentFrame )
                    {
                        if ( pContentFrame->UnionFrame().Contains( rPt ) )
                        {
                            const SwTextFrame* pTextFrame = pContentFrame->DynCastTextFrame();
                            if ( pTextFrame )
                            {
                                SwPosition aPos(GetDoc()->GetNodes());
                                Point aTmpPt( rPt );
                                if (pTextFrame->GetKeyCursorOfst(&aPos, aTmpPt))
                                {
                                    SwRect aCursorCharRect;
                                    if (pTextFrame->GetCharRect(aCursorCharRect,
                                                aPos))
                                    {
                                        if ( aCursorCharRect.Overlaps( SwRect( pObj->GetLastBoundRect() ) ) )
                                        {
                                            bRet = false;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                bRet = false;
                            }
                            break;
                        }

                        pContentFrame = pContentFrame->GetNextContentFrame();
                    }
                }
            }

            // Don't select header / footer objects in body edition and vice-versa
            SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
            if (pContact && !pContact->ObjAnchoredAtPage() )
            {
                const SwNode& rAnchorNode = pContact->GetAnchorNode();
                bool bInHdrFtr = GetDoc()->IsInHeaderFooter( rAnchorNode );
                if (IsHeaderFooterEdit() != bInHdrFtr)
                {
                    bRet = false;
                }
            }

            if ( bRet )
            {
                const SdrPage* pPage = rIDDMA.GetDrawModel()->GetPage(0);
                for(auto it = pPage->begin() + pObj->GetOrdNum() + 1; it != pPage->end(); ++it)
                {
                    SdrObject *pCandidate = it->get();

                    SwVirtFlyDrawObj* pDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pCandidate);
                    if (pDrawObj && pDrawObj->GetCurrentBoundRect().Contains(rPt))
                    {
                        bRet = false;
                        break;
                    }
                }
            }

            // within table row, where image cropped by the fixed table row height,
            // click position must be in the cell frame, where the image anchored as character
            if ( bRet && pContact && pContact->ObjAnchoredAsChar() )
            {
                if ( const SwTableBox *pBox = pContact->GetAnchorNode().GetTableBox() )
                {
                    SwIterator<SwCellFrame, SwFormat> aIter( *pBox->GetFrameFormat() );
                    bool bContainsClickPosition = false;
                    for (SwCellFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
                    {
                        const SwRect& rRect = pFrame->getFrameArea();
                        // click inside the cell frame which contains the cropped image
                        if ( rRect.Contains( rPt ) )
                        {
                            // click next to the right cell border
                            if ( pSelectFrameInsteadOfCroppedImage &&
                                    !rRect.Contains( Point(rPt.X() + 2 * nHitTol, rPt.Y()) ) )
                            {
                                *pSelectFrameInsteadOfCroppedImage = true;
                            }
                            bContainsClickPosition = true;
                            break;
                        }
                        // or click on the right table border of the same table frame
                        else if ( pSelectFrameInsteadOfCroppedImage &&
                            ( pFrame->GetUpper() && pFrame->GetUpper()->GetUpper() &&
                              pFrame->GetUpper()->GetUpper()->getFrameArea().Contains(
                                  Point(rPt.X() - 2 * nHitTol, rPt.Y()) ) &&
                              !pFrame->GetUpper()->GetUpper()->getFrameArea().Contains(
                                  Point(rPt.X() + 2 * nHitTol, rPt.Y()) ) ) )
                        {
                            *pSelectFrameInsteadOfCroppedImage = true;
                            bContainsClickPosition = true;
                        }
                    }
                    if ( !bContainsClickPosition )
                        bRet = false;
                }
            }
        }
    }

    return bRet;
}

/*
 * If an object was selected, we assume its upper-left corner
 * otherwise the middle of the current CharRects.
 * Does the object include a control or groups,
 * which comprise only controls
 */

static bool lcl_IsControlGroup( const SdrObject *pObj )
{
    bool bRet = false;
    if(dynamic_cast<const SdrUnoObj*>( pObj) !=  nullptr)
        bRet = true;
    else ifauto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
    {
        bRet = true;
        const SdrObjList *pLst = pObjGroup->GetSubList();
        for (const rtl::Reference<SdrObject>& pChildObj : *pLst)
            if( !::lcl_IsControlGroup( pChildObj.get() ) )
                return false;
    }
    return bRet;
}

namespace
{
    class MarkableObjectsOnly : public svx::ISdrObjectFilter
    {
    public:
        explicit MarkableObjectsOnly( SdrPageView* i_pPV )
            :m_pPV( i_pPV )
        {
        }

        virtual bool    includeObject( const SdrObject& i_rObject ) const override
        {
            return m_pPV && m_pPV->GetView().IsObjMarkable( &i_rObject, m_pPV );
        }

    private:
        SdrPageView*    m_pPV;
    };
}

const SdrObject* SwFEShell::GetBestObject(bool bNext, GotoObjFlags eType, bool bFlat,
                                          const svx::ISdrObjectFilter* pFilter,
                                          bool* pbWrapped)
{
    if (pbWrapped)
        *pbWrapped = false;

    if( !Imp()->HasDrawView() )
        return nullptr;

    const SdrObject *pBest  = nullptr,
                    *pTop   = nullptr;

    const tools::Long nTmp = bNext ? LONG_MAX : 0;
    Point aBestPos( nTmp, nTmp );
    Point aTopPos(  nTmp, nTmp );
    Point aCurPos;
    Point aPos;
    bool bNoDraw((GotoObjFlags::DrawAny & eType) == GotoObjFlags::NONE);
    bool bNoFly((GotoObjFlags::FlyAny & eType) == GotoObjFlags::NONE);

    if( !bNoFly && bNoDraw )
    {
        SwFlyFrame *pFly = GetCurrFrame( false )->FindFlyFrame();
        if( pFly )
            pBest = pFly->GetVirtDrawObj();
    }
    const SdrMarkList &rMrkList = Imp()->GetDrawView()->GetMarkedObjectList();
    SdrPageView* pPV = Imp()->GetDrawView()->GetSdrPageView();

    MarkableObjectsOnly aDefaultFilter( pPV );
    if ( !pFilter )
        pFilter = &aDefaultFilter;

    if( !pBest || rMrkList.GetMarkCount() == 1 )
    {
        // Determine starting point
        SdrObjList* pList = nullptr;
        if ( rMrkList.GetMarkCount() )
        {
            const SdrObject* pStartObj = rMrkList.GetMark(0)->GetMarkedSdrObj();
            ifauto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pStartObj) )
                aPos = pVirtFlyDrawObj->GetFlyFrame()->getFrameArea().Pos();
            else
                aPos = pStartObj->GetSnapRect().TopLeft();

            // If an object inside a group is selected, we want to
            // iterate over the group members.
            if ( ! pStartObj->GetUserCall() )
                pList = pStartObj->getParentSdrObjListFromSdrObject();
        }
        else
        {
            // If no object is selected, we check if we just entered a group.
            // In this case we want to iterate over the group members.
            aPos = GetCharRect().Center();
            const SdrObject* pStartObj = pPV ? pPV->GetCurrentGroup() : nullptr;
            if ( dynamic_cast<const SdrObjGroup*>( pStartObj) )
                pList = pStartObj->GetSubList();
        }

        if ( ! pList )
        {
            // Here we are if
            // A  No object has been selected and no group has been entered or
            // B  An object has been selected and it is not inside a group
            pList = getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 );
        }

        OSL_ENSURE( pList, "No object list to iterate" );

        SdrObjListIter aObjIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
        while ( aObjIter.IsMore() )
        {
            SdrObject* pObj = aObjIter.Next();
            SwVirtFlyDrawObj *pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pObj);
            if( ( bNoFly && pVirtO ) ||
                ( bNoDraw && !pVirtO ) ||
                // Ignore TextBoxes of draw shapes here, so that
                // SwFEShell::SelectObj() won't jump back on this list, meaning
                // we never jump to the next draw shape.
                (pVirtO && pVirtO->IsTextBox()) ||
                ( eType == GotoObjFlags::DrawSimple && lcl_IsControlGroup( pObj ) ) ||
                ( eType == GotoObjFlags::DrawControl && !lcl_IsControlGroup( pObj ) ) ||
                !pFilter->includeObject( *pObj ) )
                continue;
            if (pVirtO)
            {
                SwFlyFrame *pFly = pVirtO->GetFlyFrame();
                if( GotoObjFlags::FlyAny != ( GotoObjFlags::FlyAny & eType ) )
                {
                    switch ( eType )
                    {
                        case GotoObjFlags::FlyFrame:
                            if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
                                continue;
                        break;
                        case GotoObjFlags::FlyGrf:
                            if ( pFly->Lower() &&
                                (!pFly->Lower()->IsNoTextFrame() ||
                                 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetGrfNode()))
                                continue;
                        break;
                        case GotoObjFlags::FlyOLE:
                            if ( pFly->Lower() &&
                                (!pFly->Lower()->IsNoTextFrame() ||
                                 !static_cast<SwNoTextFrame*>(pFly->Lower())->GetNode()->GetOLENode()))
                                continue;
                        break;
                        defaultbreak;
                    }
                }
                aCurPos = pFly->getFrameArea().Pos();
            }
            else
                aCurPos = pObj->GetSnapRect().TopLeft();

            // Special case if another object is on same Y.
            if( aCurPos != aPos &&          // only when it is not me
                aCurPos.getY() == aPos.getY() &&  // Y positions equal
                (bNext? (aCurPos.getX() > aPos.getX()) :  // lies next to me
                        (aCurPos.getX() < aPos.getX())) ) // " reverse
            {
                aBestPos = Point( nTmp, nTmp );
                SdrObjListIter aTmpIter( pList, bFlat ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups );
                while ( aTmpIter.IsMore() )
                {
                    SdrObject* pTmpObj = aTmpIter.Next();
                    pVirtO = dynamic_cast<SwVirtFlyDrawObj*>(pTmpObj);
                    if( ( bNoFly && pVirtO ) || ( bNoDraw && !pVirtO ) )
                        continue;
                    if (pVirtO)
                    {
                        aCurPos = pVirtO->GetFlyFrame()->getFrameArea().Pos();
                    }
                    else
                        aCurPos = pTmpObj->GetCurrentBoundRect().TopLeft();

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

--> maximum size reached

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

Messung V0.5
C=92 H=95 G=93

¤ Dauer der Verarbeitung: 0.37 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.