Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / docvw / edtwin.cxx
blobba62bb8fa8566eca10d80755eac8568eacb8782b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <swtypes.hxx>
23 #include <hintids.hxx>
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>
35 #include <comphelper/scopeguard.hxx>
36 #include <comphelper/string.hxx>
38 #include <vcl/dialoghelper.hxx>
39 #include <vcl/inputctx.hxx>
40 #include <vcl/help.hxx>
41 #include <vcl/weld.hxx>
42 #include <vcl/ptrstyle.hxx>
43 #include <svl/macitem.hxx>
44 #include <unotools/securityoptions.hxx>
45 #include <basic/sbxvar.hxx>
46 #include <svl/ctloptions.hxx>
47 #include <basic/sbx.hxx>
48 #include <svl/eitem.hxx>
49 #include <svl/stritem.hxx>
50 #include <sfx2/ipclient.hxx>
51 #include <sfx2/viewfrm.hxx>
52 #include <sfx2/request.hxx>
53 #include <sfx2/bindings.hxx>
54 #include <sfx2/dispatch.hxx>
55 #include <svl/ptitem.hxx>
56 #include <editeng/sizeitem.hxx>
57 #include <editeng/langitem.hxx>
58 #include <svx/statusitem.hxx>
59 #include <svx/svdview.hxx>
60 #include <svx/svdhdl.hxx>
61 #include <svx/svdoutl.hxx>
62 #include <editeng/editeng.hxx>
63 #include <editeng/editview.hxx>
64 #include <editeng/svxacorr.hxx>
65 #include <editeng/flditem.hxx>
66 #include <editeng/colritem.hxx>
67 #include <unotools/charclass.hxx>
68 #include <unotools/datetime.hxx>
70 #include <comphelper/lok.hxx>
71 #include <sfx2/lokhelper.hxx>
73 #include <editeng/acorrcfg.hxx>
74 #include <bookmark.hxx>
75 #include <SwSmartTagMgr.hxx>
76 #include <edtdd.hxx>
77 #include <edtwin.hxx>
78 #include <view.hxx>
79 #include <wrtsh.hxx>
80 #include <IDocumentDrawModelAccess.hxx>
81 #include <IDocumentUndoRedo.hxx>
82 #include <textboxhelper.hxx>
83 #include <dcontact.hxx>
84 #include <fldbas.hxx>
85 #include <swmodule.hxx>
86 #include <docsh.hxx>
87 #include <viewopt.hxx>
88 #include <drawbase.hxx>
89 #include <dselect.hxx>
90 #include <textsh.hxx>
91 #include <shdwcrsr.hxx>
92 #include <txatbase.hxx>
93 #include <fmtanchr.hxx>
94 #include <fmtornt.hxx>
95 #include <fmthdft.hxx>
96 #include <frmfmt.hxx>
97 #include <modcfg.hxx>
98 #include <fmtcol.hxx>
99 #include <wview.hxx>
100 #include <gloslst.hxx>
101 #include <inputwin.hxx>
102 #include <gloshdl.hxx>
103 #include <swundo.hxx>
104 #include <drwtxtsh.hxx>
105 #include <fchrfmt.hxx>
106 #include "romenu.hxx"
107 #include <initui.hxx>
108 #include <frmatr.hxx>
109 #include <extinput.hxx>
110 #include <acmplwrd.hxx>
111 #include <swcalwrp.hxx>
112 #include <swdtflvr.hxx>
113 #include <breakit.hxx>
114 #include <checkit.hxx>
115 #include <pagefrm.hxx>
117 #include <helpids.h>
118 #include <cmdid.h>
119 #include <uitool.hxx>
120 #include <fmtfollowtextflow.hxx>
121 #include <toolkit/helper/vclunohelper.hxx>
122 #include <charfmt.hxx>
123 #include <numrule.hxx>
124 #include <pagedesc.hxx>
125 #include <svtools/ruler.hxx>
126 #include <formatclipboard.hxx>
127 #include <vcl/svapp.hxx>
128 #include <wordcountdialog.hxx>
129 #include <fmtfld.hxx>
131 #include <IMark.hxx>
132 #include <doc.hxx>
133 #include <xmloff/odffields.hxx>
135 #include <PostItMgr.hxx>
136 #include <FrameControlsManager.hxx>
137 #include <AnnotationWin.hxx>
139 #include <algorithm>
140 #include <vector>
142 #include <rootfrm.hxx>
144 #include <unotools/syslocaleoptions.hxx>
145 #include <i18nlangtag/mslangid.hxx>
146 #include <salhelper/singletonref.hxx>
147 #include <sfx2/event.hxx>
148 #include <memory>
150 #include "../../core/crsr/callnk.hxx"
151 #include <IDocumentOutlineNodes.hxx>
152 #include <ndtxt.hxx>
153 #include <cntfrm.hxx>
154 #include <txtfrm.hxx>
155 #include <strings.hrc>
156 #include <textcontentcontrol.hxx>
157 #include <contentcontrolbutton.hxx>
159 using namespace sw::mark;
160 using namespace ::com::sun::star;
163 * Globals
165 static bool g_bInputLanguageSwitched = false;
167 // Usually in MouseButtonUp a selection is revoked when the selection is
168 // not currently being pulled open. Unfortunately in MouseButtonDown there
169 // is being selected at double/triple click. That selection is completely
170 // finished in the Handler and thus can't be distinguished in the Up.
171 // To resolve this g_bHoldSelection is set in Down and evaluated in Up.
172 static bool g_bHoldSelection = false;
174 bool g_bFrameDrag = false;
175 static bool g_bValidCursorPos = false;
176 bool g_bModePushed = false;
177 bool g_bDDTimerStarted = false;
178 bool g_bDDINetAttr = false;
179 static SdrHdlKind g_eSdrMoveHdl = SdrHdlKind::User;
181 QuickHelpData* SwEditWin::s_pQuickHlpData = nullptr;
183 tools::Long SwEditWin::s_nDDStartPosY = 0;
184 tools::Long SwEditWin::s_nDDStartPosX = 0;
186 static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView );
188 /// Check if the selected shape has a TextBox: if so, go into that instead.
189 static bool lcl_goIntoTextBox(SwEditWin& rEditWin, SwWrtShell& rSh)
191 SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0);
192 if (!pMark)
193 return false;
195 SdrObject* pSdrObject = pMark->GetMarkedSdrObj();
196 SwFrameFormat* pObjectFormat = ::FindFrameFormat(pSdrObject);
197 if (SwFrameFormat* pTextBoxFormat = SwTextBoxHelper::getOtherTextBoxFormat(pObjectFormat, RES_DRAWFRMFMT))
199 SdrObject* pTextBox = pTextBoxFormat->FindRealSdrObject();
200 SdrView* pSdrView = rSh.GetDrawView();
201 // Unmark the shape.
202 pSdrView->UnmarkAllObj();
203 // Mark the textbox.
204 rSh.SelectObj(Point(), SW_ALLOW_TEXTBOX, pTextBox);
205 // Clear the DrawFuncPtr.
206 rEditWin.StopInsFrame();
207 return true;
209 return false;
212 class SwAnchorMarker
214 SdrHdl* m_pHdl;
215 Point m_aHdlPos;
216 Point m_aLastPos;
217 bool m_bTopRightHandle;
218 public:
219 explicit SwAnchorMarker( SdrHdl* pH )
220 : m_pHdl( pH )
221 , m_aHdlPos( pH->GetPos() )
222 , m_aLastPos( pH->GetPos() )
223 , m_bTopRightHandle( pH->GetKind() == SdrHdlKind::Anchor_TR )
225 const Point& GetLastPos() const { return m_aLastPos; }
226 void SetLastPos( const Point& rNew ) { m_aLastPos = rNew; }
227 void SetPos( const Point& rNew ) { m_pHdl->SetPos( rNew ); }
228 const Point& GetHdlPos() const { return m_aHdlPos; }
229 SdrHdl* GetHdl() const { return m_pHdl; }
230 void ChgHdl( SdrHdl* pNew )
232 m_pHdl = pNew;
233 if ( m_pHdl )
235 m_bTopRightHandle = (m_pHdl->GetKind() == SdrHdlKind::Anchor_TR);
238 Point GetPosForHitTest( const OutputDevice& rOut )
240 Point aHitTestPos( m_pHdl->GetPos() );
241 aHitTestPos = rOut.LogicToPixel( aHitTestPos );
242 if ( m_bTopRightHandle )
244 aHitTestPos += Point( -1, 1 );
246 else
248 aHitTestPos += Point( 1, 1 );
250 aHitTestPos = rOut.PixelToLogic( aHitTestPos );
252 return aHitTestPos;
256 /// Assists with auto-completion of AutoComplete words and AutoText names.
257 struct QuickHelpData
259 /// Strings that at least partially match an input word, and match length.
260 std::vector<std::pair<OUString, sal_uInt16>> m_aHelpStrings;
261 /// Index of the current help string.
262 sal_uInt16 nCurArrPos;
263 static constexpr sal_uInt16 nNoPos = std::numeric_limits<sal_uInt16>::max();
265 /// Help data stores AutoText names rather than AutoComplete words.
266 bool m_bIsAutoText;
267 /// Display help string as a tip rather than inline.
268 bool m_bIsTip;
269 /// Tip ID when a help string is displayed as a tip.
270 void* nTipId;
271 /// Append a space character to the displayed help string (if appropriate).
272 bool m_bAppendSpace;
274 /// Help string is currently displayed.
275 bool m_bIsDisplayed;
277 QuickHelpData() { ClearContent(); }
279 void Move( QuickHelpData& rCpy );
280 void ClearContent();
281 void Start(SwWrtShell& rSh, bool bRestart);
282 void Stop( SwWrtShell& rSh );
284 bool HasContent() const { return !m_aHelpStrings.empty() && nCurArrPos != nNoPos; }
285 const OUString& CurStr() const { return m_aHelpStrings[nCurArrPos].first; }
286 sal_uInt16 CurLen() const { return m_aHelpStrings[nCurArrPos].second; }
288 /// Next help string.
289 void Next( bool bEndLess )
291 if( ++nCurArrPos >= m_aHelpStrings.size() )
292 nCurArrPos = (bEndLess && !m_bIsAutoText ) ? 0 : nCurArrPos-1;
294 /// Previous help string.
295 void Previous( bool bEndLess )
297 if( 0 == nCurArrPos-- )
298 nCurArrPos = (bEndLess && !m_bIsAutoText ) ? m_aHelpStrings.size()-1 : 0;
301 // Fills internal structures with hopefully helpful information.
302 void FillStrArr( SwWrtShell const & rSh, const OUString& rWord );
303 void SortAndFilter(const OUString &rOrigWord);
307 * Avoid minimal movement shiver
309 #define HIT_PIX 2 /* hit tolerance in pixel */
310 #define MIN_MOVE 4
312 static bool IsMinMove(const Point &rStartPos, const Point &rLPt)
314 return std::abs(rStartPos.X() - rLPt.X()) > MIN_MOVE ||
315 std::abs(rStartPos.Y() - rLPt.Y()) > MIN_MOVE;
319 * For MouseButtonDown - determine whether a DrawObject
320 * a NO SwgFrame was hit! Shift/Ctrl should only result
321 * in selecting, with DrawObjects; at SwgFlys to trigger
322 * hyperlinks if applicable (Download/NewWindow!)
324 static bool IsDrawObjSelectable( const SwWrtShell& rSh, const Point& rPt )
326 bool bRet = true;
327 SdrObject* pObj;
328 switch( rSh.GetObjCntType( rPt, pObj ))
330 case OBJCNT_NONE:
331 case OBJCNT_FLY:
332 case OBJCNT_GRF:
333 case OBJCNT_OLE:
334 bRet = false;
335 break;
336 default:; //prevent warning
338 return bRet;
342 * Switch pointer
344 void SwEditWin::UpdatePointer(const Point &rLPt, sal_uInt16 nModifier )
346 SetQuickHelpText(OUString());
347 SwWrtShell &rSh = m_rView.GetWrtShell();
348 if( m_pApplyTempl )
350 PointerStyle eStyle = PointerStyle::Fill;
351 if ( rSh.IsOverReadOnlyPos( rLPt ) )
353 m_pUserMarker.reset();
355 eStyle = PointerStyle::NotAllowed;
357 else
359 SwRect aRect;
360 SwRect* pRect = &aRect;
361 const SwFrameFormat* pFormat = nullptr;
363 bool bFrameIsValidTarget = false;
364 if( m_pApplyTempl->m_pFormatClipboard )
365 bFrameIsValidTarget = m_pApplyTempl->m_pFormatClipboard->HasContentForThisType( SelectionType::Frame );
366 else if( !m_pApplyTempl->nColor )
367 bFrameIsValidTarget = ( m_pApplyTempl->eType == SfxStyleFamily::Frame );
369 if( bFrameIsValidTarget &&
370 nullptr !=(pFormat = rSh.GetFormatFromObj( rLPt, &pRect )) &&
371 dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
373 //turn on highlight for frame
374 tools::Rectangle aTmp( pRect->SVRect() );
376 if ( !m_pUserMarker )
378 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
381 else
383 m_pUserMarker.reset();
386 rSh.SwCursorShell::SetVisibleCursor( rLPt );
388 SetPointer( eStyle );
389 return;
392 if( !rSh.VisArea().Width() )
393 return;
395 CurrShell aCurr(&rSh);
397 if ( IsChainMode() )
399 SwRect aRect;
400 SwChainRet nChainable = rSh.Chainable( aRect, *rSh.GetFlyFrameFormat(), rLPt );
401 PointerStyle eStyle = nChainable != SwChainRet::OK
402 ? PointerStyle::ChainNotAllowed : PointerStyle::Chain;
403 if ( nChainable == SwChainRet::OK )
405 tools::Rectangle aTmp( aRect.SVRect() );
407 if ( !m_pUserMarker )
409 m_pUserMarker.reset(new SdrDropMarkerOverlay( *rSh.GetDrawView(), aTmp ));
412 else
414 m_pUserMarker.reset();
417 SetPointer( eStyle );
418 return;
421 bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
422 if ( !bExecHyperlinks )
424 const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
425 if ( ( bSecureOption && nModifier == KEY_MOD1 ) ||
426 ( !bSecureOption && nModifier != KEY_MOD1 ) )
427 bExecHyperlinks = true;
430 const bool bExecSmarttags = nModifier == KEY_MOD1;
432 SdrView *pSdrView = rSh.GetDrawView();
433 bool bPrefSdrPointer = false;
434 bool bHitHandle = false;
435 bool bCntAtPos = false;
436 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
437 rSh.IsCursorReadonly();
438 m_aActHitType = SdrHitKind::NONE;
439 PointerStyle eStyle = PointerStyle::Text;
440 if ( !pSdrView )
441 bCntAtPos = true;
442 else if ( (bHitHandle = (pSdrView->PickHandle(rLPt) != nullptr)) )
444 m_aActHitType = SdrHitKind::Object;
445 bPrefSdrPointer = true;
447 else
449 const bool bNotInSelObj = !rSh.IsInsideSelectedObj( rLPt );
450 if ( m_rView.GetDrawFuncPtr() && !m_bInsDraw && bNotInSelObj )
452 m_aActHitType = SdrHitKind::Object;
453 if (IsObjectSelect())
454 eStyle = PointerStyle::Arrow;
455 else
456 bPrefSdrPointer = true;
458 else
460 SdrPageView* pPV = nullptr;
461 pSdrView->SetHitTolerancePixel( HIT_PIX );
462 SdrObject* pObj = (bNotInSelObj && bExecHyperlinks) ?
463 pSdrView->PickObj(rLPt, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) :
464 nullptr;
465 if (pObj)
467 SdrObjMacroHitRec aTmp;
468 aTmp.aPos = rLPt;
469 aTmp.pPageView = pPV;
470 SetPointer( pObj->GetMacroPointer( aTmp ) );
471 return;
473 else
475 // dvo: IsObjSelectable() eventually calls SdrView::PickObj, so
476 // apparently this is used to determine whether this is a
477 // drawling layer object or not.
478 if ( rSh.IsObjSelectable( rLPt ) )
480 if (pSdrView->IsTextEdit())
482 m_aActHitType = SdrHitKind::NONE;
483 bPrefSdrPointer = true;
485 else
487 SdrViewEvent aVEvt;
488 SdrHitKind eHit = pSdrView->PickAnything(rLPt, aVEvt);
490 if (eHit == SdrHitKind::UrlField && bExecHyperlinks)
492 m_aActHitType = SdrHitKind::Object;
493 bPrefSdrPointer = true;
495 else
497 // if we're over a selected object, we show an
498 // ARROW by default. We only show a MOVE if 1) the
499 // object is selected, and 2) it may be moved
500 // (i.e., position is not protected).
501 bool bMovable =
502 (!bNotInSelObj) &&
503 (rSh.IsObjSelected() || rSh.IsFrameSelected()) &&
504 (rSh.IsSelObjProtected(FlyProtectFlags::Pos) == FlyProtectFlags::NONE);
506 SdrObject* pSelectableObj = rSh.GetObjAt(rLPt);
507 // Don't update pointer if this is a background image only.
508 if (pSelectableObj->GetLayer() != rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId())
509 eStyle = bMovable ? PointerStyle::Move : PointerStyle::Arrow;
510 m_aActHitType = SdrHitKind::Object;
514 else
516 if ( rSh.IsFrameSelected() && !bNotInSelObj )
518 // dvo: this branch appears to be dead and should be
519 // removed in a future version. Reason: The condition
520 // !bNotInSelObj means that this branch will only be
521 // executed in the cursor points inside a selected
522 // object. However, if this is the case, the previous
523 // if( rSh.IsObjSelectable(rLPt) ) must always be true:
524 // rLPt is inside a selected object, then obviously
525 // rLPt is over a selectable object.
526 if (rSh.IsSelObjProtected(FlyProtectFlags::Size) != FlyProtectFlags::NONE)
527 eStyle = PointerStyle::NotAllowed;
528 else
529 eStyle = PointerStyle::Move;
530 m_aActHitType = SdrHitKind::Object;
532 else
534 if ( m_rView.GetDrawFuncPtr() )
535 bPrefSdrPointer = true;
536 else
537 bCntAtPos = true;
543 if ( bPrefSdrPointer )
545 if (bIsDocReadOnly || (rSh.IsObjSelected() && rSh.IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE))
546 SetPointer( PointerStyle::NotAllowed );
547 else
549 if (m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->IsInsertForm() && !bHitHandle)
550 SetPointer( PointerStyle::DrawRect );
551 else
552 SetPointer( pSdrView->GetPreferredPointer( rLPt, rSh.GetOut() ) );
555 else
557 if( !rSh.IsPageAtPos( rLPt ) || m_pAnchorMarker )
558 eStyle = PointerStyle::Arrow;
559 else
561 // Even if we already have something, prefer URLs if possible.
562 SwContentAtPos aUrlPos(IsAttrAtPos::InetAttr);
563 if (bCntAtPos || rSh.GetContentAtPos(rLPt, aUrlPos))
565 SwContentAtPos aSwContentAtPos(
566 IsAttrAtPos::Field |
567 IsAttrAtPos::ClickField |
568 IsAttrAtPos::InetAttr |
569 IsAttrAtPos::Ftn |
570 IsAttrAtPos::SmartTag);
571 if( rSh.GetContentAtPos( rLPt, aSwContentAtPos) )
573 // Is edit inline input field
574 if (IsAttrAtPos::Field == aSwContentAtPos.eContentAtPos
575 && aSwContentAtPos.pFndTextAttr != nullptr
576 && aSwContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD)
578 const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
579 if (!(pCursorField && pCursorField == aSwContentAtPos.pFndTextAttr->GetFormatField().GetField()))
580 eStyle = PointerStyle::RefHand;
582 else
584 const bool bClickToFollow = IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos ||
585 IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos;
586 if( !bClickToFollow ||
587 (IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos && bExecHyperlinks) ||
588 (IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos && bExecSmarttags) )
589 eStyle = PointerStyle::RefHand;
592 else if (GetView().GetWrtShell().GetViewOptions()->IsShowOutlineContentVisibilityButton())
594 aSwContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
595 if (rSh.GetContentAtPos(rLPt, aSwContentAtPos))
597 if (IsAttrAtPos::Outline == aSwContentAtPos.eContentAtPos)
599 if (nModifier == KEY_MOD1)
601 eStyle = PointerStyle::RefHand;
602 // set quick help
603 if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
605 const SwNodes& rNds = GetView().GetWrtShell().GetDoc()->GetNodes();
606 SwOutlineNodes::size_type nPos;
607 rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos);
608 SwOutlineNodes::size_type nOutlineNodesCount
609 = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
610 int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
611 OUString sQuickHelp(SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY));
612 if (!rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent()
613 && nPos + 1 < nOutlineNodesCount
614 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos + 1) > nLevel)
615 sQuickHelp += " (" + SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
616 SetQuickHelpText(sQuickHelp);
625 // which kind of text pointer have we to show - horz / vert - ?
626 if( PointerStyle::Text == eStyle && rSh.IsInVerticalText( &rLPt ))
627 eStyle = PointerStyle::TextVertical;
628 else if (rSh.GetViewOptions()->CanHideWhitespace() &&
629 rSh.GetLayout()->IsBetweenPages(rLPt))
631 if (rSh.GetViewOptions()->IsHideWhitespaceMode())
632 eStyle = PointerStyle::ShowWhitespace;
633 else
634 eStyle = PointerStyle::HideWhitespace;
637 SetPointer( eStyle );
642 * Increase timer for selection
644 IMPL_LINK_NOARG(SwEditWin, TimerHandler, Timer *, void)
646 SwWrtShell &rSh = m_rView.GetWrtShell();
647 Point aModPt( m_aMovePos );
648 const SwRect aOldVis( rSh.VisArea() );
649 bool bDone = false;
651 if ( !rSh.VisArea().Contains( aModPt ) )
653 if ( m_bInsDraw )
655 const int nMaxScroll = 40;
656 m_rView.Scroll( tools::Rectangle(aModPt,Size(1,1)), nMaxScroll, nMaxScroll);
657 bDone = true;
659 else if ( g_bFrameDrag )
661 rSh.Drag(&aModPt, false);
662 bDone = true;
664 if ( !bDone )
665 aModPt = rSh.GetContentPos( aModPt,aModPt.Y() > rSh.VisArea().Bottom() );
667 if ( !bDone && !(g_bFrameDrag || m_bInsDraw) )
669 if ( m_xRowColumnSelectionStart )
671 Point aPos( aModPt );
672 rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag );
674 else
675 rSh.CallSetCursor( &aModPt, false );
677 // It can be that a "jump" over a table cannot be accomplished like
678 // that. So we jump over the table by Up/Down here.
679 const SwRect& rVisArea = rSh.VisArea();
680 if( aOldVis == rVisArea && !rSh.IsStartOfDoc() && !rSh.IsEndOfDoc() )
682 // take the center point of VisArea to
683 // decide in which direction the user want.
684 if( aModPt.Y() < ( rVisArea.Top() + rVisArea.Height() / 2 ) )
685 rSh.Up( true );
686 else
687 rSh.Down( true );
691 m_aMovePos += rSh.VisArea().Pos() - aOldVis.Pos();
692 JustifyAreaTimer();
695 void SwEditWin::JustifyAreaTimer()
697 const tools::Rectangle &rVisArea = GetView().GetVisArea();
698 #ifdef UNX
699 const tools::Long coMinLen = 100;
700 #else
701 const tools::Long coMinLen = 50;
702 #endif
703 tools::Long const nTimeout = 800,
704 nDiff = std::max(
705 std::max( m_aMovePos.Y() - rVisArea.Bottom(), rVisArea.Top() - m_aMovePos.Y() ),
706 std::max( m_aMovePos.X() - rVisArea.Right(), rVisArea.Left() - m_aMovePos.X()));
707 m_aTimer.SetTimeout( std::max( coMinLen, nTimeout - nDiff*2L) );
710 void SwEditWin::LeaveArea(const Point &rPos)
712 m_aMovePos = rPos;
713 JustifyAreaTimer();
714 if( !m_aTimer.IsActive() )
715 m_aTimer.Start();
716 m_pShadCursor.reset();
719 inline void SwEditWin::EnterArea()
721 m_aTimer.Stop();
725 * Insert mode for frames
727 void SwEditWin::InsFrame(sal_uInt16 nCols)
729 StdDrawMode(SdrObjKind::NewFrame, false);
730 m_bInsFrame = true;
731 m_nInsFrameColCount = nCols;
734 void SwEditWin::StdDrawMode( SdrObjKind eSdrObjectKind, bool bObjSelect )
736 SetSdrDrawMode( eSdrObjectKind );
738 if (bObjSelect)
739 m_rView.SetDrawFuncPtr(std::make_unique<DrawSelection>( &m_rView.GetWrtShell(), this, &m_rView ));
740 else
741 m_rView.SetDrawFuncPtr(std::make_unique<SwDrawBase>( &m_rView.GetWrtShell(), this, &m_rView ));
743 m_rView.SetSelDrawSlot();
744 SetSdrDrawMode( eSdrObjectKind );
745 if (bObjSelect)
746 m_rView.GetDrawFuncPtr()->Activate( SID_OBJECT_SELECT );
747 else
748 m_rView.GetDrawFuncPtr()->Activate( sal::static_int_cast< sal_uInt16 >(eSdrObjectKind) );
749 m_bInsFrame = false;
750 m_nInsFrameColCount = 1;
753 void SwEditWin::StopInsFrame()
755 if (m_rView.GetDrawFuncPtr())
757 m_rView.GetDrawFuncPtr()->Deactivate();
758 m_rView.SetDrawFuncPtr(nullptr);
760 m_rView.LeaveDrawCreate(); // leave construction mode
761 m_bInsFrame = false;
762 m_nInsFrameColCount = 1;
765 bool SwEditWin::IsInputSequenceCheckingRequired( const OUString &rText, const SwPaM& rCursor )
767 if ( !SvtCTLOptions::IsCTLFontEnabled() ||
768 !SvtCTLOptions::IsCTLSequenceChecking() )
769 return false;
771 if ( 0 == rCursor.Start()->GetContentIndex() ) /* first char needs not to be checked */
772 return false;
774 SwBreakIt *pBreakIter = SwBreakIt::Get();
775 uno::Reference < i18n::XBreakIterator > xBI = pBreakIter->GetBreakIter();
776 assert(xBI.is());
777 tools::Long nCTLScriptPos = -1;
779 if (xBI->getScriptType( rText, 0 ) == i18n::ScriptType::COMPLEX)
780 nCTLScriptPos = 0;
781 else
782 nCTLScriptPos = xBI->nextScript( rText, 0, i18n::ScriptType::COMPLEX );
784 return (0 <= nCTLScriptPos && nCTLScriptPos <= rText.getLength());
787 //return INVALID_HINT if language should not be explicitly overridden, the correct
788 //HintId to use for the eBufferLanguage otherwise
789 static sal_uInt16 lcl_isNonDefaultLanguage(LanguageType eBufferLanguage, SwView const & rView,
790 const OUString &rInBuffer)
792 sal_uInt16 nWhich = INVALID_HINT;
794 //If the option to IgnoreLanguageChange is set, short-circuit this method
795 //which results in the document/paragraph language remaining the same
796 //despite a change to the keyboard/input language
797 SvtSysLocaleOptions aSysLocaleOptions;
798 if(aSysLocaleOptions.IsIgnoreLanguageChange())
800 return INVALID_HINT;
803 bool bLang = true;
804 if(eBufferLanguage != LANGUAGE_DONTKNOW)
806 switch( SvtLanguageOptions::GetI18NScriptTypeOfLanguage( eBufferLanguage ))
808 case i18n::ScriptType::ASIAN: nWhich = RES_CHRATR_CJK_LANGUAGE; break;
809 case i18n::ScriptType::COMPLEX: nWhich = RES_CHRATR_CTL_LANGUAGE; break;
810 case i18n::ScriptType::LATIN: nWhich = RES_CHRATR_LANGUAGE; break;
811 default: bLang = false;
813 if(bLang)
815 SfxItemSet aLangSet(rView.GetPool(), nWhich, nWhich);
816 SwWrtShell& rSh = rView.GetWrtShell();
817 rSh.GetCurAttr(aLangSet);
818 if(SfxItemState::DEFAULT <= aLangSet.GetItemState(nWhich))
820 LanguageType eLang = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage();
821 if ( eLang == eBufferLanguage )
823 // current language attribute equal to language reported from system
824 bLang = false;
826 else if ( !g_bInputLanguageSwitched && RES_CHRATR_LANGUAGE == nWhich )
828 // special case: switching between two "LATIN" languages
829 // In case the current keyboard setting might be suitable
830 // for both languages we can't safely assume that the user
831 // wants to use the language reported from the system,
832 // except if we knew that it was explicitly switched (thus
833 // the check for "bInputLangeSwitched").
835 // The language reported by the system could be just the
836 // system default language that the user is not even aware
837 // of, because no language selection tool is installed at
838 // all. In this case the OOo language should get preference
839 // as it might have been selected by the user explicitly.
841 // Usually this case happens if the OOo language is
842 // different to the system language but the system keyboard
843 // is still suitable for the OOo language (e.g. writing
844 // English texts with a German keyboard).
846 // For non-latin keyboards overwriting the attribute is
847 // still valid. We do this for cyrillic and greek ATM. In
848 // future versions of OOo this should be replaced by a
849 // configuration switch that allows to give the preference
850 // to the OOo setting or the system setting explicitly
851 // and/or a better handling of the script type.
852 i18n::UnicodeScript eType = !rInBuffer.isEmpty() ?
853 GetAppCharClass().getScript( rInBuffer, 0 ) :
854 i18n::UnicodeScript_kScriptCount;
856 bool bSystemIsNonLatin = false;
857 switch ( eType )
859 case i18n::UnicodeScript_kGreek:
860 case i18n::UnicodeScript_kCyrillic:
861 // in case other UnicodeScripts require special
862 // keyboards they can be added here
863 bSystemIsNonLatin = true;
864 break;
865 default:
866 break;
869 bool bOOoLangIsNonLatin = MsLangId::isNonLatinWestern( eLang);
871 bLang = (bSystemIsNonLatin != bOOoLangIsNonLatin);
876 return bLang ? nWhich : INVALID_HINT;
880 * Character buffer is inserted into the document
882 void SwEditWin::FlushInBuffer()
884 if ( m_aKeyInputFlushTimer.IsActive())
885 m_aKeyInputFlushTimer.Stop();
887 if ( m_aInBuffer.isEmpty() )
888 return;
890 SwWrtShell& rSh = m_rView.GetWrtShell();
892 // generate new sequence input checker if not already done
893 if ( !pCheckIt )
894 pCheckIt = new SwCheckIt;
896 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = pCheckIt->xCheck;
897 if ( xISC.is() && IsInputSequenceCheckingRequired( m_aInBuffer, *rSh.GetCursor() ) )
900 // apply (Thai) input sequence checking/correction
902 rSh.Push(); // push current cursor to stack
904 // get text from the beginning (i.e left side) of current selection
905 // to the start of the paragraph
906 rSh.NormalizePam(); // make point be the first (left) one
907 if (!rSh.GetCursor()->HasMark())
908 rSh.GetCursor()->SetMark();
909 rSh.GetCursor()->GetMark()->SetContent(0);
911 const OUString aOldText( rSh.GetCursor()->GetText() );
912 const sal_Int32 nOldLen = aOldText.getLength();
914 sal_Int32 nExpandSelection = 0;
915 if (nOldLen > 0)
917 sal_Int32 nTmpPos = nOldLen;
918 sal_Int16 nCheckMode = SvtCTLOptions::IsCTLSequenceCheckingRestricted() ?
919 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
921 OUString aNewText( aOldText );
922 if (SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace())
924 for( sal_Int32 k = 0; k < m_aInBuffer.getLength(); ++k)
926 const sal_Unicode cChar = m_aInBuffer[k];
927 const sal_Int32 nPrevPos =xISC->correctInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode );
929 // valid sequence or sequence could be corrected:
930 if (nPrevPos != aNewText.getLength())
931 nTmpPos = nPrevPos + 1;
934 // find position of first character that has changed
935 sal_Int32 nNewLen = aNewText.getLength();
936 const sal_Unicode *pOldText = aOldText.getStr();
937 const sal_Unicode *pNewText = aNewText.getStr();
938 sal_Int32 nChgPos = 0;
939 while ( nChgPos < nOldLen && nChgPos < nNewLen &&
940 pOldText[nChgPos] == pNewText[nChgPos] )
941 ++nChgPos;
943 const sal_Int32 nChgLen = nNewLen - nChgPos;
944 if (nChgLen)
946 m_aInBuffer = aNewText.copy( nChgPos, nChgLen );
947 nExpandSelection = nOldLen - nChgPos;
949 else
950 m_aInBuffer.clear();
952 else
954 for( sal_Int32 k = 0; k < m_aInBuffer.getLength(); ++k )
956 const sal_Unicode cChar = m_aInBuffer[k];
957 if (xISC->checkInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode ))
959 // character can be inserted:
960 aNewText += OUStringChar( cChar );
961 ++nTmpPos;
964 m_aInBuffer = aNewText.copy( aOldText.getLength() ); // copy new text to be inserted to buffer
968 // at this point now we will insert the buffer text 'normally' some lines below...
970 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
972 if (m_aInBuffer.isEmpty())
973 return;
975 // if text prior to the original selection needs to be changed
976 // as well, we now expand the selection accordingly.
977 SwPaM &rCursor = *rSh.GetCursor();
978 const sal_Int32 nCursorStartPos = rCursor.Start()->GetContentIndex();
979 OSL_ENSURE( nCursorStartPos >= nExpandSelection, "cannot expand selection as specified!!" );
980 if (nExpandSelection && nCursorStartPos >= nExpandSelection)
982 if (!rCursor.HasMark())
983 rCursor.SetMark();
984 rCursor.Start()->AdjustContent( -nExpandSelection );
988 uno::Reference< frame::XDispatchRecorder > xRecorder =
989 m_rView.GetViewFrame().GetBindings().GetRecorder();
990 if ( xRecorder.is() )
992 // determine shell
993 SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
994 // generate request and record
995 if (pSfxShell)
997 SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
998 aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, m_aInBuffer ) );
999 aReq.Done();
1003 sal_uInt16 nWhich = lcl_isNonDefaultLanguage(m_eBufferLanguage, m_rView, m_aInBuffer);
1004 if (nWhich != INVALID_HINT )
1006 SvxLanguageItem aLangItem( m_eBufferLanguage, nWhich );
1007 rSh.SetAttrItem( aLangItem );
1010 rSh.Insert( m_aInBuffer );
1011 m_eBufferLanguage = LANGUAGE_DONTKNOW;
1012 m_aInBuffer.clear();
1015 #define MOVE_LEFT_SMALL 0
1016 #define MOVE_UP_SMALL 1
1017 #define MOVE_RIGHT_BIG 2
1018 #define MOVE_DOWN_BIG 3
1019 #define MOVE_LEFT_BIG 4
1020 #define MOVE_UP_BIG 5
1021 #define MOVE_RIGHT_SMALL 6
1022 #define MOVE_DOWN_SMALL 7
1024 // #i121236# Support for shift key in writer
1025 #define MOVE_LEFT_HUGE 8
1026 #define MOVE_UP_HUGE 9
1027 #define MOVE_RIGHT_HUGE 10
1028 #define MOVE_DOWN_HUGE 11
1030 void SwEditWin::ChangeFly( sal_uInt8 nDir, bool bWeb )
1032 SwWrtShell &rSh = m_rView.GetWrtShell();
1033 SwRect aTmp = rSh.GetFlyRect();
1034 if( !aTmp.HasArea() ||
1035 rSh.IsSelObjProtected( FlyProtectFlags::Pos ) != FlyProtectFlags::NONE )
1036 return;
1038 SfxItemSetFixed<
1039 RES_FRM_SIZE, RES_FRM_SIZE,
1040 RES_PROTECT, RES_PROTECT,
1041 RES_VERT_ORIENT, RES_ANCHOR,
1042 RES_COL, RES_COL,
1043 RES_FOLLOW_TEXT_FLOW, RES_FOLLOW_TEXT_FLOW>
1044 aSet( rSh.GetAttrPool() );
1045 rSh.GetFlyFrameAttr( aSet );
1046 RndStdIds eAnchorId = aSet.Get(RES_ANCHOR).GetAnchorId();
1047 Size aSnap;
1048 bool bHuge(MOVE_LEFT_HUGE == nDir ||
1049 MOVE_UP_HUGE == nDir ||
1050 MOVE_RIGHT_HUGE == nDir ||
1051 MOVE_DOWN_HUGE == nDir);
1053 if(MOVE_LEFT_SMALL == nDir ||
1054 MOVE_UP_SMALL == nDir ||
1055 MOVE_RIGHT_SMALL == nDir ||
1056 MOVE_DOWN_SMALL == nDir )
1058 aSnap = PixelToLogic(Size(1,1));
1060 else
1062 aSnap = rSh.GetViewOptions()->GetSnapSize();
1063 short nDiv = rSh.GetViewOptions()->GetDivisionX();
1064 if ( nDiv > 0 )
1065 aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1066 nDiv = rSh.GetViewOptions()->GetDivisionY();
1067 if ( nDiv > 0 )
1068 aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1071 if(bHuge)
1073 // #i121236# 567twips == 1cm, but just take three times the normal snap
1074 aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1077 SwRect aBoundRect;
1078 Point aRefPoint;
1079 // adjustment for allowing vertical position
1080 // aligned to page for fly frame anchored to paragraph or to character.
1082 const SwFormatVertOrient& aVert( aSet.Get(RES_VERT_ORIENT) );
1083 const bool bFollowTextFlow =
1084 aSet.Get(RES_FOLLOW_TEXT_FLOW).GetValue();
1085 const SwFormatAnchor& rFormatAnchor = aSet.Get(RES_ANCHOR);
1086 rSh.CalcBoundRect( aBoundRect, eAnchorId,
1087 text::RelOrientation::FRAME, aVert.GetRelationOrient(),
1088 &rFormatAnchor, bFollowTextFlow,
1089 false, &aRefPoint );
1091 tools::Long nLeft = std::min( aTmp.Left() - aBoundRect.Left(), aSnap.Width() );
1092 tools::Long nRight = std::min( aBoundRect.Right() - aTmp.Right(), aSnap.Width() );
1093 tools::Long nUp = std::min( aTmp.Top() - aBoundRect.Top(), aSnap.Height() );
1094 tools::Long nDown = std::min( aBoundRect.Bottom() - aTmp.Bottom(), aSnap.Height() );
1096 switch ( nDir )
1098 case MOVE_LEFT_BIG:
1099 case MOVE_LEFT_HUGE:
1100 case MOVE_LEFT_SMALL: aTmp.Left( aTmp.Left() - nLeft );
1101 break;
1103 case MOVE_UP_BIG:
1104 case MOVE_UP_HUGE:
1105 case MOVE_UP_SMALL: aTmp.Top( aTmp.Top() - nUp );
1106 break;
1108 case MOVE_RIGHT_SMALL:
1109 if( aTmp.Width() < aSnap.Width() + MINFLY )
1110 break;
1111 nRight = aSnap.Width();
1112 [[fallthrough]];
1113 case MOVE_RIGHT_HUGE:
1114 case MOVE_RIGHT_BIG: aTmp.Left( aTmp.Left() + nRight );
1115 break;
1117 case MOVE_DOWN_SMALL:
1118 if( aTmp.Height() < aSnap.Height() + MINFLY )
1119 break;
1120 nDown = aSnap.Height();
1121 [[fallthrough]];
1122 case MOVE_DOWN_HUGE:
1123 case MOVE_DOWN_BIG: aTmp.Top( aTmp.Top() + nDown );
1124 break;
1126 default: OSL_ENSURE(true, "ChangeFly: Unknown direction." );
1128 bool bSet = false;
1129 if ((RndStdIds::FLY_AS_CHAR == eAnchorId) && ( nDir % 2 ))
1131 tools::Long aDiff = aTmp.Top() - aRefPoint.Y();
1132 if( aDiff > 0 )
1133 aDiff = 0;
1134 else if ( aDiff < -aTmp.Height() )
1135 aDiff = -aTmp.Height();
1136 SwFormatVertOrient aVert( aSet.Get(RES_VERT_ORIENT) );
1137 sal_Int16 eNew;
1138 if( bWeb )
1140 eNew = aVert.GetVertOrient();
1141 bool bDown = 0 != ( nDir & 0x02 );
1142 switch( eNew )
1144 case text::VertOrientation::CHAR_TOP:
1145 if( bDown ) eNew = text::VertOrientation::CENTER;
1146 break;
1147 case text::VertOrientation::CENTER:
1148 eNew = bDown ? text::VertOrientation::TOP : text::VertOrientation::CHAR_TOP;
1149 break;
1150 case text::VertOrientation::TOP:
1151 if( !bDown ) eNew = text::VertOrientation::CENTER;
1152 break;
1153 case text::VertOrientation::LINE_TOP:
1154 if( bDown ) eNew = text::VertOrientation::LINE_CENTER;
1155 break;
1156 case text::VertOrientation::LINE_CENTER:
1157 eNew = bDown ? text::VertOrientation::LINE_BOTTOM : text::VertOrientation::LINE_TOP;
1158 break;
1159 case text::VertOrientation::LINE_BOTTOM:
1160 if( !bDown ) eNew = text::VertOrientation::LINE_CENTER;
1161 break;
1162 default:; //prevent warning
1165 else
1167 aVert.SetPos( aDiff );
1168 eNew = text::VertOrientation::NONE;
1170 aVert.SetVertOrient( eNew );
1171 aSet.Put( aVert );
1172 bSet = true;
1174 if (bWeb && (RndStdIds::FLY_AT_PARA == eAnchorId)
1175 && ( nDir==MOVE_LEFT_SMALL || nDir==MOVE_RIGHT_BIG ))
1177 SwFormatHoriOrient aHori( aSet.Get(RES_HORI_ORIENT) );
1178 sal_Int16 eNew;
1179 eNew = aHori.GetHoriOrient();
1180 switch( eNew )
1182 case text::HoriOrientation::RIGHT:
1183 if( nDir==MOVE_LEFT_SMALL )
1184 eNew = text::HoriOrientation::LEFT;
1185 break;
1186 case text::HoriOrientation::LEFT:
1187 if( nDir==MOVE_RIGHT_BIG )
1188 eNew = text::HoriOrientation::RIGHT;
1189 break;
1190 default:; //prevent warning
1192 if( eNew != aHori.GetHoriOrient() )
1194 aHori.SetHoriOrient( eNew );
1195 aSet.Put( aHori );
1196 bSet = true;
1199 rSh.StartAllAction();
1200 if( bSet )
1201 rSh.SetFlyFrameAttr( aSet );
1202 bool bSetPos = (RndStdIds::FLY_AS_CHAR != eAnchorId);
1203 if(bSetPos && bWeb)
1205 bSetPos = RndStdIds::FLY_AT_PAGE == eAnchorId;
1207 if( bSetPos )
1208 rSh.SetFlyPos( aTmp.Pos() );
1209 rSh.EndAllAction();
1213 void SwEditWin::ChangeDrawing( sal_uInt8 nDir )
1215 // start undo action in order to get only one
1216 // undo action for this change.
1217 SwWrtShell &rSh = m_rView.GetWrtShell();
1218 rSh.StartUndo();
1220 tools::Long nX = 0;
1221 tools::Long nY = 0;
1222 const bool bOnePixel(
1223 MOVE_LEFT_SMALL == nDir ||
1224 MOVE_UP_SMALL == nDir ||
1225 MOVE_RIGHT_SMALL == nDir ||
1226 MOVE_DOWN_SMALL == nDir);
1227 const bool bHuge(
1228 MOVE_LEFT_HUGE == nDir ||
1229 MOVE_UP_HUGE == nDir ||
1230 MOVE_RIGHT_HUGE == nDir ||
1231 MOVE_DOWN_HUGE == nDir);
1232 SwMove nAnchorDir = SwMove::UP;
1233 switch(nDir)
1235 case MOVE_LEFT_SMALL:
1236 case MOVE_LEFT_HUGE:
1237 case MOVE_LEFT_BIG:
1238 nX = -1;
1239 nAnchorDir = SwMove::LEFT;
1240 break;
1241 case MOVE_UP_SMALL:
1242 case MOVE_UP_HUGE:
1243 case MOVE_UP_BIG:
1244 nY = -1;
1245 break;
1246 case MOVE_RIGHT_SMALL:
1247 case MOVE_RIGHT_HUGE:
1248 case MOVE_RIGHT_BIG:
1249 nX = +1;
1250 nAnchorDir = SwMove::RIGHT;
1251 break;
1252 case MOVE_DOWN_SMALL:
1253 case MOVE_DOWN_HUGE:
1254 case MOVE_DOWN_BIG:
1255 nY = +1;
1256 nAnchorDir = SwMove::DOWN;
1257 break;
1260 if(0 != nX || 0 != nY)
1262 FlyProtectFlags nProtect = rSh.IsSelObjProtected( FlyProtectFlags::Pos|FlyProtectFlags::Size );
1263 Size aSnap( rSh.GetViewOptions()->GetSnapSize() );
1264 short nDiv = rSh.GetViewOptions()->GetDivisionX();
1265 if ( nDiv > 0 )
1266 aSnap.setWidth( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Width()) / nDiv ) );
1267 nDiv = rSh.GetViewOptions()->GetDivisionY();
1268 if ( nDiv > 0 )
1269 aSnap.setHeight( std::max( sal_uLong(1), static_cast<sal_uLong>(aSnap.Height()) / nDiv ) );
1271 if(bOnePixel)
1273 aSnap = PixelToLogic(Size(1,1));
1275 else if(bHuge)
1277 // #i121236# 567twips == 1cm, but just take three times the normal snap
1278 aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
1281 nX *= aSnap.Width();
1282 nY *= aSnap.Height();
1284 SdrView *pSdrView = rSh.GetDrawView();
1285 const SdrHdlList& rHdlList = pSdrView->GetHdlList();
1286 SdrHdl* pHdl = rHdlList.GetFocusHdl();
1287 rSh.StartAllAction();
1288 if(nullptr == pHdl)
1290 // now move the selected draw objects
1291 // if the object's position is not protected
1292 if(!(nProtect&FlyProtectFlags::Pos))
1294 // Check if object is anchored as character and move direction
1295 bool bDummy1, bDummy2;
1296 const bool bVertAnchor = rSh.IsFrameVertical( true, bDummy1, bDummy2 );
1297 bool bHoriMove = !bVertAnchor == !( nDir % 2 );
1298 bool bMoveAllowed =
1299 !bHoriMove || (rSh.GetAnchorId() != RndStdIds::FLY_AS_CHAR);
1300 if ( bMoveAllowed )
1302 pSdrView->MoveAllMarked(Size(nX, nY));
1303 rSh.SetModified();
1307 else
1309 // move handle with index nHandleIndex
1310 if (nX || nY)
1312 if( SdrHdlKind::Anchor == pHdl->GetKind() ||
1313 SdrHdlKind::Anchor_TR == pHdl->GetKind() )
1315 // anchor move cannot be allowed when position is protected
1316 if(!(nProtect&FlyProtectFlags::Pos))
1317 rSh.MoveAnchor( nAnchorDir );
1319 //now resize if size is protected
1320 else if(!(nProtect&FlyProtectFlags::Size))
1322 // now move the Handle (nX, nY)
1323 Point aStartPoint(pHdl->GetPos());
1324 Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
1325 const SdrDragStat& rDragStat = pSdrView->GetDragStat();
1327 // start dragging
1328 pSdrView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
1330 if(pSdrView->IsDragObj())
1332 bool bWasNoSnap = rDragStat.IsNoSnap();
1333 bool bWasSnapEnabled = pSdrView->IsSnapEnabled();
1335 // switch snapping off
1336 if(!bWasNoSnap)
1337 const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
1338 if(bWasSnapEnabled)
1339 pSdrView->SetSnapEnabled(false);
1341 pSdrView->MovAction(aEndPoint);
1342 pSdrView->EndDragObj();
1343 rSh.SetModified();
1345 // restore snap
1346 if(!bWasNoSnap)
1347 const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
1348 if(bWasSnapEnabled)
1349 pSdrView->SetSnapEnabled(bWasSnapEnabled);
1354 rSh.EndAllAction();
1357 rSh.EndUndo();
1361 * KeyEvents
1363 void SwEditWin::KeyInput(const KeyEvent &rKEvt)
1365 SwWrtShell &rSh = m_rView.GetWrtShell();
1367 if (comphelper::LibreOfficeKit::isActive() && m_rView.GetPostItMgr())
1369 if (vcl::Window* pWindow = m_rView.GetPostItMgr()->GetActiveSidebarWin())
1371 pWindow->KeyInput(rKEvt);
1372 return;
1376 if( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE &&
1377 m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard )
1379 m_pApplyTempl->m_pFormatClipboard->Erase();
1380 SetApplyTemplate(SwApplyTemplate());
1381 m_rView.GetViewFrame().GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
1383 else if ( rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE &&
1384 rSh.IsHeaderFooterEdit( ) )
1386 bool bHeader = bool(FrameTypeFlags::HEADER & rSh.GetFrameType(nullptr,false));
1387 if ( bHeader )
1388 rSh.SttPg();
1389 else
1390 rSh.EndPg();
1391 rSh.ToggleHeaderFooterEdit();
1394 SfxObjectShell *pObjSh = m_rView.GetViewFrame().GetObjectShell();
1395 if ( m_bLockInput || (pObjSh && pObjSh->GetProgress()) )
1396 // When the progress bar is active or a progress is
1397 // running on a document, no order is being taken
1398 return;
1400 m_pShadCursor.reset();
1401 // Do not reset the timer here, otherwise when flooded with events it would never time out
1402 // if every key event stopped and started it again.
1403 comphelper::ScopeGuard keyInputFlushTimerStop([this]() { m_aKeyInputFlushTimer.Stop(); });
1405 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
1406 rSh.IsCursorReadonly();
1408 //if the language changes the buffer must be flushed
1409 LanguageType eNewLanguage = GetInputLanguage();
1410 if(!bIsDocReadOnly && m_eBufferLanguage != eNewLanguage && !m_aInBuffer.isEmpty())
1412 FlushInBuffer();
1414 m_eBufferLanguage = eNewLanguage;
1416 QuickHelpData aTmpQHD;
1417 if( s_pQuickHlpData->m_bIsDisplayed )
1419 aTmpQHD.Move( *s_pQuickHlpData );
1420 s_pQuickHlpData->Stop( rSh );
1423 // OS:the DrawView also needs a readonly-Flag as well
1424 if ( !bIsDocReadOnly && rSh.GetDrawView() && rSh.GetDrawView()->KeyInput( rKEvt, this ) )
1426 rSh.GetView().GetViewFrame().GetBindings().InvalidateAll( false );
1427 rSh.SetModified();
1428 return; // Event evaluated by SdrView
1431 if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
1433 StopInsFrame();
1434 rSh.Edit();
1437 bool bFlushBuffer = false;
1438 bool bNormalChar = false;
1439 bool bAppendSpace = s_pQuickHlpData->m_bAppendSpace;
1440 s_pQuickHlpData->m_bAppendSpace = false;
1442 if ( getenv("SW_DEBUG") && rKEvt.GetKeyCode().GetCode() == KEY_F12 )
1444 if( rKEvt.GetKeyCode().IsShift())
1446 GetView().GetDocShell()->GetDoc()->dumpAsXml();
1447 return;
1449 else
1451 SwRootFrame* pLayout = GetView().GetDocShell()->GetWrtShell()->GetLayout();
1452 pLayout->dumpAsXml( );
1453 return;
1457 KeyEvent aKeyEvent( rKEvt );
1458 // look for vertical mappings
1459 if( !bIsDocReadOnly && !rSh.IsSelFrameMode() && !rSh.IsObjSelected() )
1461 sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
1463 if( KEY_UP == nKey || KEY_DOWN == nKey ||
1464 KEY_LEFT == nKey || KEY_RIGHT == nKey )
1466 // In general, we want to map the direction keys if we are inside
1467 // some vertical formatted text.
1468 // 1. Exception: For a table cursor in a horizontal table, the
1469 // directions should never be mapped.
1470 // 2. Exception: For a table cursor in a vertical table, the
1471 // directions should always be mapped.
1472 const bool bVertText = rSh.IsInVerticalText();
1473 const bool bTableCursor = rSh.GetTableCursor();
1474 const bool bVertTable = rSh.IsTableVertical();
1475 if( ( bVertText && ( !bTableCursor || bVertTable ) ) ||
1476 ( bTableCursor && bVertTable ) )
1478 SvxFrameDirection eDirection = rSh.GetTextDirection();
1479 if (eDirection == SvxFrameDirection::Vertical_LR_BT)
1481 // Map from physical to logical, so rotate clockwise.
1482 if (KEY_UP == nKey)
1483 nKey = KEY_RIGHT;
1484 else if (KEY_DOWN == nKey)
1485 nKey = KEY_LEFT;
1486 else if (KEY_LEFT == nKey)
1487 nKey = KEY_UP;
1488 else /* KEY_RIGHT == nKey */
1489 nKey = KEY_DOWN;
1491 else
1493 // Attempt to integrate cursor travelling for mongolian layout does not work.
1494 // Thus, back to previous mapping of cursor keys to direction keys.
1495 if( KEY_UP == nKey ) nKey = KEY_LEFT;
1496 else if( KEY_DOWN == nKey ) nKey = KEY_RIGHT;
1497 else if( KEY_LEFT == nKey ) nKey = KEY_DOWN;
1498 else /* KEY_RIGHT == nKey */ nKey = KEY_UP;
1502 if ( rSh.IsInRightToLeftText() )
1504 if( KEY_LEFT == nKey ) nKey = KEY_RIGHT;
1505 else if( KEY_RIGHT == nKey ) nKey = KEY_LEFT;
1508 aKeyEvent = KeyEvent( rKEvt.GetCharCode(),
1509 vcl::KeyCode( nKey, rKEvt.GetKeyCode().GetModifier() ),
1510 rKEvt.GetRepeat() );
1514 const vcl::KeyCode& rKeyCode = aKeyEvent.GetKeyCode();
1515 sal_Unicode aCh = aKeyEvent.GetCharCode();
1517 // enable switching to notes anchor with Ctrl - Alt - Page Up/Down
1518 // pressing this inside a note will switch to next/previous note
1519 if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((rKeyCode.GetCode() == KEY_PAGEUP) || (rKeyCode.GetCode() == KEY_PAGEDOWN)))
1521 const bool bNext = rKeyCode.GetCode()==KEY_PAGEDOWN;
1522 const SwFieldType* pFieldType = rSh.GetFieldType( 0, SwFieldIds::Postit );
1523 rSh.MoveFieldType( pFieldType, bNext );
1524 return;
1527 if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
1529 // Check if this combination of rKeyCode and pTextContentControl should open a popup.
1530 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
1531 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
1532 if (pContentControl->ShouldOpenPopup(rKeyCode))
1534 SwShellCursor* pCursor = rSh.GetCursor_();
1535 if (pCursor)
1537 VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton();
1538 if (pContentControlButton)
1540 pContentControlButton->StartPopup();
1541 return;
1547 const SwFrameFormat* pFlyFormat = rSh.GetFlyFrameFormat();
1549 if (pFlyFormat)
1551 // See if the fly frame's anchor is in a content control. If so,
1552 // try to interact with it.
1553 const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
1554 SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
1555 if (pAnchorNode)
1557 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
1558 if (pTextNode)
1560 sal_Int32 nContentIdx = rFormatAnchor.GetAnchorContentOffset();
1561 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
1562 nContentIdx, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
1563 if (pAttr)
1565 SwTextContentControl* pTextContentControl
1566 = static_txtattr_cast<SwTextContentControl*>(pAttr);
1567 const SwFormatContentControl& rFormatContentControl
1568 = pTextContentControl->GetContentControl();
1569 std::shared_ptr<SwContentControl> pContentControl
1570 = rFormatContentControl.GetContentControl();
1571 if (pContentControl->IsInteractingCharacter(aCh))
1573 rSh.GotoContentControl(rFormatContentControl);
1574 return;
1581 if( pFlyFormat )
1583 SvMacroItemId nEvent;
1585 if( 32 <= aCh &&
1586 0 == (( KEY_MOD1 | KEY_MOD2 ) & rKeyCode.GetModifier() ))
1587 nEvent = SvMacroItemId::SwFrmKeyInputAlpha;
1588 else
1589 nEvent = SvMacroItemId::SwFrmKeyInputNoAlpha;
1591 const SvxMacro* pMacro = pFlyFormat->GetMacro().GetMacroTable().Get( nEvent );
1592 if( pMacro )
1594 SbxArrayRef xArgs = new SbxArray;
1595 SbxVariableRef xVar = new SbxVariable;
1596 xVar->PutString( pFlyFormat->GetName() );
1597 xArgs->Put(xVar.get(), 1);
1599 xVar = new SbxVariable;
1600 if( SvMacroItemId::SwFrmKeyInputAlpha == nEvent )
1601 xVar->PutChar( aCh );
1602 else
1603 xVar->PutUShort( rKeyCode.GetModifier() | rKeyCode.GetCode() );
1604 xArgs->Put(xVar.get(), 2);
1606 OUString sRet;
1607 rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
1608 if( !sRet.isEmpty() && sRet.toInt32()!=0 )
1609 return ;
1612 SelectionType nLclSelectionType;
1613 //A is converted to 1
1614 if( rKeyCode.GetFullCode() == (KEY_A | KEY_MOD1 |KEY_SHIFT)
1615 && rSh.HasDrawView() &&
1616 (bool(nLclSelectionType = rSh.GetSelectionType()) &&
1617 ((nLclSelectionType & (SelectionType::Frame|SelectionType::Graphic)) ||
1618 ((nLclSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1619 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1))))
1621 SdrHdlList& rHdlList = const_cast<SdrHdlList&>(rSh.GetDrawView()->GetHdlList());
1622 SdrHdl* pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor);
1623 if ( ! pAnchor )
1624 pAnchor = rHdlList.GetHdl(SdrHdlKind::Anchor_TR);
1625 if(pAnchor)
1626 rHdlList.SetFocusHdl(pAnchor);
1627 return;
1630 SvxAutoCorrCfg* pACfg = nullptr;
1631 SvxAutoCorrect* pACorr = nullptr;
1633 uno::Reference< frame::XDispatchRecorder > xRecorder =
1634 m_rView.GetViewFrame().GetBindings().GetRecorder();
1635 if ( !xRecorder.is() )
1637 pACfg = &SvxAutoCorrCfg::Get();
1638 pACorr = pACfg->GetAutoCorrect();
1641 SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig();
1643 OUString sFormulaEntry;
1645 enum class SwKeyState { CheckKey, InsChar, InsTab,
1646 NoNum, NumOff, NumOrNoNum, NumDown, NumUp,
1647 NumIndentInc, NumIndentDec,
1649 OutlineLvOff,
1650 NextCell, PrevCell, OutlineUp, OutlineDown,
1651 GlossaryExpand, NextPrevGlossary,
1652 AutoFormatByInput,
1653 NextObject, PrevObject,
1654 KeyToView,
1655 LaunchOLEObject, GoIntoFly, GoIntoDrawing,
1656 EnterDrawHandleMode,
1657 CheckDocReadOnlyKeys,
1658 CheckAutoCorrect, EditFormula,
1659 ColLeftBig, ColRightBig,
1660 ColLeftSmall, ColRightSmall,
1661 ColBottomBig,
1662 ColBottomSmall,
1663 CellLeftBig, CellRightBig,
1664 CellLeftSmall, CellRightSmall,
1665 CellTopBig, CellBottomBig,
1666 CellTopSmall, CellBottomSmall,
1668 Fly_Change, Draw_Change,
1669 SpecialInsert,
1670 EnterCharCell,
1671 GotoNextFieldMark,
1672 GotoPrevFieldMark,
1673 End };
1675 SwKeyState eKeyState = bIsDocReadOnly ? SwKeyState::CheckDocReadOnlyKeys : SwKeyState::CheckKey;
1676 SwKeyState eNextKeyState = SwKeyState::End;
1677 sal_uInt8 nDir = 0;
1679 if (m_nKS_NUMDOWN_Count > 0)
1680 m_nKS_NUMDOWN_Count--;
1682 if (m_nKS_NUMINDENTINC_Count > 0)
1683 m_nKS_NUMINDENTINC_Count--;
1685 while( SwKeyState::End != eKeyState )
1687 SwKeyState eFlyState = SwKeyState::KeyToView;
1689 switch( eKeyState )
1691 case SwKeyState::CheckKey:
1692 eKeyState = SwKeyState::KeyToView; // default forward to View
1694 if (!comphelper::LibreOfficeKit::isActive() &&
1695 !rKeyCode.IsMod2() && '=' == aCh &&
1696 !rSh.IsTableMode() && rSh.GetTableFormat() &&
1697 rSh.IsSttPara() &&
1698 !rSh.HasReadonlySel())
1700 // at the beginning of the table's cell a '=' ->
1701 // call EditRow (F2-functionality)
1702 // [Avoid this for LibreOfficeKit, as the separate input window
1703 // steals the focus & things go wrong - the user never gets
1704 // the focus back.]
1705 rSh.Push();
1706 if( !rSh.MoveSection( GoCurrSection, fnSectionStart) &&
1707 !rSh.IsTableBoxTextFormat() )
1709 // is at the beginning of the box
1710 eKeyState = SwKeyState::EditFormula;
1711 if( rSh.HasMark() )
1712 rSh.SwapPam();
1713 else
1714 rSh.SttSelect();
1715 rSh.MoveSection( GoCurrSection, fnSectionEnd );
1716 rSh.Pop();
1717 rSh.EndSelect();
1718 sFormulaEntry = "=";
1720 else
1721 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
1723 else
1725 if( pACorr && aTmpQHD.HasContent() && !rSh.HasSelection() &&
1726 !rSh.HasReadonlySel() && !aTmpQHD.m_bIsAutoText &&
1727 pACorr->GetSwFlags().nAutoCmpltExpandKey ==
1728 (rKeyCode.GetModifier() | rKeyCode.GetCode()) )
1730 eKeyState = SwKeyState::GlossaryExpand;
1731 break;
1734 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
1736 case KEY_RIGHT | KEY_MOD2:
1737 eKeyState = SwKeyState::ColRightBig;
1738 eFlyState = SwKeyState::Fly_Change;
1739 nDir = MOVE_RIGHT_SMALL;
1740 goto KEYINPUT_CHECKTABLE;
1742 case KEY_LEFT | KEY_MOD2:
1743 eKeyState = SwKeyState::ColRightSmall;
1744 eFlyState = SwKeyState::Fly_Change;
1745 nDir = MOVE_LEFT_SMALL;
1746 goto KEYINPUT_CHECKTABLE;
1748 case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT:
1749 eKeyState = SwKeyState::ColLeftSmall;
1750 goto KEYINPUT_CHECKTABLE;
1752 case KEY_LEFT | KEY_MOD2 | KEY_SHIFT:
1753 eKeyState = SwKeyState::ColLeftBig;
1754 goto KEYINPUT_CHECKTABLE;
1756 case KEY_RIGHT | KEY_MOD2 | KEY_MOD1:
1757 eKeyState = SwKeyState::CellRightBig;
1758 goto KEYINPUT_CHECKTABLE;
1760 case KEY_LEFT | KEY_MOD2 | KEY_MOD1:
1761 eKeyState = SwKeyState::CellRightSmall;
1762 goto KEYINPUT_CHECKTABLE;
1764 case KEY_RIGHT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1765 eKeyState = SwKeyState::CellLeftSmall;
1766 goto KEYINPUT_CHECKTABLE;
1768 case KEY_LEFT | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1769 eKeyState = SwKeyState::CellLeftBig;
1770 goto KEYINPUT_CHECKTABLE;
1772 case KEY_UP | KEY_MOD2:
1773 eKeyState = SwKeyState::ColBottomSmall;
1774 eFlyState = SwKeyState::Fly_Change;
1775 nDir = MOVE_UP_SMALL;
1776 goto KEYINPUT_CHECKTABLE;
1778 case KEY_DOWN | KEY_MOD2:
1779 eKeyState = SwKeyState::ColBottomBig;
1780 eFlyState = SwKeyState::Fly_Change;
1781 nDir = MOVE_DOWN_SMALL;
1782 goto KEYINPUT_CHECKTABLE;
1784 case KEY_UP | KEY_MOD2 | KEY_MOD1:
1785 eKeyState = SwKeyState::CellBottomSmall;
1786 goto KEYINPUT_CHECKTABLE;
1788 case KEY_DOWN | KEY_MOD2 | KEY_MOD1:
1789 eKeyState = SwKeyState::CellBottomBig;
1790 goto KEYINPUT_CHECKTABLE;
1792 case KEY_UP | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1793 eKeyState = SwKeyState::CellTopBig;
1794 goto KEYINPUT_CHECKTABLE;
1796 case KEY_DOWN | KEY_MOD2 | KEY_SHIFT | KEY_MOD1:
1797 eKeyState = SwKeyState::CellTopSmall;
1798 goto KEYINPUT_CHECKTABLE;
1800 KEYINPUT_CHECKTABLE:
1801 // Resolve bugs 49091, 53190, 93402 and
1802 // https://bz.apache.org/ooo/show_bug.cgi?id=113502
1803 // but provide an option for restoring interactive
1804 // table sizing functionality when needed.
1805 if (
1806 ! (Window::GetIndicatorState() & KeyIndicatorState::CAPSLOCK)
1807 && m_rView.KeyInput( aKeyEvent ) // Keystroke is customized
1810 bFlushBuffer = true;
1811 bNormalChar = false;
1812 eKeyState = SwKeyState::End;
1813 break ;
1816 if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1818 if(!pFlyFormat && SwKeyState::KeyToView != eFlyState &&
1819 (rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1820 rSh.GetDrawView()->AreObjectsMarked())
1821 eKeyState = SwKeyState::Draw_Change;
1823 if( pFlyFormat )
1824 eKeyState = eFlyState;
1825 else if( SwKeyState::Draw_Change != eKeyState)
1826 eKeyState = SwKeyState::EnterCharCell;
1828 break;
1830 // huge object move
1831 case KEY_RIGHT | KEY_SHIFT:
1832 case KEY_LEFT | KEY_SHIFT:
1833 case KEY_UP | KEY_SHIFT:
1834 case KEY_DOWN | KEY_SHIFT:
1836 const SelectionType nSelectionType = rSh.GetSelectionType();
1837 if ( ( pFlyFormat
1838 && ( nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic) ) )
1839 || ( ( nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm) )
1840 && rSh.GetDrawView()->AreObjectsMarked() ) )
1842 eKeyState = pFlyFormat ? SwKeyState::Fly_Change : SwKeyState::Draw_Change;
1843 if (nSelectionType & SelectionType::DrawObject)
1845 // tdf#137964: always move the DrawObject if one is selected
1846 eKeyState = SwKeyState::Draw_Change;
1848 switch ( rKeyCode.GetCode() )
1850 case KEY_RIGHT: nDir = MOVE_RIGHT_HUGE; break;
1851 case KEY_LEFT: nDir = MOVE_LEFT_HUGE; break;
1852 case KEY_UP: nDir = MOVE_UP_HUGE; break;
1853 case KEY_DOWN: nDir = MOVE_DOWN_HUGE; break;
1856 break;
1859 case KEY_LEFT:
1860 case KEY_LEFT | KEY_MOD1:
1862 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1863 if(!bMod1)
1865 eFlyState = SwKeyState::Fly_Change;
1866 nDir = MOVE_LEFT_BIG;
1868 goto KEYINPUT_CHECKTABLE_INSDEL;
1870 case KEY_RIGHT | KEY_MOD1:
1872 goto KEYINPUT_CHECKTABLE_INSDEL;
1874 case KEY_UP:
1875 case KEY_UP | KEY_MOD1:
1877 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1878 if(!bMod1)
1880 eFlyState = SwKeyState::Fly_Change;
1881 nDir = MOVE_UP_BIG;
1883 goto KEYINPUT_CHECKTABLE_INSDEL;
1885 case KEY_DOWN:
1886 case KEY_DOWN | KEY_MOD1:
1888 bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
1889 if(!bMod1)
1891 ::sw::mark::IFieldmark* pMark = rSh.GetCurrentFieldmark();
1892 if (auto pDropDown = dynamic_cast<FieldmarkWithDropDownButton*>(pMark))
1894 pDropDown->LaunchPopup();
1895 eKeyState = SwKeyState::End;
1896 break;
1898 eFlyState = SwKeyState::Fly_Change;
1899 nDir = MOVE_DOWN_BIG;
1901 goto KEYINPUT_CHECKTABLE_INSDEL;
1904 KEYINPUT_CHECKTABLE_INSDEL:
1905 if( rSh.IsTableMode() || !rSh.GetTableFormat() )
1907 const SelectionType nSelectionType = rSh.GetSelectionType();
1909 eKeyState = SwKeyState::KeyToView;
1910 if(SwKeyState::KeyToView != eFlyState)
1912 if((nSelectionType & (SelectionType::DrawObject|SelectionType::DbForm)) &&
1913 rSh.GetDrawView()->AreObjectsMarked())
1914 eKeyState = SwKeyState::Draw_Change;
1915 else if(nSelectionType & (SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic))
1916 eKeyState = SwKeyState::Fly_Change;
1919 break;
1922 case KEY_DELETE:
1923 if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
1925 if (rSh.IsInFrontOfLabel() && rSh.NumOrNoNum())
1926 eKeyState = SwKeyState::NumOrNoNum;
1928 else if (!rSh.IsCursorInParagraphMetadataField())
1930 rSh.InfoReadOnlyDialog(false);
1931 eKeyState = SwKeyState::End;
1933 break;
1935 case KEY_RETURN:
1937 if ( !rSh.HasReadonlySel()
1938 && !rSh.CursorInsideInputField()
1939 && !rSh.CursorInsideContentControl() )
1941 const SelectionType nSelectionType = rSh.GetSelectionType();
1942 if(nSelectionType & SelectionType::Ole)
1943 eKeyState = SwKeyState::LaunchOLEObject;
1944 else if(nSelectionType & SelectionType::Frame)
1945 eKeyState = SwKeyState::GoIntoFly;
1946 else if((nSelectionType & SelectionType::DrawObject) &&
1947 !(nSelectionType & SelectionType::DrawObjectEditMode) &&
1948 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1)
1950 eKeyState = SwKeyState::GoIntoDrawing;
1951 if (lcl_goIntoTextBox(*this, rSh))
1952 eKeyState = SwKeyState::GoIntoFly;
1954 else if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
1955 aTmpQHD.m_bIsAutoText )
1956 eKeyState = SwKeyState::GlossaryExpand;
1958 //RETURN and empty paragraph in numbering -> end numbering
1959 else if( m_aInBuffer.isEmpty() &&
1960 rSh.GetNumRuleAtCurrCursorPos() &&
1961 !rSh.GetNumRuleAtCurrCursorPos()->IsOutlineRule() &&
1962 !rSh.HasSelection() &&
1963 rSh.IsSttPara() && rSh.IsEndPara() )
1965 eKeyState = SwKeyState::NumOff;
1966 eNextKeyState = SwKeyState::OutlineLvOff;
1968 //RETURN for new paragraph with AutoFormatting
1969 else if( pACfg && pACfg->IsAutoFormatByInput() &&
1970 !(nSelectionType & (SelectionType::Graphic |
1971 SelectionType::Ole | SelectionType::Frame |
1972 SelectionType::TableCell | SelectionType::DrawObject |
1973 SelectionType::DrawObjectEditMode)) )
1975 eKeyState = SwKeyState::AutoFormatByInput;
1977 else
1979 eNextKeyState = eKeyState;
1980 eKeyState = SwKeyState::CheckAutoCorrect;
1984 break;
1985 case KEY_RETURN | KEY_MOD2:
1987 if ( !rSh.HasReadonlySel()
1988 && !rSh.IsSttPara()
1989 && rSh.GetNumRuleAtCurrCursorPos()
1990 && !rSh.CursorInsideInputField() )
1992 eKeyState = SwKeyState::NoNum;
1994 else if( rSh.CanSpecialInsert() )
1995 eKeyState = SwKeyState::SpecialInsert;
1997 break;
1998 case KEY_BACKSPACE:
1999 case KEY_BACKSPACE | KEY_SHIFT:
2000 if ( !rSh.HasReadonlySel() || rSh.CursorInsideInputField())
2002 bool bDone = false;
2003 // try to add comment for code snip:
2004 // Remove the paragraph indent, if the cursor is at the
2005 // beginning of a paragraph, there is no selection
2006 // and no numbering rule found at the current paragraph
2007 // Also try to remove indent, if current paragraph
2008 // has numbering rule, but isn't counted and only
2009 // key <backspace> is hit.
2010 const bool bOnlyBackspaceKey( KEY_BACKSPACE == rKeyCode.GetFullCode() );
2011 if ( rSh.IsSttPara()
2012 && !rSh.HasSelection()
2013 && ( rSh.GetNumRuleAtCurrCursorPos() == nullptr
2014 || ( rSh.IsNoNum() && bOnlyBackspaceKey ) ) )
2016 bDone = rSh.TryRemoveIndent();
2019 if (bDone)
2020 eKeyState = SwKeyState::End;
2021 else
2023 if ( rSh.IsSttPara() && !rSh.IsNoNum() )
2025 if (m_nKS_NUMDOWN_Count > 0 &&
2026 0 < rSh.GetNumLevel())
2028 eKeyState = SwKeyState::NumUp;
2029 m_nKS_NUMDOWN_Count = 2;
2030 bDone = true;
2032 else if (m_nKS_NUMINDENTINC_Count > 0)
2034 eKeyState = SwKeyState::NumIndentDec;
2035 m_nKS_NUMINDENTINC_Count = 2;
2036 bDone = true;
2040 // If the cursor is in an empty paragraph, which has
2041 // a numbering, but not the outline numbering, and
2042 // there is no selection, the numbering has to be
2043 // deleted on key <Backspace>.
2044 // Otherwise method <SwEditShell::NumOrNoNum(..)>
2045 // should only change the <IsCounted()> state of
2046 // the current paragraph depending of the key.
2047 // On <backspace> it is set to <false>,
2048 // on <shift-backspace> it is set to <true>.
2049 // Thus, assure that method <SwEditShell::NumOrNum(..)>
2050 // is only called for the intended purpose.
2051 if ( !bDone && rSh.IsSttPara() )
2053 bool bCallNumOrNoNum( false );
2054 if ( bOnlyBackspaceKey && !rSh.IsNoNum() )
2056 bCallNumOrNoNum = true;
2058 else if ( !bOnlyBackspaceKey && rSh.IsNoNum() )
2060 bCallNumOrNoNum = true;
2062 else if ( bOnlyBackspaceKey
2063 && rSh.IsSttPara()
2064 && rSh.IsEndPara()
2065 && !rSh.HasSelection() )
2067 const SwNumRule* pCurrNumRule( rSh.GetNumRuleAtCurrCursorPos() );
2068 if ( pCurrNumRule != nullptr
2069 && pCurrNumRule != rSh.GetOutlineNumRule() )
2071 bCallNumOrNoNum = true;
2074 if ( bCallNumOrNoNum
2075 && rSh.NumOrNoNum( !bOnlyBackspaceKey ) )
2077 eKeyState = SwKeyState::NumOrNoNum;
2082 else if (!rSh.IsCursorInParagraphMetadataField())
2084 rSh.InfoReadOnlyDialog(false);
2085 eKeyState = SwKeyState::End;
2087 break;
2089 case KEY_RIGHT:
2091 eFlyState = SwKeyState::Fly_Change;
2092 nDir = MOVE_RIGHT_BIG;
2093 goto KEYINPUT_CHECKTABLE_INSDEL;
2095 case KEY_TAB:
2097 // Rich text contentControls accept tabs and fieldmarks and other rich text,
2098 // so first act on cases that are not a content control
2099 SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2100 if ((rSh.IsFormProtected() && !pTextContentControl) ||
2101 rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2103 eKeyState = SwKeyState::GotoNextFieldMark;
2105 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2107 GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_NEXT_INPUTFLD );
2108 eKeyState = SwKeyState::End;
2110 else if( rSh.GetNumRuleAtCurrCursorPos()
2111 && rSh.IsSttOfPara()
2112 && !rSh.HasReadonlySel() )
2114 if (numfunc::NumDownChangesIndent(rSh))
2116 eKeyState = SwKeyState::NumDown;
2118 else
2120 eKeyState = SwKeyState::InsTab;
2123 else if (rSh.GetSelectionType() &
2124 (SelectionType::Graphic |
2125 SelectionType::Frame |
2126 SelectionType::Ole |
2127 SelectionType::DrawObject |
2128 SelectionType::DbForm))
2130 eKeyState = SwKeyState::NextObject;
2132 else if ( rSh.GetTableFormat() )
2134 if( rSh.HasSelection() || rSh.HasReadonlySel() )
2135 eKeyState = SwKeyState::NextCell;
2136 else
2138 eKeyState = SwKeyState::CheckAutoCorrect;
2139 eNextKeyState = SwKeyState::NextCell;
2142 else if (pTextContentControl)
2144 auto pCC = pTextContentControl->GetContentControl().GetContentControl();
2145 if (pCC)
2147 switch (pCC->GetType())
2149 case SwContentControlType::RICH_TEXT:
2150 eKeyState = SwKeyState::InsTab;
2151 break;
2152 default:
2153 eKeyState = SwKeyState::GotoNextFieldMark;
2157 else
2159 eKeyState = SwKeyState::InsTab;
2160 if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2162 SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
2163 if( pColl &&
2165 pColl->IsAssignedToListLevelOfOutlineStyle()
2166 && MAXLEVEL-1 > pColl->GetAssignedOutlineStyleLevel() )
2167 eKeyState = SwKeyState::OutlineDown;
2171 break;
2172 case KEY_TAB | KEY_SHIFT:
2174 SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
2175 if ((rSh.IsFormProtected() && !pTextContentControl) ||
2176 rSh.GetCurrentFieldmark()|| rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2178 eKeyState = SwKeyState::GotoPrevFieldMark;
2180 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2182 GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_PREV_INPUTFLD );
2183 eKeyState = SwKeyState::End;
2185 else if( rSh.GetNumRuleAtCurrCursorPos()
2186 && rSh.IsSttOfPara()
2187 && !rSh.HasReadonlySel() )
2189 eKeyState = SwKeyState::NumUp;
2191 else if (rSh.GetSelectionType() &
2192 (SelectionType::Graphic |
2193 SelectionType::Frame |
2194 SelectionType::Ole |
2195 SelectionType::DrawObject |
2196 SelectionType::DbForm))
2198 eKeyState = SwKeyState::PrevObject;
2200 else if ( rSh.GetTableFormat() )
2202 if( rSh.HasSelection() || rSh.HasReadonlySel() )
2203 eKeyState = SwKeyState::PrevCell;
2204 else
2206 eKeyState = SwKeyState::CheckAutoCorrect;
2207 eNextKeyState = SwKeyState::PrevCell;
2210 else if (pTextContentControl)
2212 eKeyState = SwKeyState::GotoPrevFieldMark;
2214 else
2216 eKeyState = SwKeyState::End;
2217 if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
2219 SwTextFormatColl* pColl = rSh.GetCurTextFormatColl();
2220 if( pColl &&
2221 pColl->IsAssignedToListLevelOfOutlineStyle() &&
2222 0 < pColl->GetAssignedOutlineStyleLevel())
2223 eKeyState = SwKeyState::OutlineUp;
2227 break;
2228 case KEY_TAB | KEY_MOD1:
2229 case KEY_TAB | KEY_MOD2:
2230 if( !rSh.HasReadonlySel() )
2232 if( aTmpQHD.HasContent() && !rSh.HasSelection() )
2234 // Next auto-complete suggestion
2235 aTmpQHD.Next( pACorr &&
2236 pACorr->GetSwFlags().bAutoCmpltEndless );
2237 eKeyState = SwKeyState::NextPrevGlossary;
2239 else if( rSh.GetTableFormat() )
2240 eKeyState = SwKeyState::InsTab;
2241 else if((rSh.GetSelectionType() &
2242 (SelectionType::DrawObject|SelectionType::DbForm|
2243 SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic)) &&
2244 rSh.GetDrawView()->AreObjectsMarked())
2245 eKeyState = SwKeyState::EnterDrawHandleMode;
2246 else
2248 if ( !rSh.IsMultiSelection()
2249 && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
2250 eKeyState = SwKeyState::NumIndentInc;
2253 break;
2255 case KEY_TAB | KEY_MOD1 | KEY_SHIFT:
2257 if( aTmpQHD.HasContent() && !rSh.HasSelection() &&
2258 !rSh.HasReadonlySel() )
2260 // Previous auto-complete suggestion.
2261 aTmpQHD.Previous( pACorr &&
2262 pACorr->GetSwFlags().bAutoCmpltEndless );
2263 eKeyState = SwKeyState::NextPrevGlossary;
2265 else if((rSh.GetSelectionType() & (SelectionType::DrawObject|SelectionType::DbForm|
2266 SelectionType::Frame|SelectionType::Ole|SelectionType::Graphic)) &&
2267 rSh.GetDrawView()->AreObjectsMarked())
2269 eKeyState = SwKeyState::EnterDrawHandleMode;
2271 else
2273 if ( !rSh.IsMultiSelection()
2274 && numfunc::ChangeIndentOnTabAtFirstPosOfFirstListItem() )
2275 eKeyState = SwKeyState::NumIndentDec;
2278 break;
2279 case KEY_F2 :
2280 if( !rSh.HasReadonlySel() )
2282 const SelectionType nSelectionType = rSh.GetSelectionType();
2283 if(nSelectionType & SelectionType::Frame)
2284 eKeyState = SwKeyState::GoIntoFly;
2285 else if(nSelectionType & SelectionType::DrawObject)
2287 eKeyState = SwKeyState::GoIntoDrawing;
2288 if (lcl_goIntoTextBox(*this, rSh))
2289 eKeyState = SwKeyState::GoIntoFly;
2292 break;
2295 break;
2296 case SwKeyState::CheckDocReadOnlyKeys:
2298 eKeyState = SwKeyState::KeyToView;
2299 switch( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2301 case KEY_TAB:
2302 case KEY_TAB | KEY_SHIFT:
2303 bNormalChar = false;
2304 eKeyState = SwKeyState::End;
2305 if ( rSh.GetSelectionType() &
2306 (SelectionType::Graphic |
2307 SelectionType::Frame |
2308 SelectionType::Ole |
2309 SelectionType::DrawObject |
2310 SelectionType::DbForm))
2313 eKeyState = (rKeyCode.GetModifier() & KEY_SHIFT) ?
2314 SwKeyState::PrevObject : SwKeyState::NextObject;
2316 else if ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
2318 GetView().GetViewFrame().GetDispatcher()->Execute(
2319 KEY_SHIFT != rKeyCode.GetModifier() ? FN_GOTO_NEXT_INPUTFLD : FN_GOTO_PREV_INPUTFLD );
2321 else
2323 rSh.SelectNextPrevHyperlink( KEY_SHIFT != rKeyCode.GetModifier() );
2325 break;
2326 case KEY_RETURN:
2328 const SelectionType nSelectionType = rSh.GetSelectionType();
2329 if(nSelectionType & SelectionType::Frame)
2330 eKeyState = SwKeyState::GoIntoFly;
2331 else
2333 SfxItemSetFixed<RES_TXTATR_INETFMT, RES_TXTATR_INETFMT> aSet(rSh.GetAttrPool());
2334 rSh.GetCurAttr(aSet);
2335 if(SfxItemState::SET == aSet.GetItemState(RES_TXTATR_INETFMT, false))
2337 const SfxPoolItem& rItem = aSet.Get(RES_TXTATR_INETFMT);
2338 bNormalChar = false;
2339 eKeyState = SwKeyState::End;
2340 rSh.ClickToINetAttr(static_cast<const SwFormatINetFormat&>(rItem));
2344 break;
2347 break;
2349 case SwKeyState::EnterCharCell:
2351 eKeyState = SwKeyState::KeyToView;
2352 switch ( rKeyCode.GetModifier() | rKeyCode.GetCode() )
2354 case KEY_RIGHT | KEY_MOD2:
2355 rSh.Right( SwCursorSkipMode::Chars, false, 1, false );
2356 eKeyState = SwKeyState::End;
2357 FlushInBuffer();
2358 break;
2359 case KEY_LEFT | KEY_MOD2:
2360 rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
2361 eKeyState = SwKeyState::End;
2362 FlushInBuffer();
2363 break;
2366 break;
2368 case SwKeyState::KeyToView:
2370 eKeyState = SwKeyState::End;
2371 bNormalChar =
2372 !rKeyCode.IsMod2() &&
2373 rKeyCode.GetModifier() != KEY_MOD1 &&
2374 rKeyCode.GetModifier() != (KEY_MOD1|KEY_SHIFT) &&
2375 SW_ISPRINTABLE( aCh );
2377 if( bNormalChar && rSh.IsInFrontOfLabel() )
2379 rSh.NumOrNoNum();
2382 if( !m_aInBuffer.isEmpty() && ( !bNormalChar || bIsDocReadOnly ))
2383 FlushInBuffer();
2385 if (rSh.HasReadonlySel()
2386 && ( rKeyCode.GetFunction() == KeyFuncType::PASTE
2387 || rKeyCode.GetFunction() == KeyFuncType::CUT))
2389 rSh.InfoReadOnlyDialog(true);
2390 eKeyState = SwKeyState::End;
2392 else if( m_rView.KeyInput( aKeyEvent ) )
2394 bFlushBuffer = true;
2395 bNormalChar = false;
2397 else
2399 // Because Sfx accelerators are only called when they were
2400 // enabled at the last status update, copy has to called
2401 // 'forcefully' by us if necessary.
2402 if( rKeyCode.GetFunction() == KeyFuncType::COPY )
2403 GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
2405 if( !bIsDocReadOnly && bNormalChar )
2407 const SelectionType nSelectionType = rSh.GetSelectionType();
2408 const bool bDrawObject = (nSelectionType & SelectionType::DrawObject) &&
2409 !(nSelectionType & SelectionType::DrawObjectEditMode) &&
2410 rSh.GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1;
2412 bool bTextBox = false;
2413 if (bDrawObject && lcl_goIntoTextBox(*this, rSh))
2414 // A draw shape was selected, but it has a TextBox,
2415 // start editing that instead when the normal
2416 // character is pressed.
2417 bTextBox = true;
2419 if (bDrawObject && !bTextBox)
2421 SdrObject* pObj = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj();
2422 if(pObj)
2424 EnterDrawTextMode(pObj->GetLogicRect().Center());
2425 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
2426 pSwDrawTextShell->Init();
2427 rSh.GetDrawView()->KeyInput( rKEvt, this );
2430 else if (nSelectionType & SelectionType::Frame || bTextBox)
2432 rSh.UnSelectFrame();
2433 rSh.LeaveSelFrameMode();
2434 m_rView.AttrChangedNotify(nullptr);
2435 rSh.MoveSection( GoCurrSection, fnSectionEnd );
2437 eKeyState = SwKeyState::InsChar;
2439 else
2441 bNormalChar = false;
2442 Window::KeyInput( aKeyEvent );
2446 break;
2447 case SwKeyState::LaunchOLEObject:
2449 rSh.LaunchOLEObj();
2450 eKeyState = SwKeyState::End;
2452 break;
2453 case SwKeyState::GoIntoFly:
2455 rSh.UnSelectFrame();
2456 rSh.LeaveSelFrameMode();
2457 m_rView.AttrChangedNotify(nullptr);
2458 rSh.MoveSection( GoCurrSection, fnSectionEnd );
2459 eKeyState = SwKeyState::End;
2461 break;
2462 case SwKeyState::GoIntoDrawing:
2464 if (SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0))
2466 SdrObject* pObj = pMark->GetMarkedSdrObj();
2467 if(pObj)
2469 EnterDrawTextMode(pObj->GetLogicRect().Center());
2470 if (auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
2471 pSwDrawTextShell->Init();
2474 eKeyState = SwKeyState::End;
2476 break;
2477 case SwKeyState::EnterDrawHandleMode:
2479 const SdrHdlList& rHdlList = rSh.GetDrawView()->GetHdlList();
2480 bool bForward(!aKeyEvent.GetKeyCode().IsShift());
2482 const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
2483 eKeyState = SwKeyState::End;
2485 break;
2486 case SwKeyState::InsTab:
2487 if( dynamic_cast<const SwWebView*>( &m_rView) != nullptr) // no Tab for WebView
2489 // then it should be passed along
2490 Window::KeyInput( aKeyEvent );
2491 eKeyState = SwKeyState::End;
2492 break;
2494 aCh = '\t';
2495 [[fallthrough]];
2496 case SwKeyState::InsChar:
2497 if (rSh.CursorInsideContentControl())
2499 const SwPosition* pStart = rSh.GetCursor()->Start();
2500 SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
2501 if (pTextNode)
2503 sal_Int32 nIndex = pStart->GetContentIndex();
2504 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
2505 if (pAttr)
2507 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
2508 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
2509 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
2510 if (pContentControl->IsInteractingCharacter(aCh))
2512 rSh.GotoContentControl(rFormatContentControl);
2513 eKeyState = SwKeyState::End;
2514 break;
2520 if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
2522 ::sw::mark::ICheckboxFieldmark* pFieldmark =
2523 dynamic_cast< ::sw::mark::ICheckboxFieldmark* >
2524 (rSh.GetCurrentFieldmark());
2525 OSL_ENSURE(pFieldmark,
2526 "Where is my FieldMark??");
2527 if(pFieldmark)
2529 pFieldmark->SetChecked(!pFieldmark->IsChecked());
2530 OSL_ENSURE(pFieldmark->IsExpanded(),
2531 "where is the otherpos?");
2532 if (pFieldmark->IsExpanded())
2534 rSh.CalcLayout();
2537 eKeyState = SwKeyState::End;
2539 else if ( !rSh.HasReadonlySel()
2540 || rSh.CursorInsideInputField() )
2542 const bool bIsNormalChar =
2543 GetAppCharClass().isLetterNumeric( OUString( aCh ), 0 );
2544 if( bAppendSpace && bIsNormalChar &&
2545 (!m_aInBuffer.isEmpty() || !rSh.IsSttPara() || !rSh.IsEndPara() ))
2547 // insert a blank ahead of the character. this ends up
2548 // between the expanded text and the new "non-word-separator".
2549 m_aInBuffer += " ";
2552 const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar( aCh );
2553 if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2554 pACfg->IsAutoFormatByInput() &&
2555 (( pACorr->IsAutoCorrFlag( ACFlags::ChgWeightUnderl ) &&
2556 ( '*' == aCh || '_' == aCh ) ) ||
2557 ( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
2558 ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
2560 FlushInBuffer();
2561 rSh.AutoCorrect( *pACorr, aCh );
2562 if( '\"' != aCh && '\'' != aCh ) // only call when "*_"!
2563 rSh.UpdateAttr();
2565 else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) &&
2566 pACfg->IsAutoFormatByInput() &&
2567 pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2568 ACFlags::ChgOrdinalNumber | ACFlags::AddNonBrkSpace |
2569 ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2570 ACFlags::Autocorrect | ACFlags::TransliterateRTL |
2571 ACFlags::SetDOIAttr ) &&
2572 '\"' != aCh && '\'' != aCh && '*' != aCh && '_' != aCh
2575 FlushInBuffer();
2576 rSh.AutoCorrect( *pACorr, aCh );
2578 else
2580 OUStringBuffer aBuf(m_aInBuffer);
2581 comphelper::string::padToLength(aBuf,
2582 m_aInBuffer.getLength() + aKeyEvent.GetRepeat() + 1, aCh);
2583 m_aInBuffer = aBuf.makeStringAndClear();
2584 bool delayFlush = Application::AnyInput( VclInputFlags::KEYBOARD );
2585 bFlushBuffer = !delayFlush;
2586 if( delayFlush )
2588 // Start the timer, make sure to not restart it.
2589 keyInputFlushTimerStop.dismiss();
2590 if( !m_aKeyInputFlushTimer.IsActive())
2591 m_aKeyInputFlushTimer.Start();
2594 eKeyState = SwKeyState::End;
2596 else
2598 rSh.InfoReadOnlyDialog(true);
2599 eKeyState = SwKeyState::End;
2601 break;
2603 case SwKeyState::CheckAutoCorrect:
2605 if( pACorr && pACfg->IsAutoFormatByInput() &&
2606 pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
2607 ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
2608 ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr |
2609 ACFlags::Autocorrect | ACFlags::SetDOIAttr ) &&
2610 !rSh.HasReadonlySel() )
2612 FlushInBuffer();
2613 rSh.AutoCorrect( *pACorr, u'\0' );
2615 eKeyState = eNextKeyState;
2617 break;
2619 default:
2621 sal_uInt16 nSlotId = 0;
2622 FlushInBuffer();
2623 switch( eKeyState )
2625 case SwKeyState::SpecialInsert:
2626 rSh.DoSpecialInsert();
2627 break;
2629 case SwKeyState::NoNum:
2630 rSh.NoNum();
2631 break;
2633 case SwKeyState::NumOff:
2634 // shell change - so record in advance
2635 rSh.DelNumRules();
2636 break;
2637 case SwKeyState::OutlineLvOff: // delete autofmt outlinelevel later
2638 break;
2640 case SwKeyState::NumDown:
2641 rSh.NumUpDown();
2642 m_nKS_NUMDOWN_Count = 2;
2643 break;
2644 case SwKeyState::NumUp:
2645 rSh.NumUpDown( false );
2646 break;
2648 case SwKeyState::NumIndentInc:
2649 rSh.ChangeIndentOfAllListLevels(360);
2650 m_nKS_NUMINDENTINC_Count = 2;
2651 break;
2653 case SwKeyState::GotoNextFieldMark:
2655 rSh.GotoFormControl(/*bNext=*/true);
2657 break;
2659 case SwKeyState::GotoPrevFieldMark:
2661 rSh.GotoFormControl(/*bNext=*/false);
2663 break;
2665 case SwKeyState::NumIndentDec:
2666 rSh.ChangeIndentOfAllListLevels(-360);
2667 break;
2669 case SwKeyState::OutlineDown:
2670 rSh.OutlineUpDown();
2671 break;
2672 case SwKeyState::OutlineUp:
2673 rSh.OutlineUpDown( -1 );
2674 break;
2676 case SwKeyState::NextCell:
2677 // always 'flush' in tables
2678 rSh.GoNextCell(!rSh.HasReadonlySel());
2679 nSlotId = FN_GOTO_NEXT_CELL;
2680 break;
2681 case SwKeyState::PrevCell:
2682 rSh.GoPrevCell();
2683 nSlotId = FN_GOTO_PREV_CELL;
2684 break;
2685 case SwKeyState::AutoFormatByInput:
2686 rSh.SplitNode( true );
2687 break;
2689 case SwKeyState::NextObject:
2690 case SwKeyState::PrevObject:
2691 if(rSh.GotoObj( SwKeyState::NextObject == eKeyState, GotoObjFlags::Any))
2693 if( rSh.IsFrameSelected() &&
2694 m_rView.GetDrawFuncPtr() )
2696 m_rView.GetDrawFuncPtr()->Deactivate();
2697 m_rView.SetDrawFuncPtr(nullptr);
2698 m_rView.LeaveDrawCreate();
2699 m_rView.AttrChangedNotify(nullptr);
2701 rSh.HideCursor();
2702 rSh.EnterSelFrameMode();
2704 break;
2705 case SwKeyState::GlossaryExpand:
2707 // replace the word or abbreviation with the auto text
2708 rSh.StartUndo( SwUndoId::START );
2710 OUString sFnd(aTmpQHD.CurStr());
2711 if( aTmpQHD.m_bIsAutoText )
2713 SwGlossaryList* pList = ::GetGlossaryList();
2714 OUString sShrtNm;
2715 OUString sGroup;
2716 if(pList->GetShortName( sFnd, sShrtNm, sGroup))
2718 rSh.SttSelect();
2719 rSh.ExtendSelection(false, aTmpQHD.CurLen());
2720 SwGlossaryHdl* pGlosHdl = GetView().GetGlosHdl();
2721 pGlosHdl->SetCurGroup(sGroup, true);
2722 pGlosHdl->InsertGlossary( sShrtNm);
2723 s_pQuickHlpData->m_bAppendSpace = true;
2726 else
2728 sFnd = sFnd.copy(aTmpQHD.CurLen());
2729 rSh.Insert( sFnd );
2730 s_pQuickHlpData->m_bAppendSpace = !pACorr ||
2731 pACorr->GetSwFlags().bAutoCmpltAppendBlank;
2733 rSh.EndUndo( SwUndoId::END );
2735 break;
2737 case SwKeyState::NextPrevGlossary:
2738 s_pQuickHlpData->Move( aTmpQHD );
2739 s_pQuickHlpData->Start(rSh, false);
2740 break;
2742 case SwKeyState::EditFormula:
2744 const sal_uInt16 nId = SwInputChild::GetChildWindowId();
2746 SfxViewFrame& rVFrame = GetView().GetViewFrame();
2747 rVFrame.ToggleChildWindow( nId );
2748 SwInputChild* pChildWin = static_cast<SwInputChild*>(rVFrame.
2749 GetChildWindow( nId ));
2750 if( pChildWin )
2751 pChildWin->SetFormula( sFormulaEntry );
2753 break;
2755 case SwKeyState::ColLeftBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
2756 case SwKeyState::ColRightBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
2757 case SwKeyState::ColLeftSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColLeft, pModOpt->GetTableHMove() ); break;
2758 case SwKeyState::ColRightSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::ColRight, pModOpt->GetTableHMove() ); break;
2759 case SwKeyState::ColBottomBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() ); break;
2760 case SwKeyState::ColBottomSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::RowBottom, pModOpt->GetTableVMove() ); break;
2761 case SwKeyState::CellLeftBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
2762 case SwKeyState::CellRightBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableHMove() ); break;
2763 case SwKeyState::CellLeftSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellLeft, pModOpt->GetTableHMove() ); break;
2764 case SwKeyState::CellRightSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellRight, pModOpt->GetTableHMove() ); break;
2765 case SwKeyState::CellTopBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() ); break;
2766 case SwKeyState::CellBottomBig: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom|TableChgWidthHeightType::BiggerMode, pModOpt->GetTableVMove() ); break;
2767 case SwKeyState::CellTopSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellTop, pModOpt->GetTableVMove() ); break;
2768 case SwKeyState::CellBottomSmall: rSh.SetColRowWidthHeight( TableChgWidthHeightType::CellBottom, pModOpt->GetTableVMove() ); break;
2770 case SwKeyState::Fly_Change:
2772 SdrView *pSdrView = rSh.GetDrawView();
2773 const SdrHdlList& rHdlList = pSdrView->GetHdlList();
2774 if(rHdlList.GetFocusHdl())
2775 ChangeDrawing( nDir );
2776 else
2777 ChangeFly( nDir, dynamic_cast<const SwWebView*>( &m_rView) != nullptr );
2779 break;
2780 case SwKeyState::Draw_Change :
2781 ChangeDrawing( nDir );
2782 break;
2783 default:
2784 break;
2786 if( nSlotId && m_rView.GetViewFrame().GetBindings().GetRecorder().is() )
2788 SfxRequest aReq(m_rView.GetViewFrame(), nSlotId);
2789 aReq.Done();
2791 eKeyState = SwKeyState::End;
2796 // update the page number in the statusbar
2797 sal_uInt16 nKey = rKEvt.GetKeyCode().GetCode();
2798 if( KEY_UP == nKey || KEY_DOWN == nKey || KEY_PAGEUP == nKey || KEY_PAGEDOWN == nKey )
2799 GetView().GetViewFrame().GetBindings().Update( FN_STAT_PAGE );
2801 // in case the buffered characters are inserted
2802 if( bFlushBuffer && !m_aInBuffer.isEmpty() )
2804 FlushInBuffer();
2806 // maybe show Tip-Help
2807 if (bNormalChar)
2809 const bool bAutoTextShown
2810 = pACfg && pACfg->IsAutoTextTip() && ShowAutoText(rSh.GetChunkForAutoText());
2811 if (!bAutoTextShown && pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
2812 ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
2816 // get the word count dialog to update itself
2817 SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
2818 if( pWrdCnt )
2819 pWrdCnt->UpdateCounts();
2824 * MouseEvents
2826 void SwEditWin::ResetMouseButtonDownFlags()
2828 // Not on all systems a MouseButtonUp is used ahead
2829 // of the modal dialog (like on WINDOWS).
2830 // So reset the statuses here and release the mouse
2831 // for the dialog.
2832 m_bMBPressed = false;
2833 g_bNoInterrupt = false;
2834 EnterArea();
2835 ReleaseMouse();
2839 * Determines if the current position has a clickable url over a background
2840 * frame. In that case, ctrl-click should select the url, not the frame.
2842 static bool lcl_urlOverBackground(SwWrtShell& rSh, const Point& rDocPos)
2844 SwContentAtPos aSwContentAtPos(IsAttrAtPos::InetAttr);
2845 SdrObject* pSelectableObj = rSh.GetObjAt(rDocPos);
2847 return rSh.GetContentAtPos(rDocPos, aSwContentAtPos) && pSelectableObj->GetLayer() == rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId();
2850 void SwEditWin::MoveCursor( SwWrtShell &rSh, const Point& rDocPos,
2851 const bool bOnlyText, bool bLockView )
2853 const bool bTmpNoInterrupt = g_bNoInterrupt;
2854 g_bNoInterrupt = false;
2856 int nTmpSetCursor = 0;
2858 if( !rSh.IsViewLocked() && bLockView )
2859 rSh.LockView( true );
2860 else
2861 bLockView = false;
2864 // only temporary generate move context because otherwise
2865 // the query to the content form doesn't work!!!
2866 SwMvContext aMvContext( &rSh );
2867 nTmpSetCursor = rSh.CallSetCursor(&rDocPos, bOnlyText);
2868 g_bValidCursorPos = !(CRSR_POSCHG & nTmpSetCursor);
2871 // notify the edit window that from now on we do not use the input language
2872 if ( !(CRSR_POSOLD & nTmpSetCursor) )
2873 SetUseInputLanguage( false );
2875 if( bLockView )
2876 rSh.LockView( false );
2878 g_bNoInterrupt = bTmpNoInterrupt;
2881 void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
2883 SwWrtShell &rSh = m_rView.GetWrtShell();
2884 const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr;
2886 // We have to check if a context menu is shown and we have an UI
2887 // active inplace client. In that case we have to ignore the mouse
2888 // button down event. Otherwise we would crash (context menu has been
2889 // opened by inplace client and we would deactivate the inplace client,
2890 // the context menu is closed by VCL asynchronously which in the end
2891 // would work on deleted objects or the context menu has no parent anymore)
2892 SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
2893 bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
2895 if (bIsOleActive && vcl::IsInPopupMenuExecute())
2896 return;
2898 MouseEvent aMEvt(_rMEvt);
2900 if (m_rView.GetPostItMgr()->IsHit(aMEvt.GetPosPixel()))
2901 return;
2903 if (comphelper::LibreOfficeKit::isActive())
2905 if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(aMEvt.GetPosPixel()))
2907 pWindow->MouseButtonDown(aMEvt);
2908 return;
2912 m_rView.GetPostItMgr()->SetActiveSidebarWin(nullptr);
2914 GrabFocus();
2915 rSh.addCurrentPosition();
2917 //ignore key modifiers for format paintbrush
2919 bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
2920 && m_pApplyTempl->m_pFormatClipboard->HasContent();
2921 if( bExecFormatPaintbrush )
2922 aMEvt = MouseEvent(_rMEvt.GetPosPixel(), _rMEvt.GetClicks(), _rMEvt.GetMode(),
2923 _rMEvt.GetButtons());
2926 m_bWasShdwCursor = nullptr != m_pShadCursor;
2927 m_pShadCursor.reset();
2929 const Point aDocPos(PixelToLogic(aMEvt.GetPosPixel()));
2931 FrameControlType eControl;
2932 bool bOverFly = false;
2933 bool bPageAnchored = false;
2934 bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
2936 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly();
2937 if (bOverHeaderFooterFly && (!bIsDocReadOnly && rSh.GetCurField()))
2938 // We have a field here, that should have priority over header/footer fly.
2939 bOverHeaderFooterFly = false;
2941 // Are we clicking on a blank header/footer area?
2942 if ( IsInHeaderFooter( aDocPos, eControl ) || bOverHeaderFooterFly )
2944 const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( aDocPos );
2946 if ( pPageFrame )
2948 // Is it active?
2949 bool bActive = true;
2950 const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
2952 const SwFrameFormat* pFormat = pDesc->GetLeftFormat();
2953 if ( pPageFrame->OnRightPage() )
2954 pFormat = pDesc->GetRightFormat();
2956 if ( pFormat )
2958 if ( eControl == FrameControlType::Header )
2959 bActive = pFormat->GetHeader().IsActive();
2960 else
2961 bActive = pFormat->GetFooter().IsActive();
2964 if ( !bActive )
2966 // HeaderFooter menu implies header/footer controls, so only do this with IsUseHeaderFooterMenu enabled.
2967 // But, additionally, when in Hide-Whitespace mode, we don't want those controls.
2968 if (rSh.GetViewOptions()->IsUseHeaderFooterMenu() && !rSh.GetViewOptions()->IsHideWhitespaceMode())
2970 SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint());
2971 const bool bWasInHeader = aPam.GetPoint()->GetNode().FindHeaderStartNode() != nullptr;
2972 const bool bWasInFooter = aPam.GetPoint()->GetNode().FindFooterStartNode() != nullptr;
2974 // Is the cursor in a part like similar to the one we clicked on? For example,
2975 // if the cursor is in a header and we click on an empty header... don't change anything to
2976 // keep consistent behaviour due to header edit mode (and the same for the footer as well).
2978 // Otherwise, we hide the header/footer control if a separator is shown, and vice versa.
2979 if (!(bWasInHeader && eControl == FrameControlType::Header) &&
2980 !(bWasInFooter && eControl == FrameControlType::Footer))
2982 const bool bSeparatorWasVisible = rSh.IsShowHeaderFooterSeparator(eControl);
2983 rSh.SetShowHeaderFooterSeparator(eControl, !bSeparatorWasVisible);
2985 // Repaint everything
2986 Invalidate();
2988 // tdf#84929. If the footer control had not been showing, do not change the cursor position,
2989 // because the user may have scrolled to turn on the separator control and
2990 // if the cursor cannot be positioned on-screen, then the user would need to scroll back again to use the control.
2991 // This should only be done for the footer. The cursor can always be re-positioned near the header. tdf#134023.
2992 if ( eControl == FrameControlType::Footer && !bSeparatorWasVisible
2993 && !Application::IsHeadlessModeEnabled() )
2994 return;
2998 else
3000 // Make sure we have the proper Header/Footer separators shown
3001 // as these may be changed if clicking on an empty Header/Footer
3002 rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, eControl == FrameControlType::Header );
3003 rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, eControl == FrameControlType::Footer );
3005 if ( !rSh.IsHeaderFooterEdit() )
3006 rSh.ToggleHeaderFooterEdit();
3010 else
3012 if ( rSh.IsHeaderFooterEdit( ) )
3013 rSh.ToggleHeaderFooterEdit( );
3014 else
3016 // Make sure that the separators are hidden
3017 rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, false );
3018 rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
3020 // Repaint everything
3021 // FIXME fdo#67358 for unknown reasons this causes painting
3022 // problems when resizing table columns, so disable it
3023 // rSh.GetWin()->Invalidate();
3026 // Toggle Hide-Whitespace if between pages.
3027 if (rSh.GetViewOptions()->CanHideWhitespace() &&
3028 rSh.GetLayout()->IsBetweenPages(aDocPos))
3030 if (_rMEvt.GetClicks() >= 2)
3032 SwViewOption aOpt(*rSh.GetViewOptions());
3033 aOpt.SetHideWhitespaceMode(!aOpt.IsHideWhitespaceMode());
3034 rSh.ApplyViewOptions(aOpt);
3037 return;
3041 if ( IsChainMode() )
3043 SetChainMode( false );
3044 SwRect aDummy;
3045 SwFlyFrameFormat *pFormat = static_cast<SwFlyFrameFormat*>(rSh.GetFlyFrameFormat());
3046 if ( rSh.Chainable( aDummy, *pFormat, aDocPos ) == SwChainRet::OK )
3047 rSh.Chain( *pFormat, aDocPos );
3048 UpdatePointer(aDocPos, aMEvt.GetModifier());
3049 return;
3052 // After GrabFocus a shell should be pushed. That should actually
3053 // work but in practice ...
3054 m_rView.SelectShellForDrop();
3056 bool bCallBase = true;
3058 if( s_pQuickHlpData->m_bIsDisplayed )
3059 s_pQuickHlpData->Stop( rSh );
3060 s_pQuickHlpData->m_bAppendSpace = false;
3062 if( rSh.FinishOLEObj() )
3063 return; // end InPlace and the click doesn't count anymore
3065 CurrShell aCurr( &rSh );
3067 SdrView *pSdrView = rSh.GetDrawView();
3068 if ( pSdrView )
3070 if (pSdrView->MouseButtonDown(aMEvt, GetOutDev()))
3072 rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
3073 return; // SdrView's event evaluated
3077 m_bIsInMove = false;
3078 m_aStartPos = aMEvt.GetPosPixel();
3079 m_aRszMvHdlPt.setX( 0 );
3080 m_aRszMvHdlPt.setY( 0 );
3082 SwTab nMouseTabCol = SwTab::COL_NONE;
3083 const bool bTmp = !rSh.IsDrawCreate() && !m_pApplyTempl && !rSh.IsInSelect()
3084 && aMEvt.GetClicks() == 1 && MOUSE_LEFT == aMEvt.GetButtons();
3085 if ( bTmp &&
3086 SwTab::COL_NONE != (nMouseTabCol = rSh.WhichMouseTabCol( aDocPos ) ) &&
3087 !rSh.IsObjSelectable( aDocPos ) )
3089 // Enhanced table selection
3090 if ( SwTab::SEL_HORI <= nMouseTabCol && SwTab::COLSEL_VERT >= nMouseTabCol )
3092 rSh.EnterStdMode();
3093 rSh.SelectTableRowCol( aDocPos );
3094 if( SwTab::SEL_HORI != nMouseTabCol && SwTab::SEL_HORI_RTL != nMouseTabCol)
3096 m_xRowColumnSelectionStart = aDocPos;
3097 m_bIsRowDrag = SwTab::ROWSEL_HORI == nMouseTabCol||
3098 SwTab::ROWSEL_HORI_RTL == nMouseTabCol ||
3099 SwTab::COLSEL_VERT == nMouseTabCol;
3100 m_bMBPressed = true;
3101 CaptureMouse();
3103 return;
3106 if ( !rSh.IsTableMode() )
3108 // comes from table columns out of the document.
3109 if(SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol)
3110 m_rView.SetTabColFromDoc( true );
3111 else
3112 m_rView.SetTabRowFromDoc( true );
3114 m_rView.SetTabColFromDocPos( aDocPos );
3115 m_rView.InvalidateRulerPos();
3116 SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
3117 rBind.Update();
3118 if (RulerColumnDrag(
3119 aMEvt, (SwTab::COL_VERT == nMouseTabCol || SwTab::ROW_HORI == nMouseTabCol)))
3121 m_rView.SetTabColFromDoc( false );
3122 m_rView.SetTabRowFromDoc( false );
3123 m_rView.InvalidateRulerPos();
3124 rBind.Update();
3125 bCallBase = false;
3127 else
3129 return;
3133 else if (bTmp &&
3134 rSh.IsNumLabel(aDocPos))
3136 SwTextNode* pNodeAtPos = rSh.GetNumRuleNodeAtPos( aDocPos );
3137 m_rView.SetNumRuleNodeFromDoc( pNodeAtPos );
3138 m_rView.InvalidateRulerPos();
3139 SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
3140 rBind.Update();
3142 if (RulerMarginDrag(aMEvt, SwFEShell::IsVerticalModeAtNdAndPos(*pNodeAtPos, aDocPos)))
3144 m_rView.SetNumRuleNodeFromDoc( nullptr );
3145 m_rView.InvalidateRulerPos();
3146 rBind.Update();
3147 bCallBase = false;
3149 else
3151 // Make sure the pointer is set to 0, otherwise it may point to
3152 // nowhere after deleting the corresponding text node.
3153 m_rView.SetNumRuleNodeFromDoc( nullptr );
3154 return;
3158 if ( rSh.IsInSelect() )
3159 rSh.EndSelect();
3161 // query against LEFT because otherwise for example also a right
3162 // click releases the selection.
3163 if (MOUSE_LEFT == aMEvt.GetButtons())
3165 bool bOnlyText = false;
3166 m_bMBPressed = true;
3167 g_bNoInterrupt = true;
3168 m_nKS_NUMDOWN_Count = 0;
3170 CaptureMouse();
3172 // reset cursor position if applicable
3173 rSh.ResetCursorStack();
3175 switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3177 case MOUSE_LEFT:
3178 case MOUSE_LEFT + KEY_SHIFT:
3179 case MOUSE_LEFT + KEY_MOD2:
3180 if( rSh.IsObjSelected() )
3182 SdrHdl* pHdl;
3183 if( !bIsDocReadOnly &&
3184 !m_pAnchorMarker &&
3185 pSdrView &&
3186 nullptr != ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3187 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3188 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3190 // #i121463# Set selected during drag
3191 pHdl->SetSelected();
3192 m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3193 UpdatePointer(aDocPos, aMEvt.GetModifier());
3194 return;
3197 if (EnterDrawMode(aMEvt, aDocPos))
3199 g_bNoInterrupt = false;
3200 return;
3202 else if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
3204 StopInsFrame();
3205 rSh.Edit();
3208 // Without SHIFT because otherwise Toggle doesn't work at selection
3209 if (aMEvt.GetClicks() == 1)
3211 if ( rSh.IsSelFrameMode())
3213 SdrHdl* pHdl = rSh.GetDrawView()->PickHandle(aDocPos);
3214 bool bHitHandle = pHdl && pHdl->GetKind() != SdrHdlKind::Anchor &&
3215 pHdl->GetKind() != SdrHdlKind::Anchor_TR;
3217 if ((rSh.IsInsideSelectedObj(aDocPos) || bHitHandle)
3218 && (aMEvt.GetModifier() != KEY_SHIFT || bHitHandle))
3220 rSh.EnterSelFrameMode( &aDocPos );
3221 if ( !m_pApplyTempl )
3223 // only if no position to size was hit.
3224 if (!bHitHandle)
3226 StartDDTimer();
3227 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3228 SwEditWin::s_nDDStartPosX = aDocPos.X();
3230 g_bFrameDrag = true;
3232 g_bNoInterrupt = false;
3233 return;
3239 bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
3240 if ( !bExecHyperlinks )
3242 const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
3243 if ((bSecureOption && aMEvt.GetModifier() == KEY_MOD1)
3244 || (!bSecureOption && aMEvt.GetModifier() != KEY_MOD1))
3245 bExecHyperlinks = true;
3248 // Enhanced selection
3249 sal_uInt8 nNumberOfClicks = static_cast<sal_uInt8>(aMEvt.GetClicks() % 4);
3250 if (0 == nNumberOfClicks && 0 < aMEvt.GetClicks())
3251 nNumberOfClicks = 4;
3253 bool bExecDrawTextLink = false;
3255 switch (aMEvt.GetModifier() + aMEvt.GetButtons())
3257 case MOUSE_LEFT:
3258 case MOUSE_LEFT + KEY_MOD1:
3259 case MOUSE_LEFT + KEY_MOD2:
3262 // fdo#79604: first, check if a link has been clicked - do not
3263 // select fly in this case!
3264 if (1 == nNumberOfClicks)
3266 UpdatePointer(aDocPos, aMEvt.GetModifier());
3267 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3268 SwEditWin::s_nDDStartPosX = aDocPos.X();
3270 // hit a URL in DrawText object?
3271 if (bExecHyperlinks && pSdrView)
3273 SdrViewEvent aVEvt;
3274 pSdrView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
3276 if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
3277 bExecDrawTextLink = true;
3281 if (1 == nNumberOfClicks && !bExecDrawTextLink)
3283 // only try to select frame, if pointer already was
3284 // switched accordingly
3285 if ( m_aActHitType != SdrHitKind::NONE && !rSh.IsSelFrameMode() &&
3286 !GetView().GetViewFrame().GetDispatcher()->IsLocked())
3288 // Test if there is a draw object at that position and if it should be selected.
3289 bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
3291 if(bShould)
3293 m_rView.NoRotate();
3294 rSh.HideCursor();
3296 bool bUnLockView = !rSh.IsViewLocked();
3297 rSh.LockView( true );
3298 bool bSelObj
3299 = rSh.SelectObj(aDocPos, aMEvt.IsMod1() ? SW_ENTER_GROUP : 0);
3300 if( bUnLockView )
3301 rSh.LockView( false );
3303 if( bSelObj )
3305 // if the frame was deselected in the macro
3306 // the cursor just has to be displayed again
3307 if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
3308 rSh.ShowCursor();
3309 else
3311 if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
3313 m_rView.GetDrawFuncPtr()->Deactivate();
3314 m_rView.SetDrawFuncPtr(nullptr);
3315 m_rView.LeaveDrawCreate();
3316 m_rView.AttrChangedNotify(nullptr);
3319 rSh.EnterSelFrameMode( &aDocPos );
3320 g_bFrameDrag = true;
3321 UpdatePointer(aDocPos, aMEvt.GetModifier());
3323 return;
3325 else
3326 bOnlyText = rSh.IsObjSelectable( aDocPos );
3328 if (!m_rView.GetDrawFuncPtr())
3329 rSh.ShowCursor();
3331 else
3332 bOnlyText = KEY_MOD1 != aMEvt.GetModifier();
3334 else if ( rSh.IsSelFrameMode() &&
3335 (m_aActHitType == SdrHitKind::NONE ||
3336 !rSh.IsInsideSelectedObj( aDocPos )))
3338 m_rView.NoRotate();
3339 SdrHdl *pHdl;
3340 if( !bIsDocReadOnly && !m_pAnchorMarker && nullptr !=
3341 ( pHdl = pSdrView->PickHandle(aDocPos) ) &&
3342 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
3343 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
3345 m_pAnchorMarker.reset( new SwAnchorMarker( pHdl ) );
3346 UpdatePointer(aDocPos, aMEvt.GetModifier());
3347 return;
3349 else
3351 bool bUnLockView = !rSh.IsViewLocked();
3352 rSh.LockView( true );
3353 sal_uInt8 nFlag = aMEvt.IsShift() ? SW_ADD_SELECT : 0;
3354 if (aMEvt.IsMod1())
3355 nFlag = nFlag | SW_ENTER_GROUP;
3357 if ( rSh.IsSelFrameMode() )
3359 rSh.UnSelectFrame();
3360 rSh.LeaveSelFrameMode();
3361 m_rView.AttrChangedNotify(nullptr);
3364 bool bSelObj = rSh.SelectObj( aDocPos, nFlag );
3365 if( bUnLockView )
3366 rSh.LockView( false );
3368 if( !bSelObj )
3370 // move cursor here so that it is not drawn in the
3371 // frame first; ShowCursor() happens in LeaveSelFrameMode()
3372 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
3373 rSh.LeaveSelFrameMode();
3374 m_rView.AttrChangedNotify(nullptr);
3375 bCallBase = false;
3377 else
3379 rSh.HideCursor();
3380 rSh.EnterSelFrameMode( &aDocPos );
3381 rSh.SelFlyGrabCursor();
3382 rSh.MakeSelVisible();
3383 g_bFrameDrag = true;
3384 if( rSh.IsFrameSelected() &&
3385 m_rView.GetDrawFuncPtr() )
3387 m_rView.GetDrawFuncPtr()->Deactivate();
3388 m_rView.SetDrawFuncPtr(nullptr);
3389 m_rView.LeaveDrawCreate();
3390 m_rView.AttrChangedNotify(nullptr);
3392 UpdatePointer(aDocPos, aMEvt.GetModifier());
3393 return;
3399 switch ( nNumberOfClicks )
3401 case 1:
3402 break;
3403 case 2:
3405 g_bFrameDrag = false;
3406 if (!bIsDocReadOnly && rSh.IsInsideSelectedObj(aDocPos)
3407 && (FlyProtectFlags::NONE
3408 == rSh.IsSelObjProtected(FlyProtectFlags::Content
3409 | FlyProtectFlags::Parent)
3410 || rSh.GetSelectionType() == SelectionType::Ole))
3412 /* This is no good: on the one hand GetSelectionType is used as flag field
3413 * (take a look into the GetSelectionType method) and on the other hand the
3414 * return value is used in a switch without proper masking (very nice), this must lead to trouble
3416 switch ( rSh.GetSelectionType() & ~SelectionType( SelectionType::FontWork | SelectionType::ExtrudedCustomShape ) )
3418 case SelectionType::Graphic:
3419 ResetMouseButtonDownFlags();
3420 if (!comphelper::LibreOfficeKit::isActive())
3422 GetView().GetViewFrame().GetBindings().Execute(
3423 FN_FORMAT_GRAFIC_DLG, nullptr,
3424 SfxCallMode::RECORD|SfxCallMode::SLOT);
3426 return;
3428 // double click on OLE object --> OLE-InPlace
3429 case SelectionType::Ole:
3430 ResetMouseButtonDownFlags();
3431 rSh.LaunchOLEObj();
3432 return;
3434 case SelectionType::Frame:
3435 ResetMouseButtonDownFlags();
3436 if (!comphelper::LibreOfficeKit::isActive())
3438 GetView().GetViewFrame().GetBindings().Execute(
3439 FN_FORMAT_FRAME_DLG, nullptr,
3440 SfxCallMode::RECORD|SfxCallMode::SLOT);
3442 return;
3444 case SelectionType::DrawObject:
3445 ResetMouseButtonDownFlags();
3446 EnterDrawTextMode(aDocPos);
3447 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
3448 pSwDrawTextShell->Init();
3449 return;
3451 default: break;
3455 // if the cursor position was corrected or if a Fly
3456 // was selected in ReadOnlyMode, no word selection, except when tiled rendering.
3457 if ((!g_bValidCursorPos || rSh.IsFrameSelected()) && !comphelper::LibreOfficeKit::isActive())
3458 return;
3460 SwField *pField;
3461 bool bFootnote = false;
3463 if( !bIsDocReadOnly &&
3464 (nullptr != (pField = rSh.GetCurField(true)) ||
3465 ( bFootnote = rSh.GetCurFootnote() ) ) )
3467 ResetMouseButtonDownFlags();
3468 if( bFootnote )
3469 GetView().GetViewFrame().GetBindings().Execute( FN_EDIT_FOOTNOTE );
3470 else
3472 SwFieldTypesEnum nTypeId = pField->GetTypeId();
3473 SfxViewFrame& rVFrame = GetView().GetViewFrame();
3474 switch( nTypeId )
3476 case SwFieldTypesEnum::Postit:
3477 case SwFieldTypesEnum::Script:
3479 // if it's a Readonly region, status has to be enabled
3480 sal_uInt16 nSlot = SwFieldTypesEnum::Postit == nTypeId ? FN_POSTIT : FN_JAVAEDIT;
3481 SfxBoolItem aItem(nSlot, true);
3482 rVFrame.GetBindings().SetState(aItem);
3483 rVFrame.GetBindings().Execute(nSlot);
3484 break;
3486 case SwFieldTypesEnum::Authority :
3487 rVFrame.GetBindings().Execute(FN_EDIT_AUTH_ENTRY_DLG);
3488 break;
3489 case SwFieldTypesEnum::Input:
3490 case SwFieldTypesEnum::Dropdown:
3491 case SwFieldTypesEnum::SetInput:
3492 rVFrame.GetBindings().Execute(FN_UPDATE_INPUTFIELDS);
3493 break;
3494 default:
3495 rVFrame.GetBindings().Execute(FN_EDIT_FIELD);
3498 return;
3500 // in extended mode double and triple
3501 // click has no effect.
3502 if ( rSh.IsExtMode() || rSh.IsBlockMode() )
3503 return;
3505 // select word, AdditionalMode if applicable
3506 if (KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode())
3508 rSh.EnterAddMode();
3509 rSh.SelWrd( &aDocPos );
3510 rSh.LeaveAddMode();
3512 else
3514 if (!rSh.SelWrd(&aDocPos) && comphelper::LibreOfficeKit::isActive())
3515 // Double click did not select any word: try to
3516 // select the current cell in case we are in a
3517 // table.
3518 rSh.SelTableBox();
3521 SwContentAtPos aContentAtPos(IsAttrAtPos::FormControl);
3522 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3523 aContentAtPos.aFnd.pFieldmark != nullptr)
3525 IFieldmark *pFieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
3526 if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN || pFieldBM->GetFieldname( ) == ODF_FORMDATE )
3528 ResetMouseButtonDownFlags();
3529 rSh.getIDocumentMarkAccess()->ClearFieldActivation();
3530 GetView().GetViewFrame().GetBindings().Execute(SID_FM_CTL_PROPERTIES);
3531 return;
3535 // tdf#143158 - handle alphabetical index entries
3536 SwContentAtPos aToxContentAtPos(IsAttrAtPos::ToxMark);
3537 if (rSh.GetContentAtPos(aDocPos, aToxContentAtPos))
3539 const OUString sToxText = aToxContentAtPos.sStr;
3540 if (!sToxText.isEmpty() && aToxContentAtPos.pFndTextAttr)
3542 const SwTOXType* pTType
3543 = aToxContentAtPos.pFndTextAttr->GetTOXMark().GetTOXType();
3544 if (pTType && pTType->GetType() == TOXTypes::TOX_INDEX)
3546 ResetMouseButtonDownFlags();
3547 GetView().GetViewFrame().GetBindings().Execute(
3548 FN_EDIT_IDX_ENTRY_DLG);
3549 return;
3554 g_bHoldSelection = true;
3555 return;
3557 case 3:
3558 case 4:
3560 g_bFrameDrag = false;
3561 // in extended mode double and triple
3562 // click has no effect.
3563 if ( rSh.IsExtMode() )
3564 return;
3566 // if the cursor position was corrected or if a Fly
3567 // was selected in ReadOnlyMode, no word selection.
3568 if ( !g_bValidCursorPos || rSh.IsFrameSelected() )
3569 return;
3571 // select line, AdditionalMode if applicable
3572 const bool bMod = KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode();
3574 if ( bMod )
3575 rSh.EnterAddMode();
3577 // Enhanced selection
3578 if ( 3 == nNumberOfClicks )
3579 rSh.SelSentence( &aDocPos );
3580 else
3581 rSh.SelPara( &aDocPos );
3583 if ( bMod )
3584 rSh.LeaveAddMode();
3586 g_bHoldSelection = true;
3587 return;
3590 default:
3591 return;
3594 [[fallthrough]];
3596 case MOUSE_LEFT + KEY_SHIFT:
3597 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
3599 bool bLockView = m_bWasShdwCursor;
3601 switch (aMEvt.GetModifier())
3603 case KEY_MOD1 + KEY_SHIFT:
3605 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3607 m_rView.NoRotate();
3608 rSh.HideCursor();
3609 if ( rSh.IsSelFrameMode() )
3610 rSh.SelectObj(aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP);
3611 else
3612 { if ( rSh.SelectObj( aDocPos, SW_ADD_SELECT | SW_ENTER_GROUP ) )
3614 rSh.EnterSelFrameMode( &aDocPos );
3615 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3616 SwEditWin::s_nDDStartPosX = aDocPos.X();
3617 g_bFrameDrag = true;
3618 return;
3622 else if( rSh.IsSelFrameMode() &&
3623 rSh.GetDrawView()->PickHandle( aDocPos ))
3625 g_bFrameDrag = true;
3626 g_bNoInterrupt = false;
3627 return;
3630 break;
3631 case KEY_MOD1:
3632 if ( !bExecDrawTextLink )
3634 if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
3636 // ctrl+left-click on outline node frame
3637 SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3638 if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3640 SwOutlineNodes::size_type nPos;
3641 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
3643 ToggleOutlineContentVisibility(nPos, false);
3644 return;
3648 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3650 m_rView.NoRotate();
3651 rSh.HideCursor();
3652 if ( rSh.IsSelFrameMode() )
3653 rSh.SelectObj(aDocPos, SW_ENTER_GROUP);
3654 else
3655 { if ( rSh.SelectObj( aDocPos, SW_ENTER_GROUP ) )
3657 rSh.EnterSelFrameMode( &aDocPos );
3658 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3659 SwEditWin::s_nDDStartPosX = aDocPos.X();
3660 g_bFrameDrag = true;
3661 return;
3665 else if( rSh.IsSelFrameMode() &&
3666 rSh.GetDrawView()->PickHandle( aDocPos ))
3668 g_bFrameDrag = true;
3669 g_bNoInterrupt = false;
3670 return;
3672 else
3674 if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3676 rSh.PushMode();
3677 g_bModePushed = true;
3679 bool bUnLockView = !rSh.IsViewLocked();
3680 rSh.LockView( true );
3681 rSh.EnterAddMode();
3682 if( bUnLockView )
3683 rSh.LockView( false );
3685 bCallBase = false;
3688 break;
3689 case KEY_MOD2:
3691 if ( !rSh.IsAddMode() && !rSh.IsExtMode() && !rSh.IsBlockMode() )
3693 rSh.PushMode();
3694 g_bModePushed = true;
3695 bool bUnLockView = !rSh.IsViewLocked();
3696 rSh.LockView( true );
3697 rSh.EnterBlockMode();
3698 if( bUnLockView )
3699 rSh.LockView( false );
3701 bCallBase = false;
3703 break;
3704 case KEY_SHIFT:
3706 if (nNumberOfClicks == 2)
3708 // Left mouse button, shift, double-click: see if we have a graphic and
3709 // dispatch its dialog in this case.
3710 if (rSh.GetSelectionType() == SelectionType::Graphic)
3712 GetView().GetViewFrame().GetBindings().Execute(
3713 FN_FORMAT_GRAFIC_DLG, nullptr,
3714 SfxCallMode::RECORD | SfxCallMode::SLOT);
3715 return;
3719 if ( !m_bInsDraw && IsDrawObjSelectable( rSh, aDocPos ) )
3721 m_rView.NoRotate();
3722 rSh.HideCursor();
3723 if ( rSh.IsSelFrameMode() )
3725 rSh.SelectObj(aDocPos, SW_ADD_SELECT);
3727 const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
3728 if (rMarkList.GetMark(0) == nullptr)
3730 rSh.LeaveSelFrameMode();
3731 m_rView.AttrChangedNotify(nullptr);
3732 g_bFrameDrag = false;
3735 else
3736 { if ( rSh.SelectObj( aDocPos ) )
3738 rSh.EnterSelFrameMode( &aDocPos );
3739 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3740 SwEditWin::s_nDDStartPosX = aDocPos.X();
3741 g_bFrameDrag = true;
3742 return;
3746 else
3748 bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
3749 if (bShould)
3751 // Left mouse button, shift, non-double-click, not a draw object and
3752 // have an object to select: select it.
3753 rSh.HideCursor();
3754 bool bSelObj = rSh.SelectObj(aDocPos);
3755 if (bSelObj)
3757 rSh.EnterSelFrameMode(&aDocPos);
3759 return;
3762 if ( rSh.IsSelFrameMode() &&
3763 rSh.IsInsideSelectedObj( aDocPos ) )
3765 rSh.EnterSelFrameMode( &aDocPos );
3766 SwEditWin::s_nDDStartPosY = aDocPos.Y();
3767 SwEditWin::s_nDDStartPosX = aDocPos.X();
3768 g_bFrameDrag = true;
3769 return;
3771 if ( rSh.IsSelFrameMode() )
3773 rSh.UnSelectFrame();
3774 rSh.LeaveSelFrameMode();
3775 m_rView.AttrChangedNotify(nullptr);
3776 g_bFrameDrag = false;
3778 if ( !rSh.IsExtMode() )
3780 // don't start a selection when an
3781 // URL field or a graphic is clicked
3782 bool bSttSelect = rSh.HasSelection() ||
3783 PointerStyle::RefHand != GetPointer();
3785 if( !bSttSelect )
3787 bSttSelect = true;
3788 if( bExecHyperlinks )
3790 SwContentAtPos aContentAtPos(
3791 IsAttrAtPos::Ftn |
3792 IsAttrAtPos::InetAttr );
3794 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) )
3796 if( !rSh.IsViewLocked() &&
3797 !rSh.IsReadOnlyAvailable() &&
3798 aContentAtPos.IsInProtectSect() )
3799 bLockView = true;
3801 bSttSelect = false;
3803 else if( rSh.IsURLGrfAtPos( aDocPos ))
3804 bSttSelect = false;
3808 if( bSttSelect )
3809 rSh.SttSelect();
3812 bCallBase = false;
3813 break;
3815 default:
3816 if( !rSh.IsViewLocked() )
3818 SwContentAtPos aContentAtPos( IsAttrAtPos::ClickField |
3819 IsAttrAtPos::InetAttr );
3820 if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) &&
3821 !rSh.IsReadOnlyAvailable() &&
3822 aContentAtPos.IsInProtectSect() )
3823 bLockView = true;
3827 if ( rSh.IsGCAttr() )
3829 rSh.GCAttr();
3830 rSh.ClearGCAttr();
3833 SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
3834 bool bEditableFieldClicked = false;
3836 // Are we clicking on a field?
3837 if (rSh.GetContentAtPos(aDocPos, aFieldAtPos))
3839 bool bEditableField = (aFieldAtPos.pFndTextAttr != nullptr
3840 && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD);
3842 if (!bEditableField)
3844 rSh.CallSetCursor(&aDocPos, bOnlyText);
3845 // Unfortunately the cursor may be on field
3846 // position or on position after field depending on which
3847 // half of the field was clicked on.
3848 SwTextAttr const*const pTextField(aFieldAtPos.pFndTextAttr);
3849 if (pTextField &&
3850 rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() != pTextField->GetStart())
3852 assert(rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() == (pTextField->GetStart() + 1));
3853 rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
3855 // don't go into the !bOverSelect block below - it moves
3856 // the cursor
3857 break;
3859 else
3861 bEditableFieldClicked = true;
3865 bool bOverSelect = rSh.TestCurrPam( aDocPos );
3866 bool bOverURLGrf = false;
3867 if( !bOverSelect )
3868 bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
3870 if ( !bOverSelect || rSh.IsInSelect() )
3872 MoveCursor( rSh, aDocPos, bOnlyText, bLockView );
3873 bCallBase = false;
3875 if (!bOverURLGrf && !bExecDrawTextLink && !bOnlyText)
3877 const SelectionType nSelType = rSh.GetSelectionType();
3878 // Check in general, if an object is selectable at given position.
3879 // Thus, also text fly frames in background become selectable via Ctrl-Click.
3880 if ( ( nSelType & SelectionType::Ole ||
3881 nSelType & SelectionType::Graphic ||
3882 rSh.IsObjSelectable( aDocPos ) ) && !lcl_urlOverBackground( rSh, aDocPos ) )
3884 SwMvContext aMvContext( &rSh );
3885 rSh.EnterSelFrameMode();
3886 bCallBase = false;
3889 if ( !bOverSelect && bEditableFieldClicked && (!pCursorField ||
3890 pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
3892 // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
3893 // and CH_TXT_ATR_INPUTFIELDEND
3894 rSh.SttSelect();
3895 rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
3896 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
3898 // don't reset here any longer so that, in case through MouseMove
3899 // with pressed Ctrl key a multiple-selection should happen,
3900 // the previous selection is not released in Drag.
3901 break;
3905 else if (MOUSE_RIGHT == aMEvt.GetButtons())
3907 if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton()
3908 && aMEvt.GetModifier() == KEY_MOD1)
3910 // ctrl+right-click on outline node frame
3911 SwContentAtPos aContentAtPos(IsAttrAtPos::Outline);
3912 if(rSh.GetContentAtPos(aDocPos, aContentAtPos))
3914 SwOutlineNodes::size_type nPos;
3915 if (rSh.GetNodes().GetOutLineNds().Seek_Entry(aContentAtPos.aFnd.pNode, &nPos))
3917 ToggleOutlineContentVisibility(nPos, !rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent());
3918 return;
3922 else if (!aMEvt.GetModifier() && static_cast<sal_uInt8>(aMEvt.GetClicks() % 4) == 1
3923 && !rSh.TestCurrPam(aDocPos))
3925 SwContentAtPos aFieldAtPos(IsAttrAtPos::Field);
3927 // Are we clicking on a field?
3928 if (g_bValidCursorPos
3929 && rSh.GetContentAtPos(aDocPos, aFieldAtPos)
3930 && aFieldAtPos.pFndTextAttr != nullptr
3931 && aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD
3932 && (!pCursorField || pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
3934 // Move the cursor
3935 MoveCursor( rSh, aDocPos, rSh.IsObjSelectable( aDocPos ), m_bWasShdwCursor );
3936 bCallBase = false;
3938 // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
3939 // and CH_TXT_ATR_INPUTFIELDEND
3940 rSh.SttSelect();
3941 rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
3942 *(aFieldAtPos.pFndTextAttr->End()) - 1 );
3947 if (bCallBase)
3948 Window::MouseButtonDown(aMEvt);
3951 bool SwEditWin::changeMousePointer(Point const & rDocPoint)
3953 SwWrtShell & rShell = m_rView.GetWrtShell();
3955 SwTab nMouseTabCol;
3956 if ( SwTab::COL_NONE != (nMouseTabCol = rShell.WhichMouseTabCol( rDocPoint ) ) &&
3957 !rShell.IsObjSelectable( rDocPoint ) )
3959 PointerStyle nPointer = PointerStyle::Null;
3960 bool bChkTableSel = false;
3962 switch ( nMouseTabCol )
3964 case SwTab::COL_VERT :
3965 case SwTab::ROW_HORI :
3966 nPointer = PointerStyle::VSizeBar;
3967 bChkTableSel = true;
3968 break;
3969 case SwTab::ROW_VERT :
3970 case SwTab::COL_HORI :
3971 nPointer = PointerStyle::HSizeBar;
3972 bChkTableSel = true;
3973 break;
3974 // Enhanced table selection
3975 case SwTab::SEL_HORI :
3976 nPointer = PointerStyle::TabSelectSE;
3977 break;
3978 case SwTab::SEL_HORI_RTL :
3979 case SwTab::SEL_VERT :
3980 nPointer = PointerStyle::TabSelectSW;
3981 break;
3982 case SwTab::COLSEL_HORI :
3983 case SwTab::ROWSEL_VERT :
3984 nPointer = PointerStyle::TabSelectS;
3985 break;
3986 case SwTab::ROWSEL_HORI :
3987 nPointer = PointerStyle::TabSelectE;
3988 break;
3989 case SwTab::ROWSEL_HORI_RTL :
3990 case SwTab::COLSEL_VERT :
3991 nPointer = PointerStyle::TabSelectW;
3992 break;
3993 default: break; // prevent compiler warning
3996 if ( PointerStyle::Null != nPointer &&
3997 // i#35543 - Enhanced table selection is explicitly allowed in table mode
3998 ( !bChkTableSel || !rShell.IsTableMode() ) &&
3999 !comphelper::LibreOfficeKit::isActive() )
4001 SetPointer( nPointer );
4004 return true;
4006 else if (rShell.IsNumLabel(rDocPoint, RULER_MOUSE_MARGINWIDTH))
4008 // i#42921 - consider vertical mode
4009 SwTextNode* pNodeAtPos = rShell.GetNumRuleNodeAtPos( rDocPoint );
4010 const PointerStyle nPointer =
4011 SwFEShell::IsVerticalModeAtNdAndPos( *pNodeAtPos, rDocPoint )
4012 ? PointerStyle::VSizeBar
4013 : PointerStyle::HSizeBar;
4014 SetPointer( nPointer );
4016 return true;
4018 return false;
4021 void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
4023 MouseEvent rMEvt(_rMEvt);
4025 if (comphelper::LibreOfficeKit::isActive())
4027 if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
4029 pWindow->MouseMove(rMEvt);
4030 return;
4034 //ignore key modifiers for format paintbrush
4036 bool bExecFormatPaintbrush = m_pApplyTempl && m_pApplyTempl->m_pFormatClipboard
4037 && m_pApplyTempl->m_pFormatClipboard->HasContent();
4038 if( bExecFormatPaintbrush )
4039 rMEvt = MouseEvent( _rMEvt.GetPosPixel(), _rMEvt.GetClicks(),
4040 _rMEvt.GetMode(), _rMEvt.GetButtons() );
4043 // as long as an action is running the MouseMove should be disconnected
4044 // otherwise bug 40102 occurs
4045 SwWrtShell &rSh = m_rView.GetWrtShell();
4046 if( rSh.ActionPend() )
4047 return ;
4049 if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
4051 // add/remove outline content hide button
4052 const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4053 SwOutlineNodes::size_type nPos;
4054 SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline);
4055 if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
4057 // mouse pointer is on an outline paragraph node
4058 if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
4060 // Get the outline paragraph frame and compare it to the saved outline frame. If they
4061 // are not the same, remove the fold button from the saved outline frame, if not
4062 // already removed, and then add a fold button to the mouse over outline frame if
4063 // the content is not folded.
4064 SwContentFrame* pContentFrame =
4065 aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout());
4066 if (pContentFrame != m_pSavedOutlineFrame)
4068 if (m_pSavedOutlineFrame)
4070 if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4072 SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4073 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4074 rSh.GetAttrOutlineContentVisible(nPos))
4076 GetFrameControlsManager().RemoveControlsByType(
4077 FrameControlType::Outline, m_pSavedOutlineFrame);
4081 m_pSavedOutlineFrame = static_cast<SwTextFrame*>(pContentFrame);
4083 // show fold button if outline content is visible
4084 if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
4085 rSh.GetAttrOutlineContentVisible(nPos))
4086 GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
4089 else if (m_pSavedOutlineFrame)
4091 // The saved frame may not still be in the document, e.g., when an outline paragraph
4092 // is deleted. This causes the call to GetTextNodeFirst to behave badly. Use
4093 // isFrameAreaDefinitionValid to check if the frame is still in the document.
4094 if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4096 // current pointer pos is not over an outline frame
4097 // previous pointer pos was over an outline frame
4098 // remove outline content visibility button if showing
4099 SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4100 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4101 rSh.GetAttrOutlineContentVisible(nPos))
4103 GetFrameControlsManager().RemoveControlsByType(
4104 FrameControlType::Outline, m_pSavedOutlineFrame);
4107 m_pSavedOutlineFrame = nullptr;
4111 if( m_pShadCursor && 0 != (rMEvt.GetModifier() + rMEvt.GetButtons() ) )
4113 m_pShadCursor.reset();
4116 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly();
4118 CurrShell aCurr( &rSh );
4120 //aPixPt == Point in Pixel, relative to ChildWin
4121 //aDocPt == Point in Twips, document coordinates
4122 const Point aPixPt( rMEvt.GetPosPixel() );
4123 const Point aDocPt( PixelToLogic( aPixPt ) );
4125 if ( IsChainMode() )
4127 UpdatePointer( aDocPt, rMEvt.GetModifier() );
4128 return;
4131 SdrView *pSdrView = rSh.GetDrawView();
4133 const SwCallMouseEvent aLastCallEvent( m_aSaveCallEvent );
4134 m_aSaveCallEvent.Clear();
4136 if ( !bIsDocReadOnly && pSdrView && pSdrView->MouseMove(rMEvt,GetOutDev()) )
4138 SetPointer( PointerStyle::Text );
4139 return; // evaluate SdrView's event
4142 const Point aOldPt( rSh.VisArea().Pos() );
4143 const bool bInsWin = rSh.VisArea().Contains( aDocPt ) || comphelper::LibreOfficeKit::isActive();
4145 if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
4147 if (m_pSavedOutlineFrame && !bInsWin)
4149 // the mouse pointer has left the building (edit window)
4150 // remove the outline content visibility button if showing
4151 if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
4153 const SwNodes& rNds = rSh.GetDoc()->GetNodes();
4154 SwOutlineNodes::size_type nPos;
4155 SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst();
4156 if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
4157 rSh.GetAttrOutlineContentVisible(nPos))
4159 GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline,
4160 m_pSavedOutlineFrame);
4163 m_pSavedOutlineFrame = nullptr;
4167 if( m_pShadCursor && !bInsWin )
4169 m_pShadCursor.reset();
4172 if( bInsWin && m_xRowColumnSelectionStart )
4174 EnterArea();
4175 Point aPos( aDocPt );
4176 if( rSh.SelectTableRowCol( *m_xRowColumnSelectionStart, &aPos, m_bIsRowDrag ))
4177 return;
4180 // position is necessary for OS/2 because obviously after a MB-Down
4181 // a MB-Move is called immediately.
4182 if( g_bDDTimerStarted )
4184 Point aDD( SwEditWin::s_nDDStartPosX, SwEditWin::s_nDDStartPosY );
4185 aDD = LogicToPixel( aDD );
4186 tools::Rectangle aRect( aDD.X()-3, aDD.Y()-3, aDD.X()+3, aDD.Y()+3 );
4187 if ( !aRect.Contains( aPixPt ) )
4188 StopDDTimer( &rSh, aDocPt );
4191 if(m_rView.GetDrawFuncPtr())
4193 if( m_bInsDraw )
4195 m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4196 if ( !bInsWin )
4198 Point aTmp( aDocPt );
4199 aTmp += rSh.VisArea().Pos() - aOldPt;
4200 LeaveArea( aTmp );
4202 else
4203 EnterArea();
4204 return;
4206 else if(!rSh.IsFrameSelected() && !rSh.IsObjSelected())
4208 SfxBindings &rBnd = rSh.GetView().GetViewFrame().GetBindings();
4209 Point aRelPos = rSh.GetRelativePagePosition(aDocPt);
4210 if(aRelPos.X() >= 0)
4212 FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebView*>( &GetView()) != nullptr );
4213 SW_MOD()->PutItem(SfxUInt16Item(SID_ATTR_METRIC, static_cast< sal_uInt16 >(eMetric)));
4214 const SfxPointItem aTmp1( SID_ATTR_POSITION, aRelPos );
4215 rBnd.SetState( aTmp1 );
4217 else
4219 rBnd.Invalidate(SID_ATTR_POSITION);
4221 rBnd.Invalidate(SID_ATTR_SIZE);
4222 const SvxStatusItem aCell( SID_TABLE_CELL, OUString(), StatusCategory::NONE );
4223 rBnd.SetState( aCell );
4227 // determine if we only change the mouse pointer and return
4228 if (!bIsDocReadOnly && bInsWin && !m_pApplyTempl && !rSh.IsInSelect() && changeMousePointer(aDocPt))
4230 return;
4233 bool bDelShadCursor = true;
4235 switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4237 case MOUSE_LEFT:
4238 if( m_pAnchorMarker )
4240 // Now we need to refresh the SdrHdl pointer of m_pAnchorMarker.
4241 // This looks a little bit tricky, but it solves the following
4242 // problem: the m_pAnchorMarker contains a pointer to an SdrHdl,
4243 // if the FindAnchorPos-call cause a scrolling of the visible
4244 // area, it's possible that the SdrHdl will be destroyed and a
4245 // new one will initialized at the original position(GetHdlPos).
4246 // So the m_pAnchorMarker has to find the right SdrHdl, if it's
4247 // the old one, it will find it with position aOld, if this one
4248 // is destroyed, it will find a new one at position GetHdlPos().
4250 const Point aOld = m_pAnchorMarker->GetPosForHitTest( *(rSh.GetOut()) );
4251 Point aNew = rSh.FindAnchorPos( aDocPt );
4252 SdrHdl* pHdl;
4253 if( pSdrView && (nullptr!=( pHdl = pSdrView->PickHandle( aOld ) )||
4254 nullptr !=(pHdl = pSdrView->PickHandle( m_pAnchorMarker->GetHdlPos()) ) ) &&
4255 ( pHdl->GetKind() == SdrHdlKind::Anchor ||
4256 pHdl->GetKind() == SdrHdlKind::Anchor_TR ) )
4258 m_pAnchorMarker->ChgHdl( pHdl );
4259 if( aNew.X() || aNew.Y() )
4261 m_pAnchorMarker->SetPos( aNew );
4262 m_pAnchorMarker->SetLastPos( aDocPt );
4265 else
4267 m_pAnchorMarker.reset();
4270 if ( m_bInsDraw )
4272 if ( !m_bMBPressed )
4273 break;
4274 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4276 if ( !bInsWin )
4277 LeaveArea( aDocPt );
4278 else
4279 EnterArea();
4280 if ( m_rView.GetDrawFuncPtr() )
4282 pSdrView->SetOrtho(false);
4283 m_rView.GetDrawFuncPtr()->MouseMove( rMEvt );
4285 m_bIsInMove = true;
4287 return;
4291 SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
4292 if (pWrdCnt)
4293 pWrdCnt->UpdateCounts();
4295 [[fallthrough]];
4297 case MOUSE_LEFT + KEY_SHIFT:
4298 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4299 if ( !m_bMBPressed )
4300 break;
4301 [[fallthrough]];
4302 case MOUSE_LEFT + KEY_MOD1:
4303 if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4305 if( !m_bMBPressed )
4306 break;
4308 if ( m_bIsInMove || IsMinMove( m_aStartPos, aPixPt ) )
4310 // event processing for resizing
4311 if (pSdrView && pSdrView->AreObjectsMarked())
4313 const Point aSttPt( PixelToLogic( m_aStartPos ) );
4315 // can we start?
4316 if( SdrHdlKind::User == g_eSdrMoveHdl )
4318 SdrHdl* pHdl = pSdrView->PickHandle( aSttPt );
4319 g_eSdrMoveHdl = pHdl ? pHdl->GetKind() : SdrHdlKind::Move;
4322 const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4323 const SvxMacro* pMacro = nullptr;
4325 SvMacroItemId nEvent = SdrHdlKind::Move == g_eSdrMoveHdl
4326 ? SvMacroItemId::SwFrmMove
4327 : SvMacroItemId::SwFrmResize;
4329 if (nullptr != pFlyFormat)
4330 pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4331 if (nullptr != pMacro &&
4332 // or notify only e.g. every 20 Twip?
4333 m_aRszMvHdlPt != aDocPt )
4335 m_aRszMvHdlPt = aDocPt;
4336 sal_uInt32 nPos = 0;
4337 SbxArrayRef xArgs = new SbxArray;
4338 SbxVariableRef xVar = new SbxVariable;
4339 xVar->PutString( pFlyFormat->GetName() );
4340 xArgs->Put(xVar.get(), ++nPos);
4342 if( SvMacroItemId::SwFrmResize == nEvent )
4344 xVar = new SbxVariable;
4345 xVar->PutUShort( static_cast< sal_uInt16 >(g_eSdrMoveHdl) );
4346 xArgs->Put(xVar.get(), ++nPos);
4349 xVar = new SbxVariable;
4350 xVar->PutLong( aDocPt.X() - aSttPt.X() );
4351 xArgs->Put(xVar.get(), ++nPos);
4352 xVar = new SbxVariable;
4353 xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4354 xArgs->Put(xVar.get(), ++nPos);
4356 OUString sRet;
4358 ReleaseMouse();
4360 rSh.ExecMacro( *pMacro, &sRet, xArgs.get() );
4362 CaptureMouse();
4364 if( !sRet.isEmpty() && sRet.toInt32()!=0 )
4365 return ;
4368 // event processing for resizing
4370 if( bIsDocReadOnly )
4371 break;
4373 bool bResizeKeepRatio = rSh.GetSelectionType() & SelectionType::Graphic ||
4374 rSh.GetSelectionType() & SelectionType::Media ||
4375 rSh.GetSelectionType() & SelectionType::Ole;
4376 bool bisResize = g_eSdrMoveHdl != SdrHdlKind::Move;
4378 if (pSdrView)
4380 // Resize proportionally when media is selected and the user drags on a corner
4381 const Point aSttPt(PixelToLogic(m_aStartPos));
4382 SdrHdl* pHdl = pSdrView->PickHandle(aSttPt);
4383 if (pHdl)
4384 bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
4386 if (pSdrView->GetDragMode() == SdrDragMode::Crop)
4387 bisResize = false;
4388 if (rMEvt.IsShift())
4390 pSdrView->SetAngleSnapEnabled(!bResizeKeepRatio);
4391 if (bisResize)
4392 pSdrView->SetOrtho(!bResizeKeepRatio);
4393 else
4394 pSdrView->SetOrtho(true);
4396 else
4398 pSdrView->SetAngleSnapEnabled(bResizeKeepRatio);
4399 if (bisResize)
4400 pSdrView->SetOrtho(bResizeKeepRatio);
4401 else
4402 pSdrView->SetOrtho(false);
4406 rSh.Drag( &aDocPt, rMEvt.IsShift() );
4407 m_bIsInMove = true;
4409 else if( bIsDocReadOnly )
4410 break;
4412 if ( !bInsWin )
4414 Point aTmp( aDocPt );
4415 aTmp += rSh.VisArea().Pos() - aOldPt;
4416 LeaveArea( aTmp );
4418 else if(m_bIsInMove)
4419 EnterArea();
4420 return;
4422 if ( !rSh.IsSelFrameMode() && !g_bDDINetAttr &&
4423 (IsMinMove( m_aStartPos,aPixPt ) || m_bIsInMove) &&
4424 (rSh.IsInSelect() || !rSh.TestCurrPam( aDocPt )) )
4426 if ( pSdrView )
4428 if ( rMEvt.IsShift() )
4429 pSdrView->SetOrtho(true);
4430 else
4431 pSdrView->SetOrtho(false);
4433 if ( !bInsWin )
4435 Point aTmp( aDocPt );
4436 aTmp += rSh.VisArea().Pos() - aOldPt;
4437 LeaveArea( aTmp );
4439 else
4441 if( !rMEvt.IsSynthetic() &&
4442 ( MOUSE_LEFT != rMEvt.GetButtons() ||
4443 KEY_MOD1 != rMEvt.GetModifier() ||
4444 !rSh.Is_FnDragEQBeginDrag() ||
4445 rSh.IsAddMode() ) )
4447 rSh.Drag( &aDocPt, false );
4449 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4450 EnterArea();
4454 g_bDDINetAttr = false;
4455 break;
4456 case 0:
4458 if ( m_pApplyTempl )
4460 UpdatePointer(aDocPt); // maybe a frame has to be marked here
4461 break;
4463 // change ui if mouse is over SwPostItField
4464 // TODO: do the same thing for redlines IsAttrAtPos::Redline
4465 SwContentAtPos aContentAtPos( IsAttrAtPos::Field);
4466 if (rSh.GetContentAtPos(aDocPt, aContentAtPos, false))
4468 const SwField* pField = aContentAtPos.aFnd.pField;
4469 if (pField->Which()== SwFieldIds::Postit)
4471 m_rView.GetPostItMgr()->SetShadowState(reinterpret_cast<const SwPostItField*>(pField),false);
4473 else
4474 m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4476 else
4477 m_rView.GetPostItMgr()->SetShadowState(nullptr,false);
4478 [[fallthrough]];
4480 case KEY_SHIFT:
4481 case KEY_MOD2:
4482 case KEY_MOD1:
4483 if ( !m_bInsDraw )
4485 bool bTstShdwCursor = true;
4487 UpdatePointer( aDocPt, rMEvt.GetModifier() );
4489 const SwFrameFormat* pFormat = nullptr;
4490 const SwFormatINetFormat* pINet = nullptr;
4491 SwContentAtPos aContentAtPos( IsAttrAtPos::InetAttr );
4492 if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
4493 pINet = static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr);
4495 const void* pTmp = pINet;
4497 if( pINet ||
4498 nullptr != ( pTmp = pFormat = rSh.GetFormatFromAnyObj( aDocPt )))
4500 bTstShdwCursor = false;
4501 if( pTmp == pINet )
4502 m_aSaveCallEvent.Set( pINet );
4503 else
4505 IMapObject* pIMapObj = pFormat->GetIMapObject( aDocPt );
4506 if( pIMapObj )
4507 m_aSaveCallEvent.Set( pFormat, pIMapObj );
4508 else
4509 m_aSaveCallEvent.Set( EVENT_OBJECT_URLITEM, pFormat );
4512 // should be over an InternetField with an
4513 // embedded macro?
4514 if( m_aSaveCallEvent != aLastCallEvent )
4516 if( aLastCallEvent.HasEvent() )
4517 rSh.CallEvent( SvMacroItemId::OnMouseOut,
4518 aLastCallEvent, true );
4519 // 0 says that the object doesn't have any table
4520 if( !rSh.CallEvent( SvMacroItemId::OnMouseOver,
4521 m_aSaveCallEvent ))
4522 m_aSaveCallEvent.Clear();
4525 else if( aLastCallEvent.HasEvent() )
4527 // cursor was on an object
4528 rSh.CallEvent( SvMacroItemId::OnMouseOut,
4529 aLastCallEvent, true );
4532 if( bTstShdwCursor && bInsWin && !bIsDocReadOnly &&
4533 !m_bInsFrame &&
4534 !rSh.GetViewOptions()->getBrowseMode() &&
4535 rSh.GetViewOptions()->IsShadowCursor() &&
4536 !(rMEvt.GetModifier() + rMEvt.GetButtons()) &&
4537 !rSh.HasSelection() && !GetOutDev()->GetConnectMetaFile() )
4539 SwRect aRect;
4540 sal_Int16 eOrient;
4541 SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
4542 if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, eOrient ))
4544 if( !m_pShadCursor )
4545 m_pShadCursor.reset( new SwShadowCursor( *this,
4546 rSh.GetViewOptions()->GetDirectCursorColor() ) );
4547 if( text::HoriOrientation::RIGHT != eOrient && text::HoriOrientation::CENTER != eOrient )
4548 eOrient = text::HoriOrientation::LEFT;
4549 m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(eOrient) );
4550 bDelShadCursor = false;
4554 break;
4555 case MOUSE_LEFT + KEY_MOD2:
4556 if( rSh.IsBlockMode() && !rMEvt.IsSynthetic() )
4558 rSh.Drag( &aDocPt, false );
4559 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPt, false));
4560 EnterArea();
4562 break;
4565 if( bDelShadCursor && m_pShadCursor )
4567 m_pShadCursor.reset();
4569 m_bWasShdwCursor = false;
4573 * Button Up
4575 void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
4577 if (comphelper::LibreOfficeKit::isActive())
4579 if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
4581 pWindow->MouseButtonUp(rMEvt);
4582 return;
4586 bool bCallBase = true;
4588 bool bCallShadowCursor = m_bWasShdwCursor;
4589 m_bWasShdwCursor = false;
4590 if( m_pShadCursor )
4592 m_pShadCursor.reset();
4595 m_xRowColumnSelectionStart.reset();
4597 SdrHdlKind eOldSdrMoveHdl = g_eSdrMoveHdl;
4598 g_eSdrMoveHdl = SdrHdlKind::User; // for MoveEvents - reset again
4600 // preventively reset
4601 m_rView.SetTabColFromDoc( false );
4602 m_rView.SetNumRuleNodeFromDoc(nullptr);
4604 SwWrtShell &rSh = m_rView.GetWrtShell();
4605 CurrShell aCurr( &rSh );
4606 SdrView *pSdrView = rSh.GetDrawView();
4607 if ( pSdrView )
4609 // tdf34555: ortho was always reset before being used in EndSdrDrag
4610 // Now, it is reset only if not in Crop mode.
4611 if (pSdrView->GetDragMode() != SdrDragMode::Crop && !rMEvt.IsShift())
4612 pSdrView->SetOrtho(false);
4614 if ( pSdrView->MouseButtonUp( rMEvt,GetOutDev() ) )
4616 rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
4617 return; // SdrView's event evaluated
4620 // only process MouseButtonUp when the Down went to that windows as well.
4621 if ( !m_bMBPressed )
4623 // Undo for the watering can is already in CommandHdl
4624 // that's the way it should be!
4626 return;
4629 Point aDocPt( PixelToLogic( rMEvt.GetPosPixel() ) );
4631 if ( g_bDDTimerStarted )
4633 StopDDTimer( &rSh, aDocPt );
4634 m_bMBPressed = false;
4635 if ( rSh.IsSelFrameMode() )
4637 rSh.EndDrag( &aDocPt, false );
4638 g_bFrameDrag = false;
4640 g_bNoInterrupt = false;
4641 const Point aDocPos( PixelToLogic( rMEvt.GetPosPixel() ) );
4642 if ((PixelToLogic(m_aStartPos).Y() == (aDocPos.Y())) && (PixelToLogic(m_aStartPos).X() == (aDocPos.X())))//To make sure it was not moved
4644 SdrPageView* pPV = nullptr;
4645 SdrObject* pObj = pSdrView ? pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
4646 if (pObj)
4648 SwFrameFormat* pFormat = GetUserCall(pObj)->GetFormat();
4649 SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT);
4650 if (!pShapeFormat)
4652 pSdrView->UnmarkAllObj();
4653 pSdrView->MarkObj(pObj,pPV);
4655 else
4657 // If the fly frame is a textbox of a shape, then select the shape instead.
4658 SdrObject* pShape = pShapeFormat->FindSdrObject();
4659 pSdrView->UnmarkAllObj();
4660 pSdrView->MarkObj(pShape, pPV);
4664 ReleaseMouse();
4665 return;
4668 if( m_pAnchorMarker )
4670 if(m_pAnchorMarker->GetHdl())
4672 // #i121463# delete selected after drag
4673 m_pAnchorMarker->GetHdl()->SetSelected(false);
4676 Point aPnt( m_pAnchorMarker->GetLastPos() );
4677 m_pAnchorMarker.reset();
4678 if( aPnt.X() || aPnt.Y() )
4679 rSh.FindAnchorPos( aPnt, true );
4681 if ( m_bInsDraw && m_rView.GetDrawFuncPtr() )
4683 if ( m_rView.GetDrawFuncPtr()->MouseButtonUp( rMEvt ) )
4685 if (m_rView.GetDrawFuncPtr()) // could have been destroyed in MouseButtonUp
4687 m_rView.GetDrawFuncPtr()->Deactivate();
4689 if (!m_rView.IsDrawMode())
4691 m_rView.SetDrawFuncPtr(nullptr);
4692 SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
4693 rBind.Invalidate( SID_ATTR_SIZE );
4694 rBind.Invalidate( SID_TABLE_CELL );
4698 if ( rSh.IsObjSelected() )
4700 rSh.EnterSelFrameMode();
4701 if (!m_rView.GetDrawFuncPtr())
4702 StdDrawMode( SdrObjKind::NONE, true );
4704 else if ( rSh.IsFrameSelected() )
4706 rSh.EnterSelFrameMode();
4707 StopInsFrame();
4709 else
4711 const Point aDocPos( PixelToLogic( m_aStartPos ) );
4712 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4713 rSh.Edit();
4716 m_rView.AttrChangedNotify(nullptr);
4718 else if (rMEvt.GetButtons() == MOUSE_RIGHT && rSh.IsDrawCreate())
4719 m_rView.GetDrawFuncPtr()->BreakCreate(); // abort drawing
4721 g_bNoInterrupt = false;
4722 if (IsMouseCaptured())
4723 ReleaseMouse();
4724 return;
4726 bool bPopMode = false;
4727 switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
4729 case MOUSE_LEFT:
4730 if ( m_bInsDraw && rSh.IsDrawCreate() )
4732 if ( m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->MouseButtonUp(rMEvt) )
4734 m_rView.GetDrawFuncPtr()->Deactivate();
4735 m_rView.AttrChangedNotify(nullptr);
4736 if ( rSh.IsObjSelected() )
4737 rSh.EnterSelFrameMode();
4738 if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
4739 StopInsFrame();
4741 bCallBase = false;
4742 break;
4744 [[fallthrough]];
4745 case MOUSE_LEFT + KEY_MOD1:
4746 case MOUSE_LEFT + KEY_MOD2:
4747 case MOUSE_LEFT + KEY_SHIFT + KEY_MOD1:
4748 if ( g_bFrameDrag && rSh.IsSelFrameMode() )
4750 if ( rMEvt.IsMod1() ) // copy and don't move.
4752 // abort drag, use internal Copy instead
4753 tools::Rectangle aRect;
4754 rSh.GetDrawView()->TakeActionRect( aRect );
4755 if (!aRect.IsEmpty())
4757 rSh.BreakDrag();
4758 Point aEndPt, aSttPt;
4759 if ( rSh.GetSelFrameType() & FrameTypeFlags::FLY_ATCNT )
4761 aEndPt = aRect.TopLeft();
4762 aSttPt = rSh.GetDrawView()->GetAllMarkedRect().TopLeft();
4764 else
4766 aEndPt = aRect.Center();
4767 aSttPt = rSh.GetDrawView()->GetAllMarkedRect().Center();
4769 if ( aSttPt != aEndPt )
4771 rSh.StartUndo( SwUndoId::UI_DRAG_AND_COPY );
4772 rSh.Copy(rSh, aSttPt, aEndPt);
4773 rSh.EndUndo( SwUndoId::UI_DRAG_AND_COPY );
4776 else {
4777 rSh.EndDrag( &aDocPt, false );
4780 else
4783 const SwFrameFormat *const pFlyFormat(rSh.GetFlyFrameFormat());
4784 const SvxMacro* pMacro = nullptr;
4786 SvMacroItemId nEvent = SdrHdlKind::Move == eOldSdrMoveHdl
4787 ? SvMacroItemId::SwFrmMove
4788 : SvMacroItemId::SwFrmResize;
4790 if (nullptr != pFlyFormat)
4791 pMacro = pFlyFormat->GetMacro().GetMacroTable().Get(nEvent);
4792 if (nullptr != pMacro)
4794 const Point aSttPt( PixelToLogic( m_aStartPos ) );
4795 m_aRszMvHdlPt = aDocPt;
4796 sal_uInt32 nPos = 0;
4797 SbxArrayRef xArgs = new SbxArray;
4798 SbxVariableRef xVar = new SbxVariable;
4799 xVar->PutString( pFlyFormat->GetName() );
4800 xArgs->Put(xVar.get(), ++nPos);
4802 if( SvMacroItemId::SwFrmResize == nEvent )
4804 xVar = new SbxVariable;
4805 xVar->PutUShort( static_cast< sal_uInt16 >(eOldSdrMoveHdl) );
4806 xArgs->Put(xVar.get(), ++nPos);
4809 xVar = new SbxVariable;
4810 xVar->PutLong( aDocPt.X() - aSttPt.X() );
4811 xArgs->Put(xVar.get(), ++nPos);
4812 xVar = new SbxVariable;
4813 xVar->PutLong( aDocPt.Y() - aSttPt.Y() );
4814 xArgs->Put(xVar.get(), ++nPos);
4816 xVar = new SbxVariable;
4817 xVar->PutUShort( 1 );
4818 xArgs->Put(xVar.get(), ++nPos);
4820 ReleaseMouse();
4822 rSh.ExecMacro( *pMacro, nullptr, xArgs.get() );
4824 CaptureMouse();
4827 if (pFlyFormat)
4829 // See if the fly frame's anchor is in a content control. If so,
4830 // interact with it.
4831 const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
4832 SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
4833 if (pAnchorNode)
4835 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
4836 if (pTextNode)
4838 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
4839 rFormatAnchor.GetAnchorContentOffset(), RES_TXTATR_CONTENTCONTROL,
4840 ::sw::GetTextAttrMode::Parent);
4841 if (pAttr)
4843 SwTextContentControl* pTextContentControl
4844 = static_txtattr_cast<SwTextContentControl*>(pAttr);
4845 const SwFormatContentControl& rFormatContentControl
4846 = pTextContentControl->GetContentControl();
4847 rSh.GotoContentControl(rFormatContentControl);
4853 rSh.EndDrag( &aDocPt, false );
4855 g_bFrameDrag = false;
4856 bCallBase = false;
4857 break;
4859 bPopMode = true;
4860 [[fallthrough]];
4861 case MOUSE_LEFT + KEY_SHIFT:
4862 if (rSh.IsSelFrameMode())
4865 rSh.EndDrag( &aDocPt, false );
4866 g_bFrameDrag = false;
4867 bCallBase = false;
4868 break;
4871 if( g_bHoldSelection )
4873 // the EndDrag should be called in any case
4874 g_bHoldSelection = false;
4875 rSh.EndDrag( &aDocPt, false );
4877 else
4879 SwContentAtPos aFieldAtPos ( IsAttrAtPos::Field );
4880 if ( !rSh.IsInSelect() && rSh.TestCurrPam( aDocPt ) &&
4881 !rSh.GetContentAtPos( aDocPt, aFieldAtPos ) )
4883 const bool bTmpNoInterrupt = g_bNoInterrupt;
4884 g_bNoInterrupt = false;
4885 { // create only temporary move context because otherwise
4886 // the query to the content form doesn't work!!!
4887 SwMvContext aMvContext( &rSh );
4888 const Point aDocPos( PixelToLogic( m_aStartPos ) );
4889 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4891 g_bNoInterrupt = bTmpNoInterrupt;
4894 else
4896 bool bInSel = rSh.IsInSelect();
4897 rSh.EndDrag( &aDocPt, false );
4899 // Internetfield? --> call link (load doc!!)
4900 if( !bInSel )
4902 LoadUrlFlags nFilter = LoadUrlFlags::NONE;
4903 if( KEY_MOD1 == rMEvt.GetModifier() )
4904 nFilter |= LoadUrlFlags::NewView;
4906 bool bExecHyperlinks = m_rView.GetDocShell()->IsReadOnly();
4907 if ( !bExecHyperlinks )
4909 const bool bSecureOption = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
4910 if ( ( bSecureOption && rMEvt.GetModifier() == KEY_MOD1 ) ||
4911 ( !bSecureOption && rMEvt.GetModifier() != KEY_MOD1 ) )
4912 bExecHyperlinks = true;
4915 const bool bExecSmarttags = rMEvt.GetModifier() == KEY_MOD1;
4917 if(m_pApplyTempl)
4918 bExecHyperlinks = false;
4920 SwContentAtPos aContentAtPos( IsAttrAtPos::Field |
4921 IsAttrAtPos::InetAttr |
4922 IsAttrAtPos::SmartTag | IsAttrAtPos::FormControl |
4923 IsAttrAtPos::ContentControl);
4925 if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
4927 // Do it again if we're not on a field/hyperlink to update the cursor accordingly
4928 if ( IsAttrAtPos::Field != aContentAtPos.eContentAtPos
4929 && IsAttrAtPos::InetAttr != aContentAtPos.eContentAtPos )
4930 rSh.GetContentAtPos( aDocPt, aContentAtPos, true );
4932 bool bViewLocked = rSh.IsViewLocked();
4933 if( !bViewLocked && !rSh.IsReadOnlyAvailable() &&
4934 aContentAtPos.IsInProtectSect() )
4935 rSh.LockView( true );
4937 ReleaseMouse();
4939 if( IsAttrAtPos::Field == aContentAtPos.eContentAtPos )
4941 bool bAddMode(false);
4942 // AdditionalMode if applicable
4943 if (KEY_MOD1 == rMEvt.GetModifier()
4944 && !rSh.IsAddMode())
4946 bAddMode = true;
4947 rSh.EnterAddMode();
4949 if ( aContentAtPos.pFndTextAttr != nullptr
4950 && aContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD )
4952 if (!rSh.IsInSelect())
4954 // create only temporary move context because otherwise
4955 // the query to the content form doesn't work!!!
4956 SwMvContext aMvContext( &rSh );
4957 const Point aDocPos( PixelToLogic( m_aStartPos ) );
4958 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
4960 else
4962 g_bValidCursorPos = true;
4965 else
4967 rSh.ClickToField(*aContentAtPos.aFnd.pField, bExecHyperlinks);
4968 // a bit of a mystery what this is good for?
4969 // in this case we assume it's valid since we
4970 // just selected a field
4971 g_bValidCursorPos = true;
4973 if (bAddMode)
4975 rSh.LeaveAddMode();
4978 else if (aContentAtPos.eContentAtPos == IsAttrAtPos::ContentControl)
4980 auto pTextContentControl
4981 = static_txtattr_cast<const SwTextContentControl*>(
4982 aContentAtPos.pFndTextAttr);
4983 const SwFormatContentControl& rFormatContentControl
4984 = pTextContentControl->GetContentControl();
4985 rSh.GotoContentControl(rFormatContentControl);
4987 else if ( IsAttrAtPos::SmartTag == aContentAtPos.eContentAtPos )
4989 // execute smarttag menu
4990 if ( bExecSmarttags && SwSmartTagMgr::Get().IsSmartTagsEnabled() )
4991 m_rView.ExecSmartTagPopup( aDocPt );
4993 else if ( IsAttrAtPos::FormControl == aContentAtPos.eContentAtPos )
4995 OSL_ENSURE( aContentAtPos.aFnd.pFieldmark != nullptr, "where is my field ptr???");
4996 if ( aContentAtPos.aFnd.pFieldmark != nullptr)
4998 IFieldmark *fieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
4999 if ( fieldBM->GetFieldname( ) == ODF_FORMCHECKBOX )
5001 ICheckboxFieldmark& rCheckboxFm = dynamic_cast<ICheckboxFieldmark&>(*fieldBM);
5002 rCheckboxFm.SetChecked(!rCheckboxFm.IsChecked());
5003 rCheckboxFm.Invalidate();
5004 rSh.InvalidateWindows( SwRect(m_rView.GetVisArea()) );
5008 else if ( IsAttrAtPos::InetAttr == aContentAtPos.eContentAtPos )
5010 if (comphelper::LibreOfficeKit::isActive())
5012 OUString val((*static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr)).GetValue());
5013 if (val.startsWith("#"))
5014 bExecHyperlinks = true;
5016 if ( bExecHyperlinks && aContentAtPos.aFnd.pAttr )
5017 rSh.ClickToINetAttr( *static_cast<const SwFormatINetFormat*>(aContentAtPos.aFnd.pAttr), nFilter );
5020 rSh.LockView( bViewLocked );
5021 bCallShadowCursor = false;
5023 else
5025 aContentAtPos = SwContentAtPos( IsAttrAtPos::Ftn );
5026 if( !rSh.GetContentAtPos( aDocPt, aContentAtPos, true ) && bExecHyperlinks )
5028 SdrViewEvent aVEvt;
5030 if (pSdrView)
5031 pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
5033 if (pSdrView && aVEvt.meEvent == SdrEventKind::ExecuteUrl)
5035 // hit URL field
5036 const SvxURLField *pField = aVEvt.mpURLField;
5037 if (pField)
5039 const OUString& sURL(pField->GetURL());
5040 const OUString& sTarget(pField->GetTargetFrame());
5041 ::LoadURL(rSh, sURL, nFilter, sTarget);
5043 bCallShadowCursor = false;
5045 else
5047 // hit graphic
5048 ReleaseMouse();
5049 if( rSh.ClickToINetGrf( aDocPt, nFilter ))
5050 bCallShadowCursor = false;
5055 if( bCallShadowCursor &&
5056 rSh.GetViewOptions()->IsShadowCursor() &&
5057 MOUSE_LEFT == (rMEvt.GetModifier() + rMEvt.GetButtons()) &&
5058 !rSh.HasSelection() &&
5059 !GetOutDev()->GetConnectMetaFile() &&
5060 rSh.VisArea().Contains( aDocPt ))
5062 SwUndoId nLastUndoId(SwUndoId::EMPTY);
5063 if (rSh.GetLastUndoInfo(nullptr, & nLastUndoId))
5065 if (SwUndoId::INS_FROM_SHADOWCRSR == nLastUndoId)
5067 rSh.Undo();
5070 SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
5071 rSh.SetShadowCursorPos( aDocPt, eMode );
5075 bCallBase = false;
5079 // reset pushed mode in Down again if applicable
5080 if ( bPopMode && g_bModePushed )
5082 rSh.PopMode();
5083 g_bModePushed = false;
5084 bCallBase = false;
5086 break;
5088 default:
5089 ReleaseMouse();
5090 return;
5093 if( m_pApplyTempl )
5095 SelectionType eSelection = rSh.GetSelectionType();
5096 SwFormatClipboard* pFormatClipboard = m_pApplyTempl->m_pFormatClipboard;
5097 if( pFormatClipboard )//apply format paintbrush
5099 //get some parameters
5100 SwWrtShell& rWrtShell = m_rView.GetWrtShell();
5101 SfxStyleSheetBasePool* pPool=nullptr;
5102 bool bNoCharacterFormats = false;
5103 bool bNoParagraphFormats = true;
5105 SwDocShell* pDocSh = m_rView.GetDocShell();
5106 if(pDocSh)
5107 pPool = pDocSh->GetStyleSheetPool();
5108 if( (rMEvt.GetModifier()&KEY_MOD1) && (rMEvt.GetModifier()&KEY_SHIFT) )
5110 bNoCharacterFormats = true;
5111 bNoParagraphFormats = false;
5113 else if( rMEvt.GetModifier() & KEY_MOD1 )
5114 bNoParagraphFormats = false;
5116 //execute paste
5117 pFormatClipboard->Paste( rWrtShell, pPool, bNoCharacterFormats, bNoParagraphFormats );
5119 //if the clipboard is empty after paste remove the ApplyTemplate
5120 if(!pFormatClipboard->HasContent())
5121 SetApplyTemplate(SwApplyTemplate());
5123 //tdf#38101 remove temporary highlighting
5124 m_pUserMarker.reset();
5126 else if( m_pApplyTempl->nColor )
5128 sal_uInt16 nId = 0;
5129 switch( m_pApplyTempl->nColor )
5131 case SID_ATTR_CHAR_COLOR_EXT:
5132 nId = RES_CHRATR_COLOR;
5133 break;
5134 case SID_ATTR_CHAR_BACK_COLOR:
5135 case SID_ATTR_CHAR_COLOR_BACKGROUND:
5136 nId = RES_CHRATR_BACKGROUND;
5137 break;
5139 if( nId && (SelectionType::Text|SelectionType::Table) & eSelection)
5141 if( rSh.IsSelection() && !rSh.HasReadonlySel() )
5143 m_pApplyTempl->nUndo =
5144 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5145 if (nId == RES_CHRATR_BACKGROUND)
5146 ApplyCharBackground(m_aWaterCanTextBackColor, model::ComplexColor(), rSh);
5147 else
5148 rSh.SetAttrItem( SvxColorItem( m_aWaterCanTextColor, nId ) );
5149 rSh.UnSetVisibleCursor();
5150 rSh.EnterStdMode();
5151 rSh.SetVisibleCursor(aDocPt);
5152 bCallBase = false;
5153 m_aTemplateTimer.Stop();
5155 else if(rMEvt.GetClicks() == 1)
5157 // no selection -> so turn off watering can
5158 m_aTemplateTimer.Start();
5162 else
5164 OUString aStyleName;
5165 switch ( m_pApplyTempl->eType )
5167 case SfxStyleFamily::Para:
5168 if( (( SelectionType::Text | SelectionType::Table )
5169 & eSelection ) && !rSh.HasReadonlySel() )
5171 rSh.SetTextFormatColl( m_pApplyTempl->aColl.pTextColl );
5172 m_pApplyTempl->nUndo =
5173 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5174 bCallBase = false;
5175 if ( m_pApplyTempl->aColl.pTextColl )
5176 aStyleName = m_pApplyTempl->aColl.pTextColl->GetName();
5178 break;
5179 case SfxStyleFamily::Char:
5180 if( (( SelectionType::Text | SelectionType::Table )
5181 & eSelection ) && !rSh.HasReadonlySel() )
5183 rSh.SetAttrItem( SwFormatCharFormat(m_pApplyTempl->aColl.pCharFormat) );
5184 rSh.UnSetVisibleCursor();
5185 rSh.EnterStdMode();
5186 rSh.SetVisibleCursor(aDocPt);
5187 m_pApplyTempl->nUndo =
5188 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5189 bCallBase = false;
5190 if ( m_pApplyTempl->aColl.pCharFormat )
5191 aStyleName = m_pApplyTempl->aColl.pCharFormat->GetName();
5193 break;
5194 case SfxStyleFamily::Frame :
5196 const SwFrameFormat* pFormat = rSh.GetFormatFromObj( aDocPt );
5197 if(dynamic_cast<const SwFlyFrameFormat*>( pFormat) )
5199 rSh.SetFrameFormat( m_pApplyTempl->aColl.pFrameFormat, false, &aDocPt );
5200 m_pApplyTempl->nUndo =
5201 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5202 bCallBase = false;
5203 if( m_pApplyTempl->aColl.pFrameFormat )
5204 aStyleName = m_pApplyTempl->aColl.pFrameFormat->GetName();
5206 break;
5208 case SfxStyleFamily::Page:
5209 // no Undo with page templates
5210 rSh.ChgCurPageDesc( *m_pApplyTempl->aColl.pPageDesc );
5211 if ( m_pApplyTempl->aColl.pPageDesc )
5212 aStyleName = m_pApplyTempl->aColl.pPageDesc->GetName();
5213 m_pApplyTempl->nUndo =
5214 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5215 bCallBase = false;
5216 break;
5217 case SfxStyleFamily::Pseudo:
5218 if( !rSh.HasReadonlySel() )
5220 rSh.SetCurNumRule( *m_pApplyTempl->aColl.pNumRule,
5221 false,
5222 m_pApplyTempl->aColl.pNumRule->GetDefaultListId() );
5223 bCallBase = false;
5224 m_pApplyTempl->nUndo =
5225 std::min(m_pApplyTempl->nUndo, rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount());
5226 if( m_pApplyTempl->aColl.pNumRule )
5227 aStyleName = m_pApplyTempl->aColl.pNumRule->GetName();
5229 break;
5230 default: break;
5233 uno::Reference< frame::XDispatchRecorder > xRecorder =
5234 m_rView.GetViewFrame().GetBindings().GetRecorder();
5235 if ( !aStyleName.isEmpty() && xRecorder.is() )
5237 SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
5238 if ( pSfxShell )
5240 SfxRequest aReq(m_rView.GetViewFrame(), SID_STYLE_APPLY);
5241 aReq.AppendItem( SfxStringItem( SID_STYLE_APPLY, aStyleName ) );
5242 aReq.AppendItem( SfxUInt16Item( SID_STYLE_FAMILY, static_cast<sal_uInt16>(m_pApplyTempl->eType) ) );
5243 aReq.Done();
5249 ReleaseMouse();
5250 // Only processed MouseEvents arrive here; only at these this mode can
5251 // be reset.
5252 m_bMBPressed = false;
5254 // Make this call just to be sure. Selecting has finished surely by now.
5255 // Otherwise the timeout's timer could give problems.
5256 EnterArea();
5257 g_bNoInterrupt = false;
5259 if (bCallBase)
5260 Window::MouseButtonUp(rMEvt);
5262 if (!(pSdrView && rMEvt.GetClicks() == 1 && comphelper::LibreOfficeKit::isActive()))
5263 return;
5265 // When tiled rendering, single click on a shape text starts editing already.
5266 SdrViewEvent aViewEvent;
5267 SdrHitKind eHit = pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aViewEvent);
5268 const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
5269 if (eHit == SdrHitKind::TextEditObj && rMarkList.GetMarkCount() == 1)
5271 if (SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj())
5273 EnterDrawTextMode(pObj->GetLogicRect().Center());
5274 if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
5275 pSwDrawTextShell->Init();
5281 * Apply template
5283 void SwEditWin::SetApplyTemplate(const SwApplyTemplate &rTempl)
5285 static bool bIdle = false;
5286 m_pApplyTempl.reset();
5287 SwWrtShell &rSh = m_rView.GetWrtShell();
5289 if(rTempl.m_pFormatClipboard)
5291 m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5292 m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5293 SetPointer( PointerStyle::Fill );//@todo #i20119# maybe better a new brush pointer here in future
5294 rSh.NoEdit( false );
5295 bIdle = rSh.GetViewOptions()->IsIdle();
5296 rSh.GetViewOptions()->SetIdle( false );
5298 else if(rTempl.nColor)
5300 m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5301 m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5302 SetPointer( PointerStyle::Fill );
5303 rSh.NoEdit( false );
5304 bIdle = rSh.GetViewOptions()->IsIdle();
5305 rSh.GetViewOptions()->SetIdle( false );
5307 else if( rTempl.eType != SfxStyleFamily::None )
5309 m_pApplyTempl.reset(new SwApplyTemplate( rTempl ));
5310 m_pApplyTempl->nUndo = rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount();
5311 SetPointer( PointerStyle::Fill );
5312 rSh.NoEdit( false );
5313 bIdle = rSh.GetViewOptions()->IsIdle();
5314 rSh.GetViewOptions()->SetIdle( false );
5316 else
5318 SetPointer( PointerStyle::Text );
5319 rSh.UnSetVisibleCursor();
5321 rSh.GetViewOptions()->SetIdle( bIdle );
5322 if ( !rSh.IsSelFrameMode() )
5323 rSh.Edit();
5326 static sal_uInt16 aInva[] =
5328 SID_STYLE_WATERCAN,
5329 SID_ATTR_CHAR_COLOR_EXT,
5330 SID_ATTR_CHAR_COLOR_BACKGROUND_EXT,
5333 m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
5337 * Ctor
5339 SwEditWin::SwEditWin(vcl::Window *pParent, SwView &rMyView):
5340 DocWindow(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
5341 DropTargetHelper( this ),
5342 DragSourceHelper( this ),
5344 m_aTimer("SwEditWin"),
5345 m_aKeyInputFlushTimer("SwEditWin m_aKeyInputFlushTimer"),
5346 m_eBufferLanguage(LANGUAGE_DONTKNOW),
5347 m_aTemplateTimer("SwEditWin m_aTemplateTimer"),
5348 m_pUserMarkerObj( nullptr ),
5350 m_rView( rMyView ),
5352 m_aActHitType(SdrHitKind::NONE),
5353 m_nDropFormat( SotClipboardFormatId::NONE ),
5354 m_nDropAction( 0 ),
5355 m_nDropDestination( SotExchangeDest::NONE ),
5357 m_eBezierMode(SID_BEZIER_INSERT),
5358 m_nInsFrameColCount( 1 ),
5359 m_eDrawMode(SdrObjKind::NONE),
5361 m_bMBPressed(false),
5362 m_bInsDraw(false),
5363 m_bInsFrame(false),
5364 m_bIsInMove(false),
5365 m_bIsInDrag(false),
5366 m_bOldIdle(false),
5367 m_bOldIdleSet(false),
5368 m_bChainMode(false),
5369 m_bWasShdwCursor(false),
5370 m_bLockInput(false),
5371 m_bIsRowDrag(false),
5372 m_bUseInputLanguage(false),
5373 m_bObjectSelect(false),
5374 m_nKS_NUMDOWN_Count(0),
5375 m_nKS_NUMINDENTINC_Count(0),
5376 m_pFrameControlsManager(new SwFrameControlsManager(this))
5378 set_id("writer_edit");
5379 SetHelpId(HID_EDIT_WIN);
5380 EnableChildTransparentMode();
5381 SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
5383 m_bMBPressed = m_bInsDraw = m_bInsFrame =
5384 m_bIsInDrag = m_bOldIdle = m_bOldIdleSet = m_bChainMode = m_bWasShdwCursor = false;
5385 // initially use the input language
5386 m_bUseInputLanguage = true;
5388 SetMapMode(MapMode(MapUnit::MapTwip));
5390 SetPointer( PointerStyle::Text );
5391 m_aTimer.SetInvokeHandler(LINK(this, SwEditWin, TimerHandler));
5393 m_aKeyInputFlushTimer.SetTimeout( 20 );
5394 m_aKeyInputFlushTimer.SetInvokeHandler(LINK(this, SwEditWin, KeyInputFlushHandler));
5396 // TemplatePointer for colors should be reset without
5397 // selection after single click, but not after double-click (tdf#122442)
5398 m_aTemplateTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
5399 m_aTemplateTimer.SetInvokeHandler(LINK(this, SwEditWin, TemplateTimerHdl));
5401 // temporary solution!!! Should set the font of the current
5402 // insert position at every cursor movement!
5403 if( !rMyView.GetDocShell()->IsReadOnly() )
5405 vcl::Font aFont;
5406 SetInputContext( InputContext( aFont, InputContextFlags::Text |
5407 InputContextFlags::ExtText ) );
5411 SwEditWin::~SwEditWin()
5413 disposeOnce();
5416 void SwEditWin::dispose()
5418 m_pShadCursor.reset();
5420 if( s_pQuickHlpData->m_bIsDisplayed && m_rView.GetWrtShellPtr() )
5421 s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
5422 g_bExecuteDrag = false;
5423 m_pApplyTempl.reset();
5425 m_rView.SetDrawFuncPtr(nullptr);
5427 m_pUserMarker.reset();
5429 m_pAnchorMarker.reset();
5431 m_pFrameControlsManager->dispose();
5432 m_pFrameControlsManager.reset();
5434 DragSourceHelper::dispose();
5435 DropTargetHelper::dispose();
5436 vcl::Window::dispose();
5440 * Turn on DrawTextEditMode
5442 void SwEditWin::EnterDrawTextMode( const Point& aDocPos )
5444 if ( m_rView.EnterDrawTextMode(aDocPos) )
5446 if (m_rView.GetDrawFuncPtr())
5448 m_rView.GetDrawFuncPtr()->Deactivate();
5449 m_rView.SetDrawFuncPtr(nullptr);
5450 m_rView.LeaveDrawCreate();
5452 m_rView.NoRotate();
5453 m_rView.AttrChangedNotify(nullptr);
5458 * Turn on DrawMode
5460 bool SwEditWin::EnterDrawMode(const MouseEvent& rMEvt, const Point& aDocPos)
5462 SwWrtShell &rSh = m_rView.GetWrtShell();
5463 SdrView *pSdrView = rSh.GetDrawView();
5465 if ( m_rView.GetDrawFuncPtr() )
5467 if (rSh.IsDrawCreate())
5468 return true;
5470 bool bRet = m_rView.GetDrawFuncPtr()->MouseButtonDown( rMEvt );
5471 m_rView.AttrChangedNotify(nullptr);
5472 return bRet;
5475 if ( pSdrView && pSdrView->IsTextEdit() )
5477 bool bUnLockView = !rSh.IsViewLocked();
5478 rSh.LockView( true );
5480 rSh.EndTextEdit(); // clicked aside, end Edit
5481 rSh.SelectObj( aDocPos );
5482 if ( !rSh.IsObjSelected() && !rSh.IsFrameSelected() )
5483 rSh.LeaveSelFrameMode();
5484 else
5486 SwEditWin::s_nDDStartPosY = aDocPos.Y();
5487 SwEditWin::s_nDDStartPosX = aDocPos.X();
5488 g_bFrameDrag = true;
5490 if( bUnLockView )
5491 rSh.LockView( false );
5492 m_rView.AttrChangedNotify(nullptr);
5493 return true;
5495 return false;
5498 bool SwEditWin::IsDrawSelMode() const
5500 return IsObjectSelect();
5503 void SwEditWin::GetFocus()
5505 if ( m_rView.GetPostItMgr()->HasActiveSidebarWin() )
5507 m_rView.GetPostItMgr()->GrabFocusOnActiveSidebarWin();
5509 else
5511 m_rView.GotFocus();
5512 Window::GetFocus();
5513 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5514 m_rView.GetWrtShell().InvalidateAccessibleFocus();
5515 #endif
5519 void SwEditWin::LoseFocus()
5521 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
5522 if (m_rView.GetWrtShellPtr())
5523 m_rView.GetWrtShell().InvalidateAccessibleFocus();
5524 #endif
5525 Window::LoseFocus();
5526 if( s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed )
5527 s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
5530 void SwEditWin::Command( const CommandEvent& rCEvt )
5532 if (isDisposed())
5534 // If ViewFrame dies shortly, no popup anymore!
5535 Window::Command(rCEvt);
5536 return;
5539 SwWrtShell &rSh = m_rView.GetWrtShell();
5541 // The command event is send to the window after a possible context
5542 // menu from an inplace client has been closed. Now we have the chance
5543 // to deactivate the inplace client without any problem regarding parent
5544 // windows and code on the stack.
5545 SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient();
5546 bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
5547 if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu ))
5549 rSh.FinishOLEObj();
5550 return;
5553 bool bCallBase = true;
5555 switch ( rCEvt.GetCommand() )
5557 case CommandEventId::ContextMenu:
5559 const sal_uInt16 nId = SwInputChild::GetChildWindowId();
5560 SwInputChild* pChildWin = static_cast<SwInputChild*>(GetView().GetViewFrame().
5561 GetChildWindow( nId ));
5563 if (m_rView.GetPostItMgr()->IsHit(rCEvt.GetMousePosPixel()))
5564 return;
5566 Point aDocPos( PixelToLogic( rCEvt.GetMousePosPixel() ) );
5567 if ( !rCEvt.IsMouseEvent() )
5568 aDocPos = rSh.GetCharRect().Center();
5570 // Don't trigger the command on a frame anchored to header/footer is not editing it
5571 FrameControlType eControl;
5572 bool bOverFly = false;
5573 bool bPageAnchored = false;
5574 bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored );
5575 // !bOverHeaderFooterFly doesn't mean we have a frame to select
5576 if ( !bPageAnchored && rCEvt.IsMouseEvent( ) &&
5577 ( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
5578 ( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
5580 return;
5583 if((!pChildWin || pChildWin->GetView() != &m_rView) &&
5584 !rSh.IsDrawCreate() && !IsDrawAction())
5586 CurrShell aCurr( &rSh );
5587 if (!m_pApplyTempl)
5589 if (g_bNoInterrupt)
5591 ReleaseMouse();
5592 g_bNoInterrupt = false;
5593 m_bMBPressed = false;
5595 if ( rCEvt.IsMouseEvent() )
5597 SelectMenuPosition(rSh, rCEvt.GetMousePosPixel());
5598 m_rView.StopShellTimer();
5600 const Point aPixPos = LogicToPixel( aDocPos );
5602 if ( m_rView.GetDocShell()->IsReadOnly() )
5604 SwReadOnlyPopup aROPopup(aDocPos, m_rView);
5606 ui::ContextMenuExecuteEvent aEvent;
5607 aEvent.SourceWindow = VCLUnoHelper::GetInterface( this );
5608 aEvent.ExecutePosition.X = aPixPos.X();
5609 aEvent.ExecutePosition.Y = aPixPos.Y();
5610 rtl::Reference<VCLXPopupMenu> xMenu;
5611 rtl::Reference<VCLXPopupMenu> xMenuInterface = aROPopup.CreateMenuInterface();
5612 if (GetView().TryContextMenuInterception(xMenuInterface, "private:resource/ReadonlyContextMenu", xMenu, aEvent))
5614 if (xMenu.is())
5616 css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
5617 sal_uInt16 nExecId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1),
5618 css::awt::PopupMenuDirection::EXECUTE_DOWN);
5619 if (!::ExecuteMenuCommand(xMenu, m_rView.GetViewFrame(), nExecId))
5620 aROPopup.Execute(this, nExecId);
5622 else
5623 aROPopup.Execute(this, aPixPos);
5626 else if ( !m_rView.ExecSpellPopup( aDocPos ) )
5627 SfxDispatcher::ExecutePopup(this, &aPixPos);
5629 else if (m_pApplyTempl->nUndo < rSh.GetDoc()->GetIDocumentUndoRedo().GetUndoActionCount())
5631 // Undo until we reach the point when we entered this context.
5632 rSh.Do(SwWrtShell::UNDO);
5634 bCallBase = false;
5637 break;
5639 case CommandEventId::Wheel:
5640 case CommandEventId::StartAutoScroll:
5641 case CommandEventId::AutoScroll:
5642 if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
5644 GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
5645 m_pSavedOutlineFrame = nullptr;
5647 m_pShadCursor.reset();
5648 bCallBase = !m_rView.HandleWheelCommands( rCEvt );
5649 break;
5651 case CommandEventId::GestureZoom:
5653 if (m_pSavedOutlineFrame && rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
5655 GetFrameControlsManager().RemoveControlsByType(FrameControlType::Outline, m_pSavedOutlineFrame);
5656 m_pSavedOutlineFrame = nullptr;
5658 m_pShadCursor.reset();
5659 bCallBase = !m_rView.HandleGestureZoomCommand(rCEvt);
5660 break;
5663 case CommandEventId::GestureLongPress:
5664 case CommandEventId::GestureSwipe: //nothing yet
5665 break;
5667 case CommandEventId::StartExtTextInput:
5669 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
5670 rSh.IsCursorReadonly();
5671 if(!bIsDocReadOnly)
5673 if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5675 bCallBase = false;
5676 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5678 else
5680 if( rSh.HasSelection() )
5681 rSh.DelRight();
5683 bCallBase = false;
5684 LanguageType eInputLanguage = GetInputLanguage();
5685 rSh.CreateExtTextInput(eInputLanguage);
5688 break;
5690 case CommandEventId::EndExtTextInput:
5692 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
5693 rSh.IsCursorReadonly();
5694 if(!bIsDocReadOnly)
5696 if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5698 bCallBase = false;
5699 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5701 else
5703 bCallBase = false;
5704 OUString sRecord = rSh.DeleteExtTextInput();
5705 uno::Reference< frame::XDispatchRecorder > xRecorder =
5706 m_rView.GetViewFrame().GetBindings().GetRecorder();
5708 if ( !sRecord.isEmpty() )
5710 // convert quotes in IME text
5711 // works on the last input character, this is especially in Korean text often done
5712 // quotes that are inside of the string are not replaced!
5713 const sal_Unicode aCh = sRecord[sRecord.getLength() - 1];
5714 SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
5715 SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
5716 if(pACorr &&
5717 (( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
5718 ( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
5720 rSh.DelLeft();
5721 rSh.AutoCorrect( *pACorr, aCh );
5724 if ( xRecorder.is() )
5726 // determine Shell
5727 SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView );
5728 // generate request and record
5729 if (pSfxShell)
5731 SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
5732 aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, sRecord ) );
5733 aReq.Done();
5740 break;
5741 case CommandEventId::ExtTextInput:
5743 bool bIsDocReadOnly = m_rView.GetDocShell()->IsReadOnly() &&
5744 rSh.IsCursorReadonly();
5745 if (!bIsDocReadOnly && !rSh.HasReadonlySel())
5747 if( s_pQuickHlpData->m_bIsDisplayed )
5748 s_pQuickHlpData->Stop( rSh );
5750 if( rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit() )
5752 bCallBase = false;
5753 rSh.GetDrawView()->GetTextEditOutlinerView()->Command( rCEvt );
5755 else
5757 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
5758 if( pData )
5760 bCallBase = false;
5761 rSh.SetExtTextInputData( *pData );
5764 uno::Reference< frame::XDispatchRecorder > xRecorder =
5765 m_rView.GetViewFrame().GetBindings().GetRecorder();
5766 if(!xRecorder.is())
5768 SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
5769 if (!rACfg.IsAutoTextTip() || !ShowAutoText(rSh.GetChunkForAutoText()))
5771 SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect();
5772 if (pACorr && pACorr->GetSwFlags().bAutoCompleteWords)
5773 ShowAutoCorrectQuickHelp(rSh.GetPrevAutoCorrWord(*pACorr), *pACorr);
5778 if (rSh.HasReadonlySel())
5780 // Inform the user that the request has been ignored.
5781 rSh.InfoReadOnlyDialog(true);
5784 break;
5785 case CommandEventId::CursorPos:
5786 // will be handled by the base class
5787 break;
5789 case CommandEventId::PasteSelection:
5790 if( !m_rView.GetDocShell()->IsReadOnly() )
5792 TransferableDataHelper aDataHelper(
5793 TransferableDataHelper::CreateFromPrimarySelection());
5794 if( !aDataHelper.GetXTransferable().is() )
5795 break;
5797 SotExchangeDest nDropDestination = GetDropDestination( rCEvt.GetMousePosPixel() );
5798 if( nDropDestination == SotExchangeDest::NONE )
5799 break;
5800 SotClipboardFormatId nDropFormat;
5801 sal_uInt8 nEventAction, nDropAction;
5802 SotExchangeActionFlags nActionFlags;
5803 nDropAction = SotExchange::GetExchangeAction(
5804 aDataHelper.GetDataFlavorExVector(),
5805 nDropDestination, EXCHG_IN_ACTION_COPY,
5806 EXCHG_IN_ACTION_COPY, nDropFormat,
5807 nEventAction,
5808 SotClipboardFormatId::NONE, nullptr,
5809 &nActionFlags );
5810 if( EXCHG_INOUT_ACTION_NONE != nDropAction )
5812 const Point aDocPt( PixelToLogic( rCEvt.GetMousePosPixel() ) );
5813 SwTransferable::PasteData( aDataHelper, rSh, nDropAction, nActionFlags,
5814 nDropFormat, nDropDestination, false,
5815 false, &aDocPt, EXCHG_IN_ACTION_COPY,
5816 true );
5819 break;
5820 case CommandEventId::ModKeyChange :
5822 const CommandModKeyData* pCommandData = rCEvt.GetModKeyData();
5823 if (!pCommandData->IsDown() && pCommandData->IsMod1() && !pCommandData->IsMod2())
5825 sal_uInt16 nSlot = 0;
5826 if(pCommandData->IsLeftShift() && !pCommandData->IsRightShift())
5827 nSlot = SID_ATTR_PARA_LEFT_TO_RIGHT;
5828 else if(!pCommandData->IsLeftShift() && pCommandData->IsRightShift())
5829 nSlot = SID_ATTR_PARA_RIGHT_TO_LEFT;
5830 if(nSlot && SvtCTLOptions::IsCTLFontEnabled())
5831 GetView().GetViewFrame().GetDispatcher()->Execute(nSlot);
5834 break;
5835 case CommandEventId::InputLanguageChange :
5836 // i#42732 - update state of fontname if input language changes
5837 g_bInputLanguageSwitched = true;
5838 SetUseInputLanguage( true );
5839 break;
5840 case CommandEventId::SelectionChange:
5842 const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
5843 rSh.SttCursorMove();
5844 rSh.GoStartSentence();
5845 rSh.GetCursor()->GetPoint()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetStart()));
5846 rSh.SetMark();
5847 rSh.GetCursor()->GetMark()->AdjustContent(sal::static_int_cast<sal_uInt16, sal_uLong>(pData->GetEnd() - pData->GetStart()));
5848 rSh.EndCursorMove( true );
5850 break;
5851 case CommandEventId::PrepareReconversion:
5852 if( rSh.HasSelection() )
5854 SwPaM *pCursor = rSh.GetCursor();
5856 if( rSh.IsMultiSelection() )
5858 if (pCursor && !pCursor->HasMark() &&
5859 pCursor->GetPoint() == pCursor->GetMark())
5861 rSh.GoPrevCursor();
5862 pCursor = rSh.GetCursor();
5865 // Cancel all selections other than the last selected one.
5866 while( rSh.GetCursor()->GetNext() != rSh.GetCursor() )
5867 delete rSh.GetCursor()->GetNext();
5870 if( pCursor )
5872 SwNodeOffset nPosNodeIdx = pCursor->GetPoint()->GetNodeIndex();
5873 const sal_Int32 nPosIdx = pCursor->GetPoint()->GetContentIndex();
5874 SwNodeOffset nMarkNodeIdx = pCursor->GetMark()->GetNodeIndex();
5875 const sal_Int32 nMarkIdx = pCursor->GetMark()->GetContentIndex();
5877 if( !rSh.GetCursor()->HasMark() )
5878 rSh.GetCursor()->SetMark();
5880 rSh.SttCursorMove();
5882 if( nPosNodeIdx < nMarkNodeIdx )
5884 rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
5885 rSh.GetCursor()->GetMark()->Assign(nPosNodeIdx,
5886 rSh.GetCursor()->GetPointContentNode()->Len());
5888 else if( nPosNodeIdx == nMarkNodeIdx )
5890 rSh.GetCursor()->GetPoint()->Assign(nPosNodeIdx, nPosIdx);
5891 rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
5893 else
5895 rSh.GetCursor()->GetMark()->Assign(nMarkNodeIdx, nMarkIdx);
5896 rSh.GetCursor()->GetPoint()->Assign(nMarkNodeIdx,
5897 rSh.GetCursor()->GetMarkContentNode()->Len());
5900 rSh.EndCursorMove( true );
5903 break;
5904 case CommandEventId::QueryCharPosition:
5906 bool bVertical = rSh.IsInVerticalText();
5907 const SwPosition& rPos = *rSh.GetCursor()->GetPoint();
5908 SwDocShell* pDocSh = m_rView.GetDocShell();
5909 SwDoc *pDoc = pDocSh->GetDoc();
5910 SwExtTextInput* pInput = pDoc->GetExtTextInput( rPos.GetNode(), rPos.GetContentIndex() );
5911 if ( pInput )
5913 const SwPosition& rStart = *pInput->Start();
5914 const SwPosition& rEnd = *pInput->End();
5915 sal_Int32 nSize = rEnd.GetContentIndex() - rStart.GetContentIndex();
5916 vcl::Window& rWin = rSh.GetView().GetEditWin();
5917 if ( nSize == 0 )
5919 // When the composition does not exist, use Caret rect instead.
5920 const SwRect& aCaretRect ( rSh.GetCharRect() );
5921 tools::Rectangle aRect( aCaretRect.Left(), aCaretRect.Top(), aCaretRect.Right(), aCaretRect.Bottom() );
5922 rWin.SetCompositionCharRect( &aRect, 1, bVertical );
5924 else
5926 std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ nSize ]);
5927 int nRectIndex = 0;
5928 for ( sal_Int32 nIndex = rStart.GetContentIndex(); nIndex < rEnd.GetContentIndex(); ++nIndex )
5930 const SwPosition aPos( rStart.GetNode(), rStart.GetNode().GetContentNode(), nIndex );
5931 SwRect aRect ( rSh.GetCharRect() );
5932 rSh.GetCharRectAt( aRect, &aPos );
5933 aRects[ nRectIndex ] = tools::Rectangle( aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom() );
5934 ++nRectIndex;
5936 rWin.SetCompositionCharRect( aRects.get(), nSize, bVertical );
5939 bCallBase = false;
5941 break;
5942 default:
5943 SAL_WARN("sw.ui", "unknown command.");
5944 break;
5946 if (bCallBase)
5947 Window::Command(rCEvt);
5950 /* i#18686 select the object/cursor at the mouse
5951 position of the context menu request */
5952 void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const Point& rMousePos )
5954 const Point aDocPos( PixelToLogic( rMousePos ) );
5955 const bool bIsInsideSelectedObj( rSh.IsInsideSelectedObj( aDocPos ) );
5956 //create a synthetic mouse event out of the coordinates
5957 MouseEvent aMEvt(rMousePos);
5958 SdrView *pSdrView = rSh.GetDrawView();
5959 if ( pSdrView )
5961 // no close of insert_draw and reset of
5962 // draw mode, if context menu position is inside a selected object.
5963 if ( !bIsInsideSelectedObj && m_rView.GetDrawFuncPtr() )
5966 m_rView.GetDrawFuncPtr()->Deactivate();
5967 m_rView.SetDrawFuncPtr(nullptr);
5968 m_rView.LeaveDrawCreate();
5969 SfxBindings& rBind = m_rView.GetViewFrame().GetBindings();
5970 rBind.Invalidate( SID_ATTR_SIZE );
5971 rBind.Invalidate( SID_TABLE_CELL );
5974 // if draw text is active and there's a text selection
5975 // at the mouse position then do nothing
5976 if(rSh.GetSelectionType() & SelectionType::DrawObjectEditMode)
5978 OutlinerView* pOLV = pSdrView->GetTextEditOutlinerView();
5979 ESelection aSelection = pOLV->GetSelection();
5980 if(!aSelection.IsZero())
5982 SdrOutliner* pOutliner = pSdrView->GetTextEditOutliner();
5983 bool bVertical = pOutliner->IsVertical();
5984 const EditEngine& rEditEng = pOutliner->GetEditEngine();
5985 Point aEEPos(aDocPos);
5986 const tools::Rectangle& rOutputArea = pOLV->GetOutputArea();
5987 // regard vertical mode
5988 if(bVertical)
5990 aEEPos -= rOutputArea.TopRight();
5991 //invert the horizontal direction and exchange X and Y
5992 tools::Long nTemp = -aEEPos.X();
5993 aEEPos.setX( aEEPos.Y() );
5994 aEEPos.setY( nTemp );
5996 else
5997 aEEPos -= rOutputArea.TopLeft();
5999 EPosition aDocPosition = rEditEng.FindDocPosition(aEEPos);
6000 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
6001 // make it a forward selection - otherwise the IsLess/IsGreater do not work :-(
6002 aSelection.Adjust();
6003 if(!(aCompare < aSelection) && !(aCompare > aSelection))
6005 return;
6011 if (pSdrView->MouseButtonDown( aMEvt, GetOutDev() ) )
6013 pSdrView->MouseButtonUp( aMEvt, GetOutDev() );
6014 rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false);
6015 return;
6018 rSh.ResetCursorStack();
6020 if ( EnterDrawMode( aMEvt, aDocPos ) )
6022 return;
6024 if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
6026 StopInsFrame();
6027 rSh.Edit();
6030 UpdatePointer( aDocPos );
6032 if( !rSh.IsSelFrameMode() &&
6033 !GetView().GetViewFrame().GetDispatcher()->IsLocked() )
6035 // Test if there is a draw object at that position and if it should be selected.
6036 bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
6038 if(bShould)
6040 m_rView.NoRotate();
6041 rSh.HideCursor();
6043 bool bUnLockView = !rSh.IsViewLocked();
6044 rSh.LockView( true );
6045 bool bSelObj = rSh.SelectObj( aDocPos );
6046 if( bUnLockView )
6047 rSh.LockView( false );
6049 if( bSelObj )
6051 // in case the frame was deselected in the macro
6052 // just the cursor has to be displayed again.
6053 if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
6054 rSh.ShowCursor();
6055 else
6057 if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
6059 m_rView.GetDrawFuncPtr()->Deactivate();
6060 m_rView.SetDrawFuncPtr(nullptr);
6061 m_rView.LeaveDrawCreate();
6062 m_rView.AttrChangedNotify(nullptr);
6065 rSh.EnterSelFrameMode( &aDocPos );
6066 g_bFrameDrag = true;
6067 UpdatePointer( aDocPos );
6068 return;
6072 if (!m_rView.GetDrawFuncPtr())
6073 rSh.ShowCursor();
6076 else if ( rSh.IsSelFrameMode() &&
6077 (m_aActHitType == SdrHitKind::NONE ||
6078 !bIsInsideSelectedObj))
6080 m_rView.NoRotate();
6081 bool bUnLockView = !rSh.IsViewLocked();
6082 rSh.LockView( true );
6084 if ( rSh.IsSelFrameMode() )
6086 rSh.UnSelectFrame();
6087 rSh.LeaveSelFrameMode();
6088 m_rView.AttrChangedNotify(nullptr);
6091 bool bSelObj = rSh.SelectObj( aDocPos, 0/*nFlag*/ );
6092 if( bUnLockView )
6093 rSh.LockView( false );
6095 if( !bSelObj )
6097 // move cursor here so that it is not drawn in the
6098 // frame at first; ShowCursor() happens in LeaveSelFrameMode()
6099 g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
6100 rSh.LeaveSelFrameMode();
6101 m_rView.LeaveDrawCreate();
6102 m_rView.AttrChangedNotify(nullptr);
6104 else
6106 rSh.HideCursor();
6107 rSh.EnterSelFrameMode( &aDocPos );
6108 rSh.SelFlyGrabCursor();
6109 rSh.MakeSelVisible();
6110 g_bFrameDrag = true;
6111 if( rSh.IsFrameSelected() &&
6112 m_rView.GetDrawFuncPtr() )
6114 m_rView.GetDrawFuncPtr()->Deactivate();
6115 m_rView.SetDrawFuncPtr(nullptr);
6116 m_rView.LeaveDrawCreate();
6117 m_rView.AttrChangedNotify(nullptr);
6119 UpdatePointer( aDocPos );
6122 else if ( rSh.IsSelFrameMode() && bIsInsideSelectedObj )
6124 // Object at the mouse cursor is already selected - do nothing
6125 return;
6128 if ( rSh.IsGCAttr() )
6130 rSh.GCAttr();
6131 rSh.ClearGCAttr();
6134 bool bOverSelect = rSh.TestCurrPam( aDocPos );
6135 bool bOverURLGrf = false;
6136 if( !bOverSelect )
6137 bOverURLGrf = bOverSelect = nullptr != rSh.IsURLGrfAtPos( aDocPos );
6139 if ( !bOverSelect )
6141 // create only temporary move context because otherwise
6142 // the query against the content form doesn't work!!!
6143 SwMvContext aMvContext( &rSh );
6144 rSh.CallSetCursor(&aDocPos, false);
6146 if( !bOverURLGrf )
6148 const SelectionType nSelType = rSh.GetSelectionType();
6149 if( nSelType == SelectionType::Ole ||
6150 nSelType == SelectionType::Graphic )
6152 SwMvContext aMvContext( &rSh );
6153 if( !rSh.IsFrameSelected() )
6154 rSh.GotoNextFly();
6155 rSh.EnterSelFrameMode();
6160 static SfxShell* lcl_GetTextShellFromDispatcher( SwView const & rView )
6162 // determine Shell
6163 SfxShell* pShell;
6164 SfxDispatcher* pDispatcher = rView.GetViewFrame().GetDispatcher();
6165 for(sal_uInt16 i = 0; true; ++i )
6167 pShell = pDispatcher->GetShell( i );
6168 if( !pShell || dynamic_cast< const SwTextShell *>( pShell ) != nullptr )
6169 break;
6171 return pShell;
6174 IMPL_LINK_NOARG(SwEditWin, KeyInputFlushHandler, Timer *, void)
6176 FlushInBuffer();
6179 void SwEditWin::InitStaticData()
6181 s_pQuickHlpData = new QuickHelpData();
6184 void SwEditWin::FinitStaticData()
6186 delete s_pQuickHlpData;
6188 /* i#3370 - remove quick help to prevent saving
6189 * of autocorrection suggestions */
6190 void SwEditWin::StopQuickHelp()
6192 if( HasFocus() && s_pQuickHlpData && s_pQuickHlpData->m_bIsDisplayed )
6193 s_pQuickHlpData->Stop( m_rView.GetWrtShell() );
6196 IMPL_LINK_NOARG(SwEditWin, TemplateTimerHdl, Timer *, void)
6198 SetApplyTemplate(SwApplyTemplate());
6201 void SwEditWin::SetChainMode( bool bOn )
6203 if ( !m_bChainMode )
6204 StopInsFrame();
6206 m_pUserMarker.reset();
6208 m_bChainMode = bOn;
6210 static sal_uInt16 aInva[] =
6212 FN_FRAME_CHAIN, FN_FRAME_UNCHAIN, 0
6214 m_rView.GetViewFrame().GetBindings().Invalidate(aInva);
6217 uno::Reference< css::accessibility::XAccessible > SwEditWin::CreateAccessible()
6219 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
6220 SolarMutexGuard aGuard; // this should have happened already!!!
6221 SwWrtShell *pSh = m_rView.GetWrtShellPtr();
6222 OSL_ENSURE( pSh, "no writer shell, no accessible object" );
6223 uno::Reference<
6224 css::accessibility::XAccessible > xAcc;
6225 if( pSh )
6226 xAcc = pSh->CreateAccessible();
6228 return xAcc;
6229 #else
6230 return nullptr;
6231 #endif
6234 void QuickHelpData::Move( QuickHelpData& rCpy )
6236 m_aHelpStrings.clear();
6237 m_aHelpStrings.swap( rCpy.m_aHelpStrings );
6239 m_bIsDisplayed = rCpy.m_bIsDisplayed;
6240 nCurArrPos = rCpy.nCurArrPos;
6241 m_bAppendSpace = rCpy.m_bAppendSpace;
6242 m_bIsTip = rCpy.m_bIsTip;
6243 m_bIsAutoText = rCpy.m_bIsAutoText;
6246 void QuickHelpData::ClearContent()
6248 nCurArrPos = nNoPos;
6249 m_bIsDisplayed = m_bAppendSpace = false;
6250 nTipId = nullptr;
6251 m_aHelpStrings.clear();
6252 m_bIsTip = true;
6253 m_bIsAutoText = true;
6256 void QuickHelpData::Start(SwWrtShell& rSh, const bool bRestart)
6258 if (bRestart)
6260 nCurArrPos = 0;
6262 m_bIsDisplayed = true;
6264 vcl::Window& rWin = rSh.GetView().GetEditWin();
6265 if( m_bIsTip )
6267 Point aPt( rWin.OutputToScreenPixel( rWin.LogicToPixel(
6268 rSh.GetCharRect().Pos() )));
6269 aPt.AdjustY( -3 );
6270 nTipId = Help::ShowPopover(&rWin, tools::Rectangle( aPt, Size( 1, 1 )),
6271 CurStr(),
6272 QuickHelpFlags::Left | QuickHelpFlags::Bottom);
6274 else
6276 OUString sStr(CurStr());
6277 sStr = sStr.copy(CurLen());
6278 sal_uInt16 nL = sStr.getLength();
6279 const ExtTextInputAttr nVal = ExtTextInputAttr::DottedUnderline |
6280 ExtTextInputAttr::Highlight;
6281 const std::vector<ExtTextInputAttr> aAttrs( nL, nVal );
6282 CommandExtTextInputData aCETID( sStr, aAttrs.data(), nL,
6283 0, false );
6285 //fdo#33092. If the current input language is the default
6286 //language that text would appear in if typed, then don't
6287 //force a language on for the ExtTextInput.
6288 LanguageType eInputLanguage = rWin.GetInputLanguage();
6289 if (lcl_isNonDefaultLanguage(eInputLanguage,
6290 rSh.GetView(), sStr) == INVALID_HINT)
6292 eInputLanguage = LANGUAGE_DONTKNOW;
6295 rSh.CreateExtTextInput(eInputLanguage);
6296 rSh.SetExtTextInputData( aCETID );
6300 void QuickHelpData::Stop( SwWrtShell& rSh )
6302 if( !m_bIsTip )
6303 rSh.DeleteExtTextInput( false );
6304 else if( nTipId )
6306 vcl::Window& rWin = rSh.GetView().GetEditWin();
6307 Help::HidePopover(&rWin, nTipId);
6309 ClearContent();
6312 void QuickHelpData::FillStrArr( SwWrtShell const & rSh, const OUString& rWord )
6314 enum Capitalization { CASE_LOWER, CASE_UPPER, CASE_SENTENCE, CASE_OTHER };
6316 // Determine word capitalization
6317 const CharClass& rCC = GetAppCharClass();
6318 const OUString sWordLower = rCC.lowercase( rWord );
6319 Capitalization aWordCase = CASE_OTHER;
6320 if ( !rWord.isEmpty() )
6322 if ( rWord[0] == sWordLower[0] )
6324 if ( rWord == sWordLower )
6325 aWordCase = CASE_LOWER;
6327 else
6329 // First character is not lower case i.e. assume upper or title case
6330 OUString sWordSentence = sWordLower.replaceAt( 0, 1, rtl::OUStringChar(rWord[0]) );
6331 if ( rWord == sWordSentence )
6332 aWordCase = CASE_SENTENCE;
6333 else
6335 if ( rWord == rCC.uppercase( rWord ) )
6336 aWordCase = CASE_UPPER;
6341 SwCalendarWrapper& rCalendar = s_getCalendarWrapper();
6342 rCalendar.LoadDefaultCalendar( rSh.GetCurLang() );
6344 // Add matching calendar month and day names
6345 for ( const auto& aNames : { rCalendar.getMonths(), rCalendar.getDays() } )
6347 for ( const auto& rName : aNames )
6349 const OUString& rStr( rName.FullName );
6350 // Check string longer than word and case insensitive match
6351 if( rStr.getLength() > rWord.getLength() &&
6352 rCC.lowercase( rStr, 0, rWord.getLength() ) == sWordLower )
6354 OUString sStr;
6356 //fdo#61251 if it's an exact match, ensure unchanged replacement
6357 //exists as a candidate
6358 if (rStr.startsWith(rWord))
6359 m_aHelpStrings.emplace_back(rStr, rWord.getLength());
6360 else
6361 sStr = rStr; // to be added if no case conversion is performed below
6363 if ( aWordCase == CASE_LOWER )
6364 sStr = rCC.lowercase(rStr);
6365 else if ( aWordCase == CASE_SENTENCE )
6366 sStr = rCC.lowercase(rStr).replaceAt(0, 1, rtl::OUStringChar(rStr[0]));
6367 else if ( aWordCase == CASE_UPPER )
6368 sStr = rCC.uppercase(rStr);
6370 if (!sStr.isEmpty())
6371 m_aHelpStrings.emplace_back(sStr, rWord.getLength());
6376 // Add matching current date in ISO 8601 format, for example 2016-01-30
6377 OUString rStrToday;
6379 // do not suggest for single years, for example for "2016",
6380 // only for "201" or "2016-..." (to avoid unintentional text
6381 // insertion at line ending, for example typing "30 January 2016")
6382 if (!rWord.isEmpty() && rWord.getLength() != 4 && rWord[0] == '2')
6384 rStrToday = utl::toISO8601(DateTime(Date(Date::SYSTEM)).GetUNODateTime());
6385 if (rStrToday.startsWith(rWord))
6386 m_aHelpStrings.emplace_back(rStrToday, rWord.getLength());
6389 // Add matching words from AutoCompleteWord list
6390 const SwAutoCompleteWord& rACList = SwEditShell::GetAutoCompleteWords();
6391 std::vector<OUString> strings;
6393 if ( !rACList.GetWordsMatching( rWord, strings ) )
6394 return;
6396 for (const OUString & aCompletedString : strings)
6398 // when we have a matching current date, avoid to suggest
6399 // other words with the same matching starting characters,
6400 // for example 2016-01-3 instead of 2016-01-30
6401 if (!rStrToday.isEmpty() && aCompletedString.startsWith(rWord))
6402 continue;
6404 OUString sStr;
6406 //fdo#61251 if it's an exact match, ensure unchanged replacement
6407 //exists as a candidate
6408 if (aCompletedString.startsWith(rWord))
6409 m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
6410 else
6411 sStr = aCompletedString; // to be added if no case conversion is performed below
6413 if (aWordCase == CASE_LOWER)
6414 sStr = rCC.lowercase(aCompletedString);
6415 else if (aWordCase == CASE_SENTENCE)
6416 sStr = rCC.lowercase(aCompletedString)
6417 .replaceAt(0, 1, rtl::OUStringChar(aCompletedString[0]));
6418 else if (aWordCase == CASE_UPPER)
6419 sStr = rCC.uppercase(aCompletedString);
6421 if (!sStr.isEmpty())
6422 m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength());
6426 namespace {
6428 class CompareIgnoreCaseAsciiFavorExact
6430 const OUString &m_rOrigWord;
6431 public:
6432 explicit CompareIgnoreCaseAsciiFavorExact(const OUString& rOrigWord)
6433 : m_rOrigWord(rOrigWord)
6437 bool operator()(const std::pair<OUString, sal_uInt16>& s1,
6438 const std::pair<OUString, sal_uInt16>& s2) const
6440 int nRet = s1.first.compareToIgnoreAsciiCase(s2.first);
6441 if (nRet == 0)
6443 //fdo#61251 sort stuff that starts with the exact rOrigWord before
6444 //another ignore-case candidate
6445 int n1StartsWithOrig = s1.first.startsWith(m_rOrigWord) ? 0 : 1;
6446 int n2StartsWithOrig = s2.first.startsWith(m_rOrigWord) ? 0 : 1;
6447 return n1StartsWithOrig < n2StartsWithOrig;
6449 return nRet < 0;
6453 struct EqualIgnoreCaseAscii
6455 bool operator()(const std::pair<OUString, sal_uInt16>& s1,
6456 const std::pair<OUString, sal_uInt16>& s2) const
6458 return s1.first.equalsIgnoreAsciiCase(s2.first);
6462 } // anonymous namespace
6464 // TODO Implement an i18n aware sort
6465 void QuickHelpData::SortAndFilter(const OUString &rOrigWord)
6467 std::sort( m_aHelpStrings.begin(),
6468 m_aHelpStrings.end(),
6469 CompareIgnoreCaseAsciiFavorExact(rOrigWord) );
6471 const auto& it
6472 = std::unique(m_aHelpStrings.begin(), m_aHelpStrings.end(), EqualIgnoreCaseAscii());
6473 m_aHelpStrings.erase( it, m_aHelpStrings.end() );
6475 nCurArrPos = 0;
6478 // For a given chunk of typed text between 3 and 9 characters long that may start at a word boundary
6479 // or in a whitespace and may include whitespaces, SwEditShell::GetChunkForAutoTextcreates a list of
6480 // possible candidates for long AutoText names. Let's say, we have typed text "lorem ipsum dr f";
6481 // and the cursor is right after the "f". SwEditShell::GetChunkForAutoText would take " dr f",
6482 // since it's the longest chunk to the left of the cursor no longer than 9 characters, not starting
6483 // in the middle of a word. Then it would create this list from it (in this order, longest first):
6484 // " dr f"
6485 // " dr f"
6486 // "dr f"
6487 // It cannot add "r f", because it starts in the middle of the word "dr"; also it cannot give " f",
6488 // because it's only 2 characters long.
6489 // Now the result of SwEditShell::GetChunkForAutoText is passed here to SwEditWin::ShowAutoText, and
6490 // then to SwGlossaryList::HasLongName, where all existing autotext entries' long names are tested
6491 // if they start with one of the list elements. The matches are sorted according the position of the
6492 // candidate that matched first, then alphabetically inside the group of suggestions for a given
6493 // candidate. Say, if we have these AutoText entry long names:
6494 // "Dr Frodo"
6495 // "Dr Credo"
6496 // "Or Bilbo"
6497 // "dr foo"
6498 // " Dr Fuzz"
6499 // " dr Faust"
6500 // the resulting list would be:
6501 // " Dr Fuzz" -> matches the first (longest) item in the candidates list
6502 // " dr Faust" -> matches the second candidate item
6503 // "Dr Foo" -> first item of the two matching the third candidate; alphabetically sorted
6504 // "Dr Frodo" -> second item of the two matching the third candidate; alphabetically sorted
6505 // Each of the resulting suggestions knows the length of the candidate it replaces, so accepting the
6506 // first suggestion would replace 6 characters before cursor, while tabbing to and accepting the
6507 // last suggestion would replace only 4 characters to the left of cursor.
6508 bool SwEditWin::ShowAutoText(const std::vector<OUString>& rChunkCandidates)
6510 s_pQuickHlpData->ClearContent();
6511 if (!rChunkCandidates.empty())
6513 SwGlossaryList* pList = ::GetGlossaryList();
6514 pList->HasLongName(rChunkCandidates, s_pQuickHlpData->m_aHelpStrings);
6517 if (!s_pQuickHlpData->m_aHelpStrings.empty())
6519 s_pQuickHlpData->Start(m_rView.GetWrtShell(), true);
6521 return !s_pQuickHlpData->m_aHelpStrings.empty();
6524 void SwEditWin::ShowAutoCorrectQuickHelp(
6525 const OUString& rWord, SvxAutoCorrect& rACorr )
6527 if (rWord.isEmpty())
6528 return;
6529 SwWrtShell& rSh = m_rView.GetWrtShell();
6530 s_pQuickHlpData->ClearContent();
6532 if( s_pQuickHlpData->m_aHelpStrings.empty() &&
6533 rACorr.GetSwFlags().bAutoCompleteWords )
6535 s_pQuickHlpData->m_bIsAutoText = false;
6536 s_pQuickHlpData->m_bIsTip = rACorr.GetSwFlags().bAutoCmpltShowAsTip;
6538 // Get the necessary data to show help text.
6539 s_pQuickHlpData->FillStrArr( rSh, rWord );
6542 if( !s_pQuickHlpData->m_aHelpStrings.empty() )
6544 s_pQuickHlpData->SortAndFilter(rWord);
6545 s_pQuickHlpData->Start(rSh, true);
6549 bool SwEditWin::IsInHeaderFooter( const Point &rDocPt, FrameControlType &rControl ) const
6551 SwWrtShell &rSh = m_rView.GetWrtShell();
6552 const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( rDocPt );
6554 if ( pPageFrame && pPageFrame->IsOverHeaderFooterArea( rDocPt, rControl ) )
6555 return true;
6557 if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) || rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
6559 SwFrameControlsManager &rMgr = rSh.GetView().GetEditWin().GetFrameControlsManager();
6560 Point aPoint( LogicToPixel( rDocPt ) );
6562 if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Header ) )
6564 SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Header, pPageFrame );
6565 if ( pControl && pControl->Contains( aPoint ) )
6567 rControl = FrameControlType::Header;
6568 return true;
6572 if ( rSh.IsShowHeaderFooterSeparator( FrameControlType::Footer ) )
6574 SwFrameControlPtr pControl = rMgr.GetControl( FrameControlType::Footer, pPageFrame );
6575 if ( pControl && pControl->Contains( aPoint ) )
6577 rControl = FrameControlType::Footer;
6578 return true;
6583 return false;
6586 bool SwEditWin::IsOverHeaderFooterFly( const Point& rDocPos, FrameControlType& rControl, bool& bOverFly, bool& bPageAnchored ) const
6588 bool bRet = false;
6589 Point aPt( rDocPos );
6590 SwWrtShell &rSh = m_rView.GetWrtShell();
6591 SwPaM aPam( *rSh.GetCurrentShellCursor().GetPoint() );
6592 rSh.GetLayout()->GetModelPositionForViewPoint( aPam.GetPoint(), aPt, nullptr, true );
6594 const SwStartNode* pStartFly = aPam.GetPoint()->GetNode().FindFlyStartNode();
6595 if ( pStartFly )
6597 bOverFly = true;
6598 SwFrameFormat* pFlyFormat = pStartFly->GetFlyFormat( );
6599 if ( pFlyFormat )
6601 const SwNode* pAnchorNode = pFlyFormat->GetAnchor( ).GetAnchorNode( );
6602 if ( pAnchorNode )
6604 bool bInHeader = pAnchorNode->FindHeaderStartNode( ) != nullptr;
6605 bool bInFooter = pAnchorNode->FindFooterStartNode( ) != nullptr;
6607 bRet = bInHeader || bInFooter;
6608 if ( bInHeader )
6609 rControl = FrameControlType::Header;
6610 else if ( bInFooter )
6611 rControl = FrameControlType::Footer;
6613 else
6614 bPageAnchored = pFlyFormat->GetAnchor( ).GetAnchorId( ) == RndStdIds::FLY_AT_PAGE;
6617 else
6618 bOverFly = false;
6619 return bRet;
6622 void SwEditWin::SetUseInputLanguage( bool bNew )
6624 if ( bNew || m_bUseInputLanguage )
6626 SfxBindings& rBind = GetView().GetViewFrame().GetBindings();
6627 rBind.Invalidate( SID_ATTR_CHAR_FONT );
6628 rBind.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
6630 m_bUseInputLanguage = bNew;
6633 OUString SwEditWin::GetSurroundingText() const
6635 SwWrtShell& rSh = m_rView.GetWrtShell();
6637 if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6638 return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingText();
6640 OUString sReturn;
6641 if( rSh.HasSelection() && !rSh.IsMultiSelection() && rSh.IsSelOnePara() )
6642 rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
6643 else if( !rSh.HasSelection() )
6645 bool bUnLockView = !rSh.IsViewLocked();
6646 rSh.LockView(true);
6648 // store shell state *before* Push
6649 ::std::optional<SwCallLink> aLink(std::in_place, rSh);
6650 rSh.Push();
6652 // disable accessible events for internal-only helper cursor
6653 const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6654 rSh.SetSendAccessibleCursorEvents(false);
6656 // get the sentence around the cursor
6657 rSh.HideCursor();
6658 rSh.GoStartSentence();
6659 rSh.SetMark();
6660 rSh.GoEndSentence();
6661 rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
6663 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
6664 rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6665 rSh.HideCursor();
6667 if (bUnLockView)
6668 rSh.LockView(false);
6671 return sReturn;
6674 Selection SwEditWin::GetSurroundingTextSelection() const
6676 SwWrtShell& rSh = m_rView.GetWrtShell();
6678 if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6679 return rSh.GetDrawView()->GetTextEditOutlinerView()->GetSurroundingTextSelection();
6681 Selection aSel(0, 0);
6682 if( rSh.HasSelection() )
6684 OUString sReturn;
6685 rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
6686 aSel = Selection( 0, sReturn.getLength() );
6688 else if (rSh.GetCursor()->GetPoint()->GetNode().GetTextNode())
6690 bool bUnLockView = !rSh.IsViewLocked();
6691 rSh.LockView(true);
6693 // Return the position of the visible cursor in the sentence
6694 // around the visible cursor.
6695 TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
6697 // store shell state *before* Push
6698 ::std::optional<SwCallLink> aLink(std::in_place, rSh);
6699 rSh.Push();
6701 // disable accessible events for internal-only helper cursor
6702 const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6703 rSh.SetSendAccessibleCursorEvents(false);
6705 rSh.HideCursor();
6706 rSh.GoStartSentence();
6707 TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
6709 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, aLink);
6710 rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6711 rSh.ShowCursor();
6713 if (bUnLockView)
6714 rSh.LockView(false);
6716 aSel = Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
6719 return aSel;
6722 bool SwEditWin::DeleteSurroundingText(const Selection& rSelection)
6724 SwWrtShell& rSh = m_rView.GetWrtShell();
6726 if (rSh.HasDrawView() && rSh.GetDrawView()->IsTextEdit())
6727 return rSh.GetDrawView()->GetTextEditOutlinerView()->DeleteSurroundingText(rSelection);
6729 if (rSh.HasSelection())
6730 return false;
6732 // rSelection is relative to the start of the sentence, so find that and
6733 // adjust the range by it
6734 rSh.Push();
6736 // disable accessible events for internal-only helper cursor
6737 const bool bSendAccessibleEventOld = rSh.IsSendAccessibleCursorEvents();
6738 rSh.SetSendAccessibleCursorEvents(false);
6740 rSh.HideCursor();
6741 rSh.GoStartSentence();
6742 TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
6744 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
6745 rSh.SetSendAccessibleCursorEvents(bSendAccessibleEventOld);
6746 rSh.ShowCursor();
6748 if (rSh.SelectTextView(nStartPos + TextFrameIndex(rSelection.Min()), nStartPos + TextFrameIndex(rSelection.Max())))
6750 rSh.Delete(false);
6751 return true;
6754 return false;
6757 void SwEditWin::LogicInvalidate(const tools::Rectangle* pRectangle)
6759 SfxLokHelper::notifyInvalidation(&m_rView, pRectangle);
6762 void SwEditWin::SetCursorTwipPosition(const Point& rPosition, bool bPoint, bool bClearMark)
6764 if (SdrView* pSdrView = m_rView.GetWrtShell().GetDrawView())
6766 // Editing shape text, then route the call to editeng.
6767 if (pSdrView->GetTextEditObject())
6769 EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView();
6770 rEditView.SetCursorLogicPosition(rPosition, bPoint, bClearMark);
6771 return;
6775 if (m_rView.GetPostItMgr())
6777 if (sw::annotation::SwAnnotationWin* pWin = m_rView.GetPostItMgr()->GetActiveSidebarWin())
6779 // Editing postit text.
6780 pWin->SetCursorLogicPosition(rPosition, bPoint, bClearMark);
6781 return;
6785 // Not an SwWrtShell, as that would make SwCursorShell::GetCursor() inaccessible.
6786 SwEditShell& rShell = m_rView.GetWrtShell();
6788 bool bCreateSelection = false;
6790 SwMvContext aMvContext(&rShell);
6791 if (bClearMark)
6792 rShell.ClearMark();
6793 else
6794 bCreateSelection = !rShell.HasMark();
6796 if (bCreateSelection)
6797 m_rView.GetWrtShell().SttSelect();
6799 // If the mark is to be updated, then exchange the point and mark before
6800 // and after, as we can't easily set the mark.
6801 if (!bPoint)
6802 rShell.getShellCursor(/*bBlock=*/false)->Exchange();
6803 rShell.SetCursor(rPosition);
6804 if (!bPoint)
6805 rShell.getShellCursor(/*bBlock=*/false)->Exchange();
6808 if (bCreateSelection)
6809 m_rView.GetWrtShell().EndSelect();
6812 void SwEditWin::SetGraphicTwipPosition(bool bStart, const Point& rPosition)
6814 if (bStart)
6816 MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
6817 MouseButtonDown(aClickEvent);
6818 MouseEvent aMoveEvent(Point(rPosition.getX() + MIN_MOVE + 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
6819 MouseMove(aMoveEvent);
6821 else
6823 MouseEvent aMoveEvent(Point(rPosition.getX() - MIN_MOVE - 1, rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
6824 MouseMove(aMoveEvent);
6825 MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
6826 MouseButtonUp(aClickEvent);
6830 SwFrameControlsManager& SwEditWin::GetFrameControlsManager()
6832 return *m_pFrameControlsManager;
6835 void SwEditWin::ToggleOutlineContentVisibility(const size_t nOutlinePos, const bool bSubs)
6837 // bSubs purpose is to set all sub level outline content to the same visibility as
6838 // nOutlinePos outline content visibility is toggled. It is only applicable when not treating
6839 // sub outline levels as content.
6840 SwWrtShell& rSh = GetView().GetWrtShell();
6842 if (GetView().GetDrawView()->IsTextEdit())
6843 rSh.EndTextEdit();
6844 if (GetView().IsDrawMode())
6845 GetView().LeaveDrawCreate();
6846 rSh.EnterStdMode();
6848 if (!bSubs || rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
6850 SwNode* pNode = rSh.GetNodes().GetOutLineNds()[nOutlinePos];
6851 bool bVisible = true;
6852 pNode->GetTextNode()->GetAttrOutlineContentVisible(bVisible);
6853 pNode->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
6855 else if (bSubs)
6857 // also toggle sub levels to the same content visibility
6858 SwOutlineNodes::size_type nPos = nOutlinePos;
6859 SwOutlineNodes::size_type nOutlineNodesCount
6860 = rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount();
6861 int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos);
6862 bool bVisible = rSh.IsOutlineContentVisible(nOutlinePos);
6865 if (rSh.IsOutlineContentVisible(nPos) == bVisible)
6866 rSh.GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
6867 } while (++nPos < nOutlineNodesCount
6868 && rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
6871 rSh.InvalidateOutlineContentVisibility();
6872 rSh.GotoOutline(nOutlinePos);
6873 rSh.SetModified();
6874 GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
6877 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */