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