LibreOffice Module sw (master) 1
edtwin.cxx
Go to the documentation of this file.
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
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>
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>
68#include <unotools/datetime.hxx>
69
70#include <comphelper/lok.hxx>
71#include <sfx2/lokhelper.hxx>
72
73#include <editeng/acorrcfg.hxx>
74#include <bookmark.hxx>
75#include <SwSmartTagMgr.hxx>
76#include <edtdd.hxx>
77#include <edtwin.hxx>
78#include <view.hxx>
79#include <wrtsh.hxx>
81#include <IDocumentUndoRedo.hxx>
82#include <textboxhelper.hxx>
83#include <dcontact.hxx>
84#include <fldbas.hxx>
85#include <swmodule.hxx>
86#include <docsh.hxx>
87#include <viewopt.hxx>
88#include <drawbase.hxx>
89#include <dselect.hxx>
90#include <textsh.hxx>
91#include <shdwcrsr.hxx>
92#include <txatbase.hxx>
93#include <fmtanchr.hxx>
94#include <fmtornt.hxx>
95#include <fmthdft.hxx>
96#include <frmfmt.hxx>
97#include <modcfg.hxx>
98#include <fmtcol.hxx>
99#include <wview.hxx>
100#include <gloslst.hxx>
101#include <inputwin.hxx>
102#include <gloshdl.hxx>
103#include <swundo.hxx>
104#include <drwtxtsh.hxx>
105#include <fchrfmt.hxx>
106#include "romenu.hxx"
107#include <initui.hxx>
108#include <frmatr.hxx>
109#include <extinput.hxx>
110#include <acmplwrd.hxx>
111#include <swcalwrp.hxx>
112#include <swdtflvr.hxx>
113#include <breakit.hxx>
114#include <checkit.hxx>
115#include <pagefrm.hxx>
116
117#include <helpids.h>
118#include <cmdid.h>
119#include <uitool.hxx>
120#include <fmtfollowtextflow.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>
137#include <AnnotationWin.hxx>
138
139#include <algorithm>
140#include <vector>
141
142#include <rootfrm.hxx>
143
147#include <sfx2/event.hxx>
148#include <memory>
149
150#include "../../core/crsr/callnk.hxx"
152#include <ndtxt.hxx>
153#include <cntfrm.hxx>
154#include <txtfrm.hxx>
155#include <strings.hrc>
156#include <textcontentcontrol.hxx>
158
159using namespace sw::mark;
160using namespace ::com::sun::star;
161
165static bool g_bInputLanguageSwitched = false;
166
167// Usually in MouseButtonUp a selection is revoked when the selection is
168// not currently being pulled open. Unfortunately in MouseButtonDown there
169// is being selected at double/triple click. That selection is completely
170// finished in the Handler and thus can't be distinguished in the Up.
171// To resolve this g_bHoldSelection is set in Down and evaluated in Up.
172static bool g_bHoldSelection = false;
173
174bool g_bFrameDrag = false;
175static bool g_bValidCursorPos = false;
176bool g_bModePushed = false;
177bool g_bDDTimerStarted = false;
178bool g_bDDINetAttr = false;
179static SdrHdlKind g_eSdrMoveHdl = SdrHdlKind::User;
180
182
185
186static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView );
187
189static bool lcl_goIntoTextBox(SwEditWin& rEditWin, SwWrtShell& rSh)
190{
191 SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0);
192 if (!pMark)
193 return false;
194
195 SdrObject* pSdrObject = pMark->GetMarkedSdrObj();
196 SwFrameFormat* pObjectFormat = ::FindFrameFormat(pSdrObject);
197 if (SwFrameFormat* pTextBoxFormat = SwTextBoxHelper::getOtherTextBoxFormat(pObjectFormat, RES_DRAWFRMFMT))
198 {
199 SdrObject* pTextBox = pTextBoxFormat->FindRealSdrObject();
200 SdrView* pSdrView = rSh.GetDrawView();
201 // Unmark the shape.
202 pSdrView->UnmarkAllObj();
203 // Mark the textbox.
204 rSh.SelectObj(Point(), SW_ALLOW_TEXTBOX, pTextBox);
205 // Clear the DrawFuncPtr.
206 rEditWin.StopInsFrame();
207 return true;
208 }
209 return false;
210}
211
213{
218public:
219 explicit SwAnchorMarker( SdrHdl* pH )
220 : m_pHdl( pH )
221 , m_aHdlPos( pH->GetPos() )
222 , m_aLastPos( pH->GetPos() )
223 , m_bTopRightHandle( pH->GetKind() == SdrHdlKind::Anchor_TR )
224 {}
225 const Point& GetLastPos() const { return m_aLastPos; }
226 void SetLastPos( const Point& rNew ) { m_aLastPos = rNew; }
227 void SetPos( const Point& rNew ) { m_pHdl->SetPos( rNew ); }
228 const Point& GetHdlPos() const { return m_aHdlPos; }
229 SdrHdl* GetHdl() const { return m_pHdl; }
230 void ChgHdl( SdrHdl* pNew )
231 {
232 m_pHdl = pNew;
233 if ( m_pHdl )
234 {
235 m_bTopRightHandle = (m_pHdl->GetKind() == SdrHdlKind::Anchor_TR);
236 }
237 }
239 {
240 Point aHitTestPos( m_pHdl->GetPos() );
241 aHitTestPos = rOut.LogicToPixel( aHitTestPos );
242 if ( m_bTopRightHandle )
243 {
244 aHitTestPos += Point( -1, 1 );
245 }
246 else
247 {
248 aHitTestPos += Point( 1, 1 );
249 }
250 aHitTestPos = rOut.PixelToLogic( aHitTestPos );
251
252 return aHitTestPos;
253 }
254};
255
258{
260 std::vector<std::pair<OUString, sal_uInt16>> m_aHelpStrings;
262 sal_uInt16 nCurArrPos;
263 static constexpr sal_uInt16 nNoPos = std::numeric_limits<sal_uInt16>::max();
264
270 void* nTipId;
273
276
278
279 void Move( QuickHelpData& rCpy );
280 void ClearContent();
281 void Start(SwWrtShell& rSh, bool bRestart);
282 void Stop( SwWrtShell& rSh );
283
284 bool HasContent() const { return !m_aHelpStrings.empty() && nCurArrPos != nNoPos; }
285 const OUString& CurStr() const { return m_aHelpStrings[nCurArrPos].first; }
286 sal_uInt16 CurLen() const { return m_aHelpStrings[nCurArrPos].second; }
287
289 void Next( bool bEndLess )
290 {
291 if( ++nCurArrPos >= m_aHelpStrings.size() )
292 nCurArrPos = (bEndLess && !m_bIsAutoText ) ? 0 : nCurArrPos-1;
293 }
295 void Previous( bool bEndLess )
296 {
297 if( 0 == nCurArrPos-- )
298 nCurArrPos = (bEndLess && !m_bIsAutoText ) ? m_aHelpStrings.size()-1 : 0;
299 }
300
301 // Fills internal structures with hopefully helpful information.
302 void FillStrArr( SwWrtShell const & rSh, const OUString& rWord );
303 void SortAndFilter(const OUString &rOrigWord);
304};
305
309#define HIT_PIX 2 /* hit tolerance in pixel */
310#define MIN_MOVE 4
311
312static bool IsMinMove(const Point &rStartPos, const Point &rLPt)
313{
314 return std::abs(rStartPos.X() - rLPt.X()) > MIN_MOVE ||
315 std::abs(rStartPos.Y() - rLPt.Y()) > MIN_MOVE;
316}
317
324static bool IsDrawObjSelectable( const SwWrtShell& rSh, const Point& rPt )
325{
326 bool bRet = true;
327 SdrObject* pObj;
328 switch( rSh.GetObjCntType( rPt, pObj ))
329 {
330 case OBJCNT_NONE:
331 case OBJCNT_FLY:
332 case OBJCNT_GRF:
333 case OBJCNT_OLE:
334 bRet = false;
335 break;
336 default:; //prevent warning
337 }
338 return bRet;
339}
340
341/*
342 * Switch pointer
343 */
344void SwEditWin::UpdatePointer(const Point &rLPt, sal_uInt16 nModifier )
345{
346 SetQuickHelpText(OUString());
348 if( m_pApplyTempl )
349 {
350 PointerStyle eStyle = PointerStyle::Fill;
351 if ( rSh.IsOverReadOnlyPos( rLPt ) )
352 {
353 m_pUserMarker.reset();
354
355 eStyle = PointerStyle::NotAllowed;
356 }
357 else
358 {
359 SwRect aRect;
360 SwRect* pRect = &aRect;
361 const SwFrameFormat* pFormat = nullptr;
362
363 bool bFrameIsValidTarget = false;
364 if( m_pApplyTempl->m_pFormatClipboard )
365 bFrameIsValidTarget = m_pApplyTempl->m_pFormatClipboard->HasContentForThisType( SelectionType::Frame );
366 else if( !m_pApplyTempl->nColor )
367 bFrameIsValidTarget = ( m_pApplyTempl->eType == SfxStyleFamily::Frame );
368
369 if( bFrameIsValidTarget &&
370 nullptr !=(pFormat = rSh.GetFormatFromObj( rLPt, &pRect )) &&
371 dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
372 {
373 //turn on highlight for frame
374 tools::Rectangle aTmp( pRect->SVRect() );
375
376 if ( !m_pUserMarker )
377 {
378 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
379 }
380 }
381 else
382 {
383 m_pUserMarker.reset();
384 }
385
386 rSh.SwCursorShell::SetVisibleCursor( rLPt );
387 }
388 SetPointer( eStyle );
389 return;
390 }
391
392 if( !rSh.VisArea().Width() )
393 return;
394
395 CurrShell aCurr(&rSh);
396
397 if ( IsChainMode() )
398 {
399 SwRect aRect;
400 SwChainRet nChainable = rSh.Chainable( aRect, *rSh.GetFlyFrameFormat(), rLPt );
401 PointerStyle eStyle = nChainable != SwChainRet::OK
402 ? PointerStyle::ChainNotAllowed : PointerStyle::Chain;
403 if ( nChainable == SwChainRet::OK )
404 {
405 tools::Rectangle aTmp( aRect.SVRect() );
406
407 if ( !m_pUserMarker )
408 {
409 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
410 }
411 }
412 else
413 {
414 m_pUserMarker.reset();
415 }
416
417 SetPointer( eStyle );
418 return;
419 }
420
421 bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
422 if ( !bExecHyperlinks )
423 {
425 if ( ( bSecureOption && nModifier == KEY_MOD1 ) ||
426 ( !bSecureOption && nModifier != KEY_MOD1 ) )
427 bExecHyperlinks = true;
428 }
429
430 const bool bExecSmarttags = nModifier == KEY_MOD1;
431
432 SdrView *pSdrView = rSh.GetDrawView();
433 bool bPrefSdrPointer = false;
434 bool bHitHandle = false;
435 bool bCntAtPos = false;
436 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
437 rSh.IsCursorReadonly();
438 m_aActHitType = SdrHitKind::NONE;
439 PointerStyle eStyle = PointerStyle::Text;
440 if ( !pSdrView )
441 bCntAtPos = true;
442 else if ( (bHitHandle = (pSdrView->PickHandle(rLPt) != nullptr)) )
443 {
444 m_aActHitType = SdrHitKind::Object;
445 bPrefSdrPointer = true;
446 }
447 else
448 {
449 const bool bNotInSelObj = !rSh.IsInsideSelectedObj( rLPt );
450 if ( m_rView.GetDrawFuncPtr() && !m_bInsDraw && bNotInSelObj )
451 {
452 m_aActHitType = SdrHitKind::Object;
453 if (IsObjectSelect())
454 eStyle = PointerStyle::Arrow;
455 else
456 bPrefSdrPointer = true;
457 }
458 else
459 {
460 SdrPageView* pPV = nullptr;
461 pSdrView->SetHitTolerancePixel( HIT_PIX );
462 SdrObject* pObj = (bNotInSelObj && bExecHyperlinks) ?
463 pSdrView->PickObj(rLPt, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) :
464 nullptr;
465 if (pObj)
466 {
468 aTmp.aPos = rLPt;
469 aTmp.pPageView = pPV;
470 SetPointer( pObj->GetMacroPointer( aTmp ) );
471 return;
472 }
473 else
474 {
475 // dvo: IsObjSelectable() eventually calls SdrView::PickObj, so
476 // apparently this is used to determine whether this is a
477 // drawling layer object or not.
478 if ( rSh.IsObjSelectable( rLPt ) )
479 {
480 if (pSdrView->IsTextEdit())
481 {
482 m_aActHitType = SdrHitKind::NONE;
483 bPrefSdrPointer = true;
484 }
485 else
486 {
487 SdrViewEvent aVEvt;
488 SdrHitKind eHit = pSdrView->PickAnything(rLPt, aVEvt);
489
490 if (eHit == SdrHitKind::UrlField && bExecHyperlinks)
491 {
492 m_aActHitType = SdrHitKind::Object;
493 bPrefSdrPointer = true;
494 }
495 else
496 {
497 // if we're over a selected object, we show an
498 // ARROW by default. We only show a MOVE if 1) the
499 // object is selected, and 2) it may be moved
500 // (i.e., position is not protected).
501 bool bMovable =
502 (!bNotInSelObj) &&
503 (rSh.IsObjSelected() || rSh.IsFrameSelected()) &&
505
506 SdrObject* pSelectableObj = rSh.GetObjAt(rLPt);
507 // Don't update pointer if this is a background image only.
508 if (pSelectableObj->GetLayer() != rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId())
509 eStyle = bMovable ? PointerStyle::Move : PointerStyle::Arrow;
510 m_aActHitType = SdrHitKind::Object;
511 }
512 }
513 }
514 else
515 {
516 if ( rSh.IsFrameSelected() && !bNotInSelObj )
517 {
518 // dvo: this branch appears to be dead and should be
519 // removed in a future version. Reason: The condition
520 // !bNotInSelObj means that this branch will only be
521 // executed in the cursor points inside a selected
522 // object. However, if this is the case, the previous
523 // if( rSh.IsObjSelectable(rLPt) ) must always be true:
524 // rLPt is inside a selected object, then obviously
525 // rLPt is over a selectable object.
527 eStyle = PointerStyle::NotAllowed;
528 else
529 eStyle = PointerStyle::Move;
530 m_aActHitType = SdrHitKind::Object;
531 }
532 else
533 {
534 if ( m_rView.GetDrawFuncPtr() )
535 bPrefSdrPointer = true;
536 else
537 bCntAtPos = true;
538 }
539 }
540 }
541 }
542 }
543 if ( bPrefSdrPointer )
544 {
545 if (bIsDocReadOnly || (rSh.IsObjSelected() && rSh.IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE))
546 SetPointer( PointerStyle::NotAllowed );
547 else
548 {
549 if (m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->IsInsertForm() && !bHitHandle)
550 SetPointer( PointerStyle::DrawRect );
551 else
552 SetPointer( pSdrView->GetPreferredPointer( rLPt, rSh.GetOut() ) );
553 }
554 }
555 else
556 {
557 if( !rSh.IsPageAtPos( rLPt ) || m_pAnchorMarker )
558 eStyle = PointerStyle::Arrow;
559 else
560 {
561 // Even if we already have something, prefer URLs if possible.
563 if (bCntAtPos || rSh.GetContentAtPos(rLPt, aUrlPos))
564 {
565 SwContentAtPos aSwContentAtPos(
571 if( rSh.GetContentAtPos( rLPt, aSwContentAtPos) )
572 {
573 // Is edit inline input field
574 if (IsAttrAtPos::Field == aSwContentAtPos.eContentAtPos
575 && aSwContentAtPos.pFndTextAttr != nullptr
576 && aSwContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD)
577 {
578 const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
579 if (!(pCursorField && pCursorField == aSwContentAtPos.pFndTextAttr->GetFormatField().GetField()))
580 eStyle = PointerStyle::RefHand;
581 }
582 else
583 {
584 const bool bClickToFollow = IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos ||
585 IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos;
586 if( !bClickToFollow ||
587 (IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos && bExecHyperlinks) ||
588 (IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos && bExecSmarttags) )
589 eStyle = PointerStyle::RefHand;
590 }
591 }
592 else if (GetView().GetWrtShell().GetViewOptions()->IsShowOutlineContentVisibilityButton())
593 {
594 aSwContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
595 if (rSh.GetContentAtPos(rLPt, aSwContentAtPos))
596 {
597 if (IsAttrAtPos::Outline == aSwContentAtPos.eContentAtPos)
598 {
599 if (nModifier == KEY_MOD1)
600 {
601 eStyle = PointerStyle::RefHand;
602 // set quick help
603 if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
604 {
605 const SwNodes& rNds = GetView().GetWrtShell().GetDoc()->GetNodes();
607 rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos);
608 SwOutlineNodes::size_type nOutlineNodesCount
611 OUString sQuickHelp(SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY));
613 && nPos + 1 < nOutlineNodesCount
615 sQuickHelp += " (" + SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
616 SetQuickHelpText(sQuickHelp);
617 }
618 }
619 }
620 }
621 }
622 }
623 }
624
625 // which kind of text pointer have we to show - horz / vert - ?
626 if( PointerStyle::Text == eStyle && rSh.IsInVerticalText( &rLPt ))
627 eStyle = PointerStyle::TextVertical;
628 else if (rSh.GetViewOptions()->CanHideWhitespace() &&
629 rSh.GetLayout()->IsBetweenPages(rLPt))
630 {
632 eStyle = PointerStyle::ShowWhitespace;
633 else
634 eStyle = PointerStyle::HideWhitespace;
635 }
636
637 SetPointer( eStyle );
638 }
639}
640
644IMPL_LINK_NOARG(SwEditWin, TimerHandler, Timer *, void)
645{
646 SwWrtShell &rSh = m_rView.GetWrtShell();
647 Point aModPt( m_aMovePos );
648 const SwRect aOldVis( rSh.VisArea() );
649 bool bDone = false;
650
651 if ( !rSh.VisArea().Contains( aModPt ) )
652 {
653 if ( m_bInsDraw )
654 {
655 const int nMaxScroll = 40;
656 m_rView.Scroll( tools::Rectangle(aModPt,Size(1,1)), nMaxScroll, nMaxScroll);
657 bDone = true;
658 }
659 else if ( g_bFrameDrag )
660 {
661 rSh.Drag(&aModPt, false);
662 bDone = true;
663 }
664 if ( !bDone )
665 aModPt = rSh.GetContentPos( aModPt,aModPt.Y() > rSh.VisArea().Bottom() );
666 }
667 if ( !bDone && !(g_bFrameDrag || m_bInsDraw) )
668 {
669 if ( m_xRowColumnSelectionStart )
670 {
671 Point aPos( aModPt );
672 rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag );
673 }
674 else
675 rSh.CallSetCursor( &aModPt, false );
676
677 // It can be that a "jump" over a table cannot be accomplished like
678 // that. So we jump over the table by Up/Down here.
679 const SwRect& rVisArea = rSh.VisArea();
680 if( aOldVis == rVisArea && !rSh.IsStartOfDoc() && !rSh.IsEndOfDoc() )
681 {
682 // take the center point of VisArea to
683 // decide in which direction the user want.
684 if( aModPt.Y() < ( rVisArea.Top() + rVisArea.Height() / 2 ) )
685 rSh.Up( true );
686 else
687 rSh.Down( true );
688 }
689 }
690
691 m_aMovePos += rSh.VisArea().Pos() - aOldVis.Pos();
692 JustifyAreaTimer();
693}
694
696{
697 const tools::Rectangle &rVisArea = GetView().GetVisArea();
698#ifdef UNX
699 const tools::Long coMinLen = 100;
700#else
701 const tools::Long coMinLen = 50;
702#endif
703 tools::Long const nTimeout = 800,
704 nDiff = std::max(
705 std::max( m_aMovePos.Y() - rVisArea.Bottom(), rVisArea.Top() - m_aMovePos.Y() ),
706 std::max( m_aMovePos.X() - rVisArea.Right(), rVisArea.Left() - m_aMovePos.X()));
707 m_aTimer.SetTimeout( std::max( coMinLen, nTimeout - nDiff*2L) );
708}
709
710void SwEditWin::LeaveArea(const Point &rPos)
711{
712 m_aMovePos = rPos;
714 if( !m_aTimer.IsActive() )
715 m_aTimer.Start();
716 m_pShadCursor.reset();
717}
718
720{
721 m_aTimer.Stop();
722}
723
727void SwEditWin::InsFrame(sal_uInt16 nCols)
728{
729 StdDrawMode( SdrObjKind::NONE, false );
730 m_bInsFrame = true;
731 m_nInsFrameColCount = nCols;
732}
733
734void SwEditWin::StdDrawMode( SdrObjKind eSdrObjectKind, bool bObjSelect )
735{
736 SetSdrDrawMode( eSdrObjectKind );
737
738 if (bObjSelect)
739 m_rView.SetDrawFuncPtr(std::make_unique<DrawSelection>( &m_rView.GetWrtShell(), this, &m_rView ));
740 else
741 m_rView.SetDrawFuncPtr(std::make_unique<SwDrawBase>( &m_rView.GetWrtShell(), this, &m_rView ));
742
744 SetSdrDrawMode( eSdrObjectKind );
745 if (bObjSelect)
746 m_rView.GetDrawFuncPtr()->Activate( SID_OBJECT_SELECT );
747 else
748 m_rView.GetDrawFuncPtr()->Activate( sal::static_int_cast< sal_uInt16 >(eSdrObjectKind) );
749 m_bInsFrame = false;
751}
752
754{
756 {
758 m_rView.SetDrawFuncPtr(nullptr);
759 }
760 m_rView.LeaveDrawCreate(); // leave construction mode
761 m_bInsFrame = false;
763}
764
765bool SwEditWin::IsInputSequenceCheckingRequired( const OUString &rText, const SwPaM& rCursor )
766{
767 const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
768 if ( !rCTLOptions.IsCTLFontEnabled() ||
769 !rCTLOptions.IsCTLSequenceChecking() )
770 return false;
771
772 if ( 0 == rCursor.Start()->GetContentIndex() ) /* first char needs not to be checked */
773 return false;
774
775 SwBreakIt *pBreakIter = SwBreakIt::Get();
776 uno::Reference < i18n::XBreakIterator > xBI = pBreakIter->GetBreakIter();
777 assert(xBI.is());
778 tools::Long nCTLScriptPos = -1;
779
780 if (xBI->getScriptType( rText, 0 ) == i18n::ScriptType::COMPLEX)
781 nCTLScriptPos = 0;
782 else
783 nCTLScriptPos = xBI->nextScript( rText, 0, i18n::ScriptType::COMPLEX );
784
785 return (0 <= nCTLScriptPos && nCTLScriptPos <= rText.getLength());
786}
787
788//return INVALID_HINT if language should not be explicitly overridden, the correct
789//HintId to use for the eBufferLanguage otherwise
790static sal_uInt16 lcl_isNonDefaultLanguage(LanguageType eBufferLanguage, SwView const & rView,
791 const OUString &rInBuffer)
792{
793 sal_uInt16 nWhich = INVALID_HINT;
794
795 //If the option to IgnoreLanguageChange is set, short-circuit this method
796 //which results in the document/paragraph language remaining the same
797 //despite a change to the keyboard/input language
798 SvtSysLocaleOptions aSysLocaleOptions;
799 if(aSysLocaleOptions.IsIgnoreLanguageChange())
800 {
801 return INVALID_HINT;
802 }
803
804 bool bLang = true;
805 if(eBufferLanguage != LANGUAGE_DONTKNOW)
806 {
807 switch( SvtLanguageOptions::GetI18NScriptTypeOfLanguage( eBufferLanguage ))
808 {
809 case i18n::ScriptType::ASIAN: nWhich = RES_CHRATR_CJK_LANGUAGE; break;
810 case i18n::ScriptType::COMPLEX: nWhich = RES_CHRATR_CTL_LANGUAGE; break;
811 case i18n::ScriptType::LATIN: nWhich = RES_CHRATR_LANGUAGE; break;
812 default: bLang = false;
813 }
814 if(bLang)
815 {
816 SfxItemSet aLangSet(rView.GetPool(), nWhich, nWhich);
817 SwWrtShell& rSh = rView.GetWrtShell();
818 rSh.GetCurAttr(aLangSet);
819 if(SfxItemState::DEFAULT <= aLangSet.GetItemState(nWhich))
820 {
821 LanguageType eLang = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage();
822 if ( eLang == eBufferLanguage )
823 {
824 // current language attribute equal to language reported from system
825 bLang = false;
826 }
827 else if ( !g_bInputLanguageSwitched && RES_CHRATR_LANGUAGE == nWhich )
828 {
829 // special case: switching between two "LATIN" languages
830 // In case the current keyboard setting might be suitable
831 // for both languages we can't safely assume that the user
832 // wants to use the language reported from the system,
833 // except if we knew that it was explicitly switched (thus
834 // the check for "bInputLangeSwitched").
835
836 // The language reported by the system could be just the
837 // system default language that the user is not even aware
838 // of, because no language selection tool is installed at
839 // all. In this case the OOo language should get preference
840 // as it might have been selected by the user explicitly.
841
842 // Usually this case happens if the OOo language is
843 // different to the system language but the system keyboard
844 // is still suitable for the OOo language (e.g. writing
845 // English texts with a German keyboard).
846
847 // For non-latin keyboards overwriting the attribute is
848 // still valid. We do this for cyrillic and greek ATM. In
849 // future versions of OOo this should be replaced by a
850 // configuration switch that allows to give the preference
851 // to the OOo setting or the system setting explicitly
852 // and/or a better handling of the script type.
853 i18n::UnicodeScript eType = !rInBuffer.isEmpty() ?
854 GetAppCharClass().getScript( rInBuffer, 0 ) :
855 i18n::UnicodeScript_kScriptCount;
856
857 bool bSystemIsNonLatin = false;
858 switch ( eType )
859 {
860 case i18n::UnicodeScript_kGreek:
861 case i18n::UnicodeScript_kCyrillic:
862 // in case other UnicodeScripts require special
863 // keyboards they can be added here
864 bSystemIsNonLatin = true;
865 break;
866 default:
867 break;
868 }
869
870 bool bOOoLangIsNonLatin = MsLangId::isNonLatinWestern( eLang);
871
872 bLang = (bSystemIsNonLatin != bOOoLangIsNonLatin);
873 }
874 }
875 }
876 }
877 return bLang ? nWhich : INVALID_HINT;
878}
879
884{
887
888 if ( m_aInBuffer.isEmpty() )
889 return;
890
892
893 // generate new sequence input checker if not already done
894 if ( !pCheckIt )
895 pCheckIt = new SwCheckIt;
896
897 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = pCheckIt->xCheck;
898 if ( xISC.is() && IsInputSequenceCheckingRequired( m_aInBuffer, *rSh.GetCursor() ) )
899 {
900
901 // apply (Thai) input sequence checking/correction
902
903 rSh.Push(); // push current cursor to stack
904
905 // get text from the beginning (i.e left side) of current selection
906 // to the start of the paragraph
907 rSh.NormalizePam(); // make point be the first (left) one
908 if (!rSh.GetCursor()->HasMark())
909 rSh.GetCursor()->SetMark();
910 rSh.GetCursor()->GetMark()->SetContent(0);
911
912 const OUString aOldText( rSh.GetCursor()->GetText() );
913 const sal_Int32 nOldLen = aOldText.getLength();
914
915 SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
916
917 sal_Int32 nExpandSelection = 0;
918 if (nOldLen > 0)
919 {
920 sal_Int32 nTmpPos = nOldLen;
921 sal_Int16 nCheckMode = rCTLOptions.IsCTLSequenceCheckingRestricted() ?
922 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
923
924 OUString aNewText( aOldText );
925 if (rCTLOptions.IsCTLSequenceCheckingTypeAndReplace())
926 {
927 for( sal_Int32 k = 0; k < m_aInBuffer.getLength(); ++k)
928 {
929 const sal_Unicode cChar = m_aInBuffer[k];
930 const sal_Int32 nPrevPos =xISC->correctInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode );
931
932 // valid sequence or sequence could be corrected:
933 if (nPrevPos != aNewText.getLength())
934 nTmpPos = nPrevPos + 1;
935 }
936
937 // find position of first character that has changed
938 sal_Int32 nNewLen = aNewText.getLength();
939 const sal_Unicode *pOldText = aOldText.getStr();
940 const sal_Unicode *pNewText = aNewText.getStr();
941 sal_Int32 nChgPos = 0;
942 while ( nChgPos < nOldLen && nChgPos < nNewLen &&
943 pOldText[nChgPos] == pNewText[nChgPos] )
944 ++nChgPos;
945
946 const sal_Int32 nChgLen = nNewLen - nChgPos;
947 if (nChgLen)
948 {
949 m_aInBuffer = aNewText.copy( nChgPos, nChgLen );
950 nExpandSelection = nOldLen - nChgPos;
951 }
952 else
953 m_aInBuffer.clear();
954 }
955 else
956 {
957 for( sal_Int32 k = 0; k < m_aInBuffer.getLength(); ++k )
958 {
959 const sal_Unicode cChar = m_aInBuffer[k];
960 if (xISC->checkInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode ))
961 {
962 // character can be inserted:
963 aNewText += OUStringChar( cChar );
964 ++nTmpPos;
965 }
966 }
967 m_aInBuffer = aNewText.copy( aOldText.getLength() ); // copy new text to be inserted to buffer
968 }
969 }
970
971 // at this point now we will insert the buffer text 'normally' some lines below...
972
974
975 if (m_aInBuffer.isEmpty())
976 return;
977
978 // if text prior to the original selection needs to be changed
979 // as well, we now expand the selection accordingly.
980 SwPaM &rCursor = *rSh.GetCursor();
981 const sal_Int32 nCursorStartPos = rCursor.Start()->GetContentIndex();
982 OSL_ENSURE( nCursorStartPos >= nExpandSelection, "cannot expand selection as specified!!" );
983 if (nExpandSelection && nCursorStartPos >= nExpandSelection)
984 {
985 if (!rCursor.HasMark())
986 rCursor.SetMark();
987 rCursor.Start()->AdjustContent( -nExpandSelection );
988 }
989 }
990
991 uno::Reference< frame::XDispatchRecorder > xRecorder =
993 if ( xRecorder.is() )
994 {
995 // determine shell
997 // generate request and record
998 if (pSfxShell)
999 {
1002 aReq.Done();
1003 }
1004 }
1005
1007 if (nWhich != INVALID_HINT )
1008 {
1009 SvxLanguageItem aLangItem( m_eBufferLanguage, nWhich );
1010 rSh.SetAttrItem( aLangItem );
1011 }
1012
1013 rSh.Insert( m_aInBuffer );
1015 m_aInBuffer.clear();
1016}
1017
1018#define MOVE_LEFT_SMALL 0
1019#define MOVE_UP_SMALL 1
1020#define MOVE_RIGHT_BIG 2
1021#define MOVE_DOWN_BIG 3
1022#define MOVE_LEFT_BIG 4
1023#define MOVE_UP_BIG 5
1024#define MOVE_RIGHT_SMALL 6
1025#define MOVE_DOWN_SMALL 7
1026
1027// #i121236# Support for shift key in writer
1028#define MOVE_LEFT_HUGE 8
1029#define MOVE_UP_HUGE 9
1030#define MOVE_RIGHT_HUGE 10
1031#define MOVE_DOWN_HUGE 11
1032
1033void SwEditWin::ChangeFly( sal_uInt8 nDir, bool bWeb )
1034{
1036 SwRect aTmp = rSh.GetFlyRect();
1037 if( !aTmp.HasArea() ||
1039 return;
1040
1047 aSet( rSh.GetAttrPool() );
1048 rSh.GetFlyFrameAttr( aSet );
1049 RndStdIds eAnchorId = aSet.Get(RES_ANCHOR).GetAnchorId();
1050 Size aSnap;
1051 bool bHuge(MOVE_LEFT_HUGE == nDir ||
1052 MOVE_UP_HUGE == nDir ||
1053 MOVE_RIGHT_HUGE == nDir ||
1054 MOVE_DOWN_HUGE == nDir);
1055
1056 if(MOVE_LEFT_SMALL == nDir ||
1057 MOVE_UP_SMALL == nDir ||
1058 MOVE_RIGHT_SMALL == nDir ||
1059 MOVE_DOWN_SMALL == nDir )
1060 {
1061 aSnap = PixelToLogic(Size(1,1));
1062 }
1063 else
1064 {
1065 aSnap = rSh.GetViewOptions()->GetSnapSize();
1066 short nDiv = rSh.GetViewOptions()->GetDivisionX();
1067 if ( nDiv > 0 )
1068 aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1069 nDiv = rSh.GetViewOptions()->GetDivisionY();
1070 if ( nDiv > 0 )
1071 aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1072 }
1073
1074 if(bHuge)
1075 {
1076 // #i121236# 567twips == 1cm, but just take three times the normal snap
1077 aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1078 }
1079
1080 SwRect aBoundRect;
1081 Point aRefPoint;
1082 // adjustment for allowing vertical position
1083 // aligned to page for fly frame anchored to paragraph or to character.
1084 {
1085 const SwFormatVertOrient& aVert( aSet.Get(RES_VERT_ORIENT) );
1086 const bool bFollowTextFlow =
1087 aSet.Get(RES_FOLLOW_TEXT_FLOW).GetValue();
1088 const SwFormatAnchor& rFormatAnchor = aSet.Get(RES_ANCHOR);
1089 rSh.CalcBoundRect( aBoundRect, eAnchorId,
1090 text::RelOrientation::FRAME, aVert.GetRelationOrient(),
1091 &rFormatAnchor, bFollowTextFlow,
1092 false, &aRefPoint );
1093 }
1094 tools::Long nLeft = std::min( aTmp.Left() - aBoundRect.Left(), aSnap.Width() );
1095 tools::Long nRight = std::min( aBoundRect.Right() - aTmp.Right(), aSnap.Width() );
1096 tools::Long nUp = std::min( aTmp.Top() - aBoundRect.Top(), aSnap.Height() );
1097 tools::Long nDown = std::min( aBoundRect.Bottom() - aTmp.Bottom(), aSnap.Height() );
1098
1099 switch ( nDir )
1100 {
1101 case MOVE_LEFT_BIG:
1102 case MOVE_LEFT_HUGE:
1103 case MOVE_LEFT_SMALL: aTmp.Left( aTmp.Left() - nLeft );
1104 break;
1105
1106 case MOVE_UP_BIG:
1107 case MOVE_UP_HUGE:
1108 case MOVE_UP_SMALL: aTmp.Top( aTmp.Top() - nUp );
1109 break;
1110
1111 case MOVE_RIGHT_SMALL:
1112 if( aTmp.Width() < aSnap.Width() + MINFLY )
1113 break;
1114 nRight = aSnap.Width();
1115 [[fallthrough]];
1116 case MOVE_RIGHT_HUGE:
1117 case MOVE_RIGHT_BIG: aTmp.Left( aTmp.Left() + nRight );
1118 break;
1119
1120 case MOVE_DOWN_SMALL:
1121 if( aTmp.Height() < aSnap.Height() + MINFLY )
1122 break;
1123 nDown = aSnap.Height();
1124 [[fallthrough]];
1125 case MOVE_DOWN_HUGE:
1126 case MOVE_DOWN_BIG: aTmp.Top( aTmp.Top() + nDown );
1127 break;
1128
1129 default: OSL_ENSURE(true, "ChangeFly: Unknown direction." );
1130 }
1131 bool bSet = false;
1132 if ((RndStdIds::FLY_AS_CHAR == eAnchorId) && ( nDir % 2 ))
1133 {
1134 tools::Long aDiff = aTmp.Top() - aRefPoint.Y();
1135 if( aDiff > 0 )
1136 aDiff = 0;
1137 else if ( aDiff < -aTmp.Height() )
1138 aDiff = -aTmp.Height();
1139 SwFormatVertOrient aVert( aSet.Get(RES_VERT_ORIENT) );
1140 sal_Int16 eNew;
1141 if( bWeb )
1142 {
1143 eNew = aVert.GetVertOrient();
1144 bool bDown = 0 != ( nDir & 0x02 );
1145 switch( eNew )
1146 {
1147 case text::VertOrientation::CHAR_TOP:
1148 if( bDown ) eNew = text::VertOrientation::CENTER;
1149 break;
1150 case text::VertOrientation::CENTER:
1151 eNew = bDown ? text::VertOrientation::TOP : text::VertOrientation::CHAR_TOP;
1152 break;
1153 case text::VertOrientation::TOP:
1154 if( !bDown ) eNew = text::VertOrientation::CENTER;
1155 break;
1156 case text::VertOrientation::LINE_TOP:
1157 if( bDown ) eNew = text::VertOrientation::LINE_CENTER;
1158 break;
1159 case text::VertOrientation::LINE_CENTER:
1160 eNew = bDown ? text::VertOrientation::LINE_BOTTOM : text::VertOrientation::LINE_TOP;
1161 break;
1162 case text::VertOrientation::LINE_BOTTOM:
1163 if( !bDown ) eNew = text::VertOrientation::LINE_CENTER;
1164 break;
1165 default:; //prevent warning
1166 }
1167 }
1168 else
1169 {
1170 aVert.SetPos( aDiff );
1172 }
1173 aVert.SetVertOrient( eNew );
1174 aSet.Put( aVert );
1175 bSet = true;
1176 }
1177 if (bWeb && (RndStdIds::FLY_AT_PARA == eAnchorId)
1178 && ( nDir==MOVE_LEFT_SMALL || nDir==MOVE_RIGHT_BIG ))
1179 {
1180 SwFormatHoriOrient aHori( aSet.Get(RES_HORI_ORIENT) );
1181 sal_Int16 eNew;
1182 eNew = aHori.GetHoriOrient();
1183 switch( eNew )
1184 {
1185 case text::HoriOrientation::RIGHT:
1186 if( nDir==MOVE_LEFT_SMALL )
1187 eNew = text::HoriOrientation::LEFT;
1188 break;
1189 case text::HoriOrientation::LEFT:
1190 if( nDir==MOVE_RIGHT_BIG )
1191 eNew = text::HoriOrientation::RIGHT;
1192 break;
1193 default:; //prevent warning
1194 }
1195 if( eNew != aHori.GetHoriOrient() )
1196 {
1197 aHori.SetHoriOrient( eNew );
1198 aSet.Put( aHori );
1199 bSet = true;
1200 }
1201 }
1202 rSh.StartAllAction();
1203 if( bSet )
1204 rSh.SetFlyFrameAttr( aSet );
1205 bool bSetPos = (RndStdIds::FLY_AS_CHAR != eAnchorId);
1206 if(bSetPos && bWeb)
1207 {
1208 bSetPos = RndStdIds::FLY_AT_PAGE == eAnchorId;
1209 }
1210 if( bSetPos )
1211 rSh.SetFlyPos( aTmp.Pos() );
1212 rSh.EndAllAction();
1213
1214}
1215
1217{
1218 // start undo action in order to get only one
1219 // undo action for this change.
1221 rSh.StartUndo();
1222
1223 tools::Long nX = 0;
1224 tools::Long nY = 0;
1225 const bool bOnePixel(
1226 MOVE_LEFT_SMALL == nDir ||
1227 MOVE_UP_SMALL == nDir ||
1228 MOVE_RIGHT_SMALL == nDir ||
1229 MOVE_DOWN_SMALL == nDir);
1230 const bool bHuge(
1231 MOVE_LEFT_HUGE == nDir ||
1232 MOVE_UP_HUGE == nDir ||
1233 MOVE_RIGHT_HUGE == nDir ||
1234 MOVE_DOWN_HUGE == nDir);
1235 SwMove nAnchorDir = SwMove::UP;
1236 switch(nDir)
1237 {
1238 case MOVE_LEFT_SMALL:
1239 case MOVE_LEFT_HUGE:
1240 case MOVE_LEFT_BIG:
1241 nX = -1;
1242 nAnchorDir = SwMove::LEFT;
1243 break;
1244 case MOVE_UP_SMALL:
1245 case MOVE_UP_HUGE:
1246 case MOVE_UP_BIG:
1247 nY = -1;
1248 break;
1249 case MOVE_RIGHT_SMALL:
1250 case MOVE_RIGHT_HUGE:
1251 case MOVE_RIGHT_BIG:
1252 nX = +1;
1253 nAnchorDir = SwMove::RIGHT;
1254 break;
1255 case MOVE_DOWN_SMALL:
1256 case MOVE_DOWN_HUGE:
1257 case MOVE_DOWN_BIG:
1258 nY = +1;
1259 nAnchorDir = SwMove::DOWN;
1260 break;
1261 }
1262
1263 if(0 != nX || 0 != nY)
1264 {
1266 Size aSnap( rSh.GetViewOptions()->GetSnapSize() );
1267 short nDiv = rSh.GetViewOptions()->GetDivisionX();
1268 if ( nDiv > 0 )
1269 aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1270 nDiv = rSh.GetViewOptions()->GetDivisionY();
1271 if ( nDiv > 0 )
1272 aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1273
1274 if(bOnePixel)
1275 {
1276 aSnap = PixelToLogic(Size(1,1));
1277 }
1278 else if(bHuge)
1279 {
1280 // #i121236# 567twips == 1cm, but just take three times the normal snap
1281 aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1282 }
1283
1284 nX *= aSnap.Width();
1285 nY *= aSnap.Height();
1286
1287 SdrView *pSdrView = rSh.GetDrawView();
1288 const SdrHdlList& rHdlList = pSdrView->GetHdlList();
1289 SdrHdl* pHdl = rHdlList.GetFocusHdl();
1290 rSh.StartAllAction();
1291 if(nullptr == pHdl)
1292 {
1293 // now move the selected draw objects
1294 // if the object's position is not protected
1295 if(!(nProtect&FlyProtectFlags::Pos))
1296 {
1297 // Check if object is anchored as character and move direction
1298 bool bDummy1, bDummy2;
1299 const bool bVertAnchor = rSh.IsFrameVertical( true, bDummy1, bDummy2 );
1300 bool bHoriMove = !bVertAnchor == !( nDir % 2 );
1301 bool bMoveAllowed =
1302 !bHoriMove || (rSh.GetAnchorId() != RndStdIds::FLY_AS_CHAR);
1303 if ( bMoveAllowed )
1304 {
1305 pSdrView->MoveAllMarked(Size(nX, nY));
1306 rSh.SetModified();
1307 }
1308 }
1309 }
1310 else
1311 {
1312 // move handle with index nHandleIndex
1313 if (nX || nY)
1314 {
1315 if( SdrHdlKind::Anchor == pHdl->GetKind() ||
1316 SdrHdlKind::Anchor_TR == pHdl->GetKind() )
1317 {
1318 // anchor move cannot be allowed when position is protected
1319 if(!(nProtect&FlyProtectFlags::Pos))
1320 rSh.MoveAnchor( nAnchorDir );
1321 }
1322 //now resize if size is protected
1323 else if(!(nProtect&FlyProtectFlags::Size))
1324 {
1325 // now move the Handle (nX, nY)
1326 Point aStartPoint(pHdl->GetPos());
1327 Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
1328 const SdrDragStat& rDragStat = pSdrView->GetDragStat();
1329
1330 // start dragging
1331 pSdrView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
1332
1333 if(pSdrView->IsDragObj())
1334 {
1335 bool bWasNoSnap = rDragStat.IsNoSnap();
1336 bool bWasSnapEnabled = pSdrView->IsSnapEnabled();
1337
1338 // switch snapping off
1339 if(!bWasNoSnap)
1340 const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
1341 if(bWasSnapEnabled)
1342 pSdrView->SetSnapEnabled(false);
1343
1344 pSdrView->MovAction(aEndPoint);
1345 pSdrView->EndDragObj();
1346 rSh.SetModified();
1347
1348 // restore snap
1349 if(!bWasNoSnap)
1350 const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
1351 if(bWasSnapEnabled)
1352 pSdrView->SetSnapEnabled(bWasSnapEnabled);
1353 }
1354 }
1355 }
1356 }
1357 rSh.EndAllAction();
1358 }
1359
1360 rSh.EndUndo();
1361}
1362
1367{
1369
1371 {
1373 {
1374 pWindow->KeyInput(rKEvt);
1375 return;
1376 }
1377 }
1378
1379 if( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE &&
1380 m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard )
1381 {
1382 m_pApplyTempl->m_pFormatClipboard->Erase();
1384 m_rView.GetViewFrame().GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
1385 }
1386 else if ( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE &&
1387 rSh.IsHeaderFooterEdit( ) )
1388 {
1389 bool bHeader = bool(FrameTypeFlags::HEADER & rSh.GetFrameType(nullptr,false));
1390 if ( bHeader )
1391 rSh.SttPg();
1392 else
1393 rSh.EndPg();
1395 }
1396
1398 if ( m_bLockInput || (pObjSh && pObjSh->GetProgress()) )
1399 // When the progress bar is active or a progress is
1400 // running on a document, no order is being taken
1401 return;
1402
1403 m_pShadCursor.reset();
1404 // Do not reset the timer here, otherwise when flooded with events it would never time out
1405 // if every key event stopped and started it again.
1406 comphelper::ScopeGuard keyInputFlushTimerStop([this]() { m_aKeyInputFlushTimer.Stop(); });
1407
1408 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
1409 rSh.IsCursorReadonly();
1410
1411 //if the language changes the buffer must be flushed
1412 LanguageType eNewLanguage = GetInputLanguage();
1413 if(!bIsDocReadOnly && m_eBufferLanguage != eNewLanguage && !m_aInBuffer.isEmpty())
1414 {
1415 FlushInBuffer();
1416 }
1417 m_eBufferLanguage = eNewLanguage;
1418
1419 QuickHelpData aTmpQHD;
1421 {
1422 aTmpQHD.Move( *s_pQuickHlpData );
1423 s_pQuickHlpData->Stop( rSh );
1424 }
1425
1426 // OS:the DrawView also needs a readonly-Flag as well
1427 if ( !bIsDocReadOnly && rSh.GetDrawView() && rSh.GetDrawView()->KeyInput( rKEvt, this ) )
1428 {
1429 rSh.GetView().GetViewFrame().GetBindings().InvalidateAll( false );
1430 rSh.SetModified();
1431 return; // Event evaluated by SdrView
1432 }
1433
1435 {
1436 StopInsFrame();
1437 rSh.Edit();
1438 }
1439
1440 bool bFlushBuffer = false;
1441 bool bNormalChar = false;
1442 bool bAppendSpace = s_pQuickHlpData->m_bAppendSpace;
1444
1445 if ( getenv("SW_DEBUG") && rKEvt.GetKeyCode().GetCode() == KEY_F12 )
1446 {
1447 if( rKEvt.GetKeyCode().IsShift())
1448 {
1450 return;
1451 }
1452 else
1453 {
1455 pLayout->dumpAsXml( );
1456 return;
1457 }
1458 }
1459
1460 KeyEvent aKeyEvent( rKEvt );
1461 // look for vertical mappings
1462 if( !bIsDocReadOnly && !rSh.IsSelFrameMode() && !rSh.IsObjSelected() )
1463 {
1464 sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
1465
1466 if( KEY_UP == nKey || KEY_DOWN == nKey ||
1467 KEY_LEFT == nKey || KEY_RIGHT == nKey )
1468 {
1469 // In general, we want to map the direction keys if we are inside
1470 // some vertical formatted text.
1471 // 1. Exception: For a table cursor in a horizontal table, the
1472 // directions should never be mapped.
1473 // 2. Exception: For a table cursor in a vertical table, the
1474 // directions should always be mapped.
1475 const bool bVertText = rSh.IsInVerticalText();
1476 const bool bTableCursor = rSh.GetTableCursor();
1477 const bool bVertTable = rSh.IsTableVertical();
1478 if( ( bVertText && ( !bTableCursor || bVertTable ) ) ||
1479 ( bTableCursor && bVertTable ) )
1480 {
1481 SvxFrameDirection eDirection = rSh.GetTextDirection();
1482 if (eDirection == SvxFrameDirection::Vertical_LR_BT)
1483 {
1484 // Map from physical to logical, so rotate clockwise.
1485 if (KEY_UP == nKey)
1486 nKey = KEY_RIGHT;
1487 else if (KEY_DOWN == nKey)
1488 nKey = KEY_LEFT;
1489 else if (KEY_LEFT == nKey)
1490 nKey = KEY_UP;
1491 else /* KEY_RIGHT == nKey */
1492 nKey = KEY_DOWN;
1493 }
1494 else
1495 {
1496 // Attempt to integrate cursor travelling for mongolian layout does not work.
1497 // Thus, back to previous mapping of cursor keys to direction keys.
1498 if( KEY_UP == nKey ) nKey = KEY_LEFT;
1499 else if( KEY_DOWN == nKey ) nKey = KEY_RIGHT;
1500 else if( KEY_LEFT == nKey ) nKey = KEY_DOWN;
1501 else /* KEY_RIGHT == nKey */ nKey = KEY_UP;
1502 }
1503 }
1504
1505 if ( rSh.IsInRightToLeftText() )
1506 {
1507 if( KEY_LEFT == nKey ) nKey = KEY_RIGHT;
1508 else if( KEY_RIGHT == nKey ) nKey = KEY_LEFT;
1509 }
1510
1511 aKeyEvent = KeyEvent( rKEvt.GetCharCode(),
1512 vcl::KeyCode( nKey, rKEvt.GetKeyCode().GetModifier() ),
1513 rKEvt.GetRepeat() );
1514 }
1515 }
1516
1517 const vcl::KeyCode& rKeyCode = aKeyEvent.GetKeyCode();
1518 sal_Unicode aCh = aKeyEvent.GetCharCode();
1519
1520 // enable switching to notes anchor with Ctrl - Alt - Page Up/Down
1521 // pressing this inside a note will switch to next/previous note
1522 if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((rKeyCode.GetCode() == KEY_PAGEUP) || (rKeyCode.GetCode() == KEY_PAGEDOWN)))
1523 {
1524 const bool bNext = rKeyCode.GetCode()==KEY_PAGEDOWN;
1525 const SwFieldType* pFieldType = rSh.GetFieldType( 0, SwFieldIds::Postit );
1526 rSh.MoveFieldType( pFieldType, bNext );
1527 return;
1528 }
1529
1530 if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
1531 {
1532 // Check if this combination of rKeyCode and pTextContentControl should open a popup.
1533 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
1534 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
1535 if (pContentControl->ShouldOpenPopup(rKeyCode))
1536 {
1537 SwShellCursor* pCursor = rSh.GetCursor_();
1538 if (pCursor)
1539 {
1540 VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton();
1541 if (pContentControlButton)
1542 {
1543 pContentControlButton->StartPopup();
1544 return;
1545 }
1546 }
1547 }
1548 }
1549
1550 const SwFrameFormat* pFlyFormat = rSh.GetFlyFrameFormat();
1551
1552 if (pFlyFormat)
1553 {
1554 // See if the fly frame's anchor is in a content control. If so,
1555 // try to interact with it.
1556 const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
1557 SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
1558 if (pAnchorNode)
1559 {
1560 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
1561 if (pTextNode)
1562 {
1563 sal_Int32 nContentIdx = rFormatAnchor.GetAnchorContentOffset();
1564 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
1566 if (pAttr)
1567 {
1568 SwTextContentControl* pTextContentControl
1569 = static_txtattr_cast<SwTextContentControl*>(pAttr);
1570 const SwFormatContentControl& rFormatContentControl
1571 = pTextContentControl->GetContentControl();
1572 std::shared_ptr<SwContentControl> pContentControl
1573 = rFormatContentControl.GetContentControl();
1574 if (pContentControl->IsInteractingCharacter(aCh))
1575 {
1576 rSh.GotoContentControl(rFormatContentControl);
1577 return;
1578 }
1579 }
1580 }
1581 }
1582 }
1583
1584 if( pFlyFormat )
1585 {
1586 SvMacroItemId nEvent;
1587
1588 if( 32 <= aCh &&
1589 0 == (( KEY_MOD1 | KEY_MOD2 ) & rKeyCode.GetModifier() ))
1590 nEvent = SvMacroItemId::SwFrmKeyInputAlpha;
1591 else
1592 nEvent = SvMacroItemId::SwFrmKeyInputNoAlpha;
1593
1594 const SvxMacro* pMacro = pFlyFormat->GetMacro().GetMacroTable().Get( nEvent );
1595 if( pMacro )
1596 {
1597 SbxArrayRef xArgs = new SbxArray;
1598 SbxVariableRef xVar = new SbxVariable;
1599 xVar->PutString( pFlyFormat->GetName() );
1600 xArgs->Put(xVar.get(), 1);
1601
1602 xVar = new SbxVariable;
1603 if( SvMacroItemId::SwFrmKeyInputAlpha == nEvent )
1604 xVar->PutChar( aCh );
1605 else
1606 xVar->PutUShort( rKeyCode.GetModifier() | rKeyCode.GetCode() );
1607 xArgs->Put(xVar.get(), 2);
1608
1609 OUString sRet;
1610 rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
1611 if( !sRet.isEmpty() && sRet.toInt32()!=0 )
1612 return ;
1613 }
1614 }
1615 SelectionType nLclSelectionType;
1616 //A is converted to 1
1617 if( rKeyCode.GetFullCode() == (KEY_A | KEY_MOD1 |KEY_SHIFT)
1618 && rSh.HasDrawView() &&
1619 (bool(nLclSelectionType = rSh.GetSelectionType()) &&
1620 ((nLclSelectionType & (SelectionType::Frame|SelectionType::Graphic)) ||
1621 ((nLclSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1622 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1))))
1623 {
1624 SdrHdlList& rHdlList = const_cast<SdrHdlList&>(rSh.GetDrawView()->GetHdlList());
1625 SdrHdl* pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor);
1626 if ( ! pAnchor )
1627 pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor_TR);
1628 if(pAnchor)
1629 rHdlList.SetFocusHdl(pAnchor);
1630 return;
1631 }
1632
1633 SvxAutoCorrCfg* pACfg = nullptr;
1634 SvxAutoCorrect* pACorr = nullptr;
1635
1636 uno::Reference< frame::XDispatchRecorder > xRecorder =
1638 if ( !xRecorder.is() )
1639 {
1640 pACfg = &SvxAutoCorrCfg::Get();
1641 pACorr = pACfg->GetAutoCorrect();
1642 }
1643
1644 SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig();
1645
1646 OUString sFormulaEntry;
1647
1648 enum class SwKeyState { CheckKey, InsChar, InsTab,
1649 NoNum, NumOff, NumOrNoNum, NumDown, NumUp,
1650 NumIndentInc, NumIndentDec,
1651
1652 OutlineLvOff,
1653 NextCell, PrevCell, OutlineUp, OutlineDown,
1654 GlossaryExpand, NextPrevGlossary,
1655 AutoFormatByInput,
1656 NextObject, PrevObject,
1657 KeyToView,
1658 LaunchOLEObject, GoIntoFly, GoIntoDrawing,
1659 EnterDrawHandleMode,
1660 CheckDocReadOnlyKeys,
1661 CheckAutoCorrect, EditFormula,
1662 ColLeftBig, ColRightBig,
1663 ColLeftSmall, ColRightSmall,
1664 ColBottomBig,
1665 ColBottomSmall,
1666 CellLeftBig, CellRightBig,
1667 CellLeftSmall, CellRightSmall,
1668 CellTopBig, CellBottomBig,
1669 CellTopSmall, CellBottomSmall,
1670
1671 Fly_Change, Draw_Change,
1672 SpecialInsert,
1673 EnterCharCell,
1674 GotoNextFieldMark,
1675 GotoPrevFieldMark,
1676 End };
1677
1678 SwKeyState eKeyState = bIsDocReadOnly ? SwKeyState::CheckDocReadOnlyKeys : SwKeyState::CheckKey;
1679 SwKeyState eNextKeyState = SwKeyState::End;
1680 sal_uInt8 nDir = 0;
1681
1682 if (m_nKS_NUMDOWN_Count > 0)
1684
1687
1688 while( SwKeyState::End != eKeyState )
1689 {
1690 SwKeyState eFlyState = SwKeyState::KeyToView;
1691
1692 switch( eKeyState )
1693 {
1694 case SwKeyState::CheckKey:
1695 eKeyState = SwKeyState::KeyToView; // default forward to View
1696
1698 !rKeyCode.IsMod2() && '=' == aCh &&
1699 !rSh.IsTableMode() && rSh.GetTableFormat() &&
1700 rSh.IsSttPara() &&
1701 !rSh.HasReadonlySel())
1702 {
1703 // at the beginning of the table's cell a '=' ->
1704 // call EditRow (F2-functionality)
1705 // [Avoid this for LibreOfficeKit, as the separate input window
1706 // steals the focus & things go wrong - the user never gets
1707 // the focus back.]
1708 rSh.Push();
1710 !rSh.IsTableBoxTextFormat() )
1711 {
1712 // is at the beginning of the box
1713 eKeyState = SwKeyState::EditFormula;
1714 if( rSh.HasMark() )
1715 rSh.SwapPam();
1716 else
1717 rSh.SttSelect();
1719 rSh.Pop();
1720 rSh.EndSelect();
1721 sFormulaEntry = "=";
1722 }
1723 else
1725 }
1726 else
1727 {
1728 if( pACorr && aTmpQHD.HasContent() && !rSh.HasSelection() &&
1729 !rSh.HasReadonlySel() && !aTmpQHD.m_bIsAutoText &&
1730 pACorr->GetSwFlags().nAutoCmpltExpandKey ==
1731 (rKeyCode.GetModifier() | rKeyCode.GetCode()) )
1732 {
1733 eKeyState = SwKeyState::GlossaryExpand;
1734 break;
1735 }
1736
1737 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
1738 {
1739 case KEY_RIGHT | KEY_MOD2:
1740 eKeyState = SwKeyState::ColRightBig;
1741 eFlyState = SwKeyState::Fly_Change;
1742 nDir = MOVE_RIGHT_SMALL;
1743 goto KEYINPUT_CHECKTABLE;
1744
1745 case KEY_LEFT | KEY_MOD2:
1746 eKeyState = SwKeyState::ColRightSmall;
1747 eFlyState = SwKeyState::Fly_Change;
1748 nDir = MOVE_LEFT_SMALL;
1749 goto KEYINPUT_CHECKTABLE;
1750
1751 case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT:
1752 eKeyState = SwKeyState::ColLeftSmall;
1753 goto KEYINPUT_CHECKTABLE;
1754
1755 case KEY_LEFT | KEY_MOD2 | KEY_SHIFT:
1756 eKeyState = SwKeyState::ColLeftBig;
1757 goto KEYINPUT_CHECKTABLE;
1758
1759 case KEY_RIGHT | KEY_MOD2 | KEY_MOD1:
1760 eKeyState = SwKeyState::CellRightBig;
1761 goto KEYINPUT_CHECKTABLE;
1762
1763 case KEY_LEFT | KEY_MOD2 | KEY_MOD1:
1764 eKeyState = SwKeyState::CellRightSmall;
1765 goto KEYINPUT_CHECKTABLE;
1766
1768 eKeyState = SwKeyState::CellLeftSmall;
1769 goto KEYINPUT_CHECKTABLE;
1770
1772 eKeyState = SwKeyState::CellLeftBig;
1773 goto KEYINPUT_CHECKTABLE;
1774
1775 case KEY_UP | KEY_MOD2:
1776 eKeyState = SwKeyState::ColBottomSmall;
1777 eFlyState = SwKeyState::Fly_Change;
1778 nDir = MOVE_UP_SMALL;
1779 goto KEYINPUT_CHECKTABLE;
1780
1781 case KEY_DOWN | KEY_MOD2:
1782 eKeyState = SwKeyState::ColBottomBig;
1783 eFlyState = SwKeyState::Fly_Change;
1784 nDir = MOVE_DOWN_SMALL;
1785 goto KEYINPUT_CHECKTABLE;
1786
1787 case KEY_UP | KEY_MOD2 | KEY_MOD1:
1788 eKeyState = SwKeyState::CellBottomSmall;
1789 goto KEYINPUT_CHECKTABLE;
1790
1791 case KEY_DOWN | KEY_MOD2 | KEY_MOD1:
1792 eKeyState = SwKeyState::CellBottomBig;
1793 goto KEYINPUT_CHECKTABLE;
1794
1795 case KEY_UP | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1796 eKeyState = SwKeyState::CellTopBig;
1797 goto KEYINPUT_CHECKTABLE;
1798
1800 eKeyState = SwKeyState::CellTopSmall;
1801 goto KEYINPUT_CHECKTABLE;
1802
1803KEYINPUT_CHECKTABLE:
1804 // Resolve bugs 49091, 53190, 93402 and
1805 // https://bz.apache.org/ooo/show_bug.cgi?id=113502
1806 // but provide an option for restoring interactive
1807 // table sizing functionality when needed.
1808 if (
1809 ! (Window::GetIndicatorState() & KeyIndicatorState::CAPSLOCK)
1810 && m_rView.KeyInput( aKeyEvent ) // Keystroke is customized
1811 )
1812 {
1813 bFlushBuffer = true;
1814 bNormalChar = false;
1815 eKeyState = SwKeyState::End;
1816 break ;
1817 }
1818
1819 if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1820 {
1821 if(!pFlyFormat && SwKeyState::KeyToView != eFlyState &&
1824 eKeyState = SwKeyState::Draw_Change;
1825
1826 if( pFlyFormat )
1827 eKeyState = eFlyState;
1828 else if( SwKeyState::Draw_Change != eKeyState)
1829 eKeyState = SwKeyState::EnterCharCell;
1830 }
1831 break;
1832
1833 // huge object move
1834 case KEY_RIGHT | KEY_SHIFT:
1835 case KEY_LEFT | KEY_SHIFT:
1836 case KEY_UP | KEY_SHIFT:
1837 case KEY_DOWN | KEY_SHIFT:
1838 {
1839 const SelectionType nSelectionType = rSh.GetSelectionType();
1840 if ( ( pFlyFormat
1842 || ( ( nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm) )
1843 && rSh.GetDrawView()->AreObjectsMarked() ) )
1844 {
1845 eKeyState = pFlyFormat ? SwKeyState::Fly_Change : SwKeyState::Draw_Change;
1846 if (nSelectionType & SelectionType::DrawObject)
1847 {
1848 // tdf#137964: always move the DrawObject if one is selected
1849 eKeyState = SwKeyState::Draw_Change;
1850 }
1851 switch ( rKeyCode.GetCode() )
1852 {
1853 case KEY_RIGHT: nDir = MOVE_RIGHT_HUGE; break;
1854 case KEY_LEFT: nDir = MOVE_LEFT_HUGE; break;
1855 case KEY_UP: nDir = MOVE_UP_HUGE; break;
1856 case KEY_DOWN: nDir = MOVE_DOWN_HUGE; break;
1857 }
1858 }
1859 break;
1860 }
1861
1862 case KEY_LEFT:
1863 case KEY_LEFT | KEY_MOD1:
1864 {
1865 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1866 if(!bMod1)
1867 {
1868 eFlyState = SwKeyState::Fly_Change;
1869 nDir = MOVE_LEFT_BIG;
1870 }
1871 goto KEYINPUT_CHECKTABLE_INSDEL;
1872 }
1873 case KEY_RIGHT | KEY_MOD1:
1874 {
1875 goto KEYINPUT_CHECKTABLE_INSDEL;
1876 }
1877 case KEY_UP:
1878 case KEY_UP | KEY_MOD1:
1879 {
1880 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1881 if(!bMod1)
1882 {
1883 eFlyState = SwKeyState::Fly_Change;
1884 nDir = MOVE_UP_BIG;
1885 }
1886 goto KEYINPUT_CHECKTABLE_INSDEL;
1887 }
1888 case KEY_DOWN:
1889 case KEY_DOWN | KEY_MOD1:
1890 {
1891 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1892 if(!bMod1)
1893 {
1894 ::sw::mark::IFieldmark* pMark = rSh.GetCurrentFieldmark();
1895 if (auto pDropDown = dynamic_cast<FieldmarkWithDropDownButton*>(pMark))
1896 {
1897 pDropDown->LaunchPopup();
1898 eKeyState = SwKeyState::End;
1899 break;
1900 }
1901 eFlyState = SwKeyState::Fly_Change;
1902 nDir = MOVE_DOWN_BIG;
1903 }
1904 goto KEYINPUT_CHECKTABLE_INSDEL;
1905 }
1906
1907KEYINPUT_CHECKTABLE_INSDEL:
1908 if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1909 {
1910 const SelectionType nSelectionType = rSh.GetSelectionType();
1911
1912 eKeyState = SwKeyState::KeyToView;
1913 if(SwKeyState::KeyToView != eFlyState)
1914 {
1915 if((nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1917 eKeyState = SwKeyState::Draw_Change;
1919 eKeyState = SwKeyState::Fly_Change;
1920 }
1921 }
1922 break;
1923
1924
1925 case KEY_DELETE:
1926 if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
1927 {
1928 if (rSh.IsInFrontOfLabel() && rSh.NumOrNoNum())
1929 eKeyState = SwKeyState::NumOrNoNum;
1930 }
1931 else if (!rSh.IsCursorInParagraphMetadataField())
1932 {
1933 rSh.InfoReadOnlyDialog();
1934 eKeyState = SwKeyState::End;
1935 }
1936 break;
1937
1938 case KEY_RETURN:
1939 {
1940 if ( !rSh.HasReadonlySel()
1941 && !rSh.CursorInsideInputField()
1942 && !rSh.CursorInsideContentControl() )
1943 {
1944 const SelectionType nSelectionType = rSh.GetSelectionType();
1945 if(nSelectionType & SelectionType::Ole)
1946 eKeyState = SwKeyState::LaunchOLEObject;
1947 else if(nSelectionType & SelectionType::Frame)
1948 eKeyState = SwKeyState::GoIntoFly;
1949 else if((nSelectionType & SelectionType::DrawObject) &&
1950 !(nSelectionType & SelectionType::DrawObjectEditMode) &&
1952 {
1953 eKeyState = SwKeyState::GoIntoDrawing;
1954 if (lcl_goIntoTextBox(*this, rSh))
1955 eKeyState = SwKeyState::GoIntoFly;
1956 }
1957 else if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
1958 aTmpQHD.m_bIsAutoText )
1959 eKeyState = SwKeyState::GlossaryExpand;
1960
1961 //RETURN and empty paragraph in numbering -> end numbering
1962 else if( m_aInBuffer.isEmpty() &&
1965 !rSh.HasSelection() &&
1966 rSh.IsSttPara() && rSh.IsEndPara() )
1967 {
1968 eKeyState = SwKeyState::NumOff;
1969 eNextKeyState = SwKeyState::OutlineLvOff;
1970 }
1971 //RETURN for new paragraph with AutoFormatting
1972 else if( pACfg && pACfg->IsAutoFormatByInput() &&
1973 !(nSelectionType & (SelectionType::Graphic |
1977 {
1978 eKeyState = SwKeyState::AutoFormatByInput;
1979 }
1980 else
1981 {
1982 eNextKeyState = eKeyState;
1983 eKeyState = SwKeyState::CheckAutoCorrect;
1984 }
1985 }
1986 }
1987 break;
1988 case KEY_RETURN | KEY_MOD2:
1989 {
1990 if ( !rSh.HasReadonlySel()
1991 && !rSh.IsSttPara()
1993 && !rSh.CursorInsideInputField() )
1994 {
1995 eKeyState = SwKeyState::NoNum;
1996 }
1997 else if( rSh.CanSpecialInsert() )
1998 eKeyState = SwKeyState::SpecialInsert;
1999 }
2000 break;
2001 case KEY_BACKSPACE:
2002 case KEY_BACKSPACE | KEY_SHIFT:
2003 if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
2004 {
2005 bool bDone = false;
2006 // try to add comment for code snip:
2007 // Remove the paragraph indent, if the cursor is at the
2008 // beginning of a paragraph, there is no selection
2009 // and no numbering rule found at the current paragraph
2010 // Also try to remove indent, if current paragraph
2011 // has numbering rule, but isn't counted and only
2012 // key <backspace> is hit.
2013 const bool bOnlyBackspaceKey( KEY_BACKSPACE == rKeyCode.GetFullCode() );
2014 if ( rSh.IsSttPara()
2015 && !rSh.HasSelection()
2016 && ( rSh.GetNumRuleAtCurrCursorPos() == nullptr
2017 || ( rSh.IsNoNum() && bOnlyBackspaceKey ) ) )
2018 {
2019 bDone = rSh.TryRemoveIndent();
2020 }
2021
2022 if (bDone)
2023 eKeyState = SwKeyState::End;
2024 else
2025 {
2026 if ( rSh.IsSttPara() && !rSh.IsNoNum() )
2027 {
2028 if (m_nKS_NUMDOWN_Count > 0 &&
2029 0 < rSh.GetNumLevel())
2030 {
2031 eKeyState = SwKeyState::NumUp;
2033 bDone = true;
2034 }
2035 else if (m_nKS_NUMINDENTINC_Count > 0)
2036 {
2037 eKeyState = SwKeyState::NumIndentDec;
2039 bDone = true;
2040 }
2041 }
2042
2043 // If the cursor is in an empty paragraph, which has
2044 // a numbering, but not the outline numbering, and
2045 // there is no selection, the numbering has to be
2046 // deleted on key <Backspace>.
2047 // Otherwise method <SwEditShell::NumOrNoNum(..)>
2048 // should only change the <IsCounted()> state of
2049 // the current paragraph depending of the key.
2050 // On <backspace> it is set to <false>,
2051 // on <shift-backspace> it is set to <true>.
2052 // Thus, assure that method <SwEditShell::NumOrNum(..)>
2053 // is only called for the intended purpose.
2054 if ( !bDone && rSh.IsSttPara() )
2055 {
2056 bool bCallNumOrNoNum( false );
2057 if ( bOnlyBackspaceKey && !rSh.IsNoNum() )
2058 {
2059 bCallNumOrNoNum = true;
2060 }
2061 else if ( !bOnlyBackspaceKey && rSh.IsNoNum() )
2062 {
2063 bCallNumOrNoNum = true;
2064 }
2065 else if ( bOnlyBackspaceKey
2066 && rSh.IsSttPara()
2067 && rSh.IsEndPara()
2068 && !rSh.HasSelection() )
2069 {
2070 const SwNumRule* pCurrNumRule( rSh.GetNumRuleAtCurrCursorPos() );
2071 if ( pCurrNumRule != nullptr
2072 && pCurrNumRule != rSh.GetOutlineNumRule() )
2073 {
2074 bCallNumOrNoNum = true;
2075 }
2076 }
2077 if ( bCallNumOrNoNum
2078 && rSh.NumOrNoNum( !bOnlyBackspaceKey ) )
2079 {
2080 eKeyState = SwKeyState::NumOrNoNum;
2081 }
2082 }
2083 }
2084 }
2085 else if (!rSh.IsCursorInParagraphMetadataField())
2086 {
2087 rSh.InfoReadOnlyDialog();
2088 eKeyState = SwKeyState::End;
2089 }
2090 break;
2091
2092 case KEY_RIGHT:
2093 {
2094 eFlyState = SwKeyState::Fly_Change;
2095 nDir = MOVE_RIGHT_BIG;
2096 goto KEYINPUT_CHECKTABLE_INSDEL;
2097 }
2098 case KEY_TAB:
2099 {
2100 // Rich text contentControls accept tabs and fieldmarks and other rich text,
2101 // so first act on cases that are not a content control
2102 SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2103 if ((rSh.IsFormProtected() && !pTextContentControl) ||
2105 {
2106 eKeyState = SwKeyState::GotoNextFieldMark;
2107 }
2108 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2109 {
2111 eKeyState = SwKeyState::End;
2112 }
2113 else if( rSh.GetNumRuleAtCurrCursorPos()
2114 && rSh.IsSttOfPara()
2115 && !rSh.HasReadonlySel() )
2116 {
2118 {
2119 eKeyState = SwKeyState::NumDown;
2120 }
2121 else
2122 {
2123 eKeyState = SwKeyState::InsTab;
2124 }
2125 }
2126 else if (rSh.GetSelectionType() &
2132 {
2133 eKeyState = SwKeyState::NextObject;
2134 }
2135 else if ( rSh.GetTableFormat() )
2136 {
2137 if( rSh.HasSelection() || rSh.HasReadonlySel() )
2138 eKeyState = SwKeyState::NextCell;
2139 else
2140 {
2141 eKeyState = SwKeyState::CheckAutoCorrect;
2142 eNextKeyState = SwKeyState::NextCell;
2143 }
2144 }
2145 else if (pTextContentControl)
2146 {
2147 auto pCC = pTextContentControl->GetContentControl().GetContentControl();
2148 if (pCC)
2149 {
2150 switch (pCC->GetType())
2151 {
2153 eKeyState = SwKeyState::InsTab;
2154 break;
2155 default:
2156 eKeyState = SwKeyState::GotoNextFieldMark;
2157 }
2158 }
2159 }
2160 else
2161 {
2162 eKeyState = SwKeyState::InsTab;
2163 if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2164 {
2166 if( pColl &&
2167
2169 && MAXLEVEL-1 > pColl->GetAssignedOutlineStyleLevel() )
2170 eKeyState = SwKeyState::OutlineDown;
2171 }
2172 }
2173 }
2174 break;
2175 case KEY_TAB | KEY_SHIFT:
2176 {
2177 SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2178 if ((rSh.IsFormProtected() && !pTextContentControl) ||
2180 {
2181 eKeyState = SwKeyState::GotoPrevFieldMark;
2182 }
2183 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2184 {
2186 eKeyState = SwKeyState::End;
2187 }
2188 else if( rSh.GetNumRuleAtCurrCursorPos()
2189 && rSh.IsSttOfPara()
2190 && !rSh.HasReadonlySel() )
2191 {
2192 eKeyState = SwKeyState::NumUp;
2193 }
2194 else if (rSh.GetSelectionType() &
2200 {
2201 eKeyState = SwKeyState::PrevObject;
2202 }
2203 else if ( rSh.GetTableFormat() )
2204 {
2205 if( rSh.HasSelection() || rSh.HasReadonlySel() )
2206 eKeyState = SwKeyState::PrevCell;
2207 else
2208 {
2209 eKeyState = SwKeyState::CheckAutoCorrect;
2210 eNextKeyState = SwKeyState::PrevCell;
2211 }
2212 }
2213 else if (pTextContentControl)
2214 {
2215 eKeyState = SwKeyState::GotoPrevFieldMark;
2216 }
2217 else
2218 {
2219 eKeyState = SwKeyState::End;
2220 if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2221 {
2223 if( pColl &&
2225 0 < pColl->GetAssignedOutlineStyleLevel())
2226 eKeyState = SwKeyState::OutlineUp;
2227 }
2228 }
2229 }
2230 break;
2231 case KEY_TAB | KEY_MOD1:
2232 case KEY_TAB | KEY_MOD2:
2233 if( !rSh.HasReadonlySel() )
2234 {
2235 if( aTmpQHD.HasContent() && !rSh.HasSelection() )
2236 {
2237 // Next auto-complete suggestion
2238 aTmpQHD.Next( pACorr &&
2239 pACorr->GetSwFlags().bAutoCmpltEndless );
2240 eKeyState = SwKeyState::NextPrevGlossary;
2241 }
2242 else if( rSh.GetTableFormat() )
2243 eKeyState = SwKeyState::InsTab;
2244 else if((rSh.GetSelectionType() &
2248 eKeyState = SwKeyState::EnterDrawHandleMode;
2249 else
2250 {
2251 if ( !rSh.IsMultiSelection()
2253 eKeyState = SwKeyState::NumIndentInc;
2254 }
2255 }
2256 break;
2257
2258 case KEY_TAB | KEY_MOD1 | KEY_SHIFT:
2259 {
2260 if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
2261 !rSh.HasReadonlySel() )
2262 {
2263 // Previous auto-complete suggestion.
2264 aTmpQHD.Previous( pACorr &&
2265 pACorr->GetSwFlags().bAutoCmpltEndless );
2266 eKeyState = SwKeyState::NextPrevGlossary;
2267 }
2271 {
2272 eKeyState = SwKeyState::EnterDrawHandleMode;
2273 }
2274 else
2275 {
2276 if ( !rSh.IsMultiSelection()
2278 eKeyState = SwKeyState::NumIndentDec;
2279 }
2280 }
2281 break;
2282 case KEY_F2 :
2283 if( !rSh.HasReadonlySel() )
2284 {
2285 const SelectionType nSelectionType = rSh.GetSelectionType();
2286 if(nSelectionType & SelectionType::Frame)
2287 eKeyState = SwKeyState::GoIntoFly;
2288 else if(nSelectionType & SelectionType::DrawObject)
2289 {
2290 eKeyState = SwKeyState::GoIntoDrawing;
2291 if (lcl_goIntoTextBox(*this, rSh))
2292 eKeyState = SwKeyState::GoIntoFly;
2293 }
2294 }
2295 break;
2296 }
2297 }
2298 break;
2299 case SwKeyState::CheckDocReadOnlyKeys:
2300 {
2301 eKeyState = SwKeyState::KeyToView;
2302 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2303 {
2304 case KEY_TAB:
2305 case KEY_TAB | KEY_SHIFT:
2306 bNormalChar = false;
2307 eKeyState = SwKeyState::End;
2308 if ( rSh.GetSelectionType() &
2314
2315 {
2316 eKeyState = (rKeyCode.GetModifier() & KEY_SHIFT) ?
2317 SwKeyState::PrevObject : SwKeyState::NextObject;
2318 }
2319 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2320 {
2323 }
2324 else
2325 {
2326 rSh.SelectNextPrevHyperlink( KEY_SHIFT != rKeyCode.GetModifier() );
2327 }
2328 break;
2329 case KEY_RETURN:
2330 {
2331 const SelectionType nSelectionType = rSh.GetSelectionType();
2332 if(nSelectionType & SelectionType::Frame)
2333 eKeyState = SwKeyState::GoIntoFly;
2334 else
2335 {
2337 rSh.GetCurAttr(aSet);
2338 if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false))
2339 {
2340 const SfxPoolItem& rItem = aSet.Get(RES_TXTATR_INETFMT);
2341 bNormalChar = false;
2342 eKeyState = SwKeyState::End;
2343 rSh.ClickToINetAttr(static_cast<const SwFormatINetFormat&>(rItem));
2344 }
2345 }
2346 }
2347 break;
2348 }
2349 }
2350 break;
2351
2352 case SwKeyState::EnterCharCell:
2353 {
2354 eKeyState = SwKeyState::KeyToView;
2355 switch ( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2356 {
2357 case KEY_RIGHT | KEY_MOD2:
2358 rSh.Right( SwCursorSkipMode::Chars, false, 1, false );
2359 eKeyState = SwKeyState::End;
2360 FlushInBuffer();
2361 break;
2362 case KEY_LEFT | KEY_MOD2:
2363 rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
2364 eKeyState = SwKeyState::End;
2365 FlushInBuffer();
2366 break;
2367 }
2368 }
2369 break;
2370
2371 case SwKeyState::KeyToView:
2372 {
2373 eKeyState = SwKeyState::End;
2374 bNormalChar =
2375 !rKeyCode.IsMod2() &&
2376 rKeyCode.GetModifier() != KEY_MOD1 &&
2377 rKeyCode.GetModifier() != (KEY_MOD1|KEY_SHIFT) &&
2378 SW_ISPRINTABLE( aCh );
2379
2380 if( bNormalChar && rSh.IsInFrontOfLabel() )
2381 {
2382 rSh.NumOrNoNum();
2383 }
2384
2385 if( !m_aInBuffer.isEmpty() && ( !bNormalChar || bIsDocReadOnly ))
2386 FlushInBuffer();
2387
2388 if (rSh.HasReadonlySel()
2389 && ( rKeyCode.GetFunction() == KeyFuncType::PASTE
2390 || rKeyCode.GetFunction() == KeyFuncType::CUT))
2391 {
2392 rSh.InfoReadOnlyDialog(true);
2393 eKeyState = SwKeyState::End;
2394 }
2395 else if( m_rView.KeyInput( aKeyEvent ) )
2396 {
2397 bFlushBuffer = true;
2398 bNormalChar = false;
2399 }
2400 else
2401 {
2402 // Because Sfx accelerators are only called when they were
2403 // enabled at the last status update, copy has to called
2404 // 'forcefully' by us if necessary.
2405 if( rKeyCode.GetFunction() == KeyFuncType::COPY )
2406 GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
2407
2408 if( !bIsDocReadOnly && bNormalChar )
2409 {
2410 const SelectionType nSelectionType = rSh.GetSelectionType();
2411 const bool bDrawObject = (nSelectionType & SelectionType::DrawObject) &&
2412 !(nSelectionType & SelectionType::DrawObjectEditMode) &&
2414
2415 bool bTextBox = false;
2416 if (bDrawObject && lcl_goIntoTextBox(*this, rSh))
2417 // A draw shape was selected, but it has a TextBox,
2418 // start editing that instead when the normal
2419 // character is pressed.
2420 bTextBox = true;
2421
2422 if (bDrawObject && !bTextBox)
2423 {
2425 if(pObj)
2426 {
2428 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
2429 pSwDrawTextShell->Init();
2430 rSh.GetDrawView()->KeyInput( rKEvt, this );
2431 }
2432 }
2433 else if (nSelectionType & SelectionType::Frame || bTextBox)
2434 {
2435 rSh.UnSelectFrame();
2436 rSh.LeaveSelFrameMode();
2437 m_rView.AttrChangedNotify(nullptr);
2439 }
2440 eKeyState = SwKeyState::InsChar;
2441 }
2442 else
2443 {
2444 bNormalChar = false;
2445 Window::KeyInput( aKeyEvent );
2446 }
2447 }
2448 }
2449 break;
2450 case SwKeyState::LaunchOLEObject:
2451 {
2452 rSh.LaunchOLEObj();
2453 eKeyState = SwKeyState::End;
2454 }
2455 break;
2456 case SwKeyState::GoIntoFly:
2457 {
2458 rSh.UnSelectFrame();
2459 rSh.LeaveSelFrameMode();
2460 m_rView.AttrChangedNotify(nullptr);
2462 eKeyState = SwKeyState::End;
2463 }
2464 break;
2465 case SwKeyState::GoIntoDrawing:
2466 {
2467 if (SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0))
2468 {
2469 SdrObject* pObj = pMark->GetMarkedSdrObj();
2470 if(pObj)
2471 {
2473 if (auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
2474 pSwDrawTextShell->Init();
2475 }
2476 }
2477 eKeyState = SwKeyState::End;
2478 }
2479 break;
2480 case SwKeyState::EnterDrawHandleMode:
2481 {
2482 const SdrHdlList& rHdlList = rSh.GetDrawView()->GetHdlList();
2483 bool bForward(!aKeyEvent.GetKeyCode().IsShift());
2484
2485 const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
2486 eKeyState = SwKeyState::End;
2487 }
2488 break;
2489 case SwKeyState::InsTab:
2490 if( dynamic_cast<const SwWebView*>( &m_rView) != nullptr) // no Tab for WebView
2491 {
2492 // then it should be passed along
2493 Window::KeyInput( aKeyEvent );
2494 eKeyState = SwKeyState::End;
2495 break;
2496 }
2497 aCh = '\t';
2498 [[fallthrough]];
2499 case SwKeyState::InsChar:
2501 {
2502 const SwPosition* pStart = rSh.GetCursor()->Start();
2503 SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
2504 if (pTextNode)
2505 {
2506 sal_Int32 nIndex = pStart->GetContentIndex();
2508 if (pAttr)
2509 {
2510 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
2511 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
2512 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
2513 if (pContentControl->IsInteractingCharacter(aCh))
2514 {
2515 rSh.GotoContentControl(rFormatContentControl);
2516 eKeyState = SwKeyState::End;
2517 break;
2518 }
2519 }
2520 }
2521 }
2522
2523 if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2524 {
2525 ::sw::mark::ICheckboxFieldmark* pFieldmark =
2526 dynamic_cast< ::sw::mark::ICheckboxFieldmark* >
2527 (rSh.GetCurrentFieldmark());
2528 OSL_ENSURE(pFieldmark,
2529 "Where is my FieldMark??");
2530 if(pFieldmark)
2531 {
2532 pFieldmark->SetChecked(!pFieldmark->IsChecked());
2533 OSL_ENSURE(pFieldmark->IsExpanded(),
2534 "where is the otherpos?");
2535 if (pFieldmark->IsExpanded())
2536 {
2537 rSh.CalcLayout();
2538 }
2539 }
2540 eKeyState = SwKeyState::End;
2541 }
2542 else if ( !rSh.HasReadonlySel()
2543 || rSh.CursorInsideInputField() )
2544 {
2545 const bool bIsNormalChar =
2546 GetAppCharClass().isLetterNumeric( OUString( aCh ), 0 );
2547 if( bAppendSpace && bIsNormalChar &&
2548 (!m_aInBuffer.isEmpty() || !rSh.IsSttPara() || !rSh.IsEndPara() ))
2549 {
2550 // insert a blank ahead of the character. this ends up
2551 // between the expanded text and the new "non-word-separator".
2552 m_aInBuffer += " ";
2553 }
2554
2555 const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar( aCh );
2556 if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2557 pACfg->IsAutoFormatByInput() &&
2558 (( pACorr->IsAutoCorrFlag( ACFlags::ChgWeightUnderl ) &&
2559 ( '*' == aCh || '_' == aCh ) ) ||
2560 ( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
2561 ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
2562 {
2563 FlushInBuffer();
2564 rSh.AutoCorrect( *pACorr, aCh );
2565 if( '\"' != aCh && '\'' != aCh ) // only call when "*_"!
2566 rSh.UpdateAttr();
2567 }
2568 else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2569 pACfg->IsAutoFormatByInput() &&
2570 pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2571 ACFlags::ChgOrdinalNumber | ACFlags::AddNonBrkSpace |
2572 ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2573 ACFlags::Autocorrect | ACFlags::TransliterateRTL ) &&
2574 '\"' != aCh && '\'' != aCh && '*' != aCh && '_' != aCh
2575 )
2576 {
2577 FlushInBuffer();
2578 rSh.AutoCorrect( *pACorr, aCh );
2579 }
2580 else
2581 {
2582 OUStringBuffer aBuf(m_aInBuffer);
2584 m_aInBuffer.getLength() + aKeyEvent.GetRepeat() + 1, aCh);
2585 m_aInBuffer = aBuf.makeStringAndClear();
2586 bool delayFlush = Application::AnyInput( VclInputFlags::KEYBOARD );
2587 bFlushBuffer = !delayFlush;
2588 if( delayFlush )
2589 {
2590 // Start the timer, make sure to not restart it.
2591 keyInputFlushTimerStop.dismiss();
2594 }
2595 }
2596 eKeyState = SwKeyState::End;
2597 }
2598 else
2599 {
2600 rSh.InfoReadOnlyDialog(true);
2601 eKeyState = SwKeyState::End;
2602 }
2603 break;
2604
2605 case SwKeyState::CheckAutoCorrect:
2606 {
2607 if( pACorr && pACfg->IsAutoFormatByInput() &&
2608 pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2609 ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
2610 ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2611 ACFlags::Autocorrect ) &&
2612 !rSh.HasReadonlySel() )
2613 {
2614 FlushInBuffer();
2615 rSh.AutoCorrect( *pACorr, u'\0' );
2616 }
2617 eKeyState = eNextKeyState;
2618 }
2619 break;
2620
2621 default:
2622 {
2623 sal_uInt16 nSlotId = 0;
2624 FlushInBuffer();
2625 switch( eKeyState )
2626 {
2627 case SwKeyState::SpecialInsert:
2628 rSh.DoSpecialInsert();
2629 break;
2630
2631 case SwKeyState::NoNum:
2632 rSh.NoNum();
2633 break;
2634
2635 case SwKeyState::NumOff:
2636 // shell change - so record in advance
2637 rSh.DelNumRules();
2638 break;
2639 case SwKeyState::OutlineLvOff: // delete autofmt outlinelevel later
2640 break;
2641
2642 case SwKeyState::NumDown:
2643 rSh.NumUpDown();
2645 break;
2646 case SwKeyState::NumUp:
2647 rSh.NumUpDown( false );
2648 break;
2649
2650 case SwKeyState::NumIndentInc:
2653 break;
2654
2655 case SwKeyState::GotoNextFieldMark:
2656 {
2657 rSh.GotoFormControl(/*bNext=*/true);
2658 }
2659 break;
2660
2661 case SwKeyState::GotoPrevFieldMark:
2662 {
2663 rSh.GotoFormControl(/*bNext=*/false);
2664 }
2665 break;
2666
2667 case SwKeyState::NumIndentDec:
2669 break;
2670
2671 case SwKeyState::OutlineDown:
2672 rSh.OutlineUpDown();
2673 break;
2674 case SwKeyState::OutlineUp:
2675 rSh.OutlineUpDown( -1 );
2676 break;
2677
2678 case SwKeyState::NextCell:
2679 // always 'flush' in tables
2680 rSh.GoNextCell(!rSh.HasReadonlySel());
2681 nSlotId = FN_GOTO_NEXT_CELL;
2682 break;
2683 case SwKeyState::PrevCell:
2684 rSh.GoPrevCell();
2685 nSlotId = FN_GOTO_PREV_CELL;
2686 break;
2687 case SwKeyState::AutoFormatByInput:
2688 rSh.SplitNode( true );
2689 break;
2690
2691 case SwKeyState::NextObject:
2692 case SwKeyState::PrevObject:
2693 if(rSh.GotoObj( SwKeyState::NextObject == eKeyState, GotoObjFlags::Any))
2694 {
2695 if( rSh.IsFrameSelected() &&
2697 {
2699 m_rView.SetDrawFuncPtr(nullptr);
2701 m_rView.AttrChangedNotify(nullptr);
2702 }
2703 rSh.HideCursor();
2704 rSh.EnterSelFrameMode();
2705 }
2706 break;
2707 case SwKeyState::GlossaryExpand:
2708 {
2709 // replace the word or abbreviation with the auto text
2711
2712 OUString sFnd(aTmpQHD.CurStr());
2713 if( aTmpQHD.m_bIsAutoText )
2714 {
2716 OUString sShrtNm;
2717 OUString sGroup;
2718 if(pList->GetShortName( sFnd, sShrtNm, sGroup))
2719 {
2720 rSh.SttSelect();
2721 rSh.ExtendSelection(false, aTmpQHD.CurLen());
2722 SwGlossaryHdl* pGlosHdl = GetView().GetGlosHdl();
2723 pGlosHdl->SetCurGroup(sGroup, true);
2724 pGlosHdl->InsertGlossary( sShrtNm);
2726 }
2727 }
2728 else
2729 {
2730 sFnd = sFnd.copy(aTmpQHD.CurLen());
2731 rSh.Insert( sFnd );
2732 s_pQuickHlpData->m_bAppendSpace = !pACorr ||
2734 }
2735 rSh.EndUndo( SwUndoId::END );
2736 }
2737 break;
2738
2739 case SwKeyState::NextPrevGlossary:
2740 s_pQuickHlpData->Move( aTmpQHD );
2741 s_pQuickHlpData->Start(rSh, false);
2742 break;
2743
2744 case SwKeyState::EditFormula:
2745 {
2746 const sal_uInt16 nId = SwInputChild::GetChildWindowId();
2747
2748 SfxViewFrame& rVFrame = GetView().GetViewFrame();
2749 rVFrame.ToggleChildWindow( nId );
2750 SwInputChild* pChildWin = static_cast<SwInputChild*>(rVFrame.
2751 GetChildWindow( nId ));
2752 if( pChildWin )
2753 pChildWin->SetFormula( sFormulaEntry );
2754 }
2755 break;
2756
2759 case SwKeyState::ColLeftSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft, pModOpt->GetTableHMove() ); break;
2760 case SwKeyState::ColRightSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight, pModOpt->GetTableHMove() ); break;
2762 case SwKeyState::ColBottomSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom, pModOpt->GetTableVMove() ); break;
2765 case SwKeyState::CellLeftSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft, pModOpt->GetTableHMove() ); break;
2766 case SwKeyState::CellRightSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight, pModOpt->GetTableHMove() ); break;
2769 case SwKeyState::CellTopSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop, pModOpt->GetTableVMove() ); break;
2770 case SwKeyState::CellBottomSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom, pModOpt->GetTableVMove() ); break;
2771
2772 case SwKeyState::Fly_Change:
2773 {
2774 SdrView *pSdrView = rSh.GetDrawView();
2775 const SdrHdlList& rHdlList = pSdrView->GetHdlList();
2776 if(rHdlList.GetFocusHdl())
2777 ChangeDrawing( nDir );
2778 else
2779 ChangeFly( nDir, dynamic_cast<const SwWebView*>( &m_rView) != nullptr );
2780 }
2781 break;
2782 case SwKeyState::Draw_Change :
2783 ChangeDrawing( nDir );
2784 break;
2785 default:
2786 break;
2787 }
2788 if( nSlotId && m_rView.GetViewFrame().GetBindings().GetRecorder().is() )
2789 {
2790 SfxRequest aReq(m_rView.GetViewFrame(), nSlotId);
2791 aReq.Done();
2792 }
2793 eKeyState = SwKeyState::End;
2794 }
2795 }
2796 }
2797
2798 // update the page number in the statusbar
2799 sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
2800 if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey )
2802
2803 // in case the buffered characters are inserted
2804 if( bFlushBuffer && !m_aInBuffer.isEmpty() )
2805 {
2806 FlushInBuffer();
2807
2808 // maybe show Tip-Help
2809 if (bNormalChar)
2810 {
2811 const bool bAutoTextShown
2812 = pACfg && pACfg->IsAutoTextTip() && ShowAutoText(rSh.GetChunkForAutoText());
2813 if (!bAutoTextShown && pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
2814 ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
2815 }
2816 }
2817
2818 // get the word count dialog to update itself
2819 SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
2820 if( pWrdCnt )
2821 pWrdCnt->UpdateCounts();
2822
2823}
2824
2829{
2830 // Not on all systems a MouseButtonUp is used ahead
2831 // of the modal dialog (like on WINDOWS).
2832 // So reset the statuses here and release the mouse
2833 // for the dialog.
2834 m_bMBPressed = false;
2835 g_bNoInterrupt = false;
2836 EnterArea();
2837 ReleaseMouse();
2838}
2839
2844static bool lcl_urlOverBackground(SwWrtShell& rSh, const Point& rDocPos)
2845{
2846 SwContentAtPos aSwContentAtPos(IsAttrAtPos::InetAttr);
2847 SdrObject* pSelectableObj = rSh.GetObjAt(rDocPos);
2848
2849 return rSh.GetContentAtPos(rDocPos, aSwContentAtPos) && pSelectableObj->GetLayer() == rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId();
2850}
2851
2852void SwEditWin::MoveCursor( SwWrtShell &rSh, const Point& rDocPos,
2853 const bool bOnlyText, bool bLockView )
2854{
2855 const bool bTmpNoInterrupt = g_bNoInterrupt;
2856 g_bNoInterrupt = false;
2857
2858 int nTmpSetCursor = 0;
2859
2860 if( !rSh.IsViewLocked() && bLockView )
2861 rSh.LockView( true );
2862 else
2863 bLockView = false;
2864
2865 {
2866 // only temporary generate move context because otherwise
2867 // the query to the content form doesn't work!!!
2868 SwMvContext aMvContext( &rSh );
2869 nTmpSetCursor = rSh.CallSetCursor(&rDocPos, bOnlyText);
2870 g_bValidCursorPos = !(CRSR_POSCHG & nTmpSetCursor);
2871 }
2872
2873 // notify the edit window that from now on we do not use the input language
2874 if ( !(CRSR_POSOLD & nTmpSetCursor) )
2875 SetUseInputLanguage( false );
2876
2877 if( bLockView )
2878 rSh.LockView( false );
2879
2880 g_bNoInterrupt = bTmpNoInterrupt;
2881}
2882
2884{
2886 const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
2887
2888 // We have to check if a context menu is shown and we have an UI
2889 // active inplace client. In that case we have to ignore the mouse
2890 // button down event. Otherwise we would crash (context menu has been
2891 // opened by inplace client and we would deactivate the inplace client,
2892 // the context menu is closed by VCL asynchronously which in the end
2893 // would work on deleted objects or the context menu has no parent anymore)
2894 SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
2895 bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
2896
2897 if (bIsOleActive && vcl::IsInPopupMenuExecute())
2898 return;
2899
2900 MouseEvent aMEvt(_rMEvt);
2901
2902 if (m_rView.GetPostItMgr()->IsHit(aMEvt.GetPosPixel()))
2903 return;
2904
2906 {
2908 {
2909 pWindow->MouseButtonDown(aMEvt);
2910 return;
2911 }
2912 }
2913
2915
2916 GrabFocus();
2917 rSh.addCurrentPosition();
2918
2919 //ignore key modifiers for format paintbrush
2920 {
2921 bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
2922 && m_pApplyTempl->m_pFormatClipboard->HasContent();
2923 if( bExecFormatPaintbrush )
2924 aMEvt = MouseEvent(_rMEvt.GetPosPixel(), _rMEvt.GetClicks(), _rMEvt.GetMode(),
2925 _rMEvt.GetButtons());
2926 }
2927
2928 m_bWasShdwCursor = nullptr != m_pShadCursor;
2929 m_pShadCursor.reset();
2930
2931 const Point aDocPos(PixelToLogic(aMEvt.GetPosPixel()));
2932
2933 FrameControlType eControl;
2934 bool bOverFly = false;
2935 bool bPageAnchored = false;
2936 bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
2937
2938 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly();
2939 if (bOverHeaderFooterFly && (!bIsDocReadOnly && rSh.GetCurField()))
2940 // We have a field here, that should have priority over header/footer fly.
2941 bOverHeaderFooterFly = false;
2942
2943 // Are we clicking on a blank header/footer area?
2944 if ( IsInHeaderFooter( aDocPos, eControl ) || bOverHeaderFooterFly )
2945 {
2946 const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( aDocPos );
2947
2948 if ( pPageFrame )
2949 {
2950 // Is it active?
2951 bool bActive = true;
2952 const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
2953
2954 const SwFrameFormat* pFormat = pDesc->GetLeftFormat();
2955 if ( pPageFrame->OnRightPage() )
2956 pFormat = pDesc->GetRightFormat();
2957
2958 if ( pFormat )
2959 {
2960 if ( eControl == FrameControlType::Header )
2961 bActive = pFormat->GetHeader().IsActive();
2962 else
2963 bActive = pFormat->GetFooter().IsActive();
2964 }
2965
2966 if ( !bActive )
2967 {
2968 // When in Hide-Whitespace mode, we don't want header
2969 // and footer controls.
2971 {
2972 SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
2973 const bool bWasInHeader = aPam.GetPoint()->GetNode().FindHeaderStartNode() != nullptr;
2974 const bool bWasInFooter = aPam.GetPoint()->GetNode().FindFooterStartNode() != nullptr;
2975
2976 // Is the cursor in a part like similar to the one we clicked on? For example,
2977 // if the cursor is in a header and we click on an empty header... don't change anything to
2978 // keep consistent behaviour due to header edit mode (and the same for the footer as well).
2979
2980 // Otherwise, we hide the header/footer control if a separator is shown, and vice versa.
2981 if (!(bWasInHeader && eControl == FrameControlType::Header) &&
2982 !(bWasInFooter && eControl == FrameControlType::Footer))
2983 {
2984 const bool bSeparatorWasVisible = rSh.IsShowHeaderFooterSeparator(eControl);
2985 rSh.SetShowHeaderFooterSeparator(eControl, !bSeparatorWasVisible);
2986
2987 // Repaint everything
2988 Invalidate();
2989
2990 // tdf#84929. If the footer control had not been showing, do not change the cursor position,
2991 // because the user may have scrolled to turn on the separator control and
2992 // if the cursor cannot be positioned on-screen, then the user would need to scroll back again to use the control.
2993 // This should only be done for the footer. The cursor can always be re-positioned near the header. tdf#134023.
2994 if ( eControl == FrameControlType::Footer && !bSeparatorWasVisible
2996 return;
2997 }
2998 }
2999 }
3000 else
3001 {
3002 // Make sure we have the proper Header/Footer separators shown
3003 // as these may be changed if clicking on an empty Header/Footer
3006
3007 if ( !rSh.IsHeaderFooterEdit() )
3008 {
3010
3011 // Repaint everything
3012 rSh.GetWin()->Invalidate();
3013 }
3014 }
3015 }
3016 }
3017 else
3018 {
3019 if ( rSh.IsHeaderFooterEdit( ) )
3021 else
3022 {
3023 // Make sure that the separators are hidden
3026
3027 // Repaint everything
3028 // FIXME fdo#67358 for unknown reasons this causes painting
3029 // problems when resizing table columns, so disable it
3030// rSh.GetWin()->Invalidate();
3031 }
3032
3033 // Toggle Hide-Whitespace if between pages.
3034 if (rSh.GetViewOptions()->CanHideWhitespace() &&
3035 rSh.GetLayout()->IsBetweenPages(aDocPos))
3036 {
3037 if (_rMEvt.GetClicks() >= 2)
3038 {
3039 SwViewOption aOpt(*rSh.GetViewOptions());
3041 rSh.ApplyViewOptions(aOpt);
3042 }
3043
3044 return;
3045 }
3046 }
3047
3048 if ( IsChainMode() )
3049 {
3050 SetChainMode( false );
3051 SwRect aDummy;
3052 SwFlyFrameFormat *pFormat = static_cast<SwFlyFrameFormat*>(rSh.GetFlyFrameFormat());
3053 if ( rSh.Chainable( aDummy, *pFormat, aDocPos ) == SwChainRet::OK )
3054 rSh.Chain( *pFormat, aDocPos );
3055 UpdatePointer(aDocPos, aMEvt.GetModifier());
3056 return;
3057 }
3058
3059 // After GrabFocus a shell should be pushed. That should actually
3060 // work but in practice ...
3062
3063 bool bCallBase = true;
3064
3066 s_pQuickHlpData->Stop( rSh );
3068
3069 if( rSh.FinishOLEObj() )
3070 return; // end InPlace and the click doesn't count anymore
3071
3072 CurrShell aCurr( &rSh );
3073
3074 SdrView *pSdrView = rSh.GetDrawView();
3075 if ( pSdrView )
3076 {
3077 if (pSdrView->MouseButtonDown(aMEvt, GetOutDev()))
3078 {
3080 return; // SdrView's event evaluated
3081 }
3082 }
3083
3084 m_bIsInMove = false;
3085 m_aStartPos = aMEvt.GetPosPixel();
3086 m_aRszMvHdlPt.setX( 0 );
3087 m_aRszMvHdlPt.setY( 0 );
3088
3089 SwTab nMouseTabCol = SwTab::COL_NONE;
3090 const bool bTmp = !rSh.IsDrawCreate() && !m_pApplyTempl && !rSh.IsInSelect()
3091 && aMEvt.GetClicks() == 1 && MOUSE_LEFT == aMEvt.GetButtons();
3092 if ( bTmp &&
3093 SwTab::COL_NONE != (nMouseTabCol = rSh.WhichMouseTabCol( aDocPos ) ) &&
3094 !rSh.IsObjSelectable( aDocPos ) )
3095 {
3096 // Enhanced table selection
3097 if ( SwTab::SEL_HORI <= nMouseTabCol && SwTab::COLSEL_VERT >= nMouseTabCol )
3098 {
3099 rSh.EnterStdMode();
3100 rSh.SelectTableRowCol( aDocPos );
3101 if( SwTab::SEL_HORI != nMouseTabCol && SwTab::SEL_HORI_RTL != nMouseTabCol)
3102 {
3104 m_bIsRowDrag = SwTab::ROWSEL_HORI == nMouseTabCol||
3105 SwTab::ROWSEL_HORI_RTL == nMouseTabCol ||
3106 SwTab::COLSEL_VERT == nMouseTabCol;
3107 m_bMBPressed = true;
3108 CaptureMouse();
3109 }
3110 return;
3111 }
3112
3113 if ( !rSh.IsTableMode() )
3114 {
3115 // comes from table columns out of the document.
3116 if(SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol)
3117 m_rView.SetTabColFromDoc( true );
3118 else
3119 m_rView.SetTabRowFromDoc( true );
3120
3121 m_rView.SetTabColFromDocPos( aDocPos );
3124 rBind.Update();
3125 if (RulerColumnDrag(
3126 aMEvt, (SwTab::COL_VERT == nMouseTabCol || SwTab::ROW_HORI == nMouseTabCol)))
3127 {
3128 m_rView.SetTabColFromDoc( false );
3129 m_rView.SetTabRowFromDoc( false );
3131 rBind.Update();
3132 bCallBase = false;
3133 }
3134 else
3135 {
3136 return;
3137 }
3138 }
3139 }
3140 else if (bTmp &&
3141 rSh.IsNumLabel(aDocPos))
3142 {
3143 SwTextNode* pNodeAtPos = rSh.GetNumRuleNodeAtPos( aDocPos );
3144 m_rView.SetNumRuleNodeFromDoc( pNodeAtPos );
3147 rBind.Update();
3148
3149 if (RulerMarginDrag(aMEvt, SwFEShell::IsVerticalModeAtNdAndPos(*pNodeAtPos, aDocPos)))
3150 {
3151 m_rView.SetNumRuleNodeFromDoc( nullptr );
3153 rBind.Update();
3154 bCallBase = false;
3155 }
3156 else
3157 {
3158 // Make sure the pointer is set to 0, otherwise it may point to
3159 // nowhere after deleting the corresponding text node.
3160 m_rView.SetNumRuleNodeFromDoc( nullptr );
3161 return;
3162 }
3163 }
3164
3165 if ( rSh.IsInSelect() )
3166 rSh.EndSelect();
3167
3168 // query against LEFT because otherwise for example also a right
3169 // click releases the selection.
3170 if (MOUSE_LEFT == aMEvt.GetButtons())
3171 {
3172 bool bOnlyText = false;
3173 m_bMBPressed = true;
3174 g_bNoInterrupt = true;
3176
3177 CaptureMouse();
3178
3179 // reset cursor position if applicable
3180 rSh.ResetCursorStack();
3181
3182 switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3183 {
3184 case MOUSE_LEFT:
3185 case MOUSE_LEFT + KEY_SHIFT:
3186 case MOUSE_LEFT + KEY_MOD2:
3187 if( rSh.IsObjSelected() )
3188 {
3189 SdrHdl* pHdl;
3190 if( !bIsDocReadOnly &&
3191 !m_pAnchorMarker &&
3192 pSdrView &&
3193 nullptr != ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3194 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3195 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3196 {
3197 // #i121463# Set selected during drag
3198 pHdl->SetSelected();
3199 m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3200 UpdatePointer(aDocPos, aMEvt.GetModifier());
3201 return;
3202 }
3203 }
3204 if (EnterDrawMode(aMEvt, aDocPos))
3205 {
3206 g_bNoInterrupt = false;
3207 return;
3208 }
3209 else if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
3210 {
3211 StopInsFrame();
3212 rSh.Edit();
3213 }
3214
3215 // Without SHIFT because otherwise Toggle doesn't work at selection
3216 if (aMEvt.GetClicks() == 1)
3217 {
3218 if ( rSh.IsSelFrameMode())
3219 {
3220 SdrHdl* pHdl = rSh.GetDrawView()->PickHandle(aDocPos);
3221 bool bHitHandle = pHdl && pHdl->GetKind() != SdrHdlKind::Anchor &&
3222 pHdl->GetKind() != SdrHdlKind::Anchor_TR;
3223
3224 if ((rSh.IsInsideSelectedObj(aDocPos) || bHitHandle)
3225 && (aMEvt.GetModifier() != KEY_SHIFT || bHitHandle))
3226 {
3227 rSh.EnterSelFrameMode( &aDocPos );
3228 if ( !m_pApplyTempl )
3229 {
3230 // only if no position to size was hit.
3231 if (!bHitHandle)
3232 {
3233 StartDDTimer();
3234 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3235 SwEditWin::s_nDDStartPosX = aDocPos.X();
3236 }
3237 g_bFrameDrag = true;
3238 }
3239 g_bNoInterrupt = false;
3240 return;
3241 }
3242 }
3243 }
3244 }
3245
3246 bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
3247 if ( !bExecHyperlinks )
3248 {
3250 if ((bSecureOption && aMEvt.GetModifier() == KEY_MOD1)
3251 || (!bSecureOption && aMEvt.GetModifier() != KEY_MOD1))
3252 bExecHyperlinks = true;
3253 }
3254
3255 // Enhanced selection
3256 sal_uInt8 nNumberOfClicks = static_cast<sal_uInt8>(aMEvt.GetClicks() % 4);
3257 if (0 == nNumberOfClicks && 0 < aMEvt.GetClicks())
3258 nNumberOfClicks = 4;
3259
3260 bool bExecDrawTextLink = false;
3261
3262 switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3263 {
3264 case MOUSE_LEFT:
3265 case MOUSE_LEFT + KEY_MOD1:
3266 case MOUSE_LEFT + KEY_MOD2:
3267 {
3268
3269 // fdo#79604: first, check if a link has been clicked - do not
3270 // select fly in this case!
3271 if (1 == nNumberOfClicks)
3272 {
3273 UpdatePointer(aDocPos, aMEvt.GetModifier());
3274 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3275 SwEditWin::s_nDDStartPosX = aDocPos.X();
3276
3277 // hit a URL in DrawText object?
3278 if (bExecHyperlinks && pSdrView)
3279 {
3280 SdrViewEvent aVEvt;
3281 pSdrView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
3282
3283 if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
3284 bExecDrawTextLink = true;
3285 }
3286 }
3287
3288 if (1 == nNumberOfClicks && !bExecDrawTextLink)
3289 {
3290 // only try to select frame, if pointer already was
3291 // switched accordingly
3292 if ( m_aActHitType != SdrHitKind::NONE && !rSh.IsSelFrameMode() &&
3293 !GetView().GetViewFrame().GetDispatcher()->IsLocked())
3294 {
3295 // Test if there is a draw object at that position and if it should be selected.
3296 bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
3297
3298 if(bShould)
3299 {
3300 m_rView.NoRotate();
3301 rSh.HideCursor();
3302
3303 bool bUnLockView = !rSh.IsViewLocked();
3304 rSh.LockView( true );
3305 bool bSelObj
3306 = rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0);
3307 if( bUnLockView )
3308 rSh.LockView( false );
3309
3310 if( bSelObj )
3311 {
3312 // if the frame was deselected in the macro
3313 // the cursor just has to be displayed again
3315 rSh.ShowCursor();
3316 else
3317 {
3318 if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
3319 {
3321 m_rView.SetDrawFuncPtr(nullptr);
3323 m_rView.AttrChangedNotify(nullptr);
3324 }
3325
3326 rSh.EnterSelFrameMode( &aDocPos );
3327 g_bFrameDrag = true;
3328 UpdatePointer(aDocPos, aMEvt.GetModifier());
3329 }
3330 return;
3331 }
3332 else
3333 bOnlyText = rSh.IsObjSelectable( aDocPos );
3334
3335 if (!m_rView.GetDrawFuncPtr())
3336 rSh.ShowCursor();
3337 }
3338 else
3339 bOnlyText = KEY_MOD1 != aMEvt.GetModifier();
3340 }
3341 else if ( rSh.IsSelFrameMode() &&
3342 (m_aActHitType == SdrHitKind::NONE ||
3343 !rSh.IsInsideSelectedObj( aDocPos )))
3344 {
3345 m_rView.NoRotate();
3346 SdrHdl *pHdl;
3347 if( !bIsDocReadOnly && !m_pAnchorMarker && nullptr !=
3348 ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3349 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3350 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3351 {
3352 m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3353 UpdatePointer(aDocPos, aMEvt.GetModifier());
3354 return;
3355 }
3356 else
3357 {
3358 bool bUnLockView = !rSh.IsViewLocked();
3359 rSh.LockView( true );
3360 sal_uInt8 nFlag = aMEvt.IsShift() ? SW_ADD_SELECT : 0;
3361 if (aMEvt.IsMod1())
3362 nFlag = nFlag | SW_ENTER_GROUP;
3363
3364 if ( rSh.IsSelFrameMode() )
3365 {
3366 rSh.UnSelectFrame();
3367 rSh.LeaveSelFrameMode();
3368 m_rView.AttrChangedNotify(nullptr);
3369 }
3370
3371 bool bSelObj = rSh.SelectObj( aDocPos, nFlag );
3372 if( bUnLockView )
3373 rSh.LockView( false );
3374
3375 if( !bSelObj )
3376 {
3377 // move cursor here so that it is not drawn in the
3378 // frame first; ShowCursor() happens in LeaveSelFrameMode()
3379 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
3380 rSh.LeaveSelFrameMode();
3381 m_rView.AttrChangedNotify(nullptr);
3382 bCallBase = false;
3383 }
3384 else
3385 {
3386 rSh.HideCursor();
3387 rSh.EnterSelFrameMode( &aDocPos );
3388 rSh.SelFlyGrabCursor();
3389 rSh.MakeSelVisible();
3390 g_bFrameDrag = true;
3391 if( rSh.IsFrameSelected() &&
3393 {
3395 m_rView.SetDrawFuncPtr(nullptr);
3397 m_rView.AttrChangedNotify(nullptr);
3398 }
3399 UpdatePointer(aDocPos, aMEvt.GetModifier());
3400 return;
3401 }
3402 }
3403 }
3404 }
3405
3406 switch ( nNumberOfClicks )
3407 {
3408 case 1:
3409 break;
3410 case 2:
3411 {
3412 g_bFrameDrag = false;
3413 if (!bIsDocReadOnly && rSh.IsInsideSelectedObj(aDocPos)
3418 {
3419 /* This is no good: on the one hand GetSelectionType is used as flag field
3420 * (take a look into the GetSelectionType method) and on the other hand the
3421 * return value is used in a switch without proper masking (very nice), this must lead to trouble
3422 */
3424 {
3428 {
3430 FN_FORMAT_GRAFIC_DLG, nullptr,
3431 SfxCallMode::RECORD|SfxCallMode::SLOT);
3432 }
3433 return;
3434
3435 // double click on OLE object --> OLE-InPlace
3436 case SelectionType::Ole:
3438 rSh.LaunchOLEObj();
3439 return;
3440
3444 {
3446 FN_FORMAT_FRAME_DLG, nullptr,
3447 SfxCallMode::RECORD|SfxCallMode::SLOT);
3448 }
3449 return;
3450
3453 EnterDrawTextMode(aDocPos);
3454 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
3455 pSwDrawTextShell->Init();
3456 return;
3457
3458 default: break;
3459 }
3460 }
3461
3462 // if the cursor position was corrected or if a Fly
3463 // was selected in ReadOnlyMode, no word selection, except when tiled rendering.
3465 return;
3466
3467 SwField *pField;
3468 bool bFootnote = false;
3469
3470 if( !bIsDocReadOnly &&
3471 (nullptr != (pField = rSh.GetCurField(true)) ||
3472 ( bFootnote = rSh.GetCurFootnote() ) ) )
3473 {
3475 if( bFootnote )
3477 else
3478 {
3479 SwFieldTypesEnum nTypeId = pField->GetTypeId();
3480 SfxViewFrame& rVFrame = GetView().GetViewFrame();
3481 switch( nTypeId )
3482 {
3485 {
3486 // if it's a Readonly region, status has to be enabled
3487 sal_uInt16 nSlot = SwFieldTypesEnum::Postit == nTypeId ? FN_POSTIT : FN_JAVAEDIT;
3488 SfxBoolItem aItem(nSlot, true);
3489 rVFrame.GetBindings().SetState(aItem);
3490 rVFrame.GetBindings().Execute(nSlot);
3491 break;
3492 }
3495 break;
3500 break;
3501 default:
3503 }
3504 }
3505 return;
3506 }
3507 // in extended mode double and triple
3508 // click has no effect.
3509 if ( rSh.IsExtMode() || rSh.IsBlockMode() )
3510 return;
3511
3512 // select word, AdditionalMode if applicable
3513 if (KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode())
3514 {
3515 rSh.EnterAddMode();
3516 rSh.SelWrd( &aDocPos );
3517 rSh.LeaveAddMode();
3518 }
3519 else
3520 {
3521 if (!rSh.SelWrd(&aDocPos) && comphelper::LibreOfficeKit::isActive())
3522 // Double click did not select any word: try to
3523 // select the current cell in case we are in a
3524 // table.
3525 rSh.SelTableBox();
3526 }
3527
3529 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3530 aContentAtPos.aFnd.pFieldmark != nullptr)
3531 {
3532 IFieldmark *pFieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
3533 if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN || pFieldBM->GetFieldname( ) == ODF_FORMDATE )
3534 {
3537 GetView().GetViewFrame().GetBindings().Execute(SID_FM_CTL_PROPERTIES);
3538 return;
3539 }
3540 }
3541
3542 // tdf#143158 - handle alphabetical index entries
3543 SwContentAtPos aToxContentAtPos(IsAttrAtPos::ToxMark);
3544 if (rSh.GetContentAtPos(aDocPos, aToxContentAtPos))
3545 {
3546 const OUString sToxText = aToxContentAtPos.sStr;
3547 if (!sToxText.isEmpty() && aToxContentAtPos.pFndTextAttr)
3548 {
3549 const SwTOXType* pTType
3550 = aToxContentAtPos.pFndTextAttr->GetTOXMark().GetTOXType();
3551 if (pTType && pTType->GetType() == TOXTypes::TOX_INDEX)
3552 {
3556 return;
3557 }
3558 }
3559 }
3560
3561 g_bHoldSelection = true;
3562 return;
3563 }
3564 case 3:
3565 case 4:
3566 {
3567 g_bFrameDrag = false;
3568 // in extended mode double and triple
3569 // click has no effect.
3570 if ( rSh.IsExtMode() )
3571 return;
3572
3573 // if the cursor position was corrected or if a Fly
3574 // was selected in ReadOnlyMode, no word selection.
3575 if ( !g_bValidCursorPos || rSh.IsFrameSelected() )
3576 return;
3577
3578 // select line, AdditionalMode if applicable
3579 const bool bMod = KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode();
3580
3581 if ( bMod )
3582 rSh.EnterAddMode();
3583
3584 // Enhanced selection
3585 if ( 3 == nNumberOfClicks )
3586 rSh.SelSentence( &aDocPos );
3587 else
3588 rSh.SelPara( &aDocPos );
3589
3590 if ( bMod )
3591 rSh.LeaveAddMode();
3592
3593 g_bHoldSelection = true;
3594 return;
3595 }
3596
3597 default:
3598 return;
3599 }
3600
3601 [[fallthrough]];
3602 }
3603 case MOUSE_LEFT + KEY_SHIFT:
3604 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
3605 {
3606 bool bLockView = m_bWasShdwCursor;
3607
3608 switch (aMEvt.GetModifier())
3609 {
3610 case KEY_MOD1 + KEY_SHIFT:
3611 {
3612 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3613 {
3614 m_rView.NoRotate();
3615 rSh.HideCursor();
3616 if ( rSh.IsSelFrameMode() )
3617 rSh.SelectObj(aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP);
3618 else
3619 { if ( rSh.SelectObj( aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP ) )
3620 {
3621 rSh.EnterSelFrameMode( &aDocPos );
3622 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3623 SwEditWin::s_nDDStartPosX = aDocPos.X();
3624 g_bFrameDrag = true;
3625 return;
3626 }
3627 }
3628 }
3629 else if( rSh.IsSelFrameMode() &&
3630 rSh.GetDrawView()->PickHandle( aDocPos ))
3631 {
3632 g_bFrameDrag = true;
3633 g_bNoInterrupt = false;
3634 return;
3635 }
3636 }
3637 break;
3638 case KEY_MOD1:
3639 if ( !bExecDrawTextLink )
3640 {
3642 {
3643 // ctrl+left-click on outline node frame
3644 SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3645 if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3646 {
3648 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
3649 {
3651 return;
3652 }
3653 }
3654 }
3655 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3656 {
3657 m_rView.NoRotate();
3658 rSh.HideCursor();
3659 if ( rSh.IsSelFrameMode() )
3660 rSh.SelectObj(aDocPos, SW_ENTER_GROUP);
3661 else
3662 { if ( rSh.SelectObj( aDocPos, SW_ENTER_GROUP ) )
3663 {
3664 rSh.EnterSelFrameMode( &aDocPos );
3665 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3666 SwEditWin::s_nDDStartPosX = aDocPos.X();
3667 g_bFrameDrag = true;
3668 return;
3669 }
3670 }
3671 }
3672 else if( rSh.IsSelFrameMode() &&
3673 rSh.GetDrawView()->PickHandle( aDocPos ))
3674 {
3675 g_bFrameDrag = true;
3676 g_bNoInterrupt = false;
3677 return;
3678 }
3679 else
3680 {
3681 if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3682 {
3683 rSh.PushMode();
3684 g_bModePushed = true;
3685
3686 bool bUnLockView = !rSh.IsViewLocked();
3687 rSh.LockView( true );
3688 rSh.EnterAddMode();
3689 if( bUnLockView )
3690 rSh.LockView( false );
3691 }
3692 bCallBase = false;
3693 }
3694 }
3695 break;
3696 case KEY_MOD2:
3697 {
3698 if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3699 {
3700 rSh.PushMode();
3701 g_bModePushed = true;
3702 bool bUnLockView = !rSh.IsViewLocked();
3703 rSh.LockView( true );
3704 rSh.EnterBlockMode();
3705 if( bUnLockView )
3706 rSh.LockView( false );
3707 }
3708 bCallBase = false;
3709 }
3710 break;
3711 case KEY_SHIFT:
3712 {
3713 if (nNumberOfClicks == 2)
3714 {
3715 // Left mouse button, shift, double-click: see if we have a graphic and
3716 // dispatch its dialog in this case.
3718 {
3720 FN_FORMAT_GRAFIC_DLG, nullptr,
3721 SfxCallMode::RECORD | SfxCallMode::SLOT);
3722 return;
3723 }
3724 }
3725
3726 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3727 {
3728 m_rView.NoRotate();
3729 rSh.HideCursor();
3730 if ( rSh.IsSelFrameMode() )
3731 {
3732 rSh.SelectObj(aDocPos, SW_ADD_SELECT);
3733
3734 const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
3735 if (rMarkList.GetMark(0) == nullptr)
3736 {
3737 rSh.LeaveSelFrameMode();
3738 m_rView.AttrChangedNotify(nullptr);
3739 g_bFrameDrag = false;
3740 }
3741 }
3742 else
3743 { if ( rSh.SelectObj( aDocPos ) )
3744 {
3745 rSh.EnterSelFrameMode( &aDocPos );
3746 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3747 SwEditWin::s_nDDStartPosX = aDocPos.X();
3748 g_bFrameDrag = true;
3749 return;
3750 }
3751 }
3752 }
3753 else
3754 {
3755 bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
3756 if (bShould)
3757 {
3758 // Left mouse button, shift, non-double-click, not a draw object and
3759 // have an object to select: select it.
3760 rSh.HideCursor();
3761 bool bSelObj = rSh.SelectObj(aDocPos);
3762 if (bSelObj)
3763 {
3764 rSh.EnterSelFrameMode(&aDocPos);
3765 }
3766 return;
3767 }
3768
3769 if ( rSh.IsSelFrameMode() &&
3770 rSh.IsInsideSelectedObj( aDocPos ) )
3771 {
3772 rSh.EnterSelFrameMode( &aDocPos );
3773 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3774 SwEditWin::s_nDDStartPosX = aDocPos.X();
3775 g_bFrameDrag = true;
3776 return;
3777 }
3778 if ( rSh.IsSelFrameMode() )
3779 {
3780 rSh.UnSelectFrame();
3781 rSh.LeaveSelFrameMode();
3782 m_rView.AttrChangedNotify(nullptr);
3783 g_bFrameDrag = false;
3784 }
3785 if ( !rSh.IsExtMode() )
3786 {
3787 // don't start a selection when an
3788 // URL field or a graphic is clicked
3789 bool bSttSelect = rSh.HasSelection() ||
3790 PointerStyle::RefHand != GetPointer();
3791
3792 if( !bSttSelect )
3793 {
3794 bSttSelect = true;
3795 if( bExecHyperlinks )
3796 {
3797 SwContentAtPos aContentAtPos(
3800
3801 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) )
3802 {
3803 if( !rSh.IsViewLocked() &&
3804 !rSh.IsReadOnlyAvailable() &&
3805 aContentAtPos.IsInProtectSect() )
3806 bLockView = true;
3807
3808 bSttSelect = false;
3809 }
3810 else if( rSh.IsURLGrfAtPos( aDocPos ))
3811 bSttSelect = false;
3812 }
3813 }
3814
3815 if( bSttSelect )
3816 rSh.SttSelect();
3817 }
3818 }
3819 bCallBase = false;
3820 break;
3821 }
3822 default:
3823 if( !rSh.IsViewLocked() )
3824 {
3827 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3828 !rSh.IsReadOnlyAvailable() &&
3829 aContentAtPos.IsInProtectSect() )
3830 bLockView = true;
3831 }
3832 }
3833
3834 if ( rSh.IsGCAttr() )
3835 {
3836 rSh.GCAttr();
3837 rSh.ClearGCAttr();
3838 }
3839
3841 bool bEditableFieldClicked = false;
3842
3843 // Are we clicking on a field?
3844 if (rSh.GetContentAtPos(aDocPos, aFieldAtPos))
3845 {
3846 bool bEditableField = (aFieldAtPos.pFndTextAttr != nullptr
3847 && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD);
3848
3849 if (!bEditableField)
3850 {
3851 rSh.CallSetCursor(&aDocPos, bOnlyText);
3852 // Unfortunately the cursor may be on field
3853 // position or on position after field depending on which
3854 // half of the field was clicked on.
3855 SwTextAttr const*const pTextField(aFieldAtPos.pFndTextAttr);
3856 if (pTextField &&
3857 rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() != pTextField->GetStart())
3858 {
3859 assert(rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() == (pTextField->GetStart() + 1));
3860 rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
3861 }
3862 // don't go into the !bOverSelect block below - it moves
3863 // the cursor
3864 break;
3865 }
3866 else
3867 {
3868 bEditableFieldClicked = true;
3869 }
3870 }
3871
3872 bool bOverSelect = rSh.TestCurrPam( aDocPos );
3873 bool bOverURLGrf = false;
3874 if( !bOverSelect )
3875 bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
3876
3877 if ( !bOverSelect || rSh.IsInSelect() )
3878 {
3879 MoveCursor( rSh, aDocPos, bOnlyText, bLockView );
3880 bCallBase = false;
3881 }
3882 if (!bOverURLGrf && !bExecDrawTextLink && !bOnlyText)
3883 {
3884 const SelectionType nSelType = rSh.GetSelectionType();
3885 // Check in general, if an object is selectable at given position.
3886 // Thus, also text fly frames in background become selectable via Ctrl-Click.
3887 if ( ( nSelType & SelectionType::Ole ||
3888 nSelType & SelectionType::Graphic ||
3889 rSh.IsObjSelectable( aDocPos ) ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3890 {
3891 SwMvContext aMvContext( &rSh );
3892 rSh.EnterSelFrameMode();
3893 bCallBase = false;
3894 }
3895 }
3896 if ( !bOverSelect && bEditableFieldClicked && (!pCursorField ||
3897 pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
3898 {
3899 // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
3900 // and CH_TXT_ATR_INPUTFIELDEND
3901 rSh.SttSelect();
3902 rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
3903 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
3904 }
3905 // don't reset here any longer so that, in case through MouseMove
3906 // with pressed Ctrl key a multiple-selection should happen,
3907 // the previous selection is not released in Drag.
3908 break;
3909 }
3910 }
3911 }
3912 else if (MOUSE_RIGHT == aMEvt.GetButtons())
3913 {
3915 && aMEvt.GetModifier() == KEY_MOD1)
3916 {
3917 // ctrl+right-click on outline node frame
3918 SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3919 if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3920 {
3922 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
3923 {
3925 return;
3926 }
3927 }
3928 }
3929 else if (!aMEvt.GetModifier() && static_cast<sal_uInt8>(aMEvt.GetClicks() % 4) == 1
3930 && !rSh.TestCurrPam(aDocPos))
3931 {
3933
3934 // Are we clicking on a field?
3936 && rSh.GetContentAtPos(aDocPos, aFieldAtPos)
3937 && aFieldAtPos.pFndTextAttr != nullptr
3938 && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD
3939 && (!pCursorField || pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
3940 {
3941 // Move the cursor
3942 MoveCursor( rSh, aDocPos, rSh.IsObjSelectable( aDocPos ), m_bWasShdwCursor );
3943 bCallBase = false;
3944
3945 // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
3946 // and CH_TXT_ATR_INPUTFIELDEND
3947 rSh.SttSelect();
3948 rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
3949 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
3950 }
3951 }
3952 }
3953
3954 if (bCallBase)
3955 Window::MouseButtonDown(aMEvt);
3956}
3957
3958bool SwEditWin::changeMousePointer(Point const & rDocPoint)
3959{
3960 SwWrtShell & rShell = m_rView.GetWrtShell();
3961
3962 SwTab nMouseTabCol;
3963 if ( SwTab::COL_NONE != (nMouseTabCol = rShell.WhichMouseTabCol( rDocPoint ) ) &&
3964 !rShell.IsObjSelectable( rDocPoint ) )
3965 {
3966 PointerStyle nPointer = PointerStyle::Null;
3967 bool bChkTableSel = false;
3968
3969 switch ( nMouseTabCol )
3970 {
3971 case SwTab::COL_VERT :
3972 case SwTab::ROW_HORI :
3973 nPointer = PointerStyle::VSizeBar;
3974 bChkTableSel = true;
3975 break;
3976 case SwTab::ROW_VERT :
3977 case SwTab::COL_HORI :
3978 nPointer = PointerStyle::HSizeBar;
3979 bChkTableSel = true;
3980 break;
3981 // Enhanced table selection
3982 case SwTab::SEL_HORI :
3983 nPointer = PointerStyle::TabSelectSE;
3984 break;
3985 case SwTab::SEL_HORI_RTL :
3986 case SwTab::SEL_VERT :
3987 nPointer = PointerStyle::TabSelectSW;
3988 break;
3989 case SwTab::COLSEL_HORI :
3990 case SwTab::ROWSEL_VERT :
3991 nPointer = PointerStyle::TabSelectS;
3992 break;
3993 case SwTab::ROWSEL_HORI :
3994 nPointer = PointerStyle::TabSelectE;
3995 break;
3997 case SwTab::COLSEL_VERT :
3998 nPointer = PointerStyle::TabSelectW;
3999 break;
4000 default: break; // prevent compiler warning
4001 }
4002
4003 if ( PointerStyle::Null != nPointer &&
4004 // i#35543 - Enhanced table selection is explicitly allowed in table mode
4005 ( !bChkTableSel || !rShell.IsTableMode() ) &&
4007 {
4008 SetPointer( nPointer );
4009 }
4010
4011 return true;
4012 }
4013 else if (rShell.IsNumLabel(rDocPoint, RULER_MOUSE_MARGINWIDTH))
4014 {
4015 // i#42921 - consider vertical mode
4016 SwTextNode* pNodeAtPos = rShell.GetNumRuleNodeAtPos( rDocPoint );
4017 const PointerStyle nPointer =
4018 SwFEShell::IsVerticalModeAtNdAndPos( *pNodeAtPos, rDocPoint )
4019 ? PointerStyle::VSizeBar
4020 : PointerStyle::HSizeBar;
4021 SetPointer( nPointer );
4022
4023 return true;
4024 }
4025 return false;
4026}
4027
4029{
4030 MouseEvent rMEvt(_rMEvt);
4031
4033 {
4035 {
4036 pWindow->MouseMove(rMEvt);
4037 return;
4038 }
4039 }
4040
4041 //ignore key modifiers for format paintbrush
4042 {
4043 bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
4044 && m_pApplyTempl->m_pFormatClipboard->HasContent();
4045 if( bExecFormatPaintbrush )
4046 rMEvt = MouseEvent( _rMEvt.GetPosPixel(), _rMEvt.GetClicks(),
4047 _rMEvt.GetMode(), _rMEvt.GetButtons() );
4048 }
4049
4050 // as long as an action is running the MouseMove should be disconnected
4051 // otherwise bug 40102 occurs
4053 if( rSh.ActionPend() )
4054 return ;
4055
4057 {
4058 // add/remove outline content hide button
4059 const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4061 SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
4062 if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
4063 {
4064 // mouse pointer is on an outline paragraph node
4065 if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
4066 {
4067 // Get the outline paragraph frame and compare it to the saved outline frame. If they
4068 // are not the same, remove the fold button from the saved outline frame, if not
4069 // already removed, and then add a fold button to the mouse over outline frame if
4070 // the content is not folded.
4071 SwContentFrame* pContentFrame =
4072 aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout());
4073 if (pContentFrame != m_pSavedOutlineFrame)
4074 {
4076 {
4078 {
4080 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4082 {
4085 }
4086 }
4087 }
4088 m_pSavedOutlineFrame = static_cast<SwTextFrame*>(pContentFrame);
4089 }
4090 // show fold button if outline content is visible
4091 if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
4094 }
4095 }
4096 else if (m_pSavedOutlineFrame)
4097 {
4098 // The saved frame may not still be in the document, e.g., when an outline paragraph
4099 // is deleted. This causes the call to GetTextNodeFirst to behave badly. Use
4100 // isFrameAreaDefinitionValid to check if the frame is still in the document.
4102 {
4103 // current pointer pos is not over an outline frame
4104 // previous pointer pos was over an outline frame
4105 // remove outline content visibility button if showing
4107 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4109 {
4112 }
4113 }
4114 m_pSavedOutlineFrame = nullptr;
4115 }
4116 }
4117
4118 if( m_pShadCursor && 0 != (rMEvt.GetModifier() + rMEvt.GetButtons() ) )
4119 {
4120 m_pShadCursor.reset();
4121 }
4122
4123 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly();
4124
4125 CurrShell aCurr( &rSh );
4126
4127 //aPixPt == Point in Pixel, relative to ChildWin
4128 //aDocPt == Point in Twips, document coordinates
4129 const Point aPixPt( rMEvt.GetPosPixel() );
4130 const Point aDocPt( PixelToLogic( aPixPt ) );
4131
4132 if ( IsChainMode() )
4133 {
4134 UpdatePointer( aDocPt, rMEvt.GetModifier() );
4135 return;
4136 }
4137
4138 SdrView *pSdrView = rSh.GetDrawView();
4139
4140 const SwCallMouseEvent aLastCallEvent( m_aSaveCallEvent );
4142
4143 if ( !bIsDocReadOnly && pSdrView && pSdrView->MouseMove(rMEvt,GetOutDev()) )
4144 {
4145 SetPointer( PointerStyle::Text );
4146 return; // evaluate SdrView's event
4147 }
4148
4149 const Point aOldPt( rSh.VisArea().Pos() );
4150 const bool bInsWin = rSh.VisArea().Contains( aDocPt ) || comphelper::LibreOfficeKit::isActive();
4151
4153 {
4154 if (m_pSavedOutlineFrame && !bInsWin)
4155 {
4156 // the mouse pointer has left the building (edit window)
4157 // remove the outline content visibility button if showing
4159 {
4160 const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4163 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4165 {
4168 }
4169 }
4170 m_pSavedOutlineFrame = nullptr;
4171 }
4172 }
4173
4174 if( m_pShadCursor && !bInsWin )
4175 {
4176 m_pShadCursor.reset();
4177 }
4178
4179 if( bInsWin && m_xRowColumnSelectionStart )
4180 {
4181 EnterArea();
4182 Point aPos( aDocPt );
4184 return;
4185 }
4186
4187 // position is necessary for OS/2 because obviously after a MB-Down
4188 // a MB-Move is called immediately.
4189 if( g_bDDTimerStarted )
4190 {
4192 aDD = LogicToPixel( aDD );
4193 tools::Rectangle aRect( aDD.X()-3, aDD.Y()-3, aDD.X()+3, aDD.Y()+3 );
4194 if ( !aRect.Contains( aPixPt ) )
4195 StopDDTimer( &rSh, aDocPt );
4196 }
4197
4199 {
4200 if( m_bInsDraw )
4201 {
4202 m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4203 if ( !bInsWin )
4204 {
4205 Point aTmp( aDocPt );
4206 aTmp += rSh.VisArea().Pos() - aOldPt;
4207 LeaveArea( aTmp );
4208 }
4209 else
4210 EnterArea();
4211 return;
4212 }
4213 else if(!rSh.IsFrameSelected() && !rSh.IsObjSelected())
4214 {
4215 SfxBindings &rBnd = rSh.GetView().GetViewFrame().GetBindings();
4216 Point aRelPos = rSh.GetRelativePagePosition(aDocPt);
4217 if(aRelPos.X() >= 0)
4218 {
4219 FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebView*>( &GetView()) != nullptr );
4220 SW_MOD()->PutItem(SfxUInt16Item(SID_ATTR_METRIC, static_cast< sal_uInt16 >(eMetric)));
4221 const SfxPointItem aTmp1( SID_ATTR_POSITION, aRelPos );
4222 rBnd.SetState( aTmp1 );
4223 }
4224 else
4225 {
4226 rBnd.Invalidate(SID_ATTR_POSITION);
4227 }
4228 rBnd.Invalidate(SID_ATTR_SIZE);
4229 const SvxStatusItem aCell( SID_TABLE_CELL, OUString(), StatusCategory::NONE );
4230 rBnd.SetState( aCell );
4231 }
4232 }
4233
4234 // determine if we only change the mouse pointer and return
4235 if (!bIsDocReadOnly && bInsWin && !m_pApplyTempl && !rSh.IsInSelect() && changeMousePointer(aDocPt))
4236 {
4237 return;
4238 }
4239
4240 bool bDelShadCursor = true;
4241
4242 switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4243 {
4244 case MOUSE_LEFT:
4245 if( m_pAnchorMarker )
4246 {
4247 // Now we need to refresh the SdrHdl pointer of m_pAnchorMarker.
4248 // This looks a little bit tricky, but it solves the following
4249 // problem: the m_pAnchorMarker contains a pointer to an SdrHdl,
4250 // if the FindAnchorPos-call cause a scrolling of the visible
4251 // area, it's possible that the SdrHdl will be destroyed and a
4252 // new one will initialized at the original position(GetHdlPos).
4253 // So the m_pAnchorMarker has to find the right SdrHdl, if it's
4254 // the old one, it will find it with position aOld, if this one
4255 // is destroyed, it will find a new one at position GetHdlPos().
4256
4257 const Point aOld = m_pAnchorMarker->GetPosForHitTest( *(rSh.GetOut()) );
4258 Point aNew = rSh.FindAnchorPos( aDocPt );
4259 SdrHdl* pHdl;
4260 if( pSdrView && (nullptr!=( pHdl = pSdrView->PickHandle( aOld ) )||
4261 nullptr !=(pHdl = pSdrView->PickHandle( m_pAnchorMarker->GetHdlPos()) ) ) &&
4262 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
4263 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
4264 {
4265 m_pAnchorMarker->ChgHdl( pHdl );
4266 if( aNew.X() || aNew.Y() )
4267 {
4268 m_pAnchorMarker->SetPos( aNew );
4269 m_pAnchorMarker->SetLastPos( aDocPt );
4270 }
4271 }
4272 else
4273 {
4274 m_pAnchorMarker.reset();
4275 }
4276 }
4277 if ( m_bInsDraw )
4278 {
4279 if ( !m_bMBPressed )
4280 break;
4281 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4282 {
4283 if ( !bInsWin )
4284 LeaveArea( aDocPt );
4285 else
4286 EnterArea();
4287 if ( m_rView.GetDrawFuncPtr() )
4288 {
4289 pSdrView->SetOrtho(false);
4290 m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4291 }
4292 m_bIsInMove = true;
4293 }
4294 return;
4295 }
4296
4297 {
4298 SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
4299 if (pWrdCnt)
4300 pWrdCnt->UpdateCounts();
4301 }
4302 [[fallthrough]];
4303
4304 case MOUSE_LEFT + KEY_SHIFT:
4305 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4306 if ( !m_bMBPressed )
4307 break;
4308 [[fallthrough]];
4309 case MOUSE_LEFT + KEY_MOD1:
4310 if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4311 {
4312 if( !m_bMBPressed )
4313 break;
4314
4315 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4316 {
4317 // event processing for resizing
4318 if (pSdrView && pSdrView->AreObjectsMarked())
4319 {
4320 const Point aSttPt( PixelToLogic( m_aStartPos ) );
4321
4322 // can we start?
4323 if( SdrHdlKind::User == g_eSdrMoveHdl )
4324 {
4325 SdrHdl* pHdl = pSdrView->PickHandle( aSttPt );
4326 g_eSdrMoveHdl = pHdl ? pHdl->GetKind() : SdrHdlKind::Move;
4327 }
4328
4329 const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4330 const SvxMacro* pMacro = nullptr;
4331
4332 SvMacroItemId nEvent = SdrHdlKind::Move == g_eSdrMoveHdl
4333 ? SvMacroItemId::SwFrmMove
4334 : SvMacroItemId::SwFrmResize;
4335
4336 if (nullptr != pFlyFormat)
4337 pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4338 if (nullptr != pMacro &&
4339 // or notify only e.g. every 20 Twip?
4340 m_aRszMvHdlPt != aDocPt )
4341 {
4342 m_aRszMvHdlPt = aDocPt;
4343 sal_uInt32 nPos = 0;
4344 SbxArrayRef xArgs = new SbxArray;
4345 SbxVariableRef xVar = new SbxVariable;
4346 xVar->PutString( pFlyFormat->GetName() );
4347 xArgs->Put(xVar.get(), ++nPos);
4348
4349 if( SvMacroItemId::SwFrmResize == nEvent )
4350 {
4351 xVar = new SbxVariable;
4352 xVar->PutUShort( static_cast< sal_uInt16 >(g_eSdrMoveHdl) );
4353 xArgs->Put(xVar.get(), ++nPos);
4354 }
4355
4356 xVar = new SbxVariable;
4357 xVar->PutLong( aDocPt.X() - aSttPt.X() );
4358 xArgs->Put(xVar.get(), ++nPos);
4359 xVar = new SbxVariable;
4360 xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4361 xArgs->Put(xVar.get(), ++nPos);
4362
4363 OUString sRet;
4364
4365 ReleaseMouse();
4366
4367 rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
4368
4369 CaptureMouse();
4370
4371 if( !sRet.isEmpty() && sRet.toInt32()!=0 )
4372 return ;
4373 }
4374 }
4375 // event processing for resizing
4376
4377 if( bIsDocReadOnly )
4378 break;
4379
4380 bool bResizeKeepRatio = rSh.GetSelectionType() & SelectionType::Graphic ||
4383 bool bisResize = g_eSdrMoveHdl != SdrHdlKind::Move;
4384
4385 if (pSdrView)
4386 {
4387 // Resize proportionally when media is selected and the user drags on a corner
4388 const Point aSttPt(PixelToLogic(m_aStartPos));
4389 SdrHdl* pHdl = pSdrView->PickHandle(aSttPt);
4390 if (pHdl)
4391 bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
4392
4393 if (pSdrView->GetDragMode() == SdrDragMode::Crop)
4394 bisResize = false;
4395 if (rMEvt.IsShift())
4396 {
4397 pSdrView->SetAngleSnapEnabled(!bResizeKeepRatio);
4398 if (bisResize)
4399 pSdrView->SetOrtho(!bResizeKeepRatio);
4400 else
4401 pSdrView->SetOrtho(true);
4402 }
4403 else
4404 {
4405 pSdrView->SetAngleSnapEnabled(bResizeKeepRatio);
4406 if (bisResize)
4407 pSdrView->SetOrtho(bResizeKeepRatio);
4408 else
4409 pSdrView->SetOrtho(false);
4410 }
4411 }
4412
4413 rSh.Drag( &aDocPt, rMEvt.IsShift() );
4414 m_bIsInMove = true;
4415 }
4416 else if( bIsDocReadOnly )
4417 break;
4418
4419 if ( !bInsWin )
4420 {
4421 Point aTmp( aDocPt );
4422 aTmp += rSh.VisArea().Pos() - aOldPt;
4423 LeaveArea( aTmp );
4424 }
4425 else if(m_bIsInMove)
4426 EnterArea();
4427 return;
4428 }
4429 if ( !rSh.IsSelFrameMode() && !g_bDDINetAttr &&
4430 (IsMinMove( m_aStartPos,aPixPt ) || m_bIsInMove) &&
4431 (rSh.IsInSelect() || !rSh.TestCurrPam( aDocPt )) )
4432 {
4433 if ( pSdrView )
4434 {
4435 if ( rMEvt.IsShift() )
4436 pSdrView->SetOrtho(true);
4437 else
4438 pSdrView->SetOrtho(false);
4439 }
4440 if ( !bInsWin )
4441 {
4442 Point aTmp( aDocPt );
4443 aTmp += rSh.VisArea().Pos() - aOldPt;
4444 LeaveArea( aTmp );
4445 }
4446 else
4447 {
4448 if( !rMEvt.IsSynthetic() &&
4449 ( MOUSE_LEFT != rMEvt.GetButtons() ||
4450 KEY_MOD1 != rMEvt.GetModifier() ||
4451 !rSh.Is_FnDragEQBeginDrag() ||
4452 rSh.IsAddMode() ) )
4453 {
4454 rSh.Drag( &aDocPt, false );
4455
4456 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4457 EnterArea();
4458 }
4459 }
4460 }
4461 g_bDDINetAttr = false;
4462 break;
4463 case 0:
4464 {
4465 if ( m_pApplyTempl )
4466 {
4467 UpdatePointer(aDocPt); // maybe a frame has to be marked here
4468 break;
4469 }
4470 // change ui if mouse is over SwPostItField
4471 // TODO: do the same thing for redlines IsAttrAtPos::Redline
4472 SwContentAtPos aContentAtPos( IsAttrAtPos::Field);
4473 if (rSh.GetContentAtPos(aDocPt, aContentAtPos, false))
4474 {
4475 const SwField* pField = aContentAtPos.aFnd.pField;
4476 if (pField->Which()== SwFieldIds::Postit)
4477 {
4478 m_rView.GetPostItMgr()->SetShadowState(reinterpret_cast<const SwPostItField*>(pField),false);
4479 }
4480 else
4481 m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4482 }
4483 else
4484 m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4485 [[fallthrough]];
4486 }
4487 case KEY_SHIFT:
4488 case KEY_MOD2:
4489 case KEY_MOD1:
4490 if ( !m_bInsDraw )
4491 {
4492 bool bTstShdwCursor = true;
4493
4494 UpdatePointer( aDocPt, rMEvt.GetModifier() );
4495
4496 const SwFrameFormat* pFormat = nullptr;
4497 const SwFormatINetFormat* pINet = nullptr;
4498 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
4499 if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
4500 pINet = static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr);
4501
4502 const void* pTmp = pINet;
4503
4504 if( pINet ||
4505 nullptr != ( pTmp = pFormat = rSh.GetFormatFromAnyObj( aDocPt )))
4506 {
4507 bTstShdwCursor = false;
4508 if( pTmp == pINet )
4509 m_aSaveCallEvent.Set( pINet );
4510 else
4511 {
4512 IMapObject* pIMapObj = pFormat->GetIMapObject( aDocPt );
4513 if( pIMapObj )
4514 m_aSaveCallEvent.Set( pFormat, pIMapObj );
4515 else
4517 }
4518
4519 // should be over an InternetField with an
4520 // embedded macro?
4521 if( m_aSaveCallEvent != aLastCallEvent )
4522 {
4523 if( aLastCallEvent.HasEvent() )
4524 rSh.CallEvent( SvMacroItemId::OnMouseOut,
4525 aLastCallEvent, true );
4526 // 0 says that the object doesn't have any table
4527 if( !rSh.CallEvent( SvMacroItemId::OnMouseOver,
4530 }
4531 }
4532 else if( aLastCallEvent.HasEvent() )
4533 {
4534 // cursor was on an object
4535 rSh.CallEvent( SvMacroItemId::OnMouseOut,
4536 aLastCallEvent, true );
4537 }
4538
4539 if( bTstShdwCursor && bInsWin && !bIsDocReadOnly &&
4540 !m_bInsFrame &&
4541 !rSh.GetViewOptions()->getBrowseMode() &&
4542 rSh.GetViewOptions()->IsShadowCursor() &&
4543 !(rMEvt.GetModifier() + rMEvt.GetButtons()) &&
4544 !rSh.HasSelection() && !GetOutDev()->GetConnectMetaFile() )
4545 {
4546 SwRect aRect;
4547 sal_Int16 eOrient;
4549 if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, eOrient ))
4550 {
4551 if( !m_pShadCursor )
4552 m_pShadCursor.reset( new SwShadowCursor( *this,
4554 if( text::HoriOrientation::RIGHT != eOrient && text::HoriOrientation::CENTER != eOrient )
4555 eOrient = text::HoriOrientation::LEFT;
4556 m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(eOrient) );
4557 bDelShadCursor = false;
4558 }
4559 }
4560 }
4561 break;
4562 case MOUSE_LEFT + KEY_MOD2:
4563 if( rSh.IsBlockMode() && !rMEvt.IsSynthetic() )
4564 {
4565 rSh.Drag( &aDocPt, false );
4566 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4567 EnterArea();
4568 }
4569 break;
4570 }
4571
4572 if( bDelShadCursor && m_pShadCursor )
4573 {
4574 m_pShadCursor.reset();
4575 }
4576 m_bWasShdwCursor = false;
4577}
4578
4583{
4585 {
4587 {
4588 pWindow->MouseButtonUp(rMEvt);
4589 return;
4590 }
4591 }
4592
4593 bool bCallBase = true;
4594
4595 bool bCallShadowCursor = m_bWasShdwCursor;
4596 m_bWasShdwCursor = false;
4597 if( m_pShadCursor )
4598 {
4599 m_pShadCursor.reset();
4600 }
4601
4603
4604 SdrHdlKind eOldSdrMoveHdl = g_eSdrMoveHdl;
4605 g_eSdrMoveHdl = SdrHdlKind::User; // for MoveEvents - reset again
4606
4607 // preventively reset
4608 m_rView.SetTabColFromDoc( false );
4610
4612 CurrShell aCurr( &rSh );
4613 SdrView *pSdrView = rSh.GetDrawView();
4614 if ( pSdrView )
4615 {
4616 // tdf34555: ortho was always reset before being used in EndSdrDrag
4617 // Now, it is reset only if not in Crop mode.
4618 if (pSdrView->GetDragMode() != SdrDragMode::Crop && !rMEvt.IsShift())
4619 pSdrView->SetOrtho(false);
4620
4621 if ( pSdrView->MouseButtonUp( rMEvt,GetOutDev() ) )
4622 {
4624 return; // SdrView's event evaluated
4625 }
4626 }
4627 // only process MouseButtonUp when the Down went to that windows as well.
4628 if ( !m_bMBPressed )
4629 {
4630 // Undo for the watering can is already in CommandHdl
4631 // that's the way it should be!
4632
4633 return;
4634 }
4635
4636 Point aDocPt( PixelToLogic( rMEvt.GetPosPixel() ) );
4637
4638 if ( g_bDDTimerStarted )
4639 {
4640 StopDDTimer( &rSh, aDocPt );
4641 m_bMBPressed = false;
4642 if ( rSh.IsSelFrameMode() )
4643 {
4644 rSh.EndDrag( &aDocPt, false );
4645 g_bFrameDrag = false;
4646 }
4647 g_bNoInterrupt = false;
4648 const Point aDocPos( PixelToLogic( rMEvt.GetPosPixel() ) );
4649 if ((PixelToLogic(m_aStartPos).Y() == (aDocPos.Y())) && (PixelToLogic(m_aStartPos).X() == (aDocPos.X())))//To make sure it was not moved
4650 {
4651 SdrPageView* pPV = nullptr;
4652 SdrObject* pObj = pSdrView ? pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
4653 if (pObj)
4654 {
4655 SwFrameFormat* pFormat = GetUserCall(pObj)->GetFormat();
4657 if (!pShapeFormat)
4658 {
4659 pSdrView->UnmarkAllObj();
4660 pSdrView->MarkObj(pObj,pPV);
4661 }
4662 else
4663 {
4664 // If the fly frame is a textbox of a shape, then select the shape instead.
4665 SdrObject* pShape = pShapeFormat->FindSdrObject();
4666 pSdrView->UnmarkAllObj();
4667 pSdrView->MarkObj(pShape, pPV);
4668 }
4669 }
4670 }
4671 ReleaseMouse();
4672 return;
4673 }
4674
4675 if( m_pAnchorMarker )
4676 {
4677 if(m_pAnchorMarker->GetHdl())
4678 {
4679 // #i121463# delete selected after drag
4680 m_pAnchorMarker->GetHdl()->SetSelected(false);
4681 }
4682
4683 Point aPnt( m_pAnchorMarker->GetLastPos() );
4684 m_pAnchorMarker.reset();
4685 if( aPnt.X() || aPnt.Y() )
4686 rSh.FindAnchorPos( aPnt, true );
4687 }
4689 {
4690 if ( m_rView.GetDrawFuncPtr()->MouseButtonUp( rMEvt ) )
4691 {
4692 if (m_rView.GetDrawFuncPtr()) // could have been destroyed in MouseButtonUp
4693 {
4695
4696 if (!m_rView.IsDrawMode())
4697 {
4698 m_rView.SetDrawFuncPtr(nullptr);
4700 rBind.Invalidate( SID_ATTR_SIZE );
4701 rBind.Invalidate( SID_TABLE_CELL );
4702 }
4703 }
4704
4705 if ( rSh.IsObjSelected() )
4706 {
4707 rSh.EnterSelFrameMode();
4708 if (!m_rView.GetDrawFuncPtr())
4709 StdDrawMode( SdrObjKind::NONE, true );
4710 }
4711 else if ( rSh.IsFrameSelected() )
4712 {
4713 rSh.EnterSelFrameMode();
4714 StopInsFrame();
4715 }
4716 else
4717 {
4718 const Point aDocPos( PixelToLogic( m_aStartPos ) );
4719 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4720 rSh.Edit();
4721 }
4722
4723 m_rView.AttrChangedNotify(nullptr);
4724 }
4725 else if (rMEvt.GetButtons() == MOUSE_RIGHT && rSh.IsDrawCreate())
4726 m_rView.GetDrawFuncPtr()->BreakCreate(); // abort drawing
4727
4728 g_bNoInterrupt = false;
4729 if (IsMouseCaptured())
4730 ReleaseMouse();
4731 return;
4732 }
4733 bool bPopMode = false;
4734 switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4735 {
4736 case MOUSE_LEFT:
4737 if ( m_bInsDraw && rSh.IsDrawCreate() )
4738 {
4740 {
4742 m_rView.AttrChangedNotify(nullptr);
4743 if ( rSh.IsObjSelected() )
4744 rSh.EnterSelFrameMode();
4746 StopInsFrame();
4747 }
4748 bCallBase = false;
4749 break;
4750 }
4751 [[fallthrough]];
4752 case MOUSE_LEFT + KEY_MOD1:
4753 case MOUSE_LEFT + KEY_MOD2:
4754 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4755 if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4756 {
4757 if ( rMEvt.IsMod1() ) // copy and don't move.
4758 {
4759 // abort drag, use internal Copy instead
4760 tools::Rectangle aRect;
4761 rSh.GetDrawView()->TakeActionRect( aRect );
4762 if (!aRect.IsEmpty())
4763 {
4764 rSh.BreakDrag();
4765 Point aEndPt, aSttPt;
4767 {
4768 aEndPt = aRect.TopLeft();
4769 aSttPt = rSh.GetDrawView()->GetAllMarkedRect().TopLeft();
4770 }
4771 else
4772 {
4773 aEndPt = aRect.Center();
4774 aSttPt = rSh.GetDrawView()->GetAllMarkedRect().Center();
4775 }
4776 if ( aSttPt != aEndPt )
4777 {
4779 rSh.Copy(rSh, aSttPt, aEndPt);
4781 }
4782 }
4783 else {
4784 rSh.EndDrag( &aDocPt, false );
4785 }
4786 }
4787 else
4788 {
4789 {
4790 const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4791 const SvxMacro* pMacro = nullptr;
4792
4793 SvMacroItemId nEvent = SdrHdlKind::Move == eOldSdrMoveHdl
4794 ? SvMacroItemId::SwFrmMove
4795 : SvMacroItemId::SwFrmResize;
4796
4797 if (nullptr != pFlyFormat)
4798 pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4799 if (nullptr != pMacro)
4800 {
4801 const Point aSttPt( PixelToLogic( m_aStartPos ) );
4802 m_aRszMvHdlPt = aDocPt;
4803 sal_uInt32 nPos = 0;
4804 SbxArrayRef xArgs = new SbxArray;
4805 SbxVariableRef xVar = new SbxVariable;
4806 xVar->PutString( pFlyFormat->GetName() );
4807 xArgs->Put(xVar.get(), ++nPos);
4808
4809 if( SvMacroItemId::SwFrmResize == nEvent )
4810 {
4811 xVar = new SbxVariable;
4812 xVar->PutUShort( static_cast< sal_uInt16 >(eOldSdrMoveHdl) );
4813 xArgs->Put(xVar.get(), ++nPos);
4814 }
4815
4816 xVar = new SbxVariable;
4817 xVar->PutLong( aDocPt.X() - aSttPt.X() );
4818 xArgs->Put(xVar.get(), ++nPos);
4819 xVar = new SbxVariable;
4820 xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4821 xArgs->Put(xVar.get(), ++nPos);
4822
4823 xVar = new SbxVariable;
4824 xVar->PutUShort( 1 );
4825 xArgs->Put(xVar.get(), ++nPos);
4826
4827 ReleaseMouse();
4828
4829 rSh.ExecMacro( *pMacro, nullptr, xArgs.get() );
4830
4831 CaptureMouse();
4832 }
4833
4834 if (pFlyFormat)
4835 {
4836 // See if the fly frame's anchor is in a content control. If so,
4837 // interact with it.
4838 const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
4839 SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
4840 if (pAnchorNode)
4841 {
4842 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
4843 if (pTextNode)
4844 {
4845 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
4848 if (pAttr)
4849 {
4850 SwTextContentControl* pTextContentControl
4851 = static_txtattr_cast<SwTextContentControl*>(pAttr);
4852 const SwFormatContentControl& rFormatContentControl
4853 = pTextContentControl->GetContentControl();
4854 rSh.GotoContentControl(rFormatContentControl);
4855 }
4856 }
4857 }
4858 }
4859 }
4860 rSh.EndDrag( &aDocPt, false );
4861 }
4862 g_bFrameDrag = false;
4863 bCallBase = false;
4864 break;
4865 }
4866 bPopMode = true;
4867 [[fallthrough]];
4868 case MOUSE_LEFT + KEY_SHIFT:
4869 if (rSh.IsSelFrameMode())
4870 {
4871
4872 rSh.EndDrag( &aDocPt, false );
4873 g_bFrameDrag = false;
4874 bCallBase = false;
4875 break;
4876 }
4877
4878 if( g_bHoldSelection )
4879 {
4880 // the EndDrag should be called in any case
4881 g_bHoldSelection = false;
4882 rSh.EndDrag( &aDocPt, false );
4883 }
4884 else
4885 {
4886 SwContentAtPos aFieldAtPos ( IsAttrAtPos::Field );
4887 if ( !rSh.