Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/undo/undobase.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 <utility>
21
#include <vcl/virdev.hxx>
22
#include <svx/svdundo.hxx>
23
24
#include <undobase.hxx>
25
#include <refundo.hxx>
26
#include <docsh.hxx>
27
#include <tabvwsh.hxx>
28
#include <undoolk.hxx>
29
#include <undodraw.hxx>
30
#include <dbdata.hxx>
31
#include <attrib.hxx>
32
#include <queryparam.hxx>
33
#include <subtotalparam.hxx>
34
#include <rowheightcontext.hxx>
35
#include <column.hxx>
36
#include <sortparam.hxx>
37
#include <columnspanset.hxx>
38
#include <undomanager.hxx>
39
#include <sizedev.hxx>
40
41
42
ScSimpleUndo::ScSimpleUndo( ScDocShell& rDocSh ) :
43
100
    rDocShell( rDocSh ),
44
100
    mnViewShellId(-1)
45
100
{
46
100
    if (ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell())
47
0
        mnViewShellId = pViewShell->GetViewShellId();
48
100
}
49
50
ViewShellId ScSimpleUndo::GetViewShellId() const
51
0
{
52
0
    return mnViewShellId;
53
0
}
54
55
bool ScSimpleUndo::SetViewMarkData( const ScMarkData& rMarkData )
56
0
{
57
0
    if ( IsPaintLocked() )
58
0
        return false;
59
60
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
61
0
    if ( !pViewShell )
62
0
        return false;
63
64
0
    pViewShell->SetMarkData( rMarkData );
65
0
    return true;
66
0
}
67
68
bool ScSimpleUndo::Merge( SfxUndoAction *pNextAction )
69
0
{
70
    // A SdrUndoGroup for updating detective arrows can belong
71
    // to each Undo-Action.
72
    // DetectiveRefresh is always called next,
73
    // the SdrUndoGroup is encapsulated in a ScUndoDraw action.
74
    // AddUndoAction is only called with bTryMerg=sal_True
75
    // for automatic update.
76
77
0
    if ( !pDetectiveUndo && dynamic_cast<const ScUndoDraw*>( pNextAction) !=  nullptr )
78
0
    {
79
        // Take SdrUndoAction from ScUndoDraw Action,
80
        // ScUndoDraw is later deleted by the UndoManager
81
82
0
        ScUndoDraw* pCalcUndo = static_cast<ScUndoDraw*>(pNextAction);
83
0
        pDetectiveUndo = pCalcUndo->ReleaseDrawUndo();
84
0
        return true;
85
0
    }
86
87
0
    return false;
88
0
}
89
90
void ScSimpleUndo::BeginUndo()
91
0
{
92
0
    rDocShell.SetInUndo( true );
93
94
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
95
0
    if (pViewShell)
96
0
        pViewShell->HideAllCursors();       // for example due to merged cells
97
98
    //  detective updates happened last, must be undone first
99
0
    if (pDetectiveUndo)
100
0
        pDetectiveUndo->Undo();
101
0
}
102
103
namespace
104
{
105
    class DisableUndoGuard
106
    {
107
    private:
108
        ScDocument& m_rDoc;
109
        bool m_bUndoEnabled;
110
    public:
111
        explicit DisableUndoGuard(ScDocShell& rDocShell)
112
0
            : m_rDoc(rDocShell.GetDocument())
113
0
            , m_bUndoEnabled(m_rDoc.IsUndoEnabled())
114
0
        {
115
0
            m_rDoc.EnableUndo(false);
116
0
        }
117
118
        ~DisableUndoGuard()
119
0
        {
120
0
            m_rDoc.EnableUndo(m_bUndoEnabled);
121
0
        }
122
    };
123
}
124
125
void ScSimpleUndo::EndUndo()
126
0
{
127
    // After undo we need to restore the sheet views as well.
128
0
    SyncSheetViews();
129
130
0
    {
131
        // rhbz#1352881 Temporarily turn off undo generation during
132
        // SetDocumentModified
133
0
        DisableUndoGuard aGuard(rDocShell);
134
0
        rDocShell.SetDocumentModified();
135
0
    }
136
137
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
138
0
    if (pViewShell)
139
0
    {
140
0
        pViewShell->UpdateAutoFillMark();
141
0
        pViewShell->UpdateInputHandler();
142
0
        pViewShell->ShowAllCursors();
143
0
    }
144
145
0
    rDocShell.SetInUndo( false );
146
0
}
147
148
void ScSimpleUndo::BeginRedo()
149
0
{
150
0
    rDocShell.SetInUndo( true );   //! own Flag for Redo?
151
152
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
153
0
    if (pViewShell)
154
0
        pViewShell->HideAllCursors();       // for example due to merged cells
155
0
}
156
157
void ScSimpleUndo::EndRedo()
158
0
{
159
0
    if (pDetectiveUndo)
160
0
        pDetectiveUndo->Redo();
161
162
    // After redo we need to restore the sheet views as well.
163
0
    SyncSheetViews();
164
165
0
    {
166
        // rhbz#1352881 Temporarily turn off undo generation during
167
        // SetDocumentModified
168
0
        DisableUndoGuard aGuard(rDocShell);
169
0
        rDocShell.SetDocumentModified();
170
0
    }
171
172
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
173
0
    if (pViewShell)
174
0
    {
175
0
        pViewShell->UpdateAutoFillMark();
176
0
        pViewShell->UpdateInputHandler();
177
0
        pViewShell->ShowAllCursors();
178
0
    }
179
180
0
    rDocShell.SetInUndo( false );
181
0
}
182
183
void ScSimpleUndo::SyncSheetViews()
184
0
{
185
0
    ScViewData* pViewData = ScDocShell::GetViewData();
186
0
    if (!pViewData)
187
0
        return;
188
189
0
    ScDocument& rDocument = rDocShell.GetDocument();
190
0
    SCTAB nDefaultViewTable = rDocument.GetDefaultViewTableNumber(pViewData->GetTabNumber());
191
0
    rDocument.SyncSheetViews(nDefaultViewTable);
192
0
}
193
194
void ScSimpleUndo::BroadcastChanges( const ScRange& rRange )
195
0
{
196
0
    ScDocument& rDoc = rDocShell.GetDocument();
197
0
    rDoc.BroadcastCells(rRange, SfxHintId::ScDataChanged);
198
0
}
199
200
namespace {
201
202
class SpanBroadcaster : public sc::ColumnSpanSet::ColumnAction
203
{
204
    ScDocument& mrDoc;
205
    SCTAB mnCurTab;
206
    SCCOL mnCurCol;
207
208
public:
209
0
    explicit SpanBroadcaster( ScDocument& rDoc ) : mrDoc(rDoc), mnCurTab(-1), mnCurCol(-1) {}
210
211
    virtual void startColumn( ScColumn* pCol ) override
212
0
    {
213
0
        mnCurTab = pCol->GetTab();
214
0
        mnCurCol = pCol->GetCol();
215
0
    }
216
217
    virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
218
0
    {
219
0
        if (!bVal)
220
0
            return;
221
222
0
        ScRange aRange(mnCurCol, nRow1, mnCurTab, mnCurCol, nRow2, mnCurTab);
223
0
        mrDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
224
0
    };
225
};
226
227
}
228
229
void ScSimpleUndo::BroadcastChanges( const DataSpansType& rSpans )
230
0
{
231
0
    ScDocument& rDoc = rDocShell.GetDocument();
232
0
    SpanBroadcaster aBroadcaster(rDoc);
233
234
0
    for (const auto& rEntry : rSpans)
235
0
    {
236
0
        const sc::ColumnSpanSet& rSet = *rEntry.second;
237
0
        rSet.executeColumnAction(rDoc, aBroadcaster);
238
0
    }
239
0
}
240
241
void ScSimpleUndo::ShowTable( SCTAB nTab )
242
0
{
243
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
244
0
    if (pViewShell)
245
0
        pViewShell->SetTabNo( nTab );
246
0
}
247
248
void ScSimpleUndo::ShowTable( const ScRange& rRange )
249
0
{
250
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
251
0
    if (pViewShell)
252
0
    {
253
0
        SCTAB nStart = rRange.aStart.Tab();
254
0
        SCTAB nEnd   = rRange.aEnd.Tab();
255
0
        SCTAB nTab = pViewShell->GetViewData().GetTabNumber();
256
0
        if ( nTab < nStart || nTab > nEnd )                     // if not in range:
257
0
            pViewShell->SetTabNo( nStart );                     // at beginning of the range
258
0
    }
259
0
}
260
261
ScBlockUndo::ScBlockUndo( ScDocShell& rDocSh, const ScRange& rRange,
262
                                            ScBlockUndoMode eBlockMode ) :
