/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
 
#include <config_wasm_strip.h>
 
#include <swtypes.hxx>
#include <hintids.hxx>
 
#include <com/sun/star/accessibility/XAccessible.hpp>
#include <com/sun/star/awt/PopupMenuDirection.hpp>
#include <com/sun/star/awt/XPopupMenu.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
#include <com/sun/star/i18n/UnicodeScript.hpp>
#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
#include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
 
#include <comphelper/scopeguard.hxx>
#include <comphelper/string.hxx>
 
#include <vcl/dialoghelper.hxx>
#include <vcl/inputctx.hxx>
#include <vcl/help.hxx>
#include <vcl/weld.hxx>
#include <vcl/ptrstyle.hxx>
#include <svl/macitem.hxx>
#include <unotools/securityoptions.hxx>
#include <basic/sbxvar.hxx>
#include <svl/ctloptions.hxx>
#include <basic/sbx.hxx>
#include <svl/eitem.hxx>
#include <svl/stritem.hxx>
#include <sfx2/ipclient.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/request.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include <svl/ptitem.hxx>
#include <editeng/sizeitem.hxx>
#include <editeng/langitem.hxx>
#include <svx/statusitem.hxx>
#include <svx/svdview.hxx>
#include <svx/svdhdl.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/flditem.hxx>
#include <editeng/colritem.hxx>
#include <unotools/charclass.hxx>
#include <unotools/datetime.hxx>
 
#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>
 
#include <editeng/acorrcfg.hxx>
#include <SwSmartTagMgr.hxx>
#include <edtdd.hxx>
#include <edtwin.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <textboxhelper.hxx>
#include <dcontact.hxx>
#include <fldbas.hxx>
#include <swmodule.hxx>
#include <docsh.hxx>
#include <viewopt.hxx>
#include <drawbase.hxx>
#include <dselect.hxx>
#include <textsh.hxx>
#include <shdwcrsr.hxx>
#include <txatbase.hxx>
#include <fmtanchr.hxx>
#include <fmtornt.hxx>
#include <fmthdft.hxx>
#include <frmfmt.hxx>
#include <modcfg.hxx>
#include <fmtcol.hxx>
#include <wview.hxx>
#include <gloslst.hxx>
#include <inputwin.hxx>
#include <gloshdl.hxx>
#include <swundo.hxx>
#include <drwtxtsh.hxx>
#include <fchrfmt.hxx>
#include "romenu.hxx"
#include <initui.hxx>
#include <frmatr.hxx>
#include <extinput.hxx>
#include <acmplwrd.hxx>
#include <swcalwrp.hxx>
#include <swdtflvr.hxx>
#include <breakit.hxx>
#include <checkit.hxx>
#include <pagefrm.hxx>
 
#include <helpids.h>
#include <cmdid.h>
#include <uitool.hxx>
#include <fmtfollowtextflow.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <charfmt.hxx>
#include <numrule.hxx>
#include <pagedesc.hxx>
#include <svtools/ruler.hxx>
#include <formatclipboard.hxx>
#include <vcl/svapp.hxx>
#include <wordcountdialog.hxx>
#include <fmtfld.hxx>
 
#include <IMark.hxx>
#include <doc.hxx>
#include <xmloff/odffields.hxx>
 
#include <PostItMgr.hxx>
#include <FrameControlsManager.hxx>
#include <AnnotationWin.hxx>
 
#include <algorithm>
#include <vector>
 
#include <rootfrm.hxx>
 
#include <unotools/syslocaleoptions.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <salhelper/singletonref.hxx>
#include <sfx2/event.hxx>
#include <memory>
 
#include "../../core/crsr/callnk.hxx"
#include <IDocumentOutlineNodes.hxx>
#include <ndtxt.hxx>
#include <cntfrm.hxx>
#include <txtfrm.hxx>
#include <strings.hrc>
#include <textcontentcontrol.hxx>
#include <contentcontrolbutton.hxx>
 
using namespace sw::mark;
using namespace ::com::sun::star;
 
/**
 * Globals
 */
static bool g_bInputLanguageSwitched = false;
 
// Used to draw the guide line while resizing the comment sidebar width
static tools::Rectangle aLastCommentSidebarPos;
 
// Usually in MouseButtonUp a selection is revoked when the selection is
// not currently being pulled open. Unfortunately in MouseButtonDown there
// is being selected at double/triple click. That selection is completely
// finished in the Handler and thus can't be distinguished in the Up.
// To resolve this g_bHoldSelection is set in Down and evaluated in Up.
static bool g_bHoldSelection      = false;
 
bool g_bFrameDrag                   = false;
static bool g_bValidCursorPos       = false;
bool g_bModePushed = false;
bool g_bDDTimerStarted            = false;
bool g_bDDINetAttr                = false;
static SdrHdlKind g_eSdrMoveHdl   = SdrHdlKind::User;
 
QuickHelpData* SwEditWin::s_pQuickHlpData = nullptr;
 
tools::Long    SwEditWin::s_nDDStartPosY = 0;
tools::Long    SwEditWin::s_nDDStartPosX = 0;
 
static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView );
 
/// Check if the selected shape has a TextBox: if so, go into that instead.
static bool lcl_goIntoTextBox(SwEditWin& rEditWin, SwWrtShell& rSh)
{
    SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0);
    if (!pMark)
        return false;
 
    SdrObject* pSdrObject = pMark->GetMarkedSdrObj();
    SwFrameFormat* pObjectFormat = ::FindFrameFormat(pSdrObject);
    if (SwFrameFormat* pTextBoxFormat = SwTextBoxHelper::getOtherTextBoxFormat(pObjectFormat, RES_DRAWFRMFMT))
    {
        SdrObject* pTextBox = pTextBoxFormat->FindRealSdrObject();
        SdrView* pSdrView = rSh.GetDrawView();
        // Unmark the shape.
        pSdrView->UnmarkAllObj();
        // Mark the textbox.
        rSh.SelectObj(Point(), SW_ALLOW_TEXTBOX, pTextBox);
        // Clear the DrawFuncPtr.
        rEditWin.StopInsFrame();
        return true;
    }
    return false;
}
 
class SwAnchorMarker
{
    SdrHdl* m_pHdl;
    Point m_aHdlPos;
    Point m_aLastPos;
    bool m_bTopRightHandle;
public:
    explicit SwAnchorMarker( SdrHdl* pH )
        : m_pHdl( pH )
        , m_aHdlPos( pH->GetPos() )
        , m_aLastPos( pH->GetPos() )
        , m_bTopRightHandle( pH->GetKind() == SdrHdlKind::Anchor_TR )
    {}
    const Point& GetLastPos() const { return m_aLastPos; }
    void SetLastPos( const Point& rNew ) { m_aLastPos = rNew; }
    void SetPos( const Point& rNew ) { m_pHdl->SetPos( rNew ); }
    const Point& GetHdlPos() const { return m_aHdlPos; }
    SdrHdl* GetHdl() const { return m_pHdl; }
    void ChgHdl( SdrHdl* pNew )
    {
        m_pHdl = pNew;
        if ( m_pHdl )
        {
            m_bTopRightHandle = (m_pHdl->GetKind() == SdrHdlKind::Anchor_TR);
        }
    }
    Point GetPosForHitTest( const OutputDevice& rOut )
    {
        Point aHitTestPos( m_pHdl->GetPos() );
        aHitTestPos = rOut.LogicToPixel( aHitTestPos );
        if ( m_bTopRightHandle )
        {
            aHitTestPos += Point( -1, 1 );
        }
        else
        {
            aHitTestPos += Point( 1, 1 );
        }
        aHitTestPos = rOut.PixelToLogic( aHitTestPos );
 
        return aHitTestPos;
    }
};
 
/// Assists with auto-completion of AutoComplete words and AutoText names.
struct QuickHelpData
{
    /// Strings that at least partially match an input word, and match length.
    std::vector<std::pair<OUString, sal_uInt16>> m_aHelpStrings;
    /// Index of the current help string.
    sal_uInt16 nCurArrPos;
    static constexpr sal_uInt16 nNoPos = std::numeric_limits<sal_uInt16>::max();
 
    /// Help data stores AutoText names rather than AutoComplete words.
    bool m_bIsAutoText;
    /// Display help string as a tip rather than inline.
    bool m_bIsTip;
    /// Tip ID when a help string is displayed as a tip.
    void* nTipId;
    /// Append a space character to the displayed help string (if appropriate).
    bool m_bAppendSpace;
 
    /// Help string is currently displayed.
    bool m_bIsDisplayed;
 
    QuickHelpData() { ClearContent(); }
 
    void Move( QuickHelpData& rCpy );
    void ClearContent();
    void Start(SwWrtShell& rSh, bool bRestart);
    void Stop( SwWrtShell& rSh );
 
    bool HasContent() const { return !m_aHelpStrings.empty() && nCurArrPos != nNoPos; }
    const OUString& CurStr() const { return m_aHelpStrings[nCurArrPos].first; }
    sal_uInt16 CurLen() const { return m_aHelpStrings[nCurArrPos].second; }
 
    /// Next help string.
    void Next( bool bEndLess )
    {
        if( ++nCurArrPos >= m_aHelpStrings.size() )
            nCurArrPos = (bEndLess && !m_bIsAutoText ) ? 0 : nCurArrPos-1;
    }
    /// Previous help string.
    void Previous( bool bEndLess )
    {
        if( 0 == nCurArrPos-- )
            nCurArrPos = (bEndLess && !m_bIsAutoText ) ? m_aHelpStrings.size()-1 : 0;
    }
 
    // Fills internal structures with hopefully helpful information.
    void FillStrArr( SwWrtShell const & rSh, const OUString& rWord );
    void SortAndFilter(const OUString &rOrigWord);
};
 
/**
 * Avoid minimal movement shiver
 */
#define HIT_PIX  2 /* hit tolerance in pixel  */
#define MIN_MOVE 4
 
static bool IsMinMove(const Point &rStartPos, const Point &rLPt)
{
    return std::abs(rStartPos.X() - rLPt.X()) > MIN_MOVE ||
           std::abs(rStartPos.Y() - rLPt.Y()) > MIN_MOVE;
}
 
/**
 * For MouseButtonDown - determine whether a DrawObject
 * a NO SwgFrame was hit! Shift/Ctrl should only result
 * in selecting, with DrawObjects; at SwgFlys to trigger
 * hyperlinks if applicable (Download/NewWindow!)
 */
static bool IsDrawObjSelectable( const SwWrtShell& rSh, const Point& rPt )
{
    bool bRet = true;
    SdrObject* pObj;
    switch( rSh.GetObjCntType( rPt, pObj ))
    {
    case OBJCNT_NONE:
    case OBJCNT_FLY:
    case OBJCNT_GRF:
    case OBJCNT_OLE:
        bRet = false;
        break;
    default:; //prevent warning
    }
    return bRet;
}
 
/*
 * Switch pointer
 */
void SwEditWin::UpdatePointer(const Point &rLPt, sal_uInt16 nModifier )
{
    SetQuickHelpText(OUString());
    SwWrtShell &rSh = m_rView.GetWrtShell();
    if( m_pApplyTempl )
    {
        PointerStyle eStyle = PointerStyle::Fill;
        if ( rSh.IsOverReadOnlyPos( rLPt ) )
        {
            m_pUserMarker.reset();
 
            eStyle = PointerStyle::NotAllowed;
        }
        else
        {
            SwRect aRect;
            SwRect* pRect = &aRect;
            const SwFrameFormat* pFormat = nullptr;
 
            bool bFrameIsValidTarget = false;
            if( m_pApplyTempl->m_pFormatClipboard )
                bFrameIsValidTarget = m_pApplyTempl->m_pFormatClipboard->HasContentForThisType( SelectionType::Frame );
            else if( !m_pApplyTempl->nColor )
                bFrameIsValidTarget = ( m_pApplyTempl->eType == SfxStyleFamily::Frame );
 
            if( bFrameIsValidTarget &&
                        nullptr !=(pFormat = rSh.GetFormatFromObj( rLPt, &pRect )) &&
                        dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
            {
                //turn on highlight for frame
                tools::Rectangle aTmp( pRect->SVRect() );
 
                if ( !m_pUserMarker )
                {
                    m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
                }
            }
            else
            {
                m_pUserMarker.reset();
            }
 
            rSh.SwCursorShell::SetVisibleCursor( rLPt );
        }
        SetPointer( eStyle );
        return;
    }
 
    if( !rSh.VisArea().Width() )
        return;
 
    CurrShell aCurr(&rSh);
 
    if ( IsChainMode() )
    {
        SwRect aRect;
        SwChainRet nChainable = rSh.Chainable( aRect, *rSh.GetFlyFrameFormat(), rLPt );
        PointerStyle eStyle = nChainable != SwChainRet::OK
                ? PointerStyle::ChainNotAllowed : PointerStyle::Chain;
        if ( nChainable == SwChainRet::OK )
        {
            tools::Rectangle aTmp( aRect.SVRect() );
 
            if ( !m_pUserMarker )
            {
                m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
            }
        }
        else
        {
            m_pUserMarker.reset();
        }
 
        SetPointer( eStyle );
        return;
    }
 
    bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
    if ( !bExecHyperlinks )
    {
        const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
        if ( (  bSecureOption && nModifier == KEY_MOD1 ) ||
             ( !bSecureOption && nModifier != KEY_MOD1 ) )
            bExecHyperlinks = true;
    }
 
    const bool bExecSmarttags  = nModifier == KEY_MOD1;
 
    SdrView *pSdrView = rSh.GetDrawView();
    bool bPrefSdrPointer = false;
    bool bHitHandle = false;
    bool bCntAtPos = false;
    bool bIsViewReadOnly = IsViewReadonly();
 
    m_aActHitType = SdrHitKind::NONE;
    PointerStyle eStyle = PointerStyle::Text;
    if ( !pSdrView )
        bCntAtPos = true;
    else if ( (bHitHandle = (pSdrView->PickHandle(rLPt) != nullptr)) )
    {
        m_aActHitType = SdrHitKind::Object;
        bPrefSdrPointer = true;
    }
    else
    {
        const bool bNotInSelObj = !rSh.IsInsideSelectedObj( rLPt );
        if ( m_rView.GetDrawFuncPtr() && !m_bInsDraw && bNotInSelObj )
        {
            m_aActHitType = SdrHitKind::Object;
            if (IsObjectSelect())
                eStyle = PointerStyle::Arrow;
            else
                bPrefSdrPointer = true;
        }
        else
        {
            SdrPageView* pPV = nullptr;
            pSdrView->SetHitTolerancePixel( HIT_PIX );
            SdrObject* pObj  = (bNotInSelObj && bExecHyperlinks) ?
                 pSdrView->PickObj(rLPt, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) :
                 nullptr;
            if (pObj)
            {
                SdrObjMacroHitRec aTmp;
                aTmp.aPos = rLPt;
                aTmp.pPageView = pPV;
                SetPointer( pObj->GetMacroPointer( aTmp ) );
                return;
            }
            else
            {
                // dvo: IsObjSelectable() eventually calls SdrView::PickObj, so
                // apparently this is used to determine whether this is a
                // drawling layer object or not.
                if ( rSh.IsObjSelectable( rLPt ) )
                {
                    if (pSdrView->IsTextEdit())
                    {
                        m_aActHitType = SdrHitKind::NONE;
                        bPrefSdrPointer = true;
                    }
                    else
                    {
                        SdrViewEvent aVEvt;
                        SdrHitKind eHit = pSdrView->PickAnything(rLPt, aVEvt);
 
                        if (eHit == SdrHitKind::UrlField && bExecHyperlinks)
                        {
                            m_aActHitType = SdrHitKind::Object;
                            bPrefSdrPointer = true;
                        }
                        else
                        {
                            // if we're over a selected object, we show an
                            // ARROW by default. We only show a MOVE if 1) the
                            // object is selected, and 2) it may be moved
                            // (i.e., position is not protected).
                            bool bMovable =
                                (!bNotInSelObj) &&
                                (rSh.IsObjSelected() || rSh.IsFrameSelected()) &&
                                (rSh.IsSelObjProtected(FlyProtectFlags::Pos) == FlyProtectFlags::NONE);
 
                            SdrObject* pSelectableObj = rSh.GetObjAt(rLPt);
                            // Don't update pointer if this is a background image only.
                            if (pSelectableObj->GetLayer() != rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId())
                                eStyle = bMovable ? PointerStyle::Move : PointerStyle::Arrow;
                            m_aActHitType = SdrHitKind::Object;
                        }
                    }
                }
                else
                {
                    if ( rSh.IsFrameSelected() && !bNotInSelObj )
                    {
                        // dvo: this branch appears to be dead and should be
                        // removed in a future version. Reason: The condition
                        // !bNotInSelObj means that this branch will only be
                        // executed in the cursor points inside a selected
                        // object. However, if this is the case, the previous
                        // if( rSh.IsObjSelectable(rLPt) ) must always be true:
                        // rLPt is inside a selected object, then obviously
                        // rLPt is over a selectable object.
                        if (rSh.IsSelObjProtected(FlyProtectFlags::Size) != FlyProtectFlags::NONE)
                            eStyle = PointerStyle::NotAllowed;
                        else
                            eStyle = PointerStyle::Move;
                        m_aActHitType = SdrHitKind::Object;
                    }
                    else
                    {
                        if ( m_rView.GetDrawFuncPtr() )
                            bPrefSdrPointer = true;
                        else
                            bCntAtPos = true;
                    }
                }
            }
        }
    }
    if ( bPrefSdrPointer )
    {
        if (bIsViewReadOnly || (rSh.IsObjSelected() && rSh.IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE))
            SetPointer( PointerStyle::NotAllowed );
        else
        {
            if (m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->IsInsertForm() && !bHitHandle)
                SetPointer( PointerStyle::DrawRect );
            else
                SetPointer( pSdrView->GetPreferredPointer( rLPt, rSh.GetOut() ) );
        }
    }
    else
    {
        if( !rSh.IsPageAtPos( rLPt ) || m_pAnchorMarker )
            eStyle = PointerStyle::Arrow;
        else
        {
            // Even if we already have something, prefer URLs if possible.
            SwContentAtPos aUrlPos(IsAttrAtPos::InetAttr);
            if (bCntAtPos || rSh.GetContentAtPos(rLPt, aUrlPos))
            {
                SwContentAtPos aSwContentAtPos(
                    IsAttrAtPos::Field |
                    IsAttrAtPos::ClickField |
                    IsAttrAtPos::InetAttr |
                    IsAttrAtPos::Ftn |
                    IsAttrAtPos::SmartTag);
                if( rSh.GetContentAtPos( rLPt, aSwContentAtPos) )
                {
                    // Is edit inline input field
                    if (IsAttrAtPos::Field == aSwContentAtPos.eContentAtPos
                             && aSwContentAtPos.pFndTextAttr != nullptr
                             && aSwContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD)
                    {
                        const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
                        if (!(pCursorField && pCursorField == aSwContentAtPos.pFndTextAttr->GetFormatField().GetField()))
                            eStyle = PointerStyle::RefHand;
                    }
                    else
                    {
                        const bool bClickToFollow = IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos ||
                                                    IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos;
                        if( !bClickToFollow ||
                            (IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos && bExecHyperlinks) ||
                            (IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos && bExecSmarttags) )
                            eStyle = PointerStyle::RefHand;
                    }
                }
                else if (GetView().GetWrtShell().GetViewOptions()->IsShowOutlineContentVisibilityButton())
                {
                    aSwContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
                    if (rSh.GetContentAtPos(rLPt, aSwContentAtPos))
                    {
                        if (IsAttrAtPos::Outline == aSwContentAtPos.eContentAtPos)
                        {
                            if (nModifier == KEY_MOD1)
                            {
                                eStyle = PointerStyle::RefHand;
                                // set quick help
                                if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
                                {
                                    const SwNodes& rNds = GetView().GetWrtShell().GetDoc()->GetNodes();
                                    SwOutlineNodes::size_type nPos;
                                    rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos);
                                    SwOutlineNodes::size_type nOutlineNodesCount
                                            = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
                                    int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
                                    OUString sQuickHelp(SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY));
                                    if (!rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent()
                                            && nPos + 1 < nOutlineNodesCount
                                            && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos + 1) > nLevel)
                                        sQuickHelp += " (" + SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
                                    SetQuickHelpText(sQuickHelp);
                                }
                            }
                        }
                    }
                }
            }
        }
 
        // which kind of text pointer have we to show - horz / vert - ?
        if( PointerStyle::Text == eStyle && rSh.IsInVerticalText( &rLPt ))
            eStyle = PointerStyle::TextVertical;
        else if (rSh.GetViewOptions()->CanHideWhitespace() &&
                 rSh.GetLayout()->IsBetweenPages(rLPt))
        {
            if (rSh.GetViewOptions()->IsHideWhitespaceMode())
                eStyle = PointerStyle::ShowWhitespace;
            else
                eStyle = PointerStyle::HideWhitespace;
        }
 
        if( m_pShadCursor )
        {
            if( text::HoriOrientation::LEFT == m_eOrient )    // Arrow to the right
                eStyle = PointerStyle::AutoScrollE;
            else    // Arrow to the left
                eStyle = PointerStyle::AutoScrollW;
        }
 
        SetPointer( eStyle );
    }
}
 
/**
 * Increase timer for selection
 */
IMPL_LINK_NOARG(SwEditWin, TimerHandler, Timer *, void)
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    Point aModPt( m_aMovePos );
    const SwRect aOldVis( rSh.VisArea() );
    bool bDone = false;
 
    if ( !rSh.VisArea().Contains( aModPt ) )
    {
        if ( m_bInsDraw )
        {
            const int nMaxScroll = 40;
            m_rView.Scroll( tools::Rectangle(aModPt,Size(1,1)), nMaxScroll, nMaxScroll);
            bDone = true;
        }
        else if ( g_bFrameDrag )
        {
            rSh.Drag(&aModPt, false);
            bDone = true;
        }
        if ( !bDone )
            aModPt = rSh.GetContentPos( aModPt,aModPt.Y() > rSh.VisArea().Bottom() );
    }
    if ( !bDone && !(g_bFrameDrag || m_bInsDraw) )
    {
        if ( m_xRowColumnSelectionStart )
        {
            Point aPos( aModPt );
            rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag );
        }
        else
            rSh.CallSetCursor( &aModPt, false );
 
        // It can be that a "jump" over a table cannot be accomplished like
        // that. So we jump over the table by Up/Down here.
        const SwRect& rVisArea = rSh.VisArea();
        if( aOldVis == rVisArea && !rSh.IsStartOfDoc() && !rSh.IsEndOfDoc() )
        {
            // take the center point of VisArea to
            // decide in which direction the user want.
            if( aModPt.Y() < ( rVisArea.Top() + rVisArea.Height() / 2 ) )
                rSh.Up( true );
            else
                rSh.Down( true );
        }
    }
 
    m_aMovePos += rSh.VisArea().Pos() - aOldVis.Pos();
    JustifyAreaTimer();
}
 
void SwEditWin::JustifyAreaTimer()
{
    const tools::Rectangle &rVisArea = GetView().GetVisArea();
#ifdef UNX
    const tools::Long coMinLen = 100;
#else
    const tools::Long coMinLen = 50;
#endif
    tools::Long const nTimeout = 800,
         nDiff = std::max(
         std::max( m_aMovePos.Y() - rVisArea.Bottom(), rVisArea.Top() - m_aMovePos.Y() ),
         std::max( m_aMovePos.X() - rVisArea.Right(),  rVisArea.Left() - m_aMovePos.X()));
    m_aTimer.SetTimeout( std::max( coMinLen, nTimeout - nDiff*2L) );
}
 
void SwEditWin::LeaveArea(const Point &rPos)
{
    m_aMovePos = rPos;
    JustifyAreaTimer();
    if( !m_aTimer.IsActive() )
        m_aTimer.Start();
    m_pShadCursor.reset();
}
 
inline void SwEditWin::EnterArea()
{
    m_aTimer.Stop();
}
 
/**
 * Insert mode for frames
 */
void SwEditWin::InsFrame(sal_uInt16 nCols)
{
    StdDrawMode(SdrObjKind::NewFrame, false);
    m_bInsFrame = true;
    m_nInsFrameColCount = nCols;
}
 
void SwEditWin::StdDrawMode( SdrObjKind eSdrObjectKind, bool bObjSelect )
{
    SetSdrDrawMode( eSdrObjectKind );
 
    if (bObjSelect)
        m_rView.SetDrawFuncPtr(std::make_unique<DrawSelection>( &m_rView.GetWrtShell(), this, &m_rView ));
    else
        m_rView.SetDrawFuncPtr(std::make_unique<SwDrawBase>( &m_rView.GetWrtShell(), this, &m_rView ));
 
    m_rView.SetSelDrawSlot();
    SetSdrDrawMode( eSdrObjectKind );
    if (bObjSelect)
        m_rView.GetDrawFuncPtr()->Activate( SID_OBJECT_SELECT );
    else
        m_rView.GetDrawFuncPtr()->Activate( sal::static_int_cast< sal_uInt16 >(eSdrObjectKind) );
    m_bInsFrame = false;
    m_nInsFrameColCount = 1;
}
 
void SwEditWin::StopInsFrame()
{
    if (m_rView.GetDrawFuncPtr())
    {
        m_rView.GetDrawFuncPtr()->Deactivate();
        m_rView.SetDrawFuncPtr(nullptr);
    }
    m_rView.LeaveDrawCreate();    // leave construction mode
    m_bInsFrame = false;
    m_nInsFrameColCount = 1;
}
 
bool SwEditWin::IsInputSequenceCheckingRequired( const OUString &rText, const SwPaM& rCursor )
{
    if ( !SvtCTLOptions::IsCTLFontEnabled() ||
         !SvtCTLOptions::IsCTLSequenceChecking() )
         return false;
 
    if ( 0 == rCursor.Start()->GetContentIndex() ) /* first char needs not to be checked */
        return false;
 
    SwBreakIt *pBreakIter = SwBreakIt::Get();
    uno::Reference < i18n::XBreakIterator > xBI = pBreakIter->GetBreakIter();
    assert(xBI.is());
    tools::Long nCTLScriptPos = -1;
 
    if (xBI->getScriptType( rText, 0 ) == i18n::ScriptType::COMPLEX)
        nCTLScriptPos = 0;
    else
        nCTLScriptPos = xBI->nextScript( rText, 0, i18n::ScriptType::COMPLEX );
 
    return (0 <= nCTLScriptPos && nCTLScriptPos <= rText.getLength());
}
 
//return INVALID_HINT if language should not be explicitly overridden, the correct
//HintId to use for the eBufferLanguage otherwise
static sal_uInt16 lcl_isNonDefaultLanguage(LanguageType eBufferLanguage, SwView const & rView,
    const OUString &rInBuffer)
{
    sal_uInt16 nWhich = INVALID_HINT;
 
    //If the option to IgnoreLanguageChange is set, short-circuit this method
    //which results in the document/paragraph language remaining the same
    //despite a change to the keyboard/input language
    SvtSysLocaleOptions aSysLocaleOptions;
    if(aSysLocaleOptions.IsIgnoreLanguageChange())
    {
        return INVALID_HINT;
    }
 
    bool bLang = true;
    if(eBufferLanguage != LANGUAGE_DONTKNOW)
    {
        switch( SvtLanguageOptions::GetI18NScriptTypeOfLanguage( eBufferLanguage ))
        {
            case  i18n::ScriptType::ASIAN:     nWhich = RES_CHRATR_CJK_LANGUAGE; break;
            case  i18n::ScriptType::COMPLEX:   nWhich = RES_CHRATR_CTL_LANGUAGE; break;
            case  i18n::ScriptType::LATIN:     nWhich = RES_CHRATR_LANGUAGE; break;
            default: bLang = false;
        }
        if(bLang)
        {
            SfxItemSet aLangSet(rView.GetPool(), nWhich, nWhich);
            SwWrtShell& rSh = rView.GetWrtShell();
            rSh.GetCurAttr(aLangSet);
            if(SfxItemState::DEFAULT <= aLangSet.GetItemState(nWhich))
            {
                LanguageType eLang = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage();
                if ( eLang == eBufferLanguage )
                {
                    // current language attribute equal to language reported from system
                    bLang = false;
                }
                else if ( !g_bInputLanguageSwitched && RES_CHRATR_LANGUAGE == nWhich )
                {
                    // special case: switching between two "LATIN" languages
                    // In case the current keyboard setting might be suitable
                    // for both languages we can't safely assume that the user
                    // wants to use the language reported from the system,
                    // except if we knew that it was explicitly switched (thus
                    // the check for "bInputLangeSwitched").
 
                    // The language reported by the system could be just the
                    // system default language that the user is not even aware
                    // of, because no language selection tool is installed at
                    // all. In this case the OOo language should get preference
                    // as it might have been selected by the user explicitly.
 
                    // Usually this case happens if the OOo language is
                    // different to the system language but the system keyboard
                    // is still suitable for the OOo language (e.g. writing
                    // English texts with a German keyboard).
 
                    // For non-latin keyboards overwriting the attribute is
                    // still valid. We do this for cyrillic and greek ATM.  In
                    // future versions of OOo this should be replaced by a
                    // configuration switch that allows to give the preference
                    // to the OOo setting or the system setting explicitly
                    // and/or a better handling of the script type.
                    i18n::UnicodeScript eType = !rInBuffer.isEmpty() ?
                        GetAppCharClass().getScript( rInBuffer, 0 ) :
                        i18n::UnicodeScript_kScriptCount;
 
                    bool bSystemIsNonLatin = false;
                    switch ( eType )
                    {
                        case i18n::UnicodeScript_kGreek:
                        case i18n::UnicodeScript_kCyrillic:
                            // in case other UnicodeScripts require special
                            // keyboards they can be added here
                            bSystemIsNonLatin = true;
                            break;
                        default:
                            break;
                    }
 
                    bool bOOoLangIsNonLatin = MsLangId::isNonLatinWestern( eLang);
 
                    bLang = (bSystemIsNonLatin != bOOoLangIsNonLatin);
                }
            }
        }
    }
    return bLang ? nWhich : INVALID_HINT;
}
 
/**
 * Character buffer is inserted into the document
 */
