Coverage Report

Created: 2025-12-31 10:39

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