263
0
    ScSimpleUndo( rDocSh ),
264
0
    aBlockRange( rRange ),
265
0
    eMode( eBlockMode )
266
0
{
267
0
    pDrawUndo = GetSdrUndoAction( &rDocShell.GetDocument() );
268
0
}
269
270
ScBlockUndo::~ScBlockUndo()
271
0
{
272
0
    pDrawUndo.reset();
273
0
}
274
275
void ScBlockUndo::BeginUndo()
276
0
{
277
0
    ScSimpleUndo::BeginUndo();
278
0
    EnableDrawAdjust( &rDocShell.GetDocument(), false );
279
0
}
280
281
void ScBlockUndo::EndUndo()
282
0
{
283
0
    if (eMode == SC_UNDO_AUTOHEIGHT)
284
0
        AdjustHeight();
285
286
0
    EnableDrawAdjust( &rDocShell.GetDocument(), true );
287
0
    DoSdrUndoAction( pDrawUndo.get(), &rDocShell.GetDocument() );
288
289
    // tdf#161712 invoke ScSimpleUndo::EndUndo() before ShowBlock()
290
    // If this is an instance of ScUndoAutoFill, ShowBlock() will invoke
291
    // ScTabViewShell::MoveCursorAbs() which will delete this instance
292
    // so invoke ScSimpleUndo::EndUndo() first.
293
0
    ScSimpleUndo::EndUndo();
294
0
    ShowBlock();
295
0
}
296
297
void ScBlockUndo::EndRedo()
298
0
{
299
0
    if (eMode == SC_UNDO_AUTOHEIGHT)
300
0
        AdjustHeight();
301
302
0
    ShowBlock();
303
0
    ScSimpleUndo::EndRedo();
304
0
}
305
306
bool ScBlockUndo::AdjustHeight()
307
0
{
308
0
    ScDocument& rDoc = rDocShell.GetDocument();
309
310
0
    ScSizeDeviceProvider aProv(rDocShell);
311
0
    double fZoomX( 1.0 );
312
0
    double fZoomY = fZoomX;
313
0
    double nPPTX, nPPTY;
314
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
315
0
    if (pViewShell)
316
0
    {
317
0
        if (aProv.IsPrinter())
318
0
        {
319
0
            nPPTX = aProv.GetPPTX();
320
0
            nPPTY = aProv.GetPPTY();
321
0
        }
322
0
        else
323
0
        {
324
0
            ScViewData& rData = pViewShell->GetViewData();
325
0
            nPPTX = rData.GetPPTX();
326
0
            nPPTY = rData.GetPPTY();
327
0
            fZoomX = rData.GetZoomX();
328
0
            fZoomY = rData.GetZoomY();
329
0
        }
330
0
    }
331
0
    else
332
0
    {
333
        // Leave zoom at 100
334
0
        nPPTX = ScGlobal::nScreenPPTX;
335
0
        nPPTY = ScGlobal::nScreenPPTY;
336
0
    }
337
338
0
    sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, fZoomX, fZoomY, aProv.GetDevice());