void SwEditWin::FlushInBuffer()
{
    if ( m_aKeyInputFlushTimer.IsActive())
        m_aKeyInputFlushTimer.Stop();
 
    if ( m_aInBuffer.isEmpty() )
        return;
 
    SwWrtShell& rSh = m_rView.GetWrtShell();
    uno::Reference<frame::XDispatchRecorder> xRecorder
        = m_rView.GetViewFrame().GetBindings().GetRecorder();
 
    comphelper::ScopeGuard showTooltipGuard(
        [this, &rSh]
        {
            SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
            const bool bAutoTextShown
                = rACfg.IsAutoTextTip() && ShowAutoText(rSh.GetChunkForAutoText());
            if (!bAutoTextShown)
            {
                SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
                if (pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
                    ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
            }
        });
    if (!m_bMaybeShowTooltipAfterBufferFlush || xRecorder)
        showTooltipGuard.dismiss();
    m_bMaybeShowTooltipAfterBufferFlush = false;
 
    // generate new sequence input checker if not already done
    if ( !pCheckIt )
        pCheckIt = new SwCheckIt;
 
    uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = pCheckIt->xCheck;
    if ( xISC.is() && IsInputSequenceCheckingRequired( m_aInBuffer, *rSh.GetCursor() ) )
    {
 
        // apply (Thai) input sequence checking/correction
 
        rSh.Push(); // push current cursor to stack
 
        // get text from the beginning (i.e left side) of current selection
        // to the start of the paragraph
        rSh.NormalizePam();     // make point be the first (left) one
        if (!rSh.GetCursor()->HasMark())
            rSh.GetCursor()->SetMark();
        rSh.GetCursor()->GetMark()->SetContent(0);
 
        const OUString aOldText( rSh.GetCursor()->GetText() );
        const sal_Int32 nOldLen = aOldText.getLength();
 
        sal_Int32 nExpandSelection = 0;
        if (nOldLen > 0)
        {
            sal_Int32 nTmpPos = nOldLen;
            sal_Int16 nCheckMode = SvtCTLOptions::IsCTLSequenceCheckingRestricted() ?
                    i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
 
            OUString aNewText( aOldText );
            if (SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace())
            {
                for( sal_Int32 k = 0;  k < m_aInBuffer.getLength();  ++k)
                {
                    const sal_Unicode cChar = m_aInBuffer[k];
                    const sal_Int32 nPrevPos =xISC->correctInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode );
 
                    // valid sequence or sequence could be corrected:
                    if (nPrevPos != aNewText.getLength())
                        nTmpPos = nPrevPos + 1;
                }
 
                // find position of first character that has changed
                sal_Int32 nNewLen = aNewText.getLength();
                const sal_Unicode *pOldText = aOldText.getStr();
                const sal_Unicode *pNewText = aNewText.getStr();
                sal_Int32 nChgPos = 0;
                while ( nChgPos < nOldLen && nChgPos < nNewLen &&
                        pOldText[nChgPos] == pNewText[nChgPos] )
                    ++nChgPos;
 
                const sal_Int32 nChgLen = nNewLen - nChgPos;
                if (nChgLen)
                {
                    m_aInBuffer = aNewText.copy( nChgPos, nChgLen );
                    nExpandSelection = nOldLen - nChgPos;
                }
                else
                    m_aInBuffer.clear();
            }
            else
            {
                for( sal_Int32 k = 0;  k < m_aInBuffer.getLength(); ++k )
                {
                    const sal_Unicode cChar = m_aInBuffer[k];
                    if (xISC->checkInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode ))
                    {
                        // character can be inserted:
                        aNewText += OUStringChar( cChar );
                        ++nTmpPos;
                    }
                }
                m_aInBuffer = aNewText.copy( aOldText.getLength() );  // copy new text to be inserted to buffer
            }
        }
 
        // at this point now we will insert the buffer text 'normally' some lines below...
 
        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
 
        if (m_aInBuffer.isEmpty())
            return;
 
        // if text prior to the original selection needs to be changed
        // as well, we now expand the selection accordingly.
        SwPaM &rCursor = *rSh.GetCursor();
        const sal_Int32 nCursorStartPos = rCursor.Start()->GetContentIndex();
        OSL_ENSURE( nCursorStartPos >= nExpandSelection, "cannot expand selection as specified!!" );
        if (nExpandSelection && nCursorStartPos >= nExpandSelection)
        {
            if (!rCursor.HasMark())
                rCursor.SetMark();
            rCursor.Start()->AdjustContent( -nExpandSelection );
        }
    }
 
    if ( xRecorder.is() )
    {
        // determine shell
        SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
        // generate request and record
        if (pSfxShell)
        {
            SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
            aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, m_aInBuffer ) );
            aReq.Done();
        }
    }
 
    sal_uInt16 nWhich = lcl_isNonDefaultLanguage(m_eBufferLanguage, m_rView, m_aInBuffer);
    if (nWhich != INVALID_HINT )
    {
        SvxLanguageItem aLangItem( m_eBufferLanguage, nWhich );
        rSh.SetAttrItem( aLangItem );
    }
 
    rSh.Insert( m_aInBuffer );
    m_eBufferLanguage = LANGUAGE_DONTKNOW;
    m_aInBuffer.clear();
}
 
#define MOVE_LEFT_SMALL     0
#define MOVE_UP_SMALL       1
#define MOVE_RIGHT_BIG      2
#define MOVE_DOWN_BIG       3
#define MOVE_LEFT_BIG       4
#define MOVE_UP_BIG         5
#define MOVE_RIGHT_SMALL    6
#define MOVE_DOWN_SMALL     7
 
// #i121236# Support for shift key in writer
#define MOVE_LEFT_HUGE      8
#define MOVE_UP_HUGE        9
#define MOVE_RIGHT_HUGE     10
#define MOVE_DOWN_HUGE      11
 
void SwEditWin::ChangeFly( sal_uInt8 nDir, bool bWeb )
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    SwRect aTmp = rSh.GetFlyRect();
    if( !aTmp.HasArea() ||
        rSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
        return;
 
    SfxItemSetFixed<
            RES_FRM_SIZE, RES_FRM_SIZE,
            RES_PROTECT, RES_PROTECT,
            RES_VERT_ORIENT, RES_ANCHOR,
            RES_COL, RES_COL,
            RES_FOLLOW_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW>
        aSet( rSh.GetAttrPool() );
    rSh.GetFlyFrameAttr( aSet );
    RndStdIds eAnchorId = aSet.Get(RES_ANCHOR).GetAnchorId();
    Size aSnap;
    bool bHuge(MOVE_LEFT_HUGE == nDir ||
        MOVE_UP_HUGE == nDir ||
        MOVE_RIGHT_HUGE == nDir ||
        MOVE_DOWN_HUGE == nDir);
 
    if(MOVE_LEFT_SMALL == nDir ||
        MOVE_UP_SMALL == nDir ||
        MOVE_RIGHT_SMALL == nDir ||
        MOVE_DOWN_SMALL == nDir )
    {
        aSnap = PixelToLogic(Size(1,1));
    }
    else
    {
        aSnap = rSh.GetViewOptions()->GetSnapSize();
        short nDiv = rSh.GetViewOptions()->GetDivisionX();
        if ( nDiv > 0 )
            aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
        nDiv = rSh.GetViewOptions()->GetDivisionY();
        if ( nDiv > 0 )
            aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
    }
 
    if(bHuge)
    {
        // #i121236# 567twips == 1cm, but just take three times the normal snap
        aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
    }
 
    SwRect aBoundRect;
    Point aRefPoint;
    // adjustment for allowing vertical position
    // aligned to page for fly frame anchored to paragraph or to character.
    {
        const SwFormatVertOrient& aVert( aSet.Get(RES_VERT_ORIENT) );
        const bool bFollowTextFlow =
                aSet.Get(RES_FOLLOW_TEXT_FLOW).GetValue();
        const SwFormatAnchor& rFormatAnchor = aSet.Get(RES_ANCHOR);
        rSh.CalcBoundRect( aBoundRect, eAnchorId,
                           text::RelOrientation::FRAME, aVert.GetRelationOrient(),
                           &rFormatAnchor, bFollowTextFlow,
                           false, &aRefPoint );
    }
    tools::Long nLeft = std::min( aTmp.Left() - aBoundRect.Left(), aSnap.Width() );
    tools::Long nRight = std::min( aBoundRect.Right() - aTmp.Right(), aSnap.Width() );
    tools::Long nUp = std::min( aTmp.Top() - aBoundRect.Top(), aSnap.Height() );
    tools::Long nDown = std::min( aBoundRect.Bottom() - aTmp.Bottom(), aSnap.Height() );
 
    switch ( nDir )
    {
        case MOVE_LEFT_BIG:
        case MOVE_LEFT_HUGE:
        case MOVE_LEFT_SMALL: aTmp.Left( aTmp.Left() - nLeft );
            break;
 
        case MOVE_UP_BIG:
        case MOVE_UP_HUGE:
        case MOVE_UP_SMALL: aTmp.Top( aTmp.Top() - nUp );
            break;
 
        case MOVE_RIGHT_SMALL:
            if( aTmp.Width() < aSnap.Width() + MINFLY )
                break;
            nRight = aSnap.Width();
            [[fallthrough]];
        case MOVE_RIGHT_HUGE:
        case MOVE_RIGHT_BIG: aTmp.Left( aTmp.Left() + nRight );
            break;
 
        case MOVE_DOWN_SMALL:
            if( aTmp.Height() < aSnap.Height() + MINFLY )
                break;
            nDown = aSnap.Height();
            [[fallthrough]];
        case MOVE_DOWN_HUGE:
        case MOVE_DOWN_BIG: aTmp.Top( aTmp.Top() + nDown );
            break;
 
        default: OSL_ENSURE(true, "ChangeFly: Unknown direction." );
    }
    bool bSet = false;
    if ((RndStdIds::FLY_AS_CHAR == eAnchorId) && ( nDir % 2 ))
    {
        tools::Long aDiff = aTmp.Top() - aRefPoint.Y();
        if( aDiff > 0 )
            aDiff = 0;
        else if ( aDiff < -aTmp.Height() )
            aDiff = -aTmp.Height();
        SwFormatVertOrient aVert( aSet.Get(RES_VERT_ORIENT) );
        sal_Int16 eNew;
        if( bWeb )
        {
            eNew = aVert.GetVertOrient();
            bool bDown = 0 != ( nDir & 0x02 );
            switch( eNew )
            {
                case text::VertOrientation::CHAR_TOP:
                    if( bDown ) eNew = text::VertOrientation::CENTER;
                break;
                case text::VertOrientation::CENTER:
                    eNew = bDown ? text::VertOrientation::TOP : text::VertOrientation::CHAR_TOP;
                break;
                case text::VertOrientation::TOP:
                    if( !bDown ) eNew = text::VertOrientation::CENTER;
                break;
                case text::VertOrientation::LINE_TOP:
                    if( bDown ) eNew = text::VertOrientation::LINE_CENTER;
                break;
                case text::VertOrientation::LINE_CENTER:
                    eNew = bDown ? text::VertOrientation::LINE_BOTTOM : text::VertOrientation::LINE_TOP;
                break;
                case text::VertOrientation::LINE_BOTTOM:
                    if( !bDown ) eNew = text::VertOrientation::LINE_CENTER;
                break;
                default:; //prevent warning
            }
        }
        else
        {
            aVert.SetPos( aDiff );
            eNew = text::VertOrientation::NONE;
        }
        aVert.SetVertOrient( eNew );
        aSet.Put( aVert );
        bSet = true;
    }
    if (bWeb && (RndStdIds::FLY_AT_PARA == eAnchorId)
        && ( nDir==MOVE_LEFT_SMALL || nDir==MOVE_RIGHT_BIG ))
    {
        SwFormatHoriOrient aHori( aSet.Get(RES_HORI_ORIENT) );
        sal_Int16 eNew;
        eNew = aHori.GetHoriOrient();
        switch( eNew )
        {
            case text::HoriOrientation::RIGHT:
                if( nDir==MOVE_LEFT_SMALL )
                    eNew = text::HoriOrientation::LEFT;
            break;
            case text::HoriOrientation::LEFT:
                if( nDir==MOVE_RIGHT_BIG )
                    eNew = text::HoriOrientation::RIGHT;
            break;
            default:; //prevent warning
        }
        if( eNew != aHori.GetHoriOrient() )
        {
            aHori.SetHoriOrient( eNew );
            aSet.Put( aHori );
            bSet = true;
        }
    }
    rSh.StartAllAction();
    if( bSet )
        rSh.SetFlyFrameAttr( aSet );
    bool bSetPos = (RndStdIds::FLY_AS_CHAR != eAnchorId);
    if(bSetPos && bWeb)
    {
        bSetPos = RndStdIds::FLY_AT_PAGE == eAnchorId;
    }
    if( bSetPos )
        rSh.SetFlyPos( aTmp.Pos() );
    rSh.EndAllAction();
 
}
 
void SwEditWin::ChangeDrawing( sal_uInt8 nDir )
{
    // start undo action in order to get only one
    // undo action for this change.
    SwWrtShell &rSh = m_rView.GetWrtShell();
    rSh.StartUndo();
 
    tools::Long nX = 0;
    tools::Long nY = 0;
    const bool bOnePixel(
        MOVE_LEFT_SMALL == nDir ||
        MOVE_UP_SMALL == nDir ||
        MOVE_RIGHT_SMALL == nDir ||
        MOVE_DOWN_SMALL == nDir);
    const bool bHuge(
        MOVE_LEFT_HUGE == nDir ||
        MOVE_UP_HUGE == nDir ||
        MOVE_RIGHT_HUGE == nDir ||
        MOVE_DOWN_HUGE == nDir);
    SwMove nAnchorDir = SwMove::UP;
    switch(nDir)
    {
        case MOVE_LEFT_SMALL:
        case MOVE_LEFT_HUGE:
        case MOVE_LEFT_BIG:
            nX = -1;
            nAnchorDir = SwMove::LEFT;
        break;
        case MOVE_UP_SMALL:
        case MOVE_UP_HUGE:
        case MOVE_UP_BIG:
            nY = -1;
        break;
        case MOVE_RIGHT_SMALL:
        case MOVE_RIGHT_HUGE:
        case MOVE_RIGHT_BIG:
            nX = +1;
            nAnchorDir = SwMove::RIGHT;
        break;
        case MOVE_DOWN_SMALL:
        case MOVE_DOWN_HUGE:
        case MOVE_DOWN_BIG:
            nY = +1;
            nAnchorDir = SwMove::DOWN;
        break;
    }
 
    if(0 != nX || 0 != nY)
    {
        FlyProtectFlags nProtect = rSh.IsSelObjProtected( FlyProtectFlags::Pos|FlyProtectFlags::Size );
        Size aSnap( rSh.GetViewOptions()->GetSnapSize() );
        short nDiv = rSh.GetViewOptions()->GetDivisionX();
        if ( nDiv > 0 )
            aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
        nDiv = rSh.GetViewOptions()->GetDivisionY();
        if ( nDiv > 0 )
            aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
 
        if(bOnePixel)
        {
            aSnap = PixelToLogic(Size(1,1));
        }
        else if(bHuge)
        {
            // #i121236# 567twips == 1cm, but just take three times the normal snap
            aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
        }
 
        nX *= aSnap.Width();
        nY *= aSnap.Height();
 
        SdrView *pSdrView = rSh.GetDrawView();
        const SdrHdlList& rHdlList = pSdrView->GetHdlList();
        SdrHdl* pHdl = rHdlList.GetFocusHdl();
        rSh.StartAllAction();
        if(nullptr == pHdl)
        {
            // now move the selected draw objects
            // if the object's position is not protected
            if(!(nProtect&FlyProtectFlags::Pos))
            {
                // Check if object is anchored as character and move direction
                bool bDummy1, bDummy2;
                const bool bVertAnchor = rSh.IsFrameVertical( true, bDummy1, bDummy2 );
                bool bHoriMove = !bVertAnchor == !( nDir % 2 );
                bool bMoveAllowed =
                    !bHoriMove || (rSh.GetAnchorId() != RndStdIds::FLY_AS_CHAR);
                if ( bMoveAllowed )
                {
                    pSdrView->MoveAllMarked(Size(nX, nY));
                    rSh.SetModified();
                }
            }
        }
        else
        {
            // move handle with index nHandleIndex
            if (nX || nY)
            {
                if( SdrHdlKind::Anchor == pHdl->GetKind() ||
                    SdrHdlKind::Anchor_TR == pHdl->GetKind() )
                {
                    // anchor move cannot be allowed when position is protected
                    if(!(nProtect&FlyProtectFlags::Pos))
                        rSh.MoveAnchor( nAnchorDir );
                }
                //now resize if size is protected
                else if(!(nProtect&FlyProtectFlags::Size))
                {
                    // now move the Handle (nX, nY)
                    Point aStartPoint(pHdl->GetPos());
                    Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
                    const SdrDragStat& rDragStat = pSdrView->GetDragStat();
 
                    // start dragging
                    pSdrView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
 
                    if(pSdrView->IsDragObj())
                    {
                        bool bWasNoSnap = rDragStat.IsNoSnap();
                        bool bWasSnapEnabled = pSdrView->IsSnapEnabled();
 
                        // switch snapping off
                        if(!bWasNoSnap)
                            const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
                        if(bWasSnapEnabled)
                            pSdrView->SetSnapEnabled(false);
 
                        pSdrView->MovAction(aEndPoint);
                        pSdrView->EndDragObj();
                        rSh.SetModified();
 
                        // restore snap
                        if(!bWasNoSnap)
                            const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
                        if(bWasSnapEnabled)
                            pSdrView->SetSnapEnabled(bWasSnapEnabled);
                    }
                }
            }
        }
        rSh.EndAllAction();
    }
 
    rSh.EndUndo();
}
 
/**
 * KeyEvents
 */
