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