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

#include <editeng/editeng.hxx>
#include <editeng/outlobj.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdouno.hxx>
#include <svx/ImageMapInfo.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/viewfrm.hxx>
#include <svl/eitem.hxx>
#include <vcl/uitest/logger.hxx>
#include <vcl/uitest/eventdescription.hxx>

#include <sc.hrc>
#include <fudraw.hxx>
#include <futext.hxx>
#include <tabvwsh.hxx>
#include <drwlayer.hxx>
#include <userdat.hxx>
#include <docsh.hxx>
#include <drawview.hxx>
#include <comphelper/kit.hxx>
#include <com/sun/star/embed/EmbedVerbs.hpp>

namespace
{

void collectUIInformation( const OUString& aevent )
{
    EventDescription aDescription;
    aDescription.aID =  u"grid_window"_ustr;
    aDescription.aParameters = {{ aevent ,  ""}};
    aDescription.aAction = u"COMMENT"_ustr;
    aDescription.aParent = u"MainWindow"_ustr;
    aDescription.aKeyWord = u"ScGridWinUIObject"_ustr;
    UITestLogger::getInstance().logEvent(aDescription);
}

}

// base class for draw module specific functions
FuDraw::FuDraw(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
               SdrModel& rDoc, const SfxRequest& rReq)
    : FuPoor(rViewSh, pWin, pViewP, rDoc, rReq)
    , aNewPointer(PointerStyle::Arrow)
    , aOldPointer(PointerStyle::Arrow)
{
}

FuDraw::~FuDraw()
{
}

void FuDraw::DoModifiers(const MouseEvent& rMEvt)
{
    //  Shift   = Ortho and AngleSnap
    //  Control = Snap (Toggle)
    //  Alt     = centric

    bool bShift = rMEvt.IsShift();
    bool bAlt   = rMEvt.IsMod2();

    bool bOrtho     = bShift;
    bool bAngleSnap = bShift;
    bool bCenter    = bAlt;

    // #i33136#
    if(doConstructOrthogonal())
    {
        bOrtho = !bShift;
    }

    if (pView->IsOrtho() != bOrtho)
        pView->SetOrtho(bOrtho);
    if (pView->IsAngleSnapEnabled() != bAngleSnap)
        pView->SetAngleSnapEnabled(bAngleSnap);

    if (pView->IsCreate1stPointAsCenter() != bCenter)
        pView->SetCreate1stPointAsCenter(bCenter);
    if (pView->IsResizeAtCenter() != bCenter)
        pView->SetResizeAtCenter(bCenter);

}

void FuDraw::ResetModifiers()
{
    if (!pView)
        return;

    ScViewData& rViewData = rViewShell.GetViewData();
    const ScViewOptions& rOpt = rViewData.GetOptions();
    const ScGridOptions& rGrid = rOpt.GetGridOptions();
    bool bGridOpt = rGrid.GetUseGridSnap();

    if (pView->IsOrtho())
        pView->SetOrtho(false);
    if (pView->IsAngleSnapEnabled())
        pView->SetAngleSnapEnabled(false);

    if (pView->IsGridSnap() != bGridOpt)
        pView->SetGridSnap(bGridOpt);
    if (pView->IsSnapEnabled() != bGridOpt)
        pView->SetSnapEnabled(bGridOpt);

    if (pView->IsCreate1stPointAsCenter())
        pView->SetCreate1stPointAsCenter(false);
    if (pView->IsResizeAtCenter())
        pView->SetResizeAtCenter(false);
}

bool FuDraw::MouseButtonDown(const MouseEvent& rMEvt)
{
    // remember button state for creation of own MouseEvents
    SetMouseButtonCode(rMEvt.GetButtons());

    DoModifiers( rMEvt );
    return false;
}

bool FuDraw::MouseMove(const MouseEvent& rMEvt)
{
    if (SfxViewShell* pSfxViewShell = pView->GetSfxViewShell())
    {
        pSfxViewShell->GetDrawView()->MouseMove(rMEvt, pWindow->GetOutDev());
        //  evaluate modifiers only if in a drawing layer action
        //  (don't interfere with keyboard shortcut handling)
        if (pView->IsAction())
            DoModifiers( rMEvt );
    }

    return false;
}

bool FuDraw::MouseButtonUp(const MouseEvent& rMEvt)
{
    // remember button state for creation of own MouseEvents
    SetMouseButtonCode(rMEvt.GetButtons());

    ResetModifiers();
    return false;
}