void SwEditWin::KeyInput(const KeyEvent &rKEvt)
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
 
    if (comphelper::LibreOfficeKit::isActive() && m_rView.GetPostItMgr())
    {
        if (vcl::Window* pWindow = m_rView.GetPostItMgr()->GetActiveSidebarWin())
        {
            pWindow->KeyInput(rKEvt);
            return;
        }
    }
 
    // Do not show autotext / word completion tooltips in intermediate flushes
    m_bMaybeShowTooltipAfterBufferFlush = false;
 
    sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
 
    if (nKey == KEY_ESCAPE)
    {
        if (m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard)
        {
            m_pApplyTempl->m_pFormatClipboard->Erase();
            SetApplyTemplate(SwApplyTemplate());
            m_rView.GetViewFrame().GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
        }
        else if (rSh.IsHeaderFooterEdit())
        {
            bool bHeader = bool(FrameTypeFlags::HEADER & rSh.GetFrameType(nullptr, false));
            if (bHeader)
                rSh.SttPg();
            else
                rSh.EndPg();
            rSh.ToggleHeaderFooterEdit();
        }
    }
 
    SfxObjectShell *pObjSh = m_rView.GetViewFrame().GetObjectShell();
    if ( m_bLockInput || (pObjSh && pObjSh->GetProgress()) )
        // When the progress bar is active or a progress is
        // running on a document, no order is being taken
        return;
 
    m_pShadCursor.reset();
    // Do not reset the timer here, otherwise when flooded with events it would never time out
    // if every key event stopped and started it again.
    comphelper::ScopeGuard keyInputFlushTimerStop([this]() { m_aKeyInputFlushTimer.Stop(); });
 
    bool bIsViewReadOnly = IsViewReadonly();
 
    //if the language changes the buffer must be flushed
    LanguageType eNewLanguage = GetInputLanguage();
    if(!bIsViewReadOnly && m_eBufferLanguage != eNewLanguage && !m_aInBuffer.isEmpty())
    {
        FlushInBuffer();
    }
    m_eBufferLanguage = eNewLanguage;
 
    QuickHelpData aTmpQHD;
    if( s_pQuickHlpData->m_bIsDisplayed )
    {
        aTmpQHD.Move( *s_pQuickHlpData );
        s_pQuickHlpData->Stop( rSh );
    }
 
    // OS:the DrawView also needs a readonly-Flag as well
    if ( !bIsViewReadOnly && rSh.GetDrawView() && rSh.GetDrawView()->KeyInput( rKEvt, this ) )
    {
        rSh.GetView().GetViewFrame().GetBindings().InvalidateAll( false );
        rSh.SetModified();
        return; // Event evaluated by SdrView
    }
 
    if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
    {
        StopInsFrame();
        rSh.Edit();
    }
 
    bool bFlushBuffer = false;
    bool bNormalChar = false;
    bool bAppendSpace = s_pQuickHlpData->m_bAppendSpace;
    s_pQuickHlpData->m_bAppendSpace = false;
 
    if (nKey == KEY_F12 && getenv("SW_DEBUG"))
    {
        if( rKEvt.GetKeyCode().IsShift())
        {
            GetView().GetDocShell()->GetDoc()->dumpAsXml();
        }
        else
        {
            SwRootFrame* pLayout = GetView().GetDocShell()->GetWrtShell()->GetLayout();
            pLayout->dumpAsXml( );
        }
        return;
    }
 
    KeyEvent aKeyEvent( rKEvt );
    // look for vertical mappings
    if( !bIsViewReadOnly && !rSh.IsSelFrameMode() && !rSh.IsObjSelected() )
    {
        if( KEY_UP == nKey || KEY_DOWN == nKey ||
            KEY_LEFT == nKey || KEY_RIGHT == nKey )
        {
            // In general, we want to map the direction keys if we are inside
            // some vertical formatted text.
            // 1. Exception: For a table cursor in a horizontal table, the
            //               directions should never be mapped.
            // 2. Exception: For a table cursor in a vertical table, the
            //               directions should always be mapped.
            const bool bVertText = rSh.IsInVerticalText();
            const bool bTableCursor = rSh.GetTableCursor();
            const bool bVertTable = rSh.IsTableVertical();
            if( ( bVertText && ( !bTableCursor || bVertTable ) ) ||
                ( bTableCursor && bVertTable ) )
            {
                SvxFrameDirection eDirection = rSh.GetTextDirection();
                if (eDirection == SvxFrameDirection::Vertical_LR_BT)
                {
                    // Map from physical to logical, so rotate clockwise.
                    if (KEY_UP == nKey)
                        nKey = KEY_RIGHT;
                    else if (KEY_DOWN == nKey)
                        nKey = KEY_LEFT;
                    else if (KEY_LEFT == nKey)
                        nKey = KEY_UP;
                    else /* KEY_RIGHT == nKey */
                        nKey = KEY_DOWN;
                }
                else
                {
                    // Attempt to integrate cursor travelling for mongolian layout does not work.
                    // Thus, back to previous mapping of cursor keys to direction keys.
                    if( KEY_UP == nKey ) nKey = KEY_LEFT;
                    else if( KEY_DOWN == nKey ) nKey = KEY_RIGHT;
                    else if( KEY_LEFT == nKey ) nKey = KEY_DOWN;
                    else /* KEY_RIGHT == nKey */ nKey = KEY_UP;
                }
            }
 
            if ( rSh.IsInRightToLeftText() )
            {
                if( KEY_LEFT == nKey ) nKey = KEY_RIGHT;
                else if( KEY_RIGHT == nKey ) nKey = KEY_LEFT;
            }
 
            aKeyEvent = KeyEvent( rKEvt.GetCharCode(),
                                  vcl::KeyCode( nKey, rKEvt.GetKeyCode().GetModifier() ),
                                  rKEvt.GetRepeat() );
        }
    }
 
    const vcl::KeyCode& rKeyCode = aKeyEvent.GetKeyCode();
    sal_Unicode aCh = aKeyEvent.GetCharCode();
 
    // enable switching to notes anchor with Ctrl - Alt - Page Up/Down
    // pressing this inside a note will switch to next/previous note
    if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((rKeyCode.GetCode() == KEY_PAGEUP) || (rKeyCode.GetCode() == KEY_PAGEDOWN)))
    {
        const bool bNext = rKeyCode.GetCode()==KEY_PAGEDOWN;
        const SwFieldType* pFieldType = rSh.GetFieldType( 0, SwFieldIds::Postit );
        rSh.MoveFieldType( pFieldType, bNext );
        return;
    }
 
    if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
    {
        // Check if this combination of rKeyCode and pTextContentControl should open a popup.
        const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
        std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
        if (pContentControl->ShouldOpenPopup(rKeyCode))
        {
            SwShellCursor* pCursor = rSh.GetCursor_();
            if (pCursor)
            {
                VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton();
                if (pContentControlButton)
                {
                    pContentControlButton->StartPopup();
                    return;
                }
            }
        }
    }
 
    const SwFrameFormat* pFlyFormat = rSh.GetFlyFrameFormat();
 
    if (pFlyFormat)
    {
        // See if the fly frame's anchor is in a content control. If so,
        // try to interact with it.
        const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
        SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
        if (pAnchorNode)
        {
            SwTextNode* pTextNode = pAnchorNode->GetTextNode();
            if (pTextNode)
            {
                sal_Int32 nContentIdx = rFormatAnchor.GetAnchorContentOffset();
                SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
                    nContentIdx, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
                if (pAttr)
                {
                    SwTextContentControl* pTextContentControl
                        = static_txtattr_cast<SwTextContentControl*>(pAttr);
                    const SwFormatContentControl& rFormatContentControl
                        = pTextContentControl->GetContentControl();
                    std::shared_ptr<SwContentControl> pContentControl
                        = rFormatContentControl.GetContentControl();
                    if (pContentControl->IsInteractingCharacter(aCh))
                    {
                        rSh.GotoContentControl(rFormatContentControl);
                        return;
                    }
                }
            }
        }
    }
 
    if( pFlyFormat )
    {
        SvMacroItemId nEvent;
 
        if( 32 <= aCh &&
            0 == (( KEY_MOD1 | KEY_MOD2 ) & rKeyCode.GetModifier() ))
            nEvent = SvMacroItemId::SwFrmKeyInputAlpha;
        else
            nEvent = SvMacroItemId::SwFrmKeyInputNoAlpha;
 
        const SvxMacro* pMacro = pFlyFormat->GetMacro().GetMacroTable().Get( nEvent );
        if( pMacro )
        {
            SbxArrayRef xArgs = new SbxArray;
            SbxVariableRef xVar = new SbxVariable;
            xVar->PutString( pFlyFormat->GetName() );
            xArgs->Put(xVar.get(), 1);
 
            xVar = new SbxVariable;
            if( SvMacroItemId::SwFrmKeyInputAlpha == nEvent )
                xVar->PutChar( aCh );
            else
                xVar->PutUShort( rKeyCode.GetModifier() | rKeyCode.GetCode() );
            xArgs->Put(xVar.get(), 2);
 
            OUString sRet;
            rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
            if( !sRet.isEmpty() && sRet.toInt32()!=0 )
                return ;
        }
    }
    SelectionType nLclSelectionType;
    //A is converted to 1
    if( rKeyCode.GetFullCode() == (KEY_A | KEY_MOD1 |KEY_SHIFT)
        && rSh.HasDrawView() &&
        (bool(nLclSelectionType = rSh.GetSelectionType()) &&
        ((nLclSelectionType & (SelectionType::Frame|SelectionType::Graphic)) ||
        ((nLclSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1))))
    {
        SdrHdlList& rHdlList = const_cast<SdrHdlList&>(rSh.GetDrawView()->GetHdlList());
        SdrHdl* pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor);
        if ( ! pAnchor )
            pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor_TR);
        if(pAnchor)
            rHdlList.SetFocusHdl(pAnchor);
        return;
    }
 
    SvxAutoCorrCfg* pACfg = nullptr;
    SvxAutoCorrect* pACorr = nullptr;
 
    uno::Reference< frame::XDispatchRecorder > xRecorder =
            m_rView.GetViewFrame().GetBindings().GetRecorder();
    if ( !xRecorder.is() )
    {
        pACfg = &SvxAutoCorrCfg::Get();
        pACorr = pACfg->GetAutoCorrect();
    }
 
    SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig();
 
    OUString sFormulaEntry;
 
    enum class SwKeyState { CheckKey, InsChar, InsTab,
                       NoNum, NumOff, NumOrNoNum, NumDown, NumUp,
                       NumIndentInc, NumIndentDec,
 
                       OutlineLvOff,
                       NextCell, PrevCell, OutlineUp, OutlineDown,
                       GlossaryExpand, NextPrevGlossary,
                       AutoFormatByInput,
                       NextObject, PrevObject,
                       KeyToView,
                       LaunchOLEObject, GoIntoFly, GoIntoDrawing,
                       EnterDrawHandleMode,
                       CheckDocReadOnlyKeys,
                       CheckAutoCorrect, EditFormula,
                       ColLeftBig, ColRightBig,
                       ColLeftSmall, ColRightSmall,
                       ColBottomBig,
                       ColBottomSmall,
                       CellLeftBig, CellRightBig,
                       CellLeftSmall, CellRightSmall,
                       CellTopBig, CellBottomBig,
                       CellTopSmall, CellBottomSmall,
 
                       Fly_Change, Draw_Change,
                       SpecialInsert,
                       EnterCharCell,
                       GotoNextFieldMark,
                       GotoPrevFieldMark,
                       End };
 
    SwKeyState eKeyState = bIsViewReadOnly ? SwKeyState::CheckDocReadOnlyKeys : SwKeyState::CheckKey;
 
    // tdf#112932 Pressing enter in read-only Table of Content doesn't jump to heading
    if (!bIsViewReadOnly
        && ((rKeyCode.GetModifier() | rKeyCode.GetCode()) == KEY_RETURN
            || (rKeyCode.GetModifier() | rKeyCode.GetCode()) == (KEY_MOD1 | KEY_RETURN)))
    {
        const SwTOXBase* pTOXBase = rSh.GetCurTOX();
        if (pTOXBase && SwEditShell::IsTOXBaseReadonly(*pTOXBase))
            eKeyState = SwKeyState::CheckDocReadOnlyKeys;
    }
 
    SwKeyState eNextKeyState = SwKeyState::End;
    sal_uInt8 nDir = 0;
 
    if (m_nKS_NUMDOWN_Count > 0)
        m_nKS_NUMDOWN_Count--;
 
    if (m_nKS_NUMINDENTINC_Count > 0)
        m_nKS_NUMINDENTINC_Count--;
 
    while( SwKeyState::End != eKeyState )
    {
        SwKeyState eFlyState = SwKeyState::KeyToView;
 
        switch( eKeyState )
        {
        case SwKeyState::CheckKey:
            eKeyState = SwKeyState::KeyToView;       // default forward to View
 
            if (!comphelper::LibreOfficeKit::isActive() &&
                !rKeyCode.IsMod2() && '=' == aCh &&
                !rSh.IsTableMode() && rSh.GetTableFormat() &&
                rSh.IsSttPara() &&
                !rSh.HasReadonlySel())
            {
                // at the beginning of the table's cell a '=' ->
                // call EditRow (F2-functionality)
                // [Avoid this for LibreOfficeKit, as the separate input window
                // steals the focus & things go wrong - the user never gets
                // the focus back.]
                rSh.Push();
                if( !rSh.MoveSection( GoCurrSection, fnSectionStart) &&
                    !rSh.IsTableBoxTextFormat() )
                {
                    // is at the beginning of the box
                    eKeyState = SwKeyState::EditFormula;
                    if( rSh.HasMark() )
                        rSh.SwapPam();
                    else
                        rSh.SttSelect();
                    rSh.MoveSection( GoCurrSection, fnSectionEnd );
                    rSh.Pop();
                    rSh.EndSelect();
                    sFormulaEntry = "=";
                }
                else
                    rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
            }
            else
            {
                if( pACorr && aTmpQHD.HasContent() && !rSh.HasSelection() &&
                    !rSh.HasReadonlySel() && !aTmpQHD.m_bIsAutoText &&
                    pACorr->GetSwFlags().nAutoCmpltExpandKey ==
                    (rKeyCode.GetModifier() | rKeyCode.GetCode()) )
                {
                    eKeyState = SwKeyState::GlossaryExpand;
                    break;
                }
 
                switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
                {
                case KEY_RIGHT | KEY_MOD2:
                    eKeyState = SwKeyState::ColRightBig;
                    eFlyState = SwKeyState::Fly_Change;
                    nDir = MOVE_RIGHT_SMALL;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_LEFT | KEY_MOD2:
                    eKeyState = SwKeyState::ColRightSmall;
                    eFlyState = SwKeyState::Fly_Change;
                    nDir = MOVE_LEFT_SMALL;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT:
                    eKeyState = SwKeyState::ColLeftSmall;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_LEFT | KEY_MOD2 | KEY_SHIFT:
                    eKeyState = SwKeyState::ColLeftBig;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_RIGHT | KEY_MOD2 | KEY_MOD1:
                    eKeyState = SwKeyState::CellRightBig;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_LEFT | KEY_MOD2 | KEY_MOD1:
                    eKeyState = SwKeyState::CellRightSmall;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
                    eKeyState = SwKeyState::CellLeftSmall;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_LEFT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
                    eKeyState = SwKeyState::CellLeftBig;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_UP | KEY_MOD2:
                    eKeyState = SwKeyState::ColBottomSmall;
                    eFlyState = SwKeyState::Fly_Change;
                    nDir = MOVE_UP_SMALL;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_DOWN | KEY_MOD2:
                    eKeyState = SwKeyState::ColBottomBig;
                    eFlyState = SwKeyState::Fly_Change;
                    nDir = MOVE_DOWN_SMALL;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_UP | KEY_MOD2 | KEY_MOD1:
                    eKeyState = SwKeyState::CellBottomSmall;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_DOWN | KEY_MOD2 | KEY_MOD1:
                    eKeyState = SwKeyState::CellBottomBig;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_UP | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
                    eKeyState = SwKeyState::CellTopBig;
                    goto KEYINPUT_CHECKTABLE;
 
                case KEY_DOWN | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
                    eKeyState = SwKeyState::CellTopSmall;
                    goto KEYINPUT_CHECKTABLE;
 
KEYINPUT_CHECKTABLE:
                    // Resolve bugs 49091, 53190, 93402 and
                    // https://bz.apache.org/ooo/show_bug.cgi?id=113502
                    // but provide an option for restoring interactive
                    // table sizing functionality when needed.
                    if (
                      ! (Window::GetIndicatorState() & KeyIndicatorState::CAPSLOCK)
                      && m_rView.KeyInput( aKeyEvent ) // Keystroke is customized
                    )
                    {
                        bFlushBuffer = true;
                        bNormalChar = false;
                        eKeyState = SwKeyState::End;
                        break ;
                    }
 
                    if( rSh.IsTableMode() || !rSh.GetTableFormat() )
                    {
                        if(!pFlyFormat && SwKeyState::KeyToView != eFlyState &&
                            (rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm))  &&
                                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
                            eKeyState = SwKeyState::Draw_Change;
 
                        if( pFlyFormat )
                            eKeyState = eFlyState;
                        else if( SwKeyState::Draw_Change != eKeyState)
                            eKeyState = SwKeyState::EnterCharCell;
                    }
                    break;
 
                // huge object move
                case KEY_RIGHT | KEY_SHIFT:
                case KEY_LEFT | KEY_SHIFT:
                case KEY_UP | KEY_SHIFT:
                case KEY_DOWN | KEY_SHIFT:
                {
                    const SelectionType nSelectionType = rSh.GetSelectionType();
                    if ( ( pFlyFormat
                           && ( nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic) ) )
                         || ( ( nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm) )
                              && rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 ) )
                    {
                        eKeyState = pFlyFormat ? SwKeyState::Fly_Change : SwKeyState::Draw_Change;
                        if (nSelectionType & SelectionType::DrawObject)
                        {
                            // tdf#137964: always move the DrawObject if one is selected
                            eKeyState = SwKeyState::Draw_Change;
                        }
                        switch ( rKeyCode.GetCode() )
                        {
                            case KEY_RIGHT: nDir = MOVE_RIGHT_HUGE; break;
                            case KEY_LEFT: nDir = MOVE_LEFT_HUGE; break;
                            case KEY_UP: nDir = MOVE_UP_HUGE; break;
                            case KEY_DOWN: nDir = MOVE_DOWN_HUGE; break;
                        }
                    }
                    break;
                }
 
                case KEY_LEFT:
                case KEY_LEFT | KEY_MOD1:
                {
                    bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
                    if(!bMod1)
                    {
                        eFlyState = SwKeyState::Fly_Change;
                        nDir = MOVE_LEFT_BIG;
                    }
                    goto KEYINPUT_CHECKTABLE_INSDEL;
                }
                case KEY_RIGHT | KEY_MOD1:
                {
                    goto KEYINPUT_CHECKTABLE_INSDEL;
                }
                case KEY_UP:
                case KEY_UP | KEY_MOD1:
                {
                    bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
                    if(!bMod1)
                    {
                        eFlyState = SwKeyState::Fly_Change;
                        nDir = MOVE_UP_BIG;
                    }
                    goto KEYINPUT_CHECKTABLE_INSDEL;
                }
                case KEY_DOWN:
                case KEY_DOWN | KEY_MOD1:
                {
                    bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
                    if(!bMod1)
                    {
                        ::sw::mark::Fieldmark* pMark = rSh.GetCurrentFieldmark();
                        if (auto pDropDown = dynamic_cast<FieldmarkWithDropDownButton*>(pMark))
                        {
                            pDropDown->LaunchPopup();
                            eKeyState = SwKeyState::End;
                            break;
                        }
                        eFlyState = SwKeyState::Fly_Change;
                        nDir = MOVE_DOWN_BIG;
                    }
                    goto KEYINPUT_CHECKTABLE_INSDEL;
                }
 
KEYINPUT_CHECKTABLE_INSDEL:
                if( rSh.IsTableMode() || !rSh.GetTableFormat() )
                {
                    const SelectionType nSelectionType = rSh.GetSelectionType();
 
                    eKeyState = SwKeyState::KeyToView;
                    if(SwKeyState::KeyToView != eFlyState)
                    {
                        if((nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm))  &&
                                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
                            eKeyState = SwKeyState::Draw_Change;
                        else if(nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic))
                            eKeyState = SwKeyState::Fly_Change;
                    }
                }
                break;
 
 
                case KEY_DELETE:
                    if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
                    {
                        if (rSh.IsInFrontOfLabel() && rSh.NumOrNoNum())
                            eKeyState = SwKeyState::NumOrNoNum;
                    }
                    else if (!rSh.IsCursorInParagraphMetadataField())
                    {
                        rSh.InfoReadOnlyDialog(/*bAsync=*/true);
                        eKeyState = SwKeyState::End;
                    }
                    break;
 
                case KEY_RETURN:
                {
                    if ( !rSh.HasReadonlySel()
                         && !rSh.CursorInsideInputField()
                         && !rSh.CursorInsideContentControl() )
                    {
                        const SelectionType nSelectionType = rSh.GetSelectionType();
                        if(nSelectionType & SelectionType::Ole)
                            eKeyState = SwKeyState::LaunchOLEObject;
                        else if(nSelectionType & SelectionType::Frame)
                            eKeyState = SwKeyState::GoIntoFly;
                        else if((nSelectionType & SelectionType::DrawObject) &&
                                !(nSelectionType & SelectionType::DrawObjectEditMode) &&
                                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1)
                        {
                            eKeyState = SwKeyState::GoIntoDrawing;
                            if (lcl_goIntoTextBox(*this, rSh))
                                eKeyState = SwKeyState::GoIntoFly;
                        }
                        else if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
                            aTmpQHD.m_bIsAutoText )
                            eKeyState = SwKeyState::GlossaryExpand;
 
                        //RETURN and empty paragraph in numbering -> end numbering
                        else if( m_aInBuffer.isEmpty() &&
                                 rSh.GetNumRuleAtCurrCursorPos() &&
                                 !rSh.GetNumRuleAtCurrCursorPos()->IsOutlineRule() &&
                                 !rSh.HasSelection() &&
                                rSh.IsSttPara() && rSh.IsEndPara() )
                        {
                            eKeyState = SwKeyState::NumOff;
                            eNextKeyState = SwKeyState::OutlineLvOff;
                        }
                        //RETURN for new paragraph with AutoFormatting
                        else if( pACfg && pACfg->IsAutoFormatByInput() &&
                                !(nSelectionType & (SelectionType::Graphic |
                                    SelectionType::Ole | SelectionType::Frame |
                                    SelectionType::TableCell | SelectionType::DrawObject |
                                    SelectionType::DrawObjectEditMode)) )
                        {
                            eKeyState = SwKeyState::AutoFormatByInput;
                        }
                        else
                        {
                            eNextKeyState = eKeyState;
                            eKeyState = SwKeyState::CheckAutoCorrect;
                        }
                    }
                }
                break;
                case KEY_RETURN | KEY_MOD2:
                {
                    if ( !rSh.HasReadonlySel()
                         && !rSh.IsSttPara()
                         && rSh.GetNumRuleAtCurrCursorPos()
                         && !rSh.CursorInsideInputField() )
                    {
                        eKeyState = SwKeyState::NoNum;
                    }
                    else if( rSh.CanSpecialInsert() )
                        eKeyState = SwKeyState::SpecialInsert;
                }
                break;
                case KEY_BACKSPACE:
                case KEY_BACKSPACE | KEY_SHIFT:
                    if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
                    {
                        bool bDone = false;
                        // try to add comment for code snip:
                        // Remove the paragraph indent, if the cursor is at the
                        // beginning of a paragraph, there is no selection
                        // and no numbering rule found at the current paragraph
                        // Also try to remove indent, if current paragraph
                        // has numbering rule, but isn't counted and only
                        // key <backspace> is hit.
                        const bool bOnlyBackspaceKey( KEY_BACKSPACE == rKeyCode.GetFullCode() );
                        if ( rSh.IsSttPara()
                             && !rSh.HasSelection()
                             && ( rSh.GetNumRuleAtCurrCursorPos() == nullptr
                                  || ( rSh.IsNoNum() && bOnlyBackspaceKey ) ) )
                        {
                            bDone = rSh.TryRemoveIndent();
                        }
 
                        if (bDone)
                            eKeyState = SwKeyState::End;
                        else
                        {
                            if ( rSh.IsSttPara() && !rSh.IsNoNum() )
                            {
                                if (m_nKS_NUMDOWN_Count > 0 &&
                                    0 < rSh.GetNumLevel())
                                {
                                    eKeyState = SwKeyState::NumUp;
                                    m_nKS_NUMDOWN_Count = 2;
                                    bDone = true;
                                }
                                else if (m_nKS_NUMINDENTINC_Count > 0)
                                {
                                    eKeyState = SwKeyState::NumIndentDec;
                                    m_nKS_NUMINDENTINC_Count = 2;
                                    bDone = true;
                                }
                            }
 
                            // If the cursor is in an empty paragraph, which has
                            // a numbering, but not the outline numbering, and
                            // there is no selection, the numbering has to be
                            // deleted on key <Backspace>.
                            // Otherwise method <SwEditShell::NumOrNoNum(..)>
                            // should only change the <IsCounted()> state of
                            // the current paragraph depending of the key.
                            // On <backspace> it is set to <false>,
                            // on <shift-backspace> it is set to <true>.
                            // Thus, assure that method <SwEditShell::NumOrNum(..)>
                            // is only called for the intended purpose.
                            if ( !bDone && rSh.IsSttPara() )
                            {
                                bool bCallNumOrNoNum( false );
                                if ( bOnlyBackspaceKey && !rSh.IsNoNum() )
                                {
                                    bCallNumOrNoNum = true;
                                }
                                else if ( !bOnlyBackspaceKey && rSh.IsNoNum() )
                                {
                                    bCallNumOrNoNum = true;
                                }
                                else if ( bOnlyBackspaceKey
                                          && rSh.IsSttPara()
                                          && rSh.IsEndPara()
                                          && !rSh.HasSelection() )
                                {
                                    const SwNumRule* pCurrNumRule( rSh.GetNumRuleAtCurrCursorPos() );
                                    if ( pCurrNumRule != nullptr
                                         && pCurrNumRule != rSh.GetOutlineNumRule() )
                                    {
                                        bCallNumOrNoNum = true;
                                    }
                                }
                                if ( bCallNumOrNoNum
                                     && rSh.NumOrNoNum( !bOnlyBackspaceKey ) )
                                {
                                    eKeyState = SwKeyState::NumOrNoNum;
                                }
                            }
                        }
                    }
                    else if (!rSh.IsCursorInParagraphMetadataField())
                    {
                        rSh.InfoReadOnlyDialog(false);
                        eKeyState = SwKeyState::End;
                    }
                    break;
 
                case KEY_RIGHT:
                    {
                        eFlyState = SwKeyState::Fly_Change;
                        nDir = MOVE_RIGHT_BIG;
                        goto KEYINPUT_CHECKTABLE_INSDEL;
                    }
                case KEY_TAB:
                {
                    // Rich text contentControls accept tabs and fieldmarks and other rich text,
                    // so first act on cases that are not a content control
                    SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
                    if ((rSh.IsFormProtected() && !pTextContentControl) ||
                        rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
                    {
                        eKeyState = SwKeyState::GotoNextFieldMark;
                    }
                    else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
                    {
                        GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_NEXT_INPUTFLD );
                        eKeyState = SwKeyState::End;
                    }
                    else if( rSh.GetNumRuleAtCurrCursorPos()
                             && rSh.IsSttOfPara()
                             && !rSh.HasReadonlySel() )
                    {
                        if (numfunc::NumDownChangesIndent(rSh))
                        {
                            eKeyState = SwKeyState::NumDown;
                        }
                        else
                        {
                            eKeyState = SwKeyState::InsTab;
                        }
                    }
                    else if (rSh.GetSelectionType() &
                             (SelectionType::Graphic |
                              SelectionType::Frame |
                              SelectionType::Ole |
                              SelectionType::DrawObject |
                              SelectionType::DbForm))
                    {
                        eKeyState = SwKeyState::NextObject;
                    }
                    else if ( rSh.GetTableFormat() )
                    {
                        if( rSh.HasSelection() || rSh.HasReadonlySel() )
                            eKeyState = SwKeyState::NextCell;
                        else
                        {
                            eKeyState = SwKeyState::CheckAutoCorrect;
                            eNextKeyState = SwKeyState::NextCell;
                        }
                    }
                    else if (pTextContentControl)
                    {
                        auto pCC = pTextContentControl->GetContentControl().GetContentControl();
                        if (pCC)
                        {
                            switch (pCC->GetType())
                            {
                                case SwContentControlType::RICH_TEXT:
                                    eKeyState = SwKeyState::InsTab;
                                    break;
                                default:
                                    eKeyState = SwKeyState::GotoNextFieldMark;
                            }
                        }
                    }
                    else
                    {
                        eKeyState = SwKeyState::InsTab;
                        if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
                        {
                            SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
                            if( pColl &&
 
                                pColl->IsAssignedToListLevelOfOutlineStyle()
                                && MAXLEVEL-1 > pColl->GetAssignedOutlineStyleLevel() )
                                eKeyState = SwKeyState::OutlineDown;
                        }
                    }
                }
                break;
                case KEY_TAB | KEY_SHIFT:
                {
                    SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
                    if ((rSh.IsFormProtected() && !pTextContentControl) ||
                        rSh.GetCurrentFieldmark()|| rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
                    {
                        eKeyState = SwKeyState::GotoPrevFieldMark;
                    }
                    else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
                    {
                        GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_PREV_INPUTFLD );
                        eKeyState = SwKeyState::End;
                    }
                    else if( rSh.GetNumRuleAtCurrCursorPos()
                             && rSh.IsSttOfPara()
                             && !rSh.HasReadonlySel() )
                    {
                        eKeyState = SwKeyState::NumUp;
                    }
                    else if (rSh.GetSelectionType() &
                             (SelectionType::Graphic |
                              SelectionType::Frame |
                              SelectionType::Ole |
                              SelectionType::DrawObject |
                              SelectionType::DbForm))
                    {
                        eKeyState = SwKeyState::PrevObject;
                    }
                    else if ( rSh.GetTableFormat() )
                    {
                        if( rSh.HasSelection() || rSh.HasReadonlySel() )
                            eKeyState = SwKeyState::PrevCell;
                        else
                        {
                            eKeyState = SwKeyState::CheckAutoCorrect;
                            eNextKeyState = SwKeyState::PrevCell;
                        }
                    }
                    else if (pTextContentControl)
                    {
                        eKeyState = SwKeyState::GotoPrevFieldMark;
                    }
                    else
                    {
                        eKeyState = SwKeyState::End;
                        if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
                        {
                            SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
                            if( pColl &&
                                pColl->IsAssignedToListLevelOfOutlineStyle() &&
                                0 < pColl->GetAssignedOutlineStyleLevel())
                                eKeyState = SwKeyState::OutlineUp;
                        }
                    }
                }
                break;
                case KEY_TAB | KEY_MOD1:
                case KEY_TAB | KEY_MOD2:
                    if( !rSh.HasReadonlySel() )
                    {
                        if( aTmpQHD.HasContent() && !rSh.HasSelection() )
                        {
                            // Next auto-complete suggestion
                            aTmpQHD.Next( pACorr &&
                                          pACorr->GetSwFlags().bAutoCmpltEndless );
                            eKeyState = SwKeyState::NextPrevGlossary;
                        }
                        else if( rSh.GetTableFormat() )
                            eKeyState = SwKeyState::InsTab;
                        else if((rSh.GetSelectionType() &
                                    (SelectionType::DrawObject|SelectionType::DbForm|
                                        SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic))  &&
                                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
                            eKeyState = SwKeyState::EnterDrawHandleMode;
                        else
                        {
                            if ( !rSh.IsMultiSelection()
                                && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
                                eKeyState = SwKeyState::NumIndentInc;
                        }
                    }
                    break;
 
                    case KEY_TAB | KEY_MOD1 | KEY_SHIFT:
                    {
                        if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
                            !rSh.HasReadonlySel() )
                        {
                            // Previous auto-complete suggestion.
                            aTmpQHD.Previous( pACorr &&
                                              pACorr->GetSwFlags().bAutoCmpltEndless );
                            eKeyState = SwKeyState::NextPrevGlossary;
                        }
                        else if((rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm|
                                        SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic)) &&
                                rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
                        {
                            eKeyState = SwKeyState::EnterDrawHandleMode;
                        }
                        else
                        {
                            if ( !rSh.IsMultiSelection()
                                && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
                                eKeyState = SwKeyState::NumIndentDec;
                        }
                    }
                    break;
                    case KEY_F2 :
                    if( !rSh.HasReadonlySel() )
                    {
                        const SelectionType nSelectionType = rSh.GetSelectionType();
                        if(nSelectionType & SelectionType::Frame)
                            eKeyState = SwKeyState::GoIntoFly;
                        else if(nSelectionType & SelectionType::DrawObject)
                        {
                            eKeyState = SwKeyState::GoIntoDrawing;
                            if (lcl_goIntoTextBox(*this, rSh))
                                eKeyState = SwKeyState::GoIntoFly;
                        }
                    }
                    break;
                }
            }
            break;
        case SwKeyState::CheckDocReadOnlyKeys:
            {
                eKeyState = SwKeyState::KeyToView;
                switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
                {
                    case KEY_TAB:
                    case KEY_TAB | KEY_SHIFT:
                        bNormalChar = false;
                        eKeyState = SwKeyState::End;
                        if ( rSh.GetSelectionType() &
                                (SelectionType::Graphic |
                                    SelectionType::Frame |
                                    SelectionType::Ole |
                                    SelectionType::DrawObject |
                                    SelectionType::DbForm))
 
                        {
                            eKeyState = (rKeyCode.GetModifier() & KEY_SHIFT) ?
                                                SwKeyState::PrevObject : SwKeyState::NextObject;
                        }
                        else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
                        {
                            GetView().GetViewFrame().GetDispatcher()->Execute(
                                KEY_SHIFT != rKeyCode.GetModifier() ? FN_GOTO_NEXT_INPUTFLD : FN_GOTO_PREV_INPUTFLD );
                        }
                        else
                        {
                            rSh.SelectNextPrevHyperlink( KEY_SHIFT != rKeyCode.GetModifier() );
                        }
                    break;
                    case KEY_RETURN:
                    case KEY_RETURN | KEY_MOD1:
                    {
                        const SelectionType nSelectionType = rSh.GetSelectionType();
                        if(nSelectionType & SelectionType::Frame)
                            eKeyState = SwKeyState::GoIntoFly;
                        else
                        {
                            SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT> aSet(rSh.GetAttrPool());
                            rSh.GetCurAttr(aSet);
                            if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false))
                            {
                                const SfxPoolItem& rItem = aSet.Get(RES_TXTATR_INETFMT);
                                bNormalChar = false;
                                eKeyState = SwKeyState::End;
                                rSh.ClickToINetAttr(static_cast<const SwFormatINetFormat&>(rItem));
                            }
                        }
                    }
                    break;
                }
            }
            break;
 
        case SwKeyState::EnterCharCell:
            {
                eKeyState = SwKeyState::KeyToView;
                switch ( rKeyCode.GetModifier() | rKeyCode.GetCode() )
                {
                    case KEY_RIGHT | KEY_MOD2:
                        rSh.Right( SwCursorSkipMode::Chars, false, 1, false );
                        eKeyState = SwKeyState::End;
                        FlushInBuffer();
                        break;
                    case KEY_LEFT | KEY_MOD2:
                        rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
                        eKeyState = SwKeyState::End;
                        FlushInBuffer();
                        break;
                }
            }
            break;
 
        case SwKeyState::KeyToView:
            {
                eKeyState = SwKeyState::End;
                bNormalChar =
                    !rKeyCode.IsMod2() &&
                    rKeyCode.GetModifier() != KEY_MOD1 &&
                    rKeyCode.GetModifier() != (KEY_MOD1|KEY_SHIFT) &&
                    SW_ISPRINTABLE( aCh );
 
                if( bNormalChar && rSh.IsInFrontOfLabel() )
                {
                    rSh.NumOrNoNum();
                }
 
                if( !m_aInBuffer.isEmpty() && ( !bNormalChar || bIsViewReadOnly ))
                    FlushInBuffer();
 
                if (rSh.HasReadonlySel()
                    && (   rKeyCode.GetFunction() == KeyFuncType::PASTE
                        || rKeyCode.GetFunction() == KeyFuncType::CUT))
                {
                    rSh.InfoReadOnlyDialog(true);
                    eKeyState = SwKeyState::End;
                }
                else if( m_rView.KeyInput( aKeyEvent ) )
                {
                    bFlushBuffer = true;
                    bNormalChar = false;
                }
                else
                {
                    // Because Sfx accelerators are only called when they were
                    // enabled at the last status update, copy has to called
                    // 'forcefully' by us if necessary.
                    if( rKeyCode.GetFunction() == KeyFuncType::COPY )
                        GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
 
                    if( !bIsViewReadOnly && bNormalChar )
                    {
                        const SelectionType nSelectionType = rSh.GetSelectionType();
                        const bool bDrawObject = (nSelectionType & SelectionType::DrawObject) &&
                            !(nSelectionType & SelectionType::DrawObjectEditMode) &&
                            rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1;
 
                        bool bTextBox = false;
                        if (bDrawObject && lcl_goIntoTextBox(*this, rSh))
                            // A draw shape was selected, but it has a TextBox,
                            // start editing that instead when the normal
                            // character is pressed.
                            bTextBox = true;
 
                        if (bDrawObject && !bTextBox)
                        {
                            SdrObject* pObj = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
                            if(pObj)
                            {
                                EnterDrawTextMode(pObj->GetLogicRect().Center());
                                if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
                                    pSwDrawTextShell->Init();
                                rSh.GetDrawView()->KeyInput( rKEvt, this );
                            }
                        }
                        else if (nSelectionType & SelectionType::Frame || bTextBox)
                        {
                            rSh.UnSelectFrame();
                            rSh.LeaveSelFrameMode();
                            m_rView.AttrChangedNotify(nullptr);
                            rSh.MoveSection( GoCurrSection, fnSectionEnd );
                        }
                        eKeyState = SwKeyState::InsChar;
                    }
                    else
                    {
                        bNormalChar = false;
                        Window::KeyInput( aKeyEvent );
                    }
                }
            }
            break;
        case SwKeyState::LaunchOLEObject:
        {
            rSh.LaunchOLEObj();
            eKeyState = SwKeyState::End;
        }
        break;
        case SwKeyState::GoIntoFly:
        {
            rSh.UnSelectFrame();
            rSh.LeaveSelFrameMode();
            m_rView.AttrChangedNotify(nullptr);
            rSh.MoveSection( GoCurrSection, fnSectionEnd );
            eKeyState = SwKeyState::End;
        }
        break;
        case SwKeyState::GoIntoDrawing:
        {
            if (SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0))
            {
                SdrObject* pObj = pMark->GetMarkedSdrObj();
                if(pObj)
                {
                    EnterDrawTextMode(pObj->GetLogicRect().Center());
                    if (auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
                        pSwDrawTextShell->Init();
                }
            }
            eKeyState = SwKeyState::End;
        }
        break;
        case SwKeyState::EnterDrawHandleMode:
        {
            const SdrHdlList& rHdlList = rSh.GetDrawView()->GetHdlList();
            bool bForward(!aKeyEvent.GetKeyCode().IsShift());
 
            const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
            eKeyState = SwKeyState::End;
        }
        break;
        case SwKeyState::InsTab:
            if( dynamic_cast<const SwWebView*>( &m_rView) !=  nullptr)     // no Tab for WebView
            {
                // then it should be passed along
                Window::KeyInput( aKeyEvent );
                eKeyState = SwKeyState::End;
                break;
            }
            aCh = '\t';
            [[fallthrough]];
        case SwKeyState::InsChar:
        {
            if (rSh.CursorInsideContentControl())
            {
                const SwPosition* pStart = rSh.GetCursor()->Start();
                SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
                if (pTextNode)
                {
                    sal_Int32 nIndex = pStart->GetContentIndex();
                    SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
                    if (pAttr)
                    {
                        auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
                        const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
                        std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
                        if (pContentControl->IsInteractingCharacter(aCh))
                        {
                            rSh.GotoContentControl(rFormatContentControl);
                            eKeyState = SwKeyState::End;
                            break;
                        }
                    }
                }
            }
 
            if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
            {
                ::sw::mark::CheckboxFieldmark* pFieldmark =
                    dynamic_cast< ::sw::mark::CheckboxFieldmark* >
                        (rSh.GetCurrentFieldmark());
                OSL_ENSURE(pFieldmark,
                    "Where is my FieldMark??");
                if(pFieldmark)
                {
                    pFieldmark->SetChecked(!pFieldmark->IsChecked());
                    OSL_ENSURE(pFieldmark->IsExpanded(),
                        "where is the otherpos?");
                    if (pFieldmark->IsExpanded())
                    {
                        rSh.CalcLayout();
                    }
                }
                eKeyState = SwKeyState::End;
            }
            else if ( !rSh.HasReadonlySel()
                      || rSh.CursorInsideInputField() )
            {
                const bool bIsNormalChar =
                    GetAppCharClass().isLetterNumeric( OUString( aCh ), 0 );
                if( bAppendSpace && bIsNormalChar &&
                    (!m_aInBuffer.isEmpty() || !rSh.IsSttPara() || !rSh.IsEndPara() ))
                {
                    // insert a blank ahead of the character. this ends up
                    // between the expanded text and the new "non-word-separator".
                    m_aInBuffer += " ";
                }
 
                const SwViewOption& rVwOpt = SwViewOption::GetCurrentViewOptions();
                const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar(aCh);
                if (!aKeyEvent.GetRepeat() && rSh.HasSelection()
                    && rVwOpt.IsEncloseWithCharactersOn()
                    && SwViewOption::IsEncloseWithCharactersTrigger(aCh))
                {
                    FlushInBuffer();
                    switch (aCh)
                    {
                        case '(':
                            rSh.InsertEnclosingChars(u"(", u")");
                            break;
                        case '[':
                            rSh.InsertEnclosingChars(u"[", u"]");
                            break;
                        case '{':
                            rSh.InsertEnclosingChars(u"{", u"}");
                            break;
                        case '\"':
                        {
                            LanguageType eLang
                                = Application::GetSettings().GetLanguageTag().getLanguageType();
                            OUString sStartQuote{ pACorr->GetQuote('\"', true, eLang) };
                            OUString sEndQuote{ pACorr->GetQuote('\"', false, eLang) };
                            rSh.InsertEnclosingChars(sStartQuote, sEndQuote);
                            break;
                        }
                        case '\'':
                        {
                            LanguageType eLang
                                = Application::GetSettings().GetLanguageTag().getLanguageType();
                            OUString sStartQuote{ pACorr->GetQuote('\'', true, eLang) };
                            OUString sEndQuote{ pACorr->GetQuote('\'', false, eLang) };
                            rSh.InsertEnclosingChars(sStartQuote, sEndQuote);
                            break;
                        }
                    }
                }
                else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
                        pACfg->IsAutoFormatByInput() &&
                    (( pACorr->IsAutoCorrFlag( ACFlags::ChgWeightUnderl ) &&
                        ( '*' == aCh || '_' == aCh ) ) ||
                     ( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
                     ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
                {
                    FlushInBuffer();
                    rSh.AutoCorrect( *pACorr, aCh );
                    if( '\"' != aCh && '\'' != aCh )        // only call when "*_"!
                        rSh.UpdateAttr();
                }
                else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
                        pACfg->IsAutoFormatByInput() &&
                    pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
                                            ACFlags::ChgOrdinalNumber | ACFlags::AddNonBrkSpace |
                                            ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
                                            ACFlags::Autocorrect | ACFlags::TransliterateRTL |
                                            ACFlags::SetDOIAttr ) &&
                    '\"' != aCh && '\'' != aCh && '*' != aCh && '_' != aCh
                    )
                {
                    FlushInBuffer();
                    rSh.AutoCorrect( *pACorr, aCh );
                }
                else
                {
                    OUStringBuffer aBuf(m_aInBuffer);
                    comphelper::string::padToLength(aBuf,
                        m_aInBuffer.getLength() + aKeyEvent.GetRepeat() + 1, aCh);
                    m_aInBuffer = aBuf.makeStringAndClear();
                    bool delayFlush = Application::AnyInput( VclInputFlags::KEYBOARD );
                    bFlushBuffer = !delayFlush;
                    if( delayFlush )
                    {
                        // Start the timer, make sure to not restart it.
                        keyInputFlushTimerStop.dismiss();
                        if( !m_aKeyInputFlushTimer.IsActive())
                            m_aKeyInputFlushTimer.Start();
                    }
                }
                eKeyState = SwKeyState::End;
            }
            else
            {
                rSh.InfoReadOnlyDialog(true);
                eKeyState = SwKeyState::End;
            }
 
            bool bIsSpace = (aCh == ' ');
            if (bIsSpace && pACorr && pACfg)
            {
                // do the formatting only for few starting characters (for "* " or "- " conversion)
                SwPosition aPos(*rSh.GetCursor()->GetPoint());
                if (aPos.nContent < 3)
                {
                    SvxSwAutoFormatFlags& rFlags = pACorr->GetSwFlags();
                    if(pACfg->IsAutoFormatByInput() && rFlags.bSetNumRule && rFlags.bSetNumRuleAfterSpace)
                        rSh.AutoFormat(&rFlags, true);
                }
            }
        }
        break;
 
        case SwKeyState::CheckAutoCorrect:
        {
            if( pACorr && pACfg->IsAutoFormatByInput() &&
                pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
                                        ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
                                        ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
                                        ACFlags::Autocorrect | ACFlags::SetDOIAttr ) &&
                !rSh.HasReadonlySel() )
            {
                FlushInBuffer();
                rSh.AutoCorrect( *pACorr, u'\0' );
            }
            eKeyState = eNextKeyState;
        }
        break;
 
        default:
        {
            sal_uInt16 nSlotId = 0;
            FlushInBuffer();
            switch( eKeyState )
            {
            case SwKeyState::SpecialInsert:
                rSh.DoSpecialInsert();
                break;
 
            case SwKeyState::NoNum:
                rSh.NoNum();
                break;
 
            case SwKeyState::NumOff:
                // shell change - so record in advance
                rSh.DelNumRules();
                break;
            case SwKeyState::OutlineLvOff: // delete autofmt outlinelevel later
                break;
 
            case SwKeyState::NumDown:
                rSh.NumUpDown();
                m_nKS_NUMDOWN_Count = 2;
                break;
            case SwKeyState::NumUp:
                rSh.NumUpDown( false );
                break;
 
            case SwKeyState::NumIndentInc:
                rSh.ChangeIndentOfAllListLevels(360);
                m_nKS_NUMINDENTINC_Count = 2;
                break;
 
            case SwKeyState::GotoNextFieldMark:
                {
                    rSh.GotoFormControl(/*bNext=*/true);
                }
                break;
 
            case SwKeyState::GotoPrevFieldMark:
                {
                    rSh.GotoFormControl(/*bNext=*/false);
                }
                break;
 
            case SwKeyState::NumIndentDec:
                rSh.ChangeIndentOfAllListLevels(-360);
                break;
 
            case SwKeyState::OutlineDown:
                rSh.OutlineUpDown();
                break;
            case SwKeyState::OutlineUp:
                rSh.OutlineUpDown( -1 );
                break;
 
            case SwKeyState::NextCell:
                // always 'flush' in tables
                rSh.GoNextCell(!rSh.HasReadonlySel());
                nSlotId = FN_GOTO_NEXT_CELL;
                break;
            case SwKeyState::PrevCell:
                rSh.GoPrevCell();
                nSlotId = FN_GOTO_PREV_CELL;
                break;
            case SwKeyState::AutoFormatByInput:
                rSh.SplitNode( true );
                break;
 
            case SwKeyState::NextObject:
            case SwKeyState::PrevObject:
                if(rSh.GotoObj( SwKeyState::NextObject == eKeyState, GotoObjFlags::Any))
                {
                    if( rSh.IsFrameSelected() &&
                        m_rView.GetDrawFuncPtr() )
                    {
                        m_rView.GetDrawFuncPtr()->Deactivate();
                        m_rView.SetDrawFuncPtr(nullptr);
                        m_rView.LeaveDrawCreate();
                        m_rView.AttrChangedNotify(nullptr);
                    }
                    rSh.HideCursor();
                    rSh.EnterSelFrameMode();
                }
            break;
            case SwKeyState::GlossaryExpand:
            {
                // replace the word or abbreviation with the auto text
                rSh.StartUndo( SwUndoId::START );
 
                OUString sFnd(aTmpQHD.CurStr());
                if( aTmpQHD.m_bIsAutoText )
                {
                    SwGlossaryList* pList = ::GetGlossaryList();
                    OUString sShrtNm;
                    OUString sGroup;
                    if(pList->GetShortName( sFnd, sShrtNm, sGroup))
                    {
                        rSh.SttSelect();
                        rSh.ExtendSelection(false, aTmpQHD.CurLen());
                        SwGlossaryHdl* pGlosHdl = GetView().GetGlosHdl();
                        pGlosHdl->SetCurGroup(sGroup, true);
                        pGlosHdl->InsertGlossary( sShrtNm);
                        s_pQuickHlpData->m_bAppendSpace = true;
                    }
                }
                else
                {
                    sFnd = sFnd.copy(aTmpQHD.CurLen());
                    rSh.Insert( sFnd );
                    s_pQuickHlpData->m_bAppendSpace = !pACorr ||
                            pACorr->GetSwFlags().bAutoCmpltAppendBlank;
                }
                rSh.EndUndo( SwUndoId::END );
            }
            break;
 
            case SwKeyState::NextPrevGlossary:
                s_pQuickHlpData->Move( aTmpQHD );
                s_pQuickHlpData->Start(rSh, false);
                break;
 
            case SwKeyState::EditFormula:
            {
                const sal_uInt16 nId = SwInputChild::GetChildWindowId();
 
                SfxViewFrame& rVFrame = GetView().GetViewFrame();
                rVFrame.ToggleChildWindow( nId );
                SwInputChild* pChildWin = static_cast<SwInputChild*>(rVFrame.
                                                    GetChildWindow( nId ));
                if( pChildWin )
                    pChildWin->SetFormula( sFormulaEntry );
            }
            break;
 
            case SwKeyState::ColLeftBig:         rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );   break;
            case SwKeyState::ColRightBig:        rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );  break;
            case SwKeyState::ColLeftSmall:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft, pModOpt->GetTableHMove() );   break;
            case SwKeyState::ColRightSmall:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight, pModOpt->GetTableHMove() );  break;
            case SwKeyState::ColBottomBig:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() ); break;
            case SwKeyState::ColBottomSmall:     rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom, pModOpt->GetTableVMove() ); break;
            case SwKeyState::CellLeftBig:        rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );  break;
            case SwKeyState::CellRightBig:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
            case SwKeyState::CellLeftSmall:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft, pModOpt->GetTableHMove() );  break;
            case SwKeyState::CellRightSmall:     rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight, pModOpt->GetTableHMove() ); break;
            case SwKeyState::CellTopBig:         rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() );   break;
            case SwKeyState::CellBottomBig:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() );    break;
            case SwKeyState::CellTopSmall:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop, pModOpt->GetTableVMove() );   break;
            case SwKeyState::CellBottomSmall:    rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom, pModOpt->GetTableVMove() );    break;
 
            case SwKeyState::Fly_Change:
            {
                SdrView *pSdrView = rSh.GetDrawView();
                const SdrHdlList& rHdlList = pSdrView->GetHdlList();
                if(rHdlList.GetFocusHdl())
                    ChangeDrawing( nDir );
                else
                    ChangeFly( nDir, dynamic_cast<const SwWebView*>( &m_rView) !=  nullptr );
            }
            break;
            case SwKeyState::Draw_Change :
                ChangeDrawing( nDir );
                break;
            default:
                break;
            }
            if( nSlotId && m_rView.GetViewFrame().GetBindings().GetRecorder().is() )
            {
                SfxRequest aReq(m_rView.GetViewFrame(), nSlotId);
                aReq.Done();
            }
            eKeyState = SwKeyState::End;
        }
        }
    }
 
    // update the page number in the statusbar
    nKey = rKEvt.GetKeyCode().GetCode();
    if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey )
        GetView().GetViewFrame().GetBindings().Update( FN_STAT_PAGE );
 
    m_bMaybeShowTooltipAfterBufferFlush = bNormalChar;
 
    // in case the buffered characters are inserted
    if( bFlushBuffer && !m_aInBuffer.isEmpty() )
    {
        FlushInBuffer();
    }
 
    // get the word count dialog to update itself
    SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
    if( pWrdCnt )
        pWrdCnt->UpdateCounts();
 
}
 
