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