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