/**
 * MouseEvents
 */
void SwEditWin::ResetMouseButtonDownFlags()
{
    // Not on all systems a MouseButtonUp is used ahead
    // of the modal dialog (like on WINDOWS).
    // So reset the statuses here and release the mouse
    // for the dialog.
    m_bMBPressed = false;
    g_bNoInterrupt = false;
    EnterArea();
    ReleaseMouse();
}
 
/**
 * Determines if the current position has a clickable url over a background
 * frame. In that case, ctrl-click should select the url, not the frame.
 */
static bool lcl_urlOverBackground(SwWrtShell& rSh, const Point& rDocPos)
{
    SwContentAtPos aSwContentAtPos(IsAttrAtPos::InetAttr);
    SdrObject* pSelectableObj = rSh.GetObjAt(rDocPos);
 
    return rSh.GetContentAtPos(rDocPos, aSwContentAtPos) && pSelectableObj->GetLayer() == rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId();
}
 
void SwEditWin::MoveCursor( SwWrtShell &rSh, const Point& rDocPos,
                            const bool bOnlyText, bool bLockView )
{
    const bool bTmpNoInterrupt = g_bNoInterrupt;
    g_bNoInterrupt = false;
 
    int nTmpSetCursor = 0;
 
    if( !rSh.IsViewLocked() && bLockView )
        rSh.LockView( true );
    else
        bLockView = false;
 
    {
        // only temporary generate move context because otherwise
        // the query to the content form doesn't work!!!
        SwMvContext aMvContext( &rSh );
        nTmpSetCursor = rSh.CallSetCursor(&rDocPos, bOnlyText);
        g_bValidCursorPos = !(CRSR_POSCHG & nTmpSetCursor);
    }
 
    // notify the edit window that from now on we do not use the input language
    if ( !(CRSR_POSOLD & nTmpSetCursor) )
        SetUseInputLanguage( false );
 
    if( bLockView )
        rSh.LockView( false );
 
    g_bNoInterrupt = bTmpNoInterrupt;
}
 
