    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include <config_features.h>

    #include <com/sun/star/media/XPlayer.hpp>
    #include <fusel.hxx>
    #include <basic/sbstar.hxx>
    #include <svx/svddrgmt.hxx>
    #include <svx/svdpagv.hxx>
    #include <svx/svdogrp.hxx>
    #include <svx/scene3d.hxx>
    #include <drawview.hxx>
    #include <svtools/imapobj.hxx>
    #include <svl/urihelper.hxx>
    #include <unotools/localfilehelper.hxx>
    #include <unotools/securityoptions.hxx>
    #include <svx/svxids.hrc>
    #include <svx/xfillit0.hxx>
    #include <sfx2/app.hxx>
    #include <sfx2/viewfrm.hxx>
    #include <svl/aeitem.hxx>
    #include <svl/stritem.hxx>
    #include <svl/intitem.hxx>
    #include <sfx2/dispatch.hxx>
    #include <tools/urlobj.hxx>
    #include <sfx2/docfile.hxx>
    #include <editeng/eeitem.hxx>
    #include <editeng/flditem.hxx>

    #include <svx/svdotable.hxx>

    #include <app.hrc>

    #include <GraphicDocShell.hxx>
    #include <sdmod.hxx>
    #include <DrawDocShell.hxx>
    #include <stlpool.hxx>
    #include <anminfo.hxx>
    #include <fudraw.hxx>
    #include <ViewShell.hxx>
    #include <ViewShellBase.hxx>
    #include <FrameView.hxx>
    #include <View.hxx>
    #include <Window.hxx>
    #include <drawdoc.hxx>
    #include <sdpage.hxx>
    #include <DrawViewShell.hxx>
    #include <ToolBarManager.hxx>
    #include <pgjump.hxx>
    #include <svx/globl3d.hxx>
    #include <Client.hxx>

    #include <slideshow.hxx>

    #include <svx/svdundo.hxx>
    #include <avmedia/mediawindow.hxx>

    #include <svx/sdrhittesthelper.hxx>

    #include <LibreOfficeKit/LibreOfficeKitEnums.h>
    #include <comphelper/lok.hxx>

    using namespace ::com::sun::star;

    namespace sd {

    FuSelection::FuSelection (
        ViewShell* pViewSh,
        ::sd::Window* pWin,
        ::sd::View* pView,
        SdDrawDocument* pDoc,
        SfxRequest& rReq)
        : FuDraw(pViewSh, pWin, pView, pDoc, rReq),
          bTempRotation(false),
          bSelectionChanged(false),
          pHdl(nullptr),
          bSuppressChangesOfSelection(false),
          bMirrorSide0(false),
          nEditMode(SID_BEZIER_MOVE),
          pWaterCanCandidate(nullptr)
         //Add Shift+UP/DOWN/LEFT/RIGHT key to move the position of insert point,
         //and SHIFT+ENTER key to decide the position and draw the new insert point
        ,bBeginInsertPoint(false),
          oldPoint(0,0)
      ,bMovedToCenterPoint(false)
    {
    }

    rtl::Reference<FuPoor> FuSelection::Create( ViewShell* pViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument* pDoc, SfxRequest& rReq )
    {
        rtl::Reference<FuPoor> xFunc( new FuSelection( pViewSh, pWin, pView, pDoc, rReq ) );
        xFunc->DoExecute(rReq);
        return xFunc;
    }

    void FuSelection::DoExecute( SfxRequest& rReq )
    {
        FuDraw::DoExecute( rReq );

        // Select object bar
        SelectionHasChanged();
    }

    FuSelection::~FuSelection()
    {
        mpView->UnmarkAllPoints();
        mpView->ResetCreationActive();

        if ( mpView->GetDragMode() != SdrDragMode::Move )
        {
            mpView->SetDragMode(SdrDragMode::Move);
        }
    }

    bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
    {
        pHdl = nullptr;
        bool bReturn = FuDraw::MouseButtonDown(rMEvt);
        bool bWaterCan = SD_MOD()->GetWaterCan();
        const bool bReadOnly = mpDocSh->IsReadOnly();
        // When the right mouse button is pressed then only select objects
        // (and deselect others) as a preparation for showing the context
        // menu.
        const bool bSelectionOnly = rMEvt.IsRight();

        bMBDown = true;
        bSelectionChanged = false;

        if ( mpView->IsAction() )
        {
            if ( rMEvt.IsRight() )
                mpView->BckAction();
            return true;
        }

        sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
        sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );

        if (comphelper::LibreOfficeKit::isActive())
        {
            // When tiled rendering, we always work in logic units, use the non-pixel constants.
            nDrgLog = DRGLOG;
            nHitLog = HITLOG;
        }

        // The following code is executed for right clicks as well as for left
        // clicks in order to modify the selection for the right button as a
        // preparation for the context menu.  The functions BegMarkObject() and
        // BegDragObject(), however, are not called for right clicks because a)
        // it makes no sense and b) to have IsAction() return sal_False when called
        // from Command() which is a prerequisite for the context menu.
        if ((rMEvt.IsLeft() || rMEvt.IsRight())
            && !mpView->IsAction()
            && (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints()))
        {
            /******************************************************************
            * NO BEZIER_EDITOR
            ******************************************************************/
            mpWindow->CaptureMouse();
            pHdl = mpView->PickHandle(aMDPos);

            long nAngle0  = GetAngle(aMDPos - mpView->GetRef1());
            nAngle0 -= 27000;
            nAngle0 = NormAngle36000(nAngle0);
            bMirrorSide0 = nAngle0 < 18000;

            if (!pHdl && mpView->Is3DRotationCreationActive())
            {
                /******************************************************************
                * If 3D-rotation bodies are about to be created,
                * end creation now.
                ******************************************************************/
                bSuppressChangesOfSelection = true;
                mpWindow->EnterWait();
                mpView->End3DCreation();
                bSuppressChangesOfSelection = false;
                mpView->ResetCreationActive();
                mpWindow->LeaveWait();
            }

            bool bTextEdit = false;
            SdrViewEvent aVEvt;
            SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);

            if ( eHit == SdrHitKind::TextEditObj && ( mpViewShell->GetFrameView()->IsQuickEdit() || dynamic_cast< sdr::table::SdrTableObj* >( aVEvt.pObj ) != nullptr ) )
            {
                bTextEdit = true;
            }

            if(!bTextEdit
                && !mpDocSh->IsReadOnly()
                && ((mpView->IsMarkedHit(aMDPos, nHitLog) && !rMEvt.IsShift() && !rMEvt.IsMod2()) || pHdl != nullptr)
                && (rMEvt.GetClicks() != 2)
                )
            {
                if (!pHdl && mpView->Is3DRotationCreationActive())
                {
                    // Switch between 3D-rotation body -> selection
                    mpView->ResetCreationActive();
                }
                else if (bWaterCan)
                {
                    // Remember the selected object for proper handling in
                    // MouseButtonUp().
                    pWaterCanCandidate = pickObject (aMDPos);
                }
                else
                {
                    // hit handle or marked object
                    bFirstMouseMove = true;
                    aDragTimer.Start();
                }

                if ( ! rMEvt.IsRight())
                    if (mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog))
                        mpView->GetDragMethod()->SetShiftPressed( rMEvt.IsShift() );
                bReturn = true;
            }
            else
            {
                SdrPageView* pPV = nullptr;
                SdrObject* pObj = !rMEvt.IsMod2() ? mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) : nullptr;
                if (pObj)
                {
                    mpView->BegMacroObj(aMDPos, nHitLog, pObj, pPV, mpWindow);
                    bReturn = true;
                }
                else if ( bTextEdit )
                {
                    sal_uInt16 nSdrObjKind = aVEvt.pObj->GetObjIdentifier();

                    if (aVEvt.pObj->GetObjInventor() == SdrInventor::Default &&
                        (nSdrObjKind == OBJ_TEXT ||
                         nSdrObjKind == OBJ_TITLETEXT ||
                         nSdrObjKind == OBJ_OUTLINETEXT ||
                         !aVEvt.pObj->IsEmptyPresObj()))
                    {
                        // Seamless Editing: branch to text input
                        if (!rMEvt.IsShift())
                            mpView->UnmarkAll();

                        SfxUInt16Item aItem(SID_TEXTEDIT, 1);
                        mpViewShell->GetViewFrame()->GetDispatcher()->
                        ExecuteList(SID_TEXTEDIT,
                                SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
                                { &aItem });
                        return bReturn; // CAUTION, due to the synchronous slot the object is deleted now
                    }
                }
                else if ( !rMEvt.IsMod2() && rMEvt.GetClicks() == 1 &&
                          aVEvt.eEvent == SdrEventKind::ExecuteUrl )
                 {
                    mpWindow->ReleaseMouse();

                    SvtSecurityOptions aSecOpt;
                    if (!rMEvt.IsMod1() && aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
                        return true;
                    if (rMEvt.IsMod1() && !aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink))
                        return true;

                    SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.pURLField->GetURL());
                    SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
                    SfxBoolItem aBrowseItem( SID_BROWSE, true );
                    SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
                    mpWindow->ReleaseMouse();

                    // If tiled rendering, let client handles URL execution and early returns.
                    if (comphelper::LibreOfficeKit::isActive())
                    {
                        SfxViewShell& rSfxViewShell = mpViewShell->GetViewShellBase();
                        rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aVEvt.pURLField->GetURL().toUtf8().getStr());
                        return true;
                    }

                    if (rMEvt.IsMod1())
                    {
                        // Open in new frame
                        pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
                            SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
                            { &aStrItem, &aBrowseItem, &aReferer });
                    }
                    else
                    {
                        // Open in current frame
                        SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
                        pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
                            SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
                            { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
                    }

                    bReturn = true;
                }
                else if(!rMEvt.IsMod2()
                    && dynamic_cast< const DrawViewShell *>( mpViewShell ) !=  nullptr
                    )
                {
                    pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
                    if (pObj)
                    {
                        // Animate object when not just selecting.
                        if ( ! bSelectionOnly)
                            bReturn = AnimateObj(pObj, aMDPos);

                        if( !bReturn && (dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr || dynamic_cast< const E3dScene* >(pObj) != nullptr))
                        {
                            if(rMEvt.GetClicks() == 1)
                            {
                                // Look into the group
                                pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::DEEP);
                                if (pObj)
                                    bReturn = AnimateObj(pObj, aMDPos);
                            }
                            else if( !bReadOnly && rMEvt.GetClicks() == 2)
                            {
                                // New: double click on selected Group object
                                // enter group
                                if ( ! bSelectionOnly
                                    && pObj->getSdrPageFromSdrObject() == pPV->GetPage())
                                    bReturn = pPV->EnterGroup(pObj);
                            }
                        }
                    }

                    // #i71727# replaced else here with two possibilities, once the original else (!pObj)
                    // and also ignoring the found object when it's on a masterpage
                    if(!pObj || (pObj->getSdrPageFromSdrObject() && pObj->getSdrPageFromSdrObject()->IsMasterPage()))
                    {
                        if(mpView->IsGroupEntered() && 2 == rMEvt.GetClicks())
                        {
                            // New: double click on empty space/on obj on MasterPage, leave group
                            mpView->LeaveOneGroup();
                            bReturn = true;
                        }
                    }
                }

                if (!bReturn)
                {
                    if (bWaterCan)
                    {
                        if ( ! (rMEvt.IsShift() || rMEvt.IsMod2()))
                        {
                            // Find the object under the current mouse position
                            // and store it for the MouseButtonUp() method to
                            // evaluate.
                            pWaterCanCandidate = pickObject (aMDPos);
                        }
                    }
                    else
                    {
                        bReturn = true;
                        bool bDeactivateOLE = false;

                        if ( !rMEvt.IsShift() && !rMEvt.IsMod2() )
                        {
                            OSL_ASSERT (mpViewShell->GetViewShell()!=nullptr);
                            Client* pIPClient = static_cast<Client*>(
                                mpViewShell->GetViewShell()->GetIPClient());

                            if (pIPClient && pIPClient->IsObjectInPlaceActive())
                            {
                                // OLE-object gets deactivated in subsequent UnmarkAll()
                                bDeactivateOLE = true;
                            }

                            mpView->UnmarkAll();
                        }

                        bool bMarked = false;

                        if ( !rMEvt.IsMod1() && !bDeactivateOLE)
                        {
                            if ( rMEvt.IsMod2() )
                            {
                                bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift() );
                            }
                            else
                            {
                                bool bToggle = false;

                                if (rMEvt.IsShift() && mpView->GetMarkedObjectList().GetMarkCount() > 1)
                                {
                                    // No Toggle on single selection
                                    bToggle = true;
                                }

                                bMarked = mpView->MarkObj(aMDPos, nHitLog, bToggle);
                            }
                        }

                        if( !bDeactivateOLE )
                        {
                            if ( !bReadOnly &&
                                 bMarked                                                   &&
                                 (!rMEvt.IsShift() || mpView->IsMarkedHit(aMDPos, nHitLog)))
                            {
                                /**********************************************************
                                 * Move object
                                 **********************************************************/
                                aDragTimer.Start();

                                pHdl=mpView->PickHandle(aMDPos);
                                if ( ! rMEvt.IsRight())
                                    mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
                            }
                            else
                            {
                                /**********************************************************
                                 * Select object
                                 **********************************************************/
                                if ( ! rMEvt.IsRight())
                                    mpView->BegMarkObj(aMDPos);
                            }
                        }

                        if( bMarked && bTempRotation && (nSlotId == SID_OBJECT_ROTATE) && !rMEvt.IsShift() && (rMEvt.GetClicks() != 2) )
                        {
                            nSlotId = SID_OBJECT_SELECT;
                            Activate();
                        }
                    }
                }
            }
        }
        else if ( !bReadOnly
                  && (rMEvt.IsLeft() || rMEvt.IsRight())
                  && !mpView->IsAction())
        {
            /**********************************************************************
            * BEZIER-EDITOR
            **********************************************************************/
            mpWindow->CaptureMouse();
            SdrViewEvent aVEvt;
            SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);

            if (eHit == SdrHitKind::Handle && aVEvt.pHdl->GetKind() == SdrHdlKind::BezierWeight)
            {
                /******************************************************************
                * Drag Handle
                ******************************************************************/
                if ( ! rMEvt.IsRight())
                    mpView->BegDragObj(aMDPos, nullptr, aVEvt.pHdl, nDrgLog);
            }
            else if (eHit == SdrHitKind::MarkedObject && nEditMode == SID_BEZIER_INSERT)
            {
                /******************************************************************
                * Insert glue point
                ******************************************************************/
                mpView->BegInsObjPoint(aMDPos, rMEvt.IsMod1());
            }
            else if (eHit == SdrHitKind::MarkedObject && rMEvt.IsMod1())
            {
                /******************************************************************
                * Select glue point
                ******************************************************************/
                if (!rMEvt.IsShift())
                    mpView->UnmarkAllPoints();

                if ( ! rMEvt.IsRight())
                    mpView->BegMarkPoints(aMDPos);
            }
            else if (eHit == SdrHitKind::MarkedObject && !rMEvt.IsShift() && !rMEvt.IsMod2())
            {
                /******************************************************************
                * Move object
                ******************************************************************/
                if ( ! rMEvt.IsRight())
                    mpView->BegDragObj(aMDPos, nullptr, nullptr, nDrgLog);
            }
            else if (eHit == SdrHitKind::Handle)
            {
                /******************************************************************
                * Select glue point
                ******************************************************************/
                if (!mpView->IsPointMarked(*aVEvt.pHdl) || rMEvt.IsShift())
                {
                    if (!rMEvt.IsShift())
                    {
                        mpView->UnmarkAllPoints();
                        pHdl = mpView->PickHandle(aMDPos);
                    }
                    else
                    {
                        if (mpView->IsPointMarked(*aVEvt.pHdl))
                        {
                            mpView->UnmarkPoint(*aVEvt.pHdl);
                            pHdl = nullptr;
                        }
                        else
                        {
                            pHdl = mpView->PickHandle(aMDPos);
                        }
                    }

                    if (pHdl)
                    {
                        mpView->MarkPoint(*pHdl);
                        if ( ! rMEvt.IsRight())
                            mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);

                    }
                }
                else
                {
                    // Point IS marked and NO shift is pressed. Start
                    // dragging of selected point(s)
                    pHdl = mpView->PickHandle(aMDPos);
                    if(pHdl)
                        if ( ! rMEvt.IsRight())
                            mpView->BegDragObj(aMDPos, nullptr, pHdl, nDrgLog);
                }
            }
            else
            {
                /******************************************************************
                * Select or drag object
                ******************************************************************/
                if (!rMEvt.IsShift() && !rMEvt.IsMod2() && eHit == SdrHitKind::UnmarkedObject)
                {
                   mpView->UnmarkAllObj();
                }

                bool bMarked = false;

                if (!rMEvt.IsMod1())
                {
                    if (rMEvt.IsMod2())
                    {
                        bMarked = mpView->MarkNextObj(aMDPos, nHitLog, rMEvt.IsShift());
                    }
                    else
                    {
                        bMarked = mpView->MarkObj(aMDPos, nHitLog, rMEvt.IsShift());
                    }
                }

                if (bMarked &&
                    (!rMEvt.IsShift() || eHit == SdrHitKind::MarkedObject))
                {
                    // Move object
                    if ( ! rMEvt.IsRight())
                        mpView->BegDragObj(aMDPos, nullptr, aVEvt.pHdl, nDrgLog);
                }
                else if (mpView->AreObjectsMarked())
                {
                    /**************************************************************
                    * Select glue point
                    **************************************************************/
                    if (!rMEvt.IsShift())
                        mpView->UnmarkAllPoints();

                    if ( ! rMEvt.IsRight())
                        mpView->BegMarkPoints(aMDPos);
                }
                else
                {
                    /**************************************************************
                    * Select object
                    **************************************************************/
                    if ( ! rMEvt.IsRight())
                        mpView->BegMarkObj(aMDPos);
                }

                ForcePointer(&rMEvt);
            }
        }

        if (!bIsInDragMode)
        {
            ForcePointer(&rMEvt);
        }

        return bReturn;
    }

    bool FuSelection::MouseMove(const MouseEvent& rMEvt)
    {
        bool bReturn = FuDraw::MouseMove(rMEvt);

        if (aDragTimer.IsActive())
        {
            if(bFirstMouseMove)
            {
                bFirstMouseMove = false;
            }
            else
            {
                aDragTimer.Stop();
            }
        }

        if (mpView->IsAction())
        {
            Point aPix(rMEvt.GetPosPixel());
            Point aPnt(mpWindow->PixelToLogic(aPix));

            ForceScroll(aPix);

            if (mpView->IsInsObjPoint())
            {
                mpView->MovInsObjPoint(aPnt);
            }
            else
            {
                mpView->MovAction(aPnt);
            }
        }

        ForcePointer(&rMEvt);

        return bReturn;
    }

    bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
    {
        bool bReturn = false;
        // When the right mouse button is pressed then only select objects
        // (and deselect others) as a preparation for showing the context
        // menu.
        const bool bSelectionOnly = rMEvt.IsRight();

        if (aDragTimer.IsActive() )
        {
            aDragTimer.Stop();
            bIsInDragMode = false;
        }

        if( !mpView )
            return false;

        Point aPnt( mpWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
        sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
        sal_uInt16 nDrgLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );

        if (mpView->IsFrameDragSingles() || !mpView->HasMarkablePoints())
        {
            /**********************************************************************
            * NO BEZIER_EDITOR
            **********************************************************************/
            if ( mpView->IsDragObj() )
            {
                /******************************************************************
                * Object was moved
                ******************************************************************/
                FrameView* pFrameView = mpViewShell->GetFrameView();
                bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());

                if (bDragWithCopy)
                {
                    bDragWithCopy = !mpView->IsPresObjSelected(false);
                }

                mpView->SetDragWithCopy(bDragWithCopy);
                mpView->EndDragObj( mpView->IsDragWithCopy() );

                mpView->ForceMarkedToAnotherPage();

                if (!rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() &&
                    !bSelectionChanged                   &&
                    std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
                    std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
                {
                    /*************************************************************
                    * If a user wants to click on an object in front of a marked
                    * one, he releases the mouse button immediately
                    **************************************************************/
                    SdrPageView* pPV;
                    SdrObject* pObj = mpView->PickObj(aMDPos, mpView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK);
                    if (pObj)
                    {
                        if (pPV->IsObjMarkable(pObj))
                        {
                            mpView->UnmarkAllObj();
                            mpView->MarkObj(pObj,pPV);
                            return true;
                        }
                    }
                    /**************************************************************
                    * Toggle between selection and rotation
                    **************************************************************/
                    SdrObject* pSingleObj = nullptr;

                    if (mpView->GetMarkedObjectList().GetMarkCount()==1)
                    {
                        pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
                    }

                    if (nSlotId == SID_OBJECT_SELECT
                        && mpView->IsRotateAllowed()

                        && (rMEvt.GetClicks() != 2)
                        && (mpViewShell->GetFrameView()->IsClickChangeRotation()
                            || (pSingleObj
                                && pSingleObj->GetObjInventor()==SdrInventor::E3d))
                        && ! bSelectionOnly)

                    {
                        bTempRotation = true;
                        nSlotId = SID_OBJECT_ROTATE;
                        Activate();
                    }
                    else if (nSlotId == SID_OBJECT_ROTATE)
                    {
                        nSlotId = SID_OBJECT_SELECT;
                        Activate();
                    }
                }
                else if (nSlotId == SID_CONVERT_TO_3D_LATHE)
                {
                    if (!pHdl)
                    {
                        bSuppressChangesOfSelection = true;
                        mpView->Start3DCreation();
                        bSuppressChangesOfSelection = false;
                    }
                    else if (pHdl->GetKind() != SdrHdlKind::MirrorAxis &&
                             pHdl->GetKind() != SdrHdlKind::Ref1 &&
                             pHdl->GetKind() != SdrHdlKind::Ref2 && mpView->Is3DRotationCreationActive())
                    {
                        /*********************************************************
                        * If 3D-rotation bodies are about to be created,
                        * end creation now
                        **********************************************************/
                         long nAngle1  = GetAngle(aPnt - mpView->GetRef1());
                         nAngle1 -= 27000;
                         nAngle1 = NormAngle36000(nAngle1);
                         bool bMirrorSide1 = nAngle1 < 18000;

                         if (bMirrorSide0 != bMirrorSide1)
                         {
                             bSuppressChangesOfSelection = true;
                             mpWindow->EnterWait();
                             mpView->End3DCreation();
                             bSuppressChangesOfSelection = false;
                             nSlotId = SID_OBJECT_SELECT;
                             mpWindow->LeaveWait();
                             Activate();
                        }
                    }
                }
            }
            else if (rMEvt.IsMod1()
                && !rMEvt.IsMod2()
                && std::abs(aPnt.X() - aMDPos.X()) < nDrgLog
                && std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
            {
                // Enter group
                mpView->MarkObj(aPnt, nHitLog, rMEvt.IsShift(), rMEvt.IsMod1());
            }

            if (mpView->IsAction() )
            {
                mpView->EndAction();
            }

            if( SD_MOD()->GetWaterCan() )
            {
                if( rMEvt.IsRight() )
                {
                    // In watering-can mode, on press onto right mouse button, a undo is executed
                    mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_UNDO, SfxCallMode::ASYNCHRON );
                }
                else if (pWaterCanCandidate != nullptr)
                {
                    // Is the candidate object still under the mouse?
                    if (pickObject (aPnt) == pWaterCanCandidate)
                    {
                        SdStyleSheetPool* pPool = static_cast<SdStyleSheetPool*>(
                            mpDocSh->GetStyleSheetPool());
                        if (pPool != nullptr)
                        {
                            SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
                                pPool->GetActualStyleSheet());
                            if (pStyleSheet != nullptr && mpView->IsUndoEnabled() )
                            {
                                // Added UNDOs for the WaterCan mode. This was never done in
                                // the past, thus it was missing all the time.
                                SdrUndoAction* pUndoAttr = mpDoc->GetSdrUndoFactory().CreateUndoAttrObject(*pWaterCanCandidate, true, true);
                                mpView->BegUndo(pUndoAttr->GetComment());
                                mpView->AddUndo(mpDoc->GetSdrUndoFactory().CreateUndoGeoObject(*pWaterCanCandidate));
                                mpView->AddUndo(pUndoAttr);

                                pWaterCanCandidate->SetStyleSheet (pStyleSheet, false);

                                mpView->EndUndo();
                            }
                        }
                    }
                }
                // else when there has been no object under the mouse when the
                // button was pressed then nothing happens even when there is
                // one now.
            }

            sal_uInt16 nClicks = rMEvt.GetClicks();

            if (nClicks == 2 && rMEvt.IsLeft() && bMBDown &&
                !rMEvt.IsMod1() && !rMEvt.IsShift() )
            {
                DoubleClick(rMEvt);
            }

            bMBDown = false;

            ForcePointer(&rMEvt);
            pHdl = nullptr;
            mpWindow->ReleaseMouse();
            SdrObject* pSingleObj = nullptr;
            const size_t nMarkCount = mpView->GetMarkedObjectList().GetMarkCount();

            if (nMarkCount==1)
            {
                pSingleObj = mpView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
            }

            if ( (nSlotId != SID_OBJECT_SELECT && nMarkCount==0)                    ||
                 ( mpView->GetDragMode() == SdrDragMode::Crook &&
                  !mpView->IsCrookAllowed( mpView->IsCrookNoContortion() ) ) ||
                 ( mpView->GetDragMode() == SdrDragMode::Shear &&
                  !mpView->IsShearAllowed() && !mpView->IsDistortAllowed() ) ||
                 ( nSlotId==SID_CONVERT_TO_3D_LATHE && pSingleObj &&
                  (pSingleObj->GetObjInventor() != SdrInventor::Default         ||
                   pSingleObj->GetObjIdentifier() == OBJ_MEASURE) ) )
            {
                bReturn = true;
                ForcePointer(&rMEvt);
                pHdl = nullptr;
                mpWindow->ReleaseMouse();
                FuDraw::MouseButtonUp(rMEvt);
                mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::SYNCHRON);
                return bReturn; // CAUTION, due to the synchronous slot, the object is deleted now.
            }

            FuDraw::MouseButtonUp(rMEvt);
        }
        else
        {
            /**********************************************************************
            * BEZIER_EDITOR
            **********************************************************************/
            if ( mpView->IsAction() )
            {
                if ( mpView->IsInsObjPoint() )
                {
                    mpView->EndInsObjPoint(SdrCreateCmd::ForceEnd);
                }
                else if ( mpView->IsDragObj() )
                {
                    FrameView* pFrameView = mpViewShell->GetFrameView();
                    bool bDragWithCopy = (rMEvt.IsMod1() && pFrameView->IsDragWithCopy());

                    if (bDragWithCopy)
                    {
                        bDragWithCopy = !mpView->IsPresObjSelected(false);
                    }

                    mpView->SetDragWithCopy(bDragWithCopy);
                    mpView->EndDragObj( mpView->IsDragWithCopy() );
                }
                else
                {
                    mpView->EndAction();

                    sal_uInt16 nDrgLog2 = sal_uInt16 ( mpWindow->PixelToLogic(Size(DRGPIX,0)).Width() );
                    Point aPos = mpWindow->PixelToLogic( rMEvt.GetPosPixel() );

                    if (std::abs(aMDPos.X() - aPos.X()) < nDrgLog2 &&
                        std::abs(aMDPos.Y() - aPos.Y()) < nDrgLog2 &&
                        !rMEvt.IsShift() && !rMEvt.IsMod2())
                    {
                        SdrViewEvent aVEvt;
                        SdrHitKind eHit = mpView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);

                        if (eHit == SdrHitKind::NONE)
                        {
                            // Click on the same place - unselect
                            mpView->UnmarkAllObj();
                        }
                    }
                }
            }
            else if (!rMEvt.IsShift() && rMEvt.IsMod1() && !rMEvt.IsMod2() &&
                     std::abs(aPnt.X() - aMDPos.X()) < nDrgLog &&
                     std::abs(aPnt.Y() - aMDPos.Y()) < nDrgLog)
            {
                // Enter group
                mpView->MarkObj(aPnt, nHitLog, false, rMEvt.IsMod1());
            }

            ForcePointer(&rMEvt);
            pHdl = nullptr;
            mpWindow->ReleaseMouse();

            FuDraw::MouseButtonUp(rMEvt);
        }

        return bReturn;
    }

    /**
     * Process keyboard input
     * @returns sal_True if a KeyEvent is being processed, sal_False otherwise
     */
    bool FuSelection::KeyInput(const KeyEvent& rKEvt)
    {
        bool bReturn = false;

        switch (rKEvt.GetKeyCode().GetCode())
        {
            case KEY_ESCAPE:
            {
                bReturn = FuSelection::cancel();
            }
            break;
            //add keyboard operation for insert points in drawing curve
            case KEY_UP:
            case KEY_DOWN:
            case KEY_LEFT:
            case KEY_RIGHT:
            {
                if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT)){
                    long nX = 0;
                    long nY = 0;
                    sal_uInt16  nCode = rKEvt.GetKeyCode().GetCode();
                    if (nCode == KEY_UP)
                    {
                        // scroll up
                        nX = 0;
                        nY =-1;
                    }
                    else if (nCode == KEY_DOWN)
                    {
                        // scroll down
                        nX = 0;
                        nY = 1;
                    }
                    else if (nCode == KEY_LEFT)
                    {
                        // scroll left
                        nX =-1;
                        nY = 0;
                    }
                    else if (nCode == KEY_RIGHT)
                    {
                        // scroll right
                        nX = 1;
                        nY = 0;
                    }

                    Point centerPoint;
                    ::tools::Rectangle rect = mpView->GetMarkedObjRect();
                    centerPoint = mpWindow->LogicToPixel(rect.Center());
                    Point aPoint = bMovedToCenterPoint? oldPoint:centerPoint;
                    Point ePoint = aPoint + Point(nX,nY);
                    mpWindow->SetPointerPosPixel(ePoint);
                    //simulate mouse move action
                    MouseEvent eMevt(ePoint, 1, MouseEventModifiers::DRAGMOVE, MOUSE_LEFT, 0);
                    MouseMove(eMevt);
                    oldPoint = ePoint;
                    bMovedToCenterPoint = true;
                    bReturn = true;
                }
            }
            break;
            case KEY_RETURN:
                if(rKEvt.GetKeyCode().IsShift()&&(nEditMode == SID_BEZIER_INSERT))
                {
                    if(!bBeginInsertPoint)
                    {
                        //simulate mouse button down action
                        MouseEvent aMevt(oldPoint, 1,
                                         MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::DRAGMOVE,
                                         MOUSE_LEFT, KEY_SHIFT);
                        MouseButtonDown(aMevt);
                        mpWindow->CaptureMouse();
                        bBeginInsertPoint = true;
                    }
                    else
                    {
                        //simulate mouse button up action
                        MouseEvent rMEvt(oldPoint, 1,
                                         MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::ENTERWINDOW,
                                         MOUSE_LEFT, KEY_SHIFT);
                        MouseButtonUp(rMEvt);
                        bBeginInsertPoint = false;
                    }
                    bReturn= true;
                }
                break;
        }
        if (!bReturn)
        {
            bReturn = FuDraw::KeyInput(rKEvt);

            if(mpView->GetMarkedObjectList().GetMarkCount() == 0)
            {
                mpView->ResetCreationActive();

                mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
            }
        }

        return bReturn;

    }

    void FuSelection::Activate()
    {
        SdrDragMode eMode;
        mpView->ResetCreationActive();
        mpView->SetEditMode(SdrViewEditMode::Edit);

        switch( nSlotId )
        {
            case SID_OBJECT_ROTATE:
            {
                eMode = SdrDragMode::Rotate;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_MIRROR:
            {
                eMode = SdrDragMode::Mirror;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_CROP:
            {
                eMode = SdrDragMode::Crop;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_TRANSPARENCE:
            {
                eMode = SdrDragMode::Transparence;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_GRADIENT:
            {
                eMode = SdrDragMode::Gradient;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_SHEAR:
            {
                eMode = SdrDragMode::Shear;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;

            case SID_OBJECT_CROOK_ROTATE:
            {
                eMode = SdrDragMode::Crook;

                if ( mpView->GetDragMode() != eMode )
                {
                    mpView->SetDragMode(eMode);
                    mpView->SetCrookMode(SdrCrookMode::Rotate);
                }
            }
            break;

            case SID_OBJECT_CROOK_SLANT:
            {
                eMode = SdrDragMode::Crook;

                if ( mpView->GetDragMode() != eMode )
                {
                    mpView->SetDragMode(eMode);
                    mpView->SetCrookMode(SdrCrookMode::Slant);
                }
            }
            break;

            case SID_OBJECT_CROOK_STRETCH:
            {
                eMode = SdrDragMode::Crook;

                if ( mpView->GetDragMode() != eMode )
                {
                    mpView->SetDragMode(eMode);
                    mpView->SetCrookMode(SdrCrookMode::Stretch);
                }
            }
            break;

            case SID_CONVERT_TO_3D_LATHE:
            {
                eMode = SdrDragMode::Mirror;
                bSuppressChangesOfSelection = true;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);

                if (!mpView->Is3DRotationCreationActive())
                    mpView->Start3DCreation();

                bSuppressChangesOfSelection = false;
            }
            break;

            default:
            {
                eMode = SdrDragMode::Move;

                if ( mpView->GetDragMode() != eMode )
                    mpView->SetDragMode(eMode);
            }
            break;
        }

        if (nSlotId != SID_OBJECT_ROTATE)
        {
            bTempRotation = false;
        }

        FuDraw::Activate();
    }

    void FuSelection::SelectionHasChanged()
    {
        bSelectionChanged = true;

        FuDraw::SelectionHasChanged();

        if (mpView->Is3DRotationCreationActive() && !bSuppressChangesOfSelection)
        {
            // Switch rotation body -> selection
            mpView->ResetCreationActive();
            nSlotId = SID_OBJECT_SELECT;
            Activate();
        }

        // Activate the right tool bar for the current context of the view.
        mpViewShell->GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*mpViewShell, *mpView);
    }

    /**
     * Set current bezier edit mode
     */
    void FuSelection::SetEditMode(sal_uInt16 nMode)
    {
        nEditMode = nMode;

        if (nEditMode == SID_BEZIER_INSERT)
        {
            mpView->SetInsObjPointMode(true);
        }
        else
        {
            mpView->SetInsObjPointMode(false);
        }

        ForcePointer();

        SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings();
        rBindings.Invalidate(SID_BEZIER_MOVE);
        rBindings.Invalidate(SID_BEZIER_INSERT);
    }

    /**
     * Execute animation or interaction
     */
    bool FuSelection::AnimateObj(SdrObject* pObj, const Point& rPos)
    {
        bool bAnimated = false;
        bool bClosed = pObj->IsClosedObj();
        bool bFilled = false;

        if (bClosed)
        {
            SfxItemSet aSet(mpDoc->GetPool());

            aSet.Put(pObj->GetMergedItemSet());

            const XFillStyleItem& rFillStyle = aSet.Get(XATTR_FILLSTYLE);
            bFilled = rFillStyle.GetValue() != drawing::FillStyle_NONE;
        }

        const SdrLayerIDSet* pVisiLayer = &mpView->GetSdrPageView()->GetVisibleLayers();
        sal_uInt16 nHitLog = sal_uInt16 ( mpWindow->PixelToLogic(Size(HITPIX,0)).Width() );
        const long  n2HitLog = nHitLog * 2;
        Point aHitPosR(rPos);
        Point aHitPosL(rPos);
        Point aHitPosT(rPos);
        Point aHitPosB(rPos);

        aHitPosR.AdjustX(n2HitLog );
        aHitPosL.AdjustX( -n2HitLog );
        aHitPosT.AdjustY( n2HitLog );
        aHitPosB.AdjustY( -n2HitLog );

        if ( !bClosed                                      ||
             !bFilled                                      ||
             (SdrObjectPrimitiveHit(*pObj, aHitPosR, nHitLog, *mpView->GetSdrPageView(), pVisiLayer, false) &&
              SdrObjectPrimitiveHit(*pObj, aHitPosL, nHitLog, *mpView->GetSdrPageView(), pVisiLayer, false) &&
              SdrObjectPrimitiveHit(*pObj, aHitPosT, nHitLog, *mpView->GetSdrPageView(), pVisiLayer, false) &&
              SdrObjectPrimitiveHit(*pObj, aHitPosB, nHitLog, *mpView->GetSdrPageView(), pVisiLayer, false) ) )
        {
            if ( SdDrawDocument::GetIMapInfo( pObj ) )
            {
                const IMapObject* pIMapObj = SdDrawDocument::GetHitIMapObject( pObj, rPos );

                if ( pIMapObj && !pIMapObj->GetURL().isEmpty() )
                {
                    // Jump to Document
                    mpWindow->ReleaseMouse();
                    SfxStringItem aStrItem(SID_FILE_NAME, pIMapObj->GetURL());
                    SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
                    SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
                    SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
                    SfxBoolItem aBrowseItem( SID_BROWSE, true );
                    mpWindow->ReleaseMouse();
                    pFrame->GetDispatcher()->ExecuteList(SID_OPENDOC,
                            SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
                            { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });

                    bAnimated = true;
                }
            }
            else if( dynamic_cast< const GraphicDocShell *>( mpDocSh ) ==  nullptr        &&
                     dynamic_cast< const DrawView *>( mpView ) !=  nullptr                 &&
                     SdDrawDocument::GetAnimationInfo(pObj))
            {
                /**********************************************************
                * Animation-object hit in the middle -> interaction
                **********************************************************/
                SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo(pObj);
                DrawViewShell* pDrViewSh = static_cast<DrawViewShell*>(mpViewShell);
                mpWindow->ReleaseMouse();

                switch (pInfo->meClickAction)
                {
                    case presentation::ClickAction_BOOKMARK:
                    {
                         // Jump to Bookmark (Page or Object)
                        SfxStringItem aItem(SID_NAVIGATOR_OBJECT, pInfo->GetBookmark());
                        mpViewShell->GetViewFrame()->GetDispatcher()->ExecuteList(
                            SID_NAVIGATOR_OBJECT,
                            SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_DOCUMENT:
                    {
                        OUString sBookmark( pInfo->GetBookmark() );
                        // Jump to document
                        if (!sBookmark.isEmpty())
                        {
                            SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName());
                            SfxStringItem aStrItem(SID_FILE_NAME, sBookmark);
                            SfxViewFrame* pFrame = mpViewShell->GetViewFrame();
                            SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame);
                            SfxBoolItem aBrowseItem( SID_BROWSE, true );
                            pFrame->GetDispatcher()->
                            ExecuteList(SID_OPENDOC,
                                SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
                                { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer });
                        }

                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_PREVPAGE:
                    {
                        // Jump to the previous page
                        SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_PREVIOUS);
                        mpViewShell->GetViewFrame()->GetDispatcher()->
                        ExecuteList(SID_NAVIGATOR_PAGE,
                                SfxCallMode::SLOT | SfxCallMode::RECORD,
                                { &aItem });
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_NEXTPAGE:
                    {
                        // Jump to the next page
                        SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_NEXT);
                        mpViewShell->GetViewFrame()->GetDispatcher()->
                        ExecuteList(SID_NAVIGATOR_PAGE,
                                SfxCallMode::SLOT | SfxCallMode::RECORD,
                                { &aItem });
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_FIRSTPAGE:
                    {
                        // Jump to the first page
                        SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_FIRST);
                        mpViewShell->GetViewFrame()->GetDispatcher()->
                        ExecuteList(SID_NAVIGATOR_PAGE,
                                SfxCallMode::SLOT | SfxCallMode::RECORD,
                                { &aItem });
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_LASTPAGE:
                    {
                        // Jump to the last page
                        SfxUInt16Item aItem(SID_NAVIGATOR_PAGE, PAGE_LAST);
                        mpViewShell->GetViewFrame()->GetDispatcher()->
                        ExecuteList(SID_NAVIGATOR_PAGE,
                                SfxCallMode::SLOT | SfxCallMode::RECORD,
                                { &aItem });
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_SOUND:
                    {
    #if HAVE_FEATURE_AVMEDIA
                            try
                            {
                                mxPlayer.set( avmedia::MediaWindow::createPlayer( pInfo->GetBookmark(), ""/*TODO?*/), uno::UNO_QUERY_THROW );
                                mxPlayer->start();
                            }
                            catch( uno::Exception& )
                            {
                            }
    #endif
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_VERB:
                    {
                        // Assign verb
                        mpView->UnmarkAll();
                        mpView->MarkObj(pObj, mpView->GetSdrPageView());
                        pDrViewSh->DoVerb(static_cast<sal_Int16>(pInfo->mnVerb));
                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_PROGRAM:
                    {
                       OUString aBaseURL = GetDocSh()->GetMedium()->GetBaseURL();
                       INetURLObject aURL( ::URIHelper::SmartRel2Abs( INetURLObject(aBaseURL), pInfo->GetBookmark(),
                                                    URIHelper::GetMaybeFileHdl(), true, false,
                                                    INetURLObject::EncodeMechanism::WasEncoded, INetURLObject::DecodeMechanism::Unambiguous ) );

                       if( INetProtocol::File == aURL.GetProtocol() )
                       {
                            SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
                            SfxBoolItem aBrowsing( SID_BROWSE, true );

                            SfxViewFrame* pViewFrm = SfxViewFrame::Current();
                            if (pViewFrm)
                                pViewFrm->GetDispatcher()->ExecuteList(SID_OPENDOC,
                                      SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
                                      { &aUrl, &aBrowsing });
                       }

                        bAnimated = true;
                    }
                    break;

                    case presentation::ClickAction_MACRO:
                    {
                        // Execute macro
                        OUString aMacro = pInfo->GetBookmark();

                        if ( SfxApplication::IsXScriptURL( aMacro ) )
                        {
                            uno::Any aRet;
                            uno::Sequence< sal_Int16 > aOutArgsIndex;
                            uno::Sequence<uno::Any> aParams;
                            uno::Sequence< uno::Any > aOutArgs;

                            ErrCode eErr = mpDocSh->CallXScript( aMacro,
                                aParams, aRet, aOutArgsIndex, aOutArgs);

                            // Check the return value from the script
                            bool bTmp = false;
                            bAnimated = eErr == ERRCODE_NONE &&
                                 aRet.getValueType() == cppu::UnoType<bool>::get() &&
                                 ( aRet >>= bTmp ) &&
                                 bTmp;
                        }
                        else
                        {
                            // aMacro has got following format:
                            // "Macroname.Modulname.Libname.Documentname" or
                            // "Macroname.Modulname.Libname.Applicationname"
                            OUString aMacroName = aMacro.getToken(0, '.');
                            OUString aModulName = aMacro.getToken(1, '.');

                            // In this moment the Call-method only
                            // resolves modulename+macroname
                            OUString aExecMacro(aModulName + "." + aMacroName);
                            bAnimated = mpDocSh->GetBasic()->Call(aExecMacro);
                        }
                    }
                    break;

                    default:
                    {
                        bAnimated = false;
                    }
                    break;
                }
            }

            if (!bAnimated                               &&
                dynamic_cast< const DrawView *>( mpView ) !=  nullptr                 &&
                dynamic_cast< const GraphicDocShell *>( mpDocSh ) ==  nullptr        &&
                SlideShow::IsRunning( mpViewShell->GetViewShellBase() ) &&
                SdDrawDocument::GetAnimationInfo(pObj))
            {
                /**********************************************************
                * Effect-Object hit in the middle -> Play effect
                **********************************************************/
                SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo(pObj);

                switch (pInfo->meClickAction)
                {
                    case presentation::ClickAction_VANISH:
                    case presentation::ClickAction_INVISIBLE:
                        break;

                    default:
                        bAnimated = false;
                    break;
                }
            }
        }

        return bAnimated;
    }

    /** is called when the current function should be aborted. <p>
        This is used when a function gets a KEY_ESCAPE but can also
        be called directly.

        @returns true if a active function was aborted
    */
    bool FuSelection::cancel()
    {
        if (mpView->Is3DRotationCreationActive())
        {
            mpView->ResetCreationActive();
            mpViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
            return true;
        }
        else
        {
            return false;
        }
    }

    SdrObject* FuSelection::pickObject (const Point& rTestPoint)
    {
        SdrPageView* pPageView;
        sal_uInt16 nHitLog = sal_uInt16 (mpWindow->PixelToLogic(Size(HITPIX,0)).Width());
        return mpView->PickObj(rTestPoint, nHitLog, pPageView, SdrSearchOptions::PICKMARKABLE);
    }

    void FuSelection::ForcePointer(const MouseEvent* pMEvt)
    {
        if(bMovedToCenterPoint && !bBeginInsertPoint && pMEvt)
        {
            MouseEvent aMEvt(pMEvt->GetPosPixel(), pMEvt->GetClicks(),
                pMEvt->GetMode(), pMEvt->GetButtons(), pMEvt->GetModifier() & ~KEY_SHIFT);
            FuDraw::ForcePointer(&aMEvt);
        }
        else
        {
            FuDraw::ForcePointer(pMEvt);
        }
    }

    } // end of namespace sd

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V1019 Compound assignment expression 'aRet >>= bTmp' is used inside condition.