Coverage Report

Created: 2025-11-16 09:57

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