void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
 
    // We have to check if a context menu is shown and we have an UI
    // active inplace client. In that case we have to ignore the mouse
    // button down event. Otherwise we would crash (context menu has been
    // opened by inplace client and we would deactivate the inplace client,
    // the context menu is closed by VCL asynchronously which in the end
    // would work on deleted objects or the context menu has no parent anymore)
    SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
    bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
 
    if (bIsOleActive && vcl::IsInPopupMenuExecute())
        return;
 
    MouseEvent aMEvt(_rMEvt);
 
    if (m_rView.GetPostItMgr()->IsHit(aMEvt.GetPosPixel()))
        return;
 
    if (comphelper::LibreOfficeKit::isActive())
    {
        if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(aMEvt.GetPosPixel()))
        {
            pWindow->MouseButtonDown(aMEvt);
            return;
        }
    }
 
    if (aMEvt.GetButtons() == MOUSE_LEFT && m_rView.GetPostItMgr()->IsHitSidebarDragArea(aMEvt.GetPosPixel()))
    {
        mbIsDragSidebar = true;
        // Capture mouse to keep tracking even if the mouse leaves the document window
        CaptureMouse();
        return;
    }
 
    m_rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
 
    GrabFocus();
    rSh.addCurrentPosition();
 
    //ignore key modifiers for format paintbrush
    {
        bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
                                &&  m_pApplyTempl->m_pFormatClipboard->HasContent();
        if( bExecFormatPaintbrush )
            aMEvt = MouseEvent(_rMEvt.GetPosPixel(), _rMEvt.GetClicks(), _rMEvt.GetMode(),
                               _rMEvt.GetButtons());
    }
 
    m_bWasShdwCursor = nullptr != m_pShadCursor;
    m_pShadCursor.reset();
 
    const Point aDocPos(PixelToLogic(aMEvt.GetPosPixel()));
 
    FrameControlType eControl;
    bool bOverFly = false;
    bool bPageAnchored = false;
    bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
 
    bool bIsViewReadOnly = m_rView.GetDocShell()->IsReadOnly() || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
    if (bOverHeaderFooterFly && (!bIsViewReadOnly && rSh.GetCurField()))
        // We have a field here, that should have priority over header/footer fly.
        bOverHeaderFooterFly = false;
 
    // Are we clicking on a blank header/footer area?
    if ( IsInHeaderFooter( aDocPos, eControl ) || bOverHeaderFooterFly )
    {
        const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( aDocPos );
 
        if ( pPageFrame )
        {
            // Is it active?
            bool bActive = true;
            const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
 
            const SwFrameFormat* pFormat = pDesc->GetLeftFormat();
            if ( pPageFrame->OnRightPage() )
                 pFormat = pDesc->GetRightFormat();
 
            if ( pFormat )
            {
                if ( eControl == FrameControlType::Header )
                    bActive = pFormat->GetHeader().IsActive();
                else
                    bActive = pFormat->GetFooter().IsActive();
            }
 
            if ( !bActive )
            {
                // HeaderFooter menu implies header/footer controls, so only do this with IsUseHeaderFooterMenu enabled.
                // But, additionally, when in Hide-Whitespace mode, we don't want those controls.
                if (rSh.GetViewOptions()->IsUseHeaderFooterMenu() && !rSh.GetViewOptions()->IsHideWhitespaceMode())
                {
                    SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
                    const bool bWasInHeader = aPam.GetPoint()->GetNode().FindHeaderStartNode() != nullptr;
                    const bool bWasInFooter = aPam.GetPoint()->GetNode().FindFooterStartNode() != nullptr;
 
                    // Is the cursor in a part like similar to the one we clicked on? For example,
                    // if the cursor is in a header and we click on an empty header... don't change anything to
                    // keep consistent behaviour due to header edit mode (and the same for the footer as well).
 
                    // Otherwise, we hide the header/footer control if a separator is shown, and vice versa.
                    if (!(bWasInHeader && eControl == FrameControlType::Header) &&
                        !(bWasInFooter && eControl == FrameControlType::Footer))
                    {
                        const bool bSeparatorWasVisible = rSh.IsShowHeaderFooterSeparator(eControl);
                        rSh.SetShowHeaderFooterSeparator(eControl, !bSeparatorWasVisible);
 
                        // Repaint everything
                        Invalidate();
 
                        // tdf#84929. If the footer control had not been showing, do not change the cursor position,
                        // because the user may have scrolled to turn on the separator control and
                        // if the cursor cannot be positioned on-screen, then the user would need to scroll back again to use the control.
                        // This should only be done for the footer. The cursor can always be re-positioned near the header. tdf#134023.
                        if ( eControl == FrameControlType::Footer && !bSeparatorWasVisible
                             && !Application::IsHeadlessModeEnabled() )
                            return;
                    }
                }
            }
            else
            {
                // Make sure we have the proper Header/Footer separators shown
                // as these may be changed if clicking on an empty Header/Footer
                rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, eControl == FrameControlType::Header );
                rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, eControl == FrameControlType::Footer );
 
                if ( !rSh.IsHeaderFooterEdit() )
                    rSh.ToggleHeaderFooterEdit();
            }
        }
    }
    else
    {
        if ( rSh.IsHeaderFooterEdit( ) )
            rSh.ToggleHeaderFooterEdit( );
        else
        {
            // Make sure that the separators are hidden
            rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, false );
            rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
        }
 
        // Toggle Hide-Whitespace if between pages.
        if (rSh.GetViewOptions()->CanHideWhitespace() &&
            rSh.GetLayout()->IsBetweenPages(aDocPos))
        {
            if (_rMEvt.GetClicks() >= 2)
            {
                SwViewOption aOpt(*rSh.GetViewOptions());
                aOpt.SetHideWhitespaceMode(!aOpt.IsHideWhitespaceMode());
                rSh.ApplyViewOptions(aOpt);
            }
 
            return;
        }
    }
 
    if ( IsChainMode() )
    {
        SetChainMode( false );
        SwRect aDummy;
        SwFlyFrameFormat *pFormat = static_cast<SwFlyFrameFormat*>(rSh.GetFlyFrameFormat());
        if ( rSh.Chainable( aDummy, *pFormat, aDocPos ) == SwChainRet::OK )
            rSh.Chain( *pFormat, aDocPos );
        UpdatePointer(aDocPos, aMEvt.GetModifier());
        return;
    }
 
    // After GrabFocus a shell should be pushed. That should actually
    // work but in practice ...
    m_rView.SelectShellForDrop();
 
    bool bCallBase = true;
 
    if( s_pQuickHlpData->m_bIsDisplayed )
        s_pQuickHlpData->Stop( rSh );
    s_pQuickHlpData->m_bAppendSpace = false;
 
    if( rSh.FinishOLEObj() )
        return; // end InPlace and the click doesn't count anymore
 
    CurrShell aCurr( &rSh );
 
    SdrView *pSdrView = rSh.GetDrawView();
    if ( pSdrView )
    {
        if (pSdrView->MouseButtonDown(aMEvt, GetOutDev()))
        {
            rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
            return; // SdrView's event evaluated
        }
    }
 
    m_bIsInMove = false;
    m_aStartPos = aMEvt.GetPosPixel();
    m_aRszMvHdlPt.setX( 0 );
    m_aRszMvHdlPt.setY( 0 );
 
    SwTab nMouseTabCol = SwTab::COL_NONE;
    const bool bTmp = !rSh.IsDrawCreate() && !m_pApplyTempl && !rSh.IsInSelect()
                      && aMEvt.GetClicks() == 1 && MOUSE_LEFT == aMEvt.GetButtons();
 
    if (  bTmp &&
         SwTab::COL_NONE != (nMouseTabCol = rSh.WhichMouseTabCol( aDocPos ) ) &&
         ( !rSh.IsObjSelectable( aDocPos ) ||
             // allow resizing row height, if the image is anchored as character in the cell
             !( SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol ) ) )
    {
        // Enhanced table selection
        if ( SwTab::SEL_HORI <= nMouseTabCol && SwTab::COLSEL_VERT >= nMouseTabCol )
        {
            rSh.EnterStdMode();
            rSh.SelectTableRowCol( aDocPos );
            if( SwTab::SEL_HORI  != nMouseTabCol && SwTab::SEL_HORI_RTL  != nMouseTabCol)
            {
                m_xRowColumnSelectionStart = aDocPos;
                m_bIsRowDrag = SwTab::ROWSEL_HORI == nMouseTabCol||
                            SwTab::ROWSEL_HORI_RTL == nMouseTabCol ||
                            SwTab::COLSEL_VERT == nMouseTabCol;
                m_bMBPressed = true;
                CaptureMouse();
            }
            return;
        }
 
        if ( !rSh.IsTableMode() )
        {
            // comes from table columns out of the document.
            if(SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol)
                m_rView.SetTabColFromDoc( true );
            else
                m_rView.SetTabRowFromDoc( true );
 
            m_rView.SetTabColFromDocPos( aDocPos );
            m_rView.InvalidateRulerPos();
            SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
            rBind.Update();
            if (RulerColumnDrag(
                    aMEvt, (SwTab::COL_VERT == nMouseTabCol || SwTab::ROW_HORI == nMouseTabCol)))
            {
                m_rView.SetTabColFromDoc( false );
                m_rView.SetTabRowFromDoc( false );
                m_rView.InvalidateRulerPos();
                rBind.Update();
                bCallBase = false;
            }
            else
            {
                return;
            }
        }
    }
    else if (bTmp &&
             rSh.IsNumLabel(aDocPos))
    {
        SwTextNode* pNodeAtPos = rSh.GetNumRuleNodeAtPos( aDocPos );
        m_rView.SetNumRuleNodeFromDoc( pNodeAtPos );
        m_rView.InvalidateRulerPos();
        SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
        rBind.Update();
 
        if (RulerMarginDrag(aMEvt, SwFEShell::IsVerticalModeAtNdAndPos(*pNodeAtPos, aDocPos)))
        {
            m_rView.SetNumRuleNodeFromDoc( nullptr );
            m_rView.InvalidateRulerPos();
            rBind.Update();
            bCallBase = false;
        }
        else
        {
            // Make sure the pointer is set to 0, otherwise it may point to
            // nowhere after deleting the corresponding text node.
            m_rView.SetNumRuleNodeFromDoc( nullptr );
            return;
        }
    }
 
    if ( rSh.IsInSelect() )
        rSh.EndSelect();
 
    // query against LEFT because otherwise for example also a right
    // click releases the selection.
    if (MOUSE_LEFT == aMEvt.GetButtons())
    {
        bool bOnlyText = false;
        m_bMBPressed = true;
        g_bNoInterrupt = true;
        m_nKS_NUMDOWN_Count = 0;
 
        CaptureMouse();
 
        // reset cursor position if applicable
        rSh.ResetCursorStack();
 
        switch (aMEvt.GetModifier() + aMEvt.GetButtons())
        {
            case MOUSE_LEFT:
            case MOUSE_LEFT + KEY_SHIFT:
            case MOUSE_LEFT + KEY_MOD2:
                if( rSh.IsObjSelected() )
                {
                    SdrHdl* pHdl;
                    if( !bIsViewReadOnly &&
                        !m_pAnchorMarker &&
                        pSdrView &&
                        nullptr != ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
                            ( pHdl->GetKind() == SdrHdlKind::Anchor ||
                              pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
                    {
                        // #i121463# Set selected during drag
                        pHdl->SetSelected();
                        m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
                        UpdatePointer(aDocPos, aMEvt.GetModifier());
                        return;
                    }
                }
                if (EnterDrawMode(aMEvt, aDocPos))
                {
                    g_bNoInterrupt = false;
                    return;
                }
                else  if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
                {
                    StopInsFrame();
                    rSh.Edit();
                }
 
                // Without SHIFT because otherwise Toggle doesn't work at selection
                if (aMEvt.GetClicks() == 1)
                {
                    if ( rSh.IsSelFrameMode())
                    {
                        SdrHdl* pHdl = rSh.GetDrawView()->PickHandle(aDocPos);
                        bool bHitHandle = pHdl && pHdl->GetKind() != SdrHdlKind::Anchor &&
                                                  pHdl->GetKind() != SdrHdlKind::Anchor_TR;
 
                        if ((rSh.IsInsideSelectedObj(aDocPos) || bHitHandle)
                            && (aMEvt.GetModifier() != KEY_SHIFT || bHitHandle))
                        {
                            rSh.EnterSelFrameMode( &aDocPos );
                            if ( !m_pApplyTempl )
                            {
                                // only if no position to size was hit.
                                if (!bHitHandle)
                                {
                                    StartDDTimer();
                                    SwEditWin::s_nDDStartPosY = aDocPos.Y();
                                    SwEditWin::s_nDDStartPosX = aDocPos.X();
                                }
                                g_bFrameDrag = true;
                            }
                            g_bNoInterrupt = false;
                            return;
                        }
                    }
                }
        }
 
        bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
        if ( !bExecHyperlinks )
        {
            const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
            if ((bSecureOption && aMEvt.GetModifier() == KEY_MOD1)
                || (!bSecureOption && aMEvt.GetModifier() != KEY_MOD1))
                bExecHyperlinks = true;
        }
 
        // Enhanced selection
        sal_uInt8 nNumberOfClicks = static_cast<sal_uInt8>(aMEvt.GetClicks() % 4);
        if (0 == nNumberOfClicks && 0 < aMEvt.GetClicks())
            nNumberOfClicks = 4;
 
        bool bExecDrawTextLink = false;
 
        switch (aMEvt.GetModifier() + aMEvt.GetButtons())
        {
            case MOUSE_LEFT:
            case MOUSE_LEFT + KEY_MOD1:
            case MOUSE_LEFT + KEY_MOD2:
            {
 
                // fdo#79604: first, check if a link has been clicked - do not
                // select fly in this case!
                if (1 == nNumberOfClicks)
                {
                    UpdatePointer(aDocPos, aMEvt.GetModifier());
                    SwEditWin::s_nDDStartPosY = aDocPos.Y();
                    SwEditWin::s_nDDStartPosX = aDocPos.X();
 
                    // hit a URL in DrawText object?
                    if (bExecHyperlinks && pSdrView)
                    {
                        SdrViewEvent aVEvt;
                        pSdrView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
 
                        if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
                            bExecDrawTextLink = true;
                    }
                }
 
                if (1 == nNumberOfClicks && !bExecDrawTextLink)
                {
                    // only try to select frame, if pointer already was
                    // switched accordingly
                    if ( m_aActHitType != SdrHitKind::NONE && !rSh.IsSelFrameMode() &&
                        !GetView().GetViewFrame().GetDispatcher()->IsLocked())
                    {
                        // Test if there is a draw object at that position and if it should be selected.
                        bool bSelectFrameInsteadOfCroppedImage = false;
                        bool bShould = rSh.ShouldObjectBeSelected(aDocPos, &bSelectFrameInsteadOfCroppedImage);
 
                        if(bShould)
                        {
                            m_rView.NoRotate();
                            rSh.HideCursor();
 
                            bool bUnLockView = !rSh.IsViewLocked();
                            rSh.LockView( true );
                            bool bSelObj
                                = rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0);
                            if ( bSelObj && bSelectFrameInsteadOfCroppedImage && pSdrView )
                            {
                                bool bWrapped(false);
                                const SdrObject* pFly = rSh.GetBestObject(false, GotoObjFlags::FlyAny, true, nullptr, &bWrapped);
                                pSdrView->UnmarkAllObj();
                                bSelObj =
                                    rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0, const_cast<SdrObject*>(pFly));
                            }
                            if( bUnLockView )
                                rSh.LockView( false );
 
                            if( bSelObj )
                            {
                                // if the frame was deselected in the macro
                                // the cursor just has to be displayed again
                                if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
                                    rSh.ShowCursor();
                                else
                                {
                                    if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
                                    {
                                        m_rView.GetDrawFuncPtr()->Deactivate();
                                        m_rView.SetDrawFuncPtr(nullptr);
                                        m_rView.LeaveDrawCreate();
                                        m_rView.AttrChangedNotify(nullptr);
                                    }
 
                                    rSh.EnterSelFrameMode( &aDocPos );
                                    g_bFrameDrag = true;
                                    UpdatePointer(aDocPos, aMEvt.GetModifier());
                                }
                                return;
                            }
                            else
                                bOnlyText = rSh.IsObjSelectable( aDocPos );
 
                            if (!m_rView.GetDrawFuncPtr())
                                rSh.ShowCursor();
                        }
                        else
                            bOnlyText = KEY_MOD1 != aMEvt.GetModifier();
                    }
                    else if ( rSh.IsSelFrameMode() &&
                              (m_aActHitType == SdrHitKind::NONE ||
                               !rSh.IsInsideSelectedObj( aDocPos )))
                    {
                        m_rView.NoRotate();
                        SdrHdl *pHdl;
                        if( !bIsViewReadOnly && !m_pAnchorMarker && nullptr !=
                            ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
                                ( pHdl->GetKind() == SdrHdlKind::Anchor ||
                                  pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
                        {
                            m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
                            UpdatePointer(aDocPos, aMEvt.GetModifier());
                            return;
                        }
                        else
                        {
                            bool bUnLockView = !rSh.IsViewLocked();
                            rSh.LockView( true );
                            sal_uInt8 nFlag = aMEvt.IsShift() ? SW_ADD_SELECT : 0;
                            if (aMEvt.IsMod1())
                                nFlag = nFlag | SW_ENTER_GROUP;
 
                            if ( rSh.IsSelFrameMode() )
                            {
                                rSh.UnSelectFrame();
                                rSh.LeaveSelFrameMode();
                                m_rView.AttrChangedNotify(nullptr);
                            }
 
                            bool bSelObj = rSh.SelectObj( aDocPos, nFlag );
                            if( bUnLockView )
                                rSh.LockView( false );
 
                            if( !bSelObj )
                            {
                                // move cursor here so that it is not drawn in the
                                // frame first; ShowCursor() happens in LeaveSelFrameMode()
                                g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
                                rSh.LeaveSelFrameMode();
                                m_rView.AttrChangedNotify(nullptr);
                                bCallBase = false;
                            }
                            else
                            {
                                rSh.HideCursor();
                                rSh.EnterSelFrameMode( &aDocPos );
                                rSh.SelFlyGrabCursor();
                                rSh.MakeSelVisible();
                                g_bFrameDrag = true;
                                if( rSh.IsFrameSelected() &&
                                    m_rView.GetDrawFuncPtr() )
                                {
                                    m_rView.GetDrawFuncPtr()->Deactivate();
                                    m_rView.SetDrawFuncPtr(nullptr);
                                    m_rView.LeaveDrawCreate();
                                    m_rView.AttrChangedNotify(nullptr);
                                }
                                UpdatePointer(aDocPos, aMEvt.GetModifier());
                                return;
                            }
                        }
                    }
                }
 
                switch ( nNumberOfClicks )
                {
                    case 1:
                        break;
                    case 2:
                    {
                        g_bFrameDrag = false;
                        if (!bIsViewReadOnly && rSh.IsInsideSelectedObj(aDocPos)
                            && (FlyProtectFlags::NONE
                                    == rSh.IsSelObjProtected(FlyProtectFlags::Content
                                                             | FlyProtectFlags::Parent)
                                || rSh.GetSelectionType() == SelectionType::Ole))
                        {
                        /* This is no good: on the one hand GetSelectionType is used as flag field
                         * (take a look into the GetSelectionType method) and on the other hand the
                         * return value is used in a switch without proper masking (very nice), this must lead to trouble
                         */
                            switch ( rSh.GetSelectionType() & ~SelectionType( SelectionType::FontWork | SelectionType::ExtrudedCustomShape ) )
                            {
                            case SelectionType::Graphic:
                                ResetMouseButtonDownFlags();
                                if (!comphelper::LibreOfficeKit::isActive())
                                {
                                    GetView().GetViewFrame().GetBindings().Execute(
                                        FN_FORMAT_GRAFIC_DLG, nullptr,
                                        SfxCallMode::RECORD|SfxCallMode::SLOT);
                                }
                                return;
 
                            // double click on OLE object --> OLE-InPlace
                            case SelectionType::Ole:
                                ResetMouseButtonDownFlags();
                                rSh.LaunchOLEObj();
                                return;
 
                            case SelectionType::Frame:
                                ResetMouseButtonDownFlags();
                                if (!comphelper::LibreOfficeKit::isActive())
                                {
                                    GetView().GetViewFrame().GetBindings().Execute(
                                        FN_FORMAT_FRAME_DLG, nullptr,
                                        SfxCallMode::RECORD|SfxCallMode::SLOT);
                                }
                                return;
 
                            case SelectionType::DrawObject:
                                ResetMouseButtonDownFlags();
                                EnterDrawTextMode(aDocPos);
                                if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
                                    pSwDrawTextShell->Init();
                                return;
 
                            default: break;
                            }
                        }
 
                        // if the cursor position was corrected or if a Fly
                        // was selected in ReadOnlyMode, no word selection, except when tiled rendering.
                        if ((!g_bValidCursorPos || rSh.IsFrameSelected()) && !comphelper::LibreOfficeKit::isActive())
                            return;
 
                        SwField *pField;
                        bool bFootnote = false;
 
                        if( !bIsViewReadOnly &&
                            (nullptr != (pField = rSh.GetCurField(true)) ||
                              ( bFootnote = rSh.GetCurFootnote() )        ) )
                        {
                            ResetMouseButtonDownFlags();
                            if( bFootnote )
                                GetView().GetViewFrame().GetBindings().Execute( FN_EDIT_FOOTNOTE );
                            else
                            {
                                SwFieldTypesEnum nTypeId = pField->GetTypeId();
                                SfxViewFrame& rVFrame = GetView().GetViewFrame();
                                switch( nTypeId )
                                {
                                case SwFieldTypesEnum::Postit:
                                case SwFieldTypesEnum::Script:
                                {
                                    // if it's a Readonly region, status has to be enabled
                                    sal_uInt16 nSlot = SwFieldTypesEnum::Postit == nTypeId ? FN_POSTIT : FN_JAVAEDIT;
                                    SfxBoolItem aItem(nSlot, true);
                                    rVFrame.GetBindings().SetState(aItem);
                                    rVFrame.GetBindings().Execute(nSlot);
                                    break;
                                }
                                case SwFieldTypesEnum::Authority :
                                    rVFrame.GetBindings().Execute(FN_EDIT_AUTH_ENTRY_DLG);
                                break;
                                case SwFieldTypesEnum::Input:
                                case SwFieldTypesEnum::Dropdown:
                                case SwFieldTypesEnum::SetInput:
                                    rVFrame.GetBindings().Execute(FN_UPDATE_INPUTFIELDS);
                                    break;
                                default:
                                    rVFrame.GetBindings().Execute(FN_EDIT_FIELD);
                                }
                            }
                            return;
                        }
                        // in extended mode double and triple
                        // click has no effect.
                        if ( rSh.IsExtMode() || rSh.IsBlockMode() )
                            return;
 
                        // select word, AdditionalMode if applicable
                        if (KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode())
                        {
                            rSh.EnterAddMode();
                            rSh.SelWrd( &aDocPos );
                            rSh.LeaveAddMode();
                        }
                        else
                        {
                            if (!rSh.SelWrd(&aDocPos) && comphelper::LibreOfficeKit::isActive())
                                // Double click did not select any word: try to
                                // select the current cell in case we are in a
                                // table.
                                rSh.SelTableBox();
                        }
 
                        SwContentAtPos aContentAtPos(IsAttrAtPos::FormControl);
                        if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
                                aContentAtPos.aFnd.pFieldmark != nullptr)
                        {
                            Fieldmark *pFieldBM = const_cast< Fieldmark* > ( aContentAtPos.aFnd.pFieldmark );
                            if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN || pFieldBM->GetFieldname( ) == ODF_FORMDATE )
                            {
                                ResetMouseButtonDownFlags();
                                rSh.getIDocumentMarkAccess()->ClearFieldActivation();
                                GetView().GetViewFrame().GetBindings().Execute(SID_FM_CTL_PROPERTIES);
                                return;
                            }
                        }
 
                        // tdf#143158 - handle alphabetical index entries
                        SwContentAtPos aToxContentAtPos(IsAttrAtPos::ToxMark);
                        if (rSh.GetContentAtPos(aDocPos, aToxContentAtPos))
                        {
                            const OUString sToxText = aToxContentAtPos.sStr;
                            if (!sToxText.isEmpty() && aToxContentAtPos.pFndTextAttr)
                            {
                                const SwTOXType* pTType
                                    = aToxContentAtPos.pFndTextAttr->GetTOXMark().GetTOXType();
                                if (pTType && pTType->GetType() == TOXTypes::TOX_INDEX)
                                {
                                    ResetMouseButtonDownFlags();
                                    GetView().GetViewFrame().GetBindings().Execute(
                                        FN_EDIT_IDX_ENTRY_DLG);
                                    return;
                                }
                            }
                        }
 
                        g_bHoldSelection = true;
                        return;
                    }
                    case 3:
                    case 4:
                    {
                        g_bFrameDrag = false;
                        // in extended mode double and triple
                        // click has no effect.
                        if ( rSh.IsExtMode() )
                            return;
 
                        // if the cursor position was corrected or if a Fly
                        // was selected in ReadOnlyMode, no word selection.
                        if ( !g_bValidCursorPos || rSh.IsFrameSelected() )
                            return;
 
                        // select line, AdditionalMode if applicable
                        const bool bMod = KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode();
 
                        if ( bMod )
                            rSh.EnterAddMode();
 
                        // Enhanced selection
                        if ( 3 == nNumberOfClicks )
                            rSh.SelSentence( &aDocPos );
                        else
                            rSh.SelPara( &aDocPos );
 
                        if ( bMod )
                            rSh.LeaveAddMode();
 
                        g_bHoldSelection = true;
                        return;
                    }
 
                    default:
                        return;
                }
 
                [[fallthrough]];
            }
            case MOUSE_LEFT + KEY_SHIFT:
            case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
            {
                bool bLockView = m_bWasShdwCursor;
 
                switch (aMEvt.GetModifier())
                {
                    case KEY_MOD1 + KEY_SHIFT:
                    {
                        if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
                        {
                            m_rView.NoRotate();
                            rSh.HideCursor();
                            if ( rSh.IsSelFrameMode() )
                                rSh.SelectObj(aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP);
                            else
                            {   if ( rSh.SelectObj( aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP ) )
                                {
                                    rSh.EnterSelFrameMode( &aDocPos );
                                    SwEditWin::s_nDDStartPosY = aDocPos.Y();
                                    SwEditWin::s_nDDStartPosX = aDocPos.X();
                                    g_bFrameDrag = true;
                                    return;
                                }
                            }
                        }
                        else if( rSh.IsSelFrameMode() &&
                                 rSh.GetDrawView()->PickHandle( aDocPos ))
                        {
                            g_bFrameDrag = true;
                            g_bNoInterrupt = false;
                            return;
                        }
                    }
                    break;
                    case KEY_MOD1:
                    if ( !bExecDrawTextLink )
                    {
                        if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
                        {
                            // ctrl+left-click on outline node frame
                            SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
                            if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
                            {
                                SwOutlineNodes::size_type nPos;
                                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
                                {
                                    ToggleOutlineContentVisibility(nPos, false);
                                    return;
                                }
                            }
                        }
                        if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) && !lcl_urlOverBackground( rSh, aDocPos ) )
                        {
                            m_rView.NoRotate();
                            rSh.HideCursor();
                            if ( rSh.IsSelFrameMode() )
                                rSh.SelectObj(aDocPos, SW_ENTER_GROUP);
                            else
                            {   if ( rSh.SelectObj( aDocPos, SW_ENTER_GROUP ) )
                                {
                                    rSh.EnterSelFrameMode( &aDocPos );
                                    SwEditWin::s_nDDStartPosY = aDocPos.Y();
                                    SwEditWin::s_nDDStartPosX = aDocPos.X();
                                    g_bFrameDrag = true;
                                    return;
                                }
                            }
                        }
                        else if( rSh.IsSelFrameMode() &&
                                 rSh.GetDrawView()->PickHandle( aDocPos ))
                        {
                            g_bFrameDrag = true;
                            g_bNoInterrupt = false;
                            return;
                        }
                        else
                        {
                            if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
                            {
                                rSh.PushMode();
                                g_bModePushed = true;
 
                                bool bUnLockView = !rSh.IsViewLocked();
                                rSh.LockView( true );
                                rSh.EnterAddMode();
                                if( bUnLockView )
                                    rSh.LockView( false );
                            }
                            bCallBase = false;
                        }
                    }
                    break;
                    case KEY_MOD2:
                    {
                        if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
                        {
                            rSh.PushMode();
                            g_bModePushed = true;
                            bool bUnLockView = !rSh.IsViewLocked();
                            rSh.LockView( true );
                            rSh.EnterBlockMode();
                            if( bUnLockView )
                                rSh.LockView( false );
                        }
                        bCallBase = false;
                    }
                    break;
                    case KEY_SHIFT:
                    {
                        if (nNumberOfClicks == 2)
                        {
                            // Left mouse button, shift, double-click: see if we have a graphic and
                            // dispatch its dialog in this case.
                            if (rSh.GetSelectionType() == SelectionType::Graphic)
                            {
                                GetView().GetViewFrame().GetBindings().Execute(
                                    FN_FORMAT_GRAFIC_DLG, nullptr,
                                    SfxCallMode::RECORD | SfxCallMode::SLOT);
                                return;
                            }
                        }
 
                        if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
                        {
                            m_rView.NoRotate();
                            rSh.HideCursor();
                            if ( rSh.IsSelFrameMode() )
                            {
                                rSh.SelectObj(aDocPos, SW_ADD_SELECT);
 
                                const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
                                if (rMarkList.GetMark(0) == nullptr)
                                {
                                    rSh.LeaveSelFrameMode();
                                    m_rView.AttrChangedNotify(nullptr);
                                    g_bFrameDrag = false;
                                }
                            }
                            else
                            {   if ( rSh.SelectObj( aDocPos ) )
                                {
                                    rSh.EnterSelFrameMode( &aDocPos );
                                    SwEditWin::s_nDDStartPosY = aDocPos.Y();
                                    SwEditWin::s_nDDStartPosX = aDocPos.X();
                                    g_bFrameDrag = true;
                                    return;
                                }
                            }
                        }
                        else
                        {
                            bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
                            if (bShould)
                            {
                                // Left mouse button, shift, non-double-click, not a draw object and
                                // have an object to select: select it.
                                rSh.HideCursor();
                                bool bSelObj = rSh.SelectObj(aDocPos);
                                if (bSelObj)
                                {
                                    rSh.EnterSelFrameMode(&aDocPos);
                                }
                                return;
                            }
 
                            if ( rSh.IsSelFrameMode() &&
                                 rSh.IsInsideSelectedObj( aDocPos ) )
                            {
                                rSh.EnterSelFrameMode( &aDocPos );
                                SwEditWin::s_nDDStartPosY = aDocPos.Y();
                                SwEditWin::s_nDDStartPosX = aDocPos.X();
                                g_bFrameDrag = true;
                                return;
                            }
                            if ( rSh.IsSelFrameMode() )
                            {
                                rSh.UnSelectFrame();
                                rSh.LeaveSelFrameMode();
                                m_rView.AttrChangedNotify(nullptr);
                                g_bFrameDrag = false;
                            }
                            if ( !rSh.IsExtMode() )
                            {
                                // don't start a selection when an
                                // URL field or a graphic is clicked
                                bool bSttSelect = rSh.HasSelection() ||
                                                PointerStyle::RefHand != GetPointer();
 
                                if( !bSttSelect )
                                {
                                    bSttSelect = true;
                                    if( bExecHyperlinks )
                                    {
                                        SwContentAtPos aContentAtPos(
                                            IsAttrAtPos::Ftn |
                                            IsAttrAtPos::InetAttr );
 
                                        if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) )
                                        {
                                            if( !rSh.IsViewLocked() &&
                                                !rSh.IsReadOnlyAvailable() &&
                                                aContentAtPos.IsInProtectSect() )
                                                    bLockView = true;
 
                                            bSttSelect = false;
                                        }
                                        else if( rSh.IsURLGrfAtPos( aDocPos ))
                                            bSttSelect = false;
                                    }
                                }
 
                                if( bSttSelect )
                                    rSh.SttSelect();
                            }
                        }
                        bCallBase = false;
                        break;
                    }
                    default:
                        if( !rSh.IsViewLocked() )
                        {
                            SwContentAtPos aContentAtPos( IsAttrAtPos::ClickField |
                                                        IsAttrAtPos::InetAttr );
                            if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
                                !rSh.IsReadOnlyAvailable() &&
                                aContentAtPos.IsInProtectSect() )
                                bLockView = true;
                        }
                }
 
                if ( rSh.IsGCAttr() )
                {
                    rSh.GCAttr();
                    rSh.ClearGCAttr();
                }
 
                SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
                bool bEditableFieldClicked = false;
 
                // Are we clicking on a field?
                if (rSh.GetContentAtPos(aDocPos, aFieldAtPos))
                {
                    bool bEditableField = (aFieldAtPos.pFndTextAttr != nullptr
                        && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD);
 
                    if (!bEditableField)
                    {
                        rSh.CallSetCursor(&aDocPos, bOnlyText);
                        // Unfortunately the cursor may be on field
                        // position or on position after field depending on which
                        // half of the field was clicked on.
                        SwTextAttr const*const pTextField(aFieldAtPos.pFndTextAttr);
                        if (pTextField &&
                            rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() != pTextField->GetStart())
                        {
                            assert(rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() == (pTextField->GetStart() + 1));
                            rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
                        }
                        // don't go into the !bOverSelect block below - it moves
                        // the cursor
                        break;
                    }
                    else
                    {
                        bEditableFieldClicked = true;
                    }
                }
 
                bool bOverSelect = rSh.TestCurrPam( aDocPos );
                bool bOverURLGrf = false;
                if( !bOverSelect )
                    bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
 
                if ( !bOverSelect || rSh.IsInSelect() )
                {
                    MoveCursor( rSh, aDocPos, bOnlyText, bLockView );
                    bCallBase = false;
                }
                if (!bOverURLGrf && !bExecDrawTextLink && !bOnlyText)
                {
                    const SelectionType nSelType = rSh.GetSelectionType();
                    // Check in general, if an object is selectable at given position.
                    // Thus, also text fly frames in background become selectable via Ctrl-Click.
                    if ( ( nSelType & SelectionType::Ole ||
                         nSelType & SelectionType::Graphic ||
                         rSh.IsObjSelectable( aDocPos ) ) && !lcl_urlOverBackground( rSh, aDocPos ) )
                    {
                        SwMvContext aMvContext( &rSh );
                        rSh.EnterSelFrameMode();
                        bCallBase = false;
                    }
                }
                if ( !bOverSelect && bEditableFieldClicked && (!pCursorField ||
                     pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
                {
                    // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
                    // and CH_TXT_ATR_INPUTFIELDEND
                    rSh.SttSelect();
                    rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
                                 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
                }
                // don't reset here any longer so that, in case through MouseMove
                // with pressed Ctrl key a multiple-selection should happen,
                // the previous selection is not released in Drag.
                break;
            }
        }
    }
    else if (MOUSE_RIGHT == aMEvt.GetButtons())
    {
        // If right-click while dragging to resize the comment width, stop resizing
        if (mbIsDragSidebar)
        {
            ReleaseCommentGuideLine();
            ReleaseMouse();
            return;
        }
 
        if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()
            && aMEvt.GetModifier() == KEY_MOD1)
        {
            // ctrl+right-click on outline node frame
            SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
            if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
            {
                SwOutlineNodes::size_type nPos;
                if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
                {
                    ToggleOutlineContentVisibility(nPos, !rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent());
                    return;
                }
            }
        }
        else if (!aMEvt.GetModifier() && static_cast<sal_uInt8>(aMEvt.GetClicks() % 4) == 1
                 && !rSh.TestCurrPam(aDocPos))
        {
            SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
 
            // Are we clicking on a field?
            if (g_bValidCursorPos
                    && rSh.GetContentAtPos(aDocPos, aFieldAtPos)
                    && aFieldAtPos.pFndTextAttr != nullptr
                    && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD
                    && (!pCursorField || pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
            {
                // Move the cursor
                MoveCursor( rSh, aDocPos, rSh.IsObjSelectable( aDocPos ), m_bWasShdwCursor );
                bCallBase = false;
 
                // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
                // and CH_TXT_ATR_INPUTFIELDEND
                rSh.SttSelect();
                rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
                                *(aFieldAtPos.pFndTextAttr->End()) - 1 );
            }
        }
    }
 
    if (bCallBase)
        Window::MouseButtonDown(aMEvt);
}
 
bool SwEditWin::changeMousePointer(Point const & rDocPoint)
{
    SwWrtShell & rShell = m_rView.GetWrtShell();
 
    SwTab nMouseTabCol;
 
    if ( SwTab::COL_NONE != (nMouseTabCol = rShell.WhichMouseTabCol( rDocPoint ) ) &&
         ( !rShell.IsObjSelectable( rDocPoint ) ||
             // allow resizing row height, if the image is anchored as character in the cell
             !( SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol ) ) )
    {
        PointerStyle nPointer = PointerStyle::Null;
        bool bChkTableSel = false;
 
        switch ( nMouseTabCol )
        {
            case SwTab::COL_VERT :
            case SwTab::ROW_HORI :
                nPointer = PointerStyle::VSizeBar;
                bChkTableSel = true;
                break;
            case SwTab::ROW_VERT :
            case SwTab::COL_HORI :
                nPointer = PointerStyle::HSizeBar;
                bChkTableSel = true;
                break;
            // Enhanced table selection
            case SwTab::SEL_HORI :
                nPointer = PointerStyle::TabSelectSE;
                break;
            case SwTab::SEL_HORI_RTL :
            case SwTab::SEL_VERT :
                nPointer = PointerStyle::TabSelectSW;
                break;
            case SwTab::COLSEL_HORI :
            case SwTab::ROWSEL_VERT :
                nPointer = PointerStyle::TabSelectS;
                break;
            case SwTab::ROWSEL_HORI :
                nPointer = PointerStyle::TabSelectE;
                break;
            case SwTab::ROWSEL_HORI_RTL :
            case SwTab::COLSEL_VERT :
                nPointer = PointerStyle::TabSelectW;
                break;
            default: break; // prevent compiler warning
        }
 
        if ( PointerStyle::Null != nPointer &&
            // i#35543 - Enhanced table selection is explicitly allowed in table mode
            ( !bChkTableSel || !rShell.IsTableMode() ) &&
            !comphelper::LibreOfficeKit::isActive() )
        {
            SetPointer( nPointer );
        }
 
        return true;
    }
    else if (rShell.IsNumLabel(rDocPoint, RULER_MOUSE_MARGINWIDTH))
    {
        // i#42921 - consider vertical mode
        SwTextNode* pNodeAtPos = rShell.GetNumRuleNodeAtPos( rDocPoint );
        const PointerStyle nPointer =
                SwFEShell::IsVerticalModeAtNdAndPos( *pNodeAtPos, rDocPoint )
                ? PointerStyle::VSizeBar
                : PointerStyle::HSizeBar;
        SetPointer( nPointer );
 
        return true;
    }
    return false;
}
 
void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
{
    MouseEvent rMEvt(_rMEvt);
 
    if (comphelper::LibreOfficeKit::isActive())
    {
        if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
        {
            pWindow->MouseMove(rMEvt);
            return;
        }
    }
 
    if (m_rView.GetPostItMgr()->IsHitSidebarDragArea(rMEvt.GetPosPixel()))
    {
        SetPointer(PointerStyle::HSizeBar);
        return;
    }
 
    if (mbIsDragSidebar)
    {
        DrawCommentGuideLine(rMEvt.GetPosPixel());
        return;
    }
 
    //ignore key modifiers for format paintbrush
    {
        bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
                                &&  m_pApplyTempl->m_pFormatClipboard->HasContent();
        if( bExecFormatPaintbrush )
            rMEvt = MouseEvent( _rMEvt.GetPosPixel(), _rMEvt.GetClicks(),
                                    _rMEvt.GetMode(), _rMEvt.GetButtons() );
    }
 
    // as long as an action is running the MouseMove should be disconnected
    // otherwise bug 40102 occurs
    SwWrtShell &rSh = m_rView.GetWrtShell();
    if( rSh.ActionPend() )
        return ;
 
    if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
    {
        // add/remove outline content hide button
        const SwNodes& rNds = rSh.GetDoc()->GetNodes();
        SwOutlineNodes::size_type nPos;
        SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
        if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
        {
            // mouse pointer is on an outline paragraph node
            if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
            {
                // Get the outline paragraph frame and compare it to the saved outline frame. If they
                // are not the same, remove the fold button from the saved outline frame, if not
                // already removed, and then add a fold button to the mouse over outline frame if
                // the content is not folded.
                SwContentFrame* pContentFrame =
                        aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout());
                if (pContentFrame != m_pSavedOutlineFrame)
                {
                    if (m_pSavedOutlineFrame)
                    {
                        if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
                        {
                            SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
                            if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
                                    rSh.GetAttrOutlineContentVisible(nPos))
                            {
                                GetFrameControlsManager().RemoveControlsByType(
                                            FrameControlType::Outline, m_pSavedOutlineFrame);
                            }
                        }
                    }
                    m_pSavedOutlineFrame = static_cast<SwTextFrame*>(pContentFrame);
                }
                // show fold button if outline content is visible
                if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
                        rSh.GetAttrOutlineContentVisible(nPos))
                    GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
            }
        }
        else if (m_pSavedOutlineFrame)
        {
            // The saved frame may not still be in the document, e.g., when an outline paragraph
            // is deleted. This causes the call to GetTextNodeFirst to behave badly. Use
            // isFrameAreaDefinitionValid to check if the frame is still in the document.
            if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
            {
                // current pointer pos is not over an outline frame
                // previous pointer pos was over an outline frame
                // remove outline content visibility button if showing
                SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
                if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
                        rSh.GetAttrOutlineContentVisible(nPos))
                {
                    GetFrameControlsManager().RemoveControlsByType(
                                FrameControlType::Outline, m_pSavedOutlineFrame);
                }
            }
            m_pSavedOutlineFrame = nullptr;
        }
    }
 
    if( m_pShadCursor && 0 != (rMEvt.GetModifier() + rMEvt.GetButtons() ) )
    {
        m_pShadCursor.reset();
    }
 
    bool bIsViewReadOnly = m_rView.GetDocShell()->IsReadOnly() || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
 
    CurrShell aCurr( &rSh );
 
    //aPixPt == Point in Pixel, relative to ChildWin
    //aDocPt == Point in Twips, document coordinates
    const Point aPixPt( rMEvt.GetPosPixel() );
    const Point aDocPt( PixelToLogic( aPixPt ) );
 
    if ( IsChainMode() )
    {
        UpdatePointer( aDocPt, rMEvt.GetModifier() );
        return;
    }
 
    SdrView *pSdrView = rSh.GetDrawView();
 
    const SwCallMouseEvent aLastCallEvent( m_aSaveCallEvent );
    m_aSaveCallEvent.Clear();
 
    if ( !bIsViewReadOnly && pSdrView && pSdrView->MouseMove(rMEvt,GetOutDev()) )
    {
        SetPointer( PointerStyle::Text );
        return; // evaluate SdrView's event
    }
 
    const Point aOldPt( rSh.VisArea().Pos() );
    const bool bInsWin = rSh.VisArea().Contains( aDocPt ) || comphelper::LibreOfficeKit::isActive();
 
    if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
    {
        if (m_pSavedOutlineFrame && !bInsWin)
        {
            // the mouse pointer has left the building (edit window)
            // remove the outline content visibility button if showing
            if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
            {
                const SwNodes& rNds = rSh.GetDoc()->GetNodes();
                SwOutlineNodes::size_type nPos;
                SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
                if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
                        rSh.GetAttrOutlineContentVisible(nPos))
                {
                    GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
                                                                   m_pSavedOutlineFrame);
                }
            }
            m_pSavedOutlineFrame = nullptr;
        }
    }
 
    if( m_pShadCursor && !bInsWin )
    {
        m_pShadCursor.reset();
    }
 
    if( bInsWin && m_xRowColumnSelectionStart )
    {
        EnterArea();
        Point aPos( aDocPt );
        if( rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag ))
            return;
    }
 
    // position is necessary for OS/2 because obviously after a MB-Down
    // a MB-Move is called immediately.
    if( g_bDDTimerStarted )
    {
        Point aDD( SwEditWin::s_nDDStartPosX, SwEditWin::s_nDDStartPosY );
        aDD = LogicToPixel( aDD );
        tools::Rectangle aRect( aDD.X()-3, aDD.Y()-3, aDD.X()+3, aDD.Y()+3 );
        if ( !aRect.Contains( aPixPt ) )
            StopDDTimer( &rSh, aDocPt );
    }
 
    if(m_rView.GetDrawFuncPtr())
    {
        if( m_bInsDraw  )
        {
            m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
            if ( !bInsWin )
            {
                Point aTmp( aDocPt );
                aTmp += rSh.VisArea().Pos() - aOldPt;
                LeaveArea( aTmp );
            }
            else
                EnterArea();
            return;
        }
        else if(!rSh.IsFrameSelected() && !rSh.IsObjSelected())
        {
            SfxBindings &rBnd = rSh.GetView().GetViewFrame().GetBindings();
            Point aRelPos = rSh.GetRelativePagePosition(aDocPt);
            if(aRelPos.X() >= 0)
            {
                FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebView*>( &GetView())  != nullptr );
                SW_MOD()->PutItem(SfxUInt16Item(SID_ATTR_METRIC, static_cast< sal_uInt16 >(eMetric)));
                const SfxPointItem aTmp1( SID_ATTR_POSITION, aRelPos );
                rBnd.SetState( aTmp1 );
            }
            else
            {
                rBnd.Invalidate(SID_ATTR_POSITION);
            }
            rBnd.Invalidate(SID_ATTR_SIZE);
            const SvxStatusItem aCell( SID_TABLE_CELL, OUString(), StatusCategory::NONE );
            rBnd.SetState( aCell );
        }
    }
 
    // determine if we only change the mouse pointer and return
    if (!bIsViewReadOnly && bInsWin && !m_pApplyTempl && !rSh.IsInSelect() && changeMousePointer(aDocPt))
    {
        return;
    }
 
    bool bDelShadCursor = true;
 
    switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
    {
        case MOUSE_LEFT:
            if( m_pAnchorMarker )
            {
                // Now we need to refresh the SdrHdl pointer of m_pAnchorMarker.
                // This looks a little bit tricky, but it solves the following
                // problem: the m_pAnchorMarker contains a pointer to an SdrHdl,
                // if the FindAnchorPos-call cause a scrolling of the visible
                // area, it's possible that the SdrHdl will be destroyed and a
                // new one will initialized at the original position(GetHdlPos).
                // So the m_pAnchorMarker has to find the right SdrHdl, if it's
                // the old one, it will find it with position aOld, if this one
                // is destroyed, it will find a new one at position GetHdlPos().
 
                const Point aOld = m_pAnchorMarker->GetPosForHitTest( *(rSh.GetOut()) );
                Point aNew = rSh.FindAnchorPos( aDocPt );
                SdrHdl* pHdl;
                if( pSdrView && (nullptr!=( pHdl = pSdrView->PickHandle( aOld ) )||
                    nullptr !=(pHdl = pSdrView->PickHandle( m_pAnchorMarker->GetHdlPos()) ) ) &&
                        ( pHdl->GetKind() == SdrHdlKind::Anchor ||
                          pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
                {
                    m_pAnchorMarker->ChgHdl( pHdl );
                    if( aNew.X() || aNew.Y() )
                    {
                        m_pAnchorMarker->SetPos( aNew );
                        m_pAnchorMarker->SetLastPos( aDocPt );
                    }
                }
                else
                {
                    m_pAnchorMarker.reset();
                }
            }
            if ( m_bInsDraw )
            {
                if ( !m_bMBPressed )
                    break;
                if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
                {
                    if ( !bInsWin )
                        LeaveArea( aDocPt );
                    else
                        EnterArea();
                    if ( m_rView.GetDrawFuncPtr() )
                    {
                        pSdrView->SetOrtho(false);
                        m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
                    }
                    m_bIsInMove = true;
                }
                return;
            }
 
            {
            SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
            if (pWrdCnt)
                pWrdCnt->UpdateCounts();
            }
            [[fallthrough]];
 
        case MOUSE_LEFT + KEY_SHIFT:
        case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
            if ( !m_bMBPressed )
                break;
            [[fallthrough]];
        case MOUSE_LEFT + KEY_MOD1:
            if ( g_bFrameDrag && rSh.IsSelFrameMode() )
            {
                if( !m_bMBPressed )
                    break;
 
                if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
                {
                    // event processing for resizing
                    if (pSdrView && pSdrView->GetMarkedObjectList().GetMarkCount() != 0)
                    {
                        const Point aSttPt( PixelToLogic( m_aStartPos ) );
 
                        // can we start?
                        if( SdrHdlKind::User == g_eSdrMoveHdl )
                        {
                            SdrHdl* pHdl = pSdrView->PickHandle( aSttPt );
                            g_eSdrMoveHdl = pHdl ? pHdl->GetKind() : SdrHdlKind::Move;
                        }
 
                        const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
                        const SvxMacro* pMacro = nullptr;
 
                        SvMacroItemId nEvent = SdrHdlKind::Move == g_eSdrMoveHdl
                                            ? SvMacroItemId::SwFrmMove
                                            : SvMacroItemId::SwFrmResize;
 
                        if (nullptr != pFlyFormat)
                            pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
                        if (nullptr != pMacro &&
                        // or notify only e.g. every 20 Twip?
                            m_aRszMvHdlPt != aDocPt )
                        {
                            m_aRszMvHdlPt = aDocPt;
                            sal_uInt32 nPos = 0;
                            SbxArrayRef xArgs = new SbxArray;
                            SbxVariableRef xVar = new SbxVariable;
                            xVar->PutString( pFlyFormat->GetName() );
                            xArgs->Put(xVar.get(), ++nPos);
 
                            if( SvMacroItemId::SwFrmResize == nEvent )
                            {
                                xVar = new SbxVariable;
                                xVar->PutUShort( static_cast< sal_uInt16 >(g_eSdrMoveHdl) );
                                xArgs->Put(xVar.get(), ++nPos);
                            }
 
                            xVar = new SbxVariable;
                            xVar->PutLong( aDocPt.X() - aSttPt.X() );
                            xArgs->Put(xVar.get(), ++nPos);
                            xVar = new SbxVariable;
                            xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
                            xArgs->Put(xVar.get(), ++nPos);
 
                            OUString sRet;
 
                            ReleaseMouse();
 
                            rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
 
                            CaptureMouse();
 
                            if( !sRet.isEmpty() && sRet.toInt32()!=0 )
                                return ;
                        }
                    }
                    // event processing for resizing
 
                    if( bIsViewReadOnly )
                        break;
 
                    bool bResizeKeepRatio = rSh.GetSelectionType() & SelectionType::Graphic ||
                                            rSh.GetSelectionType() & SelectionType::Media ||
                                            rSh.GetSelectionType() & SelectionType::Ole;
                    bool bisResize = g_eSdrMoveHdl != SdrHdlKind::Move;
 
                    if (pSdrView)
                    {
                        // Resize proportionally when media is selected and the user drags on a corner
                        const Point aSttPt(PixelToLogic(m_aStartPos));
                        SdrHdl* pHdl = pSdrView->PickHandle(aSttPt);
                        if (pHdl)
                            bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
 
                        if (pSdrView->GetDragMode() == SdrDragMode::Crop)
                            bisResize = false;
                        if (rMEvt.IsShift())
                        {
                            pSdrView->SetAngleSnapEnabled(!bResizeKeepRatio);
                            if (bisResize)
                                pSdrView->SetOrtho(!bResizeKeepRatio);
                            else
                                pSdrView->SetOrtho(true);
                        }
                        else
                        {
                            pSdrView->SetAngleSnapEnabled(bResizeKeepRatio);
                            if (bisResize)
                                pSdrView->SetOrtho(bResizeKeepRatio);
                            else
                                pSdrView->SetOrtho(false);
                        }
                    }
 
                    rSh.Drag( &aDocPt, rMEvt.IsShift() );
                    m_bIsInMove = true;
                }
                else if( bIsViewReadOnly )
                    break;
 
                if ( !bInsWin )
                {
                    Point aTmp( aDocPt );
                    aTmp += rSh.VisArea().Pos() - aOldPt;
                    LeaveArea( aTmp );
                }
                else if(m_bIsInMove)
                    EnterArea();
                return;
            }
            if ( !rSh.IsSelFrameMode() && !g_bDDINetAttr &&
                (IsMinMove( m_aStartPos,aPixPt ) || m_bIsInMove) &&
                (rSh.IsInSelect() || !rSh.TestCurrPam( aDocPt )) )
            {
                if ( pSdrView )
                {
                    if ( rMEvt.IsShift() )
                        pSdrView->SetOrtho(true);
                    else
                        pSdrView->SetOrtho(false);
                }
                if ( !bInsWin )
                {
                    Point aTmp( aDocPt );
                    aTmp += rSh.VisArea().Pos() - aOldPt;
                    LeaveArea( aTmp );
                }
                else
                {
                    if( !rMEvt.IsSynthetic() &&
                        ( MOUSE_LEFT != rMEvt.GetButtons() ||
                          KEY_MOD1 != rMEvt.GetModifier() ||
                          !rSh.Is_FnDragEQBeginDrag() ||
                          rSh.IsAddMode() ) )
                    {
                        rSh.Drag( &aDocPt, false );
 
                        g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
                        EnterArea();
                    }
                }
            }
            g_bDDINetAttr = false;
            break;
        case 0:
        {
            if ( m_pApplyTempl )
            {
                UpdatePointer(aDocPt); // maybe a frame has to be marked here
                break;
            }
            // change ui if mouse is over SwPostItField
            // TODO: do the same thing for redlines IsAttrAtPos::Redline
            SwContentAtPos aContentAtPos( IsAttrAtPos::Field);
            if (rSh.GetContentAtPos(aDocPt, aContentAtPos, false))
            {
                const SwField* pField = aContentAtPos.aFnd.pField;
                if (pField->Which()== SwFieldIds::Postit)
                {
                    m_rView.GetPostItMgr()->SetShadowState(reinterpret_cast<const SwPostItField*>(pField),false);
                }
                else
                    m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
            }
            else
                m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
            [[fallthrough]];
        }
        case KEY_SHIFT:
        case KEY_MOD2:
        case KEY_MOD1:
            if ( !m_bInsDraw )
            {
                bool bTstShdwCursor = true;
 
                UpdatePointer( aDocPt, rMEvt.GetModifier() );
 
                const SwFrameFormat* pFormat = nullptr;
                const SwFormatINetFormat* pINet = nullptr;
                SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
                if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
                    pINet = static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr);
 
                const void* pTmp = pINet;
 
                if( pINet ||
                    nullptr != ( pTmp = pFormat = rSh.GetFormatFromAnyObj( aDocPt )))
                {
                    bTstShdwCursor = false;
                    if( pTmp == pINet )
                        m_aSaveCallEvent.Set( pINet );
                    else
                    {
                        IMapObject* pIMapObj = pFormat->GetIMapObject( aDocPt );
                        if( pIMapObj )
                            m_aSaveCallEvent.Set( pFormat, pIMapObj );
                        else
                            m_aSaveCallEvent.Set( EVENT_OBJECT_URLITEM, pFormat );
                    }
 
                    // should be over an InternetField with an
                    // embedded macro?
                    if( m_aSaveCallEvent != aLastCallEvent )
                    {
                        if( aLastCallEvent.HasEvent() )
                            rSh.CallEvent( SvMacroItemId::OnMouseOut,
                                            aLastCallEvent, true );
                        // 0 says that the object doesn't have any table
                        if( !rSh.CallEvent( SvMacroItemId::OnMouseOver,
                                        m_aSaveCallEvent ))
                            m_aSaveCallEvent.Clear();
                    }
                }
                else if( aLastCallEvent.HasEvent() )
                {
                    // cursor was on an object
                    rSh.CallEvent( SvMacroItemId::OnMouseOut,
                                    aLastCallEvent, true );
                }
 
                if( bTstShdwCursor && bInsWin && !bIsViewReadOnly &&
                    !m_bInsFrame &&
                    !rSh.GetViewOptions()->getBrowseMode() &&
                    rSh.GetViewOptions()->IsShadowCursor() &&
                    !(rMEvt.GetModifier() + rMEvt.GetButtons()) &&
                    !rSh.HasSelection() && !GetOutDev()->GetConnectMetaFile() )
                {
                    SwRect aRect;
 
                    SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
                    if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, m_eOrient ))
                    {
                        if( !m_pShadCursor )
                            m_pShadCursor.reset( new SwShadowCursor( *this ) );
                        if( text::HoriOrientation::RIGHT != m_eOrient && text::HoriOrientation::CENTER != m_eOrient )
                            m_eOrient = text::HoriOrientation::LEFT;
                        m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(m_eOrient) );
                        bDelShadCursor = false;
                    }
                }
            }
            break;
        case MOUSE_LEFT + KEY_MOD2:
            if( rSh.IsBlockMode() && !rMEvt.IsSynthetic() )
            {
                rSh.Drag( &aDocPt, false );
                g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
                EnterArea();
            }
        break;
    }
 
    if( bDelShadCursor && m_pShadCursor )
    {
        m_pShadCursor.reset();
    }
    m_bWasShdwCursor = false;
}
 
