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