xref: /core/sw/source/uibase/wrtsh/select.cxx (revision ac3b217a43e21b00f434fa796a0c966b9ddfd9df)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <limits.h>
21 #include <hintids.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/viewfrm.hxx>
24 #include <svl/eitem.hxx>
25 #include <svl/macitem.hxx>
26 #include <unotools/charclass.hxx>
27 #include <sfx2/event.hxx>
28 #include <osl/diagnose.h>
29 #include <cmdid.h>
30 #include <view.hxx>
31 #include <basesh.hxx>
32 #include <wrtsh.hxx>
33 #include <frmatr.hxx>
34 #include <mdiexp.hxx>
35 #include <fmtcol.hxx>
36 #include <frmfmt.hxx>
37 #include <swdtflvr.hxx>
38 #include <doc.hxx>
39 #include <wordcountdialog.hxx>
40 #include <memory>
41 #include <vcl/uitest/logger.hxx>
42 #include <vcl/uitest/eventdescription.hxx>
43 
44 #include <officecfg/Office/Common.hxx>
45 #include <strings.hrc>
46 
47 #include <svx/svdview.hxx>
48 
49 namespace com::sun::star::util {
50     struct SearchOptions2;
51 }
52 
53 using namespace ::com::sun::star::util;
54 
55 static tools::Long nStartDragX = 0, nStartDragY = 0;
56 static bool  bStartDrag = false;
57 
Invalidate()58 void SwWrtShell::Invalidate()
59 {
60     // to avoid making the slot volatile, invalidate it every time if something could have been changed
61     // this is still much cheaper than asking for the state every 200 ms (and avoid background processing)
62     GetView().GetViewFrame().GetBindings().Invalidate( FN_STAT_SELMODE );
63     GetView().GetViewFrame().GetBindings().Update(FN_STAT_SELMODE); // make selection mode control icon update immediately
64     SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
65     if (pWrdCnt)
66         pWrdCnt->UpdateCounts();
67 }
68 
SelNearestWrd()69 bool SwWrtShell::SelNearestWrd()
70 {
71     SwMvContext aMvContext(this);
72     if( !IsInWord() && !IsEndWrd() && !IsStartWord() )
73         PrvWrd();
74     if( IsEndWrd() )
75         Left(SwCursorSkipMode::Cells, false, 1, false );
76     return SelWrd();
77 }
78 
SelWrd(const Point * pPt,sal_Int16 nWordType)79 bool SwWrtShell::SelWrd(const Point *pPt, sal_Int16 nWordType )
80 {
81     bool bRet;
82     {
83         SwMvContext aMvContext(this);
84         SttSelect();
85         bRet = SwCursorShell::SelectWordWT( pPt, nWordType );
86     }
87     EndSelect();
88     if( bRet )
89     {
90         m_bSelWrd = true;
91         if(pPt)
92             m_aStart = *pPt;
93     }
94     return bRet;
95 }
96 
SelSentence(const Point * pPt)97 void SwWrtShell::SelSentence(const Point *pPt )
98 {
99     {
100         SwMvContext aMvContext(this);
101         ClearMark();
102         SwCursorShell::GoStartSentence();
103         SttSelect();
104         SwCursorShell::GoEndSentence();
105     }
106     EndSelect();
107     if(pPt)
108         m_aStart = *pPt;
109     m_bSelLn = true;
110     m_bSelWrd = false;  // disable SelWord, otherwise no SelLine goes on
111 }
112 
SelPara(const Point * pPt)113 void SwWrtShell::SelPara(const Point *pPt )
114 {
115     {
116         SwMvContext aMvContext(this);
117         ClearMark();
118         SwCursorShell::MovePara( GoCurrPara, fnParaStart );
119         SttSelect();
120         SwCursorShell::MovePara( GoCurrPara, fnParaEnd );
121     }
122     EndSelect();
123     if(pPt)
124         m_aStart = *pPt;
125     m_bSelLn = false;
126     m_bSelWrd = false;  // disable SelWord, otherwise no SelLine goes on
127 }
128 
SelAll()129 void SwWrtShell::SelAll()
130 {
131     const bool bLockedView = IsViewLocked();
132     LockView( true );
133     {
134         if(m_bBlockMode)
135             LeaveBlockMode();
136         SwMvContext aMvContext(this);
137         bool bMoveTable = false;
138         std::optional<SwPosition> oStartPos;
139         std::optional<SwPosition> oEndPos;
140         SwShellCursor* pTmpCursor = nullptr;
141 
142         // Query these early, before we move the cursor.
143         bool bHasWholeTabSelection = HasWholeTabSelection();
144         bool bIsCursorInTable = IsCursorInTable();
145 
146         if (!bHasWholeTabSelection
147             && (   !bIsCursorInTable
148                 || getShellCursor(false)->GetMarkNode().FindTableNode() == nullptr
149                 || !ExtendedSelectedAll())) // ESA inside table -> else branch
150         {
151             if ( IsSelection() && IsCursorPtAtEnd() )
152                 SwapPam();
153             pTmpCursor = getShellCursor( false );
154             if( pTmpCursor )
155             {
156                 oStartPos.emplace( *pTmpCursor->GetPoint() );
157                 oEndPos.emplace( *pTmpCursor->GetMark() );
158             }
159             Push();
160             bool bIsFullSel = !MoveSection( GoCurrSection, fnSectionStart);
161             SwapPam();
162             bIsFullSel &= !MoveSection( GoCurrSection, fnSectionEnd);
163             Pop(SwCursorShell::PopMode::DeleteCurrent);
164             GoStart(true, &bMoveTable, false, !bIsFullSel);
165             SttSelect();
166             GoEnd(true, &bMoveTable);
167         }
168         else
169         {
170             if (MoveOutOfTable())
171             {   // select outer text
172                 EnterStdMode(); // delete m_pTableCursor
173 //                GoStart(true, &bMoveTable, false, true);
174                 MoveSection(GoCurrSection, fnSectionStart); // don't move into prev table
175                 SttSelect();
176                 MoveSection(GoCurrSection, fnSectionEnd); // don't move to different cell
177             }
178             else
179             {
180                 TrySelectOuterTable();
181             }
182         }
183 
184         bool bNeedsExtendedSelectAll = StartsWith_() != StartsWith::None;
185 
186         // the GoEnd() could have created a table selection, if so avoid ESA.
187         if (bNeedsExtendedSelectAll && bIsCursorInTable)
188         {
189             bNeedsExtendedSelectAll = !HasWholeTabSelection();
190         }
191 
192         if (bNeedsExtendedSelectAll)
193         {
194             ExtendedSelectAll(/*bFootnotes =*/ false);
195         }
196 
197         SwDoc *pDoc = GetDoc();
198         if ( pDoc )
199         {
200             pDoc->SetPrepareSelAll();
201         }
202 
203         if( oStartPos )
204         {
205             pTmpCursor = getShellCursor( false );
206             if( pTmpCursor )
207             {
208                 // Some special handling for sections (e.g. TOC) at the beginning of the document body
209                 // to avoid the selection of the first section
210                 // if the last selection was behind the first section or
211                 // if the last selection was already the first section
212                 // In this both cases we select to the end of document
213                 if( ( *pTmpCursor->GetPoint() < *oEndPos ||
214                     ( *oStartPos == *pTmpCursor->GetMark() &&
215                       *oEndPos == *pTmpCursor->GetPoint() ) ) && !bNeedsExtendedSelectAll)
216                     SwCursorShell::SttEndDoc(false);
217             }
218         }
219     }
220     EndSelect();
221     LockView( bLockedView );
222 }
223 
224 // Description: Text search
225 
SearchPattern(const i18nutil::SearchOptions2 & rSearchOpt,bool bSearchInNotes,SwDocPositions eStt,SwDocPositions eEnd,FindRanges eFlags,bool bReplace)226 sal_Int32 SwWrtShell::SearchPattern( const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes,
227                                 SwDocPositions eStt, SwDocPositions eEnd,
228                                 FindRanges eFlags, bool bReplace )
229 {
230         // no enhancement of existing selections
231     if(!(eFlags & FindRanges::InSel))
232         ClearMark();
233     bool bCancel = false;
234     sal_Int32 nRet = Find_Text(rSearchOpt, bSearchInNotes, eStt, eEnd, bCancel, eFlags, bReplace);
235     if(bCancel)
236     {
237         Undo();
238         nRet = SAL_MAX_INT32;
239     }
240     return nRet;
241 }
242 
243 // Description: search for templates
244 
SearchTempl(const UIName & rTempl,SwDocPositions eStt,SwDocPositions eEnd,FindRanges eFlags,const UIName * pReplTempl)245 sal_Int32 SwWrtShell::SearchTempl( const UIName &rTempl,
246                                SwDocPositions eStt, SwDocPositions eEnd,
247                                FindRanges eFlags, const UIName* pReplTempl )
248 {
249         // no enhancement of existing selections
250     if(!(eFlags & FindRanges::InSel))
251         ClearMark();
252     SwTextFormatColl *pColl = GetParaStyle(rTempl, SwWrtShell::GETSTYLE_CREATESOME);
253     SwTextFormatColl *pReplaceColl = nullptr;
254     if( pReplTempl )
255         pReplaceColl = GetParaStyle(*pReplTempl, SwWrtShell::GETSTYLE_CREATESOME );
256 
257     bool bCancel = false;
258     sal_Int32 nRet = FindFormat(pColl ? *pColl : GetDfltTextFormatColl(),
259                                eStt,eEnd, bCancel, eFlags, pReplaceColl);
260     if(bCancel)
261     {
262         Undo();
263         nRet = SAL_MAX_INT32;
264     }
265     return nRet;
266 }
267 
268 // search for attributes
269 
SearchAttr(const SfxItemSet & rFindSet,bool bNoColls,SwDocPositions eStart,SwDocPositions eEnd,FindRanges eFlags,const i18nutil::SearchOptions2 * pSearchOpt,const SfxItemSet * pReplaceSet)270 sal_Int32 SwWrtShell::SearchAttr( const SfxItemSet& rFindSet, bool bNoColls,
271                                 SwDocPositions eStart, SwDocPositions eEnd,
272                                 FindRanges eFlags, const i18nutil::SearchOptions2* pSearchOpt,
273                                 const SfxItemSet* pReplaceSet )
274 {
275     // no enhancement of existing selections
276     if (!(eFlags & FindRanges::InSel))
277         ClearMark();
278 
279     // Searching
280     bool bCancel = false;
281     sal_Int32 nRet = FindAttrs(rFindSet, bNoColls, eStart, eEnd, bCancel, eFlags, pSearchOpt, pReplaceSet);
282 
283     if(bCancel)
284     {
285         Undo();
286         nRet = SAL_MAX_INT32;
287     }
288     return nRet;
289 }
290 
291 // Selection modes
292 
PushMode()293 void SwWrtShell::PushMode()
294 {
295     m_pModeStack = new ModeStack( m_pModeStack, m_bIns, m_bExtMode, m_bAddMode, m_bBlockMode );
296 }
297 
PopMode()298 void SwWrtShell::PopMode()
299 {
300     if ( nullptr == m_pModeStack )
301         return;
302 
303     if ( m_bExtMode && !m_pModeStack->bExt )
304         LeaveExtMode();
305     if ( m_bAddMode && !m_pModeStack->bAdd )
306         LeaveAddMode();
307     if ( m_bBlockMode && !m_pModeStack->bBlock )
308         LeaveBlockMode();
309     m_bIns = m_pModeStack->bIns;
310 
311     m_pModeStack = std::move(m_pModeStack->pNext);
312 }
313 
314 // Two methods for setting cursors: the first maps at the
315 // eponymous methods in the CursorShell, the second removes
316 // all selections at first.
317 
SetCursor(const Point * pPt,bool bTextOnly,ScrollSizeMode eScrollSizeMode)318 tools::Long SwWrtShell::SetCursor(const Point *pPt, bool bTextOnly, ScrollSizeMode eScrollSizeMode)
319 {
320         // Remove a possibly present selection at the position
321         // of the mouseclick
322 
323     if(!IsInSelect() && TestCurrPam(*pPt)) {
324         ClearMark();
325     }
326 
327     return SwCursorShell::SetCursor(*pPt, bTextOnly, true, false, eScrollSizeMode );
328 }
329 
SetCursorKillSel(const Point * pPt,bool bTextOnly,ScrollSizeMode eScrollSizeMode)330 tools::Long SwWrtShell::SetCursorKillSel(const Point *pPt, bool bTextOnly, ScrollSizeMode eScrollSizeMode )
331 {
332     SwActContext aActContext(this);
333     ResetSelect(pPt, false, ScrollSizeMode::ScrollSizeDefault);
334     return SwCursorShell::SetCursor(*pPt, bTextOnly, true, false, eScrollSizeMode);
335 }
336 
UnSelectFrame()337 void SwWrtShell::UnSelectFrame()
338 {
339     // Remove Frame selection with guaranteed invalid position
340     Point aPt(LONG_MIN, LONG_MIN);
341     SelectObj(aPt);
342     SwTransferable::ClearSelection( *this );
343 }
344 
345 // Remove of all selections
346 
ResetSelect(const Point *,bool,ScrollSizeMode)347 tools::Long SwWrtShell::ResetSelect(const Point *, bool, ScrollSizeMode)
348 {
349     if(IsSelFrameMode())
350     {
351         UnSelectFrame();
352         LeaveSelFrameMode();
353     }
354     else
355     {
356         //  SwActContext opens an Action -
357         //  to avoid problems in the basic process with the
358         //  shell switching, GetChgLnk().Call() may be called
359         //  after EndAction().
360         {
361             SwActContext aActContext(this);
362             m_bSelWrd = m_bSelLn = false;
363             KillPams();
364             ClearMark();
365             m_fnKillSel = &SwWrtShell::Ignore;
366             m_fnSetCursor = &SwWrtShell::SetCursor;
367         }
368 
369         // After canceling of all selections an update of Attr-Controls
370         // could be necessary.
371         GetChgLnk().Call(nullptr);
372 
373         if ( GetEnhancedTableSelection() != SwTable::SEARCH_NONE )
374             UnsetEnhancedTableSelection();
375     }
376     Invalidate();
377     SwTransferable::ClearSelection( *this );
378     return 1;
379 }
380 
IsSplitVerticalByDefault() const381 bool SwWrtShell::IsSplitVerticalByDefault() const
382 {
383     return GetDoc()->IsSplitVerticalByDefault();
384 }
385 
SetSplitVerticalByDefault(bool value)386 void SwWrtShell::SetSplitVerticalByDefault(bool value)
387 {
388     GetDoc()->SetSplitVerticalByDefault(value);
389 }
390 
391 // Do nothing
392 
Ignore(const Point *,bool,ScrollSizeMode)393 tools::Long SwWrtShell::Ignore(const Point *, bool, ScrollSizeMode )
394 {
395     return 1;
396 }
397 
398 // Begin of a selection process.
399 
SttSelect()400 void SwWrtShell::SttSelect()
401 {
402     if(m_bInSelect)
403         return;
404     if(!HasMark())
405         SetMark();
406     if( m_bBlockMode )
407     {
408         SwShellCursor* pTmp = getShellCursor( true );
409         if( !pTmp->HasMark() )
410             pTmp->SetMark();
411     }
412     m_fnKillSel = &SwWrtShell::Ignore;
413     m_fnSetCursor = &SwWrtShell::SetCursor;
414     m_bInSelect = true;
415     Invalidate();
416     SwTransferable::CreateSelection( *this );
417 }
418 
419 namespace {
420 
collectUIInformation(SwShellCursor * pCursor)421 void collectUIInformation(SwShellCursor* pCursor)
422 {
423     EventDescription aDescription;
424     OUString aSelStart = OUString::number(pCursor->Start()->GetContentIndex());
425     OUString aSelEnd = OUString::number(pCursor->End()->GetContentIndex());
426 
427     aDescription.aParameters = {{"START_POS", aSelStart}, {"END_POS", aSelEnd}};
428     aDescription.aAction = "SELECT";
429     aDescription.aID = "writer_edit";
430     aDescription.aKeyWord = "SwEditWinUIObject";
431     aDescription.aParent = "MainWindow";
432 
433     UITestLogger::getInstance().logEvent(aDescription);
434 }
435 
436 }
437 
438 // End of a selection process.
439 
EndSelect()440 void SwWrtShell::EndSelect()
441 {
442     if(m_bInSelect && !m_bExtMode)
443     {
444         m_bInSelect = false;
445         if (m_bAddMode)
446         {
447             AddLeaveSelect();
448         }
449         else
450         {
451             SttLeaveSelect();
452             m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
453             m_fnKillSel = &SwWrtShell::ResetSelect;
454         }
455     }
456     SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
457     if (pWrdCnt)
458         pWrdCnt->UpdateCounts();
459 
460     collectUIInformation(GetCursor_());
461 }
462 
ExtSelWrd(const Point * pPt,bool)463 void SwWrtShell::ExtSelWrd(const Point *pPt, bool )
464 {
465     SwMvContext aMvContext(this);
466     if( IsTableMode() )
467         return;
468 
469     // Bug 66823: actual crsr has in additional mode no selection?
470     // Then destroy the actual and go to prev, this will be expand
471     if( !HasMark() && GoPrevCursor() )
472     {
473         bool bHasMark = HasMark(); // that's wrong!
474         GoNextCursor();
475         if( bHasMark )
476         {
477             DestroyCursor();
478             GoPrevCursor();
479         }
480     }
481 
482     // check the direction of the selection with the new point
483     bool bMoveCursor = true, bToTop = false;
484     SwCursorShell::SelectWord( &m_aStart );     // select the startword
485     SwCursorShell::Push();                    // save the cursor
486     SwCursorShell::SetCursor( *pPt );           // and check the direction
487 
488     switch( SwCursorShell::CompareCursorStackMkCurrPt())
489     {
490     case -1:    bToTop = false;     break;
491     case 1:     bToTop = true;      break;
492     default:    bMoveCursor = false;  break;
493     }
494 
495     SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent); // restore the saved cursor
496 
497     if( !bMoveCursor )
498         return;
499 
500     // select to Top but cursor select to Bottom? or
501     // select to Bottom but cursor select to Top?       --> swap the cursor
502     if( bToTop )
503         SwapPam();
504 
505     SwCursorShell::Push();                // save cur cursor
506     if( SwCursorShell::SelectWord( pPt )) // select the current word
507     {
508         if( bToTop )
509             SwapPam();
510         Combine();
511     }
512     else
513     {
514         SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
515         if( bToTop )
516             SwapPam();
517     }
518 }
519 
ExtSelLn(const Point * pPt,bool)520 void SwWrtShell::ExtSelLn(const Point *pPt, bool )
521 {
522     SwMvContext aMvContext(this);
523     SwCursorShell::SetCursor(*pPt);
524     if( IsTableMode() )
525         return;
526 
527     // Bug 66823: actual crsr has in additional mode no selection?
528     // Then destroy the actual and go to prev, this will be expand
529     if( !HasMark() && GoPrevCursor() )
530     {
531         bool bHasMark = HasMark(); // that's wrong!
532         GoNextCursor();
533         if( bHasMark )
534         {
535             DestroyCursor();
536             GoPrevCursor();
537         }
538     }
539 
540     // if applicable fit the selection to the "Mark"
541     bool bToTop = !IsCursorPtAtEnd();
542     SwapPam();
543 
544     // The "Mark" has to be at the end or the beginning of the line.
545     if( bToTop ? !IsEndSentence() : !IsStartSentence() )
546     {
547         if( bToTop )
548         {
549             if( !IsEndPara() )
550                 SwCursorShell::Right(1,SwCursorSkipMode::Chars);
551             SwCursorShell::GoEndSentence();
552         }
553         else
554             SwCursorShell::GoStartSentence();
555     }
556     SwapPam();
557 
558     if (bToTop)
559         SwCursorShell::GoStartSentence();
560     else
561         SwCursorShell::GoEndSentence();
562 }
563 
564 // Back into the standard mode: no mode, no selections.
565 
EnterStdMode()566 void SwWrtShell::EnterStdMode()
567 {
568     if(m_bAddMode)
569         LeaveAddMode();
570     if(m_bBlockMode)
571         LeaveBlockMode();
572     m_bBlockMode = false;
573     m_bExtMode = false;
574     m_bInSelect = false;
575     if(IsSelFrameMode())
576     {
577         UnSelectFrame();
578         LeaveSelFrameMode();
579     }
580     else
581     {
582         // SwActContext opens and action which has to be
583         // closed prior to the call of
584         // GetChgLnk().Call()
585         SwActContext aActContext(this);
586         m_bSelWrd = m_bSelLn = false;
587         if( !IsRetainSelection() )
588             KillPams();
589         ClearMark();
590         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
591         m_fnKillSel = &SwWrtShell::ResetSelect;
592     }
593     Invalidate();
594     SwTransferable::ClearSelection( *this );
595 }
596 
AssureStdMode()597 void SwWrtShell::AssureStdMode()
598 {
599     // deselect any drawing or frame and leave editing mode
600     if (SdrView* pSdrView = GetDrawView())
601     {
602         if (pSdrView->IsTextEdit())
603         {
604             bool bLockView = IsViewLocked();
605             LockView(true);
606             EndTextEdit();
607             LockView(bLockView);
608         }
609         // go out of the frame
610         Point aPt(LONG_MIN, LONG_MIN);
611         SelectObj(aPt, SW_LEAVE_FRAME);
612     }
613     if (IsSelFrameMode() || GetSelectedObjCount())
614     {
615         UnSelectFrame();
616         LeaveSelFrameMode();
617         GetView().LeaveDrawCreate();
618         EnterStdMode();
619         DrawSelChanged();
620         GetView().StopShellTimer();
621     }
622     else
623         EnterStdMode();
624 }
625 
626 // Extended Mode
627 
EnterExtMode()628 void SwWrtShell::EnterExtMode()
629 {
630     if(m_bBlockMode)
631     {
632         LeaveBlockMode();
633         KillPams();
634         ClearMark();
635     }
636     m_bExtMode = true;
637     m_bAddMode = false;
638     m_bBlockMode = false;
639     SttSelect();
640 }
641 
LeaveExtMode()642 void SwWrtShell::LeaveExtMode()
643 {
644     m_bExtMode = false;
645     EndSelect();
646 }
647 
648 // End of a selection; if the selection is empty,
649 // ClearMark().
650 
SttLeaveSelect()651 void SwWrtShell::SttLeaveSelect()
652 {
653     if(SwCursorShell::HasSelection() && !IsSelTableCells() && m_bClearMark) {
654         return;
655     }
656     ClearMark();
657 }
658 
659 // Leaving of the selection mode in additional mode
660 
AddLeaveSelect()661 void SwWrtShell::AddLeaveSelect()
662 {
663     if(IsTableMode()) LeaveAddMode();
664     else if(SwCursorShell::HasSelection())
665         CreateCursor();
666 }
667 
668 // Additional Mode
669 
EnterAddMode()670 void SwWrtShell::EnterAddMode()
671 {
672     if(IsTableMode()) return;
673     if(m_bBlockMode)
674         LeaveBlockMode();
675     m_fnSetCursor = &SwWrtShell::SetCursor;
676     m_bAddMode = true;
677     m_bBlockMode = false;
678     m_bExtMode = false;
679     if(SwCursorShell::HasSelection())
680         CreateCursor();
681     Invalidate();
682 }
683 
LeaveAddMode()684 void SwWrtShell::LeaveAddMode()
685 {
686     m_fnKillSel = &SwWrtShell::ResetSelect;
687     m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
688     m_bAddMode = false;
689     Invalidate();
690 }
691 
692 // Block Mode
693 
EnterBlockMode()694 void SwWrtShell::EnterBlockMode()
695 {
696     m_bBlockMode = false;
697     EnterStdMode();
698     m_bBlockMode = true;
699     CursorToBlockCursor();
700     Invalidate();
701 }
702 
LeaveBlockMode()703 void SwWrtShell::LeaveBlockMode()
704 {
705     m_bBlockMode = false;
706     BlockCursorToCursor();
707     EndSelect();
708     Invalidate();
709 }
710 
711 // Insert mode
712 
ImplSetInsMode(bool bOn)713 void SwWrtShell::ImplSetInsMode(bool bOn)
714 {
715     m_bIns = bOn;
716     SwCursorShell::SetOverwriteCursor( !m_bIns );
717     const SfxBoolItem aTmp( SID_ATTR_INSERT, m_bIns );
718     GetView().GetViewFrame().GetBindings().SetState( aTmp );
719     StartAction();
720     EndAction();
721     Invalidate();
722 }
723 
SetInsMode(bool bOn)724 void SwWrtShell::SetInsMode( bool bOn )
725 {
726     const bool bDoAsk = officecfg::Office::Common::Misc::QuerySetInsMode::get();
727     if (!bOn && bDoAsk)
728     {
729         VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
730         auto pDlg = pFact->CreateQueryDialog(
731             GetView().GetFrameWeld(), SwResId(STR_QUERY_INSMODE_TITLE),
732             SwResId(STR_QUERY_INSMODE_TEXT), SwResId(STR_QUERY_INSMODE_QUESTION), true);
733         pDlg->StartExecuteAsync( [this, pDlg] (sal_Int32 nResult)->void
734         {
735             if (pDlg->ShowAgain() == false)
736             {
737                 std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
738                     comphelper::ConfigurationChanges::create());
739                 officecfg::Office::Common::Misc::QuerySetInsMode::set(false, xChanges);
740                 xChanges->commit();
741             }
742             if (nResult == RET_YES)
743                 ImplSetInsMode(false);
744             pDlg->disposeOnce();
745         });
746         return;
747     }
748     ImplSetInsMode(bOn);
749 }
750 
751 //Overwrite mode is incompatible with red-lining
SetRedlineFlagsAndCheckInsMode(RedlineFlags eMode,SfxRedlineRecordingMode eRedlineRecordingMode)752 void SwWrtShell::SetRedlineFlagsAndCheckInsMode( RedlineFlags eMode, SfxRedlineRecordingMode eRedlineRecordingMode )
753 {
754    SetRedlineFlags( eMode, eRedlineRecordingMode );
755    if (IsRedlineOn())
756        SetInsMode();
757 }
758 
759 // Edit frame
760 
BeginFrameDrag(const Point * pPt,bool bIsShift)761 void SwWrtShell::BeginFrameDrag(const Point *pPt, bool bIsShift)
762 {
763     m_fnDrag = &SwFEShell::Drag;
764     if(bStartDrag)
765     {
766         Point aTmp( nStartDragX, nStartDragY );
767         SwFEShell::BeginDrag( &aTmp, bIsShift );
768     }
769     else
770         SwFEShell::BeginDrag( pPt, bIsShift );
771 }
772 
EnterSelFrameMode(const Point * pPos)773 void SwWrtShell::EnterSelFrameMode(const Point *pPos)
774 {
775     if(pPos)
776     {
777         nStartDragX = pPos->X();
778         nStartDragY = pPos->Y();
779         bStartDrag = true;
780     }
781     m_bLayoutMode = true;
782     HideCursor();
783 
784         // equal call of BeginDrag in the SwFEShell
785     m_fnDrag          = &SwWrtShell::BeginFrameDrag;
786     m_fnEndDrag       = &SwWrtShell::UpdateLayoutFrame;
787     SwBaseShell::SetFrameMode( FLY_DRAG_START, this );
788     Invalidate();
789 }
790 
LeaveSelFrameMode()791 void SwWrtShell::LeaveSelFrameMode()
792 {
793     m_fnDrag          = &SwWrtShell::BeginDrag;
794     m_fnEndDrag       = &SwWrtShell::DefaultEndDrag;
795     m_bLayoutMode = false;
796     bStartDrag = false;
797     Edit();
798     SwBaseShell::SetFrameMode( FLY_DRAG_END, this );
799     Invalidate();
800 }
801 
802 // Description: execute framebound macro
803 
IMPL_LINK(SwWrtShell,ExecFlyMac,const SwFlyFrameFormat *,pFlyFormat,void)804 IMPL_LINK( SwWrtShell, ExecFlyMac, const SwFlyFrameFormat*, pFlyFormat, void )
805 {
806     const SwFrameFormat *pFormat = pFlyFormat ? static_cast<const SwFrameFormat*>(pFlyFormat) : GetFlyFrameFormat();
807     assert(pFormat && "no frame format");
808     const SvxMacroItem &rFormatMac = pFormat->GetMacro();
809 
810     if(rFormatMac.HasMacro(SvMacroItemId::SwObjectSelect))
811     {
812         const SvxMacro &rMac = rFormatMac.GetMacro(SvMacroItemId::SwObjectSelect);
813         if( IsFrameSelected() )
814             m_bLayoutMode = true;
815         CallChgLnk();
816         ExecMacro( rMac );
817     }
818 }
819 
UpdateLayoutFrame(const Point *,bool)820 void SwWrtShell::UpdateLayoutFrame(const Point *, bool )
821 {
822         // still a dummy
823     SwFEShell::EndDrag();
824     m_fnDrag = &SwWrtShell::BeginFrameDrag;
825 }
826 
827 // Handler for toggling the modes. Returns back the old mode.
828 
ToggleAddMode()829 void SwWrtShell::ToggleAddMode()
830 {
831     m_bAddMode ? LeaveAddMode(): EnterAddMode();
832     Invalidate();
833 }
834 
ToggleBlockMode()835 void SwWrtShell::ToggleBlockMode()
836 {
837     m_bBlockMode ? LeaveBlockMode(): EnterBlockMode();
838     Invalidate();
839 }
840 
ToggleExtMode()841 void SwWrtShell::ToggleExtMode()
842 {
843     m_bExtMode ? LeaveExtMode() : EnterExtMode();
844     Invalidate();
845 }
846 
847 // Dragging in standard mode (Selecting of content)
848 
BeginDrag(const Point *,bool)849 void SwWrtShell::BeginDrag(const Point * /*pPt*/, bool )
850 {
851     if(m_bSelWrd)
852     {
853         m_bInSelect = true;
854         if( !IsCursorPtAtEnd() )
855             SwapPam();
856 
857         m_fnDrag = &SwWrtShell::ExtSelWrd;
858         m_fnSetCursor = &SwWrtShell::Ignore;
859     }
860     else if(m_bSelLn)
861     {
862         m_bInSelect = true;
863         m_fnDrag = &SwWrtShell::ExtSelLn;
864         m_fnSetCursor = &SwWrtShell::Ignore;
865     }
866     else
867     {
868         m_fnDrag = &SwWrtShell::DefaultDrag;
869         SttSelect();
870     }
871 }
872 
DefaultDrag(const Point *,bool)873 void SwWrtShell::DefaultDrag(const Point *, bool )
874 {
875     if( IsSelTableCells() )
876         m_aSelTableLink.Call(*this);
877 }
878 
DefaultEndDrag(const Point *,bool)879 void SwWrtShell::DefaultEndDrag(const Point * /*pPt*/, bool )
880 {
881     m_fnDrag = &SwWrtShell::BeginDrag;
882     if( IsExtSel() )
883         LeaveExtSel();
884 
885     if( IsSelTableCells() )
886         m_aSelTableLink.Call(*this);
887     EndSelect();
888 }
889 
890 // #i32329# Enhanced table selection
SelectTableRowCol(const Point & rPt,const Point * pEnd,bool bRowDrag)891 bool SwWrtShell::SelectTableRowCol( const Point& rPt, const Point* pEnd, bool bRowDrag )
892 {
893     SwMvContext aMvContext(this);
894     SttSelect();
895     if(SelTableRowCol( rPt, pEnd, bRowDrag ))
896     {
897         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
898         m_fnKillSel = &SwWrtShell::ResetSelect;
899         return true;
900     }
901     return false;
902 }
903 
904 // Description: Selection of a table line or column
905 
SelectTableRow()906 void SwWrtShell::SelectTableRow()
907 {
908     if ( SelTableRow() )
909     {
910         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
911         m_fnKillSel = &SwWrtShell::ResetSelect;
912     }
913 }
914 
SelectTableCol()915 void SwWrtShell::SelectTableCol()
916 {
917     if ( SelTableCol() )
918     {
919         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
920         m_fnKillSel = &SwWrtShell::ResetSelect;
921     }
922 }
923 
SelectTableCell()924 void SwWrtShell::SelectTableCell()
925 {
926     if ( SelTableBox() )
927     {
928         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
929         m_fnKillSel = &SwWrtShell::ResetSelect;
930     }
931 }
932 
933 // Description: Check if a word selection is present.
934 //              According to the rules for intelligent cut / paste
935 //              surrounding spaces are cut out.
936 // Return:      Delivers the type of the word selection.
937 
IntelligentCut(SelectionType nSelection,bool bCut)938 int SwWrtShell::IntelligentCut(SelectionType nSelection, bool bCut)
939 {
940         // On multiple selection no intelligent drag and drop
941         // there are multiple cursors, since a second was placed
942         // already at the target position.
943     if( IsAddMode() || !(nSelection & SelectionType::Text) )
944         return NO_WORD;
945 
946     OUString sText;
947     CharClass& rCC = GetAppCharClass();
948 
949         // If the first character is no word character,
950         // no word selected.
951     sal_Unicode cPrev = GetChar(false);
952     sal_Unicode cNext = GetChar(true, -1);
953     if( !cPrev || !cNext ||
954         !rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) ||
955         !rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
956         return NO_WORD;
957 
958     cPrev = GetChar(false, -1);
959     cNext = GetChar();
960 
961     int cWord = NO_WORD;
962         // is a word selected?
963     if (cPrev && cNext &&
964         CH_TXTATR_BREAKWORD != cPrev && CH_TXTATR_INWORD != cPrev &&
965         CH_TXTATR_BREAKWORD != cNext && CH_TXTATR_INWORD != cNext &&
966         !rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) &&
967         !rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
968        cWord = WORD_NO_SPACE;
969 
970     if(cWord == WORD_NO_SPACE && ' ' == cPrev )
971     {
972         cWord = WORD_SPACE_BEFORE;
973             // delete the space before
974         if(bCut)
975         {
976             Push();
977             if(IsCursorPtAtEnd())
978                 SwapPam();
979             ClearMark();
980             SetMark();
981             SwCursorShell::Left(1,SwCursorSkipMode::Chars);
982             SwFEShell::Delete(true);
983             Pop(SwCursorShell::PopMode::DeleteCurrent);
984         }
985     }
986     else if(cWord == WORD_NO_SPACE && cNext == ' ')
987     {
988         cWord = WORD_SPACE_AFTER;
989             // delete the space behind
990         if(bCut) {
991             Push();
992             if(!IsCursorPtAtEnd()) SwapPam();
993             ClearMark();
994             SetMark();
995             SwCursorShell::Right(1,SwCursorSkipMode::Chars);
996             SwFEShell::Delete(true);
997             Pop(SwCursorShell::PopMode::DeleteCurrent);
998         }
999     }
1000     return cWord;
1001 }
1002 
1003     // jump to the next / previous hyperlink - inside text and also
1004     // on graphics
SelectNextPrevHyperlink(bool bNext)1005 void SwWrtShell::SelectNextPrevHyperlink( bool bNext )
1006 {
1007     StartAction();
1008     bool bRet = SwCursorShell::SelectNxtPrvHyperlink( bNext );
1009     if( !bRet ) // didn't find? wrap and check again
1010     {
1011         SwShellCursor* pCursor = GetCursor_();
1012         SwCursorSaveState aSaveState(*pCursor);
1013         EnterStdMode();
1014         if( bNext )
1015             SttEndDoc(true);
1016         else
1017             SttEndDoc(false);
1018         bRet = SwCursorShell::SelectNxtPrvHyperlink(bNext);
1019         if (!bRet) // didn't find again? restore cursor position and bail
1020         {
1021             pCursor->RestoreSavePos();
1022             EndAction(true); // don't scroll to restored cursor position
1023             return;
1024         }
1025     }
1026     EndAction();
1027 
1028     bool bCreateXSelection = false;
1029     const bool bFrameSelected = IsFrameSelected() || GetSelectedObjCount();
1030     if( IsSelection() )
1031     {
1032         if ( bFrameSelected )
1033             UnSelectFrame();
1034 
1035         // Set the function pointer for the canceling of the selection
1036         // set at cursor
1037         m_fnKillSel = &SwWrtShell::ResetSelect;
1038         m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
1039         bCreateXSelection = true;
1040     }
1041     else if( bFrameSelected )
1042     {
1043         EnterSelFrameMode();
1044         bCreateXSelection = true;
1045     }
1046     else if( (CNT_GRF | CNT_OLE ) & GetCntType() )
1047     {
1048         SelectObj( GetCharRect().Pos() );
1049         EnterSelFrameMode();
1050         bCreateXSelection = true;
1051     }
1052 
1053     if( bCreateXSelection )
1054         SwTransferable::CreateSelection( *this );
1055 }
1056 
1057 // For the preservation of the selection the cursor will be moved left
1058 // after SetMark(), so that the cursor is not moved by inserting text.
1059 // Because a present selection at the CORE page is cleared at the
1060 // current cursor position, the cursor will be pushed on the stack.
1061 // After moving, they will again resummarized.
1062 
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1064