/**
 * Button Up
 */
void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
{
    if (comphelper::LibreOfficeKit::isActive())
    {
        if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
        {
            pWindow->MouseButtonUp(rMEvt);
            return;
        }
    }
 
    if (mbIsDragSidebar)
    {
        SetSidebarWidth(rMEvt.GetPosPixel());
        // While dragging the mouse is captured, so we need to release it here
        ReleaseMouse();
        ReleaseCommentGuideLine();
        return;
    }
 
    bool bCallBase = true;
 
    bool bCallShadowCursor = m_bWasShdwCursor;
    m_bWasShdwCursor = false;
    if( m_pShadCursor )
    {
        m_pShadCursor.reset();
    }
 
    m_xRowColumnSelectionStart.reset();
 
    SdrHdlKind eOldSdrMoveHdl = g_eSdrMoveHdl;
    g_eSdrMoveHdl = SdrHdlKind::User;     // for MoveEvents - reset again
 
    // preventively reset
    m_rView.SetTabColFromDoc( false );
    m_rView.SetNumRuleNodeFromDoc(nullptr);
 
    SwWrtShell &rSh = m_rView.GetWrtShell();
    CurrShell aCurr( &rSh );
    SdrView *pSdrView = rSh.GetDrawView();
    if ( pSdrView )
    {
        // tdf34555: ortho was always reset before being used in EndSdrDrag
        // Now, it is reset only if not in Crop mode.
        if (pSdrView->GetDragMode() != SdrDragMode::Crop && !rMEvt.IsShift())
            pSdrView->SetOrtho(false);
 
        if ( pSdrView->MouseButtonUp( rMEvt,GetOutDev() ) )
        {
            rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
            return; // SdrView's event evaluated
        }
    }
    // only process MouseButtonUp when the Down went to that windows as well.
    if ( !m_bMBPressed )
    {
    // Undo for the watering can is already in CommandHdl
    // that's the way it should be!
 
        return;
    }
 
    Point aDocPt( PixelToLogic( rMEvt.GetPosPixel() ) );
 
    if ( g_bDDTimerStarted )
    {
        StopDDTimer( &rSh, aDocPt );
        m_bMBPressed = false;
        if ( rSh.IsSelFrameMode() )
        {
            rSh.EndDrag( &aDocPt, false );
            g_bFrameDrag = false;
        }
        g_bNoInterrupt = false;
        const Point aDocPos( PixelToLogic( rMEvt.GetPosPixel() ) );
        if ((PixelToLogic(m_aStartPos).Y() == (aDocPos.Y())) && (PixelToLogic(m_aStartPos).X() == (aDocPos.X())))//To make sure it was not moved
        {
            SdrPageView* pPV = nullptr;
            SdrObject* pObj = pSdrView ? pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
            if (pObj)
            {
                if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
                {
                    SwFrameFormat* pFormat = pContact->GetFormat();
                    SwFrameFormat* pShapeFormat
                        = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT);
                    if (!pShapeFormat)
                    {
                        pSdrView->UnmarkAllObj();
                        pSdrView->MarkObj(pObj, pPV);
                    }
                    else
                    {
                        // If the fly frame is a textbox of a shape, then select the shape instead.
                        SdrObject* pShape = pShapeFormat->FindSdrObject();
                        pSdrView->UnmarkAllObj();
                        pSdrView->MarkObj(pShape, pPV);
                    }
                }
            }
        }
        ReleaseMouse();
        return;
    }
 
    if( m_pAnchorMarker )
    {
        if(m_pAnchorMarker->GetHdl())
        {
            // #i121463# delete selected after drag
            m_pAnchorMarker->GetHdl()->SetSelected(false);
        }
 
        Point aPnt( m_pAnchorMarker->GetLastPos() );
        m_pAnchorMarker.reset();
        if( aPnt.X() || aPnt.Y() )
            rSh.FindAnchorPos( aPnt, true );
    }
    if ( m_bInsDraw && m_rView.GetDrawFuncPtr() )
    {
        if ( m_rView.GetDrawFuncPtr()->MouseButtonUp( rMEvt ) )
        {
            if (m_rView.GetDrawFuncPtr()) // could have been destroyed in MouseButtonUp
            {
                m_rView.GetDrawFuncPtr()->Deactivate();
 
                if (!m_rView.IsDrawMode())
                {
                    m_rView.SetDrawFuncPtr(nullptr);
                    SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
                    rBind.Invalidate( SID_ATTR_SIZE );
                    rBind.Invalidate( SID_TABLE_CELL );
                }
            }
 
            if ( rSh.IsObjSelected() )
            {
                rSh.EnterSelFrameMode();
                if (!m_rView.GetDrawFuncPtr())
                    StdDrawMode( SdrObjKind::NONE, true );
            }
            else if ( rSh.IsFrameSelected() )
            {
                rSh.EnterSelFrameMode();
                StopInsFrame();
            }
            else
            {
                const Point aDocPos( PixelToLogic( m_aStartPos ) );
                g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
                rSh.Edit();
            }
 
            m_rView.AttrChangedNotify(nullptr);
        }
        else if (rMEvt.GetButtons() == MOUSE_RIGHT && rSh.IsDrawCreate())
            m_rView.GetDrawFuncPtr()->BreakCreate();   // abort drawing
 
        g_bNoInterrupt = false;
        if (IsMouseCaptured())
            ReleaseMouse();
        return;
    }
    bool bPopMode = false;
    switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
    {
        case MOUSE_LEFT:
            if ( m_bInsDraw && rSh.IsDrawCreate() )
            {
                if ( m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->MouseButtonUp(rMEvt) )
                {
                    m_rView.GetDrawFuncPtr()->Deactivate();
                    m_rView.AttrChangedNotify(nullptr);
                    if ( rSh.IsObjSelected() )
                        rSh.EnterSelFrameMode();
                    if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
                        StopInsFrame();
                }
                bCallBase = false;
                break;
            }
            [[fallthrough]];
        case MOUSE_LEFT + KEY_MOD1:
        case MOUSE_LEFT + KEY_MOD2:
        case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
            if ( g_bFrameDrag && rSh.IsSelFrameMode() )
            {
                if ( rMEvt.IsMod1() ) // copy and don't move.
                {
                    // abort drag, use internal Copy instead
                    tools::Rectangle aRect;
                    rSh.GetDrawView()->TakeActionRect( aRect );
                    if (!aRect.IsEmpty())
                    {
                        rSh.BreakDrag();
                        Point aEndPt, aSttPt;
                        if ( rSh.GetSelFrameType() & FrameTypeFlags::FLY_ATCNT )
                        {
                            aEndPt = aRect.TopLeft();
                            aSttPt = rSh.GetDrawView()->GetAllMarkedRect().TopLeft();
                        }
                        else
                        {
                            aEndPt = aRect.Center();
                            aSttPt = rSh.GetDrawView()->GetAllMarkedRect().Center();
                        }
                        if ( aSttPt != aEndPt )
                        {
                            rSh.StartUndo( SwUndoId::UI_DRAG_AND_COPY );
                            rSh.Copy(rSh, aSttPt, aEndPt);
                            rSh.EndUndo( SwUndoId::UI_DRAG_AND_COPY );
                        }
                    }
                    else {
                        rSh.EndDrag( &aDocPt, false );
                    }
                }
                else
                {
                    {
                        const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
                        const SvxMacro* pMacro = nullptr;
 
                        SvMacroItemId nEvent = SdrHdlKind::Move == eOldSdrMoveHdl
                                            ? SvMacroItemId::SwFrmMove
                                            : SvMacroItemId::SwFrmResize;
 
                        if (nullptr != pFlyFormat)
                            pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
                        if (nullptr != pMacro)
                        {
                            const Point aSttPt( PixelToLogic( m_aStartPos ) );
                            m_aRszMvHdlPt = aDocPt;
                            sal_uInt32 nPos = 0;
                            SbxArrayRef xArgs = new SbxArray;
                            SbxVariableRef xVar = new SbxVariable;
                            xVar->PutString( pFlyFormat->GetName() );
                            xArgs->Put(xVar.get(), ++nPos);
 
                            if( SvMacroItemId::SwFrmResize == nEvent )
                            {
                                xVar = new SbxVariable;
                                xVar->PutUShort( static_cast< sal_uInt16 >(eOldSdrMoveHdl) );
                                xArgs->Put(xVar.get(), ++nPos);
                            }
 
                            xVar = new SbxVariable;
                            xVar->PutLong( aDocPt.X() - aSttPt.X() );
                            xArgs->Put(xVar.get(), ++nPos);
                            xVar = new SbxVariable;
                            xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
                            xArgs->Put(xVar.get(), ++nPos);
 
                            xVar = new SbxVariable;
                            xVar->PutUShort( 1 );
                            xArgs->Put(xVar.get(), ++nPos);
 
                            ReleaseMouse();
 
                            rSh.ExecMacro( *pMacro, nullptr, xArgs.get() );
 
                            CaptureMouse();
                        }
 
                        if (pFlyFormat)
                        {
                            // See if the fly frame's anchor is in a content control. If so,
                            // interact with it.
                            const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
                            SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
                            if (pAnchorNode)
                            {
                                SwTextNode* pTextNode = pAnchorNode->GetTextNode();
                                if (pTextNode)
                                {
                                    SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
                                        rFormatAnchor.GetAnchorContentOffset(), RES_TXTATR_CONTENTCONTROL,
                                        ::sw::GetTextAttrMode::Parent);
                                    if (pAttr)
                                    {
                                        SwTextContentControl* pTextContentControl
                                            = static_txtattr_cast<SwTextContentControl*>(pAttr);
                                        const SwFormatContentControl& rFormatContentControl
                                            = pTextContentControl->GetContentControl();
                                        rSh.GotoContentControl(rFormatContentControl);
                                    }
                                }
                            }
                        }
                    }
                    rSh.EndDrag( &aDocPt, false );
                }
                g_bFrameDrag = false;
                bCallBase = false;
                break;
            }
            bPopMode = true;
            [[fallthrough]];
        case MOUSE_LEFT + KEY_SHIFT:
            if (rSh.IsSelFrameMode())
            {
 
                rSh.EndDrag( &aDocPt, false );
                g_bFrameDrag = false;
                bCallBase = false;
                break;
            }
 
            if( g_bHoldSelection )
            {
                // the EndDrag should be called in any case
                g_bHoldSelection = false;
                rSh.EndDrag( &aDocPt, false );
            }
            else
            {
                SwContentAtPos aFieldAtPos (IsAttrAtPos::Field);
                if ( !rSh.IsInSelect() && rSh.TestCurrPam( aDocPt ) &&
                     !rSh.GetContentAtPos( aDocPt, aFieldAtPos ) )
                {
                    const bool bTmpNoInterrupt = g_bNoInterrupt;
                    g_bNoInterrupt = false;
                    {   // create only temporary move context because otherwise
                        // the query to the content form doesn't work!!!
                        SwMvContext aMvContext( &rSh );
                        const Point aDocPos( PixelToLogic( m_aStartPos ) );
                        g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
                    }
                    g_bNoInterrupt = bTmpNoInterrupt;
 
                }
                else
                {
                    bool bInSel = rSh.IsInSelect();
                    rSh.EndDrag( &aDocPt, false );
 
                    // Internetfield? --> call link (load doc!!)
                    if( !bInSel )
                    {
                        LoadUrlFlags nFilter = LoadUrlFlags::NONE;
                        if( KEY_MOD1 == rMEvt.GetModifier() )
                            nFilter |= LoadUrlFlags::NewView;
 
                        bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
                        if ( !bExecHyperlinks )
                        {
                            const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
                            if ( (  bSecureOption && rMEvt.GetModifier() == KEY_MOD1 ) ||
                                 ( !bSecureOption && rMEvt.GetModifier() != KEY_MOD1 ) )
                                bExecHyperlinks = true;
                        }
 
                        const bool bExecSmarttags = rMEvt.GetModifier() == KEY_MOD1;
 
                        if(m_pApplyTempl)
                            bExecHyperlinks = false;
 
                        SwContentAtPos aContentAtPos( IsAttrAtPos::Field |
                                                    IsAttrAtPos::InetAttr |
                                                    IsAttrAtPos::SmartTag  | IsAttrAtPos::FormControl |
                                                    IsAttrAtPos::ContentControl);
 
                        if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
                        {
                            // Do it again if we're not on a field/hyperlink to update the cursor accordingly
                            if ( IsAttrAtPos::Field != aContentAtPos.eContentAtPos
                                 && IsAttrAtPos::InetAttr != aContentAtPos.eContentAtPos )
                                rSh.GetContentAtPos( aDocPt, aContentAtPos, true );
 
                            bool bViewLocked = rSh.IsViewLocked();
                            if( !bViewLocked && !rSh.IsReadOnlyAvailable() &&
                                aContentAtPos.IsInProtectSect() )
                                rSh.LockView( true );
 
                            ReleaseMouse();
 
                            if( IsAttrAtPos::Field == aContentAtPos.eContentAtPos )
                            {
                                bool bAddMode(false);
                                // AdditionalMode if applicable
                                if (KEY_MOD1 == rMEvt.GetModifier()
                                    && !rSh.IsAddMode())
                                {
                                    bAddMode = true;
                                    rSh.EnterAddMode();
                                }
                                if ( aContentAtPos.pFndTextAttr != nullptr
                                     && aContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD )
                                {
                                    if (!rSh.IsInSelect())
                                    {
                                        // create only temporary move context because otherwise
                                        // the query to the content form doesn't work!!!
                                        SwMvContext aMvContext( &rSh );
                                        const Point aDocPos( PixelToLogic( m_aStartPos ) );
                                        g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
                                    }
                                    else
                                    {
                                        g_bValidCursorPos = true;
                                    }
                                }
                                else
                                {
                                    rSh.ClickToField(*aContentAtPos.aFnd.pField, bExecHyperlinks);
                                    // a bit of a mystery what this is good for?
                                    // in this case we assume it's valid since we
                                    // just selected a field
                                    g_bValidCursorPos = true;
                                }
                                if (bAddMode)
                                {
                                    rSh.LeaveAddMode();
                                }
                            }
                            else if (aContentAtPos.eContentAtPos == IsAttrAtPos::ContentControl)
                            {
                                auto pTextContentControl
                                    = static_txtattr_cast<const SwTextContentControl*>(
                                        aContentAtPos.pFndTextAttr);
                                const SwFormatContentControl& rFormatContentControl
                                    = pTextContentControl->GetContentControl();
                                rSh.GotoContentControl(rFormatContentControl);
                            }
                            else if ( IsAttrAtPos::SmartTag == aContentAtPos.eContentAtPos )
                            {
                                    // execute smarttag menu
                                    if ( bExecSmarttags && SwSmartTagMgr::Get().IsSmartTagsEnabled() )
                                        m_rView.ExecSmartTagPopup( aDocPt );
                            }
                            else if ( IsAttrAtPos::FormControl == aContentAtPos.eContentAtPos )
                            {
                                OSL_ENSURE( aContentAtPos.aFnd.pFieldmark != nullptr, "where is my field ptr???");
                                if ( aContentAtPos.aFnd.pFieldmark != nullptr)
                                {
                                    Fieldmark *fieldBM = const_cast< Fieldmark* > ( aContentAtPos.aFnd.pFieldmark );
                                    if ( fieldBM->GetFieldname( ) == ODF_FORMCHECKBOX )
                                    {
                                        CheckboxFieldmark& rCheckboxFm = dynamic_cast<CheckboxFieldmark&>(*fieldBM);
                                        rCheckboxFm.SetChecked(!rCheckboxFm.IsChecked());
                                        rCheckboxFm.Invalidate();
                                        rSh.InvalidateWindows( SwRect(m_rView.GetVisArea()) );
                                    }
                                    else if ( fieldBM->GetFieldname( ) == ODF_FORMTEXT &&
                                        static_cast< const TextFieldmark* > ( aContentAtPos.aFnd.pFieldmark )->HasDefaultContent() )
                                    {
                                        rSh.GotoFieldmark( aContentAtPos.aFnd.pFieldmark );
                                    }
 
                                }
                            }
                            else if ( IsAttrAtPos::InetAttr == aContentAtPos.eContentAtPos )
                            {
                                if (comphelper::LibreOfficeKit::isActive())
                                {
                                    OUString val((*static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)).GetValue());
                                    if (val.startsWith("#"))
                                        bExecHyperlinks = true;
                                }
                                if ( bExecHyperlinks && aContentAtPos.aFnd.pAttr )
                                    rSh.ClickToINetAttr( *static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr), nFilter );
                            }
 
                            rSh.LockView( bViewLocked );
                            bCallShadowCursor = false;
                        }
                        else
                        {
                            aContentAtPos = SwContentAtPos( IsAttrAtPos::Ftn );
                            if( !rSh.GetContentAtPos( aDocPt, aContentAtPos, true ) && bExecHyperlinks )
                            {
                                SdrViewEvent aVEvt;
 
                                if (pSdrView)
                                    pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
 
                                if (pSdrView && aVEvt.meEvent == SdrEventKind::ExecuteUrl)
                                {
                                    // hit URL field
                                    const SvxURLField *pField = aVEvt.mpURLField;
                                    if (pField)
                                    {
                                        const OUString& sURL(pField->GetURL());
                                        const OUString& sTarget(pField->GetTargetFrame());
                                        ::LoadURL(rSh, sURL, nFilter, sTarget);
                                    }
                                    bCallShadowCursor = false;
                                }
                                else
                                {
                                    // hit graphic
                                    ReleaseMouse();
                                    if( rSh.ClickToINetGrf( aDocPt, nFilter ))
                                        bCallShadowCursor = false;
                                }
                            }
                        }
 
                        if( bCallShadowCursor &&
                            rSh.GetViewOptions()->IsShadowCursor() &&
                            MOUSE_LEFT == (rMEvt.GetModifier() + rMEvt.GetButtons()) &&
                            !rSh.HasSelection() &&
                            !GetOutDev()->GetConnectMetaFile() &&
                            rSh.VisArea().Contains( aDocPt ))
                        {
                            SwUndoId nLastUndoId(SwUndoId::EMPTY);
                            if (rSh.GetLastUndoInfo(nullptr, & nLastUndoId))
                            {
                                if (SwUndoId::INS_FROM_SHADOWCRSR == nLastUndoId)
                                {
                                    rSh.Undo();
                                }
                            }
                            SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
                            rSh.SetShadowCursorPos( aDocPt, eMode );
                        }
                    }
                }
                bCallBase = false;
 
            }
 
            // reset pushed mode in Down again if applicable
            if ( bPopMode && g_bModePushed )
            {
                rSh.PopMode();
                g_bModePushed = false;
                bCallBase = false;
            }
            break;
 
        default:
            ReleaseMouse();
            return;
    }
 
    if( m_pApplyTempl )
    {
        SelectionType eSelection = rSh.GetSelectionType();
        SwFormatClipboard* pFormatClipboard = m_pApplyTempl->m_pFormatClipboard;
        if( pFormatClipboard )//apply format paintbrush
        {
            //get some parameters
            SwWrtShell& rWrtShell = m_rView.GetWrtShell();
            SfxStyleSheetBasePool* pPool=nullptr;
            bool bNoCharacterFormats = false;
            // Paste paragraph properties if the selection contains a whole paragraph or
            // there was no selection at all (i.e. just a left click)
            bool bNoParagraphFormats = rSh.HasSelection() && rSh.IsSelOnePara() && !rSh.IsSelFullPara();
 
            {
                SwDocShell* pDocSh = m_rView.GetDocShell();
                if(pDocSh)
                    pPool = pDocSh->GetStyleSheetPool();
                if( (rMEvt.GetModifier()&KEY_MOD1) && (rMEvt.GetModifier()&KEY_SHIFT) )
                {
                    bNoCharacterFormats = true;
                    bNoParagraphFormats = false;
                }
                else if( rMEvt.GetModifier() & KEY_MOD1 )
                    bNoParagraphFormats = true;
            }
            //execute paste
            pFormatClipboard->Paste( rWrtShell, pPool, bNoCharacterFormats, bNoParagraphFormats );
 
            //if the clipboard is empty after paste remove the ApplyTemplate
            if(!pFormatClipboard->HasContent())
                SetApplyTemplate(SwApplyTemplate());
 
            //tdf#38101 remove temporary highlighting
            m_pUserMarker.reset();
        }
        else if( m_pApplyTempl->nColor )
        {
            sal_uInt16 nId = 0;
            switch( m_pApplyTempl->nColor )
            {
                case SID_ATTR_CHAR_COLOR_EXT:
                    nId = RES_CHRATR_COLOR;
                    break;
                case SID_ATTR_CHAR_BACK_COLOR:
                case SID_ATTR_CHAR_COLOR_BACKGROUND:
                    nId = RES_CHRATR_BACKGROUND;
                    break;
            }
            if( nId && (SelectionType::Text|SelectionType::Table) & eSelection)
            {
                if( rSh.IsSelection() && !rSh.HasReadonlySel() )
                {
                    m_pApplyTempl->nUndo =
                        std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                    if (nId == RES_CHRATR_BACKGROUND)
                        ApplyCharBackground(m_aWaterCanTextBackColor, model::ComplexColor(), rSh);
                    else
                        rSh.SetAttrItem( SvxColorItem( m_aWaterCanTextColor, nId ) );
                    rSh.UnSetVisibleCursor();
                    rSh.EnterStdMode();
                    rSh.SetVisibleCursor(aDocPt);
                    bCallBase = false;
                    m_aTemplateTimer.Stop();
                }
                else if(rMEvt.GetClicks() == 1)
                {
                    // no selection -> so turn off watering can
                    m_aTemplateTimer.Start();
                }
            }
        }
        else
        {
            OUString aStyleName;
            switch ( m_pApplyTempl->eType )
            {
                case SfxStyleFamily::Para:
                    if( (( SelectionType::Text | SelectionType::Table )
                         & eSelection ) && !rSh.HasReadonlySel() )
                    {
                        rSh.SetTextFormatColl( m_pApplyTempl->aColl.pTextColl );
                        m_pApplyTempl->nUndo =
                            std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                        bCallBase = false;
                        if ( m_pApplyTempl->aColl.pTextColl )
                            aStyleName = m_pApplyTempl->aColl.pTextColl->GetName();
                    }
                    break;
                case SfxStyleFamily::Char:
                    if( (( SelectionType::Text | SelectionType::Table )
                         & eSelection ) && !rSh.HasReadonlySel() )
                    {
                        rSh.SetAttrItem( SwFormatCharFormat(m_pApplyTempl->aColl.pCharFormat) );
                        rSh.UnSetVisibleCursor();
                        rSh.EnterStdMode();
                        rSh.SetVisibleCursor(aDocPt);
                        m_pApplyTempl->nUndo =
                            std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                        bCallBase = false;
                        if ( m_pApplyTempl->aColl.pCharFormat )
                            aStyleName = m_pApplyTempl->aColl.pCharFormat->GetName();
                    }
                    break;
                case SfxStyleFamily::Frame :
                {
                    const SwFrameFormat* pFormat = rSh.GetFormatFromObj( aDocPt );
                    if(dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
                    {
                        rSh.SetFrameFormat( m_pApplyTempl->aColl.pFrameFormat, false, &aDocPt );
                        m_pApplyTempl->nUndo =
                            std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                        bCallBase = false;
                        if( m_pApplyTempl->aColl.pFrameFormat )
                            aStyleName = m_pApplyTempl->aColl.pFrameFormat->GetName();
                    }
                    break;
                }
                case SfxStyleFamily::Page:
                    // no Undo with page templates
                    rSh.ChgCurPageDesc( *m_pApplyTempl->aColl.pPageDesc );
                    if ( m_pApplyTempl->aColl.pPageDesc )
                        aStyleName = m_pApplyTempl->aColl.pPageDesc->GetName();
                    m_pApplyTempl->nUndo =
                        std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                    bCallBase = false;
                    break;
                case SfxStyleFamily::Pseudo:
                    if( !rSh.HasReadonlySel() )
                    {
                        rSh.SetCurNumRule( *m_pApplyTempl->aColl.pNumRule,
                                           false,
                                           m_pApplyTempl->aColl.pNumRule->GetDefaultListId() );
                        bCallBase = false;
                        m_pApplyTempl->nUndo =
                            std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
                        if( m_pApplyTempl->aColl.pNumRule )
                            aStyleName = m_pApplyTempl->aColl.pNumRule->GetName();
                    }
                    break;
                default: break;
            }
 
            uno::Reference< frame::XDispatchRecorder > xRecorder =
                    m_rView.GetViewFrame().GetBindings().GetRecorder();
            if ( !aStyleName.isEmpty() && xRecorder.is() )
            {
                SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
                if ( pSfxShell )
                {
                    SfxRequest aReq(m_rView.GetViewFrame(), SID_STYLE_APPLY);
                    aReq.AppendItem( SfxStringItem( SID_STYLE_APPLY, aStyleName ) );
                    aReq.AppendItem( SfxUInt16Item( SID_STYLE_FAMILY, static_cast<sal_uInt16>(m_pApplyTempl->eType) ) );
                    aReq.Done();
                }
            }
        }
 
    }
    ReleaseMouse();
    // Only processed MouseEvents arrive here; only at these this mode can
    // be reset.
    m_bMBPressed = false;
 
    // Make this call just to be sure. Selecting has finished surely by now.
    // Otherwise the timeout's timer could give problems.
    EnterArea();
    g_bNoInterrupt = false;
 
    if (bCallBase)
        Window::MouseButtonUp(rMEvt);
 
    // tdf#161717 - Track changes: Clicking on change in document should highlight related change
    // in "Manage Changes" window/sidebar
    if (m_rView.GetWrtShell().GetCurrRedline())
    {
        SwDocShell* pDocSh = m_rView.GetDocShell();
        if (pDocSh)
            pDocSh->Broadcast(SfxHint(SfxHintId::SwRedlineContentAtPos));
    }
 
    if (!(pSdrView && rMEvt.GetClicks() == 1 && comphelper::LibreOfficeKit::isActive()))
        return;
 
    // When tiled rendering, single click on a shape text starts editing already.
    SdrViewEvent aViewEvent;
    SdrHitKind eHit = pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aViewEvent);
    const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
    if (eHit == SdrHitKind::TextEditObj && rMarkList.GetMarkCount() == 1)
    {
        if (SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj())
        {
            EnterDrawTextMode(pObj->GetLogicRect().Center());
            if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
                pSwDrawTextShell->Init();
        }
    }
}
 
