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