// Process Keyboard events. Return true if an event is being handled
static bool lcl_KeyEditMode( SdrObject* pObj, ScTabViewShell& rViewShell, const KeyEvent* pInitialKey )
{
    bool bReturn = false;
    if ( DynCastSdrTextObj( pObj) != nullptr && dynamic_cast<const SdrUnoObj*>( pObj) ==  nullptr )
    {
        assert(pObj);
        // start text edit - like FuSelection::MouseButtonUp,
        // but with bCursorToEnd instead of mouse position

        OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
        bool bVertical = ( pOPO && pOPO->IsEffectivelyVertical() );
        sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT;

        // don't switch shells if text shell is already active
        FuPoor* pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
        if ( !pPoor || pPoor->GetSlotID() != nTextSlotId )
        {
            // the object to edit is there, so ask for the text function without a new object
            SfxBoolItem aCreateDirectly(FN_PARAM_1, false);
            rViewShell.GetViewData().GetDispatcher().ExecuteList(
                nTextSlotId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, { &aCreateDirectly });
        }

        // get the resulting FuText and set in edit mode
        pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
        if ( pPoor && pPoor->GetSlotID() == nTextSlotId )    // no RTTI
        {
            FuText* pText = static_cast<FuText*>(pPoor);
            pText->SetInEditMode( pObj, nullptr, true, pInitialKey );
            //! set cursor to end of text
        }
        bReturn = true;
    }
    return bReturn;
}