339
0
    bool bRet = rDoc.SetOptimalHeight(
340
0
        aCxt, aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(), aBlockRange.aStart.Tab(), true);
341
342
0
    if (bRet)
343
0
    {
344
        // tdf#76183: recalculate objects' positions
345
0
        rDoc.SetDrawPageSize(aBlockRange.aStart.Tab());
346
347
0
        rDocShell.PostPaint( 0,      aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(),
348
0
                              rDoc.MaxCol(), rDoc.MaxRow(),                   aBlockRange.aEnd.Tab(),
349
0
                              PaintPartFlags::Grid | PaintPartFlags::Left );
350
0
    }
351
0
    return bRet;
352
0
}
353
354
void ScBlockUndo::ShowBlock()
355
0
{
356
0
    if ( IsPaintLocked() )
357
0
        return;
358
359
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
360
0
    if (!pViewShell)
361
0
        return;
362
363
0
    ShowTable( aBlockRange );       // with multiple sheets in range each of them is good
364
0
    pViewShell->MoveCursorAbs( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
365
0
                               SC_FOLLOW_JUMP, false, false );
366
0
    SCTAB nTab = pViewShell->GetViewData().GetTabNumber();
367
0
    ScRange aRange = aBlockRange;
368
0
    aRange.aStart.SetTab( nTab );
369
0
    aRange.aEnd.SetTab( nTab );
370
0
    pViewShell->MarkRange( aRange );
371
372
    // not through SetMarkArea to MarkData, due to possibly lacking paint
373
0
}
374
375
ScMultiBlockUndo::ScMultiBlockUndo(
376
    ScDocShell& rDocSh, ScRangeList aRanges) :