/**
 * Apply template
 */
void SwEditWin::SetApplyTemplate(const SwApplyTemplate &rTempl)
{
    static bool bIdle = false;
    m_pApplyTempl.reset();
    SwWrtShell &rSh = m_rView.GetWrtShell();
 
    if(rTempl.m_pFormatClipboard)
    {
        m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
        m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
        SetPointer( PointerStyle::Fill );//@todo #i20119# maybe better a new brush pointer here in future
        rSh.NoEdit( false );
        bIdle = rSh.GetViewOptions()->IsIdle();
        rSh.GetViewOptions()->SetIdle( false );
    }
    else if(rTempl.nColor)
    {
        m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
        m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
        SetPointer( PointerStyle::Fill );
        rSh.NoEdit( false );
        bIdle = rSh.GetViewOptions()->IsIdle();
        rSh.GetViewOptions()->SetIdle( false );
    }
    else if( rTempl.eType != SfxStyleFamily::None )
    {
        m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
        m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
        SetPointer( PointerStyle::Fill  );
        rSh.NoEdit( false );
        bIdle = rSh.GetViewOptions()->IsIdle();
        rSh.GetViewOptions()->SetIdle( false );
    }
    else
    {
        SetPointer( PointerStyle::Text );
        rSh.UnSetVisibleCursor();
 
        rSh.GetViewOptions()->SetIdle( bIdle );
        if ( !rSh.IsSelFrameMode() )
            rSh.Edit();
    }
 
    static sal_uInt16 aInva[] =
    {
        SID_STYLE_WATERCAN,
        SID_ATTR_CHAR_COLOR_EXT,
        SID_ATTR_CHAR_COLOR_BACKGROUND_EXT,
        0
    };
    m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
}
 
/**
 * Ctor
 */
SwEditWin::SwEditWin(vcl::Window *pParent, SwView &rMyView):
    DocWindow(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
    DropTargetHelper( this ),
    DragSourceHelper( this ),
 
    m_aTimer("SwEditWin"),
    m_aKeyInputFlushTimer("SwEditWin m_aKeyInputFlushTimer"),
    m_eBufferLanguage(LANGUAGE_DONTKNOW),
    m_aTemplateTimer("SwEditWin m_aTemplateTimer"),
    m_pUserMarkerObj( nullptr ),
 
    m_rView( rMyView ),
 
    m_aActHitType(SdrHitKind::NONE),
    m_nDropFormat( SotClipboardFormatId::NONE ),
    m_nDropAction( 0 ),
    m_nDropDestination( SotExchangeDest::NONE ),
 
    m_eBezierMode(SID_BEZIER_INSERT),
    m_nInsFrameColCount( 1 ),
    m_eDrawMode(SdrObjKind::NONE),
 
    m_bMBPressed(false),
    m_bInsDraw(false),
    m_bInsFrame(false),
    m_bIsInMove(false),
    m_bIsInDrag(false),
    m_bOldIdle(false),
    m_bOldIdleSet(false),
    m_bChainMode(false),
    m_bWasShdwCursor(false),
    m_bLockInput(false),
    m_bIsRowDrag(false),
    m_bUseInputLanguage(false),
    m_bObjectSelect(false),
    mbIsDragSidebar(false),
    m_nKS_NUMDOWN_Count(0),
    m_nKS_NUMINDENTINC_Count(0),
    m_pFrameControlsManager(new SwFrameControlsManager(this))
{
    set_id(u"writer_edit"_ustr);
    SetHelpId(HID_EDIT_WIN);
    EnableChildTransparentMode();
    SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
 
    m_bMBPressed = m_bInsDraw = m_bInsFrame =
    m_bIsInDrag = m_bOldIdle = m_bOldIdleSet = m_bChainMode = m_bWasShdwCursor = false;
    // initially use the input language
    m_bUseInputLanguage = true;
 
    SetMapMode(MapMode(MapUnit::MapTwip));
 
    SetPointer( PointerStyle::Text );
    m_aTimer.SetInvokeHandler(LINK(this, SwEditWin, TimerHandler));
 
    m_aKeyInputFlushTimer.SetTimeout( 20 );
    m_aKeyInputFlushTimer.SetInvokeHandler(LINK(this, SwEditWin, KeyInputFlushHandler));
 
    // TemplatePointer for colors should be reset without
    // selection after single click, but not after double-click (tdf#122442)
    m_aTemplateTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
    m_aTemplateTimer.SetInvokeHandler(LINK(this, SwEditWin, TemplateTimerHdl));
 
    // temporary solution!!! Should set the font of the current
    // insert position at every cursor movement!
    if( !rMyView.GetDocShell()->IsReadOnly() )
    {
        SetInputContext( InputContext(vcl::Font(), InputContextFlags::Text |
                                            InputContextFlags::ExtText ) );
    }
}
 
SwEditWin::~SwEditWin()
{
    disposeOnce();
}
 
void SwEditWin::dispose()
{
    m_pShadCursor.reset();
 
    if( s_pQuickHlpData->m_bIsDisplayed && m_rView.GetWrtShellPtr() )
        s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
    g_bExecuteDrag = false;
    m_pApplyTempl.reset();
 
    m_rView.SetDrawFuncPtr(nullptr);
 
    m_pUserMarker.reset();
 
    m_pAnchorMarker.reset();
 
    m_pFrameControlsManager->dispose();
    m_pFrameControlsManager.reset();
 
    DragSourceHelper::dispose();
    DropTargetHelper::dispose();
    vcl::Window::dispose();
}
 
/**
 * Turn on DrawTextEditMode
 */
void SwEditWin::EnterDrawTextMode( const Point& aDocPos )
{
    if ( m_rView.EnterDrawTextMode(aDocPos) )
    {
        if (m_rView.GetDrawFuncPtr())
        {
            m_rView.GetDrawFuncPtr()->Deactivate();
            m_rView.SetDrawFuncPtr(nullptr);
            m_rView.LeaveDrawCreate();
        }
        m_rView.NoRotate();
        m_rView.AttrChangedNotify(nullptr);
    }
}
 
/**
 * Turn on DrawMode
 */
bool SwEditWin::EnterDrawMode(const MouseEvent& rMEvt, const Point& aDocPos)
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    SdrView *pSdrView = rSh.GetDrawView();
 
    if ( m_rView.GetDrawFuncPtr() )
    {
        if (rSh.IsDrawCreate())
            return true;
 
        bool bRet = m_rView.GetDrawFuncPtr()->MouseButtonDown( rMEvt );
        m_rView.AttrChangedNotify(nullptr);
        return bRet;
    }
 
    if ( pSdrView && pSdrView->IsTextEdit() )
    {
        bool bUnLockView = !rSh.IsViewLocked();
        rSh.LockView( true );
 
        rSh.EndTextEdit(); // clicked aside, end Edit
        rSh.SelectObj( aDocPos );
        if ( !rSh.IsObjSelected() && !rSh.IsFrameSelected() )
            rSh.LeaveSelFrameMode();
        else
        {
            SwEditWin::s_nDDStartPosY = aDocPos.Y();
            SwEditWin::s_nDDStartPosX = aDocPos.X();
            g_bFrameDrag = true;
        }
        if( bUnLockView )
            rSh.LockView( false );
        m_rView.AttrChangedNotify(nullptr);
        return true;
    }
    return false;
}
 
bool SwEditWin::IsDrawSelMode() const
{
    return IsObjectSelect();
}
 
void SwEditWin::GetFocus()
{
    if ( m_rView.GetPostItMgr()->HasActiveSidebarWin() )
    {
        m_rView.GetPostItMgr()->GrabFocusOnActiveSidebarWin();
    }
    else
    {
        m_rView.GotFocus();
        Window::GetFocus();
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
        m_rView.GetWrtShell().InvalidateAccessibleFocus();
#endif
    }
}
 
void SwEditWin::LoseFocus()
{
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    if (m_rView.GetWrtShellPtr())
        m_rView.GetWrtShell().InvalidateAccessibleFocus();
#endif
    Window::LoseFocus();
    if( s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed )
        s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
}
 
bool SwEditWin::IsViewReadonly() const
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    return (m_rView.GetDocShell()->IsReadOnly() && rSh.IsCursorReadonly()) || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
}
 
void SwEditWin::Command( const CommandEvent& rCEvt )
{
    if (isDisposed())
    {
        // If ViewFrame dies shortly, no popup anymore!
        Window::Command(rCEvt);
        return;
    }
 
    SwWrtShell &rSh = m_rView.GetWrtShell();
 
    // The command event is send to the window after a possible context
    // menu from an inplace client has been closed. Now we have the chance
    // to deactivate the inplace client without any problem regarding parent
    // windows and code on the stack.
    SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
    bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
    if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu ))
    {
        rSh.FinishOLEObj();
        return;
    }
 
    bool bCallBase      = true;
 
    switch ( rCEvt.GetCommand() )
    {
    case CommandEventId::ContextMenu:
    {
            const sal_uInt16 nId = SwInputChild::GetChildWindowId();
            SwInputChild* pChildWin = static_cast<SwInputChild*>(GetView().GetViewFrame().
                                                GetChildWindow( nId ));
 
            if (m_rView.GetPostItMgr()->IsHit(rCEvt.GetMousePosPixel()))
                return;
 
            Point aDocPos( PixelToLogic( rCEvt.GetMousePosPixel() ) );
            if ( !rCEvt.IsMouseEvent() )
                aDocPos = rSh.GetCharRect().Center();
 
            // Don't trigger the command on a frame anchored to header/footer is not editing it
            FrameControlType eControl;
            bool bOverFly = false;
            bool bPageAnchored = false;
            bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
            // !bOverHeaderFooterFly doesn't mean we have a frame to select
            if ( !bPageAnchored && rCEvt.IsMouseEvent( ) &&
                 ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
                   ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
            {
                return;
            }
 
            if((!pChildWin || pChildWin->GetView() != &m_rView) &&
                !rSh.IsDrawCreate() && !IsDrawAction())
            {
                CurrShell aCurr( &rSh );
                if (!m_pApplyTempl)
                {
                    if (g_bNoInterrupt)
                    {
                        ReleaseMouse();
                        g_bNoInterrupt = false;
                        m_bMBPressed = false;
                    }
                    if ( rCEvt.IsMouseEvent() )
                    {
                        SelectMenuPosition(rSh, rCEvt.GetMousePosPixel());
                        m_rView.StopShellTimer();
                    }
                    const Point aPixPos = LogicToPixel( aDocPos );
 
                    if ( m_rView.GetDocShell()->IsReadOnly() )
                    {
                        SwReadOnlyPopup aROPopup(aDocPos, m_rView);
 
                        ui::ContextMenuExecuteEvent aEvent;
                        aEvent.SourceWindow = VCLUnoHelper::GetInterface( this );
                        aEvent.ExecutePosition.X = aPixPos.X();
                        aEvent.ExecutePosition.Y = aPixPos.Y();
                        rtl::Reference<VCLXPopupMenu> xMenu;
                        rtl::Reference<VCLXPopupMenu> xMenuInterface = aROPopup.CreateMenuInterface();
                        if (GetView().TryContextMenuInterception(xMenuInterface, u"private:resource/ReadonlyContextMenu"_ustr, xMenu, aEvent))
                        {
                            if (xMenu.is())
                            {
                                css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
                                sal_uInt16 nExecId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1),
                                                                    css::awt::PopupMenuDirection::EXECUTE_DOWN);
                                if (!::ExecuteMenuCommand(xMenu, m_rView.GetViewFrame(), nExecId))
                                    aROPopup.Execute(this, nExecId);
                            }
                            else
                                aROPopup.Execute(this, aPixPos);
                        }
                    }
                    else if ( !m_rView.ExecSpellPopup( aDocPos ) )
                        SfxDispatcher::ExecutePopup(this, &aPixPos);
                }
                else if (m_pApplyTempl->nUndo < rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount())
                {
                    // Undo until we reach the point when we entered this context.
                    rSh.Do(SwWrtShell::UNDO);
                }
                bCallBase = false;
            }
    }
    break;
 
    case CommandEventId::Wheel:
    case CommandEventId::StartAutoScroll:
    case CommandEventId::AutoScroll:
            if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
            {
                GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
                m_pSavedOutlineFrame = nullptr;
            }
            m_pShadCursor.reset();
            bCallBase = !m_rView.HandleWheelCommands( rCEvt );
            break;
 
    case CommandEventId::GestureZoom:
    {
        if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
        {
            GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
            m_pSavedOutlineFrame = nullptr;
        }
        m_pShadCursor.reset();
        bCallBase = !m_rView.HandleGestureZoomCommand(rCEvt);
        break;
    }
 
    case CommandEventId::GesturePan:
    {
        if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
        {
            GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
            m_pSavedOutlineFrame = nullptr;
        }
        m_pShadCursor.reset();
        bCallBase = !m_rView.HandleGesturePanCommand(rCEvt);
        break;
    }
 
    case CommandEventId::GestureLongPress:
    case CommandEventId::GestureSwipe: //nothing yet
            break;
 
    case CommandEventId::StartExtTextInput:
    {
        bool bIsViewReadOnly = IsViewReadonly();
        if(!bIsViewReadOnly)
        {
            if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
            {
                bCallBase = false;
                rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
            }
            else
            {
                if( rSh.HasSelection() )
                    rSh.DelRight();
 
                bCallBase = false;
                LanguageType eInputLanguage = GetInputLanguage();
                rSh.CreateExtTextInput(eInputLanguage);
            }
        }
        break;
    }
    case CommandEventId::EndExtTextInput:
    {
        bool bIsViewReadOnly = IsViewReadonly();
 
        if(!bIsViewReadOnly)
        {
            if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
            {
                bCallBase = false;
                rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
            }
            else
            {
                bCallBase = false;
                OUString sRecord = rSh.DeleteExtTextInput();
                uno::Reference< frame::XDispatchRecorder > xRecorder =
                        m_rView.GetViewFrame().GetBindings().GetRecorder();
 
                if ( !sRecord.isEmpty() )
                {
                    // convert quotes in IME text
                    // works on the last input character, this is especially in Korean text often done
                    // quotes that are inside of the string are not replaced!
                    const sal_Unicode aCh = sRecord[sRecord.getLength() - 1];
                    SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
                    SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
                    if(pACorr &&
                        (( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
                        ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
                    {
                        rSh.DelLeft();
                        rSh.AutoCorrect( *pACorr, aCh );
                    }
 
                    if ( xRecorder.is() )
                    {
                        // determine Shell
                        SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
                        // generate request and record
                        if (pSfxShell)
                        {
                            SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
                            aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, sRecord ) );
                            aReq.Done();
                        }
                    }
                }
            }
        }
    }
    break;
    case CommandEventId::ExtTextInput:
    {
        bool bIsViewReadOnly = IsViewReadonly();
 
        if (!bIsViewReadOnly && !rSh.HasReadonlySel())
        {
            if( s_pQuickHlpData->m_bIsDisplayed )
                s_pQuickHlpData->Stop( rSh );
 
            if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
            {
                bCallBase = false;
                rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
            }
            else
            {
                const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
                if( pData )
                {
                    bCallBase = false;
                    rSh.SetExtTextInputData( *pData );
                }
            }
            uno::Reference< frame::XDispatchRecorder > xRecorder =
                        m_rView.GetViewFrame().GetBindings().GetRecorder();
            if(!xRecorder.is())
            {
                SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
                if (!rACfg.IsAutoTextTip() || !ShowAutoText(rSh.GetChunkForAutoText()))
                {
                    SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
                    if (pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
                        ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
                }
            }
        }
 
        if (rSh.HasReadonlySel())
        {
            // Inform the user that the request has been ignored.
            rSh.InfoReadOnlyDialog(true);
        }
    }
    break;
    case CommandEventId::CursorPos:
        // will be handled by the base class
        break;
 
    case CommandEventId::PasteSelection:
        if( !m_rView.GetDocShell()->IsReadOnly() )
        {
            TransferableDataHelper aDataHelper(
                        TransferableDataHelper::CreateFromPrimarySelection());
            if( !aDataHelper.GetXTransferable().is() )
                break;
 
            SotExchangeDest nDropDestination = GetDropDestination( rCEvt.GetMousePosPixel() );
            if( nDropDestination == SotExchangeDest::NONE )
                break;
            SotClipboardFormatId nDropFormat;
            sal_uInt8 nEventAction, nDropAction;
            SotExchangeActionFlags nActionFlags;
            nDropAction = SotExchange::GetExchangeAction(
                                aDataHelper.GetDataFlavorExVector(),
                                nDropDestination, EXCHG_IN_ACTION_COPY,
                                EXCHG_IN_ACTION_COPY, nDropFormat,
                                nEventAction,
                                SotClipboardFormatId::NONE, nullptr,
                                &nActionFlags );
            if( EXCHG_INOUT_ACTION_NONE != nDropAction )
            {
                const Point aDocPt( PixelToLogic( rCEvt.GetMousePosPixel() ) );
                SwTransferable::PasteData( aDataHelper, rSh, nDropAction, nActionFlags,
                                    nDropFormat, nDropDestination, false,
                                    false, &aDocPt, EXCHG_IN_ACTION_COPY,
                                    true );
            }
        }
        break;
        case CommandEventId::ModKeyChange :
        {
            const CommandModKeyData* pCommandData = rCEvt.GetModKeyData();
            if (!pCommandData->IsDown() && pCommandData->IsMod1() && !pCommandData->IsMod2())
            {
                sal_uInt16 nSlot = 0;
                if(pCommandData->IsLeftShift() && !pCommandData->IsRightShift())
                    nSlot = SID_ATTR_PARA_LEFT_TO_RIGHT;
                else if(!pCommandData->IsLeftShift() && pCommandData->IsRightShift())
                    nSlot = SID_ATTR_PARA_RIGHT_TO_LEFT;
                if(nSlot && SvtCTLOptions::IsCTLFontEnabled())
                    GetView().GetViewFrame().GetDispatcher()->Execute(nSlot);
            }
        }
        break;
        case CommandEventId::InputLanguageChange :
            // i#42732 - update state of fontname if input language changes
            g_bInputLanguageSwitched = true;
            SetUseInputLanguage( true );
        break;
        case CommandEventId::SelectionChange:
        {
            const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
            rSh.SttCursorMove();
            rSh.GoStartSentence();
            rSh.GetCursor()->GetPoint()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetStart()));
            rSh.SetMark();
            rSh.GetCursor()->GetMark()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetEnd() - pData->GetStart()));
            rSh.EndCursorMove( true );
        }
        break;
        case CommandEventId::PrepareReconversion:
        if( rSh.HasSelection() )
        {
            SwPaM *pCursor = rSh.GetCursor();
 
            if( rSh.IsMultiSelection() )
            {
                if (pCursor && !pCursor->HasMark() &&
                    pCursor->GetPoint() == pCursor->GetMark())
                {
                    rSh.GoPrevCursor();
                    pCursor = rSh.GetCursor();
                }
 
                // Cancel all selections other than the last selected one.
                while( rSh.GetCursor()->GetNext() != rSh.GetCursor() )
                    delete rSh.GetCursor()->GetNext();
            }
 
            if( pCursor )
            {
                SwNodeOffset nPosNodeIdx = pCursor->GetPoint()->GetNodeIndex();
                const sal_Int32 nPosIdx = pCursor->GetPoint()->GetContentIndex();
                SwNodeOffset nMarkNodeIdx = pCursor->GetMark()->GetNodeIndex();
                const sal_Int32 nMarkIdx = pCursor->GetMark()->GetContentIndex();
 
                if( !rSh.GetCursor()->HasMark() )
                    rSh.GetCursor()->SetMark();
 
                rSh.SttCursorMove();
 
                if( nPosNodeIdx < nMarkNodeIdx )
                {
                    rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
                    rSh.GetCursor()->GetMark()->Assign(nPosNodeIdx,
                        rSh.GetCursor()->GetPointContentNode()->Len());
                }
                else if( nPosNodeIdx == nMarkNodeIdx )
                {
                    rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
                    rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
                }
                else
                {
                    rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
                    rSh.GetCursor()->GetPoint()->Assign(nMarkNodeIdx,
                        rSh.GetCursor()->GetMarkContentNode()->Len());
                }
 
                rSh.EndCursorMove( true );
            }
        }
        break;
        case CommandEventId::QueryCharPosition:
        {
            bool bVertical = rSh.IsInVerticalText();
            const SwPosition& rPos = *rSh.GetCursor()->GetPoint();
            SwDocShell* pDocSh = m_rView.GetDocShell();
            SwDoc *pDoc = pDocSh->GetDoc();
            SwExtTextInput* pInput = pDoc->GetExtTextInput( rPos.GetNode(), rPos.GetContentIndex() );
            if ( pInput )
            {
                const SwPosition& rStart = *pInput->Start();
                const SwPosition& rEnd = *pInput->End();
                sal_Int32 nSize = rEnd.GetContentIndex() - rStart.GetContentIndex();
                vcl::Window& rWin = rSh.GetView().GetEditWin();
                if ( nSize == 0 )
                {
                    // When the composition does not exist, use Caret rect instead.
                    const SwRect& aCaretRect ( rSh.GetCharRect() );
                    tools::Rectangle aRect( aCaretRect.Left(), aCaretRect.Top(), aCaretRect.Right(), aCaretRect.Bottom() );
                    rWin.SetCompositionCharRect( &aRect, 1, bVertical );
                }
                else
                {
                    std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ nSize ]);
                    int nRectIndex = 0;
                    for ( sal_Int32 nIndex = rStart.GetContentIndex(); nIndex < rEnd.GetContentIndex(); ++nIndex )
                    {
                        const SwPosition aPos( rStart.GetNode(), rStart.GetNode().GetContentNode(), nIndex );
                        SwRect aRect ( rSh.GetCharRect() );
                        rSh.GetCharRectAt( aRect, &aPos );
                        aRects[ nRectIndex ] = tools::Rectangle( aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom() );
                        ++nRectIndex;
                    }
                    rWin.SetCompositionCharRect( aRects.get(), nSize, bVertical );
                }
            }
            bCallBase = false;
        }
        break;
        default:
            SAL_WARN("sw.ui", "unknown command.");
        break;
    }
    if (bCallBase)
        Window::Command(rCEvt);
}
 
/*  i#18686 select the object/cursor at the mouse
    position of the context menu request */