bool FuDraw::KeyInput(const KeyEvent& rKEvt)
{
    bool bReturn = false;
    ScViewData& rViewData = rViewShell.GetViewData();

    const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
    switch ( rKEvt.GetKeyCode().GetCode() )
    {
        case KEY_ESCAPE:
            if ( rViewShell.IsDrawTextShell() || aSfxRequest.GetSlot() == SID_DRAW_NOTEEDIT )
            {
                collectUIInformation(u"CLOSE"_ustr);
                // if object selected -> normal draw-shell, else turn off drawing
                rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
                bReturn = true;
            }
            else if ( rViewShell.IsDrawSelMode() )
            {
                pView->UnmarkAll();
                rViewData.GetDispatcher().Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
                bReturn = true;
            }
            else if ( rMarkList.GetMarkCount() != 0 )
            {
                // III
                SdrHdlList& rHdlList = const_cast< SdrHdlList& >( pView->GetHdlList() );
                if( rHdlList.GetFocusHdl() )
                    rHdlList.ResetFocusHdl();
                else
                    pView->UnmarkAll();

                //  while bezier editing, object is selected
                if (rMarkList.GetMarkCount() == 0)
                    rViewShell.SetDrawShell( false );

                bReturn = true;
            }
            break;

        case KEY_DELETE:                    //! via accelerator
            pView->DeleteMarked();
            bReturn = true;
        break;

        case KEY_RETURN:
        {
            if( rKEvt.GetKeyCode().GetModifier() == 0 )
            {
                // activate OLE object on RETURN for selected object
                // put selected text object in edit mode
                if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() )
                {
                    bool bOle = rViewShell.GetViewFrame().GetFrame().IsInPlace();
                    SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
                    auto pOleObj = dynamic_cast<SdrOle2Obj*>(pObj);
                    if( pOleObj && !bOle )
                    {
                        rViewShell.ActivateObject(pOleObj, css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);

                        // consumed
                        bReturn = true;
                    }
                    else if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) )       // start text edit for suitable object
                        bReturn = true;
                }
            }
        }
        break;

        case KEY_F2:
        {
            if( rKEvt.GetKeyCode().GetModifier() == 0 )
            {
                // put selected text object in edit mode
                // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer)
                if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() )
                {
                    SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
                    bool isMobilePhone = comphelper::COKit::isActive() && rViewShell.isKitMobilePhone();
                    // Double tapping on charts on phone may result in activating the edit mode which is not wanted.
                    // It happens due to the delay of selection message of the object from kit to javascript
                    // in that case F2 is sent instead of double click
                    if (isMobilePhone && ScDocument::IsChart(pObj))
                    {
                        rViewShell.ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
                        break;
                    }
                    if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) )            // start text edit for suitable object
                        bReturn = true;
                }
            }
        }
        break;

        case KEY_TAB:
        {
            // in calc do NOT start draw object selection using TAB/SHIFT-TAB when
            // there is not yet an object selected
            if(rMarkList.GetMarkCount() != 0)
            {
                vcl::KeyCode aCode = rKEvt.GetKeyCode();

                if ( !aCode.IsMod1() && !aCode.IsMod2() )
                {
                    // changeover to the next object
                    if(!pView->MarkNextObj( !aCode.IsShift() ))
                    {
                        //If there is only one object, don't do the UnmarkAllObj() & MarkNextObj().
                        if ( pView->HasMultipleMarkableObjects() && pView->HasMarkableObj() )
                        {
                            // No next object: go over open end and
                            // get first from the other side
                            pView->UnmarkAllObj();
                            pView->MarkNextObj(!aCode.IsShift());
                        }
                    }

                    // II
                    if(rMarkList.GetMarkCount() != 0)
                        pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);

                    bReturn = true;
                }

                // handle Mod1 and Mod2 to get travelling running on different systems
                if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2())
                {
                    // II do something with a selected handle?
                    const SdrHdlList& rHdlList = pView->GetHdlList();
                    bool bForward(!rKEvt.GetKeyCode().IsShift());

                    const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);

                    // guarantee visibility of focused handle
                    SdrHdl* pHdl = rHdlList.GetFocusHdl();

                    if(pHdl)
                    {
                        Point aHdlPosition(pHdl->GetPos());
                        tools::Rectangle aVisRect(aHdlPosition - Point(100, 100), Size(200, 200));
                        pView->MakeVisible(aVisRect, *pWindow);
                    }

                    // consumed
                    bReturn = true;
                }
            }
        }
        break;

        case KEY_END:
        {
            // in calc do NOT select the last draw object when
            // there is not yet an object selected
            if(rMarkList.GetMarkCount() != 0)
            {
                vcl::KeyCode aCode = rKEvt.GetKeyCode();

                if ( aCode.IsMod1() )
                {
                    // mark last object
                    pView->UnmarkAllObj();
                    pView->MarkNextObj();

                    // II
                    if(rMarkList.GetMarkCount() != 0)
                        pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);

                    bReturn = true;
                }
            }
        }
        break;

        case KEY_HOME:
        {
            // in calc do NOT select the first draw object when
            // there is not yet an object selected
            if(rMarkList.GetMarkCount() != 0)
            {
                vcl::KeyCode aCode = rKEvt.GetKeyCode();

                if ( aCode.IsMod1() )
                {
                    // mark first object
                    pView->UnmarkAllObj();
                    pView->MarkNextObj(true);

                    // II
                    if(rMarkList.GetMarkCount() != 0)
                        pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);

                    bReturn = true;
                }
            }
        }
        break;

        case KEY_UP:
        case KEY_DOWN:
        case KEY_LEFT:
        case KEY_RIGHT:
        {
            // in calc do cursor travelling of draw objects only when
            // there is an object selected yet
            if(rMarkList.GetMarkCount() != 0)
            {

                if(rMarkList.GetMarkCount() == 1)
                {
                    // disable cursor travelling on note objects as the tail connector position
                    // must not move.
                    SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
                    if( ScDrawLayer::IsNoteCaption( pObj ) )
                        break;
                }

                tools::Long nX = 0;
                tools::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;
                }

                bool bReadOnly = rViewData.GetDocShell()->IsReadOnly()
                    || rViewShell.IsKitReadOnlyView();

                if(!rKEvt.GetKeyCode().IsMod1() && !bReadOnly)
                {
                    if(rKEvt.GetKeyCode().IsMod2())
                    {
                        // move in 1 pixel distance
                        Size aLogicSizeOnePixel = pWindow ? pWindow->PixelToLogic(Size(1,1)) : Size(100, 100);
                        nX *= aLogicSizeOnePixel.Width();
                        nY *= aLogicSizeOnePixel.Height();
                    }
                    else if(rKEvt.GetKeyCode().IsShift()) // #i121236# Support for shift key in calc
                    {
                        nX *= 1000;
                        nY *= 1000;
                    }
                    else
                    {
                        // old, fixed move distance
                        nX *= 100;
                        nY *= 100;
                    }

                    // is there a movement to do?
                    if(0 != nX || 0 != nY)
                    {
                        // II
                        const SdrHdlList& rHdlList = pView->GetHdlList();
                        SdrHdl* pHdl = rHdlList.GetFocusHdl();

                        if(nullptr == pHdl)
                        {
                            // only take action when move is allowed
                            if(pView->IsMoveAllowed())
                            {
                                // restrict movement to WorkArea
                                const tools::Rectangle& rWorkArea = pView->GetWorkArea();

                                if(!rWorkArea.IsEmpty())
                                {
                                    tools::Rectangle aMarkRect(pView->GetMarkedObjRect());
                                    aMarkRect.Move(nX, nY);

                                    if(!aMarkRect.Contains(rWorkArea))
                                    {
                                        if(aMarkRect.Left() < rWorkArea.Left())
                                        {
                                            nX += rWorkArea.Left() - aMarkRect.Left();
                                        }

                                        if(aMarkRect.Right() > rWorkArea.Right())
                                        {
                                            nX -= aMarkRect.Right() - rWorkArea.Right();
                                        }

                                        if(aMarkRect.Top() < rWorkArea.Top())
                                        {
                                            nY += rWorkArea.Top() - aMarkRect.Top();
                                        }

                                        if(aMarkRect.Bottom() > rWorkArea.Bottom())
                                        {
                                            nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
                                        }
                                    }
                                }

                                // now move the selected draw objects
                                pView->MoveAllMarked(Size(nX, nY));

                                // II
                                pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);

                                bReturn = true;
                            }
                        }
                        else
                        {
                            // move handle with index nHandleIndex
                            if (nX || nY)
                            {
                                // now move the Handle (nX, nY)
                                Point aStartPoint(pHdl->GetPos());
                                Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
                                const SdrDragStat& rDragStat = pView->GetDragStat();

                                // start dragging
                                pView->BegDragObj(aStartPoint, nullptr, pHdl, 0);

                                if(pView->IsDragObj())
                                {
                                    bool bWasNoSnap = rDragStat.IsNoSnap();
                                    bool bWasSnapEnabled = pView->IsSnapEnabled();

                                    // switch snapping off
                                    if(!bWasNoSnap)
                                        const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
                                    if(bWasSnapEnabled)
                                        pView->SetSnapEnabled(false);

                                    pView->MovAction(aEndPoint);
                                    pView->EndDragObj();

                                    // restore snap
                                    if(!bWasNoSnap)
                                        const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
                                    if(bWasSnapEnabled)
                                        pView->SetSnapEnabled(bWasSnapEnabled);
                                }

                                // make moved handle visible
                                tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200));
                                pView->MakeVisible(aVisRect, *pWindow);

                                bReturn = true;
                            }
                        }
                    }
                }
            }
        }
        break;

        case KEY_SPACE:
        {
            // in calc do only something when draw objects are selected
            if(rMarkList.GetMarkCount() != 0)
            {
                const SdrHdlList& rHdlList = pView->GetHdlList();
                SdrHdl* pHdl = rHdlList.GetFocusHdl();

                if(pHdl)
                {
                    if(pHdl->GetKind() == SdrHdlKind::Poly)
                    {
                        // rescue ID of point with focus
                        sal_uInt32 nPol(pHdl->GetPolyNum());
                        sal_uInt32 nPnt(pHdl->GetPointNum());

                        if(pView->IsPointMarked(*pHdl))
                        {
                            if(rKEvt.GetKeyCode().IsShift())
                            {
                                pView->UnmarkPoint(*pHdl);
                            }
                        }
                        else
                        {
                            if(!rKEvt.GetKeyCode().IsShift())
                            {
                                pView->UnmarkAllPoints();
                            }

                            pView->MarkPoint(*pHdl);
                        }

                        if(nullptr == rHdlList.GetFocusHdl())
                        {
                            // restore point with focus
                            SdrHdl* pNewOne = nullptr;

                            for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
                            {
                                SdrHdl* pAct = rHdlList.GetHdl(a);

                                if(pAct
                                    && pAct->GetKind() == SdrHdlKind::Poly
                                    && pAct->GetPolyNum() == nPol
                                    && pAct->GetPointNum() == nPnt)
                                {
                                    pNewOne = pAct;
                                }
                            }

                            if(pNewOne)
                            {
                                const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
                            }
                        }

                        bReturn = true;
                    }
                }
            }
        }
        break;
    }

    if (!bReturn)
    {
        bReturn = FuPoor::KeyInput(rKEvt);
    }

    if (!bReturn)
    {
        // allow direct typing into a selected text object

        if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt) )
        {
            SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();

            if (nullptr != pObj && pObj->isDiagram())
            {
                SdrObject* pSubSelection(pObj->getDiagramSubSelection());
                if (nullptr != pSubSelection && pSubSelection->isDiagramTextNode())
                    pObj = pSubSelection;
            }

            // start text edit for suitable object, pass key event to OutlinerView
            if ( lcl_KeyEditMode( pObj, rViewShell, &rKEvt ) )
                bReturn = true;
        }
    }

    return bReturn;
}

