xref: /core/sw/source/uibase/docvw/edtwin.cxx (revision f3cc8838)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_wasm_strip.h>
21 
22 #include <swtypes.hxx>
23 #include <hintids.hxx>
24 
25 #include <com/sun/star/accessibility/XAccessible.hpp>
26 #include <com/sun/star/awt/PopupMenuDirection.hpp>
27 #include <com/sun/star/awt/XPopupMenu.hpp>
28 #include <com/sun/star/i18n/XBreakIterator.hpp>
29 #include <com/sun/star/i18n/ScriptType.hpp>
30 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
31 #include <com/sun/star/i18n/UnicodeScript.hpp>
32 #include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
33 #include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
34 
35 #include <comphelper/scopeguard.hxx>
36 #include <comphelper/string.hxx>
37 
38 #include <vcl/dialoghelper.hxx>
39 #include <vcl/inputctx.hxx>
40 #include <vcl/help.hxx>
41 #include <vcl/weld.hxx>
42 #include <vcl/ptrstyle.hxx>
43 #include <svl/macitem.hxx>
44 #include <unotools/securityoptions.hxx>
45 #include <basic/sbxvar.hxx>
46 #include <svl/ctloptions.hxx>
47 #include <basic/sbx.hxx>
48 #include <svl/eitem.hxx>
49 #include <svl/stritem.hxx>
50 #include <sfx2/ipclient.hxx>
51 #include <sfx2/viewfrm.hxx>
52 #include <sfx2/request.hxx>
53 #include <sfx2/bindings.hxx>
54 #include <sfx2/dispatch.hxx>
55 #include <svl/ptitem.hxx>
56 #include <editeng/sizeitem.hxx>
57 #include <editeng/langitem.hxx>
58 #include <svx/statusitem.hxx>
59 #include <svx/svdview.hxx>
60 #include <svx/svdhdl.hxx>
61 #include <svx/svdoutl.hxx>
62 #include <editeng/editeng.hxx>
63 #include <editeng/editview.hxx>
64 #include <editeng/svxacorr.hxx>
65 #include <editeng/flditem.hxx>
66 #include <editeng/colritem.hxx>
67 #include <unotools/charclass.hxx>
68 #include <unotools/datetime.hxx>
69 
70 #include <comphelper/lok.hxx>
71 #include <sfx2/lokhelper.hxx>
72 
73 #include <editeng/acorrcfg.hxx>
74 #include <SwSmartTagMgr.hxx>
75 #include <edtdd.hxx>
76 #include <edtwin.hxx>
77 #include <view.hxx>
78 #include <wrtsh.hxx>
79 #include <IDocumentDrawModelAccess.hxx>
80 #include <IDocumentUndoRedo.hxx>
81 #include <textboxhelper.hxx>
82 #include <dcontact.hxx>
83 #include <fldbas.hxx>
84 #include <swmodule.hxx>
85 #include <docsh.hxx>
86 #include <viewopt.hxx>
87 #include <drawbase.hxx>
88 #include <dselect.hxx>
89 #include <textsh.hxx>
90 #include <shdwcrsr.hxx>
91 #include <txatbase.hxx>
92 #include <fmtanchr.hxx>
93 #include <fmtornt.hxx>
94 #include <fmthdft.hxx>
95 #include <frmfmt.hxx>
96 #include <modcfg.hxx>
97 #include <fmtcol.hxx>
98 #include <wview.hxx>
99 #include <gloslst.hxx>
100 #include <inputwin.hxx>
101 #include <gloshdl.hxx>
102 #include <swundo.hxx>
103 #include <drwtxtsh.hxx>
104 #include <fchrfmt.hxx>
105 #include "romenu.hxx"
106 #include <initui.hxx>
107 #include <frmatr.hxx>
108 #include <extinput.hxx>
109 #include <acmplwrd.hxx>
110 #include <swcalwrp.hxx>
111 #include <swdtflvr.hxx>
112 #include <breakit.hxx>
113 #include <checkit.hxx>
114 #include <pagefrm.hxx>
115 
116 #include <helpids.h>
117 #include <cmdid.h>
118 #include <uitool.hxx>
119 #include <fmtfollowtextflow.hxx>
120 #include <toolkit/helper/vclunohelper.hxx>
121 #include <charfmt.hxx>
122 #include <numrule.hxx>
123 #include <pagedesc.hxx>
124 #include <svtools/ruler.hxx>
125 #include <formatclipboard.hxx>
126 #include <vcl/svapp.hxx>
127 #include <wordcountdialog.hxx>
128 #include <fmtfld.hxx>
129 
130 #include <IMark.hxx>
131 #include <doc.hxx>
132 #include <xmloff/odffields.hxx>
133 
134 #include <PostItMgr.hxx>
135 #include <FrameControlsManager.hxx>
136 #include <AnnotationWin.hxx>
137 
138 #include <algorithm>
139 #include <vector>
140 
141 #include <rootfrm.hxx>
142 
143 #include <unotools/syslocaleoptions.hxx>
144 #include <i18nlangtag/mslangid.hxx>
145 #include <salhelper/singletonref.hxx>
146 #include <sfx2/event.hxx>
147 #include <memory>
148 
149 #include "../../core/crsr/callnk.hxx"
150 #include <IDocumentOutlineNodes.hxx>
151 #include <ndtxt.hxx>
152 #include <cntfrm.hxx>
153 #include <txtfrm.hxx>
154 #include <strings.hrc>
155 #include <textcontentcontrol.hxx>
156 #include <contentcontrolbutton.hxx>
157 
158 using namespace sw::mark;
159 using namespace ::com::sun::star;
160 
161 /**
162  * Globals
163  */
164 static bool g_bInputLanguageSwitched = false;
165 
166 // Usually in MouseButtonUp a selection is revoked when the selection is
167 // not currently being pulled open. Unfortunately in MouseButtonDown there
168 // is being selected at double/triple click. That selection is completely
169 // finished in the Handler and thus can't be distinguished in the Up.
170 // To resolve this g_bHoldSelection is set in Down and evaluated in Up.
171 static bool g_bHoldSelection      = false;
172 
173 bool g_bFrameDrag                   = false;
174 static bool g_bValidCursorPos       = false;
175 bool g_bModePushed = false;
176 bool g_bDDTimerStarted            = false;
177 bool g_bDDINetAttr                = false;
178 static SdrHdlKind g_eSdrMoveHdl   = SdrHdlKind::User;
179 
180 QuickHelpData* SwEditWin::s_pQuickHlpData = nullptr;
181 
182 tools::Long    SwEditWin::s_nDDStartPosY = 0;
183 tools::Long    SwEditWin::s_nDDStartPosX = 0;
184 
185 static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView );
186 
187 /// Check if the selected shape has a TextBox: if so, go into that instead.
lcl_goIntoTextBox(SwEditWin & rEditWin,SwWrtShell & rSh)188 static bool lcl_goIntoTextBox(SwEditWin& rEditWin, SwWrtShell& rSh)
189 {
190     SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0);
191     if (!pMark)
192         return false;
193 
194     SdrObject* pSdrObject = pMark->GetMarkedSdrObj();
195     SwFrameFormat* pObjectFormat = ::FindFrameFormat(pSdrObject);
196     if (SwFrameFormat* pTextBoxFormat = SwTextBoxHelper::getOtherTextBoxFormat(pObjectFormat, RES_DRAWFRMFMT))
197     {
198         SdrObject* pTextBox = pTextBoxFormat->FindRealSdrObject();
199         SdrView* pSdrView = rSh.GetDrawView();
200         // Unmark the shape.
201         pSdrView->UnmarkAllObj();
202         // Mark the textbox.
203         rSh.SelectObj(Point(), SW_ALLOW_TEXTBOX, pTextBox);
204         // Clear the DrawFuncPtr.
205         rEditWin.StopInsFrame();
206         return true;
207     }
208     return false;
209 }
210 
211 class SwAnchorMarker
212 {
213     SdrHdl* m_pHdl;
214     Point m_aHdlPos;
215     Point m_aLastPos;
216     bool m_bTopRightHandle;
217 public:
SwAnchorMarker(SdrHdl * pH)218     explicit SwAnchorMarker( SdrHdl* pH )
219         : m_pHdl( pH )
220         , m_aHdlPos( pH->GetPos() )
221         , m_aLastPos( pH->GetPos() )
222         , m_bTopRightHandle( pH->GetKind() == SdrHdlKind::Anchor_TR )
223     {}
GetLastPos() const224     const Point& GetLastPos() const { return m_aLastPos; }
SetLastPos(const Point & rNew)225     void SetLastPos( const Point& rNew ) { m_aLastPos = rNew; }
SetPos(const Point & rNew)226     void SetPos( const Point& rNew ) { m_pHdl->SetPos( rNew ); }
GetHdlPos() const227     const Point& GetHdlPos() const { return m_aHdlPos; }
GetHdl() const228     SdrHdl* GetHdl() const { return m_pHdl; }
ChgHdl(SdrHdl * pNew)229     void ChgHdl( SdrHdl* pNew )
230     {
231         m_pHdl = pNew;
232         if ( m_pHdl )
233         {
234             m_bTopRightHandle = (m_pHdl->GetKind() == SdrHdlKind::Anchor_TR);
235         }
236     }
GetPosForHitTest(const OutputDevice & rOut)237     Point GetPosForHitTest( const OutputDevice& rOut )
238     {
239         Point aHitTestPos( m_pHdl->GetPos() );
240         aHitTestPos = rOut.LogicToPixel( aHitTestPos );
241         if ( m_bTopRightHandle )
242         {
243             aHitTestPos += Point( -1, 1 );
244         }
245         else
246         {
247             aHitTestPos += Point( 1, 1 );
248         }
249         aHitTestPos = rOut.PixelToLogic( aHitTestPos );
250 
251         return aHitTestPos;
252     }
253 };
254 
255 /// Assists with auto-completion of AutoComplete words and AutoText names.
256 struct QuickHelpData
257 {
258     /// Strings that at least partially match an input word, and match length.
259     std::vector<std::pair<OUString, sal_uInt16>> m_aHelpStrings;
260     /// Index of the current help string.
261     sal_uInt16 nCurArrPos;
262     static constexpr sal_uInt16 nNoPos = std::numeric_limits<sal_uInt16>::max();
263 
264     /// Help data stores AutoText names rather than AutoComplete words.
265     bool m_bIsAutoText;
266     /// Display help string as a tip rather than inline.
267     bool m_bIsTip;
268     /// Tip ID when a help string is displayed as a tip.
269     void* nTipId;
270     /// Append a space character to the displayed help string (if appropriate).
271     bool m_bAppendSpace;
272 
273     /// Help string is currently displayed.
274     bool m_bIsDisplayed;
275 
QuickHelpDataQuickHelpData276     QuickHelpData() { ClearContent(); }
277 
278     void Move( QuickHelpData& rCpy );
279     void ClearContent();
280     void Start(SwWrtShell& rSh, bool bRestart);
281     void Stop( SwWrtShell& rSh );
282 
HasContentQuickHelpData283     bool HasContent() const { return !m_aHelpStrings.empty() && nCurArrPos != nNoPos; }
CurStrQuickHelpData284     const OUString& CurStr() const { return m_aHelpStrings[nCurArrPos].first; }
CurLenQuickHelpData285     sal_uInt16 CurLen() const { return m_aHelpStrings[nCurArrPos].second; }
286 
287     /// Next help string.
NextQuickHelpData288     void Next( bool bEndLess )
289     {
290         if( ++nCurArrPos >= m_aHelpStrings.size() )
291             nCurArrPos = (bEndLess && !m_bIsAutoText ) ? 0 : nCurArrPos-1;
292     }
293     /// Previous help string.
PreviousQuickHelpData294     void Previous( bool bEndLess )
295     {
296         if( 0 == nCurArrPos-- )
297             nCurArrPos = (bEndLess && !m_bIsAutoText ) ? m_aHelpStrings.size()-1 : 0;
298     }
299 
300     // Fills internal structures with hopefully helpful information.
301     void FillStrArr( SwWrtShell const & rSh, const OUString& rWord );
302     void SortAndFilter(const OUString &rOrigWord);
303 };
304 
305 /**
306  * Avoid minimal movement shiver
307  */
308 #define HIT_PIX  2 /* hit tolerance in pixel  */
309 #define MIN_MOVE 4
310 
IsMinMove(const Point & rStartPos,const Point & rLPt)311 static bool IsMinMove(const Point &rStartPos, const Point &rLPt)
312 {
313     return std::abs(rStartPos.X() - rLPt.X()) > MIN_MOVE ||
314            std::abs(rStartPos.Y() - rLPt.Y()) > MIN_MOVE;
315 }
316 
317 /**
318  * For MouseButtonDown - determine whether a DrawObject
319  * a NO SwgFrame was hit! Shift/Ctrl should only result
320  * in selecting, with DrawObjects; at SwgFlys to trigger
321  * hyperlinks if applicable (Download/NewWindow!)
322  */
IsDrawObjSelectable(const SwWrtShell & rSh,const Point & rPt)323 static bool IsDrawObjSelectable( const SwWrtShell& rSh, const Point& rPt )
324 {
325     bool bRet = true;
326     SdrObject* pObj;
327     switch( rSh.GetObjCntType( rPt, pObj ))
328     {
329     case OBJCNT_NONE:
330     case OBJCNT_FLY:
331     case OBJCNT_GRF:
332     case OBJCNT_OLE:
333         bRet = false;
334         break;
335     default:; //prevent warning
336     }
337     return bRet;
338 }
339 
340 /*
341  * Switch pointer
342  */
UpdatePointer(const Point & rLPt,sal_uInt16 nModifier)343 void SwEditWin::UpdatePointer(const Point &rLPt, sal_uInt16 nModifier )
344 {
345     SetQuickHelpText(OUString());
346     SwWrtShell &rSh = m_rView.GetWrtShell();
347     if( m_pApplyTempl )
348     {
349         PointerStyle eStyle = PointerStyle::Fill;
350         if ( rSh.IsOverReadOnlyPos( rLPt ) )
351         {
352             m_pUserMarker.reset();
353 
354             eStyle = PointerStyle::NotAllowed;
355         }
356         else
357         {
358             SwRect aRect;
359             SwRect* pRect = &aRect;
360             const SwFrameFormat* pFormat = nullptr;
361 
362             bool bFrameIsValidTarget = false;
363             if( m_pApplyTempl->m_pFormatClipboard )
364                 bFrameIsValidTarget = m_pApplyTempl->m_pFormatClipboard->HasContentForThisType( SelectionType::Frame );
365             else if( !m_pApplyTempl->nColor )
366                 bFrameIsValidTarget = ( m_pApplyTempl->eType == SfxStyleFamily::Frame );
367 
368             if( bFrameIsValidTarget &&
369                         nullptr !=(pFormat = rSh.GetFormatFromObj( rLPt, &pRect )) &&
370                         dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
371             {
372                 //turn on highlight for frame
373                 tools::Rectangle aTmp( pRect->SVRect() );
374 
375                 if ( !m_pUserMarker )
376                 {
377                     m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
378                 }
379             }
380             else
381             {
382                 m_pUserMarker.reset();
383             }
384 
385             rSh.SwCursorShell::SetVisibleCursor( rLPt );
386         }
387         SetPointer( eStyle );
388         return;
389     }
390 
391     if( !rSh.VisArea().Width() )
392         return;
393 
394     CurrShell aCurr(&rSh);
395 
396     if ( IsChainMode() )
397     {
398         SwRect aRect;
399         SwChainRet nChainable = rSh.Chainable( aRect, *rSh.GetFlyFrameFormat(), rLPt );
400         PointerStyle eStyle = nChainable != SwChainRet::OK
401                 ? PointerStyle::ChainNotAllowed : PointerStyle::Chain;
402         if ( nChainable == SwChainRet::OK )
403         {
404             tools::Rectangle aTmp( aRect.SVRect() );
405 
406             if ( !m_pUserMarker )
407             {
408                 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
409             }
410         }
411         else
412         {
413             m_pUserMarker.reset();
414         }
415 
416         SetPointer( eStyle );
417         return;
418     }
419 
420     bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
421     if ( !bExecHyperlinks )
422     {
423         const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
424         if ( (  bSecureOption && nModifier == KEY_MOD1 ) ||
425              ( !bSecureOption && nModifier != KEY_MOD1 ) )
426             bExecHyperlinks = true;
427     }
428 
429     const bool bExecSmarttags  = nModifier == KEY_MOD1;
430 
431     SdrView *pSdrView = rSh.GetDrawView();
432     bool bPrefSdrPointer = false;
433     bool bHitHandle = false;
434     bool bCntAtPos = false;
435     bool bIsViewReadOnly = IsViewReadonly();
436 
437     m_aActHitType = SdrHitKind::NONE;
438     PointerStyle eStyle = PointerStyle::Text;
439     if ( !pSdrView )
440         bCntAtPos = true;
441     else if ( (bHitHandle = (pSdrView->PickHandle(rLPt) != nullptr)) )
442     {
443         m_aActHitType = SdrHitKind::Object;
444         bPrefSdrPointer = true;
445     }
446     else
447     {
448         const bool bNotInSelObj = !rSh.IsInsideSelectedObj( rLPt );
449         if ( m_rView.GetDrawFuncPtr() && !m_bInsDraw && bNotInSelObj )
450         {
451             m_aActHitType = SdrHitKind::Object;
452             if (IsObjectSelect())
453                 eStyle = PointerStyle::Arrow;
454             else
455                 bPrefSdrPointer = true;
456         }
457         else
458         {
459             SdrPageView* pPV = nullptr;
460             pSdrView->SetHitTolerancePixel( HIT_PIX );
461             SdrObject* pObj  = (bNotInSelObj && bExecHyperlinks) ?
462                  pSdrView->PickObj(rLPt, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) :
463                  nullptr;
464             if (pObj)
465             {
466                 SdrObjMacroHitRec aTmp;
467                 aTmp.aPos = rLPt;
468                 aTmp.pPageView = pPV;
469                 SetPointer( pObj->GetMacroPointer( aTmp ) );
470                 return;
471             }
472             else
473             {
474                 // dvo: IsObjSelectable() eventually calls SdrView::PickObj, so
475                 // apparently this is used to determine whether this is a
476                 // drawling layer object or not.
477                 if ( rSh.IsObjSelectable( rLPt ) )
478                 {
479                     if (pSdrView->IsTextEdit())
480                     {
481                         m_aActHitType = SdrHitKind::NONE;
482                         bPrefSdrPointer = true;
483                     }
484                     else
485                     {
486                         SdrViewEvent aVEvt;
487                         SdrHitKind eHit = pSdrView->PickAnything(rLPt, aVEvt);
488 
489                         if (eHit == SdrHitKind::UrlField && bExecHyperlinks)
490                         {
491                             m_aActHitType = SdrHitKind::Object;
492                             bPrefSdrPointer = true;
493                         }
494                         else
495                         {
496                             // if we're over a selected object, we show an
497                             // ARROW by default. We only show a MOVE if 1) the
498                             // object is selected, and 2) it may be moved
499                             // (i.e., position is not protected).
500                             bool bMovable =
501                                 (!bNotInSelObj) &&
502                                 (rSh.IsObjSelected() || rSh.IsFrameSelected()) &&
503                                 (rSh.IsSelObjProtected(FlyProtectFlags::Pos) == FlyProtectFlags::NONE);
504 
505                             SdrObject* pSelectableObj = rSh.GetObjAt(rLPt);
506                             // Don't update pointer if this is a background image only.
507                             if (pSelectableObj->GetLayer() != rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId())
508                                 eStyle = bMovable ? PointerStyle::Move : PointerStyle::Arrow;
509                             m_aActHitType = SdrHitKind::Object;
510                         }
511                     }
512                 }
513                 else
514                 {
515                     if ( rSh.IsFrameSelected() && !bNotInSelObj )
516                     {
517                         // dvo: this branch appears to be dead and should be
518                         // removed in a future version. Reason: The condition
519                         // !bNotInSelObj means that this branch will only be
520                         // executed in the cursor points inside a selected
521                         // object. However, if this is the case, the previous
522                         // if( rSh.IsObjSelectable(rLPt) ) must always be true:
523                         // rLPt is inside a selected object, then obviously
524                         // rLPt is over a selectable object.
525                         if (rSh.IsSelObjProtected(FlyProtectFlags::Size) != FlyProtectFlags::NONE)
526                             eStyle = PointerStyle::NotAllowed;
527                         else
528                             eStyle = PointerStyle::Move;
529                         m_aActHitType = SdrHitKind::Object;
530                     }
531                     else
532                     {
533                         if ( m_rView.GetDrawFuncPtr() )
534                             bPrefSdrPointer = true;
535                         else
536                             bCntAtPos = true;
537                     }
538                 }
539             }
540         }
541     }
542     if ( bPrefSdrPointer )
543     {
544         if (bIsViewReadOnly || (rSh.IsObjSelected() && rSh.IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE))
545             SetPointer( PointerStyle::NotAllowed );
546         else
547         {
548             if (m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->IsInsertForm() && !bHitHandle)
549                 SetPointer( PointerStyle::DrawRect );
550             else
551                 SetPointer( pSdrView->GetPreferredPointer( rLPt, rSh.GetOut() ) );
552         }
553     }
554     else
555     {
556         if( !rSh.IsPageAtPos( rLPt ) || m_pAnchorMarker )
557             eStyle = PointerStyle::Arrow;
558         else
559         {
560             // Even if we already have something, prefer URLs if possible.
561             SwContentAtPos aUrlPos(IsAttrAtPos::InetAttr);
562             if (bCntAtPos || rSh.GetContentAtPos(rLPt, aUrlPos))
563             {
564                 SwContentAtPos aSwContentAtPos(
565                     IsAttrAtPos::Field |
566                     IsAttrAtPos::ClickField |
567                     IsAttrAtPos::InetAttr |
568                     IsAttrAtPos::Ftn |
569                     IsAttrAtPos::SmartTag);
570                 if( rSh.GetContentAtPos( rLPt, aSwContentAtPos) )
571                 {
572                     // Is edit inline input field
573                     if (IsAttrAtPos::Field == aSwContentAtPos.eContentAtPos
574                              && aSwContentAtPos.pFndTextAttr != nullptr
575                              && aSwContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD)
576                     {
577                         const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
578                         if (!(pCursorField && pCursorField == aSwContentAtPos.pFndTextAttr->GetFormatField().GetField()))
579                             eStyle = PointerStyle::RefHand;
580                     }
581                     else
582                     {
583                         const bool bClickToFollow = IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos ||
584                                                     IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos;
585                         if( !bClickToFollow ||
586                             (IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos && bExecHyperlinks) ||
587                             (IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos && bExecSmarttags) )
588                             eStyle = PointerStyle::RefHand;
589                     }
590                 }
591                 else if (GetView().GetWrtShell().GetViewOptions()->IsShowOutlineContentVisibilityButton())
592                 {
593                     aSwContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
594                     if (rSh.GetContentAtPos(rLPt, aSwContentAtPos))
595                     {
596                         if (IsAttrAtPos::Outline == aSwContentAtPos.eContentAtPos)
597                         {
598                             if (nModifier == KEY_MOD1)
599                             {
600                                 eStyle = PointerStyle::RefHand;
601                                 // set quick help
602                                 if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
603                                 {
604                                     const SwNodes& rNds = GetView().GetWrtShell().GetDoc()->GetNodes();
605                                     SwOutlineNodes::size_type nPos;
606                                     rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos);
607                                     SwOutlineNodes::size_type nOutlineNodesCount
608                                             = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
609                                     int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
610                                     OUString sQuickHelp(SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY));
611                                     if (!rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent()
612                                             && nPos + 1 < nOutlineNodesCount
613                                             && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos + 1) > nLevel)
614                                         sQuickHelp += " (" + SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
615                                     SetQuickHelpText(sQuickHelp);
616                                 }
617                             }
618                         }
619                     }
620                 }
621             }
622         }
623 
624         // which kind of text pointer have we to show - horz / vert - ?
625         if( PointerStyle::Text == eStyle && rSh.IsInVerticalText( &rLPt ))
626             eStyle = PointerStyle::TextVertical;
627         else if (rSh.GetViewOptions()->CanHideWhitespace() &&
628                  rSh.GetLayout()->IsBetweenPages(rLPt))
629         {
630             if (rSh.GetViewOptions()->IsHideWhitespaceMode())
631                 eStyle = PointerStyle::ShowWhitespace;
632             else
633                 eStyle = PointerStyle::HideWhitespace;
634         }
635 
636         if( m_pShadCursor )
637         {
638             if( text::HoriOrientation::LEFT == m_eOrient )    // Arrow to the right
639                 eStyle = PointerStyle::AutoScrollE;
640             else    // Arrow to the left
641                 eStyle = PointerStyle::AutoScrollW;
642         }
643 
644         SetPointer( eStyle );
645     }
646 }
647 
648 /**
649  * Increase timer for selection
650  */
IMPL_LINK_NOARG(SwEditWin,TimerHandler,Timer *,void)651 IMPL_LINK_NOARG(SwEditWin, TimerHandler, Timer *, void)
652 {
653     SwWrtShell &rSh = m_rView.GetWrtShell();
654     Point aModPt( m_aMovePos );
655     const SwRect aOldVis( rSh.VisArea() );
656     bool bDone = false;
657 
658     if ( !rSh.VisArea().Contains( aModPt ) )
659     {
660         if ( m_bInsDraw )
661         {
662             const int nMaxScroll = 40;
663             m_rView.Scroll( tools::Rectangle(aModPt,Size(1,1)), nMaxScroll, nMaxScroll);
664             bDone = true;
665         }
666         else if ( g_bFrameDrag )
667         {
668             rSh.Drag(&aModPt, false);
669             bDone = true;
670         }
671         if ( !bDone )
672             aModPt = rSh.GetContentPos( aModPt,aModPt.Y() > rSh.VisArea().Bottom() );
673     }
674     if ( !bDone && !(g_bFrameDrag || m_bInsDraw) )
675     {
676         if ( m_xRowColumnSelectionStart )
677         {
678             Point aPos( aModPt );
679             rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag );
680         }
681         else
682             rSh.CallSetCursor( &aModPt, false );
683 
684         // It can be that a "jump" over a table cannot be accomplished like
685         // that. So we jump over the table by Up/Down here.
686         const SwRect& rVisArea = rSh.VisArea();
687         if( aOldVis == rVisArea && !rSh.IsStartOfDoc() && !rSh.IsEndOfDoc() )
688         {
689             // take the center point of VisArea to
690             // decide in which direction the user want.
691             if( aModPt.Y() < ( rVisArea.Top() + rVisArea.Height() / 2 ) )
692                 rSh.Up( true );
693             else
694                 rSh.Down( true );
695         }
696     }
697 
698     m_aMovePos += rSh.VisArea().Pos() - aOldVis.Pos();
699     JustifyAreaTimer();
700 }
701 
JustifyAreaTimer()702 void SwEditWin::JustifyAreaTimer()
703 {
704     const tools::Rectangle &rVisArea = GetView().GetVisArea();
705 #ifdef UNX
706     const tools::Long coMinLen = 100;
707 #else
708     const tools::Long coMinLen = 50;
709 #endif
710     tools::Long const nTimeout = 800,
711          nDiff = std::max(
712          std::max( m_aMovePos.Y() - rVisArea.Bottom(), rVisArea.Top() - m_aMovePos.Y() ),
713          std::max( m_aMovePos.X() - rVisArea.Right(),  rVisArea.Left() - m_aMovePos.X()));
714     m_aTimer.SetTimeout( std::max( coMinLen, nTimeout - nDiff*2L) );
715 }
716 
LeaveArea(const Point & rPos)717 void SwEditWin::LeaveArea(const Point &rPos)
718 {
719     m_aMovePos = rPos;
720     JustifyAreaTimer();
721     if( !m_aTimer.IsActive() )
722         m_aTimer.Start();
723     m_pShadCursor.reset();
724 }
725 
EnterArea()726 inline void SwEditWin::EnterArea()
727 {
728     m_aTimer.Stop();
729 }
730 
731 /**
732  * Insert mode for frames
733  */
InsFrame(sal_uInt16 nCols)734 void SwEditWin::InsFrame(sal_uInt16 nCols)
735 {
736     StdDrawMode(SdrObjKind::NewFrame, false);
737     m_bInsFrame = true;
738     m_nInsFrameColCount = nCols;
739 }
740 
StdDrawMode(SdrObjKind eSdrObjectKind,bool bObjSelect)741 void SwEditWin::StdDrawMode( SdrObjKind eSdrObjectKind, bool bObjSelect )
742 {
743     SetSdrDrawMode( eSdrObjectKind );
744 
745     if (bObjSelect)
746         m_rView.SetDrawFuncPtr(std::make_unique<DrawSelection>( &m_rView.GetWrtShell(), this, &m_rView ));
747     else
748         m_rView.SetDrawFuncPtr(std::make_unique<SwDrawBase>( &m_rView.GetWrtShell(), this, &m_rView ));
749 
750     m_rView.SetSelDrawSlot();
751     SetSdrDrawMode( eSdrObjectKind );
752     if (bObjSelect)
753         m_rView.GetDrawFuncPtr()->Activate( SID_OBJECT_SELECT );
754     else
755         m_rView.GetDrawFuncPtr()->Activate( sal::static_int_cast< sal_uInt16 >(eSdrObjectKind) );
756     m_bInsFrame = false;
757     m_nInsFrameColCount = 1;
758 }
759 
StopInsFrame()760 void SwEditWin::StopInsFrame()
761 {
762     if (m_rView.GetDrawFuncPtr())
763     {
764         m_rView.GetDrawFuncPtr()->Deactivate();
765         m_rView.SetDrawFuncPtr(nullptr);
766     }
767     m_rView.LeaveDrawCreate();    // leave construction mode
768     m_bInsFrame = false;
769     m_nInsFrameColCount = 1;
770 }
771 
IsInputSequenceCheckingRequired(const OUString & rText,const SwPaM & rCursor)772 bool SwEditWin::IsInputSequenceCheckingRequired( const OUString &rText, const SwPaM& rCursor )
773 {
774     if ( !SvtCTLOptions::IsCTLFontEnabled() ||
775          !SvtCTLOptions::IsCTLSequenceChecking() )
776          return false;
777 
778     if ( 0 == rCursor.Start()->GetContentIndex() ) /* first char needs not to be checked */
779         return false;
780 
781     SwBreakIt *pBreakIter = SwBreakIt::Get();
782     uno::Reference < i18n::XBreakIterator > xBI = pBreakIter->GetBreakIter();
783     assert(xBI.is());
784     tools::Long nCTLScriptPos = -1;
785 
786     if (xBI->getScriptType( rText, 0 ) == i18n::ScriptType::COMPLEX)
787         nCTLScriptPos = 0;
788     else
789         nCTLScriptPos = xBI->nextScript( rText, 0, i18n::ScriptType::COMPLEX );
790 
791     return (0 <= nCTLScriptPos && nCTLScriptPos <= rText.getLength());
792 }
793 
794 //return INVALID_HINT if language should not be explicitly overridden, the correct
795 //HintId to use for the eBufferLanguage otherwise
lcl_isNonDefaultLanguage(LanguageType eBufferLanguage,SwView const & rView,const OUString & rInBuffer)796 static sal_uInt16 lcl_isNonDefaultLanguage(LanguageType eBufferLanguage, SwView const & rView,
797     const OUString &rInBuffer)
798 {
799     sal_uInt16 nWhich = INVALID_HINT;
800 
801     //If the option to IgnoreLanguageChange is set, short-circuit this method
802     //which results in the document/paragraph language remaining the same
803     //despite a change to the keyboard/input language
804     SvtSysLocaleOptions aSysLocaleOptions;
805     if(aSysLocaleOptions.IsIgnoreLanguageChange())
806     {
807         return INVALID_HINT;
808     }
809 
810     bool bLang = true;
811     if(eBufferLanguage != LANGUAGE_DONTKNOW)
812     {
813         switch( SvtLanguageOptions::GetI18NScriptTypeOfLanguage( eBufferLanguage ))
814         {
815             case  i18n::ScriptType::ASIAN:     nWhich = RES_CHRATR_CJK_LANGUAGE; break;
816             case  i18n::ScriptType::COMPLEX:   nWhich = RES_CHRATR_CTL_LANGUAGE; break;
817             case  i18n::ScriptType::LATIN:     nWhich = RES_CHRATR_LANGUAGE; break;
818             default: bLang = false;
819         }
820         if(bLang)
821         {
822             SfxItemSet aLangSet(rView.GetPool(), nWhich, nWhich);
823             SwWrtShell& rSh = rView.GetWrtShell();
824             rSh.GetCurAttr(aLangSet);
825             if(SfxItemState::DEFAULT <= aLangSet.GetItemState(nWhich))
826             {
827                 LanguageType eLang = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage();
828                 if ( eLang == eBufferLanguage )
829                 {
830                     // current language attribute equal to language reported from system
831                     bLang = false;
832                 }
833                 else if ( !g_bInputLanguageSwitched && RES_CHRATR_LANGUAGE == nWhich )
834                 {
835                     // special case: switching between two "LATIN" languages
836                     // In case the current keyboard setting might be suitable
837                     // for both languages we can't safely assume that the user
838                     // wants to use the language reported from the system,
839                     // except if we knew that it was explicitly switched (thus
840                     // the check for "bInputLangeSwitched").
841 
842                     // The language reported by the system could be just the
843                     // system default language that the user is not even aware
844                     // of, because no language selection tool is installed at
845                     // all. In this case the OOo language should get preference
846                     // as it might have been selected by the user explicitly.
847 
848                     // Usually this case happens if the OOo language is
849                     // different to the system language but the system keyboard
850                     // is still suitable for the OOo language (e.g. writing
851                     // English texts with a German keyboard).
852 
853                     // For non-latin keyboards overwriting the attribute is
854                     // still valid. We do this for cyrillic and greek ATM.  In
855                     // future versions of OOo this should be replaced by a
856                     // configuration switch that allows to give the preference
857                     // to the OOo setting or the system setting explicitly
858                     // and/or a better handling of the script type.
859                     i18n::UnicodeScript eType = !rInBuffer.isEmpty() ?
860                         GetAppCharClass().getScript( rInBuffer, 0 ) :
861                         i18n::UnicodeScript_kScriptCount;
862 
863                     bool bSystemIsNonLatin = false;
864                     switch ( eType )
865                     {
866                         case i18n::UnicodeScript_kGreek:
867                         case i18n::UnicodeScript_kCyrillic:
868                             // in case other UnicodeScripts require special
869                             // keyboards they can be added here
870                             bSystemIsNonLatin = true;
871                             break;
872                         default:
873                             break;
874                     }
875 
876                     bool bOOoLangIsNonLatin = MsLangId::isNonLatinWestern( eLang);
877 
878                     bLang = (bSystemIsNonLatin != bOOoLangIsNonLatin);
879                 }
880             }
881         }
882     }
883     return bLang ? nWhich : INVALID_HINT;
884 }
885 
886 /**
887  * Character buffer is inserted into the document
888  */
FlushInBuffer()889 void SwEditWin::FlushInBuffer()
890 {
891     if ( m_aKeyInputFlushTimer.IsActive())
892         m_aKeyInputFlushTimer.Stop();
893 
894     if ( m_aInBuffer.isEmpty() )
895         return;
896 
897     SwWrtShell& rSh = m_rView.GetWrtShell();
898     uno::Reference<frame::XDispatchRecorder> xRecorder
899         = m_rView.GetViewFrame().GetBindings().GetRecorder();
900 
901     comphelper::ScopeGuard showTooltipGuard(
902         [this, &rSh]
903         {
904             SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
905             const bool bAutoTextShown
906                 = rACfg.IsAutoTextTip() && ShowAutoText(rSh.GetChunkForAutoText());
907             if (!bAutoTextShown)
908             {
909                 SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
910                 if (pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
911                     ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
912             }
913         });
914     if (!m_bMaybeShowTooltipAfterBufferFlush || xRecorder)
915         showTooltipGuard.dismiss();
916     m_bMaybeShowTooltipAfterBufferFlush = false;
917 
918     // generate new sequence input checker if not already done
919     if ( !pCheckIt )
920         pCheckIt = new SwCheckIt;
921 
922     uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = pCheckIt->xCheck;
923     if ( xISC.is() && IsInputSequenceCheckingRequired( m_aInBuffer, *rSh.GetCursor() ) )
924     {
925 
926         // apply (Thai) input sequence checking/correction
927 
928         rSh.Push(); // push current cursor to stack
929 
930         // get text from the beginning (i.e left side) of current selection
931         // to the start of the paragraph
932         rSh.NormalizePam();     // make point be the first (left) one
933         if (!rSh.GetCursor()->HasMark())
934             rSh.GetCursor()->SetMark();
935         rSh.GetCursor()->GetMark()->SetContent(0);
936 
937         const OUString aOldText( rSh.GetCursor()->GetText() );
938         const sal_Int32 nOldLen = aOldText.getLength();
939 
940         sal_Int32 nExpandSelection = 0;
941         if (nOldLen > 0)
942         {
943             sal_Int32 nTmpPos = nOldLen;
944             sal_Int16 nCheckMode = SvtCTLOptions::IsCTLSequenceCheckingRestricted() ?
945                     i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
946 
947             OUString aNewText( aOldText );
948             if (SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace())
949             {
950                 for( sal_Int32 k = 0;  k < m_aInBuffer.getLength();  ++k)
951                 {
952                     const sal_Unicode cChar = m_aInBuffer[k];
953                     const sal_Int32 nPrevPos =xISC->correctInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode );
954 
955                     // valid sequence or sequence could be corrected:
956                     if (nPrevPos != aNewText.getLength())
957                         nTmpPos = nPrevPos + 1;
958                 }
959 
960                 // find position of first character that has changed
961                 sal_Int32 nNewLen = aNewText.getLength();
962                 const sal_Unicode *pOldText = aOldText.getStr();
963                 const sal_Unicode *pNewText = aNewText.getStr();
964                 sal_Int32 nChgPos = 0;
965                 while ( nChgPos < nOldLen && nChgPos < nNewLen &&
966                         pOldText[nChgPos] == pNewText[nChgPos] )
967                     ++nChgPos;
968 
969                 const sal_Int32 nChgLen = nNewLen - nChgPos;
970                 if (nChgLen)
971                 {
972                     m_aInBuffer = aNewText.copy( nChgPos, nChgLen );
973                     nExpandSelection = nOldLen - nChgPos;
974                 }
975                 else
976                     m_aInBuffer.clear();
977             }
978             else
979             {
980                 for( sal_Int32 k = 0;  k < m_aInBuffer.getLength(); ++k )
981                 {
982                     const sal_Unicode cChar = m_aInBuffer[k];
983                     if (xISC->checkInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode ))
984                     {
985                         // character can be inserted:
986                         aNewText += OUStringChar( cChar );
987                         ++nTmpPos;
988                     }
989                 }
990                 m_aInBuffer = aNewText.copy( aOldText.getLength() );  // copy new text to be inserted to buffer
991             }
992         }
993 
994         // at this point now we will insert the buffer text 'normally' some lines below...
995 
996         rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
997 
998         if (m_aInBuffer.isEmpty())
999             return;
1000 
1001         // if text prior to the original selection needs to be changed
1002         // as well, we now expand the selection accordingly.
1003         SwPaM &rCursor = *rSh.GetCursor();
1004         const sal_Int32 nCursorStartPos = rCursor.Start()->GetContentIndex();
1005         OSL_ENSURE( nCursorStartPos >= nExpandSelection, "cannot expand selection as specified!!" );
1006         if (nExpandSelection && nCursorStartPos >= nExpandSelection)
1007         {
1008             if (!rCursor.HasMark())
1009                 rCursor.SetMark();
1010             rCursor.Start()->AdjustContent( -nExpandSelection );
1011         }
1012     }
1013 
1014     if ( xRecorder.is() )
1015     {
1016         // determine shell
1017         SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
1018         // generate request and record
1019         if (pSfxShell)
1020         {
1021             SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
1022             aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, m_aInBuffer ) );
1023             aReq.Done();
1024         }
1025     }
1026 
1027     sal_uInt16 nWhich = lcl_isNonDefaultLanguage(m_eBufferLanguage, m_rView, m_aInBuffer);
1028     if (nWhich != INVALID_HINT )
1029     {
1030         SvxLanguageItem aLangItem( m_eBufferLanguage, nWhich );
1031         rSh.SetAttrItem( aLangItem );
1032     }
1033 
1034     rSh.Insert( m_aInBuffer );
1035     m_eBufferLanguage = LANGUAGE_DONTKNOW;
1036     m_aInBuffer.clear();
1037 }
1038 
1039 #define MOVE_LEFT_SMALL     0
1040 #define MOVE_UP_SMALL       1
1041 #define MOVE_RIGHT_BIG      2
1042 #define MOVE_DOWN_BIG       3
1043 #define MOVE_LEFT_BIG       4
1044 #define MOVE_UP_BIG         5
1045 #define MOVE_RIGHT_SMALL    6
1046 #define MOVE_DOWN_SMALL     7
1047 
1048 // #i121236# Support for shift key in writer
1049 #define MOVE_LEFT_HUGE      8
1050 #define MOVE_UP_HUGE        9
1051 #define MOVE_RIGHT_HUGE     10
1052 #define MOVE_DOWN_HUGE      11
1053 
ChangeFly(sal_uInt8 nDir,bool bWeb)1054 void SwEditWin::ChangeFly( sal_uInt8 nDir, bool bWeb )
1055 {
1056     SwWrtShell &rSh = m_rView.GetWrtShell();
1057     SwRect aTmp = rSh.GetFlyRect();
1058     if( !aTmp.HasArea() ||
1059         rSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
1060         return;
1061 
1062     SfxItemSetFixed<
1063             RES_FRM_SIZE, RES_FRM_SIZE,
1064             RES_PROTECT, RES_PROTECT,
1065             RES_VERT_ORIENT, RES_ANCHOR,
1066             RES_COL, RES_COL,
1067             RES_FOLLOW_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW>
1068         aSet( rSh.GetAttrPool() );
1069     rSh.GetFlyFrameAttr( aSet );
1070     RndStdIds eAnchorId = aSet.Get(RES_ANCHOR).GetAnchorId();
1071     Size aSnap;
1072     bool bHuge(MOVE_LEFT_HUGE == nDir ||
1073         MOVE_UP_HUGE == nDir ||
1074         MOVE_RIGHT_HUGE == nDir ||
1075         MOVE_DOWN_HUGE == nDir);
1076 
1077     if(MOVE_LEFT_SMALL == nDir ||
1078         MOVE_UP_SMALL == nDir ||
1079         MOVE_RIGHT_SMALL == nDir ||
1080         MOVE_DOWN_SMALL == nDir )
1081     {
1082         aSnap = PixelToLogic(Size(1,1));
1083     }
1084     else
1085     {
1086         aSnap = rSh.GetViewOptions()->GetSnapSize();
1087         short nDiv = rSh.GetViewOptions()->GetDivisionX();
1088         if ( nDiv > 0 )
1089             aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1090         nDiv = rSh.GetViewOptions()->GetDivisionY();
1091         if ( nDiv > 0 )
1092             aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1093     }
1094 
1095     if(bHuge)
1096     {
1097         // #i121236# 567twips == 1cm, but just take three times the normal snap
1098         aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1099     }
1100 
1101     SwRect aBoundRect;
1102     Point aRefPoint;
1103     // adjustment for allowing vertical position
1104     // aligned to page for fly frame anchored to paragraph or to character.
1105     {
1106         const SwFormatVertOrient& aVert( aSet.Get(RES_VERT_ORIENT) );
1107         const bool bFollowTextFlow =
1108                 aSet.Get(RES_FOLLOW_TEXT_FLOW).GetValue();
1109         const SwFormatAnchor& rFormatAnchor = aSet.Get(RES_ANCHOR);
1110         rSh.CalcBoundRect( aBoundRect, eAnchorId,
1111                            text::RelOrientation::FRAME, aVert.GetRelationOrient(),
1112                            &rFormatAnchor, bFollowTextFlow,
1113                            false, &aRefPoint );
1114     }
1115     tools::Long nLeft = std::min( aTmp.Left() - aBoundRect.Left(), aSnap.Width() );
1116     tools::Long nRight = std::min( aBoundRect.Right() - aTmp.Right(), aSnap.Width() );
1117     tools::Long nUp = std::min( aTmp.Top() - aBoundRect.Top(), aSnap.Height() );
1118     tools::Long nDown = std::min( aBoundRect.Bottom() - aTmp.Bottom(), aSnap.Height() );
1119 
1120     switch ( nDir )
1121     {
1122         case MOVE_LEFT_BIG:
1123         case MOVE_LEFT_HUGE:
1124         case MOVE_LEFT_SMALL: aTmp.Left( aTmp.Left() - nLeft );
1125             break;
1126 
1127         case MOVE_UP_BIG:
1128         case MOVE_UP_HUGE:
1129         case MOVE_UP_SMALL: aTmp.Top( aTmp.Top() - nUp );
1130             break;
1131 
1132         case MOVE_RIGHT_SMALL:
1133             if( aTmp.Width() < aSnap.Width() + MINFLY )
1134                 break;
1135             nRight = aSnap.Width();
1136             [[fallthrough]];
1137         case MOVE_RIGHT_HUGE:
1138         case MOVE_RIGHT_BIG: aTmp.Left( aTmp.Left() + nRight );
1139             break;
1140 
1141         case MOVE_DOWN_SMALL:
1142             if( aTmp.Height() < aSnap.Height() + MINFLY )
1143                 break;
1144             nDown = aSnap.Height();
1145             [[fallthrough]];
1146         case MOVE_DOWN_HUGE:
1147         case MOVE_DOWN_BIG: aTmp.Top( aTmp.Top() + nDown );
1148             break;
1149 
1150         default: OSL_ENSURE(true, "ChangeFly: Unknown direction." );
1151     }
1152     bool bSet = false;
1153     if ((RndStdIds::FLY_AS_CHAR == eAnchorId) && ( nDir % 2 ))
1154     {
1155         tools::Long aDiff = aTmp.Top() - aRefPoint.Y();
1156         if( aDiff > 0 )
1157             aDiff = 0;
1158         else if ( aDiff < -aTmp.Height() )
1159             aDiff = -aTmp.Height();
1160         SwFormatVertOrient aVert( aSet.Get(RES_VERT_ORIENT) );
1161         sal_Int16 eNew;
1162         if( bWeb )
1163         {
1164             eNew = aVert.GetVertOrient();
1165             bool bDown = 0 != ( nDir & 0x02 );
1166             switch( eNew )
1167             {
1168                 case text::VertOrientation::CHAR_TOP:
1169                     if( bDown ) eNew = text::VertOrientation::CENTER;
1170                 break;
1171                 case text::VertOrientation::CENTER:
1172                     eNew = bDown ? text::VertOrientation::TOP : text::VertOrientation::CHAR_TOP;
1173                 break;
1174                 case text::VertOrientation::TOP:
1175                     if( !bDown ) eNew = text::VertOrientation::CENTER;
1176                 break;
1177                 case text::VertOrientation::LINE_TOP:
1178                     if( bDown ) eNew = text::VertOrientation::LINE_CENTER;
1179                 break;
1180                 case text::VertOrientation::LINE_CENTER:
1181                     eNew = bDown ? text::VertOrientation::LINE_BOTTOM : text::VertOrientation::LINE_TOP;
1182                 break;
1183                 case text::VertOrientation::LINE_BOTTOM:
1184                     if( !bDown ) eNew = text::VertOrientation::LINE_CENTER;
1185                 break;
1186                 default:; //prevent warning
1187             }
1188         }
1189         else
1190         {
1191             aVert.SetPos( aDiff );
1192             eNew = text::VertOrientation::NONE;
1193         }
1194         aVert.SetVertOrient( eNew );
1195         aSet.Put( aVert );
1196         bSet = true;
1197     }
1198     if (bWeb && (RndStdIds::FLY_AT_PARA == eAnchorId)
1199         && ( nDir==MOVE_LEFT_SMALL || nDir==MOVE_RIGHT_BIG ))
1200     {
1201         SwFormatHoriOrient aHori( aSet.Get(RES_HORI_ORIENT) );
1202         sal_Int16 eNew;
1203         eNew = aHori.GetHoriOrient();
1204         switch( eNew )
1205         {
1206             case text::HoriOrientation::RIGHT:
1207                 if( nDir==MOVE_LEFT_SMALL )
1208                     eNew = text::HoriOrientation::LEFT;
1209             break;
1210             case text::HoriOrientation::LEFT:
1211                 if( nDir==MOVE_RIGHT_BIG )
1212                     eNew = text::HoriOrientation::RIGHT;
1213             break;
1214             default:; //prevent warning
1215         }
1216         if( eNew != aHori.GetHoriOrient() )
1217         {
1218             aHori.SetHoriOrient( eNew );
1219             aSet.Put( aHori );
1220             bSet = true;
1221         }
1222     }
1223     rSh.StartAllAction();
1224     if( bSet )
1225         rSh.SetFlyFrameAttr( aSet );
1226     bool bSetPos = (RndStdIds::FLY_AS_CHAR != eAnchorId);
1227     if(bSetPos && bWeb)
1228     {
1229         bSetPos = RndStdIds::FLY_AT_PAGE == eAnchorId;
1230     }
1231     if( bSetPos )
1232         rSh.SetFlyPos( aTmp.Pos() );
1233     rSh.EndAllAction();
1234 
1235 }
1236 
ChangeDrawing(sal_uInt8 nDir)1237 void SwEditWin::ChangeDrawing( sal_uInt8 nDir )
1238 {
1239     // start undo action in order to get only one
1240     // undo action for this change.
1241     SwWrtShell &rSh = m_rView.GetWrtShell();
1242     rSh.StartUndo();
1243 
1244     tools::Long nX = 0;
1245     tools::Long nY = 0;
1246     const bool bOnePixel(
1247         MOVE_LEFT_SMALL == nDir ||
1248         MOVE_UP_SMALL == nDir ||
1249         MOVE_RIGHT_SMALL == nDir ||
1250         MOVE_DOWN_SMALL == nDir);
1251     const bool bHuge(
1252         MOVE_LEFT_HUGE == nDir ||
1253         MOVE_UP_HUGE == nDir ||
1254         MOVE_RIGHT_HUGE == nDir ||
1255         MOVE_DOWN_HUGE == nDir);
1256     SwMove nAnchorDir = SwMove::UP;
1257     switch(nDir)
1258     {
1259         case MOVE_LEFT_SMALL:
1260         case MOVE_LEFT_HUGE:
1261         case MOVE_LEFT_BIG:
1262             nX = -1;
1263             nAnchorDir = SwMove::LEFT;
1264         break;
1265         case MOVE_UP_SMALL:
1266         case MOVE_UP_HUGE:
1267         case MOVE_UP_BIG:
1268             nY = -1;
1269         break;
1270         case MOVE_RIGHT_SMALL:
1271         case MOVE_RIGHT_HUGE:
1272         case MOVE_RIGHT_BIG:
1273             nX = +1;
1274             nAnchorDir = SwMove::RIGHT;
1275         break;
1276         case MOVE_DOWN_SMALL:
1277         case MOVE_DOWN_HUGE:
1278         case MOVE_DOWN_BIG:
1279             nY = +1;
1280             nAnchorDir = SwMove::DOWN;
1281         break;
1282     }
1283 
1284     if(0 != nX || 0 != nY)
1285     {
1286         FlyProtectFlags nProtect = rSh.IsSelObjProtected( FlyProtectFlags::Pos|FlyProtectFlags::Size );
1287         Size aSnap( rSh.GetViewOptions()->GetSnapSize() );
1288         short nDiv = rSh.GetViewOptions()->GetDivisionX();
1289         if ( nDiv > 0 )
1290             aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1291         nDiv = rSh.GetViewOptions()->GetDivisionY();
1292         if ( nDiv > 0 )
1293             aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1294 
1295         if(bOnePixel)
1296         {
1297             aSnap = PixelToLogic(Size(1,1));
1298         }
1299         else if(bHuge)
1300         {
1301             // #i121236# 567twips == 1cm, but just take three times the normal snap
1302             aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1303         }
1304 
1305         nX *= aSnap.Width();
1306         nY *= aSnap.Height();
1307 
1308         SdrView *pSdrView = rSh.GetDrawView();
1309         const SdrHdlList& rHdlList = pSdrView->GetHdlList();
1310         SdrHdl* pHdl = rHdlList.GetFocusHdl();
1311         rSh.StartAllAction();
1312         if(nullptr == pHdl)
1313         {
1314             // now move the selected draw objects
1315             // if the object's position is not protected
1316             if(!(nProtect&FlyProtectFlags::Pos))
1317             {
1318                 // Check if object is anchored as character and move direction
1319                 bool bDummy1, bDummy2;
1320                 const bool bVertAnchor = rSh.IsFrameVertical( true, bDummy1, bDummy2 );
1321                 bool bHoriMove = !bVertAnchor == !( nDir % 2 );
1322                 bool bMoveAllowed =
1323                     !bHoriMove || (rSh.GetAnchorId() != RndStdIds::FLY_AS_CHAR);
1324                 if ( bMoveAllowed )
1325                 {
1326                     pSdrView->MoveAllMarked(Size(nX, nY));
1327                     rSh.SetModified();
1328                 }
1329             }
1330         }
1331         else
1332         {
1333             // move handle with index nHandleIndex
1334             if (nX || nY)
1335             {
1336                 if( SdrHdlKind::Anchor == pHdl->GetKind() ||
1337                     SdrHdlKind::Anchor_TR == pHdl->GetKind() )
1338                 {
1339                     // anchor move cannot be allowed when position is protected
1340                     if(!(nProtect&FlyProtectFlags::Pos))
1341                         rSh.MoveAnchor( nAnchorDir );
1342                 }
1343                 //now resize if size is protected
1344                 else if(!(nProtect&FlyProtectFlags::Size))
1345                 {
1346                     // now move the Handle (nX, nY)
1347                     Point aStartPoint(pHdl->GetPos());
1348                     Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
1349                     const SdrDragStat& rDragStat = pSdrView->GetDragStat();
1350 
1351                     // start dragging
1352                     pSdrView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
1353 
1354                     if(pSdrView->IsDragObj())
1355                     {
1356                         bool bWasNoSnap = rDragStat.IsNoSnap();
1357                         bool bWasSnapEnabled = pSdrView->IsSnapEnabled();
1358 
1359                         // switch snapping off
1360                         if(!bWasNoSnap)
1361                             const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
1362                         if(bWasSnapEnabled)
1363                             pSdrView->SetSnapEnabled(false);
1364 
1365                         pSdrView->MovAction(aEndPoint);
1366                         pSdrView->EndDragObj();
1367                         rSh.SetModified();
1368 
1369                         // restore snap
1370                         if(!bWasNoSnap)
1371                             const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
1372                         if(bWasSnapEnabled)
1373                             pSdrView->SetSnapEnabled(bWasSnapEnabled);
1374                     }
1375                 }
1376             }
1377         }
1378         rSh.EndAllAction();
1379     }
1380 
1381     rSh.EndUndo();
1382 }
1383 
1384 /**
1385  * KeyEvents
1386  */
KeyInput(const KeyEvent & rKEvt)1387 void SwEditWin::KeyInput(const KeyEvent &rKEvt)
1388 {
1389     SwWrtShell &rSh = m_rView.GetWrtShell();
1390 
1391     if (comphelper::LibreOfficeKit::isActive() && m_rView.GetPostItMgr())
1392     {
1393         if (vcl::Window* pWindow = m_rView.GetPostItMgr()->GetActiveSidebarWin())
1394         {
1395             pWindow->KeyInput(rKEvt);
1396             return;
1397         }
1398     }
1399 
1400     // Do not show autotext / word completion tooltips in intermediate flushes
1401     m_bMaybeShowTooltipAfterBufferFlush = false;
1402 
1403     sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
1404 
1405     if (nKey == KEY_ESCAPE)
1406     {
1407         if (m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard)
1408         {
1409             m_pApplyTempl->m_pFormatClipboard->Erase();
1410             SetApplyTemplate(SwApplyTemplate());
1411             m_rView.GetViewFrame().GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
1412         }
1413         else if (rSh.IsHeaderFooterEdit())
1414         {
1415             bool bHeader = bool(FrameTypeFlags::HEADER & rSh.GetFrameType(nullptr, false));
1416             if (bHeader)
1417                 rSh.SttPg();
1418             else
1419                 rSh.EndPg();
1420             rSh.ToggleHeaderFooterEdit();
1421         }
1422     }
1423 
1424     SfxObjectShell *pObjSh = m_rView.GetViewFrame().GetObjectShell();
1425     if ( m_bLockInput || (pObjSh && pObjSh->GetProgress()) )
1426         // When the progress bar is active or a progress is
1427         // running on a document, no order is being taken
1428         return;
1429 
1430     m_pShadCursor.reset();
1431     // Do not reset the timer here, otherwise when flooded with events it would never time out
1432     // if every key event stopped and started it again.
1433     comphelper::ScopeGuard keyInputFlushTimerStop([this]() { m_aKeyInputFlushTimer.Stop(); });
1434 
1435     bool bIsViewReadOnly = IsViewReadonly();
1436 
1437     //if the language changes the buffer must be flushed
1438     LanguageType eNewLanguage = GetInputLanguage();
1439     if(!bIsViewReadOnly && m_eBufferLanguage != eNewLanguage && !m_aInBuffer.isEmpty())
1440     {
1441         FlushInBuffer();
1442     }
1443     m_eBufferLanguage = eNewLanguage;
1444 
1445     QuickHelpData aTmpQHD;
1446     if( s_pQuickHlpData->m_bIsDisplayed )
1447     {
1448         aTmpQHD.Move( *s_pQuickHlpData );
1449         s_pQuickHlpData->Stop( rSh );
1450     }
1451 
1452     // OS:the DrawView also needs a readonly-Flag as well
1453     if ( !bIsViewReadOnly && rSh.GetDrawView() && rSh.GetDrawView()->KeyInput( rKEvt, this ) )
1454     {
1455         rSh.GetView().GetViewFrame().GetBindings().InvalidateAll( false );
1456         rSh.SetModified();
1457         return; // Event evaluated by SdrView
1458     }
1459 
1460     if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
1461     {
1462         StopInsFrame();
1463         rSh.Edit();
1464     }
1465 
1466     bool bFlushBuffer = false;
1467     bool bNormalChar = false;
1468     bool bAppendSpace = s_pQuickHlpData->m_bAppendSpace;
1469     s_pQuickHlpData->m_bAppendSpace = false;
1470 
1471     if (nKey == KEY_F12 && getenv("SW_DEBUG"))
1472     {
1473         if( rKEvt.GetKeyCode().IsShift())
1474         {
1475             GetView().GetDocShell()->GetDoc()->dumpAsXml();
1476         }
1477         else
1478         {
1479             SwRootFrame* pLayout = GetView().GetDocShell()->GetWrtShell()->GetLayout();
1480             pLayout->dumpAsXml( );
1481         }
1482         return;
1483     }
1484 
1485     KeyEvent aKeyEvent( rKEvt );
1486     // look for vertical mappings
1487     if( !bIsViewReadOnly && !rSh.IsSelFrameMode() && !rSh.IsObjSelected() )
1488     {
1489         if( KEY_UP == nKey || KEY_DOWN == nKey ||
1490             KEY_LEFT == nKey || KEY_RIGHT == nKey )
1491         {
1492             // In general, we want to map the direction keys if we are inside
1493             // some vertical formatted text.
1494             // 1. Exception: For a table cursor in a horizontal table, the
1495             //               directions should never be mapped.
1496             // 2. Exception: For a table cursor in a vertical table, the
1497             //               directions should always be mapped.
1498             const bool bVertText = rSh.IsInVerticalText();
1499             const bool bTableCursor = rSh.GetTableCursor();
1500             const bool bVertTable = rSh.IsTableVertical();
1501             if( ( bVertText && ( !bTableCursor || bVertTable ) ) ||
1502                 ( bTableCursor && bVertTable ) )
1503             {
1504                 SvxFrameDirection eDirection = rSh.GetTextDirection();
1505                 if (eDirection == SvxFrameDirection::Vertical_LR_BT)
1506                 {
1507                     // Map from physical to logical, so rotate clockwise.
1508                     if (KEY_UP == nKey)
1509                         nKey = KEY_RIGHT;
1510                     else if (KEY_DOWN == nKey)
1511                         nKey = KEY_LEFT;
1512                     else if (KEY_LEFT == nKey)
1513                         nKey = KEY_UP;
1514                     else /* KEY_RIGHT == nKey */
1515                         nKey = KEY_DOWN;
1516                 }
1517                 else
1518                 {
1519                     // Attempt to integrate cursor travelling for mongolian layout does not work.
1520                     // Thus, back to previous mapping of cursor keys to direction keys.
1521                     if( KEY_UP == nKey ) nKey = KEY_LEFT;
1522                     else if( KEY_DOWN == nKey ) nKey = KEY_RIGHT;
1523                     else if( KEY_LEFT == nKey ) nKey = KEY_DOWN;
1524                     else /* KEY_RIGHT == nKey */ nKey = KEY_UP;
1525                 }
1526             }
1527 
1528             if ( rSh.IsInRightToLeftText() )
1529             {
1530                 if( KEY_LEFT == nKey ) nKey = KEY_RIGHT;
1531                 else if( KEY_RIGHT == nKey ) nKey = KEY_LEFT;
1532             }
1533 
1534             aKeyEvent = KeyEvent( rKEvt.GetCharCode(),
1535                                   vcl::KeyCode( nKey, rKEvt.GetKeyCode().GetModifier() ),
1536                                   rKEvt.GetRepeat() );
1537         }
1538     }
1539 
1540     const vcl::KeyCode& rKeyCode = aKeyEvent.GetKeyCode();
1541     sal_Unicode aCh = aKeyEvent.GetCharCode();
1542 
1543     // enable switching to notes anchor with Ctrl - Alt - Page Up/Down
1544     // pressing this inside a note will switch to next/previous note
1545     if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((rKeyCode.GetCode() == KEY_PAGEUP) || (rKeyCode.GetCode() == KEY_PAGEDOWN)))
1546     {
1547         const bool bNext = rKeyCode.GetCode()==KEY_PAGEDOWN;
1548         const SwFieldType* pFieldType = rSh.GetFieldType( 0, SwFieldIds::Postit );
1549         rSh.MoveFieldType( pFieldType, bNext );
1550         return;
1551     }
1552 
1553     if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
1554     {
1555         // Check if this combination of rKeyCode and pTextContentControl should open a popup.
1556         const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
1557         std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
1558         if (pContentControl->ShouldOpenPopup(rKeyCode))
1559         {
1560             SwShellCursor* pCursor = rSh.GetCursor_();
1561             if (pCursor)
1562             {
1563                 VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton();
1564                 if (pContentControlButton)
1565                 {
1566                     pContentControlButton->StartPopup();
1567                     return;
1568                 }
1569             }
1570         }
1571     }
1572 
1573     const SwFrameFormat* pFlyFormat = rSh.GetFlyFrameFormat();
1574 
1575     if (pFlyFormat)
1576     {
1577         // See if the fly frame's anchor is in a content control. If so,
1578         // try to interact with it.
1579         const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
1580         SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
1581         if (pAnchorNode)
1582         {
1583             SwTextNode* pTextNode = pAnchorNode->GetTextNode();
1584             if (pTextNode)
1585             {
1586                 sal_Int32 nContentIdx = rFormatAnchor.GetAnchorContentOffset();
1587                 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
1588                     nContentIdx, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
1589                 if (pAttr)
1590                 {
1591                     SwTextContentControl* pTextContentControl
1592                         = static_txtattr_cast<SwTextContentControl*>(pAttr);
1593                     const SwFormatContentControl& rFormatContentControl
1594                         = pTextContentControl->GetContentControl();
1595                     std::shared_ptr<SwContentControl> pContentControl
1596                         = rFormatContentControl.GetContentControl();
1597                     if (pContentControl->IsInteractingCharacter(aCh))
1598                     {
1599                         rSh.GotoContentControl(rFormatContentControl);
1600                         return;
1601                     }
1602                 }
1603             }
1604         }
1605     }
1606 
1607     if( pFlyFormat )
1608     {
1609         SvMacroItemId nEvent;
1610 
1611         if( 32 <= aCh &&
1612             0 == (( KEY_MOD1 | KEY_MOD2 ) & rKeyCode.GetModifier() ))
1613             nEvent = SvMacroItemId::SwFrmKeyInputAlpha;
1614         else
1615             nEvent = SvMacroItemId::SwFrmKeyInputNoAlpha;
1616 
1617         const SvxMacro* pMacro = pFlyFormat->GetMacro().GetMacroTable().Get( nEvent );
1618         if( pMacro )
1619         {
1620             SbxArrayRef xArgs = new SbxArray;
1621             SbxVariableRef xVar = new SbxVariable;
1622             xVar->PutString( pFlyFormat->GetName() );
1623             xArgs->Put(xVar.get(), 1);
1624 
1625             xVar = new SbxVariable;
1626             if( SvMacroItemId::SwFrmKeyInputAlpha == nEvent )
1627                 xVar->PutChar( aCh );
1628             else
1629                 xVar->PutUShort( rKeyCode.GetModifier() | rKeyCode.GetCode() );
1630             xArgs->Put(xVar.get(), 2);
1631 
1632             OUString sRet;
1633             rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
1634             if( !sRet.isEmpty() && sRet.toInt32()!=0 )
1635                 return ;
1636         }
1637     }
1638     SelectionType nLclSelectionType;
1639     //A is converted to 1
1640     if( rKeyCode.GetFullCode() == (KEY_A | KEY_MOD1 |KEY_SHIFT)
1641         && rSh.HasDrawView() &&
1642         (bool(nLclSelectionType = rSh.GetSelectionType()) &&
1643         ((nLclSelectionType & (SelectionType::Frame|SelectionType::Graphic)) ||
1644         ((nLclSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1645                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1))))
1646     {
1647         SdrHdlList& rHdlList = const_cast<SdrHdlList&>(rSh.GetDrawView()->GetHdlList());
1648         SdrHdl* pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor);
1649         if ( ! pAnchor )
1650             pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor_TR);
1651         if(pAnchor)
1652             rHdlList.SetFocusHdl(pAnchor);
1653         return;
1654     }
1655 
1656     SvxAutoCorrCfg* pACfg = nullptr;
1657     SvxAutoCorrect* pACorr = nullptr;
1658 
1659     uno::Reference< frame::XDispatchRecorder > xRecorder =
1660             m_rView.GetViewFrame().GetBindings().GetRecorder();
1661     if ( !xRecorder.is() )
1662     {
1663         pACfg = &SvxAutoCorrCfg::Get();
1664         pACorr = pACfg->GetAutoCorrect();
1665     }
1666 
1667     SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig();
1668 
1669     OUString sFormulaEntry;
1670 
1671     enum class SwKeyState { CheckKey, InsChar, InsTab,
1672                        NoNum, NumOff, NumOrNoNum, NumDown, NumUp,
1673                        NumIndentInc, NumIndentDec,
1674 
1675                        OutlineLvOff,
1676                        NextCell, PrevCell, OutlineUp, OutlineDown,
1677                        GlossaryExpand, NextPrevGlossary,
1678                        AutoFormatByInput,
1679                        NextObject, PrevObject,
1680                        KeyToView,
1681                        LaunchOLEObject, GoIntoFly, GoIntoDrawing,
1682                        EnterDrawHandleMode,
1683                        CheckDocReadOnlyKeys,
1684                        CheckAutoCorrect, EditFormula,
1685                        ColLeftBig, ColRightBig,
1686                        ColLeftSmall, ColRightSmall,
1687                        ColBottomBig,
1688                        ColBottomSmall,
1689                        CellLeftBig, CellRightBig,
1690                        CellLeftSmall, CellRightSmall,
1691                        CellTopBig, CellBottomBig,
1692                        CellTopSmall, CellBottomSmall,
1693 
1694                        Fly_Change, Draw_Change,
1695                        SpecialInsert,
1696                        EnterCharCell,
1697                        GotoNextFieldMark,
1698                        GotoPrevFieldMark,
1699                        End };
1700 
1701     SwKeyState eKeyState = bIsViewReadOnly ? SwKeyState::CheckDocReadOnlyKeys : SwKeyState::CheckKey;
1702     SwKeyState eNextKeyState = SwKeyState::End;
1703     sal_uInt8 nDir = 0;
1704 
1705     if (m_nKS_NUMDOWN_Count > 0)
1706         m_nKS_NUMDOWN_Count--;
1707 
1708     if (m_nKS_NUMINDENTINC_Count > 0)
1709         m_nKS_NUMINDENTINC_Count--;
1710 
1711     while( SwKeyState::End != eKeyState )
1712     {
1713         SwKeyState eFlyState = SwKeyState::KeyToView;
1714 
1715         switch( eKeyState )
1716         {
1717         case SwKeyState::CheckKey:
1718             eKeyState = SwKeyState::KeyToView;       // default forward to View
1719 
1720             if (!comphelper::LibreOfficeKit::isActive() &&
1721                 !rKeyCode.IsMod2() && '=' == aCh &&
1722                 !rSh.IsTableMode() && rSh.GetTableFormat() &&
1723                 rSh.IsSttPara() &&
1724                 !rSh.HasReadonlySel())
1725             {
1726                 // at the beginning of the table's cell a '=' ->
1727                 // call EditRow (F2-functionality)
1728                 // [Avoid this for LibreOfficeKit, as the separate input window
1729                 // steals the focus & things go wrong - the user never gets
1730                 // the focus back.]
1731                 rSh.Push();
1732                 if( !rSh.MoveSection( GoCurrSection, fnSectionStart) &&
1733                     !rSh.IsTableBoxTextFormat() )
1734                 {
1735                     // is at the beginning of the box
1736                     eKeyState = SwKeyState::EditFormula;
1737                     if( rSh.HasMark() )
1738                         rSh.SwapPam();
1739                     else
1740                         rSh.SttSelect();
1741                     rSh.MoveSection( GoCurrSection, fnSectionEnd );
1742                     rSh.Pop();
1743                     rSh.EndSelect();
1744                     sFormulaEntry = "=";
1745                 }
1746                 else
1747                     rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
1748             }
1749             else
1750             {
1751                 if( pACorr && aTmpQHD.HasContent() && !rSh.HasSelection() &&
1752                     !rSh.HasReadonlySel() && !aTmpQHD.m_bIsAutoText &&
1753                     pACorr->GetSwFlags().nAutoCmpltExpandKey ==
1754                     (rKeyCode.GetModifier() | rKeyCode.GetCode()) )
1755                 {
1756                     eKeyState = SwKeyState::GlossaryExpand;
1757                     break;
1758                 }
1759 
1760                 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
1761                 {
1762                 case KEY_RIGHT | KEY_MOD2:
1763                     eKeyState = SwKeyState::ColRightBig;
1764                     eFlyState = SwKeyState::Fly_Change;
1765                     nDir = MOVE_RIGHT_SMALL;
1766                     goto KEYINPUT_CHECKTABLE;
1767 
1768                 case KEY_LEFT | KEY_MOD2:
1769                     eKeyState = SwKeyState::ColRightSmall;
1770                     eFlyState = SwKeyState::Fly_Change;
1771                     nDir = MOVE_LEFT_SMALL;
1772                     goto KEYINPUT_CHECKTABLE;
1773 
1774                 case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT:
1775                     eKeyState = SwKeyState::ColLeftSmall;
1776                     goto KEYINPUT_CHECKTABLE;
1777 
1778                 case KEY_LEFT | KEY_MOD2 | KEY_SHIFT:
1779                     eKeyState = SwKeyState::ColLeftBig;
1780                     goto KEYINPUT_CHECKTABLE;
1781 
1782                 case KEY_RIGHT | KEY_MOD2 | KEY_MOD1:
1783                     eKeyState = SwKeyState::CellRightBig;
1784                     goto KEYINPUT_CHECKTABLE;
1785 
1786                 case KEY_LEFT | KEY_MOD2 | KEY_MOD1:
1787                     eKeyState = SwKeyState::CellRightSmall;
1788                     goto KEYINPUT_CHECKTABLE;
1789 
1790                 case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1791                     eKeyState = SwKeyState::CellLeftSmall;
1792                     goto KEYINPUT_CHECKTABLE;
1793 
1794                 case KEY_LEFT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1795                     eKeyState = SwKeyState::CellLeftBig;
1796                     goto KEYINPUT_CHECKTABLE;
1797 
1798                 case KEY_UP | KEY_MOD2:
1799                     eKeyState = SwKeyState::ColBottomSmall;
1800                     eFlyState = SwKeyState::Fly_Change;
1801                     nDir = MOVE_UP_SMALL;
1802                     goto KEYINPUT_CHECKTABLE;
1803 
1804                 case KEY_DOWN | KEY_MOD2:
1805                     eKeyState = SwKeyState::ColBottomBig;
1806                     eFlyState = SwKeyState::Fly_Change;
1807                     nDir = MOVE_DOWN_SMALL;
1808                     goto KEYINPUT_CHECKTABLE;
1809 
1810                 case KEY_UP | KEY_MOD2 | KEY_MOD1:
1811                     eKeyState = SwKeyState::CellBottomSmall;
1812                     goto KEYINPUT_CHECKTABLE;
1813 
1814                 case KEY_DOWN | KEY_MOD2 | KEY_MOD1:
1815                     eKeyState = SwKeyState::CellBottomBig;
1816                     goto KEYINPUT_CHECKTABLE;
1817 
1818                 case KEY_UP | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1819                     eKeyState = SwKeyState::CellTopBig;
1820                     goto KEYINPUT_CHECKTABLE;
1821 
1822                 case KEY_DOWN | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1823                     eKeyState = SwKeyState::CellTopSmall;
1824                     goto KEYINPUT_CHECKTABLE;
1825 
1826 KEYINPUT_CHECKTABLE:
1827                     // Resolve bugs 49091, 53190, 93402 and
1828                     // https://bz.apache.org/ooo/show_bug.cgi?id=113502
1829                     // but provide an option for restoring interactive
1830                     // table sizing functionality when needed.
1831                     if (
1832                       ! (Window::GetIndicatorState() & KeyIndicatorState::CAPSLOCK)
1833                       && m_rView.KeyInput( aKeyEvent ) // Keystroke is customized
1834                     )
1835                     {
1836                         bFlushBuffer = true;
1837                         bNormalChar = false;
1838                         eKeyState = SwKeyState::End;
1839                         break ;
1840                     }
1841 
1842                     if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1843                     {
1844                         if(!pFlyFormat && SwKeyState::KeyToView != eFlyState &&
1845                             (rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm))  &&
1846                                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
1847                             eKeyState = SwKeyState::Draw_Change;
1848 
1849                         if( pFlyFormat )
1850                             eKeyState = eFlyState;
1851                         else if( SwKeyState::Draw_Change != eKeyState)
1852                             eKeyState = SwKeyState::EnterCharCell;
1853                     }
1854                     break;
1855 
1856                 // huge object move
1857                 case KEY_RIGHT | KEY_SHIFT:
1858                 case KEY_LEFT | KEY_SHIFT:
1859                 case KEY_UP | KEY_SHIFT:
1860                 case KEY_DOWN | KEY_SHIFT:
1861                 {
1862                     const SelectionType nSelectionType = rSh.GetSelectionType();
1863                     if ( ( pFlyFormat
1864                            && ( nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic) ) )
1865                          || ( ( nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm) )
1866                               && rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0 ) )
1867                     {
1868                         eKeyState = pFlyFormat ? SwKeyState::Fly_Change : SwKeyState::Draw_Change;
1869                         if (nSelectionType & SelectionType::DrawObject)
1870                         {
1871                             // tdf#137964: always move the DrawObject if one is selected
1872                             eKeyState = SwKeyState::Draw_Change;
1873                         }
1874                         switch ( rKeyCode.GetCode() )
1875                         {
1876                             case KEY_RIGHT: nDir = MOVE_RIGHT_HUGE; break;
1877                             case KEY_LEFT: nDir = MOVE_LEFT_HUGE; break;
1878                             case KEY_UP: nDir = MOVE_UP_HUGE; break;
1879                             case KEY_DOWN: nDir = MOVE_DOWN_HUGE; break;
1880                         }
1881                     }
1882                     break;
1883                 }
1884 
1885                 case KEY_LEFT:
1886                 case KEY_LEFT | KEY_MOD1:
1887                 {
1888                     bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1889                     if(!bMod1)
1890                     {
1891                         eFlyState = SwKeyState::Fly_Change;
1892                         nDir = MOVE_LEFT_BIG;
1893                     }
1894                     goto KEYINPUT_CHECKTABLE_INSDEL;
1895                 }
1896                 case KEY_RIGHT | KEY_MOD1:
1897                 {
1898                     goto KEYINPUT_CHECKTABLE_INSDEL;
1899                 }
1900                 case KEY_UP:
1901                 case KEY_UP | KEY_MOD1:
1902                 {
1903                     bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1904                     if(!bMod1)
1905                     {
1906                         eFlyState = SwKeyState::Fly_Change;
1907                         nDir = MOVE_UP_BIG;
1908                     }
1909                     goto KEYINPUT_CHECKTABLE_INSDEL;
1910                 }
1911                 case KEY_DOWN:
1912                 case KEY_DOWN | KEY_MOD1:
1913                 {
1914                     bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1915                     if(!bMod1)
1916                     {
1917                         ::sw::mark::IFieldmark* pMark = rSh.GetCurrentFieldmark();
1918                         if (auto pDropDown = dynamic_cast<FieldmarkWithDropDownButton*>(pMark))
1919                         {
1920                             pDropDown->LaunchPopup();
1921                             eKeyState = SwKeyState::End;
1922                             break;
1923                         }
1924                         eFlyState = SwKeyState::Fly_Change;
1925                         nDir = MOVE_DOWN_BIG;
1926                     }
1927                     goto KEYINPUT_CHECKTABLE_INSDEL;
1928                 }
1929 
1930 KEYINPUT_CHECKTABLE_INSDEL:
1931                 if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1932                 {
1933                     const SelectionType nSelectionType = rSh.GetSelectionType();
1934 
1935                     eKeyState = SwKeyState::KeyToView;
1936                     if(SwKeyState::KeyToView != eFlyState)
1937                     {
1938                         if((nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm))  &&
1939                                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
1940                             eKeyState = SwKeyState::Draw_Change;
1941                         else if(nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic))
1942                             eKeyState = SwKeyState::Fly_Change;
1943                     }
1944                 }
1945                 break;
1946 
1947 
1948                 case KEY_DELETE:
1949                     if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
1950                     {
1951                         if (rSh.IsInFrontOfLabel() && rSh.NumOrNoNum())
1952                             eKeyState = SwKeyState::NumOrNoNum;
1953                     }
1954                     else if (!rSh.IsCursorInParagraphMetadataField())
1955                     {
1956                         rSh.InfoReadOnlyDialog(false);
1957                         eKeyState = SwKeyState::End;
1958                     }
1959                     break;
1960 
1961                 case KEY_RETURN:
1962                 {
1963                     if ( !rSh.HasReadonlySel()
1964                          && !rSh.CursorInsideInputField()
1965                          && !rSh.CursorInsideContentControl() )
1966                     {
1967                         const SelectionType nSelectionType = rSh.GetSelectionType();
1968                         if(nSelectionType & SelectionType::Ole)
1969                             eKeyState = SwKeyState::LaunchOLEObject;
1970                         else if(nSelectionType & SelectionType::Frame)
1971                             eKeyState = SwKeyState::GoIntoFly;
1972                         else if((nSelectionType & SelectionType::DrawObject) &&
1973                                 !(nSelectionType & SelectionType::DrawObjectEditMode) &&
1974                                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1)
1975                         {
1976                             eKeyState = SwKeyState::GoIntoDrawing;
1977                             if (lcl_goIntoTextBox(*this, rSh))
1978                                 eKeyState = SwKeyState::GoIntoFly;
1979                         }
1980                         else if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
1981                             aTmpQHD.m_bIsAutoText )
1982                             eKeyState = SwKeyState::GlossaryExpand;
1983 
1984                         //RETURN and empty paragraph in numbering -> end numbering
1985                         else if( m_aInBuffer.isEmpty() &&
1986                                  rSh.GetNumRuleAtCurrCursorPos() &&
1987                                  !rSh.GetNumRuleAtCurrCursorPos()->IsOutlineRule() &&
1988                                  !rSh.HasSelection() &&
1989                                 rSh.IsSttPara() && rSh.IsEndPara() )
1990                         {
1991                             eKeyState = SwKeyState::NumOff;
1992                             eNextKeyState = SwKeyState::OutlineLvOff;
1993                         }
1994                         //RETURN for new paragraph with AutoFormatting
1995                         else if( pACfg && pACfg->IsAutoFormatByInput() &&
1996                                 !(nSelectionType & (SelectionType::Graphic |
1997                                     SelectionType::Ole | SelectionType::Frame |
1998                                     SelectionType::TableCell | SelectionType::DrawObject |
1999                                     SelectionType::DrawObjectEditMode)) )
2000                         {
2001                             eKeyState = SwKeyState::AutoFormatByInput;
2002                         }
2003                         else
2004                         {
2005                             eNextKeyState = eKeyState;
2006                             eKeyState = SwKeyState::CheckAutoCorrect;
2007                         }
2008                     }
2009                 }
2010                 break;
2011                 case KEY_RETURN | KEY_MOD2:
2012                 {
2013                     if ( !rSh.HasReadonlySel()
2014                          && !rSh.IsSttPara()
2015                          && rSh.GetNumRuleAtCurrCursorPos()
2016                          && !rSh.CursorInsideInputField() )
2017                     {
2018                         eKeyState = SwKeyState::NoNum;
2019                     }
2020                     else if( rSh.CanSpecialInsert() )
2021                         eKeyState = SwKeyState::SpecialInsert;
2022                 }
2023                 break;
2024                 case KEY_BACKSPACE:
2025                 case KEY_BACKSPACE | KEY_SHIFT:
2026                     if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
2027                     {
2028                         bool bDone = false;
2029                         // try to add comment for code snip:
2030                         // Remove the paragraph indent, if the cursor is at the
2031                         // beginning of a paragraph, there is no selection
2032                         // and no numbering rule found at the current paragraph
2033                         // Also try to remove indent, if current paragraph
2034                         // has numbering rule, but isn't counted and only
2035                         // key <backspace> is hit.
2036                         const bool bOnlyBackspaceKey( KEY_BACKSPACE == rKeyCode.GetFullCode() );
2037                         if ( rSh.IsSttPara()
2038                              && !rSh.HasSelection()
2039                              && ( rSh.GetNumRuleAtCurrCursorPos() == nullptr
2040                                   || ( rSh.IsNoNum() && bOnlyBackspaceKey ) ) )
2041                         {
2042                             bDone = rSh.TryRemoveIndent();
2043                         }
2044 
2045                         if (bDone)
2046                             eKeyState = SwKeyState::End;
2047                         else
2048                         {
2049                             if ( rSh.IsSttPara() && !rSh.IsNoNum() )
2050                             {
2051                                 if (m_nKS_NUMDOWN_Count > 0 &&
2052                                     0 < rSh.GetNumLevel())
2053                                 {
2054                                     eKeyState = SwKeyState::NumUp;
2055                                     m_nKS_NUMDOWN_Count = 2;
2056                                     bDone = true;
2057                                 }
2058                                 else if (m_nKS_NUMINDENTINC_Count > 0)
2059                                 {
2060                                     eKeyState = SwKeyState::NumIndentDec;
2061                                     m_nKS_NUMINDENTINC_Count = 2;
2062                                     bDone = true;
2063                                 }
2064                             }
2065 
2066                             // If the cursor is in an empty paragraph, which has
2067                             // a numbering, but not the outline numbering, and
2068                             // there is no selection, the numbering has to be
2069                             // deleted on key <Backspace>.
2070                             // Otherwise method <SwEditShell::NumOrNoNum(..)>
2071                             // should only change the <IsCounted()> state of
2072                             // the current paragraph depending of the key.
2073                             // On <backspace> it is set to <false>,
2074                             // on <shift-backspace> it is set to <true>.
2075                             // Thus, assure that method <SwEditShell::NumOrNum(..)>
2076                             // is only called for the intended purpose.
2077                             if ( !bDone && rSh.IsSttPara() )
2078                             {
2079                                 bool bCallNumOrNoNum( false );
2080                                 if ( bOnlyBackspaceKey && !rSh.IsNoNum() )
2081                                 {
2082                                     bCallNumOrNoNum = true;
2083                                 }
2084                                 else if ( !bOnlyBackspaceKey && rSh.IsNoNum() )
2085                                 {
2086                                     bCallNumOrNoNum = true;
2087                                 }
2088                                 else if ( bOnlyBackspaceKey
2089                                           && rSh.IsSttPara()
2090                                           && rSh.IsEndPara()
2091                                           && !rSh.HasSelection() )
2092                                 {
2093                                     const SwNumRule* pCurrNumRule( rSh.GetNumRuleAtCurrCursorPos() );
2094                                     if ( pCurrNumRule != nullptr
2095                                          && pCurrNumRule != rSh.GetOutlineNumRule() )
2096                                     {
2097                                         bCallNumOrNoNum = true;
2098                                     }
2099                                 }
2100                                 if ( bCallNumOrNoNum
2101                                      && rSh.NumOrNoNum( !bOnlyBackspaceKey ) )
2102                                 {
2103                                     eKeyState = SwKeyState::NumOrNoNum;
2104                                 }
2105                             }
2106                         }
2107                     }
2108                     else if (!rSh.IsCursorInParagraphMetadataField())
2109                     {
2110                         rSh.InfoReadOnlyDialog(false);
2111                         eKeyState = SwKeyState::End;
2112                     }
2113                     break;
2114 
2115                 case KEY_RIGHT:
2116                     {
2117                         eFlyState = SwKeyState::Fly_Change;
2118                         nDir = MOVE_RIGHT_BIG;
2119                         goto KEYINPUT_CHECKTABLE_INSDEL;
2120                     }
2121                 case KEY_TAB:
2122                 {
2123                     // Rich text contentControls accept tabs and fieldmarks and other rich text,
2124                     // so first act on cases that are not a content control
2125                     SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2126                     if ((rSh.IsFormProtected() && !pTextContentControl) ||
2127                         rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2128                     {
2129                         eKeyState = SwKeyState::GotoNextFieldMark;
2130                     }
2131                     else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2132                     {
2133                         GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_NEXT_INPUTFLD );
2134                         eKeyState = SwKeyState::End;
2135                     }
2136                     else if( rSh.GetNumRuleAtCurrCursorPos()
2137                              && rSh.IsSttOfPara()
2138                              && !rSh.HasReadonlySel() )
2139                     {
2140                         if (numfunc::NumDownChangesIndent(rSh))
2141                         {
2142                             eKeyState = SwKeyState::NumDown;
2143                         }
2144                         else
2145                         {
2146                             eKeyState = SwKeyState::InsTab;
2147                         }
2148                     }
2149                     else if (rSh.GetSelectionType() &
2150                              (SelectionType::Graphic |
2151                               SelectionType::Frame |
2152                               SelectionType::Ole |
2153                               SelectionType::DrawObject |
2154                               SelectionType::DbForm))
2155                     {
2156                         eKeyState = SwKeyState::NextObject;
2157                     }
2158                     else if ( rSh.GetTableFormat() )
2159                     {
2160                         if( rSh.HasSelection() || rSh.HasReadonlySel() )
2161                             eKeyState = SwKeyState::NextCell;
2162                         else
2163                         {
2164                             eKeyState = SwKeyState::CheckAutoCorrect;
2165                             eNextKeyState = SwKeyState::NextCell;
2166                         }
2167                     }
2168                     else if (pTextContentControl)
2169                     {
2170                         auto pCC = pTextContentControl->GetContentControl().GetContentControl();
2171                         if (pCC)
2172                         {
2173                             switch (pCC->GetType())
2174                             {
2175                                 case SwContentControlType::RICH_TEXT:
2176                                     eKeyState = SwKeyState::InsTab;
2177                                     break;
2178                                 default:
2179                                     eKeyState = SwKeyState::GotoNextFieldMark;
2180                             }
2181                         }
2182                     }
2183                     else
2184                     {
2185                         eKeyState = SwKeyState::InsTab;
2186                         if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2187                         {
2188                             SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
2189                             if( pColl &&
2190 
2191                                 pColl->IsAssignedToListLevelOfOutlineStyle()
2192                                 && MAXLEVEL-1 > pColl->GetAssignedOutlineStyleLevel() )
2193                                 eKeyState = SwKeyState::OutlineDown;
2194                         }
2195                     }
2196                 }
2197                 break;
2198                 case KEY_TAB | KEY_SHIFT:
2199                 {
2200                     SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2201                     if ((rSh.IsFormProtected() && !pTextContentControl) ||
2202                         rSh.GetCurrentFieldmark()|| rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2203                     {
2204                         eKeyState = SwKeyState::GotoPrevFieldMark;
2205                     }
2206                     else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2207                     {
2208                         GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_PREV_INPUTFLD );
2209                         eKeyState = SwKeyState::End;
2210                     }
2211                     else if( rSh.GetNumRuleAtCurrCursorPos()
2212                              && rSh.IsSttOfPara()
2213                              && !rSh.HasReadonlySel() )
2214                     {
2215                         eKeyState = SwKeyState::NumUp;
2216                     }
2217                     else if (rSh.GetSelectionType() &
2218                              (SelectionType::Graphic |
2219                               SelectionType::Frame |
2220                               SelectionType::Ole |
2221                               SelectionType::DrawObject |
2222                               SelectionType::DbForm))
2223                     {
2224                         eKeyState = SwKeyState::PrevObject;
2225                     }
2226                     else if ( rSh.GetTableFormat() )
2227                     {
2228                         if( rSh.HasSelection() || rSh.HasReadonlySel() )
2229                             eKeyState = SwKeyState::PrevCell;
2230                         else
2231                         {
2232                             eKeyState = SwKeyState::CheckAutoCorrect;
2233                             eNextKeyState = SwKeyState::PrevCell;
2234                         }
2235                     }
2236                     else if (pTextContentControl)
2237                     {
2238                         eKeyState = SwKeyState::GotoPrevFieldMark;
2239                     }
2240                     else
2241                     {
2242                         eKeyState = SwKeyState::End;
2243                         if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2244                         {
2245                             SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
2246                             if( pColl &&
2247                                 pColl->IsAssignedToListLevelOfOutlineStyle() &&
2248                                 0 < pColl->GetAssignedOutlineStyleLevel())
2249                                 eKeyState = SwKeyState::OutlineUp;
2250                         }
2251                     }
2252                 }
2253                 break;
2254                 case KEY_TAB | KEY_MOD1:
2255                 case KEY_TAB | KEY_MOD2:
2256                     if( !rSh.HasReadonlySel() )
2257                     {
2258                         if( aTmpQHD.HasContent() && !rSh.HasSelection() )
2259                         {
2260                             // Next auto-complete suggestion
2261                             aTmpQHD.Next( pACorr &&
2262                                           pACorr->GetSwFlags().bAutoCmpltEndless );
2263                             eKeyState = SwKeyState::NextPrevGlossary;
2264                         }
2265                         else if( rSh.GetTableFormat() )
2266                             eKeyState = SwKeyState::InsTab;
2267                         else if((rSh.GetSelectionType() &
2268                                     (SelectionType::DrawObject|SelectionType::DbForm|
2269                                         SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic))  &&
2270                                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
2271                             eKeyState = SwKeyState::EnterDrawHandleMode;
2272                         else
2273                         {
2274                             if ( !rSh.IsMultiSelection()
2275                                 && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
2276                                 eKeyState = SwKeyState::NumIndentInc;
2277                         }
2278                     }
2279                     break;
2280 
2281                     case KEY_TAB | KEY_MOD1 | KEY_SHIFT:
2282                     {
2283                         if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
2284                             !rSh.HasReadonlySel() )
2285                         {
2286                             // Previous auto-complete suggestion.
2287                             aTmpQHD.Previous( pACorr &&
2288                                               pACorr->GetSwFlags().bAutoCmpltEndless );
2289                             eKeyState = SwKeyState::NextPrevGlossary;
2290                         }
2291                         else if((rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm|
2292                                         SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic)) &&
2293                                 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() != 0)
2294                         {
2295                             eKeyState = SwKeyState::EnterDrawHandleMode;
2296                         }
2297                         else
2298                         {
2299                             if ( !rSh.IsMultiSelection()
2300                                 && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
2301                                 eKeyState = SwKeyState::NumIndentDec;
2302                         }
2303                     }
2304                     break;
2305                     case KEY_F2 :
2306                     if( !rSh.HasReadonlySel() )
2307                     {
2308                         const SelectionType nSelectionType = rSh.GetSelectionType();
2309                         if(nSelectionType & SelectionType::Frame)
2310                             eKeyState = SwKeyState::GoIntoFly;
2311                         else if(nSelectionType & SelectionType::DrawObject)
2312                         {
2313                             eKeyState = SwKeyState::GoIntoDrawing;
2314                             if (lcl_goIntoTextBox(*this, rSh))
2315                                 eKeyState = SwKeyState::GoIntoFly;
2316                         }
2317                     }
2318                     break;
2319                 }
2320             }
2321             break;
2322         case SwKeyState::CheckDocReadOnlyKeys:
2323             {
2324                 eKeyState = SwKeyState::KeyToView;
2325                 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2326                 {
2327                     case KEY_TAB:
2328                     case KEY_TAB | KEY_SHIFT:
2329                         bNormalChar = false;
2330                         eKeyState = SwKeyState::End;
2331                         if ( rSh.GetSelectionType() &
2332                                 (SelectionType::Graphic |
2333                                     SelectionType::Frame |
2334                                     SelectionType::Ole |
2335                                     SelectionType::DrawObject |
2336                                     SelectionType::DbForm))
2337 
2338                         {
2339                             eKeyState = (rKeyCode.GetModifier() & KEY_SHIFT) ?
2340                                                 SwKeyState::PrevObject : SwKeyState::NextObject;
2341                         }
2342                         else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2343                         {
2344                             GetView().GetViewFrame().GetDispatcher()->Execute(
2345                                 KEY_SHIFT != rKeyCode.GetModifier() ? FN_GOTO_NEXT_INPUTFLD : FN_GOTO_PREV_INPUTFLD );
2346                         }
2347                         else
2348                         {
2349                             rSh.SelectNextPrevHyperlink( KEY_SHIFT != rKeyCode.GetModifier() );
2350                         }
2351                     break;
2352                     case KEY_RETURN:
2353                     {
2354                         const SelectionType nSelectionType = rSh.GetSelectionType();
2355                         if(nSelectionType & SelectionType::Frame)
2356                             eKeyState = SwKeyState::GoIntoFly;
2357                         else
2358                         {
2359                             SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT> aSet(rSh.GetAttrPool());
2360                             rSh.GetCurAttr(aSet);
2361                             if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false))
2362                             {
2363                                 const SfxPoolItem& rItem = aSet.Get(RES_TXTATR_INETFMT);
2364                                 bNormalChar = false;
2365                                 eKeyState = SwKeyState::End;
2366                                 rSh.ClickToINetAttr(static_cast<const SwFormatINetFormat&>(rItem));
2367                             }
2368                         }
2369                     }
2370                     break;
2371                 }
2372             }
2373             break;
2374 
2375         case SwKeyState::EnterCharCell:
2376             {
2377                 eKeyState = SwKeyState::KeyToView;
2378                 switch ( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2379                 {
2380                     case KEY_RIGHT | KEY_MOD2:
2381                         rSh.Right( SwCursorSkipMode::Chars, false, 1, false );
2382                         eKeyState = SwKeyState::End;
2383                         FlushInBuffer();
2384                         break;
2385                     case KEY_LEFT | KEY_MOD2:
2386                         rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
2387                         eKeyState = SwKeyState::End;
2388                         FlushInBuffer();
2389                         break;
2390                 }
2391             }
2392             break;
2393 
2394         case SwKeyState::KeyToView:
2395             {
2396                 eKeyState = SwKeyState::End;
2397                 bNormalChar =
2398                     !rKeyCode.IsMod2() &&
2399                     rKeyCode.GetModifier() != KEY_MOD1 &&
2400                     rKeyCode.GetModifier() != (KEY_MOD1|KEY_SHIFT) &&
2401                     SW_ISPRINTABLE( aCh );
2402 
2403                 if( bNormalChar && rSh.IsInFrontOfLabel() )
2404                 {
2405                     rSh.NumOrNoNum();
2406                 }
2407 
2408                 if( !m_aInBuffer.isEmpty() && ( !bNormalChar || bIsViewReadOnly ))
2409                     FlushInBuffer();
2410 
2411                 if (rSh.HasReadonlySel()
2412                     && (   rKeyCode.GetFunction() == KeyFuncType::PASTE
2413                         || rKeyCode.GetFunction() == KeyFuncType::CUT))
2414                 {
2415                     rSh.InfoReadOnlyDialog(true);
2416                     eKeyState = SwKeyState::End;
2417                 }
2418                 else if( m_rView.KeyInput( aKeyEvent ) )
2419                 {
2420                     bFlushBuffer = true;
2421                     bNormalChar = false;
2422                 }
2423                 else
2424                 {
2425                     // Because Sfx accelerators are only called when they were
2426                     // enabled at the last status update, copy has to called
2427                     // 'forcefully' by us if necessary.
2428                     if( rKeyCode.GetFunction() == KeyFuncType::COPY )
2429                         GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
2430 
2431                     if( !bIsViewReadOnly && bNormalChar )
2432                     {
2433                         const SelectionType nSelectionType = rSh.GetSelectionType();
2434                         const bool bDrawObject = (nSelectionType & SelectionType::DrawObject) &&
2435                             !(nSelectionType & SelectionType::DrawObjectEditMode) &&
2436                             rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1;
2437 
2438                         bool bTextBox = false;
2439                         if (bDrawObject && lcl_goIntoTextBox(*this, rSh))
2440                             // A draw shape was selected, but it has a TextBox,
2441                             // start editing that instead when the normal
2442                             // character is pressed.
2443                             bTextBox = true;
2444 
2445                         if (bDrawObject && !bTextBox)
2446                         {
2447                             SdrObject* pObj = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
2448                             if(pObj)
2449                             {
2450                                 EnterDrawTextMode(pObj->GetLogicRect().Center());
2451                                 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
2452                                     pSwDrawTextShell->Init();
2453                                 rSh.GetDrawView()->KeyInput( rKEvt, this );
2454                             }
2455                         }
2456                         else if (nSelectionType & SelectionType::Frame || bTextBox)
2457                         {
2458                             rSh.UnSelectFrame();
2459                             rSh.LeaveSelFrameMode();
2460                             m_rView.AttrChangedNotify(nullptr);
2461                             rSh.MoveSection( GoCurrSection, fnSectionEnd );
2462                         }
2463                         eKeyState = SwKeyState::InsChar;
2464                     }
2465                     else
2466                     {
2467                         bNormalChar = false;
2468                         Window::KeyInput( aKeyEvent );
2469                     }
2470                 }
2471             }
2472             break;
2473         case SwKeyState::LaunchOLEObject:
2474         {
2475             rSh.LaunchOLEObj();
2476             eKeyState = SwKeyState::End;
2477         }
2478         break;
2479         case SwKeyState::GoIntoFly:
2480         {
2481             rSh.UnSelectFrame();
2482             rSh.LeaveSelFrameMode();
2483             m_rView.AttrChangedNotify(nullptr);
2484             rSh.MoveSection( GoCurrSection, fnSectionEnd );
2485             eKeyState = SwKeyState::End;
2486         }
2487         break;
2488         case SwKeyState::GoIntoDrawing:
2489         {
2490             if (SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0))
2491             {
2492                 SdrObject* pObj = pMark->GetMarkedSdrObj();
2493                 if(pObj)
2494                 {
2495                     EnterDrawTextMode(pObj->GetLogicRect().Center());
2496                     if (auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
2497                         pSwDrawTextShell->Init();
2498                 }
2499             }
2500             eKeyState = SwKeyState::End;
2501         }
2502         break;
2503         case SwKeyState::EnterDrawHandleMode:
2504         {
2505             const SdrHdlList& rHdlList = rSh.GetDrawView()->GetHdlList();
2506             bool bForward(!aKeyEvent.GetKeyCode().IsShift());
2507 
2508             const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
2509             eKeyState = SwKeyState::End;
2510         }
2511         break;
2512         case SwKeyState::InsTab:
2513             if( dynamic_cast<const SwWebView*>( &m_rView) !=  nullptr)     // no Tab for WebView
2514             {
2515                 // then it should be passed along
2516                 Window::KeyInput( aKeyEvent );
2517                 eKeyState = SwKeyState::End;
2518                 break;
2519             }
2520             aCh = '\t';
2521             [[fallthrough]];
2522         case SwKeyState::InsChar:
2523         {
2524             if (rSh.CursorInsideContentControl())
2525             {
2526                 const SwPosition* pStart = rSh.GetCursor()->Start();
2527                 SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
2528                 if (pTextNode)
2529                 {
2530                     sal_Int32 nIndex = pStart->GetContentIndex();
2531                     SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
2532                     if (pAttr)
2533                     {
2534                         auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
2535                         const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
2536                         std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
2537                         if (pContentControl->IsInteractingCharacter(aCh))
2538                         {
2539                             rSh.GotoContentControl(rFormatContentControl);
2540                             eKeyState = SwKeyState::End;
2541                             break;
2542                         }
2543                     }
2544                 }
2545             }
2546 
2547             if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2548             {
2549                 ::sw::mark::ICheckboxFieldmark* pFieldmark =
2550                     dynamic_cast< ::sw::mark::ICheckboxFieldmark* >
2551                         (rSh.GetCurrentFieldmark());
2552                 OSL_ENSURE(pFieldmark,
2553                     "Where is my FieldMark??");
2554                 if(pFieldmark)
2555                 {
2556                     pFieldmark->SetChecked(!pFieldmark->IsChecked());
2557                     OSL_ENSURE(pFieldmark->IsExpanded(),
2558                         "where is the otherpos?");
2559                     if (pFieldmark->IsExpanded())
2560                     {
2561                         rSh.CalcLayout();
2562                     }
2563                 }
2564                 eKeyState = SwKeyState::End;
2565             }
2566             else if ( !rSh.HasReadonlySel()
2567                       || rSh.CursorInsideInputField() )
2568             {
2569                 const bool bIsNormalChar =
2570                     GetAppCharClass().isLetterNumeric( OUString( aCh ), 0 );
2571                 if( bAppendSpace && bIsNormalChar &&
2572                     (!m_aInBuffer.isEmpty() || !rSh.IsSttPara() || !rSh.IsEndPara() ))
2573                 {
2574                     // insert a blank ahead of the character. this ends up
2575                     // between the expanded text and the new "non-word-separator".
2576                     m_aInBuffer += " ";
2577                 }
2578 
2579                 const SwViewOption& rVwOpt = SwViewOption::GetCurrentViewOptions();
2580                 const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar(aCh);
2581                 if (!aKeyEvent.GetRepeat() && rSh.HasSelection()
2582                     && rVwOpt.IsEncloseWithCharactersOn()
2583                     && SwViewOption::IsEncloseWithCharactersTrigger(aCh))
2584                 {
2585                     FlushInBuffer();
2586                     switch (aCh)
2587                     {
2588                         case '(':
2589                             rSh.InsertEnclosingChars(u"(", u")");
2590                             break;
2591                         case '[':
2592                             rSh.InsertEnclosingChars(u"[", u"]");
2593                             break;
2594                         case '{':
2595                             rSh.InsertEnclosingChars(u"{", u"}");
2596                             break;
2597                         case '\"':
2598                         {
2599                             LanguageType eLang
2600                                 = Application::GetSettings().GetLanguageTag().getLanguageType();
2601                             OUString sStartQuote{ pACorr->GetQuote('\"', true, eLang) };
2602                             OUString sEndQuote{ pACorr->GetQuote('\"', false, eLang) };
2603                             rSh.InsertEnclosingChars(sStartQuote, sEndQuote);
2604                             break;
2605                         }
2606                         case '\'':
2607                         {
2608                             LanguageType eLang
2609                                 = Application::GetSettings().GetLanguageTag().getLanguageType();
2610                             OUString sStartQuote{ pACorr->GetQuote('\'', true, eLang) };
2611                             OUString sEndQuote{ pACorr->GetQuote('\'', false, eLang) };
2612                             rSh.InsertEnclosingChars(sStartQuote, sEndQuote);
2613                             break;
2614                         }
2615                     }
2616                 }
2617                 else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2618                         pACfg->IsAutoFormatByInput() &&
2619                     (( pACorr->IsAutoCorrFlag( ACFlags::ChgWeightUnderl ) &&
2620                         ( '*' == aCh || '_' == aCh ) ) ||
2621                      ( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
2622                      ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
2623                 {
2624                     FlushInBuffer();
2625                     rSh.AutoCorrect( *pACorr, aCh );
2626                     if( '\"' != aCh && '\'' != aCh )        // only call when "*_"!
2627                         rSh.UpdateAttr();
2628                 }
2629                 else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2630                         pACfg->IsAutoFormatByInput() &&
2631                     pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2632                                             ACFlags::ChgOrdinalNumber | ACFlags::AddNonBrkSpace |
2633                                             ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2634                                             ACFlags::Autocorrect | ACFlags::TransliterateRTL |
2635                                             ACFlags::SetDOIAttr ) &&
2636                     '\"' != aCh && '\'' != aCh && '*' != aCh && '_' != aCh
2637                     )
2638                 {
2639                     FlushInBuffer();
2640                     rSh.AutoCorrect( *pACorr, aCh );
2641                 }
2642                 else
2643                 {
2644                     OUStringBuffer aBuf(m_aInBuffer);
2645                     comphelper::string::padToLength(aBuf,
2646                         m_aInBuffer.getLength() + aKeyEvent.GetRepeat() + 1, aCh);
2647                     m_aInBuffer = aBuf.makeStringAndClear();
2648                     bool delayFlush = Application::AnyInput( VclInputFlags::KEYBOARD );
2649                     bFlushBuffer = !delayFlush;
2650                     if( delayFlush )
2651                     {
2652                         // Start the timer, make sure to not restart it.
2653                         keyInputFlushTimerStop.dismiss();
2654                         if( !m_aKeyInputFlushTimer.IsActive())
2655                             m_aKeyInputFlushTimer.Start();
2656                     }
2657                 }
2658                 eKeyState = SwKeyState::End;
2659             }
2660             else
2661             {
2662                 rSh.InfoReadOnlyDialog(true);
2663                 eKeyState = SwKeyState::End;
2664             }
2665 
2666             bool bIsSpace = (aCh == ' ');
2667             if (bIsSpace && pACorr && pACfg)
2668             {
2669                 // do the formatting only for few starting characters (for "* " or "- " conversion)
2670                 SwPosition aPos(*rSh.GetCursor()->GetPoint());
2671                 if (aPos.nContent < 3)
2672                 {
2673                     SvxSwAutoFormatFlags& rFlags = pACorr->GetSwFlags();
2674                     if(pACfg->IsAutoFormatByInput() && rFlags.bSetNumRule && rFlags.bSetNumRuleAfterSpace)
2675                         rSh.AutoFormat(&rFlags, true);
2676                 }
2677             }
2678         }
2679         break;
2680 
2681         case SwKeyState::CheckAutoCorrect:
2682         {
2683             if( pACorr && pACfg->IsAutoFormatByInput() &&
2684                 pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2685                                         ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
2686                                         ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2687                                         ACFlags::Autocorrect | ACFlags::SetDOIAttr ) &&
2688                 !rSh.HasReadonlySel() )
2689             {
2690                 FlushInBuffer();
2691                 rSh.AutoCorrect( *pACorr, u'\0' );
2692             }
2693             eKeyState = eNextKeyState;
2694         }
2695         break;
2696 
2697         default:
2698         {
2699             sal_uInt16 nSlotId = 0;
2700             FlushInBuffer();
2701             switch( eKeyState )
2702             {
2703             case SwKeyState::SpecialInsert:
2704                 rSh.DoSpecialInsert();
2705                 break;
2706 
2707             case SwKeyState::NoNum:
2708                 rSh.NoNum();
2709                 break;
2710 
2711             case SwKeyState::NumOff:
2712                 // shell change - so record in advance
2713                 rSh.DelNumRules();
2714                 break;
2715             case SwKeyState::OutlineLvOff: // delete autofmt outlinelevel later
2716                 break;
2717 
2718             case SwKeyState::NumDown:
2719                 rSh.NumUpDown();
2720                 m_nKS_NUMDOWN_Count = 2;
2721                 break;
2722             case SwKeyState::NumUp:
2723                 rSh.NumUpDown( false );
2724                 break;
2725 
2726             case SwKeyState::NumIndentInc:
2727                 rSh.ChangeIndentOfAllListLevels(360);
2728                 m_nKS_NUMINDENTINC_Count = 2;
2729                 break;
2730 
2731             case SwKeyState::GotoNextFieldMark:
2732                 {
2733                     rSh.GotoFormControl(/*bNext=*/true);
2734                 }
2735                 break;
2736 
2737             case SwKeyState::GotoPrevFieldMark:
2738                 {
2739                     rSh.GotoFormControl(/*bNext=*/false);
2740                 }
2741                 break;
2742 
2743             case SwKeyState::NumIndentDec:
2744                 rSh.ChangeIndentOfAllListLevels(-360);
2745                 break;
2746 
2747             case SwKeyState::OutlineDown:
2748                 rSh.OutlineUpDown();
2749                 break;
2750             case SwKeyState::OutlineUp:
2751                 rSh.OutlineUpDown( -1 );
2752                 break;
2753 
2754             case SwKeyState::NextCell:
2755                 // always 'flush' in tables
2756                 rSh.GoNextCell(!rSh.HasReadonlySel());
2757                 nSlotId = FN_GOTO_NEXT_CELL;
2758                 break;
2759             case SwKeyState::PrevCell:
2760                 rSh.GoPrevCell();
2761                 nSlotId = FN_GOTO_PREV_CELL;
2762                 break;
2763             case SwKeyState::AutoFormatByInput:
2764                 rSh.SplitNode( true );
2765                 break;
2766 
2767             case SwKeyState::NextObject:
2768             case SwKeyState::PrevObject:
2769                 if(rSh.GotoObj( SwKeyState::NextObject == eKeyState, GotoObjFlags::Any))
2770                 {
2771                     if( rSh.IsFrameSelected() &&
2772                         m_rView.GetDrawFuncPtr() )
2773                     {
2774                         m_rView.GetDrawFuncPtr()->Deactivate();
2775                         m_rView.SetDrawFuncPtr(nullptr);
2776                         m_rView.LeaveDrawCreate();
2777                         m_rView.AttrChangedNotify(nullptr);
2778                     }
2779                     rSh.HideCursor();
2780                     rSh.EnterSelFrameMode();
2781                 }
2782             break;
2783             case SwKeyState::GlossaryExpand:
2784             {
2785                 // replace the word or abbreviation with the auto text
2786                 rSh.StartUndo( SwUndoId::START );
2787 
2788                 OUString sFnd(aTmpQHD.CurStr());
2789                 if( aTmpQHD.m_bIsAutoText )
2790                 {
2791                     SwGlossaryList* pList = ::GetGlossaryList();
2792                     OUString sShrtNm;
2793                     OUString sGroup;
2794                     if(pList->GetShortName( sFnd, sShrtNm, sGroup))
2795                     {
2796                         rSh.SttSelect();
2797                         rSh.ExtendSelection(false, aTmpQHD.CurLen());
2798                         SwGlossaryHdl* pGlosHdl = GetView().GetGlosHdl();
2799                         pGlosHdl->SetCurGroup(sGroup, true);
2800                         pGlosHdl->InsertGlossary( sShrtNm);
2801                         s_pQuickHlpData->m_bAppendSpace = true;
2802                     }
2803                 }
2804                 else
2805                 {
2806                     sFnd = sFnd.copy(aTmpQHD.CurLen());
2807                     rSh.Insert( sFnd );
2808                     s_pQuickHlpData->m_bAppendSpace = !pACorr ||
2809                             pACorr->GetSwFlags().bAutoCmpltAppendBlank;
2810                 }
2811                 rSh.EndUndo( SwUndoId::END );
2812             }
2813             break;
2814 
2815             case SwKeyState::NextPrevGlossary:
2816                 s_pQuickHlpData->Move( aTmpQHD );
2817                 s_pQuickHlpData->Start(rSh, false);
2818                 break;
2819 
2820             case SwKeyState::EditFormula:
2821             {
2822                 const sal_uInt16 nId = SwInputChild::GetChildWindowId();
2823 
2824                 SfxViewFrame& rVFrame = GetView().GetViewFrame();
2825                 rVFrame.ToggleChildWindow( nId );
2826                 SwInputChild* pChildWin = static_cast<SwInputChild*>(rVFrame.
2827                                                     GetChildWindow( nId ));
2828                 if( pChildWin )
2829                     pChildWin->SetFormula( sFormulaEntry );
2830             }
2831             break;
2832 
2833             case SwKeyState::ColLeftBig:         rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );   break;
2834             case SwKeyState::ColRightBig:        rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );  break;
2835             case SwKeyState::ColLeftSmall:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft, pModOpt->GetTableHMove() );   break;
2836             case SwKeyState::ColRightSmall:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight, pModOpt->GetTableHMove() );  break;
2837             case SwKeyState::ColBottomBig:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() ); break;
2838             case SwKeyState::ColBottomSmall:     rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom, pModOpt->GetTableVMove() ); break;
2839             case SwKeyState::CellLeftBig:        rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() );  break;
2840             case SwKeyState::CellRightBig:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
2841             case SwKeyState::CellLeftSmall:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft, pModOpt->GetTableHMove() );  break;
2842             case SwKeyState::CellRightSmall:     rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight, pModOpt->GetTableHMove() ); break;
2843             case SwKeyState::CellTopBig:         rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() );   break;
2844             case SwKeyState::CellBottomBig:      rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() );    break;
2845             case SwKeyState::CellTopSmall:       rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop, pModOpt->GetTableVMove() );   break;
2846             case SwKeyState::CellBottomSmall:    rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom, pModOpt->GetTableVMove() );    break;
2847 
2848             case SwKeyState::Fly_Change:
2849             {
2850                 SdrView *pSdrView = rSh.GetDrawView();
2851                 const SdrHdlList& rHdlList = pSdrView->GetHdlList();
2852                 if(rHdlList.GetFocusHdl())
2853                     ChangeDrawing( nDir );
2854                 else
2855                     ChangeFly( nDir, dynamic_cast<const SwWebView*>( &m_rView) !=  nullptr );
2856             }
2857             break;
2858             case SwKeyState::Draw_Change :
2859                 ChangeDrawing( nDir );
2860                 break;
2861             default:
2862                 break;
2863             }
2864             if( nSlotId && m_rView.GetViewFrame().GetBindings().GetRecorder().is() )
2865             {
2866                 SfxRequest aReq(m_rView.GetViewFrame(), nSlotId);
2867                 aReq.Done();
2868             }
2869             eKeyState = SwKeyState::End;
2870         }
2871         }
2872     }
2873 
2874     // update the page number in the statusbar
2875     nKey = rKEvt.GetKeyCode().GetCode();
2876     if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey )
2877         GetView().GetViewFrame().GetBindings().Update( FN_STAT_PAGE );
2878 
2879     m_bMaybeShowTooltipAfterBufferFlush = bNormalChar;
2880 
2881     // in case the buffered characters are inserted
2882     if( bFlushBuffer && !m_aInBuffer.isEmpty() )
2883     {
2884         FlushInBuffer();
2885     }
2886 
2887     // get the word count dialog to update itself
2888     SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
2889     if( pWrdCnt )
2890         pWrdCnt->UpdateCounts();
2891 
2892 }
2893 
2894 /**
2895  * MouseEvents
2896  */
ResetMouseButtonDownFlags()2897 void SwEditWin::ResetMouseButtonDownFlags()
2898 {
2899     // Not on all systems a MouseButtonUp is used ahead
2900     // of the modal dialog (like on WINDOWS).
2901     // So reset the statuses here and release the mouse
2902     // for the dialog.
2903     m_bMBPressed = false;
2904     g_bNoInterrupt = false;
2905     EnterArea();
2906     ReleaseMouse();
2907 }
2908 
2909 /**
2910  * Determines if the current position has a clickable url over a background
2911  * frame. In that case, ctrl-click should select the url, not the frame.
2912  */
lcl_urlOverBackground(SwWrtShell & rSh,const Point & rDocPos)2913 static bool lcl_urlOverBackground(SwWrtShell& rSh, const Point& rDocPos)
2914 {
2915     SwContentAtPos aSwContentAtPos(IsAttrAtPos::InetAttr);
2916     SdrObject* pSelectableObj = rSh.GetObjAt(rDocPos);
2917 
2918     return rSh.GetContentAtPos(rDocPos, aSwContentAtPos) && pSelectableObj->GetLayer() == rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId();
2919 }
2920 
MoveCursor(SwWrtShell & rSh,const Point & rDocPos,const bool bOnlyText,bool bLockView)2921 void SwEditWin::MoveCursor( SwWrtShell &rSh, const Point& rDocPos,
2922                             const bool bOnlyText, bool bLockView )
2923 {
2924     const bool bTmpNoInterrupt = g_bNoInterrupt;
2925     g_bNoInterrupt = false;
2926 
2927     int nTmpSetCursor = 0;
2928 
2929     if( !rSh.IsViewLocked() && bLockView )
2930         rSh.LockView( true );
2931     else
2932         bLockView = false;
2933 
2934     {
2935         // only temporary generate move context because otherwise
2936         // the query to the content form doesn't work!!!
2937         SwMvContext aMvContext( &rSh );
2938         nTmpSetCursor = rSh.CallSetCursor(&rDocPos, bOnlyText);
2939         g_bValidCursorPos = !(CRSR_POSCHG & nTmpSetCursor);
2940     }
2941 
2942     // notify the edit window that from now on we do not use the input language
2943     if ( !(CRSR_POSOLD & nTmpSetCursor) )
2944         SetUseInputLanguage( false );
2945 
2946     if( bLockView )
2947         rSh.LockView( false );
2948 
2949     g_bNoInterrupt = bTmpNoInterrupt;
2950 }
2951 
MouseButtonDown(const MouseEvent & _rMEvt)2952 void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
2953 {
2954     SwWrtShell &rSh = m_rView.GetWrtShell();
2955     const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
2956 
2957     // We have to check if a context menu is shown and we have an UI
2958     // active inplace client. In that case we have to ignore the mouse
2959     // button down event. Otherwise we would crash (context menu has been
2960     // opened by inplace client and we would deactivate the inplace client,
2961     // the context menu is closed by VCL asynchronously which in the end
2962     // would work on deleted objects or the context menu has no parent anymore)
2963     SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
2964     bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
2965 
2966     if (bIsOleActive && vcl::IsInPopupMenuExecute())
2967         return;
2968 
2969     MouseEvent aMEvt(_rMEvt);
2970 
2971     if (m_rView.GetPostItMgr()->IsHit(aMEvt.GetPosPixel()))
2972         return;
2973 
2974     if (comphelper::LibreOfficeKit::isActive())
2975     {
2976         if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(aMEvt.GetPosPixel()))
2977         {
2978             pWindow->MouseButtonDown(aMEvt);
2979             return;
2980         }
2981     }
2982 
2983     if (m_rView.GetPostItMgr()->IsHitSidebarDragArea(aMEvt.GetPosPixel()))
2984     {
2985         mbIsDragSidebar = true;
2986         return;
2987     }
2988 
2989     m_rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
2990 
2991     GrabFocus();
2992     rSh.addCurrentPosition();
2993 
2994     //ignore key modifiers for format paintbrush
2995     {
2996         bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
2997                                 &&  m_pApplyTempl->m_pFormatClipboard->HasContent();
2998         if( bExecFormatPaintbrush )
2999             aMEvt = MouseEvent(_rMEvt.GetPosPixel(), _rMEvt.GetClicks(), _rMEvt.GetMode(),
3000                                _rMEvt.GetButtons());
3001     }
3002 
3003     m_bWasShdwCursor = nullptr != m_pShadCursor;
3004     m_pShadCursor.reset();
3005 
3006     const Point aDocPos(PixelToLogic(aMEvt.GetPosPixel()));
3007 
3008     FrameControlType eControl;
3009     bool bOverFly = false;
3010     bool bPageAnchored = false;
3011     bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
3012 
3013     bool bIsViewReadOnly = m_rView.GetDocShell()->IsReadOnly() || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
3014     if (bOverHeaderFooterFly && (!bIsViewReadOnly && rSh.GetCurField()))
3015         // We have a field here, that should have priority over header/footer fly.
3016         bOverHeaderFooterFly = false;
3017 
3018     // Are we clicking on a blank header/footer area?
3019     if ( IsInHeaderFooter( aDocPos, eControl ) || bOverHeaderFooterFly )
3020     {
3021         const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( aDocPos );
3022 
3023         if ( pPageFrame )
3024         {
3025             // Is it active?
3026             bool bActive = true;
3027             const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
3028 
3029             const SwFrameFormat* pFormat = pDesc->GetLeftFormat();
3030             if ( pPageFrame->OnRightPage() )
3031                  pFormat = pDesc->GetRightFormat();
3032 
3033             if ( pFormat )
3034             {
3035                 if ( eControl == FrameControlType::Header )
3036                     bActive = pFormat->GetHeader().IsActive();
3037                 else
3038                     bActive = pFormat->GetFooter().IsActive();
3039             }
3040 
3041             if ( !bActive )
3042             {
3043                 // HeaderFooter menu implies header/footer controls, so only do this with IsUseHeaderFooterMenu enabled.
3044                 // But, additionally, when in Hide-Whitespace mode, we don't want those controls.
3045                 if (rSh.GetViewOptions()->IsUseHeaderFooterMenu() && !rSh.GetViewOptions()->IsHideWhitespaceMode())
3046                 {
3047                     SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
3048                     const bool bWasInHeader = aPam.GetPoint()->GetNode().FindHeaderStartNode() != nullptr;
3049                     const bool bWasInFooter = aPam.GetPoint()->GetNode().FindFooterStartNode() != nullptr;
3050 
3051                     // Is the cursor in a part like similar to the one we clicked on? For example,
3052                     // if the cursor is in a header and we click on an empty header... don't change anything to
3053                     // keep consistent behaviour due to header edit mode (and the same for the footer as well).
3054 
3055                     // Otherwise, we hide the header/footer control if a separator is shown, and vice versa.
3056                     if (!(bWasInHeader && eControl == FrameControlType::Header) &&
3057                         !(bWasInFooter && eControl == FrameControlType::Footer))
3058                     {
3059                         const bool bSeparatorWasVisible = rSh.IsShowHeaderFooterSeparator(eControl);
3060                         rSh.SetShowHeaderFooterSeparator(eControl, !bSeparatorWasVisible);
3061 
3062                         // Repaint everything
3063                         Invalidate();
3064 
3065                         // tdf#84929. If the footer control had not been showing, do not change the cursor position,
3066                         // because the user may have scrolled to turn on the separator control and
3067                         // if the cursor cannot be positioned on-screen, then the user would need to scroll back again to use the control.
3068                         // This should only be done for the footer. The cursor can always be re-positioned near the header. tdf#134023.
3069                         if ( eControl == FrameControlType::Footer && !bSeparatorWasVisible
3070                              && !Application::IsHeadlessModeEnabled() )
3071                             return;
3072                     }
3073                 }
3074             }
3075             else
3076             {
3077                 // Make sure we have the proper Header/Footer separators shown
3078                 // as these may be changed if clicking on an empty Header/Footer
3079                 rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, eControl == FrameControlType::Header );
3080                 rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, eControl == FrameControlType::Footer );
3081 
3082                 if ( !rSh.IsHeaderFooterEdit() )
3083                     rSh.ToggleHeaderFooterEdit();
3084             }
3085         }
3086     }
3087     else
3088     {
3089         if ( rSh.IsHeaderFooterEdit( ) )
3090             rSh.ToggleHeaderFooterEdit( );
3091         else
3092         {
3093             // Make sure that the separators are hidden
3094             rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, false );
3095             rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
3096         }
3097 
3098         // Toggle Hide-Whitespace if between pages.
3099         if (rSh.GetViewOptions()->CanHideWhitespace() &&
3100             rSh.GetLayout()->IsBetweenPages(aDocPos))
3101         {
3102             if (_rMEvt.GetClicks() >= 2)
3103             {
3104                 SwViewOption aOpt(*rSh.GetViewOptions());
3105                 aOpt.SetHideWhitespaceMode(!aOpt.IsHideWhitespaceMode());
3106                 rSh.ApplyViewOptions(aOpt);
3107             }
3108 
3109             return;
3110         }
3111     }
3112 
3113     if ( IsChainMode() )
3114     {
3115         SetChainMode( false );
3116         SwRect aDummy;
3117         SwFlyFrameFormat *pFormat = static_cast<SwFlyFrameFormat*>(rSh.GetFlyFrameFormat());
3118         if ( rSh.Chainable( aDummy, *pFormat, aDocPos ) == SwChainRet::OK )
3119             rSh.Chain( *pFormat, aDocPos );
3120         UpdatePointer(aDocPos, aMEvt.GetModifier());
3121         return;
3122     }
3123 
3124     // After GrabFocus a shell should be pushed. That should actually
3125     // work but in practice ...
3126     m_rView.SelectShellForDrop();
3127 
3128     bool bCallBase = true;
3129 
3130     if( s_pQuickHlpData->m_bIsDisplayed )
3131         s_pQuickHlpData->Stop( rSh );
3132     s_pQuickHlpData->m_bAppendSpace = false;
3133 
3134     if( rSh.FinishOLEObj() )
3135         return; // end InPlace and the click doesn't count anymore
3136 
3137     CurrShell aCurr( &rSh );
3138 
3139     SdrView *pSdrView = rSh.GetDrawView();
3140     if ( pSdrView )
3141     {
3142         if (pSdrView->MouseButtonDown(aMEvt, GetOutDev()))
3143         {
3144             rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
3145             return; // SdrView's event evaluated
3146         }
3147     }
3148 
3149     m_bIsInMove = false;
3150     m_aStartPos = aMEvt.GetPosPixel();
3151     m_aRszMvHdlPt.setX( 0 );
3152     m_aRszMvHdlPt.setY( 0 );
3153 
3154     SwTab nMouseTabCol = SwTab::COL_NONE;
3155     const bool bTmp = !rSh.IsDrawCreate() && !m_pApplyTempl && !rSh.IsInSelect()
3156                       && aMEvt.GetClicks() == 1 && MOUSE_LEFT == aMEvt.GetButtons();
3157 
3158     if (  bTmp &&
3159          SwTab::COL_NONE != (nMouseTabCol = rSh.WhichMouseTabCol( aDocPos ) ) &&
3160          ( !rSh.IsObjSelectable( aDocPos ) ||
3161              // allow resizing row height, if the image is anchored as character in the cell
3162              !( SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol ) ) )
3163     {
3164         // Enhanced table selection
3165         if ( SwTab::SEL_HORI <= nMouseTabCol && SwTab::COLSEL_VERT >= nMouseTabCol )
3166         {
3167             rSh.EnterStdMode();
3168             rSh.SelectTableRowCol( aDocPos );
3169             if( SwTab::SEL_HORI  != nMouseTabCol && SwTab::SEL_HORI_RTL  != nMouseTabCol)
3170             {
3171                 m_xRowColumnSelectionStart = aDocPos;
3172                 m_bIsRowDrag = SwTab::ROWSEL_HORI == nMouseTabCol||
3173                             SwTab::ROWSEL_HORI_RTL == nMouseTabCol ||
3174                             SwTab::COLSEL_VERT == nMouseTabCol;
3175                 m_bMBPressed = true;
3176                 CaptureMouse();
3177             }
3178             return;
3179         }
3180 
3181         if ( !rSh.IsTableMode() )
3182         {
3183             // comes from table columns out of the document.
3184             if(SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol)
3185                 m_rView.SetTabColFromDoc( true );
3186             else
3187                 m_rView.SetTabRowFromDoc( true );
3188 
3189             m_rView.SetTabColFromDocPos( aDocPos );
3190             m_rView.InvalidateRulerPos();
3191             SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
3192             rBind.Update();
3193             if (RulerColumnDrag(
3194                     aMEvt, (SwTab::COL_VERT == nMouseTabCol || SwTab::ROW_HORI == nMouseTabCol)))
3195             {
3196                 m_rView.SetTabColFromDoc( false );
3197                 m_rView.SetTabRowFromDoc( false );
3198                 m_rView.InvalidateRulerPos();
3199                 rBind.Update();
3200                 bCallBase = false;
3201             }
3202             else
3203             {
3204                 return;
3205             }
3206         }
3207     }
3208     else if (bTmp &&
3209              rSh.IsNumLabel(aDocPos))
3210     {
3211         SwTextNode* pNodeAtPos = rSh.GetNumRuleNodeAtPos( aDocPos );
3212         m_rView.SetNumRuleNodeFromDoc( pNodeAtPos );
3213         m_rView.InvalidateRulerPos();
3214         SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
3215         rBind.Update();
3216 
3217         if (RulerMarginDrag(aMEvt, SwFEShell::IsVerticalModeAtNdAndPos(*pNodeAtPos, aDocPos)))
3218         {
3219             m_rView.SetNumRuleNodeFromDoc( nullptr );
3220             m_rView.InvalidateRulerPos();
3221             rBind.Update();
3222             bCallBase = false;
3223         }
3224         else
3225         {
3226             // Make sure the pointer is set to 0, otherwise it may point to
3227             // nowhere after deleting the corresponding text node.
3228             m_rView.SetNumRuleNodeFromDoc( nullptr );
3229             return;
3230         }
3231     }
3232 
3233     if ( rSh.IsInSelect() )
3234         rSh.EndSelect();
3235 
3236     // query against LEFT because otherwise for example also a right
3237     // click releases the selection.
3238     if (MOUSE_LEFT == aMEvt.GetButtons())
3239     {
3240         bool bOnlyText = false;
3241         m_bMBPressed = true;
3242         g_bNoInterrupt = true;
3243         m_nKS_NUMDOWN_Count = 0;
3244 
3245         CaptureMouse();
3246 
3247         // reset cursor position if applicable
3248         rSh.ResetCursorStack();
3249 
3250         switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3251         {
3252             case MOUSE_LEFT:
3253             case MOUSE_LEFT + KEY_SHIFT:
3254             case MOUSE_LEFT + KEY_MOD2:
3255                 if( rSh.IsObjSelected() )
3256                 {
3257                     SdrHdl* pHdl;
3258                     if( !bIsViewReadOnly &&
3259                         !m_pAnchorMarker &&
3260                         pSdrView &&
3261                         nullptr != ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3262                             ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3263                               pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3264                     {
3265                         // #i121463# Set selected during drag
3266                         pHdl->SetSelected();
3267                         m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3268                         UpdatePointer(aDocPos, aMEvt.GetModifier());
3269                         return;
3270                     }
3271                 }
3272                 if (EnterDrawMode(aMEvt, aDocPos))
3273                 {
3274                     g_bNoInterrupt = false;
3275                     return;
3276                 }
3277                 else  if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
3278                 {
3279                     StopInsFrame();
3280                     rSh.Edit();
3281                 }
3282 
3283                 // Without SHIFT because otherwise Toggle doesn't work at selection
3284                 if (aMEvt.GetClicks() == 1)
3285                 {
3286                     if ( rSh.IsSelFrameMode())
3287                     {
3288                         SdrHdl* pHdl = rSh.GetDrawView()->PickHandle(aDocPos);
3289                         bool bHitHandle = pHdl && pHdl->GetKind() != SdrHdlKind::Anchor &&
3290                                                   pHdl->GetKind() != SdrHdlKind::Anchor_TR;
3291 
3292                         if ((rSh.IsInsideSelectedObj(aDocPos) || bHitHandle)
3293                             && (aMEvt.GetModifier() != KEY_SHIFT || bHitHandle))
3294                         {
3295                             rSh.EnterSelFrameMode( &aDocPos );
3296                             if ( !m_pApplyTempl )
3297                             {
3298                                 // only if no position to size was hit.
3299                                 if (!bHitHandle)
3300                                 {
3301                                     StartDDTimer();
3302                                     SwEditWin::s_nDDStartPosY = aDocPos.Y();
3303                                     SwEditWin::s_nDDStartPosX = aDocPos.X();
3304                                 }
3305                                 g_bFrameDrag = true;
3306                             }
3307                             g_bNoInterrupt = false;
3308                             return;
3309                         }
3310                     }
3311                 }
3312         }
3313 
3314         bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
3315         if ( !bExecHyperlinks )
3316         {
3317             const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
3318             if ((bSecureOption && aMEvt.GetModifier() == KEY_MOD1)
3319                 || (!bSecureOption && aMEvt.GetModifier() != KEY_MOD1))
3320                 bExecHyperlinks = true;
3321         }
3322 
3323         // Enhanced selection
3324         sal_uInt8 nNumberOfClicks = static_cast<sal_uInt8>(aMEvt.GetClicks() % 4);
3325         if (0 == nNumberOfClicks && 0 < aMEvt.GetClicks())
3326             nNumberOfClicks = 4;
3327 
3328         bool bExecDrawTextLink = false;
3329 
3330         switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3331         {
3332             case MOUSE_LEFT:
3333             case MOUSE_LEFT + KEY_MOD1:
3334             case MOUSE_LEFT + KEY_MOD2:
3335             {
3336 
3337                 // fdo#79604: first, check if a link has been clicked - do not
3338                 // select fly in this case!
3339                 if (1 == nNumberOfClicks)
3340                 {
3341                     UpdatePointer(aDocPos, aMEvt.GetModifier());
3342                     SwEditWin::s_nDDStartPosY = aDocPos.Y();
3343                     SwEditWin::s_nDDStartPosX = aDocPos.X();
3344 
3345                     // hit a URL in DrawText object?
3346                     if (bExecHyperlinks && pSdrView)
3347                     {
3348                         SdrViewEvent aVEvt;
3349                         pSdrView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
3350 
3351                         if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
3352                             bExecDrawTextLink = true;
3353                     }
3354                 }
3355 
3356                 if (1 == nNumberOfClicks && !bExecDrawTextLink)
3357                 {
3358                     // only try to select frame, if pointer already was
3359                     // switched accordingly
3360                     if ( m_aActHitType != SdrHitKind::NONE && !rSh.IsSelFrameMode() &&
3361                         !GetView().GetViewFrame().GetDispatcher()->IsLocked())
3362                     {
3363                         // Test if there is a draw object at that position and if it should be selected.
3364                         bool bSelectFrameInsteadOfCroppedImage = false;
3365                         bool bShould = rSh.ShouldObjectBeSelected(aDocPos, &bSelectFrameInsteadOfCroppedImage);
3366 
3367                         if(bShould)
3368                         {
3369                             m_rView.NoRotate();
3370                             rSh.HideCursor();
3371 
3372                             bool bUnLockView = !rSh.IsViewLocked();
3373                             rSh.LockView( true );
3374                             bool bSelObj
3375                                 = rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0);
3376                             if ( bSelObj && bSelectFrameInsteadOfCroppedImage && pSdrView )
3377                             {
3378                                 bool bWrapped(false);
3379                                 const SdrObject* pFly = rSh.GetBestObject(false, GotoObjFlags::FlyAny, true, nullptr, &bWrapped);
3380                                 pSdrView->UnmarkAllObj();
3381                                 bSelObj =
3382                                     rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0, const_cast<SdrObject*>(pFly));
3383                             }
3384                             if( bUnLockView )
3385                                 rSh.LockView( false );
3386 
3387                             if( bSelObj )
3388                             {
3389                                 // if the frame was deselected in the macro
3390                                 // the cursor just has to be displayed again
3391                                 if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
3392                                     rSh.ShowCursor();
3393                                 else
3394                                 {
3395                                     if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
3396                                     {
3397                                         m_rView.GetDrawFuncPtr()->Deactivate();
3398                                         m_rView.SetDrawFuncPtr(nullptr);
3399                                         m_rView.LeaveDrawCreate();
3400                                         m_rView.AttrChangedNotify(nullptr);
3401                                     }
3402 
3403                                     rSh.EnterSelFrameMode( &aDocPos );
3404                                     g_bFrameDrag = true;
3405                                     UpdatePointer(aDocPos, aMEvt.GetModifier());
3406                                 }
3407                                 return;
3408                             }
3409                             else
3410                                 bOnlyText = rSh.IsObjSelectable( aDocPos );
3411 
3412                             if (!m_rView.GetDrawFuncPtr())
3413                                 rSh.ShowCursor();
3414                         }
3415                         else
3416                             bOnlyText = KEY_MOD1 != aMEvt.GetModifier();
3417                     }
3418                     else if ( rSh.IsSelFrameMode() &&
3419                               (m_aActHitType == SdrHitKind::NONE ||
3420                                !rSh.IsInsideSelectedObj( aDocPos )))
3421                     {
3422                         m_rView.NoRotate();
3423                         SdrHdl *pHdl;
3424                         if( !bIsViewReadOnly && !m_pAnchorMarker && nullptr !=
3425                             ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3426                                 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3427                                   pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3428                         {
3429                             m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3430                             UpdatePointer(aDocPos, aMEvt.GetModifier());
3431                             return;
3432                         }
3433                         else
3434                         {
3435                             bool bUnLockView = !rSh.IsViewLocked();
3436                             rSh.LockView( true );
3437                             sal_uInt8 nFlag = aMEvt.IsShift() ? SW_ADD_SELECT : 0;
3438                             if (aMEvt.IsMod1())
3439                                 nFlag = nFlag | SW_ENTER_GROUP;
3440 
3441                             if ( rSh.IsSelFrameMode() )
3442                             {
3443                                 rSh.UnSelectFrame();
3444                                 rSh.LeaveSelFrameMode();
3445                                 m_rView.AttrChangedNotify(nullptr);
3446                             }
3447 
3448                             bool bSelObj = rSh.SelectObj( aDocPos, nFlag );
3449                             if( bUnLockView )
3450                                 rSh.LockView( false );
3451 
3452                             if( !bSelObj )
3453                             {
3454                                 // move cursor here so that it is not drawn in the
3455                                 // frame first; ShowCursor() happens in LeaveSelFrameMode()
3456                                 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
3457                                 rSh.LeaveSelFrameMode();
3458                                 m_rView.AttrChangedNotify(nullptr);
3459                                 bCallBase = false;
3460                             }
3461                             else
3462                             {
3463                                 rSh.HideCursor();
3464                                 rSh.EnterSelFrameMode( &aDocPos );
3465                                 rSh.SelFlyGrabCursor();
3466                                 rSh.MakeSelVisible();
3467                                 g_bFrameDrag = true;
3468                                 if( rSh.IsFrameSelected() &&
3469                                     m_rView.GetDrawFuncPtr() )
3470                                 {
3471                                     m_rView.GetDrawFuncPtr()->Deactivate();
3472                                     m_rView.SetDrawFuncPtr(nullptr);
3473                                     m_rView.LeaveDrawCreate();
3474                                     m_rView.AttrChangedNotify(nullptr);
3475                                 }
3476                                 UpdatePointer(aDocPos, aMEvt.GetModifier());
3477                                 return;
3478                             }
3479                         }
3480                     }
3481                 }
3482 
3483                 switch ( nNumberOfClicks )
3484                 {
3485                     case 1:
3486                         break;
3487                     case 2:
3488                     {
3489                         g_bFrameDrag = false;
3490                         if (!bIsViewReadOnly && rSh.IsInsideSelectedObj(aDocPos)
3491                             && (FlyProtectFlags::NONE
3492                                     == rSh.IsSelObjProtected(FlyProtectFlags::Content
3493                                                              | FlyProtectFlags::Parent)
3494                                 || rSh.GetSelectionType() == SelectionType::Ole))
3495                         {
3496                         /* This is no good: on the one hand GetSelectionType is used as flag field
3497                          * (take a look into the GetSelectionType method) and on the other hand the
3498                          * return value is used in a switch without proper masking (very nice), this must lead to trouble
3499                          */
3500                             switch ( rSh.GetSelectionType() & ~SelectionType( SelectionType::FontWork | SelectionType::ExtrudedCustomShape ) )
3501                             {
3502                             case SelectionType::Graphic:
3503                                 ResetMouseButtonDownFlags();
3504                                 if (!comphelper::LibreOfficeKit::isActive())
3505                                 {
3506                                     GetView().GetViewFrame().GetBindings().Execute(
3507                                         FN_FORMAT_GRAFIC_DLG, nullptr,
3508                                         SfxCallMode::RECORD|SfxCallMode::SLOT);
3509                                 }
3510                                 return;
3511 
3512                             // double click on OLE object --> OLE-InPlace
3513                             case SelectionType::Ole:
3514                                 ResetMouseButtonDownFlags();
3515                                 rSh.LaunchOLEObj();
3516                                 return;
3517 
3518                             case SelectionType::Frame:
3519                                 ResetMouseButtonDownFlags();
3520                                 if (!comphelper::LibreOfficeKit::isActive())
3521                                 {
3522                                     GetView().GetViewFrame().GetBindings().Execute(
3523                                         FN_FORMAT_FRAME_DLG, nullptr,
3524                                         SfxCallMode::RECORD|SfxCallMode::SLOT);
3525                                 }
3526                                 return;
3527 
3528                             case SelectionType::DrawObject:
3529                                 ResetMouseButtonDownFlags();
3530                                 EnterDrawTextMode(aDocPos);
3531                                 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>(  m_rView.GetCurShell() )  )
3532                                     pSwDrawTextShell->Init();
3533                                 return;
3534 
3535                             default: break;
3536                             }
3537                         }
3538 
3539                         // if the cursor position was corrected or if a Fly
3540                         // was selected in ReadOnlyMode, no word selection, except when tiled rendering.
3541                         if ((!g_bValidCursorPos || rSh.IsFrameSelected()) && !comphelper::LibreOfficeKit::isActive())
3542                             return;
3543 
3544                         SwField *pField;
3545                         bool bFootnote = false;
3546 
3547                         if( !bIsViewReadOnly &&
3548                             (nullptr != (pField = rSh.GetCurField(true)) ||
3549                               ( bFootnote = rSh.GetCurFootnote() )        ) )
3550                         {
3551                             ResetMouseButtonDownFlags();
3552                             if( bFootnote )
3553                                 GetView().GetViewFrame().GetBindings().Execute( FN_EDIT_FOOTNOTE );
3554                             else
3555                             {
3556                                 SwFieldTypesEnum nTypeId = pField->GetTypeId();
3557                                 SfxViewFrame& rVFrame = GetView().GetViewFrame();
3558                                 switch( nTypeId )
3559                                 {
3560                                 case SwFieldTypesEnum::Postit:
3561                                 case SwFieldTypesEnum::Script:
3562                                 {
3563                                     // if it's a Readonly region, status has to be enabled
3564                                     sal_uInt16 nSlot = SwFieldTypesEnum::Postit == nTypeId ? FN_POSTIT : FN_JAVAEDIT;
3565                                     SfxBoolItem aItem(nSlot, true);
3566                                     rVFrame.GetBindings().SetState(aItem);
3567                                     rVFrame.GetBindings().Execute(nSlot);
3568                                     break;
3569                                 }
3570                                 case SwFieldTypesEnum::Authority :
3571                                     rVFrame.GetBindings().Execute(FN_EDIT_AUTH_ENTRY_DLG);
3572                                 break;
3573                                 case SwFieldTypesEnum::Input:
3574                                 case SwFieldTypesEnum::Dropdown:
3575                                 case SwFieldTypesEnum::SetInput:
3576                                     rVFrame.GetBindings().Execute(FN_UPDATE_INPUTFIELDS);
3577                                     break;
3578                                 default:
3579                                     rVFrame.GetBindings().Execute(FN_EDIT_FIELD);
3580                                 }
3581                             }
3582                             return;
3583                         }
3584                         // in extended mode double and triple
3585                         // click has no effect.
3586                         if ( rSh.IsExtMode() || rSh.IsBlockMode() )
3587                             return;
3588 
3589                         // select word, AdditionalMode if applicable
3590                         if (KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode())
3591                         {
3592                             rSh.EnterAddMode();
3593                             rSh.SelWrd( &aDocPos );
3594                             rSh.LeaveAddMode();
3595                         }
3596                         else
3597                         {
3598                             if (!rSh.SelWrd(&aDocPos) && comphelper::LibreOfficeKit::isActive())
3599                                 // Double click did not select any word: try to
3600                                 // select the current cell in case we are in a
3601                                 // table.
3602                                 rSh.SelTableBox();
3603                         }
3604 
3605                         SwContentAtPos aContentAtPos(IsAttrAtPos::FormControl);
3606                         if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3607                                 aContentAtPos.aFnd.pFieldmark != nullptr)
3608                         {
3609                             IFieldmark *pFieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
3610                             if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN || pFieldBM->GetFieldname( ) == ODF_FORMDATE )
3611                             {
3612                                 ResetMouseButtonDownFlags();
3613                                 rSh.getIDocumentMarkAccess()->ClearFieldActivation();
3614                                 GetView().GetViewFrame().GetBindings().Execute(SID_FM_CTL_PROPERTIES);
3615                                 return;
3616                             }
3617                         }
3618 
3619                         // tdf#143158 - handle alphabetical index entries
3620                         SwContentAtPos aToxContentAtPos(IsAttrAtPos::ToxMark);
3621                         if (rSh.GetContentAtPos(aDocPos, aToxContentAtPos))
3622                         {
3623                             const OUString sToxText = aToxContentAtPos.sStr;
3624                             if (!sToxText.isEmpty() && aToxContentAtPos.pFndTextAttr)
3625                             {
3626                                 const SwTOXType* pTType
3627                                     = aToxContentAtPos.pFndTextAttr->GetTOXMark().GetTOXType();
3628                                 if (pTType && pTType->GetType() == TOXTypes::TOX_INDEX)
3629                                 {
3630                                     ResetMouseButtonDownFlags();
3631                                     GetView().GetViewFrame().GetBindings().Execute(
3632                                         FN_EDIT_IDX_ENTRY_DLG);
3633                                     return;
3634                                 }
3635                             }
3636                         }
3637 
3638                         g_bHoldSelection = true;
3639                         return;
3640                     }
3641                     case 3:
3642                     case 4:
3643                     {
3644                         g_bFrameDrag = false;
3645                         // in extended mode double and triple
3646                         // click has no effect.
3647                         if ( rSh.IsExtMode() )
3648                             return;
3649 
3650                         // if the cursor position was corrected or if a Fly
3651                         // was selected in ReadOnlyMode, no word selection.
3652                         if ( !g_bValidCursorPos || rSh.IsFrameSelected() )
3653                             return;
3654 
3655                         // select line, AdditionalMode if applicable
3656                         const bool bMod = KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode();
3657 
3658                         if ( bMod )
3659                             rSh.EnterAddMode();
3660 
3661                         // Enhanced selection
3662                         if ( 3 == nNumberOfClicks )
3663                             rSh.SelSentence( &aDocPos );
3664                         else
3665                             rSh.SelPara( &aDocPos );
3666 
3667                         if ( bMod )
3668                             rSh.LeaveAddMode();
3669 
3670                         g_bHoldSelection = true;
3671                         return;
3672                     }
3673 
3674                     default:
3675                         return;
3676                 }
3677 
3678                 [[fallthrough]];
3679             }
3680             case MOUSE_LEFT + KEY_SHIFT:
3681             case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
3682             {
3683                 bool bLockView = m_bWasShdwCursor;
3684 
3685                 switch (aMEvt.GetModifier())
3686                 {
3687                     case KEY_MOD1 + KEY_SHIFT:
3688                     {
3689                         if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3690                         {
3691                             m_rView.NoRotate();
3692                             rSh.HideCursor();
3693                             if ( rSh.IsSelFrameMode() )
3694                                 rSh.SelectObj(aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP);
3695                             else
3696                             {   if ( rSh.SelectObj( aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP ) )
3697                                 {
3698                                     rSh.EnterSelFrameMode( &aDocPos );
3699                                     SwEditWin::s_nDDStartPosY = aDocPos.Y();
3700                                     SwEditWin::s_nDDStartPosX = aDocPos.X();
3701                                     g_bFrameDrag = true;
3702                                     return;
3703                                 }
3704                             }
3705                         }
3706                         else if( rSh.IsSelFrameMode() &&
3707                                  rSh.GetDrawView()->PickHandle( aDocPos ))
3708                         {
3709                             g_bFrameDrag = true;
3710                             g_bNoInterrupt = false;
3711                             return;
3712                         }
3713                     }
3714                     break;
3715                     case KEY_MOD1:
3716                     if ( !bExecDrawTextLink )
3717                     {
3718                         if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
3719                         {
3720                             // ctrl+left-click on outline node frame
3721                             SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3722                             if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3723                             {
3724                                 SwOutlineNodes::size_type nPos;
3725                                 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
3726                                 {
3727                                     ToggleOutlineContentVisibility(nPos, false);
3728                                     return;
3729                                 }
3730                             }
3731                         }
3732                         if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3733                         {
3734                             m_rView.NoRotate();
3735                             rSh.HideCursor();
3736                             if ( rSh.IsSelFrameMode() )
3737                                 rSh.SelectObj(aDocPos, SW_ENTER_GROUP);
3738                             else
3739                             {   if ( rSh.SelectObj( aDocPos, SW_ENTER_GROUP ) )
3740                                 {
3741                                     rSh.EnterSelFrameMode( &aDocPos );
3742                                     SwEditWin::s_nDDStartPosY = aDocPos.Y();
3743                                     SwEditWin::s_nDDStartPosX = aDocPos.X();
3744                                     g_bFrameDrag = true;
3745                                     return;
3746                                 }
3747                             }
3748                         }
3749                         else if( rSh.IsSelFrameMode() &&
3750                                  rSh.GetDrawView()->PickHandle( aDocPos ))
3751                         {
3752                             g_bFrameDrag = true;
3753                             g_bNoInterrupt = false;
3754                             return;
3755                         }
3756                         else
3757                         {
3758                             if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3759                             {
3760                                 rSh.PushMode();
3761                                 g_bModePushed = true;
3762 
3763                                 bool bUnLockView = !rSh.IsViewLocked();
3764                                 rSh.LockView( true );
3765                                 rSh.EnterAddMode();
3766                                 if( bUnLockView )
3767                                     rSh.LockView( false );
3768                             }
3769                             bCallBase = false;
3770                         }
3771                     }
3772                     break;
3773                     case KEY_MOD2:
3774                     {
3775                         if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3776                         {
3777                             rSh.PushMode();
3778                             g_bModePushed = true;
3779                             bool bUnLockView = !rSh.IsViewLocked();
3780                             rSh.LockView( true );
3781                             rSh.EnterBlockMode();
3782                             if( bUnLockView )
3783                                 rSh.LockView( false );
3784                         }
3785                         bCallBase = false;
3786                     }
3787                     break;
3788                     case KEY_SHIFT:
3789                     {
3790                         if (nNumberOfClicks == 2)
3791                         {
3792                             // Left mouse button, shift, double-click: see if we have a graphic and
3793                             // dispatch its dialog in this case.
3794                             if (rSh.GetSelectionType() == SelectionType::Graphic)
3795                             {
3796                                 GetView().GetViewFrame().GetBindings().Execute(
3797                                     FN_FORMAT_GRAFIC_DLG, nullptr,
3798                                     SfxCallMode::RECORD | SfxCallMode::SLOT);
3799                                 return;
3800                             }
3801                         }
3802 
3803                         if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3804                         {
3805                             m_rView.NoRotate();
3806                             rSh.HideCursor();
3807                             if ( rSh.IsSelFrameMode() )
3808                             {
3809                                 rSh.SelectObj(aDocPos, SW_ADD_SELECT);
3810 
3811                                 const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
3812                                 if (rMarkList.GetMark(0) == nullptr)
3813                                 {
3814                                     rSh.LeaveSelFrameMode();
3815                                     m_rView.AttrChangedNotify(nullptr);
3816                                     g_bFrameDrag = false;
3817                                 }
3818                             }
3819                             else
3820                             {   if ( rSh.SelectObj( aDocPos ) )
3821                                 {
3822                                     rSh.EnterSelFrameMode( &aDocPos );
3823                                     SwEditWin::s_nDDStartPosY = aDocPos.Y();
3824                                     SwEditWin::s_nDDStartPosX = aDocPos.X();
3825                                     g_bFrameDrag = true;
3826                                     return;
3827                                 }
3828                             }
3829                         }
3830                         else
3831                         {
3832                             bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
3833                             if (bShould)
3834                             {
3835                                 // Left mouse button, shift, non-double-click, not a draw object and
3836                                 // have an object to select: select it.
3837                                 rSh.HideCursor();
3838                                 bool bSelObj = rSh.SelectObj(aDocPos);
3839                                 if (bSelObj)
3840                                 {
3841                                     rSh.EnterSelFrameMode(&aDocPos);
3842                                 }
3843                                 return;
3844                             }
3845 
3846                             if ( rSh.IsSelFrameMode() &&
3847                                  rSh.IsInsideSelectedObj( aDocPos ) )
3848                             {
3849                                 rSh.EnterSelFrameMode( &aDocPos );
3850                                 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3851                                 SwEditWin::s_nDDStartPosX = aDocPos.X();
3852                                 g_bFrameDrag = true;
3853                                 return;
3854                             }
3855                             if ( rSh.IsSelFrameMode() )
3856                             {
3857                                 rSh.UnSelectFrame();
3858                                 rSh.LeaveSelFrameMode();
3859                                 m_rView.AttrChangedNotify(nullptr);
3860                                 g_bFrameDrag = false;
3861                             }
3862                             if ( !rSh.IsExtMode() )
3863                             {
3864                                 // don't start a selection when an
3865                                 // URL field or a graphic is clicked
3866                                 bool bSttSelect = rSh.HasSelection() ||
3867                                                 PointerStyle::RefHand != GetPointer();
3868 
3869                                 if( !bSttSelect )
3870                                 {
3871                                     bSttSelect = true;
3872                                     if( bExecHyperlinks )
3873                                     {
3874                                         SwContentAtPos aContentAtPos(
3875                                             IsAttrAtPos::Ftn |
3876                                             IsAttrAtPos::InetAttr );
3877 
3878                                         if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) )
3879                                         {
3880                                             if( !rSh.IsViewLocked() &&
3881                                                 !rSh.IsReadOnlyAvailable() &&
3882                                                 aContentAtPos.IsInProtectSect() )
3883                                                     bLockView = true;
3884 
3885                                             bSttSelect = false;
3886                                         }
3887                                         else if( rSh.IsURLGrfAtPos( aDocPos ))
3888                                             bSttSelect = false;
3889                                     }
3890                                 }
3891 
3892                                 if( bSttSelect )
3893                                     rSh.SttSelect();
3894                             }
3895                         }
3896                         bCallBase = false;
3897                         break;
3898                     }
3899                     default:
3900                         if( !rSh.IsViewLocked() )
3901                         {
3902                             SwContentAtPos aContentAtPos( IsAttrAtPos::ClickField |
3903                                                         IsAttrAtPos::InetAttr );
3904                             if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3905                                 !rSh.IsReadOnlyAvailable() &&
3906                                 aContentAtPos.IsInProtectSect() )
3907                                 bLockView = true;
3908                         }
3909                 }
3910 
3911                 if ( rSh.IsGCAttr() )
3912                 {
3913                     rSh.GCAttr();
3914                     rSh.ClearGCAttr();
3915                 }
3916 
3917                 SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
3918                 bool bEditableFieldClicked = false;
3919 
3920                 // Are we clicking on a field?
3921                 if (rSh.GetContentAtPos(aDocPos, aFieldAtPos))
3922                 {
3923                     bool bEditableField = (aFieldAtPos.pFndTextAttr != nullptr
3924                         && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD);
3925 
3926                     if (!bEditableField)
3927                     {
3928                         rSh.CallSetCursor(&aDocPos, bOnlyText);
3929                         // Unfortunately the cursor may be on field
3930                         // position or on position after field depending on which
3931                         // half of the field was clicked on.
3932                         SwTextAttr const*const pTextField(aFieldAtPos.pFndTextAttr);
3933                         if (pTextField &&
3934                             rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() != pTextField->GetStart())
3935                         {
3936                             assert(rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() == (pTextField->GetStart() + 1));
3937                             rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
3938                         }
3939                         // don't go into the !bOverSelect block below - it moves
3940                         // the cursor
3941                         break;
3942                     }
3943                     else
3944                     {
3945                         bEditableFieldClicked = true;
3946                     }
3947                 }
3948 
3949                 bool bOverSelect = rSh.TestCurrPam( aDocPos );
3950                 bool bOverURLGrf = false;
3951                 if( !bOverSelect )
3952                     bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
3953 
3954                 if ( !bOverSelect || rSh.IsInSelect() )
3955                 {
3956                     MoveCursor( rSh, aDocPos, bOnlyText, bLockView );
3957                     bCallBase = false;
3958                 }
3959                 if (!bOverURLGrf && !bExecDrawTextLink && !bOnlyText)
3960                 {
3961                     const SelectionType nSelType = rSh.GetSelectionType();
3962                     // Check in general, if an object is selectable at given position.
3963                     // Thus, also text fly frames in background become selectable via Ctrl-Click.
3964                     if ( ( nSelType & SelectionType::Ole ||
3965                          nSelType & SelectionType::Graphic ||
3966                          rSh.IsObjSelectable( aDocPos ) ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3967                     {
3968                         SwMvContext aMvContext( &rSh );
3969                         rSh.EnterSelFrameMode();
3970                         bCallBase = false;
3971                     }
3972                 }
3973                 if ( !bOverSelect && bEditableFieldClicked && (!pCursorField ||
3974                      pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
3975                 {
3976                     // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
3977                     // and CH_TXT_ATR_INPUTFIELDEND
3978                     rSh.SttSelect();
3979                     rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
3980                                  *(aFieldAtPos.pFndTextAttr->End()) - 1 );
3981                 }
3982                 // don't reset here any longer so that, in case through MouseMove
3983                 // with pressed Ctrl key a multiple-selection should happen,
3984                 // the previous selection is not released in Drag.
3985                 break;
3986             }
3987         }
3988     }
3989     else if (MOUSE_RIGHT == aMEvt.GetButtons())
3990     {
3991         if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()
3992             && aMEvt.GetModifier() == KEY_MOD1)
3993         {
3994             // ctrl+right-click on outline node frame
3995             SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3996             if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3997             {
3998                 SwOutlineNodes::size_type nPos;
3999                 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
4000                 {
4001                     ToggleOutlineContentVisibility(nPos, !rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent());
4002                     return;
4003                 }
4004             }
4005         }
4006         else if (!aMEvt.GetModifier() && static_cast<sal_uInt8>(aMEvt.GetClicks() % 4) == 1
4007                  && !rSh.TestCurrPam(aDocPos))
4008         {
4009             SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
4010 
4011             // Are we clicking on a field?
4012             if (g_bValidCursorPos
4013                     && rSh.GetContentAtPos(aDocPos, aFieldAtPos)
4014                     && aFieldAtPos.pFndTextAttr != nullptr
4015                     && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD
4016                     && (!pCursorField || pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
4017             {
4018                 // Move the cursor
4019                 MoveCursor( rSh, aDocPos, rSh.IsObjSelectable( aDocPos ), m_bWasShdwCursor );
4020                 bCallBase = false;
4021 
4022                 // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
4023                 // and CH_TXT_ATR_INPUTFIELDEND
4024                 rSh.SttSelect();
4025                 rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
4026                                 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
4027             }
4028         }
4029     }
4030 
4031     if (bCallBase)
4032         Window::MouseButtonDown(aMEvt);
4033 }
4034 
changeMousePointer(Point const & rDocPoint)4035 bool SwEditWin::changeMousePointer(Point const & rDocPoint)
4036 {
4037     SwWrtShell & rShell = m_rView.GetWrtShell();
4038 
4039     SwTab nMouseTabCol;
4040 
4041     if ( SwTab::COL_NONE != (nMouseTabCol = rShell.WhichMouseTabCol( rDocPoint ) ) &&
4042          ( !rShell.IsObjSelectable( rDocPoint ) ||
4043              // allow resizing row height, if the image is anchored as character in the cell
4044              !( SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol ) ) )
4045     {
4046         PointerStyle nPointer = PointerStyle::Null;
4047         bool bChkTableSel = false;
4048 
4049         switch ( nMouseTabCol )
4050         {
4051             case SwTab::COL_VERT :
4052             case SwTab::ROW_HORI :
4053                 nPointer = PointerStyle::VSizeBar;
4054                 bChkTableSel = true;
4055                 break;
4056             case SwTab::ROW_VERT :
4057             case SwTab::COL_HORI :
4058                 nPointer = PointerStyle::HSizeBar;
4059                 bChkTableSel = true;
4060                 break;
4061             // Enhanced table selection
4062             case SwTab::SEL_HORI :
4063                 nPointer = PointerStyle::TabSelectSE;
4064                 break;
4065             case SwTab::SEL_HORI_RTL :
4066             case SwTab::SEL_VERT :
4067                 nPointer = PointerStyle::TabSelectSW;
4068                 break;
4069             case SwTab::COLSEL_HORI :
4070             case SwTab::ROWSEL_VERT :
4071                 nPointer = PointerStyle::TabSelectS;
4072                 break;
4073             case SwTab::ROWSEL_HORI :
4074                 nPointer = PointerStyle::TabSelectE;
4075                 break;
4076             case SwTab::ROWSEL_HORI_RTL :
4077             case SwTab::COLSEL_VERT :
4078                 nPointer = PointerStyle::TabSelectW;
4079                 break;
4080             default: break; // prevent compiler warning
4081         }
4082 
4083         if ( PointerStyle::Null != nPointer &&
4084             // i#35543 - Enhanced table selection is explicitly allowed in table mode
4085             ( !bChkTableSel || !rShell.IsTableMode() ) &&
4086             !comphelper::LibreOfficeKit::isActive() )
4087         {
4088             SetPointer( nPointer );
4089         }
4090 
4091         return true;
4092     }
4093     else if (rShell.IsNumLabel(rDocPoint, RULER_MOUSE_MARGINWIDTH))
4094     {
4095         // i#42921 - consider vertical mode
4096         SwTextNode* pNodeAtPos = rShell.GetNumRuleNodeAtPos( rDocPoint );
4097         const PointerStyle nPointer =
4098                 SwFEShell::IsVerticalModeAtNdAndPos( *pNodeAtPos, rDocPoint )
4099                 ? PointerStyle::VSizeBar
4100                 : PointerStyle::HSizeBar;
4101         SetPointer( nPointer );
4102 
4103         return true;
4104     }
4105     return false;
4106 }
4107 
MouseMove(const MouseEvent & _rMEvt)4108 void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
4109 {
4110     MouseEvent rMEvt(_rMEvt);
4111 
4112     if (comphelper::LibreOfficeKit::isActive())
4113     {
4114         if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
4115         {
4116             pWindow->MouseMove(rMEvt);
4117             return;
4118         }
4119     }
4120     if (m_rView.GetPostItMgr()->IsHitSidebarDragArea(rMEvt.GetPosPixel()))
4121     {
4122         SetPointer(PointerStyle::HSizeBar);
4123         return;
4124     }
4125 
4126     //ignore key modifiers for format paintbrush
4127     {
4128         bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
4129                                 &&  m_pApplyTempl->m_pFormatClipboard->HasContent();
4130         if( bExecFormatPaintbrush )
4131             rMEvt = MouseEvent( _rMEvt.GetPosPixel(), _rMEvt.GetClicks(),
4132                                     _rMEvt.GetMode(), _rMEvt.GetButtons() );
4133     }
4134 
4135     // as long as an action is running the MouseMove should be disconnected
4136     // otherwise bug 40102 occurs
4137     SwWrtShell &rSh = m_rView.GetWrtShell();
4138     if( rSh.ActionPend() )
4139         return ;
4140 
4141     if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
4142     {
4143         // add/remove outline content hide button
4144         const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4145         SwOutlineNodes::size_type nPos;
4146         SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
4147         if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
4148         {
4149             // mouse pointer is on an outline paragraph node
4150             if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
4151             {
4152                 // Get the outline paragraph frame and compare it to the saved outline frame. If they
4153                 // are not the same, remove the fold button from the saved outline frame, if not
4154                 // already removed, and then add a fold button to the mouse over outline frame if
4155                 // the content is not folded.
4156                 SwContentFrame* pContentFrame =
4157                         aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout());
4158                 if (pContentFrame != m_pSavedOutlineFrame)
4159                 {
4160                     if (m_pSavedOutlineFrame)
4161                     {
4162                         if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4163                         {
4164                             SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4165                             if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4166                                     rSh.GetAttrOutlineContentVisible(nPos))
4167                             {
4168                                 GetFrameControlsManager().RemoveControlsByType(
4169                                             FrameControlType::Outline, m_pSavedOutlineFrame);
4170                             }
4171                         }
4172                     }
4173                     m_pSavedOutlineFrame = static_cast<SwTextFrame*>(pContentFrame);
4174                 }
4175                 // show fold button if outline content is visible
4176                 if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
4177                         rSh.GetAttrOutlineContentVisible(nPos))
4178                     GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
4179             }
4180         }
4181         else if (m_pSavedOutlineFrame)
4182         {
4183             // The saved frame may not still be in the document, e.g., when an outline paragraph
4184             // is deleted. This causes the call to GetTextNodeFirst to behave badly. Use
4185             // isFrameAreaDefinitionValid to check if the frame is still in the document.
4186             if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4187             {
4188                 // current pointer pos is not over an outline frame
4189                 // previous pointer pos was over an outline frame
4190                 // remove outline content visibility button if showing
4191                 SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4192                 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4193                         rSh.GetAttrOutlineContentVisible(nPos))
4194                 {
4195                     GetFrameControlsManager().RemoveControlsByType(
4196                                 FrameControlType::Outline, m_pSavedOutlineFrame);
4197                 }
4198             }
4199             m_pSavedOutlineFrame = nullptr;
4200         }
4201     }
4202 
4203     if( m_pShadCursor && 0 != (rMEvt.GetModifier() + rMEvt.GetButtons() ) )
4204     {
4205         m_pShadCursor.reset();
4206     }
4207 
4208     bool bIsViewReadOnly = m_rView.GetDocShell()->IsReadOnly() || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
4209 
4210     CurrShell aCurr( &rSh );
4211 
4212     //aPixPt == Point in Pixel, relative to ChildWin
4213     //aDocPt == Point in Twips, document coordinates
4214     const Point aPixPt( rMEvt.GetPosPixel() );
4215     const Point aDocPt( PixelToLogic( aPixPt ) );
4216 
4217     if ( IsChainMode() )
4218     {
4219         UpdatePointer( aDocPt, rMEvt.GetModifier() );
4220         return;
4221     }
4222 
4223     SdrView *pSdrView = rSh.GetDrawView();
4224 
4225     const SwCallMouseEvent aLastCallEvent( m_aSaveCallEvent );
4226     m_aSaveCallEvent.Clear();
4227 
4228     if ( !bIsViewReadOnly && pSdrView && pSdrView->MouseMove(rMEvt,GetOutDev()) )
4229     {
4230         SetPointer( PointerStyle::Text );
4231         return; // evaluate SdrView's event
4232     }
4233 
4234     const Point aOldPt( rSh.VisArea().Pos() );
4235     const bool bInsWin = rSh.VisArea().Contains( aDocPt ) || comphelper::LibreOfficeKit::isActive();
4236 
4237     if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
4238     {
4239         if (m_pSavedOutlineFrame && !bInsWin)
4240         {
4241             // the mouse pointer has left the building (edit window)
4242             // remove the outline content visibility button if showing
4243             if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4244             {
4245                 const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4246                 SwOutlineNodes::size_type nPos;
4247                 SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4248                 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4249                         rSh.GetAttrOutlineContentVisible(nPos))
4250                 {
4251                     GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
4252                                                                    m_pSavedOutlineFrame);
4253                 }
4254             }
4255             m_pSavedOutlineFrame = nullptr;
4256         }
4257     }
4258 
4259     if( m_pShadCursor && !bInsWin )
4260     {
4261         m_pShadCursor.reset();
4262     }
4263 
4264     if( bInsWin && m_xRowColumnSelectionStart )
4265     {
4266         EnterArea();
4267         Point aPos( aDocPt );
4268         if( rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag ))
4269             return;
4270     }
4271 
4272     // position is necessary for OS/2 because obviously after a MB-Down
4273     // a MB-Move is called immediately.
4274     if( g_bDDTimerStarted )
4275     {
4276         Point aDD( SwEditWin::s_nDDStartPosX, SwEditWin::s_nDDStartPosY );
4277         aDD = LogicToPixel( aDD );
4278         tools::Rectangle aRect( aDD.X()-3, aDD.Y()-3, aDD.X()+3, aDD.Y()+3 );
4279         if ( !aRect.Contains( aPixPt ) )
4280             StopDDTimer( &rSh, aDocPt );
4281     }
4282 
4283     if(m_rView.GetDrawFuncPtr())
4284     {
4285         if( m_bInsDraw  )
4286         {
4287             m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4288             if ( !bInsWin )
4289             {
4290                 Point aTmp( aDocPt );
4291                 aTmp += rSh.VisArea().Pos() - aOldPt;
4292                 LeaveArea( aTmp );
4293             }
4294             else
4295                 EnterArea();
4296             return;
4297         }
4298         else if(!rSh.IsFrameSelected() && !rSh.IsObjSelected())
4299         {
4300             SfxBindings &rBnd = rSh.GetView().GetViewFrame().GetBindings();
4301             Point aRelPos = rSh.GetRelativePagePosition(aDocPt);
4302             if(aRelPos.X() >= 0)
4303             {
4304                 FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebView*>( &GetView())  != nullptr );
4305                 SW_MOD()->PutItem(SfxUInt16Item(SID_ATTR_METRIC, static_cast< sal_uInt16 >(eMetric)));
4306                 const SfxPointItem aTmp1( SID_ATTR_POSITION, aRelPos );
4307                 rBnd.SetState( aTmp1 );
4308             }
4309             else
4310             {
4311                 rBnd.Invalidate(SID_ATTR_POSITION);
4312             }
4313             rBnd.Invalidate(SID_ATTR_SIZE);
4314             const SvxStatusItem aCell( SID_TABLE_CELL, OUString(), StatusCategory::NONE );
4315             rBnd.SetState( aCell );
4316         }
4317     }
4318 
4319     // determine if we only change the mouse pointer and return
4320     if (!bIsViewReadOnly && bInsWin && !m_pApplyTempl && !rSh.IsInSelect() && changeMousePointer(aDocPt))
4321     {
4322         return;
4323     }
4324 
4325     bool bDelShadCursor = true;
4326 
4327     switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4328     {
4329         case MOUSE_LEFT:
4330             if( m_pAnchorMarker )
4331             {
4332                 // Now we need to refresh the SdrHdl pointer of m_pAnchorMarker.
4333                 // This looks a little bit tricky, but it solves the following
4334                 // problem: the m_pAnchorMarker contains a pointer to an SdrHdl,
4335                 // if the FindAnchorPos-call cause a scrolling of the visible
4336                 // area, it's possible that the SdrHdl will be destroyed and a
4337                 // new one will initialized at the original position(GetHdlPos).
4338                 // So the m_pAnchorMarker has to find the right SdrHdl, if it's
4339                 // the old one, it will find it with position aOld, if this one
4340                 // is destroyed, it will find a new one at position GetHdlPos().
4341 
4342                 const Point aOld = m_pAnchorMarker->GetPosForHitTest( *(rSh.GetOut()) );
4343                 Point aNew = rSh.FindAnchorPos( aDocPt );
4344                 SdrHdl* pHdl;
4345                 if( pSdrView && (nullptr!=( pHdl = pSdrView->PickHandle( aOld ) )||
4346                     nullptr !=(pHdl = pSdrView->PickHandle( m_pAnchorMarker->GetHdlPos()) ) ) &&
4347                         ( pHdl->GetKind() == SdrHdlKind::Anchor ||
4348                           pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
4349                 {
4350                     m_pAnchorMarker->ChgHdl( pHdl );
4351                     if( aNew.X() || aNew.Y() )
4352                     {
4353                         m_pAnchorMarker->SetPos( aNew );
4354                         m_pAnchorMarker->SetLastPos( aDocPt );
4355                     }
4356                 }
4357                 else
4358                 {
4359                     m_pAnchorMarker.reset();
4360                 }
4361             }
4362             if ( m_bInsDraw )
4363             {
4364                 if ( !m_bMBPressed )
4365                     break;
4366                 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4367                 {
4368                     if ( !bInsWin )
4369                         LeaveArea( aDocPt );
4370                     else
4371                         EnterArea();
4372                     if ( m_rView.GetDrawFuncPtr() )
4373                     {
4374                         pSdrView->SetOrtho(false);
4375                         m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4376                     }
4377                     m_bIsInMove = true;
4378                 }
4379                 return;
4380             }
4381 
4382             {
4383             SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
4384             if (pWrdCnt)
4385                 pWrdCnt->UpdateCounts();
4386             }
4387             [[fallthrough]];
4388 
4389         case MOUSE_LEFT + KEY_SHIFT:
4390         case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4391             if ( !m_bMBPressed )
4392                 break;
4393             [[fallthrough]];
4394         case MOUSE_LEFT + KEY_MOD1:
4395             if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4396             {
4397                 if( !m_bMBPressed )
4398                     break;
4399 
4400                 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4401                 {
4402                     // event processing for resizing
4403                     if (pSdrView && pSdrView->GetMarkedObjectList().GetMarkCount() != 0)
4404                     {
4405                         const Point aSttPt( PixelToLogic( m_aStartPos ) );
4406 
4407                         // can we start?
4408                         if( SdrHdlKind::User == g_eSdrMoveHdl )
4409                         {
4410                             SdrHdl* pHdl = pSdrView->PickHandle( aSttPt );
4411                             g_eSdrMoveHdl = pHdl ? pHdl->GetKind() : SdrHdlKind::Move;
4412                         }
4413 
4414                         const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4415                         const SvxMacro* pMacro = nullptr;
4416 
4417                         SvMacroItemId nEvent = SdrHdlKind::Move == g_eSdrMoveHdl
4418                                             ? SvMacroItemId::SwFrmMove
4419                                             : SvMacroItemId::SwFrmResize;
4420 
4421                         if (nullptr != pFlyFormat)
4422                             pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4423                         if (nullptr != pMacro &&
4424                         // or notify only e.g. every 20 Twip?
4425                             m_aRszMvHdlPt != aDocPt )
4426                         {
4427                             m_aRszMvHdlPt = aDocPt;
4428                             sal_uInt32 nPos = 0;
4429                             SbxArrayRef xArgs = new SbxArray;
4430                             SbxVariableRef xVar = new SbxVariable;
4431                             xVar->PutString( pFlyFormat->GetName() );
4432                             xArgs->Put(xVar.get(), ++nPos);
4433 
4434                             if( SvMacroItemId::SwFrmResize == nEvent )
4435                             {
4436                                 xVar = new SbxVariable;
4437                                 xVar->PutUShort( static_cast< sal_uInt16 >(g_eSdrMoveHdl) );
4438                                 xArgs->Put(xVar.get(), ++nPos);
4439                             }
4440 
4441                             xVar = new SbxVariable;
4442                             xVar->PutLong( aDocPt.X() - aSttPt.X() );
4443                             xArgs->Put(xVar.get(), ++nPos);
4444                             xVar = new SbxVariable;
4445                             xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4446                             xArgs->Put(xVar.get(), ++nPos);
4447 
4448                             OUString sRet;
4449 
4450                             ReleaseMouse();
4451 
4452                             rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
4453 
4454                             CaptureMouse();
4455 
4456                             if( !sRet.isEmpty() && sRet.toInt32()!=0 )
4457                                 return ;
4458                         }
4459                     }
4460                     // event processing for resizing
4461 
4462                     if( bIsViewReadOnly )
4463                         break;
4464 
4465                     bool bResizeKeepRatio = rSh.GetSelectionType() & SelectionType::Graphic ||
4466                                             rSh.GetSelectionType() & SelectionType::Media ||
4467                                             rSh.GetSelectionType() & SelectionType::Ole;
4468                     bool bisResize = g_eSdrMoveHdl != SdrHdlKind::Move;
4469 
4470                     if (pSdrView)
4471                     {
4472                         // Resize proportionally when media is selected and the user drags on a corner
4473                         const Point aSttPt(PixelToLogic(m_aStartPos));
4474                         SdrHdl* pHdl = pSdrView->PickHandle(aSttPt);
4475                         if (pHdl)
4476                             bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
4477 
4478                         if (pSdrView->GetDragMode() == SdrDragMode::Crop)
4479                             bisResize = false;
4480                         if (rMEvt.IsShift())
4481                         {
4482                             pSdrView->SetAngleSnapEnabled(!bResizeKeepRatio);
4483                             if (bisResize)
4484                                 pSdrView->SetOrtho(!bResizeKeepRatio);
4485                             else
4486                                 pSdrView->SetOrtho(true);
4487                         }
4488                         else
4489                         {
4490                             pSdrView->SetAngleSnapEnabled(bResizeKeepRatio);
4491                             if (bisResize)
4492                                 pSdrView->SetOrtho(bResizeKeepRatio);
4493                             else
4494                                 pSdrView->SetOrtho(false);
4495                         }
4496                     }
4497 
4498                     rSh.Drag( &aDocPt, rMEvt.IsShift() );
4499                     m_bIsInMove = true;
4500                 }
4501                 else if( bIsViewReadOnly )
4502                     break;
4503 
4504                 if ( !bInsWin )
4505                 {
4506                     Point aTmp( aDocPt );
4507                     aTmp += rSh.VisArea().Pos() - aOldPt;
4508                     LeaveArea( aTmp );
4509                 }
4510                 else if(m_bIsInMove)
4511                     EnterArea();
4512                 return;
4513             }
4514             if ( !rSh.IsSelFrameMode() && !g_bDDINetAttr &&
4515                 (IsMinMove( m_aStartPos,aPixPt ) || m_bIsInMove) &&
4516                 (rSh.IsInSelect() || !rSh.TestCurrPam( aDocPt )) )
4517             {
4518                 if ( pSdrView )
4519                 {
4520                     if ( rMEvt.IsShift() )
4521                         pSdrView->SetOrtho(true);
4522                     else
4523                         pSdrView->SetOrtho(false);
4524                 }
4525                 if ( !bInsWin )
4526                 {
4527                     Point aTmp( aDocPt );
4528                     aTmp += rSh.VisArea().Pos() - aOldPt;
4529                     LeaveArea( aTmp );
4530                 }
4531                 else
4532                 {
4533                     if( !rMEvt.IsSynthetic() &&
4534                         ( MOUSE_LEFT != rMEvt.GetButtons() ||
4535                           KEY_MOD1 != rMEvt.GetModifier() ||
4536                           !rSh.Is_FnDragEQBeginDrag() ||
4537                           rSh.IsAddMode() ) )
4538                     {
4539                         rSh.Drag( &aDocPt, false );
4540 
4541                         g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4542                         EnterArea();
4543                     }
4544                 }
4545             }
4546             g_bDDINetAttr = false;
4547             break;
4548         case 0:
4549         {
4550             if ( m_pApplyTempl )
4551             {
4552                 UpdatePointer(aDocPt); // maybe a frame has to be marked here
4553                 break;
4554             }
4555             // change ui if mouse is over SwPostItField
4556             // TODO: do the same thing for redlines IsAttrAtPos::Redline
4557             SwContentAtPos aContentAtPos( IsAttrAtPos::Field);
4558             if (rSh.GetContentAtPos(aDocPt, aContentAtPos, false))
4559             {
4560                 const SwField* pField = aContentAtPos.aFnd.pField;
4561                 if (pField->Which()== SwFieldIds::Postit)
4562                 {
4563                     m_rView.GetPostItMgr()->SetShadowState(reinterpret_cast<const SwPostItField*>(pField),false);
4564                 }
4565                 else
4566                     m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4567             }
4568             else
4569                 m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4570             [[fallthrough]];
4571         }
4572         case KEY_SHIFT:
4573         case KEY_MOD2:
4574         case KEY_MOD1:
4575             if ( !m_bInsDraw )
4576             {
4577                 bool bTstShdwCursor = true;
4578 
4579                 UpdatePointer( aDocPt, rMEvt.GetModifier() );
4580 
4581                 const SwFrameFormat* pFormat = nullptr;
4582                 const SwFormatINetFormat* pINet = nullptr;
4583                 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
4584                 if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
4585                     pINet = static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr);
4586 
4587                 const void* pTmp = pINet;
4588 
4589                 if( pINet ||
4590                     nullptr != ( pTmp = pFormat = rSh.GetFormatFromAnyObj( aDocPt )))
4591                 {
4592                     bTstShdwCursor = false;
4593                     if( pTmp == pINet )
4594                         m_aSaveCallEvent.Set( pINet );
4595                     else
4596                     {
4597                         IMapObject* pIMapObj = pFormat->GetIMapObject( aDocPt );
4598                         if( pIMapObj )
4599                             m_aSaveCallEvent.Set( pFormat, pIMapObj );
4600                         else
4601                             m_aSaveCallEvent.Set( EVENT_OBJECT_URLITEM, pFormat );
4602                     }
4603 
4604                     // should be over an InternetField with an
4605                     // embedded macro?
4606                     if( m_aSaveCallEvent != aLastCallEvent )
4607                     {
4608                         if( aLastCallEvent.HasEvent() )
4609                             rSh.CallEvent( SvMacroItemId::OnMouseOut,
4610                                             aLastCallEvent, true );
4611                         // 0 says that the object doesn't have any table
4612                         if( !rSh.CallEvent( SvMacroItemId::OnMouseOver,
4613                                         m_aSaveCallEvent ))
4614                             m_aSaveCallEvent.Clear();
4615                     }
4616                 }
4617                 else if( aLastCallEvent.HasEvent() )
4618                 {
4619                     // cursor was on an object
4620                     rSh.CallEvent( SvMacroItemId::OnMouseOut,
4621                                     aLastCallEvent, true );
4622                 }
4623 
4624                 if( bTstShdwCursor && bInsWin && !bIsViewReadOnly &&
4625                     !m_bInsFrame &&
4626                     !rSh.GetViewOptions()->getBrowseMode() &&
4627                     rSh.GetViewOptions()->IsShadowCursor() &&
4628                     !(rMEvt.GetModifier() + rMEvt.GetButtons()) &&
4629                     !rSh.HasSelection() && !GetOutDev()->GetConnectMetaFile() )
4630                 {
4631                     SwRect aRect;
4632 
4633                     SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
4634                     if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, m_eOrient ))
4635                     {
4636                         if( !m_pShadCursor )
4637                             m_pShadCursor.reset( new SwShadowCursor( *this ) );
4638                         if( text::HoriOrientation::RIGHT != m_eOrient && text::HoriOrientation::CENTER != m_eOrient )
4639                             m_eOrient = text::HoriOrientation::LEFT;
4640                         m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(m_eOrient) );
4641                         bDelShadCursor = false;
4642                     }
4643                 }
4644             }
4645             break;
4646         case MOUSE_LEFT + KEY_MOD2:
4647             if( rSh.IsBlockMode() && !rMEvt.IsSynthetic() )
4648             {
4649                 rSh.Drag( &aDocPt, false );
4650                 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4651                 EnterArea();
4652             }
4653         break;
4654     }
4655 
4656     if( bDelShadCursor && m_pShadCursor )
4657     {
4658         m_pShadCursor.reset();
4659     }
4660     m_bWasShdwCursor = false;
4661 }
4662 
4663 /**
4664  * Button Up
4665  */
MouseButtonUp(const MouseEvent & rMEvt)4666 void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
4667 {
4668     if (comphelper::LibreOfficeKit::isActive())
4669     {
4670         if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
4671         {
4672             pWindow->MouseButtonUp(rMEvt);
4673             return;
4674         }
4675     }
4676 
4677     if (mbIsDragSidebar)
4678     {
4679         m_rView.GetPostItMgr()->SetSidebarWidth(rMEvt.GetPosPixel());
4680         mbIsDragSidebar = false;
4681         return;
4682     }
4683 
4684     bool bCallBase = true;
4685 
4686     bool bCallShadowCursor = m_bWasShdwCursor;
4687     m_bWasShdwCursor = false;
4688     if( m_pShadCursor )
4689     {
4690         m_pShadCursor.reset();
4691     }
4692 
4693     m_xRowColumnSelectionStart.reset();
4694 
4695     SdrHdlKind eOldSdrMoveHdl = g_eSdrMoveHdl;
4696     g_eSdrMoveHdl = SdrHdlKind::User;     // for MoveEvents - reset again
4697 
4698     // preventively reset
4699     m_rView.SetTabColFromDoc( false );
4700     m_rView.SetNumRuleNodeFromDoc(nullptr);
4701 
4702     SwWrtShell &rSh = m_rView.GetWrtShell();
4703     CurrShell aCurr( &rSh );
4704     SdrView *pSdrView = rSh.GetDrawView();
4705     if ( pSdrView )
4706     {
4707         // tdf34555: ortho was always reset before being used in EndSdrDrag
4708         // Now, it is reset only if not in Crop mode.
4709         if (pSdrView->GetDragMode() != SdrDragMode::Crop && !rMEvt.IsShift())
4710             pSdrView->SetOrtho(false);
4711 
4712         if ( pSdrView->MouseButtonUp( rMEvt,GetOutDev() ) )
4713         {
4714             rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
4715             return; // SdrView's event evaluated
4716         }
4717     }
4718     // only process MouseButtonUp when the Down went to that windows as well.
4719     if ( !m_bMBPressed )
4720     {
4721     // Undo for the watering can is already in CommandHdl
4722     // that's the way it should be!
4723 
4724         return;
4725     }
4726 
4727     Point aDocPt( PixelToLogic( rMEvt.GetPosPixel() ) );
4728 
4729     if ( g_bDDTimerStarted )
4730     {
4731         StopDDTimer( &rSh, aDocPt );
4732         m_bMBPressed = false;
4733         if ( rSh.IsSelFrameMode() )
4734         {
4735             rSh.EndDrag( &aDocPt, false );
4736             g_bFrameDrag = false;
4737         }
4738         g_bNoInterrupt = false;
4739         const Point aDocPos( PixelToLogic( rMEvt.GetPosPixel() ) );
4740         if ((PixelToLogic(m_aStartPos).Y() == (aDocPos.Y())) && (PixelToLogic(m_aStartPos).X() == (aDocPos.X())))//To make sure it was not moved
4741         {
4742             SdrPageView* pPV = nullptr;
4743             SdrObject* pObj = pSdrView ? pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
4744             if (pObj)
4745             {
4746                 if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
4747                 {
4748                     SwFrameFormat* pFormat = pContact->GetFormat();
4749                     SwFrameFormat* pShapeFormat
4750                         = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT);
4751                     if (!pShapeFormat)
4752                     {
4753                         pSdrView->UnmarkAllObj();
4754                         pSdrView->MarkObj(pObj, pPV);
4755                     }
4756                     else
4757                     {
4758                         // If the fly frame is a textbox of a shape, then select the shape instead.
4759                         SdrObject* pShape = pShapeFormat->FindSdrObject();
4760                         pSdrView->UnmarkAllObj();
4761                         pSdrView->MarkObj(pShape, pPV);
4762                     }
4763                 }
4764             }
4765         }
4766         ReleaseMouse();
4767         return;
4768     }
4769 
4770     if( m_pAnchorMarker )
4771     {
4772         if(m_pAnchorMarker->GetHdl())
4773         {
4774             // #i121463# delete selected after drag
4775             m_pAnchorMarker->GetHdl()->SetSelected(false);
4776         }
4777 
4778         Point aPnt( m_pAnchorMarker->GetLastPos() );
4779         m_pAnchorMarker.reset();
4780         if( aPnt.X() || aPnt.Y() )
4781             rSh.FindAnchorPos( aPnt, true );
4782     }
4783     if ( m_bInsDraw && m_rView.GetDrawFuncPtr() )
4784     {
4785         if ( m_rView.GetDrawFuncPtr()->MouseButtonUp( rMEvt ) )
4786         {
4787             if (m_rView.GetDrawFuncPtr()) // could have been destroyed in MouseButtonUp
4788             {
4789                 m_rView.GetDrawFuncPtr()->Deactivate();
4790 
4791                 if (!m_rView.IsDrawMode())
4792                 {
4793                     m_rView.SetDrawFuncPtr(nullptr);
4794                     SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
4795                     rBind.Invalidate( SID_ATTR_SIZE );
4796                     rBind.Invalidate( SID_TABLE_CELL );
4797                 }
4798             }
4799 
4800             if ( rSh.IsObjSelected() )
4801             {
4802                 rSh.EnterSelFrameMode();
4803                 if (!m_rView.GetDrawFuncPtr())
4804                     StdDrawMode( SdrObjKind::NONE, true );
4805             }
4806             else if ( rSh.IsFrameSelected() )
4807             {
4808                 rSh.EnterSelFrameMode();
4809                 StopInsFrame();
4810             }
4811             else
4812             {
4813                 const Point aDocPos( PixelToLogic( m_aStartPos ) );
4814                 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4815                 rSh.Edit();
4816             }
4817 
4818             m_rView.AttrChangedNotify(nullptr);
4819         }
4820         else if (rMEvt.GetButtons() == MOUSE_RIGHT && rSh.IsDrawCreate())
4821             m_rView.GetDrawFuncPtr()->BreakCreate();   // abort drawing
4822 
4823         g_bNoInterrupt = false;
4824         if (IsMouseCaptured())
4825             ReleaseMouse();
4826         return;
4827     }
4828     bool bPopMode = false;
4829     switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4830     {
4831         case MOUSE_LEFT:
4832             if ( m_bInsDraw && rSh.IsDrawCreate() )
4833             {
4834                 if ( m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->MouseButtonUp(rMEvt) )
4835                 {
4836                     m_rView.GetDrawFuncPtr()->Deactivate();
4837                     m_rView.AttrChangedNotify(nullptr);
4838                     if ( rSh.IsObjSelected() )
4839                         rSh.EnterSelFrameMode();
4840                     if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
4841                         StopInsFrame();
4842                 }
4843                 bCallBase = false;
4844                 break;
4845             }
4846             [[fallthrough]];
4847         case MOUSE_LEFT + KEY_MOD1:
4848         case MOUSE_LEFT + KEY_MOD2:
4849         case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4850             if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4851             {
4852                 if ( rMEvt.IsMod1() ) // copy and don't move.
4853                 {
4854                     // abort drag, use internal Copy instead
4855                     tools::Rectangle aRect;
4856                     rSh.GetDrawView()->TakeActionRect( aRect );
4857                     if (!aRect.IsEmpty())
4858                     {
4859                         rSh.BreakDrag();
4860                         Point aEndPt, aSttPt;
4861                         if ( rSh.GetSelFrameType() & FrameTypeFlags::FLY_ATCNT )
4862                         {
4863                             aEndPt = aRect.TopLeft();
4864                             aSttPt = rSh.GetDrawView()->GetAllMarkedRect().TopLeft();
4865                         }
4866                         else
4867                         {
4868                             aEndPt = aRect.Center();
4869                             aSttPt = rSh.GetDrawView()->GetAllMarkedRect().Center();
4870                         }
4871                         if ( aSttPt != aEndPt )
4872                         {
4873                             rSh.StartUndo( SwUndoId::UI_DRAG_AND_COPY );
4874                             rSh.Copy(rSh, aSttPt, aEndPt);
4875                             rSh.EndUndo( SwUndoId::UI_DRAG_AND_COPY );
4876                         }
4877                     }
4878                     else {
4879                         rSh.EndDrag( &aDocPt, false );
4880                     }
4881                 }
4882                 else
4883                 {
4884                     {
4885                         const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4886                         const SvxMacro* pMacro = nullptr;
4887 
4888                         SvMacroItemId nEvent = SdrHdlKind::Move == eOldSdrMoveHdl
4889                                             ? SvMacroItemId::SwFrmMove
4890                                             : SvMacroItemId::SwFrmResize;
4891 
4892                         if (nullptr != pFlyFormat)
4893                             pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4894                         if (nullptr != pMacro)
4895                         {
4896                             const Point aSttPt( PixelToLogic( m_aStartPos ) );
4897                             m_aRszMvHdlPt = aDocPt;
4898                             sal_uInt32 nPos = 0;
4899                             SbxArrayRef xArgs = new SbxArray;
4900                             SbxVariableRef xVar = new SbxVariable;
4901                             xVar->PutString( pFlyFormat->GetName() );
4902                             xArgs->Put(xVar.get(), ++nPos);
4903 
4904                             if( SvMacroItemId::SwFrmResize == nEvent )
4905                             {
4906                                 xVar = new SbxVariable;
4907                                 xVar->PutUShort( static_cast< sal_uInt16 >(eOldSdrMoveHdl) );
4908                                 xArgs->Put(xVar.get(), ++nPos);
4909                             }
4910 
4911                             xVar = new SbxVariable;
4912                             xVar->PutLong( aDocPt.X() - aSttPt.X() );
4913                             xArgs->Put(xVar.get(), ++nPos);
4914                             xVar = new SbxVariable;
4915                             xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4916                             xArgs->Put(xVar.get(), ++nPos);
4917 
4918                             xVar = new SbxVariable;
4919                             xVar->PutUShort( 1 );
4920                             xArgs->Put(xVar.get(), ++nPos);
4921 
4922                             ReleaseMouse();
4923 
4924                             rSh.ExecMacro( *pMacro, nullptr, xArgs.get() );
4925 
4926                             CaptureMouse();
4927                         }
4928 
4929                         if (pFlyFormat)
4930                         {
4931                             // See if the fly frame's anchor is in a content control. If so,
4932                             // interact with it.
4933                             const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
4934                             SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
4935                             if (pAnchorNode)
4936                             {
4937                                 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
4938                                 if (pTextNode)
4939                                 {
4940                                     SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
4941                                         rFormatAnchor.GetAnchorContentOffset(), RES_TXTATR_CONTENTCONTROL,
4942                                         ::sw::GetTextAttrMode::Parent);
4943                                     if (pAttr)
4944                                     {
4945                                         SwTextContentControl* pTextContentControl
4946                                             = static_txtattr_cast<SwTextContentControl*>(pAttr);
4947                                         const SwFormatContentControl& rFormatContentControl
4948                                             = pTextContentControl->GetContentControl();
4949                                         rSh.GotoContentControl(rFormatContentControl);
4950                                     }
4951                                 }
4952                             }
4953                         }
4954                     }
4955                     rSh.EndDrag( &aDocPt, false );
4956                 }
4957                 g_bFrameDrag = false;
4958                 bCallBase = false;
4959                 break;
4960             }
4961             bPopMode = true;
4962             [[fallthrough]];
4963         case MOUSE_LEFT + KEY_SHIFT:
4964             if (rSh.IsSelFrameMode())
4965             {
4966 
4967                 rSh.EndDrag( &aDocPt, false );
4968                 g_bFrameDrag = false;
4969                 bCallBase = false;
4970                 break;
4971             }
4972 
4973             if( g_bHoldSelection )
4974             {
4975                 // the EndDrag should be called in any case
4976                 g_bHoldSelection = false;
4977                 rSh.EndDrag( &aDocPt, false );
4978             }
4979             else
4980             {
4981                 SwContentAtPos aFieldAtPos (IsAttrAtPos::Field);
4982                 if ( !rSh.IsInSelect() && rSh.TestCurrPam( aDocPt ) &&
4983                      !rSh.GetContentAtPos( aDocPt, aFieldAtPos ) )
4984                 {
4985                     const bool bTmpNoInterrupt = g_bNoInterrupt;
4986                     g_bNoInterrupt = false;
4987                     {   // create only temporary move context because otherwise
4988                         // the query to the content form doesn't work!!!
4989                         SwMvContext aMvContext( &rSh );
4990                         const Point aDocPos( PixelToLogic( m_aStartPos ) );
4991                         g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4992                     }
4993                     g_bNoInterrupt = bTmpNoInterrupt;
4994 
4995                 }
4996                 else
4997                 {
4998                     bool bInSel = rSh.IsInSelect();
4999                     rSh.EndDrag( &aDocPt, false );
5000 
5001                     // Internetfield? --> call link (load doc!!)
5002                     if( !bInSel )
5003                     {
5004                         LoadUrlFlags nFilter = LoadUrlFlags::NONE;
5005                         if( KEY_MOD1 == rMEvt.GetModifier() )
5006                             nFilter |= LoadUrlFlags::NewView;
5007 
5008                         bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
5009                         if ( !bExecHyperlinks )
5010                         {
5011                             const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
5012                             if ( (  bSecureOption && rMEvt.GetModifier() == KEY_MOD1 ) ||
5013                                  ( !bSecureOption && rMEvt.GetModifier() != KEY_MOD1 ) )
5014                                 bExecHyperlinks = true;
5015                         }
5016 
5017                         const bool bExecSmarttags = rMEvt.GetModifier() == KEY_MOD1;
5018 
5019                         if(m_pApplyTempl)
5020                             bExecHyperlinks = false;
5021 
5022                         SwContentAtPos aContentAtPos( IsAttrAtPos::Field |
5023                                                     IsAttrAtPos::InetAttr |
5024                                                     IsAttrAtPos::SmartTag  | IsAttrAtPos::FormControl |
5025                                                     IsAttrAtPos::ContentControl);
5026 
5027                         if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
5028                         {
5029                             // Do it again if we're not on a field/hyperlink to update the cursor accordingly
5030                             if ( IsAttrAtPos::Field != aContentAtPos.eContentAtPos
5031                                  && IsAttrAtPos::InetAttr != aContentAtPos.eContentAtPos )
5032                                 rSh.GetContentAtPos( aDocPt, aContentAtPos, true );
5033 
5034                             bool bViewLocked = rSh.IsViewLocked();
5035                             if( !bViewLocked && !rSh.IsReadOnlyAvailable() &&
5036                                 aContentAtPos.IsInProtectSect() )
5037                                 rSh.LockView( true );
5038 
5039                             ReleaseMouse();
5040 
5041                             if( IsAttrAtPos::Field == aContentAtPos.eContentAtPos )
5042                             {
5043                                 bool bAddMode(false);
5044                                 // AdditionalMode if applicable
5045                                 if (KEY_MOD1 == rMEvt.GetModifier()
5046                                     && !rSh.IsAddMode())
5047                                 {
5048                                     bAddMode = true;
5049                                     rSh.EnterAddMode();
5050                                 }
5051                                 if ( aContentAtPos.pFndTextAttr != nullptr
5052                                      && aContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD )
5053                                 {
5054                                     if (!rSh.IsInSelect())
5055                                     {
5056                                         // create only temporary move context because otherwise
5057                                         // the query to the content form doesn't work!!!
5058                                         SwMvContext aMvContext( &rSh );
5059                                         const Point aDocPos( PixelToLogic( m_aStartPos ) );
5060                                         g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
5061                                     }
5062                                     else
5063                                     {
5064                                         g_bValidCursorPos = true;
5065                                     }
5066                                 }
5067                                 else
5068                                 {
5069                                     rSh.ClickToField(*aContentAtPos.aFnd.pField, bExecHyperlinks);
5070                                     // a bit of a mystery what this is good for?
5071                                     // in this case we assume it's valid since we
5072                                     // just selected a field
5073                                     g_bValidCursorPos = true;
5074                                 }
5075                                 if (bAddMode)
5076                                 {
5077                                     rSh.LeaveAddMode();
5078                                 }
5079                             }
5080                             else if (aContentAtPos.eContentAtPos == IsAttrAtPos::ContentControl)
5081                             {
5082                                 auto pTextContentControl
5083                                     = static_txtattr_cast<const SwTextContentControl*>(
5084                                         aContentAtPos.pFndTextAttr);
5085                                 const SwFormatContentControl& rFormatContentControl
5086                                     = pTextContentControl->GetContentControl();
5087                                 rSh.GotoContentControl(rFormatContentControl);
5088                             }
5089                             else if ( IsAttrAtPos::SmartTag == aContentAtPos.eContentAtPos )
5090                             {
5091                                     // execute smarttag menu
5092                                     if ( bExecSmarttags && SwSmartTagMgr::Get().IsSmartTagsEnabled() )
5093                                         m_rView.ExecSmartTagPopup( aDocPt );
5094                             }
5095                             else if ( IsAttrAtPos::FormControl == aContentAtPos.eContentAtPos )
5096                             {
5097                                 OSL_ENSURE( aContentAtPos.aFnd.pFieldmark != nullptr, "where is my field ptr???");
5098                                 if ( aContentAtPos.aFnd.pFieldmark != nullptr)
5099                                 {
5100                                     IFieldmark *fieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
5101                                     if ( fieldBM->GetFieldname( ) == ODF_FORMCHECKBOX )
5102                                     {
5103                                         ICheckboxFieldmark& rCheckboxFm = dynamic_cast<ICheckboxFieldmark&>(*fieldBM);
5104                                         rCheckboxFm.SetChecked(!rCheckboxFm.IsChecked());
5105                                         rCheckboxFm.Invalidate();
5106                                         rSh.InvalidateWindows( SwRect(m_rView.GetVisArea()) );
5107                                     }
5108                                 }
5109                             }
5110                             else if ( IsAttrAtPos::InetAttr == aContentAtPos.eContentAtPos )
5111                             {
5112                                 if (comphelper::LibreOfficeKit::isActive())
5113                                 {
5114                                     OUString val((*static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)).GetValue());
5115                                     if (val.startsWith("#"))
5116                                         bExecHyperlinks = true;
5117                                 }
5118                                 if ( bExecHyperlinks && aContentAtPos.aFnd.pAttr )
5119                                     rSh.ClickToINetAttr( *static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr), nFilter );
5120                             }
5121 
5122                             rSh.LockView( bViewLocked );
5123                             bCallShadowCursor = false;
5124                         }
5125                         else
5126                         {
5127                             aContentAtPos = SwContentAtPos( IsAttrAtPos::Ftn );
5128                             if( !rSh.GetContentAtPos( aDocPt, aContentAtPos, true ) && bExecHyperlinks )
5129                             {
5130                                 SdrViewEvent aVEvt;
5131 
5132                                 if (pSdrView)
5133                                     pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
5134 
5135                                 if (pSdrView && aVEvt.meEvent == SdrEventKind::ExecuteUrl)
5136                                 {
5137                                     // hit URL field
5138                                     const SvxURLField *pField = aVEvt.mpURLField;
5139                                     if (pField)
5140                                     {
5141                                         const OUString& sURL(pField->GetURL());
5142                                         const OUString& sTarget(pField->GetTargetFrame());
5143                                         ::LoadURL(rSh, sURL, nFilter, sTarget);
5144                                     }
5145                                     bCallShadowCursor = false;
5146                                 }
5147                                 else
5148                                 {
5149                                     // hit graphic
5150                                     ReleaseMouse();
5151                                     if( rSh.ClickToINetGrf( aDocPt, nFilter ))
5152                                         bCallShadowCursor = false;
5153                                 }
5154                             }
5155                         }
5156 
5157                         if( bCallShadowCursor &&
5158                             rSh.GetViewOptions()->IsShadowCursor() &&
5159                             MOUSE_LEFT == (rMEvt.GetModifier() + rMEvt.GetButtons()) &&
5160                             !rSh.HasSelection() &&
5161                             !GetOutDev()->GetConnectMetaFile() &&
5162                             rSh.VisArea().Contains( aDocPt ))
5163                         {
5164                             SwUndoId nLastUndoId(SwUndoId::EMPTY);
5165                             if (rSh.GetLastUndoInfo(nullptr, & nLastUndoId))
5166                             {
5167                                 if (SwUndoId::INS_FROM_SHADOWCRSR == nLastUndoId)
5168                                 {
5169                                     rSh.Undo();
5170                                 }
5171                             }
5172                             SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
5173                             rSh.SetShadowCursorPos( aDocPt, eMode );
5174                         }
5175                     }
5176                 }
5177                 bCallBase = false;
5178 
5179             }
5180 
5181             // reset pushed mode in Down again if applicable
5182             if ( bPopMode && g_bModePushed )
5183             {
5184                 rSh.PopMode();
5185                 g_bModePushed = false;
5186                 bCallBase = false;
5187             }
5188             break;
5189 
5190         default:
5191             ReleaseMouse();
5192             return;
5193     }
5194 
5195     if( m_pApplyTempl )
5196     {
5197         SelectionType eSelection = rSh.GetSelectionType();
5198         SwFormatClipboard* pFormatClipboard = m_pApplyTempl->m_pFormatClipboard;
5199         if( pFormatClipboard )//apply format paintbrush
5200         {
5201             //get some parameters
5202             SwWrtShell& rWrtShell = m_rView.GetWrtShell();
5203             SfxStyleSheetBasePool* pPool=nullptr;
5204             bool bNoCharacterFormats = false;
5205             // Paste paragraph properties if the selection contains a whole paragraph or
5206             // there was no selection at all (i.e. just a left click)
5207             bool bNoParagraphFormats = rSh.HasSelection() && rSh.IsSelOnePara() && !rSh.IsSelFullPara();
5208 
5209             {
5210                 SwDocShell* pDocSh = m_rView.GetDocShell();
5211                 if(pDocSh)
5212                     pPool = pDocSh->GetStyleSheetPool();
5213                 if( (rMEvt.GetModifier()&KEY_MOD1) && (rMEvt.GetModifier()&KEY_SHIFT) )
5214                 {
5215                     bNoCharacterFormats = true;
5216                     bNoParagraphFormats = false;
5217                 }
5218                 else if( rMEvt.GetModifier() & KEY_MOD1 )
5219                     bNoParagraphFormats = true;
5220             }
5221             //execute paste
5222             pFormatClipboard->Paste( rWrtShell, pPool, bNoCharacterFormats, bNoParagraphFormats );
5223 
5224             //if the clipboard is empty after paste remove the ApplyTemplate
5225             if(!pFormatClipboard->HasContent())
5226                 SetApplyTemplate(SwApplyTemplate());
5227 
5228             //tdf#38101 remove temporary highlighting
5229             m_pUserMarker.reset();
5230         }
5231         else if( m_pApplyTempl->nColor )
5232         {
5233             sal_uInt16 nId = 0;
5234             switch( m_pApplyTempl->nColor )
5235             {
5236                 case SID_ATTR_CHAR_COLOR_EXT:
5237                     nId = RES_CHRATR_COLOR;
5238                     break;
5239                 case SID_ATTR_CHAR_BACK_COLOR:
5240                 case SID_ATTR_CHAR_COLOR_BACKGROUND:
5241                     nId = RES_CHRATR_BACKGROUND;
5242                     break;
5243             }
5244             if( nId && (SelectionType::Text|SelectionType::Table) & eSelection)
5245             {
5246                 if( rSh.IsSelection() && !rSh.HasReadonlySel() )
5247                 {
5248                     m_pApplyTempl->nUndo =
5249                         std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5250                     if (nId == RES_CHRATR_BACKGROUND)
5251                         ApplyCharBackground(m_aWaterCanTextBackColor, model::ComplexColor(), rSh);
5252                     else
5253                         rSh.SetAttrItem( SvxColorItem( m_aWaterCanTextColor, nId ) );
5254                     rSh.UnSetVisibleCursor();
5255                     rSh.EnterStdMode();
5256                     rSh.SetVisibleCursor(aDocPt);
5257                     bCallBase = false;
5258                     m_aTemplateTimer.Stop();
5259                 }
5260                 else if(rMEvt.GetClicks() == 1)
5261                 {
5262                     // no selection -> so turn off watering can
5263                     m_aTemplateTimer.Start();
5264                 }
5265             }
5266         }
5267         else
5268         {
5269             OUString aStyleName;
5270             switch ( m_pApplyTempl->eType )
5271             {
5272                 case SfxStyleFamily::Para:
5273                     if( (( SelectionType::Text | SelectionType::Table )
5274                          & eSelection ) && !rSh.HasReadonlySel() )
5275                     {
5276                         rSh.SetTextFormatColl( m_pApplyTempl->aColl.pTextColl );
5277                         m_pApplyTempl->nUndo =
5278                             std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5279                         bCallBase = false;
5280                         if ( m_pApplyTempl->aColl.pTextColl )
5281                             aStyleName = m_pApplyTempl->aColl.pTextColl->GetName();
5282                     }
5283                     break;
5284                 case SfxStyleFamily::Char:
5285                     if( (( SelectionType::Text | SelectionType::Table )
5286                          & eSelection ) && !rSh.HasReadonlySel() )
5287                     {
5288                         rSh.SetAttrItem( SwFormatCharFormat(m_pApplyTempl->aColl.pCharFormat) );
5289                         rSh.UnSetVisibleCursor();
5290                         rSh.EnterStdMode();
5291                         rSh.SetVisibleCursor(aDocPt);
5292                         m_pApplyTempl->nUndo =
5293                             std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5294                         bCallBase = false;
5295                         if ( m_pApplyTempl->aColl.pCharFormat )
5296                             aStyleName = m_pApplyTempl->aColl.pCharFormat->GetName();
5297                     }
5298                     break;
5299                 case SfxStyleFamily::Frame :
5300                 {
5301                     const SwFrameFormat* pFormat = rSh.GetFormatFromObj( aDocPt );
5302                     if(dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
5303                     {
5304                         rSh.SetFrameFormat( m_pApplyTempl->aColl.pFrameFormat, false, &aDocPt );
5305                         m_pApplyTempl->nUndo =
5306                             std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5307                         bCallBase = false;
5308                         if( m_pApplyTempl->aColl.pFrameFormat )
5309                             aStyleName = m_pApplyTempl->aColl.pFrameFormat->GetName();
5310                     }
5311                     break;
5312                 }
5313                 case SfxStyleFamily::Page:
5314                     // no Undo with page templates
5315                     rSh.ChgCurPageDesc( *m_pApplyTempl->aColl.pPageDesc );
5316                     if ( m_pApplyTempl->aColl.pPageDesc )
5317                         aStyleName = m_pApplyTempl->aColl.pPageDesc->GetName();
5318                     m_pApplyTempl->nUndo =
5319                         std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5320                     bCallBase = false;
5321                     break;
5322                 case SfxStyleFamily::Pseudo:
5323                     if( !rSh.HasReadonlySel() )
5324                     {
5325                         rSh.SetCurNumRule( *m_pApplyTempl->aColl.pNumRule,
5326                                            false,
5327                                            m_pApplyTempl->aColl.pNumRule->GetDefaultListId() );
5328                         bCallBase = false;
5329                         m_pApplyTempl->nUndo =
5330                             std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5331                         if( m_pApplyTempl->aColl.pNumRule )
5332                             aStyleName = m_pApplyTempl->aColl.pNumRule->GetName();
5333                     }
5334                     break;
5335                 default: break;
5336             }
5337 
5338             uno::Reference< frame::XDispatchRecorder > xRecorder =
5339                     m_rView.GetViewFrame().GetBindings().GetRecorder();
5340             if ( !aStyleName.isEmpty() && xRecorder.is() )
5341             {
5342                 SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
5343                 if ( pSfxShell )
5344                 {
5345                     SfxRequest aReq(m_rView.GetViewFrame(), SID_STYLE_APPLY);
5346                     aReq.AppendItem( SfxStringItem( SID_STYLE_APPLY, aStyleName ) );
5347                     aReq.AppendItem( SfxUInt16Item( SID_STYLE_FAMILY, static_cast<sal_uInt16>(m_pApplyTempl->eType) ) );
5348                     aReq.Done();
5349                 }
5350             }
5351         }
5352 
5353     }
5354     ReleaseMouse();
5355     // Only processed MouseEvents arrive here; only at these this mode can
5356     // be reset.
5357     m_bMBPressed = false;
5358 
5359     // Make this call just to be sure. Selecting has finished surely by now.
5360     // Otherwise the timeout's timer could give problems.
5361     EnterArea();
5362     g_bNoInterrupt = false;
5363 
5364     if (bCallBase)
5365         Window::MouseButtonUp(rMEvt);
5366 
5367     if (!(pSdrView && rMEvt.GetClicks() == 1 && comphelper::LibreOfficeKit::isActive()))
5368         return;
5369 
5370     // When tiled rendering, single click on a shape text starts editing already.
5371     SdrViewEvent aViewEvent;
5372     SdrHitKind eHit = pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aViewEvent);
5373     const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
5374     if (eHit == SdrHitKind::TextEditObj && rMarkList.GetMarkCount() == 1)
5375     {
5376         if (SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj())
5377         {
5378             EnterDrawTextMode(pObj->GetLogicRect().Center());
5379             if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
5380                 pSwDrawTextShell->Init();
5381         }
5382     }
5383 }
5384 
5385 /**
5386  * Apply template
5387  */
SetApplyTemplate(const SwApplyTemplate & rTempl)5388 void SwEditWin::SetApplyTemplate(const SwApplyTemplate &rTempl)
5389 {
5390     static bool bIdle = false;
5391     m_pApplyTempl.reset();
5392     SwWrtShell &rSh = m_rView.GetWrtShell();
5393 
5394     if(rTempl.m_pFormatClipboard)
5395     {
5396         m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5397         m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5398         SetPointer( PointerStyle::Fill );//@todo #i20119# maybe better a new brush pointer here in future
5399         rSh.NoEdit( false );
5400         bIdle = rSh.GetViewOptions()->IsIdle();
5401         rSh.GetViewOptions()->SetIdle( false );
5402     }
5403     else if(rTempl.nColor)
5404     {
5405         m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5406         m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5407         SetPointer( PointerStyle::Fill );
5408         rSh.NoEdit( false );
5409         bIdle = rSh.GetViewOptions()->IsIdle();
5410         rSh.GetViewOptions()->SetIdle( false );
5411     }
5412     else if( rTempl.eType != SfxStyleFamily::None )
5413     {
5414         m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5415         m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5416         SetPointer( PointerStyle::Fill  );
5417         rSh.NoEdit( false );
5418         bIdle = rSh.GetViewOptions()->IsIdle();
5419         rSh.GetViewOptions()->SetIdle( false );
5420     }
5421     else
5422     {
5423         SetPointer( PointerStyle::Text );
5424         rSh.UnSetVisibleCursor();
5425 
5426         rSh.GetViewOptions()->SetIdle( bIdle );
5427         if ( !rSh.IsSelFrameMode() )
5428             rSh.Edit();
5429     }
5430 
5431     static sal_uInt16 aInva[] =
5432     {
5433         SID_STYLE_WATERCAN,
5434         SID_ATTR_CHAR_COLOR_EXT,
5435         SID_ATTR_CHAR_COLOR_BACKGROUND_EXT,
5436         0
5437     };
5438     m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
5439 }
5440 
5441 /**
5442  * Ctor
5443  */
SwEditWin(vcl::Window * pParent,SwView & rMyView)5444 SwEditWin::SwEditWin(vcl::Window *pParent, SwView &rMyView):
5445     DocWindow(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
5446     DropTargetHelper( this ),
5447     DragSourceHelper( this ),
5448 
5449     m_aTimer("SwEditWin"),
5450     m_aKeyInputFlushTimer("SwEditWin m_aKeyInputFlushTimer"),
5451     m_eBufferLanguage(LANGUAGE_DONTKNOW),
5452     m_aTemplateTimer("SwEditWin m_aTemplateTimer"),
5453     m_pUserMarkerObj( nullptr ),
5454 
5455     m_rView( rMyView ),
5456 
5457     m_aActHitType(SdrHitKind::NONE),
5458     m_nDropFormat( SotClipboardFormatId::NONE ),
5459     m_nDropAction( 0 ),
5460     m_nDropDestination( SotExchangeDest::NONE ),
5461 
5462     m_eBezierMode(SID_BEZIER_INSERT),
5463     m_nInsFrameColCount( 1 ),
5464     m_eDrawMode(SdrObjKind::NONE),
5465 
5466     m_bMBPressed(false),
5467     m_bInsDraw(false),
5468     m_bInsFrame(false),
5469     m_bIsInMove(false),
5470     m_bIsInDrag(false),
5471     m_bOldIdle(false),
5472     m_bOldIdleSet(false),
5473     m_bChainMode(false),
5474     m_bWasShdwCursor(false),
5475     m_bLockInput(false),
5476     m_bIsRowDrag(false),
5477     m_bUseInputLanguage(false),
5478     m_bObjectSelect(false),
5479     mbIsDragSidebar(false),
5480     m_nKS_NUMDOWN_Count(0),
5481     m_nKS_NUMINDENTINC_Count(0),
5482     m_pFrameControlsManager(new SwFrameControlsManager(this))
5483 {
5484     set_id(u"writer_edit"_ustr);
5485     SetHelpId(HID_EDIT_WIN);
5486     EnableChildTransparentMode();
5487     SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
5488 
5489     m_bMBPressed = m_bInsDraw = m_bInsFrame =
5490     m_bIsInDrag = m_bOldIdle = m_bOldIdleSet = m_bChainMode = m_bWasShdwCursor = false;
5491     // initially use the input language
5492     m_bUseInputLanguage = true;
5493 
5494     SetMapMode(MapMode(MapUnit::MapTwip));
5495 
5496     SetPointer( PointerStyle::Text );
5497     m_aTimer.SetInvokeHandler(LINK(this, SwEditWin, TimerHandler));
5498 
5499     m_aKeyInputFlushTimer.SetTimeout( 20 );
5500     m_aKeyInputFlushTimer.SetInvokeHandler(LINK(this, SwEditWin, KeyInputFlushHandler));
5501 
5502     // TemplatePointer for colors should be reset without
5503     // selection after single click, but not after double-click (tdf#122442)
5504     m_aTemplateTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
5505     m_aTemplateTimer.SetInvokeHandler(LINK(this, SwEditWin, TemplateTimerHdl));
5506 
5507     // temporary solution!!! Should set the font of the current
5508     // insert position at every cursor movement!
5509     if( !rMyView.GetDocShell()->IsReadOnly() )
5510     {
5511         SetInputContext( InputContext(vcl::Font(), InputContextFlags::Text |
5512                                             InputContextFlags::ExtText ) );
5513     }
5514 }
5515 
~SwEditWin()5516 SwEditWin::~SwEditWin()
5517 {
5518     disposeOnce();
5519 }
5520 
dispose()5521 void SwEditWin::dispose()
5522 {
5523     m_pShadCursor.reset();
5524 
5525     if( s_pQuickHlpData->m_bIsDisplayed && m_rView.GetWrtShellPtr() )
5526         s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
5527     g_bExecuteDrag = false;
5528     m_pApplyTempl.reset();
5529 
5530     m_rView.SetDrawFuncPtr(nullptr);
5531 
5532     m_pUserMarker.reset();
5533 
5534     m_pAnchorMarker.reset();
5535 
5536     m_pFrameControlsManager->dispose();
5537     m_pFrameControlsManager.reset();
5538 
5539     DragSourceHelper::dispose();
5540     DropTargetHelper::dispose();
5541     vcl::Window::dispose();
5542 }
5543 
5544 /**
5545  * Turn on DrawTextEditMode
5546  */
EnterDrawTextMode(const Point & aDocPos)5547 void SwEditWin::EnterDrawTextMode( const Point& aDocPos )
5548 {
5549     if ( m_rView.EnterDrawTextMode(aDocPos) )
5550     {
5551         if (m_rView.GetDrawFuncPtr())
5552         {
5553             m_rView.GetDrawFuncPtr()->Deactivate();
5554             m_rView.SetDrawFuncPtr(nullptr);
5555             m_rView.LeaveDrawCreate();
5556         }
5557         m_rView.NoRotate();
5558         m_rView.AttrChangedNotify(nullptr);
5559     }
5560 }
5561 
5562 /**
5563  * Turn on DrawMode
5564  */
EnterDrawMode(const MouseEvent & rMEvt,const Point & aDocPos)5565 bool SwEditWin::EnterDrawMode(const MouseEvent& rMEvt, const Point& aDocPos)
5566 {
5567     SwWrtShell &rSh = m_rView.GetWrtShell();
5568     SdrView *pSdrView = rSh.GetDrawView();
5569 
5570     if ( m_rView.GetDrawFuncPtr() )
5571     {
5572         if (rSh.IsDrawCreate())
5573             return true;
5574 
5575         bool bRet = m_rView.GetDrawFuncPtr()->MouseButtonDown( rMEvt );
5576         m_rView.AttrChangedNotify(nullptr);
5577         return bRet;
5578     }
5579 
5580     if ( pSdrView && pSdrView->IsTextEdit() )
5581     {
5582         bool bUnLockView = !rSh.IsViewLocked();
5583         rSh.LockView( true );
5584 
5585         rSh.EndTextEdit(); // clicked aside, end Edit
5586         rSh.SelectObj( aDocPos );
5587         if ( !rSh.IsObjSelected() && !rSh.IsFrameSelected() )
5588             rSh.LeaveSelFrameMode();
5589         else
5590         {
5591             SwEditWin::s_nDDStartPosY = aDocPos.Y();
5592             SwEditWin::s_nDDStartPosX = aDocPos.X();
5593             g_bFrameDrag = true;
5594         }
5595         if( bUnLockView )
5596             rSh.LockView( false );
5597         m_rView.AttrChangedNotify(nullptr);
5598         return true;
5599     }
5600     return false;
5601 }
5602 
IsDrawSelMode() const5603 bool SwEditWin::IsDrawSelMode() const
5604 {
5605     return IsObjectSelect();
5606 }
5607 
GetFocus()5608 void SwEditWin::GetFocus()
5609 {
5610     if ( m_rView.GetPostItMgr()->HasActiveSidebarWin() )
5611     {
5612         m_rView.GetPostItMgr()->GrabFocusOnActiveSidebarWin();
5613     }
5614     else
5615     {
5616         m_rView.GotFocus();
5617         Window::GetFocus();
5618 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5619         m_rView.GetWrtShell().InvalidateAccessibleFocus();
5620 #endif
5621     }
5622 }
5623 
LoseFocus()5624 void SwEditWin::LoseFocus()
5625 {
5626 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5627     if (m_rView.GetWrtShellPtr())
5628         m_rView.GetWrtShell().InvalidateAccessibleFocus();
5629 #endif
5630     Window::LoseFocus();
5631     if( s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed )
5632         s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
5633 }
5634 
IsViewReadonly() const5635 bool SwEditWin::IsViewReadonly() const
5636 {
5637     SwWrtShell &rSh = m_rView.GetWrtShell();
5638     return (m_rView.GetDocShell()->IsReadOnly() && rSh.IsCursorReadonly()) || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView());
5639 }
5640 
Command(const CommandEvent & rCEvt)5641 void SwEditWin::Command( const CommandEvent& rCEvt )
5642 {
5643     if (isDisposed())
5644     {
5645         // If ViewFrame dies shortly, no popup anymore!
5646         Window::Command(rCEvt);
5647         return;
5648     }
5649 
5650     SwWrtShell &rSh = m_rView.GetWrtShell();
5651 
5652     // The command event is send to the window after a possible context
5653     // menu from an inplace client has been closed. Now we have the chance
5654     // to deactivate the inplace client without any problem regarding parent
5655     // windows and code on the stack.
5656     SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
5657     bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
5658     if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu ))
5659     {
5660         rSh.FinishOLEObj();
5661         return;
5662     }
5663 
5664     bool bCallBase      = true;
5665 
5666     switch ( rCEvt.GetCommand() )
5667     {
5668     case CommandEventId::ContextMenu:
5669     {
5670             const sal_uInt16 nId = SwInputChild::GetChildWindowId();
5671             SwInputChild* pChildWin = static_cast<SwInputChild*>(GetView().GetViewFrame().
5672                                                 GetChildWindow( nId ));
5673 
5674             if (m_rView.GetPostItMgr()->IsHit(rCEvt.GetMousePosPixel()))
5675                 return;
5676 
5677             Point aDocPos( PixelToLogic( rCEvt.GetMousePosPixel() ) );
5678             if ( !rCEvt.IsMouseEvent() )
5679                 aDocPos = rSh.GetCharRect().Center();
5680 
5681             // Don't trigger the command on a frame anchored to header/footer is not editing it
5682             FrameControlType eControl;
5683             bool bOverFly = false;
5684             bool bPageAnchored = false;
5685             bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
5686             // !bOverHeaderFooterFly doesn't mean we have a frame to select
5687             if ( !bPageAnchored && rCEvt.IsMouseEvent( ) &&
5688                  ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
5689                    ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
5690             {
5691                 return;
5692             }
5693 
5694             if((!pChildWin || pChildWin->GetView() != &m_rView) &&
5695                 !rSh.IsDrawCreate() && !IsDrawAction())
5696             {
5697                 CurrShell aCurr( &rSh );
5698                 if (!m_pApplyTempl)
5699                 {
5700                     if (g_bNoInterrupt)
5701                     {
5702                         ReleaseMouse();
5703                         g_bNoInterrupt = false;
5704                         m_bMBPressed = false;
5705                     }
5706                     if ( rCEvt.IsMouseEvent() )
5707                     {
5708                         SelectMenuPosition(rSh, rCEvt.GetMousePosPixel());
5709                         m_rView.StopShellTimer();
5710                     }
5711                     const Point aPixPos = LogicToPixel( aDocPos );
5712 
5713                     if ( m_rView.GetDocShell()->IsReadOnly() )
5714                     {
5715                         SwReadOnlyPopup aROPopup(aDocPos, m_rView);
5716 
5717                         ui::ContextMenuExecuteEvent aEvent;
5718                         aEvent.SourceWindow = VCLUnoHelper::GetInterface( this );
5719                         aEvent.ExecutePosition.X = aPixPos.X();
5720                         aEvent.ExecutePosition.Y = aPixPos.Y();
5721                         rtl::Reference<VCLXPopupMenu> xMenu;
5722                         rtl::Reference<VCLXPopupMenu> xMenuInterface = aROPopup.CreateMenuInterface();
5723                         if (GetView().TryContextMenuInterception(xMenuInterface, u"private:resource/ReadonlyContextMenu"_ustr, xMenu, aEvent))
5724                         {
5725                             if (xMenu.is())
5726                             {
5727                                 css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
5728                                 sal_uInt16 nExecId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1),
5729                                                                     css::awt::PopupMenuDirection::EXECUTE_DOWN);
5730                                 if (!::ExecuteMenuCommand(xMenu, m_rView.GetViewFrame(), nExecId))
5731                                     aROPopup.Execute(this, nExecId);
5732                             }
5733                             else
5734                                 aROPopup.Execute(this, aPixPos);
5735                         }
5736                     }
5737                     else if ( !m_rView.ExecSpellPopup( aDocPos ) )
5738                         SfxDispatcher::ExecutePopup(this, &aPixPos);
5739                 }
5740                 else if (m_pApplyTempl->nUndo < rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount())
5741                 {
5742                     // Undo until we reach the point when we entered this context.
5743                     rSh.Do(SwWrtShell::UNDO);
5744                 }
5745                 bCallBase = false;
5746             }
5747     }
5748     break;
5749 
5750     case CommandEventId::Wheel:
5751     case CommandEventId::StartAutoScroll:
5752     case CommandEventId::AutoScroll:
5753             if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
5754             {
5755                 GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
5756                 m_pSavedOutlineFrame = nullptr;
5757             }
5758             m_pShadCursor.reset();
5759             bCallBase = !m_rView.HandleWheelCommands( rCEvt );
5760             break;
5761 
5762     case CommandEventId::GestureZoom:
5763     {
5764         if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
5765         {
5766             GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
5767             m_pSavedOutlineFrame = nullptr;
5768         }
5769         m_pShadCursor.reset();
5770         bCallBase = !m_rView.HandleGestureZoomCommand(rCEvt);
5771         break;
5772     }
5773 
5774     case CommandEventId::GestureLongPress:
5775     case CommandEventId::GestureSwipe: //nothing yet
5776             break;
5777 
5778     case CommandEventId::StartExtTextInput:
5779     {
5780         bool bIsViewReadOnly = IsViewReadonly();
5781         if(!bIsViewReadOnly)
5782         {
5783             if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5784             {
5785                 bCallBase = false;
5786                 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5787             }
5788             else
5789             {
5790                 if( rSh.HasSelection() )
5791                     rSh.DelRight();
5792 
5793                 bCallBase = false;
5794                 LanguageType eInputLanguage = GetInputLanguage();
5795                 rSh.CreateExtTextInput(eInputLanguage);
5796             }
5797         }
5798         break;
5799     }
5800     case CommandEventId::EndExtTextInput:
5801     {
5802         bool bIsViewReadOnly = IsViewReadonly();
5803 
5804         if(!bIsViewReadOnly)
5805         {
5806             if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5807             {
5808                 bCallBase = false;
5809                 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5810             }
5811             else
5812             {
5813                 bCallBase = false;
5814                 OUString sRecord = rSh.DeleteExtTextInput();
5815                 uno::Reference< frame::XDispatchRecorder > xRecorder =
5816                         m_rView.GetViewFrame().GetBindings().GetRecorder();
5817 
5818                 if ( !sRecord.isEmpty() )
5819                 {
5820                     // convert quotes in IME text
5821                     // works on the last input character, this is especially in Korean text often done
5822                     // quotes that are inside of the string are not replaced!
5823                     const sal_Unicode aCh = sRecord[sRecord.getLength() - 1];
5824                     SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
5825                     SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
5826                     if(pACorr &&
5827                         (( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
5828                         ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
5829                     {
5830                         rSh.DelLeft();
5831                         rSh.AutoCorrect( *pACorr, aCh );
5832                     }
5833 
5834                     if ( xRecorder.is() )
5835                     {
5836                         // determine Shell
5837                         SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
5838                         // generate request and record
5839                         if (pSfxShell)
5840                         {
5841                             SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
5842                             aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, sRecord ) );
5843                             aReq.Done();
5844                         }
5845                     }
5846                 }
5847             }
5848         }
5849     }
5850     break;
5851     case CommandEventId::ExtTextInput:
5852     {
5853         bool bIsViewReadOnly = IsViewReadonly();
5854 
5855         if (!bIsViewReadOnly && !rSh.HasReadonlySel())
5856         {
5857             if( s_pQuickHlpData->m_bIsDisplayed )
5858                 s_pQuickHlpData->Stop( rSh );
5859 
5860             if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5861             {
5862                 bCallBase = false;
5863                 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5864             }
5865             else
5866             {
5867                 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
5868                 if( pData )
5869                 {
5870                     bCallBase = false;
5871                     rSh.SetExtTextInputData( *pData );
5872                 }
5873             }
5874             uno::Reference< frame::XDispatchRecorder > xRecorder =
5875                         m_rView.GetViewFrame().GetBindings().GetRecorder();
5876             if(!xRecorder.is())
5877             {
5878                 SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
5879                 if (!rACfg.IsAutoTextTip() || !ShowAutoText(rSh.GetChunkForAutoText()))
5880                 {
5881                     SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
5882                     if (pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
5883                         ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
5884                 }
5885             }
5886         }
5887 
5888         if (rSh.HasReadonlySel())
5889         {
5890             // Inform the user that the request has been ignored.
5891             rSh.InfoReadOnlyDialog(true);
5892         }
5893     }
5894     break;
5895     case CommandEventId::CursorPos:
5896         // will be handled by the base class
5897         break;
5898 
5899     case CommandEventId::PasteSelection:
5900         if( !m_rView.GetDocShell()->IsReadOnly() )
5901         {
5902             TransferableDataHelper aDataHelper(
5903                         TransferableDataHelper::CreateFromPrimarySelection());
5904             if( !aDataHelper.GetXTransferable().is() )
5905                 break;
5906 
5907             SotExchangeDest nDropDestination = GetDropDestination( rCEvt.GetMousePosPixel() );
5908             if( nDropDestination == SotExchangeDest::NONE )
5909                 break;
5910             SotClipboardFormatId nDropFormat;
5911             sal_uInt8 nEventAction, nDropAction;
5912             SotExchangeActionFlags nActionFlags;
5913             nDropAction = SotExchange::GetExchangeAction(
5914                                 aDataHelper.GetDataFlavorExVector(),
5915                                 nDropDestination, EXCHG_IN_ACTION_COPY,
5916                                 EXCHG_IN_ACTION_COPY, nDropFormat,
5917                                 nEventAction,
5918                                 SotClipboardFormatId::NONE, nullptr,
5919                                 &nActionFlags );
5920             if( EXCHG_INOUT_ACTION_NONE != nDropAction )
5921             {
5922                 const Point aDocPt( PixelToLogic( rCEvt.GetMousePosPixel() ) );
5923                 SwTransferable::PasteData( aDataHelper, rSh, nDropAction, nActionFlags,
5924                                     nDropFormat, nDropDestination, false,
5925                                     false, &aDocPt, EXCHG_IN_ACTION_COPY,
5926                                     true );
5927             }
5928         }
5929         break;
5930         case CommandEventId::ModKeyChange :
5931         {
5932             const CommandModKeyData* pCommandData = rCEvt.GetModKeyData();
5933             if (!pCommandData->IsDown() && pCommandData->IsMod1() && !pCommandData->IsMod2())
5934             {
5935                 sal_uInt16 nSlot = 0;
5936                 if(pCommandData->IsLeftShift() && !pCommandData->IsRightShift())
5937                     nSlot = SID_ATTR_PARA_LEFT_TO_RIGHT;
5938                 else if(!pCommandData->IsLeftShift() && pCommandData->IsRightShift())
5939                     nSlot = SID_ATTR_PARA_RIGHT_TO_LEFT;
5940                 if(nSlot && SvtCTLOptions::IsCTLFontEnabled())
5941                     GetView().GetViewFrame().GetDispatcher()->Execute(nSlot);
5942             }
5943         }
5944         break;
5945         case CommandEventId::InputLanguageChange :
5946             // i#42732 - update state of fontname if input language changes
5947             g_bInputLanguageSwitched = true;
5948             SetUseInputLanguage( true );
5949         break;
5950         case CommandEventId::SelectionChange:
5951         {
5952             const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
5953             rSh.SttCursorMove();
5954             rSh.GoStartSentence();
5955             rSh.GetCursor()->GetPoint()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetStart()));
5956             rSh.SetMark();
5957             rSh.GetCursor()->GetMark()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetEnd() - pData->GetStart()));
5958             rSh.EndCursorMove( true );
5959         }
5960         break;
5961         case CommandEventId::PrepareReconversion:
5962         if( rSh.HasSelection() )
5963         {
5964             SwPaM *pCursor = rSh.GetCursor();
5965 
5966             if( rSh.IsMultiSelection() )
5967             {
5968                 if (pCursor && !pCursor->HasMark() &&
5969                     pCursor->GetPoint() == pCursor->GetMark())
5970                 {
5971                     rSh.GoPrevCursor();
5972                     pCursor = rSh.GetCursor();
5973                 }
5974 
5975                 // Cancel all selections other than the last selected one.
5976                 while( rSh.GetCursor()->GetNext() != rSh.GetCursor() )
5977                     delete rSh.GetCursor()->GetNext();
5978             }
5979 
5980             if( pCursor )
5981             {
5982                 SwNodeOffset nPosNodeIdx = pCursor->GetPoint()->GetNodeIndex();
5983                 const sal_Int32 nPosIdx = pCursor->GetPoint()->GetContentIndex();
5984                 SwNodeOffset nMarkNodeIdx = pCursor->GetMark()->GetNodeIndex();
5985                 const sal_Int32 nMarkIdx = pCursor->GetMark()->GetContentIndex();
5986 
5987                 if( !rSh.GetCursor()->HasMark() )
5988                     rSh.GetCursor()->SetMark();
5989 
5990                 rSh.SttCursorMove();
5991 
5992                 if( nPosNodeIdx < nMarkNodeIdx )
5993                 {
5994                     rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
5995                     rSh.GetCursor()->GetMark()->Assign(nPosNodeIdx,
5996                         rSh.GetCursor()->GetPointContentNode()->Len());
5997                 }
5998                 else if( nPosNodeIdx == nMarkNodeIdx )
5999                 {
6000                     rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
6001                     rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
6002                 }
6003                 else
6004                 {
6005                     rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
6006                     rSh.GetCursor()->GetPoint()->Assign(nMarkNodeIdx,
6007                         rSh.GetCursor()->GetMarkContentNode()->Len());
6008                 }
6009 
6010                 rSh.EndCursorMove( true );
6011             }
6012         }
6013         break;
6014         case CommandEventId::QueryCharPosition:
6015         {
6016             bool bVertical = rSh.IsInVerticalText();
6017             const SwPosition& rPos = *rSh.GetCursor()->GetPoint();
6018             SwDocShell* pDocSh = m_rView.GetDocShell();
6019             SwDoc *pDoc = pDocSh->GetDoc();
6020             SwExtTextInput* pInput = pDoc->GetExtTextInput( rPos.GetNode(), rPos.GetContentIndex() );
6021             if ( pInput )
6022             {
6023                 const SwPosition& rStart = *pInput->Start();
6024                 const SwPosition& rEnd = *pInput->End();
6025                 sal_Int32 nSize = rEnd.GetContentIndex() - rStart.GetContentIndex();
6026                 vcl::Window& rWin = rSh.GetView().GetEditWin();
6027                 if ( nSize == 0 )
6028                 {
6029                     // When the composition does not exist, use Caret rect instead.
6030                     const SwRect& aCaretRect ( rSh.GetCharRect() );
6031                     tools::Rectangle aRect( aCaretRect.Left(), aCaretRect.Top(), aCaretRect.Right(), aCaretRect.Bottom() );
6032                     rWin.SetCompositionCharRect( &aRect, 1, bVertical );
6033                 }
6034                 else
6035                 {
6036                     std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ nSize ]);
6037                     int nRectIndex = 0;
6038                     for ( sal_Int32 nIndex = rStart.GetContentIndex(); nIndex < rEnd.GetContentIndex(); ++nIndex )
6039                     {
6040                         const SwPosition aPos( rStart.GetNode(), rStart.GetNode().GetContentNode(), nIndex );
6041                         SwRect aRect ( rSh.GetCharRect() );
6042                         rSh.GetCharRectAt( aRect, &aPos );
6043                         aRects[ nRectIndex ] = tools::Rectangle( aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom() );
6044                         ++nRectIndex;
6045                     }
6046                     rWin.SetCompositionCharRect( aRects.get(), nSize, bVertical );
6047                 }
6048             }
6049             bCallBase = false;
6050         }
6051         break;
6052         default:
6053             SAL_WARN("sw.ui", "unknown command.");
6054         break;
6055     }
6056     if (bCallBase)
6057         Window::Command(rCEvt);
6058 }
6059 
6060 /*  i#18686 select the object/cursor at the mouse
6061     position of the context menu request */
SelectMenuPosition(SwWrtShell & rSh,const Point & rMousePos)6062 void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const Point& rMousePos )
6063 {
6064     const Point aDocPos( PixelToLogic( rMousePos ) );
6065     const bool bIsInsideSelectedObj( rSh.IsInsideSelectedObj( aDocPos ) );
6066     //create a synthetic mouse event out of the coordinates
6067     MouseEvent aMEvt(rMousePos);
6068     SdrView *pSdrView = rSh.GetDrawView();
6069     if ( pSdrView )
6070     {
6071         // no close of insert_draw and reset of
6072         // draw mode, if context menu position is inside a selected object.
6073         if ( !bIsInsideSelectedObj && m_rView.GetDrawFuncPtr() )
6074         {
6075 
6076             m_rView.GetDrawFuncPtr()->Deactivate();
6077             m_rView.SetDrawFuncPtr(nullptr);
6078             m_rView.LeaveDrawCreate();
6079             SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
6080             rBind.Invalidate( SID_ATTR_SIZE );
6081             rBind.Invalidate( SID_TABLE_CELL );
6082         }
6083 
6084         // if draw text is active and there's a text selection
6085         // at the mouse position then do nothing
6086         if(rSh.GetSelectionType() & SelectionType::DrawObjectEditMode)
6087         {
6088             OutlinerView* pOLV = pSdrView->GetTextEditOutlinerView();
6089             ESelection aSelection = pOLV->GetSelection();
6090             if(!aSelection.IsZero())
6091             {
6092                 SdrOutliner* pOutliner = pSdrView->GetTextEditOutliner();
6093                 bool bVertical = pOutliner->IsVertical();
6094                 const EditEngine& rEditEng = pOutliner->GetEditEngine();
6095                 Point aEEPos(aDocPos);
6096                 const tools::Rectangle& rOutputArea = pOLV->GetOutputArea();
6097                 // regard vertical mode
6098                 if(bVertical)
6099                 {
6100                     aEEPos -= rOutputArea.TopRight();
6101                     //invert the horizontal direction and exchange X and Y
6102                     tools::Long nTemp = -aEEPos.X();
6103                     aEEPos.setX( aEEPos.Y() );
6104                     aEEPos.setY( nTemp );
6105                 }
6106                 else
6107                     aEEPos -= rOutputArea.TopLeft();
6108 
6109                 EPosition aDocPosition = rEditEng.FindDocPosition(aEEPos);
6110                 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
6111                 // make it a forward selection - otherwise the IsLess/IsGreater do not work :-(
6112                 aSelection.Adjust();
6113                 if(!(aCompare < aSelection) && !(aCompare > aSelection))
6114                 {
6115                     return;
6116                 }
6117             }
6118 
6119         }
6120 
6121         if (pSdrView->MouseButtonDown( aMEvt, GetOutDev() ) )
6122         {
6123             pSdrView->MouseButtonUp( aMEvt, GetOutDev() );
6124             rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
6125             return;
6126         }
6127     }
6128     rSh.ResetCursorStack();
6129 
6130     if ( EnterDrawMode( aMEvt, aDocPos ) )
6131     {
6132         return;
6133     }
6134     if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
6135     {
6136         StopInsFrame();
6137         rSh.Edit();
6138     }
6139 
6140     UpdatePointer( aDocPos );
6141 
6142     if( !rSh.IsSelFrameMode() &&
6143         !GetView().GetViewFrame().GetDispatcher()->IsLocked() )
6144     {
6145         // Test if there is a draw object at that position and if it should be selected.
6146         bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
6147 
6148         if(bShould)
6149         {
6150             m_rView.NoRotate();
6151             rSh.HideCursor();
6152 
6153             bool bUnLockView = !rSh.IsViewLocked();
6154             rSh.LockView( true );
6155             bool bSelObj = rSh.SelectObj( aDocPos );
6156             if( bUnLockView )
6157                 rSh.LockView( false );
6158 
6159             if( bSelObj )
6160             {
6161                 // in case the frame was deselected in the macro
6162                 // just the cursor has to be displayed again.
6163                 if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
6164                     rSh.ShowCursor();
6165                 else
6166                 {
6167                     if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
6168                     {
6169                         m_rView.GetDrawFuncPtr()->Deactivate();
6170                         m_rView.SetDrawFuncPtr(nullptr);
6171                         m_rView.LeaveDrawCreate();
6172                         m_rView.AttrChangedNotify(nullptr);
6173                     }
6174 
6175                     rSh.EnterSelFrameMode( &aDocPos );
6176                     g_bFrameDrag = true;
6177                     UpdatePointer( aDocPos );
6178                     return;
6179                 }
6180             }
6181 
6182             if (!m_rView.GetDrawFuncPtr())
6183                 rSh.ShowCursor();
6184         }
6185     }
6186     else if ( rSh.IsSelFrameMode() &&
6187               (m_aActHitType == SdrHitKind::NONE ||
6188                !bIsInsideSelectedObj))
6189     {
6190         m_rView.NoRotate();
6191         bool bUnLockView = !rSh.IsViewLocked();
6192         rSh.LockView( true );
6193 
6194         if ( rSh.IsSelFrameMode() )
6195         {
6196             rSh.UnSelectFrame();
6197             rSh.LeaveSelFrameMode();
6198             m_rView.AttrChangedNotify(nullptr);
6199         }
6200 
6201         bool bSelObj = rSh.SelectObj( aDocPos, 0/*nFlag*/ );
6202         if( bUnLockView )
6203             rSh.LockView( false );
6204 
6205         if( !bSelObj )
6206         {
6207             // move cursor here so that it is not drawn in the
6208             // frame at first; ShowCursor() happens in LeaveSelFrameMode()
6209             g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
6210             rSh.LeaveSelFrameMode();
6211             m_rView.LeaveDrawCreate();
6212             m_rView.AttrChangedNotify(nullptr);
6213         }
6214         else
6215         {
6216             rSh.HideCursor();
6217             rSh.EnterSelFrameMode( &aDocPos );
6218             rSh.SelFlyGrabCursor();
6219             rSh.MakeSelVisible();
6220             g_bFrameDrag = true;
6221             if( rSh.IsFrameSelected() &&
6222                 m_rView.GetDrawFuncPtr() )
6223             {
6224                 m_rView.GetDrawFuncPtr()->Deactivate();
6225                 m_rView.SetDrawFuncPtr(nullptr);
6226                 m_rView.LeaveDrawCreate();
6227                 m_rView.AttrChangedNotify(nullptr);
6228             }
6229             UpdatePointer( aDocPos );
6230         }
6231     }
6232     else if ( rSh.IsSelFrameMode() && bIsInsideSelectedObj )
6233     {
6234         // Object at the mouse cursor is already selected - do nothing
6235         return;
6236     }
6237 
6238     if ( rSh.IsGCAttr() )
6239     {
6240         rSh.GCAttr();
6241         rSh.ClearGCAttr();
6242     }
6243 
6244     bool bOverSelect = rSh.TestCurrPam( aDocPos );
6245     bool bOverURLGrf = false;
6246     if( !bOverSelect )
6247         bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
6248 
6249     if ( !bOverSelect )
6250     {
6251         // create only temporary move context because otherwise
6252         // the query against the content form doesn't work!!!
6253         SwMvContext aMvContext( &rSh );
6254         if (rSh.HasSelection())
6255             rSh.ResetSelect(&aDocPos, false);
6256         rSh.SwCursorShell::SetCursor(aDocPos, false, /*Block=*/false, /*FieldInfo=*/true);
6257     }
6258     if( !bOverURLGrf )
6259     {
6260         const SelectionType nSelType = rSh.GetSelectionType();
6261         if( nSelType == SelectionType::Ole ||
6262             nSelType == SelectionType::Graphic )
6263         {
6264             SwMvContext aMvContext( &rSh );
6265             if( !rSh.IsFrameSelected() )
6266                 rSh.GotoNextFly();
6267             rSh.EnterSelFrameMode();
6268         }
6269     }
6270 }
6271 
lcl_GetTextShellFromDispatcher(SwView const & rView)6272 static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView )
6273 {
6274     // determine Shell
6275     SfxShell* pShell;
6276     SfxDispatcher* pDispatcher = rView.GetViewFrame().GetDispatcher();
6277     for(sal_uInt16  i = 0; true; ++i )
6278     {
6279         pShell = pDispatcher->GetShell( i );
6280         if( !pShell || dynamic_cast< const SwTextShell *>( pShell ) !=  nullptr )
6281             break;
6282     }
6283     return pShell;
6284 }
6285 
IMPL_LINK_NOARG(SwEditWin,KeyInputFlushHandler,Timer *,void)6286 IMPL_LINK_NOARG(SwEditWin, KeyInputFlushHandler, Timer *, void)
6287 {
6288     FlushInBuffer();
6289 }
6290 
InitStaticData()6291 void SwEditWin::InitStaticData()
6292 {
6293     s_pQuickHlpData = new QuickHelpData();
6294 }
6295 
FinitStaticData()6296 void SwEditWin::FinitStaticData()
6297 {
6298     delete s_pQuickHlpData;
6299 }
6300 /* i#3370 - remove quick help to prevent saving
6301  * of autocorrection suggestions */
StopQuickHelp()6302 void SwEditWin::StopQuickHelp()
6303 {
6304     if( HasFocus() && s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed  )
6305         s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
6306 }
6307 
IMPL_LINK_NOARG(SwEditWin,TemplateTimerHdl,Timer *,void)6308 IMPL_LINK_NOARG(SwEditWin, TemplateTimerHdl, Timer *, void)
6309 {
6310     SetApplyTemplate(SwApplyTemplate());
6311 }
6312 
SetChainMode(bool bOn)6313 void SwEditWin::SetChainMode( bool bOn )
6314 {
6315     if ( !m_bChainMode )
6316         StopInsFrame();
6317 
6318     m_pUserMarker.reset();
6319 
6320     m_bChainMode = bOn;
6321 
6322     static sal_uInt16 aInva[] =
6323     {
6324         FN_FRAME_CHAIN, FN_FRAME_UNCHAIN, 0
6325     };
6326     m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
6327 }
6328 
CreateAccessible()6329 uno::Reference< css::accessibility::XAccessible > SwEditWin::CreateAccessible()
6330 {
6331 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
6332     SolarMutexGuard aGuard;   // this should have happened already!!!
6333     SwWrtShell *pSh = m_rView.GetWrtShellPtr();
6334     OSL_ENSURE( pSh, "no writer shell, no accessible object" );
6335     uno::Reference<
6336         css::accessibility::XAccessible > xAcc;
6337     if( pSh )
6338         xAcc = pSh->CreateAccessible();
6339 
6340     return xAcc;
6341 #else
6342     return nullptr;
6343 #endif
6344 }
6345 
Move(QuickHelpData & rCpy)6346 void QuickHelpData::Move( QuickHelpData& rCpy )
6347 {
6348     m_aHelpStrings.clear();
6349     m_aHelpStrings.swap( rCpy.m_aHelpStrings );
6350 
6351     m_bIsDisplayed = rCpy.m_bIsDisplayed;
6352     nCurArrPos = rCpy.nCurArrPos;
6353     m_bAppendSpace = rCpy.m_bAppendSpace;
6354     m_bIsTip = rCpy.m_bIsTip;
6355     m_bIsAutoText = rCpy.m_bIsAutoText;
6356 }
6357 
ClearContent()6358 void QuickHelpData::ClearContent()
6359 {
6360     nCurArrPos = nNoPos;
6361     m_bIsDisplayed = m_bAppendSpace = false;
6362     nTipId = nullptr;
6363     m_aHelpStrings.clear();
6364     m_bIsTip = true;
6365     m_bIsAutoText = true;
6366 }
6367 
Start(SwWrtShell & rSh,const bool bRestart)6368 void QuickHelpData::Start(SwWrtShell& rSh, const bool bRestart)
6369 {
6370     if (bRestart)
6371     {
6372         nCurArrPos = 0;
6373     }
6374     m_bIsDisplayed = true;
6375 
6376     vcl::Window& rWin = rSh.GetView().GetEditWin();
6377     if( m_bIsTip )
6378     {
6379         Point aPt( rWin.OutputToScreenPixel( rWin.LogicToPixel(
6380                     rSh.GetCharRect().Pos() )));
6381         aPt.AdjustY( -3 );
6382         nTipId = Help::ShowPopover(&rWin, tools::Rectangle( aPt, Size( 1, 1 )),
6383                         CurStr(),
6384                         QuickHelpFlags::Left | QuickHelpFlags::Bottom);
6385     }
6386     else
6387     {
6388         OUString sStr(CurStr());
6389         sStr = sStr.copy(CurLen());
6390         sal_uInt16 nL = sStr.getLength();
6391         const ExtTextInputAttr nVal = ExtTextInputAttr::DottedUnderline |
6392                                 ExtTextInputAttr::Highlight;
6393         const std::vector<ExtTextInputAttr> aAttrs( nL, nVal );
6394         CommandExtTextInputData aCETID( sStr, aAttrs.data(), nL,
6395                                         0, false );
6396 
6397         //fdo#33092. If the current input language is the default
6398         //language that text would appear in if typed, then don't
6399         //force a language on for the ExtTextInput.
6400         LanguageType eInputLanguage = rWin.GetInputLanguage();
6401         if (lcl_isNonDefaultLanguage(eInputLanguage,
6402             rSh.GetView(), sStr) == INVALID_HINT)
6403         {
6404             eInputLanguage = LANGUAGE_DONTKNOW;
6405         }
6406 
6407         rSh.CreateExtTextInput(eInputLanguage);
6408         rSh.SetExtTextInputData( aCETID );
6409     }
6410 }
6411 
Stop(SwWrtShell & rSh)6412 void QuickHelpData::Stop( SwWrtShell& rSh )
6413 {
6414     if( !m_bIsTip )
6415         rSh.DeleteExtTextInput( false );
6416     else if( nTipId )
6417     {
6418         vcl::Window& rWin = rSh.GetView().GetEditWin();
6419         Help::HidePopover(&rWin, nTipId);
6420     }
6421     ClearContent();
6422 }
6423 
FillStrArr(SwWrtShell const & rSh,const OUString & rWord)6424 void QuickHelpData::FillStrArr( SwWrtShell const & rSh, const OUString& rWord )
6425 {
6426     enum Capitalization { CASE_LOWER, CASE_UPPER, CASE_SENTENCE, CASE_OTHER };
6427 
6428     // Determine word capitalization
6429     const CharClass& rCC = GetAppCharClass();
6430     const OUString sWordLower = rCC.lowercase( rWord );
6431     Capitalization aWordCase = CASE_OTHER;
6432     if ( !rWord.isEmpty() )
6433     {
6434         if ( rWord[0] == sWordLower[0] )
6435         {
6436             if ( rWord == sWordLower )
6437                 aWordCase = CASE_LOWER;
6438         }
6439         else
6440         {
6441             // First character is not lower case i.e. assume upper or title case
6442             OUString sWordSentence = sWordLower.replaceAt( 0, 1, rtl::OUStringChar(rWord[0]) );
6443             if ( rWord == sWordSentence )
6444                 aWordCase = CASE_SENTENCE;
6445             else
6446             {
6447                 if ( rWord == rCC.uppercase( rWord ) )
6448                     aWordCase = CASE_UPPER;
6449             }
6450         }
6451     }
6452 
6453     SwCalendarWrapper& rCalendar = s_getCalendarWrapper();
6454     rCalendar.LoadDefaultCalendar( rSh.GetCurLang() );
6455 
6456     // Add matching calendar month and day names
6457     for ( const auto& aNames : { rCalendar.getMonths(), rCalendar.getDays() } )
6458     {
6459         for ( const auto& rName : aNames )
6460         {
6461             const OUString& rStr( rName.FullName );
6462             // Check string longer than word and case insensitive match
6463             if( rStr.getLength() > rWord.getLength() &&
6464                 rCC.lowercase( rStr, 0, rWord.getLength() ) == sWordLower )
6465             {
6466                 OUString sStr;
6467 
6468                 //fdo#61251 if it's an exact match, ensure unchanged replacement
6469                 //exists as a candidate
6470                 if (rStr.startsWith(rWord))
6471                     m_aHelpStrings.emplace_back(rStr, rWord.getLength());
6472                 else
6473                     sStr = rStr; // to be added if no case conversion is performed below
6474 
6475                 if ( aWordCase == CASE_LOWER )
6476                     sStr = rCC.lowercase(rStr);
6477                 else if ( aWordCase == CASE_SENTENCE )
6478                     sStr = rCC.lowercase(rStr).replaceAt(0, 1, rtl::OUStringChar(rStr[0]));
6479                 else if ( aWordCase == CASE_UPPER )
6480                     sStr = rCC.uppercase(rStr);
6481 
6482                 if (!sStr.isEmpty())
6483                     m_aHelpStrings.emplace_back(sStr, rWord.getLength());
6484             }
6485         }
6486     }
6487 
6488     // Add matching current date in ISO 8601 format, for example 2016-01-30
6489     OUString rStrToday;
6490 
6491     // do not suggest for single years, for example for "2016",
6492     // only for "201" or "2016-..." (to avoid unintentional text
6493     // insertion at line ending, for example typing "30 January 2016")
6494     if (!rWord.isEmpty() && rWord.getLength() != 4 && rWord[0] == '2')
6495     {
6496         rStrToday = utl::toISO8601(DateTime(Date(Date::SYSTEM)).GetUNODateTime());
6497         if (rStrToday.startsWith(rWord))
6498             m_aHelpStrings.emplace_back(rStrToday, rWord.getLength());
6499     }
6500 
6501     // Add matching words from AutoCompleteWord list
6502     const SwAutoCompleteWord& rACList = SwEditShell::GetAutoCompleteWords();
6503     std::vector<OUString> strings;
6504 
6505     if ( !rACList.GetWordsMatching( rWord, strings ) )
6506         return;
6507 
6508     for (const OUString & aCompletedString : strings)
6509     {
6510         // when we have a matching current date, avoid to suggest
6511         // other words with the same matching starting characters,
6512         // for example 2016-01-3 instead of 2016-01-30
6513         if (!rStrToday.isEmpty() && aCompletedString.startsWith(rWord))
6514             continue;
6515 
6516         OUString sStr;
6517 
6518         //fdo#61251 if it's an exact match, ensure unchanged replacement
6519         //exists as a candidate
6520         if (aCompletedString.startsWith(rWord))
6521             m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
6522         else
6523             sStr = aCompletedString; // to be added if no case conversion is performed below
6524 
6525         if (aWordCase == CASE_LOWER)
6526             sStr = rCC.lowercase(aCompletedString);
6527         else if (aWordCase == CASE_SENTENCE)
6528             sStr = rCC.lowercase(aCompletedString)
6529                        .replaceAt(0, 1, rtl::OUStringChar(aCompletedString[0]));
6530         else if (aWordCase == CASE_UPPER)
6531             sStr = rCC.uppercase(aCompletedString);
6532 
6533         if (!sStr.isEmpty())
6534             m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
6535     }
6536 }
6537 
6538 namespace {
6539 
6540 class CompareIgnoreCaseAsciiFavorExact
6541 {
6542     const OUString &m_rOrigWord;
6543 public:
CompareIgnoreCaseAsciiFavorExact(const OUString & rOrigWord)6544     explicit CompareIgnoreCaseAsciiFavorExact(const OUString& rOrigWord)
6545         : m_rOrigWord(rOrigWord)
6546     {
6547     }
6548 
operator ()(const std::pair<OUString,sal_uInt16> & s1,const std::pair<OUString,sal_uInt16> & s2) const6549     bool operator()(const std::pair<OUString, sal_uInt16>& s1,
6550                     const std::pair<OUString, sal_uInt16>& s2) const
6551     {
6552         int nRet = s1.first.compareToIgnoreAsciiCase(s2.first);
6553         if (nRet == 0)
6554         {
6555             //fdo#61251 sort stuff that starts with the exact rOrigWord before
6556             //another ignore-case candidate
6557             int n1StartsWithOrig = s1.first.startsWith(m_rOrigWord) ? 0 : 1;
6558             int n2StartsWithOrig = s2.first.startsWith(m_rOrigWord) ? 0 : 1;
6559             return n1StartsWithOrig < n2StartsWithOrig;
6560         }
6561         return nRet < 0;
6562     }
6563 };
6564 
6565 struct EqualIgnoreCaseAscii
6566 {
operator ()__anon7cdd4f140311::EqualIgnoreCaseAscii6567     bool operator()(const std::pair<OUString, sal_uInt16>& s1,
6568                     const std::pair<OUString, sal_uInt16>& s2) const
6569     {
6570         return s1.first.equalsIgnoreAsciiCase(s2.first);
6571     }
6572 };
6573 
6574 } // anonymous namespace
6575 
6576 // TODO Implement an i18n aware sort
SortAndFilter(const OUString & rOrigWord)6577 void QuickHelpData::SortAndFilter(const OUString &rOrigWord)
6578 {
6579     std::sort( m_aHelpStrings.begin(),
6580                m_aHelpStrings.end(),
6581                CompareIgnoreCaseAsciiFavorExact(rOrigWord) );
6582 
6583     const auto& it
6584         = std::unique(m_aHelpStrings.begin(), m_aHelpStrings.end(), EqualIgnoreCaseAscii());
6585     m_aHelpStrings.erase( it, m_aHelpStrings.end() );
6586 
6587     nCurArrPos = 0;
6588 }
6589 
6590 // For a given chunk of typed text between 3 and 9 characters long that may start at a word boundary
6591 // or in a whitespace and may include whitespaces, SwEditShell::GetChunkForAutoTextcreates a list of
6592 // possible candidates for long AutoText names. Let's say, we have typed text "lorem ipsum  dr f";
6593 // and the cursor is right after the "f". SwEditShell::GetChunkForAutoText would take "  dr f",
6594 // since it's the longest chunk to the left of the cursor no longer than 9 characters, not starting
6595 // in the middle of a word. Then it would create this list from it (in this order, longest first):
6596 //     "  dr f"
6597 //      " dr f"
6598 //       "dr f"
6599 // It cannot add "r f", because it starts in the middle of the word "dr"; also it cannot give " f",
6600 // because it's only 2 characters long.
6601 // Now the result of SwEditShell::GetChunkForAutoText is passed here to SwEditWin::ShowAutoText, and
6602 // then to SwGlossaryList::HasLongName, where all existing autotext entries' long names are tested
6603 // if they start with one of the list elements. The matches are sorted according the position of the
6604 // candidate that matched first, then alphabetically inside the group of suggestions for a given
6605 // candidate. Say, if we have these AutoText entry long names:
6606 //    "Dr Frodo"
6607 //    "Dr Credo"
6608 //    "Or Bilbo"
6609 //    "dr foo"
6610 //    "  Dr Fuzz"
6611 //    " dr Faust"
6612 // the resulting list would be:
6613 //    "  Dr Fuzz" -> matches the first (longest) item in the candidates list
6614 //    " dr Faust" -> matches the second candidate item
6615 //    "Dr Foo" -> first item of the two matching the third candidate; alphabetically sorted
6616 //    "Dr Frodo" -> second item of the two matching the third candidate; alphabetically sorted
6617 // Each of the resulting suggestions knows the length of the candidate it replaces, so accepting the
6618 // first suggestion would replace 6 characters before cursor, while tabbing to and accepting the
6619 // last suggestion would replace only 4 characters to the left of cursor.
ShowAutoText(const std::vector<OUString> & rChunkCandidates)6620 bool SwEditWin::ShowAutoText(const std::vector<OUString>& rChunkCandidates)
6621 {
6622     s_pQuickHlpData->ClearContent();
6623     if (!rChunkCandidates.empty())
6624     {
6625         SwGlossaryList* pList = ::GetGlossaryList();
6626         pList->HasLongName(rChunkCandidates, s_pQuickHlpData->m_aHelpStrings);
6627     }
6628 
6629     if (!s_pQuickHlpData->m_aHelpStrings.empty())
6630     {
6631         s_pQuickHlpData->Start(m_rView.GetWrtShell(), true);
6632     }
6633     return !s_pQuickHlpData->m_aHelpStrings.empty();
6634 }
6635 
ShowAutoCorrectQuickHelp(const OUString & rWord,SvxAutoCorrect & rACorr)6636 void SwEditWin::ShowAutoCorrectQuickHelp(
6637         const OUString& rWord, SvxAutoCorrect& rACorr )
6638 {
6639     if (rWord.isEmpty())
6640         return;
6641     SwWrtShell& rSh = m_rView.GetWrtShell();
6642     s_pQuickHlpData->ClearContent();
6643 
6644     if( s_pQuickHlpData->m_aHelpStrings.empty() &&
6645         rACorr.GetSwFlags().bAutoCompleteWords )
6646     {
6647         s_pQuickHlpData->m_bIsAutoText = false;
6648         s_pQuickHlpData->m_bIsTip = rACorr.GetSwFlags().bAutoCmpltShowAsTip;
6649 
6650         // Get the necessary data to show help text.
6651         s_pQuickHlpData->FillStrArr( rSh, rWord );
6652     }
6653 
6654     if( !s_pQuickHlpData->m_aHelpStrings.empty() )
6655     {
6656         s_pQuickHlpData->SortAndFilter(rWord);
6657         s_pQuickHlpData->Start(rSh, true);
6658     }
6659 }
6660 
IsInHeaderFooter(const Point & rDocPt,FrameControlType & rControl) const6661 bool SwEditWin::IsInHeaderFooter( const Point &rDocPt, FrameControlType &rControl ) const
6662 {
6663     SwWrtShell &rSh = m_rView.GetWrtShell();
6664     const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( rDocPt );
6665 
6666     if ( pPageFrame && pPageFrame->IsOverHeaderFooterArea( rDocPt, rControl ) )
6667         return true;
6668 
6669     if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) || rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
6670     {
6671         SwFrameControlsManager &rMgr = rSh.GetView().GetEditWin().GetFrameControlsManager();
6672         Point aPoint( LogicToPixel( rDocPt ) );
6673 
6674         if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) )
6675         {
6676             SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Header, pPageFrame );
6677             if ( pControl && pControl->Contains( aPoint ) )
6678             {
6679                 rControl = FrameControlType::Header;
6680                 return true;
6681             }
6682         }
6683 
6684         if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
6685         {
6686             SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Footer, pPageFrame );
6687             if ( pControl && pControl->Contains( aPoint ) )
6688             {
6689                 rControl = FrameControlType::Footer;
6690                 return true;
6691             }
6692         }
6693     }
6694 
6695     return false;
6696 }
6697 
IsOverHeaderFooterFly(const Point & rDocPos,FrameControlType & rControl,bool & bOverFly,bool & bPageAnchored) const6698 bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly, bool& bPageAnchored ) const
6699 {
6700     bool bRet = false;
6701     Point aPt( rDocPos );
6702     SwWrtShell &rSh = m_rView.GetWrtShell();
6703     SwPaM aPam( *rSh.GetCurrentShellCursor().GetPoint() );
6704     rSh.GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aPt, nullptr, true );
6705 
6706     const SwStartNode* pStartFly = aPam.GetPoint()->GetNode().FindFlyStartNode();
6707     if ( pStartFly )
6708     {
6709         bOverFly = true;
6710         SwFrameFormat* pFlyFormat = pStartFly->GetFlyFormat( );
6711         if ( pFlyFormat )
6712         {
6713             const SwNode* pAnchorNode = pFlyFormat->GetAnchor( ).GetAnchorNode( );
6714             if ( pAnchorNode )
6715             {
6716                 bool bInHeader = pAnchorNode->FindHeaderStartNode( ) != nullptr;
6717                 bool bInFooter = pAnchorNode->FindFooterStartNode( ) != nullptr;
6718 
6719                 bRet = bInHeader || bInFooter;
6720                 if ( bInHeader )
6721                     rControl = FrameControlType::Header;
6722                 else if ( bInFooter )
6723                     rControl = FrameControlType::Footer;
6724             }
6725             else
6726                 bPageAnchored = pFlyFormat->GetAnchor( ).GetAnchorId( ) == RndStdIds::FLY_AT_PAGE;
6727         }
6728     }
6729     else
6730         bOverFly = false;
6731     return bRet;
6732 }
6733 
SetUseInputLanguage(bool bNew)6734 void SwEditWin::SetUseInputLanguage( bool bNew )
6735 {
6736     if ( bNew || m_bUseInputLanguage )
6737     {
6738         SfxBindings& rBind = GetView().GetViewFrame().GetBindings();
6739         rBind.Invalidate( SID_ATTR_CHAR_FONT );
6740         rBind.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
6741     }
6742     m_bUseInputLanguage = bNew;
6743 }
6744 
GetSurroundingText() const6745 OUString SwEditWin::GetSurroundingText() const
6746 {
6747     SwWrtShell& rSh = m_rView.GetWrtShell();
6748 
6749     if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6750         return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingText();
6751 
6752     OUString sReturn;
6753     if( rSh.HasSelection() && !rSh.IsMultiSelection() && rSh.IsSelOnePara() )
6754         rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
6755     else if( !rSh.HasSelection() )
6756     {
6757         bool bUnLockView = !rSh.IsViewLocked();
6758         rSh.LockView(true);
6759 
6760         // store shell state *before* Push
6761         ::std::optional<SwCallLink> aLink(std::in_place, rSh);
6762         rSh.Push();
6763 
6764         // disable accessible events for internal-only helper cursor
6765         const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6766         rSh.SetSendAccessibleCursorEvents(false);
6767 
6768         // get the sentence around the cursor
6769         rSh.HideCursor();
6770         rSh.GoStartSentence();
6771         rSh.SetMark();
6772         rSh.GoEndSentence();
6773         rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
6774 
6775         rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
6776         rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6777         rSh.HideCursor();
6778 
6779         if (bUnLockView)
6780             rSh.LockView(false);
6781     }
6782 
6783     return sReturn;
6784 }
6785 
GetSurroundingTextSelection() const6786 Selection SwEditWin::GetSurroundingTextSelection() const
6787 {
6788     SwWrtShell& rSh = m_rView.GetWrtShell();
6789 
6790     if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6791         return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingTextSelection();
6792 
6793     Selection aSel(0, 0);
6794     if( rSh.HasSelection() )
6795     {
6796         OUString sReturn;
6797         rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR  );
6798         aSel = Selection( 0, sReturn.getLength() );
6799     }
6800     else if (rSh.GetCursor()->GetPoint()->GetNode().GetTextNode())
6801     {
6802         bool bUnLockView = !rSh.IsViewLocked();
6803         rSh.LockView(true);
6804 
6805         // Return the position of the visible cursor in the sentence
6806         // around the visible cursor.
6807         TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
6808 
6809         // store shell state *before* Push
6810         ::std::optional<SwCallLink> aLink(std::in_place, rSh);
6811         rSh.Push();
6812 
6813         // disable accessible events for internal-only helper cursor
6814         const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6815         rSh.SetSendAccessibleCursorEvents(false);
6816 
6817         rSh.HideCursor();
6818         rSh.GoStartSentence();
6819         TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
6820 
6821         rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
6822         rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6823         rSh.ShowCursor();
6824 
6825         if (bUnLockView)
6826             rSh.LockView(false);
6827 
6828         aSel = Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
6829     }
6830 
6831     return aSel;
6832 }
6833 
DeleteSurroundingText(const Selection & rSelection)6834 bool SwEditWin::DeleteSurroundingText(const Selection& rSelection)
6835 {
6836     SwWrtShell& rSh = m_rView.GetWrtShell();
6837 
6838     if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6839         return rSh.GetDrawView()->GetTextEditOutlinerView()->DeleteSurroundingText(rSelection);
6840 
6841     if (rSh.HasSelection())
6842         return false;
6843 
6844     // rSelection is relative to the start of the sentence, so find that and
6845     // adjust the range by it
6846     rSh.Push();
6847 
6848     // disable accessible events for internal-only helper cursor
6849     const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6850     rSh.SetSendAccessibleCursorEvents(false);
6851 
6852     rSh.HideCursor();
6853     rSh.GoStartSentence();
6854     TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
6855 
6856     rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
6857     rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6858     rSh.ShowCursor();
6859 
6860     if (rSh.SelectTextView(nStartPos + TextFrameIndex(rSelection.Min()), nStartPos + TextFrameIndex(rSelection.Max())))
6861     {
6862         rSh.Delete(false);
6863         return true;
6864     }
6865 
6866     return false;
6867 }
6868 
LogicInvalidate(const tools::Rectangle * pRectangle)6869 void SwEditWin::LogicInvalidate(const tools::Rectangle* pRectangle)
6870 {
6871     SfxLokHelper::notifyInvalidation(&m_rView, pRectangle);
6872 }
6873 
SetCursorTwipPosition(const Point & rPosition,bool bPoint,bool bClearMark)6874 void SwEditWin::SetCursorTwipPosition(const Point& rPosition, bool bPoint, bool bClearMark)
6875 {
6876     if (SdrView* pSdrView = m_rView.GetWrtShell().GetDrawView())
6877     {
6878         // Editing shape text, then route the call to editeng.
6879         if (pSdrView->GetTextEditObject())
6880         {
6881             EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
6882             rEditView.SetCursorLogicPosition(rPosition, bPoint, bClearMark);
6883             return;
6884         }
6885     }
6886 
6887     if (m_rView.GetPostItMgr())
6888     {
6889         if (sw::annotation::SwAnnotationWin* pWin = m_rView.GetPostItMgr()->GetActiveSidebarWin())
6890         {
6891             // Editing postit text.
6892             pWin->SetCursorLogicPosition(rPosition, bPoint, bClearMark);
6893             return;
6894         }
6895     }
6896 
6897     // Not an SwWrtShell, as that would make SwCursorShell::GetCursor() inaccessible.
6898     SwEditShell& rShell = m_rView.GetWrtShell();
6899 
6900     bool bCreateSelection = false;
6901     {
6902         SwMvContext aMvContext(&rShell);
6903         if (bClearMark)
6904             rShell.ClearMark();
6905         else
6906             bCreateSelection = !rShell.HasMark();
6907 
6908         if (bCreateSelection)
6909             m_rView.GetWrtShell().SttSelect();
6910 
6911         // If the mark is to be updated, then exchange the point and mark before
6912         // and after, as we can't easily set the mark.
6913         if (!bPoint)
6914             rShell.getShellCursor(/*bBlock=*/false)->Exchange();
6915         rShell.SetCursor(rPosition);
6916         if (!bPoint)
6917             rShell.getShellCursor(/*bBlock=*/false)->Exchange();
6918     }
6919 
6920     if (bCreateSelection)
6921         m_rView.GetWrtShell().EndSelect();
6922 }
6923 
SetGraphicTwipPosition(bool bStart,const Point & rPosition)6924 void SwEditWin::SetGraphicTwipPosition(bool bStart, const Point& rPosition)
6925 {
6926     if (bStart)
6927     {
6928         MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
6929         MouseButtonDown(aClickEvent);
6930         MouseEvent aMoveEvent(Point(rPosition.getX() + MIN_MOVE + 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
6931         MouseMove(aMoveEvent);
6932     }
6933     else
6934     {
6935         MouseEvent aMoveEvent(Point(rPosition.getX() - MIN_MOVE - 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
6936         MouseMove(aMoveEvent);
6937         MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
6938         MouseButtonUp(aClickEvent);
6939     }
6940 }
6941 
GetFrameControlsManager()6942 SwFrameControlsManager& SwEditWin::GetFrameControlsManager()
6943 {
6944     return *m_pFrameControlsManager;
6945 }
6946 
ToggleOutlineContentVisibility(const size_t nOutlinePos,const bool bSubs)6947 void SwEditWin::ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs)
6948 {
6949     // bSubs purpose is to set all sub level outline content to the same visibility as
6950     // nOutlinePos outline content visibility is toggled. It is only applicable when not treating
6951     // sub outline levels as content.
6952     SwWrtShell& rSh = GetView().GetWrtShell();
6953 
6954     if (GetView().GetDrawView()->IsTextEdit())
6955         rSh.EndTextEdit();
6956     if (GetView().IsDrawMode())
6957         GetView().LeaveDrawCreate();
6958     rSh.EnterStdMode();
6959 
6960     if (!bSubs || rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
6961     {
6962         SwNode* pNode = rSh.GetNodes().GetOutLineNds()[nOutlinePos];
6963         bool bVisible = true;
6964         pNode->GetTextNode()->GetAttrOutlineContentVisible(bVisible);
6965         pNode->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
6966     }
6967     else if (bSubs)
6968     {
6969         // also toggle sub levels to the same content visibility
6970         SwOutlineNodes::size_type nPos = nOutlinePos;
6971         SwOutlineNodes::size_type nOutlineNodesCount
6972                 = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
6973         int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
6974         bool bVisible = rSh.IsOutlineContentVisible(nOutlinePos);
6975         do
6976         {
6977             if (rSh.IsOutlineContentVisible(nPos) == bVisible)
6978                 rSh.GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
6979         } while (++nPos < nOutlineNodesCount
6980                  && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
6981     }
6982 
6983     rSh.InvalidateOutlineContentVisibility();
6984     rSh.GotoOutline(nOutlinePos);
6985     rSh.SetModified();
6986     GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
6987 }
6988 
6989 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
6990