377
0
    ScSimpleUndo(rDocSh),
378
0
    maBlockRanges(std::move(aRanges))
379
0
{
380
0
    mpDrawUndo = GetSdrUndoAction( &rDocShell.GetDocument() );
381
0
}
382
383
ScMultiBlockUndo::~ScMultiBlockUndo()
384
0
{
385
0
    mpDrawUndo.reset();
386
0
}
387
388
void ScMultiBlockUndo::BeginUndo()
389
0
{
390
0
    ScSimpleUndo::BeginUndo();
391
0
    EnableDrawAdjust(&rDocShell.GetDocument(), false);
392
0
}
393
394
void ScMultiBlockUndo::EndUndo()
395
0
{
396
0
    EnableDrawAdjust(&rDocShell.GetDocument(), true);
397
0
    DoSdrUndoAction(mpDrawUndo.get(), &rDocShell.GetDocument());
398
399
0
    ShowBlock();
400
0
    ScSimpleUndo::EndUndo();
401
0
}
402
403
void ScMultiBlockUndo::EndRedo()
404
0
{
405
0
    ShowBlock();
406
0
    ScSimpleUndo::EndRedo();
407
0
}
408
409
void ScMultiBlockUndo::ShowBlock()
410
0
{
411
0
    if ( IsPaintLocked() )
412
0
        return;
413
414
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
415
0
    if (!pViewShell)
416
0
        return;
417
418
0
    if (maBlockRanges.empty())
419
0
        return;
420
421
    // Move to the sheet of the first range.
422
0
    ScRange aRange = maBlockRanges.front();
423
0
    ShowTable(aRange);
424
0
    pViewShell->MoveCursorAbs(
425
0
        aRange.aStart.Col(), aRange.aStart.Row(), SC_FOLLOW_JUMP, false, false);
426
0
    SCTAB nTab = pViewShell->GetViewData().GetTabNumber();
427
0
    aRange.aStart.SetTab(nTab);
428
0
    aRange.aEnd.SetTab(nTab);
429
0
    pViewShell->MarkRange(aRange, false);
430
431
0
    for (size_t i = 1, n = maBlockRanges.size(); i < n; ++i)
432
0
    {
433
0
        aRange = maBlockRanges[i];
434
0
        aRange.aStart.SetTab(nTab);
435
0
        aRange.aEnd.SetTab(nTab);
436
0
        pViewShell->MarkRange(aRange, false, true);
437
0
    }
438
0
}
439
440
ScMoveUndo::ScMoveUndo( ScDocShell& rDocSh, ScDocumentUniquePtr pRefDoc, std::unique_ptr<ScRefUndoData> pRefData ) :
441
0
    ScSimpleUndo( rDocSh ),
