Coverage Report

Created: 2026-09-28 10:59

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