// toggle mouse-pointer
static bool lcl_UrlHit( const SdrView* pView, const Point& rPosPixel, const vcl::Window* pWindow )
{
    SdrViewEvent aVEvt;
    MouseEvent aMEvt( rPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT );
    SdrHitKind eHit = pView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );

    if (eHit != SdrHitKind::NONE && aVEvt.mpObj != nullptr)
    {
        if ( SvxIMapInfo::GetIMapInfo(aVEvt.mpObj) && SvxIMapInfo::GetHitIMapObject(
                                aVEvt.mpObj, pWindow->PixelToLogic(rPosPixel), pWindow->GetOutDev() ) )
            return true;

        if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
            return true;
    }

    return false;
}

void FuDraw::ForcePointer(const MouseEvent* pMEvt)
{
    if ( pView->IsAction() )
        return;

    Point aPosPixel = pWindow->GetPointerPosPixel();
    bool bAlt       = pMEvt && pMEvt->IsMod2();
    Point aPnt      = pWindow->PixelToLogic( aPosPixel );
    SdrHdl* pHdl    = pView->PickHandle(aPnt);
    SdrPageView* pPV;
    SdrObject* pMacroPickObj;

    ScMacroInfo* pInfo = nullptr;
    SdrObject* pObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
    if (pObj)
    {
        if ( pObj->IsGroupObject() )
        {
            SdrObject* pHit = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
            if (pHit)
                pObj = pHit;
        }
        pInfo = ScDrawLayer::GetMacroInfo( pObj );
    }

    if ( pView->IsTextEdit() )
    {
        rViewShell.SetActivePointer(PointerStyle::Text);        // can't be ?
    }
    else if ( pHdl )
    {
        rViewShell.SetActivePointer(
            pView->GetPreferredPointer( aPnt, pWindow->GetOutDev() ) );
    }
    else if ( pView->IsMarkedHit(aPnt) )
    {
        rViewShell.SetActivePointer( PointerStyle::Move );
    }
    else if ( !bAlt && ( !pMEvt || !pMEvt->GetButtons() )
                    && lcl_UrlHit( pView, aPosPixel, pWindow ) )
    {
        //  could be suppressed with ALT
        pWindow->SetPointer( PointerStyle::RefHand );          // Text-URL / ImageMap
    }
    else if ( !bAlt && (pMacroPickObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO)) )
    {
        //  could be suppressed with ALT
        SdrObjMacroHitRec aHitRec;  //! something missing ????
        rViewShell.SetActivePointer(pMacroPickObj->GetMacroPointer(aHitRec));
    }
    else if ( !bAlt && pInfo && (!pInfo->GetMacro().isEmpty() || !pObj->getHyperlink().isEmpty()) )
        pWindow->SetPointer( PointerStyle::RefHand );
    else if ( IsDetectiveHit( aPnt ) )
        rViewShell.SetActivePointer( PointerStyle::Detective );
    else
    {
        const bool bIsThemed = rViewShell.GetViewData().IsThemedCursor();
        rViewShell.SetActivePointer( bIsThemed ? PointerStyle::FatCross : PointerStyle::Arrow ); //! in Gridwin?
    }
}

bool FuDraw::IsEditingANote() const
{
    const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
    const size_t backval=rMarkList.GetMarkCount();
    for (size_t nlv1=0; nlv1<backval; ++nlv1)
    {
        SdrObject* pObj = rMarkList.GetMark( nlv1 )->GetMarkedSdrObj();
        if ( ScDrawLayer::IsNoteCaption( pObj ) )
        {
            return true;
        }
    }
    return false;
}

bool FuDraw::IsSizingOrMovingNote( const MouseEvent& rMEvt ) const
{
    bool bIsSizingOrMoving = false;
    if ( rMEvt.IsLeft() )
    {
        const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
        if(rMarkList.GetMarkCount() == 1)
        {
            SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
            if ( ScDrawLayer::IsNoteCaption( pObj ) )
            {
                Point aMPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
                bIsSizingOrMoving =
                    pView->PickHandle( aMPos ) ||      // handles to resize the note
                    pView->IsTextEditFrameHit( aMPos );         // frame for moving the note
            }
        }
    }
    return bIsSizingOrMoving;
}

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