442
0
    pRefUndoDoc( std::move(pRefDoc) ),
443
0
    pRefUndoData( std::move(pRefData) )
444
0
{
445
0
    ScDocument& rDoc = rDocShell.GetDocument();
446
0
    if (pRefUndoData)
447
0
        pRefUndoData->DeleteUnchanged(rDoc);
448
0
    pDrawUndo = GetSdrUndoAction( &rDoc );
449
0
}
450
451
ScMoveUndo::~ScMoveUndo()
452
0
{
453
0
    pRefUndoData.reset();
454
0
    pRefUndoDoc.reset();
455
0
    pDrawUndo.reset();
456
0
}
457
458
void ScMoveUndo::UndoRef()
459
0
{
460
0
    ScDocument& rDoc = rDocShell.GetDocument();
461
0
    ScRange aRange(0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),pRefUndoDoc->GetTableCount()-1);
462
0
    pRefUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::FORMULA, false, rDoc, nullptr, false);
463
0
    if (pRefUndoData)
464
0
        pRefUndoData->DoUndo( rDoc, false );
465
0
}
466
467
void ScMoveUndo::BeginUndo()
468
0
{
469
0
    ScSimpleUndo::BeginUndo();
470
471
0
    EnableDrawAdjust( &rDocShell.GetDocument(), false );
472
0
}
473
474
void ScMoveUndo::EndUndo()
475
0
{
476
0
    DoSdrUndoAction( pDrawUndo.get(), &rDocShell.GetDocument() );     // must also be called when pointer is null
477
478
0
    if (pRefUndoDoc)
479
0
        UndoRef();
480
481
0
    EnableDrawAdjust( &rDocShell.GetDocument(), true );
482
483
0
    ScSimpleUndo::EndUndo();
484
0
}
485
486
ScDBFuncUndo::ScDBFuncUndo( ScDocShell& rDocSh, const ScRange& rOriginal ) :
487
0
    ScSimpleUndo( rDocSh ),
488
0
    aOriginalRange( rOriginal )
