7099 lines
280 KiB
C++
7099 lines
280 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <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 = SwModule::get()->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 );
|
|
SwModule::get()->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, rCEvt.IsMouseEvent()))
|
|
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 != ESelection())
|
|
{
|
|
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();
|
|
|
|
ESelection aCompare(rEditEng.FindDocPosition(aEEPos));
|
|
// 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 = pNode->GetTextNode()->GetAttrOutlineContentVisible();
|
|
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: */
|