void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const Point& rMousePos )
{
    const Point aDocPos( PixelToLogic( rMousePos ) );
    const bool bIsInsideSelectedObj( rSh.IsInsideSelectedObj( aDocPos ) );
    //create a synthetic mouse event out of the coordinates
    MouseEvent aMEvt(rMousePos);
    SdrView *pSdrView = rSh.GetDrawView();
    if ( pSdrView )
    {
        // no close of insert_draw and reset of
        // draw mode, if context menu position is inside a selected object.
        if ( !bIsInsideSelectedObj && m_rView.GetDrawFuncPtr() )
        {
 
            m_rView.GetDrawFuncPtr()->Deactivate();
            m_rView.SetDrawFuncPtr(nullptr);
            m_rView.LeaveDrawCreate();
            SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
            rBind.Invalidate( SID_ATTR_SIZE );
            rBind.Invalidate( SID_TABLE_CELL );
        }
 
        // if draw text is active and there's a text selection
        // at the mouse position then do nothing
        if(rSh.GetSelectionType() & SelectionType::DrawObjectEditMode)
        {
            OutlinerView* pOLV = pSdrView->GetTextEditOutlinerView();
            ESelection aSelection = pOLV->GetSelection();
            if(!aSelection.IsZero())
            {
                SdrOutliner* pOutliner = pSdrView->GetTextEditOutliner();
                bool bVertical = pOutliner->IsVertical();
                const EditEngine& rEditEng = pOutliner->GetEditEngine();
                Point aEEPos(aDocPos);
                const tools::Rectangle& rOutputArea = pOLV->GetOutputArea();
                // regard vertical mode
                if(bVertical)
                {
                    aEEPos -= rOutputArea.TopRight();
                    //invert the horizontal direction and exchange X and Y
                    tools::Long nTemp = -aEEPos.X();
                    aEEPos.setX( aEEPos.Y() );
                    aEEPos.setY( nTemp );
                }
                else
                    aEEPos -= rOutputArea.TopLeft();
 
                EPosition aDocPosition = rEditEng.FindDocPosition(aEEPos);
                ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
                // make it a forward selection - otherwise the IsLess/IsGreater do not work :-(
                aSelection.Adjust();
                if(!(aCompare < aSelection) && !(aCompare > aSelection))
                {
                    return;
                }
            }
 
        }
 
        if (pSdrView->MouseButtonDown( aMEvt, GetOutDev() ) )
        {
            pSdrView->MouseButtonUp( aMEvt, GetOutDev() );
            rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
            return;
        }
    }
    rSh.ResetCursorStack();
 
    if ( EnterDrawMode( aMEvt, aDocPos ) )
    {
        return;
    }
    if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
    {
        StopInsFrame();
        rSh.Edit();
    }
 
    UpdatePointer( aDocPos );
 
    if( !rSh.IsSelFrameMode() &&
        !GetView().GetViewFrame().GetDispatcher()->IsLocked() )
    {
        // Test if there is a draw object at that position and if it should be selected.
        bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
 
        if(bShould)
        {
            m_rView.NoRotate();
            rSh.HideCursor();
 
            bool bUnLockView = !rSh.IsViewLocked();
            rSh.LockView( true );
            bool bSelObj = rSh.SelectObj( aDocPos );
            if( bUnLockView )
                rSh.LockView( false );
 
            if( bSelObj )
            {
                // in case the frame was deselected in the macro
                // just the cursor has to be displayed again.
                if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
                    rSh.ShowCursor();
                else
                {
                    if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
                    {
                        m_rView.GetDrawFuncPtr()->Deactivate();
                        m_rView.SetDrawFuncPtr(nullptr);
                        m_rView.LeaveDrawCreate();
                        m_rView.AttrChangedNotify(nullptr);
                    }
 
                    rSh.EnterSelFrameMode( &aDocPos );
                    g_bFrameDrag = true;
                    UpdatePointer( aDocPos );
                    return;
                }
            }
 
            if (!m_rView.GetDrawFuncPtr())
                rSh.ShowCursor();
        }
    }
    else if ( rSh.IsSelFrameMode() &&
              (m_aActHitType == SdrHitKind::NONE ||
               !bIsInsideSelectedObj))
    {
        m_rView.NoRotate();
        bool bUnLockView = !rSh.IsViewLocked();
        rSh.LockView( true );
 
        if ( rSh.IsSelFrameMode() )
        {
            rSh.UnSelectFrame();
            rSh.LeaveSelFrameMode();
            m_rView.AttrChangedNotify(nullptr);
        }
 
        bool bSelObj = rSh.SelectObj( aDocPos, 0/*nFlag*/ );
        if( bUnLockView )
            rSh.LockView( false );
 
        if( !bSelObj )
        {
            // move cursor here so that it is not drawn in the
            // frame at first; ShowCursor() happens in LeaveSelFrameMode()
            g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
            rSh.LeaveSelFrameMode();
            m_rView.LeaveDrawCreate();
            m_rView.AttrChangedNotify(nullptr);
        }
        else
        {
            rSh.HideCursor();
            rSh.EnterSelFrameMode( &aDocPos );
            rSh.SelFlyGrabCursor();
            rSh.MakeSelVisible();
            g_bFrameDrag = true;
            if( rSh.IsFrameSelected() &&
                m_rView.GetDrawFuncPtr() )
            {
                m_rView.GetDrawFuncPtr()->Deactivate();
                m_rView.SetDrawFuncPtr(nullptr);
                m_rView.LeaveDrawCreate();
                m_rView.AttrChangedNotify(nullptr);
            }
            UpdatePointer( aDocPos );
        }
    }
    else if ( rSh.IsSelFrameMode() && bIsInsideSelectedObj )
    {
        // Object at the mouse cursor is already selected - do nothing
        return;
    }
 
    if ( rSh.IsGCAttr() )
    {
        rSh.GCAttr();
        rSh.ClearGCAttr();
    }
 
    bool bOverSelect = rSh.TestCurrPam( aDocPos );
    bool bOverURLGrf = false;
    if( !bOverSelect )
        bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
 
    if ( !bOverSelect )
    {
        // create only temporary move context because otherwise
        // the query against the content form doesn't work!!!
        SwMvContext aMvContext( &rSh );
        if (rSh.HasSelection())
            rSh.ResetSelect(&aDocPos, false);
        rSh.SwCursorShell::SetCursor(aDocPos, false, /*Block=*/false, /*FieldInfo=*/true);
    }
    if( !bOverURLGrf )
    {
        const SelectionType nSelType = rSh.GetSelectionType();
        if( nSelType == SelectionType::Ole ||
            nSelType == SelectionType::Graphic )
        {
            SwMvContext aMvContext( &rSh );
            if( !rSh.IsFrameSelected() )
                rSh.GotoNextFly();
            rSh.EnterSelFrameMode();
        }
    }
}
 
void SwEditWin::DrawCommentGuideLine(Point aPointPixel)
{
    const Point aPointLogic = PixelToLogic(aPointPixel);
 
    sw::sidebarwindows::SidebarPosition eSidebarPosition
        = m_rView.GetPostItMgr()->GetSidebarPos(aPointLogic);
    if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::NONE) // should never happen
        return;
 
    tools::Long nPosX;
    sal_uInt16 nZoom = m_rView.GetWrtShell().GetViewOptions()->GetZoom();
    if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::RIGHT)
    {
        tools::Long nSidebarRectLeft
            = LogicToPixel(m_rView.GetPostItMgr()->GetSidebarRect(aPointLogic).TopLeft()).X();
        tools::Long nPxWidth = aPointPixel.X() - nSidebarRectLeft;
        nPosX = nSidebarRectLeft + std::clamp<tools::Long>(nPxWidth, 1 * nZoom, 8 * nZoom);
    }
    else
    {
        tools::Long nSidebarRectRight
            = LogicToPixel(m_rView.GetPostItMgr()->GetSidebarRect(aPointLogic).TopRight()).X();
        tools::Long nPxWidth = nSidebarRectRight - aPointPixel.X();
        nPosX = nSidebarRectRight - std::clamp<tools::Long>(nPxWidth, 1 * nZoom, 8 * nZoom);
    }
 
 
    // We need two InvertTracking calls here to "erase" the previous and draw the new position at each mouse move
    InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split);
    const tools::Long nHeight = GetOutDev()->GetOutputSizePixel().Height();
    aLastCommentSidebarPos
        = tools::Rectangle(PixelToLogic(Point(nPosX, 0)), PixelToLogic(Point(nPosX, nHeight)));
    InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split);
}
 
void SwEditWin::ReleaseCommentGuideLine()
{
    InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split);
    aLastCommentSidebarPos = tools::Rectangle();
    mbIsDragSidebar = false;
}
 
void SwEditWin::SetSidebarWidth(const Point& rPointPixel)
{
    if (aLastCommentSidebarPos.IsEmpty())
        return;
    // aLastCommentSidebarPos right and left positions are the same so either can be used here
    m_rView.GetPostItMgr()->SetSidebarWidth(
        Point(aLastCommentSidebarPos.Right(), PixelToLogic(rPointPixel).Y()));
}
 
static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView )
{
    // determine Shell
    SfxShell* pShell;
    SfxDispatcher* pDispatcher = rView.GetViewFrame().GetDispatcher();
    for(sal_uInt16  i = 0; true; ++i )
    {
        pShell = pDispatcher->GetShell( i );
        if( !pShell || dynamic_cast< const SwTextShell *>( pShell ) !=  nullptr )
            break;
    }
    return pShell;
}
 
IMPL_LINK_NOARG(SwEditWin, KeyInputFlushHandler, Timer *, void)
{
    FlushInBuffer();
}
 
void SwEditWin::InitStaticData()
{
    s_pQuickHlpData = new QuickHelpData();
}
 
void SwEditWin::FinitStaticData()
{
    delete s_pQuickHlpData;
}
/* i#3370 - remove quick help to prevent saving
 * of autocorrection suggestions */
void SwEditWin::StopQuickHelp()
{
    if( HasFocus() && s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed  )
        s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
}
 
IMPL_LINK_NOARG(SwEditWin, TemplateTimerHdl, Timer *, void)
{
    SetApplyTemplate(SwApplyTemplate());
}
 
void SwEditWin::SetChainMode( bool bOn )
{
    if ( !m_bChainMode )
        StopInsFrame();
 
    m_pUserMarker.reset();
 
    m_bChainMode = bOn;
 
    static sal_uInt16 aInva[] =
    {
        FN_FRAME_CHAIN, FN_FRAME_UNCHAIN, 0
    };
    m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
}
 
uno::Reference< css::accessibility::XAccessible > SwEditWin::CreateAccessible()
{
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
    SolarMutexGuard aGuard;   // this should have happened already!!!
    SwWrtShell *pSh = m_rView.GetWrtShellPtr();
    OSL_ENSURE( pSh, "no writer shell, no accessible object" );
    uno::Reference<
        css::accessibility::XAccessible > xAcc;
    if( pSh )
        xAcc = pSh->CreateAccessible();
 
    return xAcc;
#else
    return nullptr;
#endif
}
 
void QuickHelpData::Move( QuickHelpData& rCpy )
{
    m_aHelpStrings.clear();
    m_aHelpStrings.swap( rCpy.m_aHelpStrings );
 
    m_bIsDisplayed = rCpy.m_bIsDisplayed;
    nCurArrPos = rCpy.nCurArrPos;
    m_bAppendSpace = rCpy.m_bAppendSpace;
    m_bIsTip = rCpy.m_bIsTip;
    m_bIsAutoText = rCpy.m_bIsAutoText;
}
 
void QuickHelpData::ClearContent()
{
    nCurArrPos = nNoPos;
    m_bIsDisplayed = m_bAppendSpace = false;
    nTipId = nullptr;
    m_aHelpStrings.clear();
    m_bIsTip = true;
    m_bIsAutoText = true;
}
 
void QuickHelpData::Start(SwWrtShell& rSh, const bool bRestart)
{
    if (bRestart)
    {
        nCurArrPos = 0;
    }
    m_bIsDisplayed = true;
 
    vcl::Window& rWin = rSh.GetView().GetEditWin();
    if( m_bIsTip )
    {
        Point aPt( rWin.OutputToScreenPixel( rWin.LogicToPixel(
                    rSh.GetCharRect().Pos() )));
        aPt.AdjustY( -3 );
        nTipId = Help::ShowPopover(&rWin, tools::Rectangle( aPt, Size( 1, 1 )),
                        CurStr(),
                        QuickHelpFlags::Left | QuickHelpFlags::Bottom);
    }
    else
    {
        OUString sStr(CurStr());
        sStr = sStr.copy(CurLen());
        sal_uInt16 nL = sStr.getLength();
        const ExtTextInputAttr nVal = ExtTextInputAttr::DottedUnderline |
                                ExtTextInputAttr::Highlight;
        const std::vector<ExtTextInputAttr> aAttrs( nL, nVal );
        CommandExtTextInputData aCETID( sStr, aAttrs.data(), nL,
                                        0, false );
 
        //fdo#33092. If the current input language is the default
        //language that text would appear in if typed, then don't
        //force a language on for the ExtTextInput.
        LanguageType eInputLanguage = rWin.GetInputLanguage();
        if (lcl_isNonDefaultLanguage(eInputLanguage,
            rSh.GetView(), sStr) == INVALID_HINT)
        {
            eInputLanguage = LANGUAGE_DONTKNOW;
        }
 
        rSh.CreateExtTextInput(eInputLanguage);
        rSh.SetExtTextInputData( aCETID );
    }
}
 
void QuickHelpData::Stop( SwWrtShell& rSh )
{
    if( !m_bIsTip )
        rSh.DeleteExtTextInput( false );
    else if( nTipId )
    {
        vcl::Window& rWin = rSh.GetView().GetEditWin();
        Help::HidePopover(&rWin, nTipId);
    }
    ClearContent();
}
 
void QuickHelpData::FillStrArr( SwWrtShell const & rSh, const OUString& rWord )
{
    enum Capitalization { CASE_LOWER, CASE_UPPER, CASE_SENTENCE, CASE_OTHER };
 
    // Determine word capitalization
    const CharClass& rCC = GetAppCharClass();
    const OUString sWordLower = rCC.lowercase( rWord );
    Capitalization aWordCase = CASE_OTHER;
    if ( !rWord.isEmpty() )
    {
        if ( rWord[0] == sWordLower[0] )
        {
            if ( rWord == sWordLower )
                aWordCase = CASE_LOWER;
        }
        else
        {
            // First character is not lower case i.e. assume upper or title case
            OUString sWordSentence = sWordLower.replaceAt( 0, 1, rtl::OUStringChar(rWord[0]) );
            if ( rWord == sWordSentence )
                aWordCase = CASE_SENTENCE;
            else
            {
                if ( rWord == rCC.uppercase( rWord ) )
                    aWordCase = CASE_UPPER;
            }
        }
    }
 
    SwCalendarWrapper& rCalendar = s_getCalendarWrapper();
    rCalendar.LoadDefaultCalendar( rSh.GetCurLang() );
 
    // Add matching calendar month and day names
    for ( const auto& aNames : { rCalendar.getMonths(), rCalendar.getDays() } )
    {
        for ( const auto& rName : aNames )
        {
            const OUString& rStr( rName.FullName );
            // Check string longer than word and case insensitive match
            if( rStr.getLength() > rWord.getLength() &&
                rCC.lowercase( rStr, 0, rWord.getLength() ) == sWordLower )
            {
                OUString sStr;
 
                //fdo#61251 if it's an exact match, ensure unchanged replacement
                //exists as a candidate
                if (rStr.startsWith(rWord))
                    m_aHelpStrings.emplace_back(rStr, rWord.getLength());
                else
                    sStr = rStr; // to be added if no case conversion is performed below
 
                if ( aWordCase == CASE_LOWER )
                    sStr = rCC.lowercase(rStr);
                else if ( aWordCase == CASE_SENTENCE )
                    sStr = rCC.lowercase(rStr).replaceAt(0, 1, rtl::OUStringChar(rStr[0]));
                else if ( aWordCase == CASE_UPPER )
                    sStr = rCC.uppercase(rStr);
 
                if (!sStr.isEmpty())
                    m_aHelpStrings.emplace_back(sStr, rWord.getLength());
            }
        }
    }
 
    // Add matching current date in ISO 8601 format, for example 2016-01-30
    OUString rStrToday;
 
    // do not suggest for single years, for example for "2016",
    // only for "201" or "2016-..." (to avoid unintentional text
    // insertion at line ending, for example typing "30 January 2016")
    if (!rWord.isEmpty() && rWord.getLength() != 4 && rWord[0] == '2')
    {
        rStrToday = utl::toISO8601(DateTime(Date(Date::SYSTEM)).GetUNODateTime());
        if (rStrToday.startsWith(rWord))
            m_aHelpStrings.emplace_back(rStrToday, rWord.getLength());
    }
 
    // Add matching words from AutoCompleteWord list
    const SwAutoCompleteWord& rACList = SwEditShell::GetAutoCompleteWords();
    std::vector<OUString> strings;
 
    if ( !rACList.GetWordsMatching( rWord, strings ) )
        return;
 
    for (const OUString & aCompletedString : strings)
    {
        // when we have a matching current date, avoid to suggest
        // other words with the same matching starting characters,
        // for example 2016-01-3 instead of 2016-01-30
        if (!rStrToday.isEmpty() && aCompletedString.startsWith(rWord))
            continue;
 
        OUString sStr;
 
        //fdo#61251 if it's an exact match, ensure unchanged replacement
        //exists as a candidate
        if (aCompletedString.startsWith(rWord))
            m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
        else
            sStr = aCompletedString; // to be added if no case conversion is performed below
 
        if (aWordCase == CASE_LOWER)
            sStr = rCC.lowercase(aCompletedString);
        else if (aWordCase == CASE_SENTENCE)
            sStr = rCC.lowercase(aCompletedString)
                       .replaceAt(0, 1, rtl::OUStringChar(aCompletedString[0]));
        else if (aWordCase == CASE_UPPER)
            sStr = rCC.uppercase(aCompletedString);
 
        if (!sStr.isEmpty())
            m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
    }
}
 
namespace {
 
class CompareIgnoreCaseAsciiFavorExact
{
    const OUString &m_rOrigWord;
public:
    explicit CompareIgnoreCaseAsciiFavorExact(const OUString& rOrigWord)
        : m_rOrigWord(rOrigWord)
    {
    }
 
    bool operator()(const std::pair<OUString, sal_uInt16>& s1,
                    const std::pair<OUString, sal_uInt16>& s2) const
    {
        int nRet = s1.first.compareToIgnoreAsciiCase(s2.first);
        if (nRet == 0)
        {
            //fdo#61251 sort stuff that starts with the exact rOrigWord before
            //another ignore-case candidate
            int n1StartsWithOrig = s1.first.startsWith(m_rOrigWord) ? 0 : 1;
            int n2StartsWithOrig = s2.first.startsWith(m_rOrigWord) ? 0 : 1;
            return n1StartsWithOrig < n2StartsWithOrig;
        }
        return nRet < 0;
    }
};
 
struct EqualIgnoreCaseAscii
{
    bool operator()(const std::pair<OUString, sal_uInt16>& s1,
                    const std::pair<OUString, sal_uInt16>& s2) const
    {
        return s1.first.equalsIgnoreAsciiCase(s2.first);
    }
};
 
} // anonymous namespace
 
// TODO Implement an i18n aware sort
void QuickHelpData::SortAndFilter(const OUString &rOrigWord)
{
    std::sort( m_aHelpStrings.begin(),
               m_aHelpStrings.end(),
               CompareIgnoreCaseAsciiFavorExact(rOrigWord) );
 
    const auto it
        = std::unique(m_aHelpStrings.begin(), m_aHelpStrings.end(), EqualIgnoreCaseAscii());
    m_aHelpStrings.erase( it, m_aHelpStrings.end() );
 
    nCurArrPos = 0;
}
 
// For a given chunk of typed text between 3 and 9 characters long that may start at a word boundary
// or in a whitespace and may include whitespaces, SwEditShell::GetChunkForAutoTextcreates a list of
// possible candidates for long AutoText names. Let's say, we have typed text "lorem ipsum  dr f";
// and the cursor is right after the "f". SwEditShell::GetChunkForAutoText would take "  dr f",
// since it's the longest chunk to the left of the cursor no longer than 9 characters, not starting
// in the middle of a word. Then it would create this list from it (in this order, longest first):
//     "  dr f"
//      " dr f"
//       "dr f"
// It cannot add "r f", because it starts in the middle of the word "dr"; also it cannot give " f",
// because it's only 2 characters long.
// Now the result of SwEditShell::GetChunkForAutoText is passed here to SwEditWin::ShowAutoText, and
// then to SwGlossaryList::HasLongName, where all existing autotext entries' long names are tested
// if they start with one of the list elements. The matches are sorted according the position of the
// candidate that matched first, then alphabetically inside the group of suggestions for a given
// candidate. Say, if we have these AutoText entry long names:
//    "Dr Frodo"
//    "Dr Credo"
//    "Or Bilbo"
//    "dr foo"
//    "  Dr Fuzz"
//    " dr Faust"
// the resulting list would be:
//    "  Dr Fuzz" -> matches the first (longest) item in the candidates list
//    " dr Faust" -> matches the second candidate item
//    "Dr Foo" -> first item of the two matching the third candidate; alphabetically sorted
//    "Dr Frodo" -> second item of the two matching the third candidate; alphabetically sorted
// Each of the resulting suggestions knows the length of the candidate it replaces, so accepting the
// first suggestion would replace 6 characters before cursor, while tabbing to and accepting the
// last suggestion would replace only 4 characters to the left of cursor.
bool SwEditWin::ShowAutoText(const std::vector<OUString>& rChunkCandidates)
{
    s_pQuickHlpData->ClearContent();
    if (!rChunkCandidates.empty())
    {
        SwGlossaryList* pList = ::GetGlossaryList();
        pList->HasLongName(rChunkCandidates, s_pQuickHlpData->m_aHelpStrings);
    }
 
    if (!s_pQuickHlpData->m_aHelpStrings.empty())
    {
        s_pQuickHlpData->Start(m_rView.GetWrtShell(), true);
    }
    return !s_pQuickHlpData->m_aHelpStrings.empty();
}
 
void SwEditWin::ShowAutoCorrectQuickHelp(
        const OUString& rWord, SvxAutoCorrect& rACorr )
{
    if (rWord.isEmpty())
        return;
    SwWrtShell& rSh = m_rView.GetWrtShell();
    s_pQuickHlpData->ClearContent();
 
    if( s_pQuickHlpData->m_aHelpStrings.empty() &&
        rACorr.GetSwFlags().bAutoCompleteWords )
    {
        s_pQuickHlpData->m_bIsAutoText = false;
        s_pQuickHlpData->m_bIsTip = rACorr.GetSwFlags().bAutoCmpltShowAsTip;
 
        // Get the necessary data to show help text.
        s_pQuickHlpData->FillStrArr( rSh, rWord );
    }
 
    if( !s_pQuickHlpData->m_aHelpStrings.empty() )
    {
        s_pQuickHlpData->SortAndFilter(rWord);
        s_pQuickHlpData->Start(rSh, true);
    }
}
 
bool SwEditWin::IsInHeaderFooter( const Point &rDocPt, FrameControlType &rControl ) const
{
    SwWrtShell &rSh = m_rView.GetWrtShell();
    const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( rDocPt );
 
    if ( pPageFrame && pPageFrame->IsOverHeaderFooterArea( rDocPt, rControl ) )
        return true;
 
    if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) || rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
    {
        SwFrameControlsManager &rMgr = rSh.GetView().GetEditWin().GetFrameControlsManager();
        Point aPoint( LogicToPixel( rDocPt ) );
 
        if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) )
        {
            SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Header, pPageFrame );
            if ( pControl && pControl->Contains( aPoint ) )
            {
                rControl = FrameControlType::Header;
                return true;
            }
        }
 
        if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
        {
            SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Footer, pPageFrame );
            if ( pControl && pControl->Contains( aPoint ) )
            {
                rControl = FrameControlType::Footer;
                return true;
            }
        }
    }
 
    return false;
}
 
bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly, bool& bPageAnchored ) const
{
    bool bRet = false;
    Point aPt( rDocPos );
    SwWrtShell &rSh = m_rView.GetWrtShell();
    SwPaM aPam( *rSh.GetCurrentShellCursor().GetPoint() );
    rSh.GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aPt, nullptr, true );
 
    const SwStartNode* pStartFly = aPam.GetPoint()->GetNode().FindFlyStartNode();
    if ( pStartFly )
    {
        bOverFly = true;
        SwFrameFormat* pFlyFormat = pStartFly->GetFlyFormat( );
        if ( pFlyFormat )
        {
            const SwNode* pAnchorNode = pFlyFormat->GetAnchor( ).GetAnchorNode( );
            if ( pAnchorNode )
            {
                bool bInHeader = pAnchorNode->FindHeaderStartNode( ) != nullptr;
                bool bInFooter = pAnchorNode->FindFooterStartNode( ) != nullptr;
 
                bRet = bInHeader || bInFooter;
                if ( bInHeader )
                    rControl = FrameControlType::Header;
                else if ( bInFooter )
                    rControl = FrameControlType::Footer;
            }
            else
                bPageAnchored = pFlyFormat->GetAnchor( ).GetAnchorId( ) == RndStdIds::FLY_AT_PAGE;
        }
    }
    else
        bOverFly = false;
    return bRet;
}
 
void SwEditWin::SetUseInputLanguage( bool bNew )
{
    if ( bNew || m_bUseInputLanguage )
    {
        SfxBindings& rBind = GetView().GetViewFrame().GetBindings();
        rBind.Invalidate( SID_ATTR_CHAR_FONT );
        rBind.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
    }
    m_bUseInputLanguage = bNew;
}
 
OUString SwEditWin::GetSurroundingText() const
{
    SwWrtShell& rSh = m_rView.GetWrtShell();
 
    if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
        return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingText();
 
    OUString sReturn;
    if( rSh.HasSelection() && !rSh.IsMultiSelection() && rSh.IsSelOnePara() )
        rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
    else if( !rSh.HasSelection() )
    {
        bool bUnLockView = !rSh.IsViewLocked();
        rSh.LockView(true);
 
        // store shell state *before* Push
        ::std::optional<SwCallLink> aLink(std::in_place, rSh);
        rSh.Push();
 
        // disable accessible events for internal-only helper cursor
        const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
        rSh.SetSendAccessibleCursorEvents(false);
 
        // get the sentence around the cursor
        rSh.HideCursor();
        rSh.GoStartSentence();
        rSh.SetMark();
        rSh.GoEndSentence();
        rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
 
        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
        rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
        rSh.HideCursor();
 
        if (bUnLockView)
            rSh.LockView(false);
    }
 
    return sReturn;
}
 
Selection SwEditWin::GetSurroundingTextSelection() const
{
    SwWrtShell& rSh = m_rView.GetWrtShell();
 
    if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
        return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingTextSelection();
 
    Selection aSel(0, 0);
    if( rSh.HasSelection() )
    {
        OUString sReturn;
        rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
        aSel = Selection( 0, sReturn.getLength() );
    }
    else if (rSh.GetCursor()->GetPoint()->GetNode().GetTextNode())
    {
        bool bUnLockView = !rSh.IsViewLocked();
        rSh.LockView(true);
 
        // Return the position of the visible cursor in the sentence
        // around the visible cursor.
        TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
 
        // store shell state *before* Push
        ::std::optional<SwCallLink> aLink(std::in_place, rSh);
        rSh.Push();
 
        // disable accessible events for internal-only helper cursor
        const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
        rSh.SetSendAccessibleCursorEvents(false);
 
        rSh.HideCursor();
        rSh.GoStartSentence();
        TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
 
        rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
        rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
        rSh.ShowCursor();
 
        if (bUnLockView)
            rSh.LockView(false);
 
        aSel = Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
    }
 
    return aSel;
}
 
bool SwEditWin::DeleteSurroundingText(const Selection& rSelection)
{
    SwWrtShell& rSh = m_rView.GetWrtShell();
 
    if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
        return rSh.GetDrawView()->GetTextEditOutlinerView()->DeleteSurroundingText(rSelection);
 
    if (rSh.HasSelection())
        return false;
 
    // rSelection is relative to the start of the sentence, so find that and
    // adjust the range by it
    rSh.Push();
 
    // disable accessible events for internal-only helper cursor
    const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
    rSh.SetSendAccessibleCursorEvents(false);
 
    rSh.HideCursor();
    rSh.GoStartSentence();
    TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
 
    rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
    rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
    rSh.ShowCursor();
 
    if (rSh.SelectTextView(nStartPos + TextFrameIndex(rSelection.Min()), nStartPos + TextFrameIndex(rSelection.Max())))
    {
        rSh.Delete(false);
        return true;
    }
 
    return false;
}
 
void SwEditWin::LogicInvalidate(const tools::Rectangle* pRectangle)
{
    SfxLokHelper::notifyInvalidation(&m_rView, pRectangle);
}
 
void SwEditWin::SetCursorTwipPosition(const Point& rPosition, bool bPoint, bool bClearMark)
{
    if (SdrView* pSdrView = m_rView.GetWrtShell().GetDrawView())
    {
        // Editing shape text, then route the call to editeng.
        if (pSdrView->GetTextEditObject())
        {
            EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
            rEditView.SetCursorLogicPosition(rPosition, bPoint, bClearMark);
            return;
        }
    }
 
    if (m_rView.GetPostItMgr())
    {
        if (sw::annotation::SwAnnotationWin* pWin = m_rView.GetPostItMgr()->GetActiveSidebarWin())
        {
            // Editing postit text.
            pWin->SetCursorLogicPosition(rPosition, bPoint, bClearMark);
            return;
        }
    }
 
    // Not an SwWrtShell, as that would make SwCursorShell::GetCursor() inaccessible.
    SwEditShell& rShell = m_rView.GetWrtShell();
 
    bool bCreateSelection = false;
    {
        SwMvContext aMvContext(&rShell);
        if (bClearMark)
            rShell.ClearMark();
        else
            bCreateSelection = !rShell.HasMark();
 
        if (bCreateSelection)
            m_rView.GetWrtShell().SttSelect();
 
        // If the mark is to be updated, then exchange the point and mark before
        // and after, as we can't easily set the mark.
        if (!bPoint)
            rShell.getShellCursor(/*bBlock=*/false)->Exchange();
        rShell.SetCursor(rPosition);
        if (!bPoint)
            rShell.getShellCursor(/*bBlock=*/false)->Exchange();
    }
 
    if (bCreateSelection)
        m_rView.GetWrtShell().EndSelect();
}
 
void SwEditWin::SetGraphicTwipPosition(bool bStart, const Point& rPosition)
{
    if (bStart)
    {
        MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
        MouseButtonDown(aClickEvent);
        MouseEvent aMoveEvent(Point(rPosition.getX() + MIN_MOVE + 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
        MouseMove(aMoveEvent);
    }
    else
    {
        MouseEvent aMoveEvent(Point(rPosition.getX() - MIN_MOVE - 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
        MouseMove(aMoveEvent);
        MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
        MouseButtonUp(aClickEvent);
    }
}
 
SwFrameControlsManager& SwEditWin::GetFrameControlsManager()
{
    return *m_pFrameControlsManager;
}
 
void SwEditWin::ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs)
{
    // bSubs purpose is to set all sub level outline content to the same visibility as
    // nOutlinePos outline content visibility is toggled. It is only applicable when not treating
    // sub outline levels as content.
    SwWrtShell& rSh = GetView().GetWrtShell();
 
    if (GetView().GetDrawView()->IsTextEdit())
        rSh.EndTextEdit();
    if (GetView().IsDrawMode())
        GetView().LeaveDrawCreate();
    rSh.EnterStdMode();
 
    if (!bSubs || rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
    {
        SwNode* pNode = rSh.GetNodes().GetOutLineNds()[nOutlinePos];
        bool bVisible = true;
        pNode->GetTextNode()->GetAttrOutlineContentVisible(bVisible);
        pNode->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
    }
    else if (bSubs)
    {
        // also toggle sub levels to the same content visibility
        SwOutlineNodes::size_type nPos = nOutlinePos;
        SwOutlineNodes::size_type nOutlineNodesCount
                = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
        int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
        bool bVisible = rSh.IsOutlineContentVisible(nOutlinePos);
        do
        {
            if (rSh.IsOutlineContentVisible(nPos) == bVisible)
                rSh.GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
        } while (++nPos < nOutlineNodesCount
                 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
    }
 
    rSh.InvalidateOutlineContentVisibility();
    rSh.GotoOutline(nOutlinePos);
    rSh.SetModified();
    GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'padToLength' is required to be utilized.

V530 The return value of function 'FindAnchorPos' is required to be utilized.

V530 The return value of function 'Execute' is required to be utilized.

V530 The return value of function 'DeleteExtTextInput' is required to be utilized.

V595 The 'pFlyFormat' pointer was utilized before it was verified against nullptr. Check lines: 4935, 4963.

V1053 Calling the 'SetPointer' virtual function in the constructor may lead to unexpected result at runtime.

V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 1578, 1610.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4301, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4328, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4354, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4411, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4489, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4544, 4298.

V1020 The function exited without calling the 'LeaveArea' function. Check lines: 4692, 4298.

V1048 The 'eKeyState' variable was assigned the same value.