489
0
{
490
0
    pAutoDBRange = rDocSh.GetOldAutoDBRange();
491
0
}
492
493
ScDBFuncUndo::~ScDBFuncUndo()
494
0
{
495
0
    pAutoDBRange.reset();
496
0
}
497
498
void ScDBFuncUndo::BeginUndo()
499
0
{
500
0
    ScSimpleUndo::BeginUndo();
501
0
    DoSdrUndoAction( nullptr, &rDocShell.GetDocument() );
502
0
}
503
504
void ScDBFuncUndo::EndUndo()
505
0
{
506
0
    ScSimpleUndo::EndUndo();
507
508
0
    if ( !pAutoDBRange )
509
0
        return;
510
511
0
    ScDocument& rDoc = rDocShell.GetDocument();
512
0
    SCTAB nTab = rDoc.GetVisibleTab();
513
0
    ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
514
0
    if (!pNoNameData )
515
0
        return;
516
517
0
    SCCOL nRangeX1;
518
0
    SCROW nRangeY1;
519
0
    SCCOL nRangeX2;
520
0
    SCROW nRangeY2;
521
0
    SCTAB nRangeTab;
522
0
    pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
523
0
    rDocShell.DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
524
525
0
    *pNoNameData = *pAutoDBRange;
526
527
0
    if ( pAutoDBRange->HasAutoFilter() )
528
0
    {
529
        // restore AutoFilter buttons
530
0
        pAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
531
0
        rDoc.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
532
0
        rDocShell.PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
533
0
    }
534
0
}
535
536
void ScDBFuncUndo::BeginRedo()
537
0
{
538
0
    RedoSdrUndoAction( nullptr );
539
0
    if ( pAutoDBRange )
540
0
    {
541
        // move the database range to this function's position again (see ScDocShell::GetDBData)
542
543
0
        ScDocument& rDoc = rDocShell.GetDocument();
544
0
        ScDBData* pNoNameData = rDoc.GetAnonymousDBData(aOriginalRange.aStart.Tab());
545
0
        if ( pNoNameData )
546
0
        {
547
548
0
            SCCOL nRangeX1;
549
0
            SCROW nRangeY1;
550
0
            SCCOL nRangeX2;
551
0
            SCROW nRangeY2;
552
0
            SCTAB nRangeTab;
553
0
            pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
554
0
            rDocShell.DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
555
556
0
            pNoNameData->SetSortParam( ScSortParam() );
557
0
            pNoNameData->SetQueryParam( ScQueryParam() );
558
0
            pNoNameData->SetSubTotalParam( ScSubTotalParam() );
559
560
0
            pNoNameData->SetArea( aOriginalRange.aStart.Tab(),
561
0
                                  aOriginalRange.aStart.Col(), aOriginalRange.aStart.Row(),
562
0
                                  aOriginalRange.aEnd.Col(), aOriginalRange.aEnd.Row() );
563
564
0
            pNoNameData->SetByRow( true );
565
0
            pNoNameData->SetAutoFilter( false );
566
            // header is always set with the operation in redo
567
0
        }
568
0
    }
569
570
0
    ScSimpleUndo::BeginRedo();
571
0
}
572
573
void ScDBFuncUndo::EndRedo()
574
0
{
575
0
    ScSimpleUndo::EndRedo();
576
0
}
577
578
ScUndoWrapper::ScUndoWrapper( std::unique_ptr<SfxUndoAction> pUndo ) :
579
0
    pWrappedUndo( std::move(pUndo) ),
580
0
    mnViewShellId( -1 )
581
0
{
582
0
    if (pWrappedUndo)
583
0
        mnViewShellId = pWrappedUndo->GetViewShellId();
584
0
}
585
586
ScUndoWrapper::~ScUndoWrapper()
587
0
{
588
0
}
589
590
OUString ScUndoWrapper::GetComment() const
591
0
{
592
0
    if (pWrappedUndo)
593
0
        return pWrappedUndo->GetComment();
594
0
    return OUString();
595
0
}
596
597
ViewShellId ScUndoWrapper::GetViewShellId() const
598
0
{
599
0
    return mnViewShellId;
600
0
}
601
602
OUString ScUndoWrapper::GetRepeatComment(SfxRepeatTarget& rTarget) const
603
0
{
604
0
    if (pWrappedUndo)
605
0
        return pWrappedUndo->GetRepeatComment(rTarget);
606
0
    return OUString();
607
0
}
608
609
bool ScUndoWrapper::Merge( SfxUndoAction* pNextAction )
610
0
{
611
0
    if (pWrappedUndo)
612
0
        return pWrappedUndo->Merge(pNextAction);
613
0
    else
614
0
        return false;
615
0
}
616
617
void ScUndoWrapper::Undo()
618
0
{
619
0
    if (pWrappedUndo)
620
0
        pWrappedUndo->Undo();
621
0
}
622
623
void ScUndoWrapper::Redo()
624
0
{
625
0
    if (pWrappedUndo)
626
0
        pWrappedUndo->Redo();
627
0
}
628
629
void ScUndoWrapper::Repeat(SfxRepeatTarget& rTarget)
630
0
{
631
0
    if (pWrappedUndo)
632
0
        pWrappedUndo->Repeat(rTarget);
633
0
}
634
635
bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const
636
0
{
637
0
    if (pWrappedUndo)
638
0
        return pWrappedUndo->CanRepeat(rTarget);
639
0
    else
640
0
        return false;
641
0
}
642
643
4.33k
ScUndoManager::~ScUndoManager() {}
644
645
/**
646
 * Checks if the topmost undo action owned by pView is independent from the topmost action undo
647
 * action.
648
 */
649
bool ScUndoManager::IsViewUndoActionIndependent(const SfxViewShell* pView, sal_uInt16& rOffset) const
650
0
{
651
0
    if (GetUndoActionCount() <= 1)
652
0
    {
653
        // Single or less undo, owned by another view.
654
0
        return false;
655
0
    }
656
657
0
    if (!pView)
658
0
    {
659
0
        return false;
660
0
    }
661
662
    // Last undo action that doesn't belong to the view.
663
0
    const SfxUndoAction* pTopAction = GetUndoAction();
664
665
0
    ViewShellId nViewId = pView->GetViewShellId();
666
667
    // Earlier undo action that belongs to the view, but is not the top one.
668
0
    const SfxUndoAction* pViewAction = nullptr;
669
0
    size_t nOffset = 0;
670
0
    for (size_t i = 0; i < GetUndoActionCount(); ++i)
671
0
    {
672
0
        const SfxUndoAction* pAction = GetUndoAction(i);
673
0
        if (pAction->GetViewShellId() == nViewId)
674
0
        {
675
0
            pViewAction = pAction;
676
0
            nOffset = i;
677
0
            break;
678
0
        }
679
0
    }
680
681
0
    if (!pViewAction)
682
0
    {
683
        // Found no earlier undo action that belongs to the view.
684
0
        return false;
685
0
    }
686
687
0
    std::optional<ScRange> topRange = getAffectedRangeFromUndo(pTopAction);
688
0
    if (!topRange)
689
0
        return false;
690
691
0
    std::optional<ScRange> viewRange = getAffectedRangeFromUndo(pViewAction);
692
0
    if (!viewRange)
693
0
        return false;
694
695
0
    if (topRange->Intersects(*viewRange))
696
0
        return false;
697
698
0
    for (size_t i = 0; i < GetRedoActionCount(); ++i)
699
0
    {
700
0
        auto pRedoAction = getScSimpleUndo(GetRedoAction(i));
701
0
        if (!pRedoAction)
702
0
        {
703
0
            return false;
704
0
        }
705
0
        std::optional<ScRange> redoRange = getAffectedRangeFromUndo(pRedoAction);
706
0
        if (!redoRange || (redoRange->Intersects(*viewRange) && pRedoAction->GetViewShellId() != nViewId))
707
0
        {
708
            // Dependent redo action and owned by another view.
709
0
            return false;
710
0
        }
711
0
    }
712
713
0
    rOffset = nOffset;
714
0
    return true;
715
0
}
716
717
std::optional<ScRange> ScUndoManager::getAffectedRangeFromUndo(const SfxUndoAction* pAction)
718
0
{
719
0
    auto pSimpleUndo = getScSimpleUndo(pAction);
720
0
    if (!pSimpleUndo)
721
0
        return std::nullopt;
722
0
    return pSimpleUndo->getAffectedRange();
723
0
}
724
725
const ScSimpleUndo* ScUndoManager::getScSimpleUndo(const SfxUndoAction* pAction)
726
0
{
727
0
    const ScSimpleUndo* pSimpleUndo = dynamic_cast<const ScSimpleUndo*>(pAction);
728
0
    if (pSimpleUndo)
729
0
        return pSimpleUndo;
730
0
    auto pListAction = dynamic_cast<const SfxListUndoAction*>(pAction);
731
0
    if (!pListAction)
732
0
        return nullptr;
733
0
    if (pListAction->maUndoActions.size() > 1)
734
0
        return nullptr;
735
0
    return dynamic_cast<ScSimpleUndo*>(pListAction->maUndoActions[0].pAction.get());
736
0
}
737
738
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */