Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/undo/undocell.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 <undocell.hxx>
21
#include <svx/svdundo.hxx>
22
23
#include <scitems.hxx>
24
#include <editeng/editobj.hxx>
25
#include <sfx2/app.hxx>
26
#include <svx/svdocapt.hxx> //
27
#include <comphelper/lok.hxx>
28
#include <osl/diagnose.h>
29
30
#include <document.hxx>
31
#include <patattr.hxx>
32
#include <docsh.hxx>
33
#include <tabvwsh.hxx>
34
#include <globstr.hrc>
35
#include <scresid.hxx>
36
#include <global.hxx>
37
#include <formulacell.hxx>
38
#include <target.hxx>
39
#include <undoolk.hxx>
40
#include <detdata.hxx>
41
#include <stlpool.hxx>
42
#include <printfun.hxx>
43
#include <rangenam.hxx>
44
#include <chgtrack.hxx>
45
#include <stringutil.hxx>
46
#include <utility>
47
48
namespace HelperNotifyChanges
49
{
50
    static void NotifyIfChangesListeners(const ScDocShell& rDocShell, const ScAddress &rPos,
51
        const ScUndoEnterData::ValuesType &rOldValues, const OUString& rType = u"cell-change"_ustr)
52
0
    {
53
0
        ScModelObj* pModelObj = rDocShell.GetModel();
54
0
        if (pModelObj)
55
0
        {
56
0
            ScRangeList aChangeRanges;
57
58
0
            for (const auto & rOldValue : rOldValues)
59
0
            {
60
0
                aChangeRanges.push_back( ScRange(rPos.Col(), rPos.Row(), rOldValue.mnTab));
61
0
            }
62
63
0
            if (getMustPropagateChangesModel(pModelObj))
64
0
                Notify(*pModelObj, aChangeRanges, rType);
65
0
            if (pModelObj) // possibly need to invalidate getCellArea results
66
0
            {
67
0
                Notify(*pModelObj, aChangeRanges, isDataAreaInvalidateType(rType)
68
0
                    ? u"data-area-invalidate"_ustr : u"data-area-extend"_ustr);
69
0
            }
70
0
        }
71
0
    }
72
}
73
74
75
ScUndoCursorAttr::ScUndoCursorAttr( ScDocShell& rNewDocShell,
76
            SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
77
            const ScPatternAttr* pOldPat, const ScPatternAttr* pNewPat,
78
            const ScPatternAttr* pApplyPat ) :
79
0
    ScSimpleUndo( rNewDocShell ),
80
0
    nCol( nNewCol ),
81
0
    nRow( nNewRow ),
82
0
    nTab( nNewTab ),
83
0
    aOldPattern( pOldPat ),
84
0
    aNewPattern( pNewPat ),
85
0
    aApplyPattern( pApplyPat ),
86
0
    pOldEditData( static_cast<EditTextObject*>(nullptr) ),
87
0
    pNewEditData( static_cast<EditTextObject*>(nullptr) )
88
0
{
89
0
}
90
91
ScUndoCursorAttr::~ScUndoCursorAttr()
92
0
{
93
0
}
94
95
OUString ScUndoCursorAttr::GetComment() const
96
0
{
97
    //! own text for automatic attribution
98
0
    return ScResId( STR_UNDO_CURSORATTR ); // "Attribute"
99
0
}
100
101
void ScUndoCursorAttr::SetEditData( std::unique_ptr<EditTextObject> pOld, std::unique_ptr<EditTextObject> pNew )
102
0
{
103
0
    pOldEditData = std::move(pOld);
104
0
    pNewEditData = std::move(pNew);
105
0
}
106
107
void ScUndoCursorAttr::DoChange( const CellAttributeHolder& rWhichPattern, const std::unique_ptr<EditTextObject>& pEditData ) const
108
0
{
109
0
    ScDocument& rDoc = rDocShell.GetDocument();
110
0
    ScAddress aPos(nCol, nRow, nTab);
111
0
    rDoc.SetPattern( nCol, nRow, nTab, rWhichPattern );
112
113
0
    if (rDoc.GetCellType(aPos) == CELLTYPE_EDIT && pEditData)
114
0
        rDoc.SetEditText(aPos, *pEditData, nullptr);
115
116
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
117
0
    if (pViewShell)
118
0
    {
119
0
        pViewShell->SetTabNo( nTab );
120
0
        pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
121
0
        pViewShell->AdjustBlockHeight();
122
0
    }
123
124
0
    const SfxItemSet& rApplySet = aApplyPattern.getScPatternAttr()->GetItemSet();
125
0
    bool bPaintExt = ( rApplySet.GetItemState( ATTR_SHADOW ) != SfxItemState::DEFAULT ||
126
0
                       rApplySet.GetItemState( ATTR_CONDITIONAL ) != SfxItemState::DEFAULT );
127
0
    bool bPaintRows = ( rApplySet.GetItemState( ATTR_HOR_JUSTIFY ) != SfxItemState::DEFAULT );
128
129
0
    sal_uInt16 nFlags = SC_PF_TESTMERGE;
130
0
    if (bPaintExt)
131
0
        nFlags |= SC_PF_LINES;
132
0
    if (bPaintRows)
133
0
        nFlags |= SC_PF_WHOLEROWS;
134
0
    rDocShell.PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, nFlags );
135
0
}
136
137
void ScUndoCursorAttr::Undo()
138
0
{
139
0
    BeginUndo();
140
0
    DoChange(aOldPattern, pOldEditData);
141
0
    EndUndo();
142
0
}
143
144
void ScUndoCursorAttr::Redo()
145
0
{
146
0
    BeginRedo();
147
0
    DoChange(aNewPattern, pNewEditData);
148
0
    EndRedo();
149
0
}
150
151
void ScUndoCursorAttr::Repeat(SfxRepeatTarget& rTarget)
152
0
{
153
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
154
0
        pViewTarget->GetViewShell().ApplySelectionPattern( *aApplyPattern.getScPatternAttr() );
155
0
}
156
157
bool ScUndoCursorAttr::CanRepeat(SfxRepeatTarget& rTarget) const
158
0
{
159
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
160
0
}
161
162
0
ScUndoEnterData::Value::Value() : mnTab(-1), mbHasFormat(false), mnFormat(0) {}
163
164
ScUndoEnterData::ScUndoEnterData(
165
    ScDocShell& rNewDocShell, const ScAddress& rPos, ValuesType& rOldValues,
166
    OUString aNewStr, std::unique_ptr<EditTextObject> pObj ) :
167
0
    ScSimpleUndo( rNewDocShell ),
168
0
    maNewString(std::move(aNewStr)),
169
0
    mpNewEditData(std::move(pObj)),
170
0
    mnEndChangeAction(0),
171
0
    maPos(rPos)
172
0
{
173
0
    maOldValues.swap(rOldValues);
174
175
0
    SetChangeTrack();
176
0
}
177
178
OUString ScUndoEnterData::GetComment() const
179
0
{
180
0
    return ScResId( STR_UNDO_ENTERDATA ); // "Input"
181
0
}
182
183
void ScUndoEnterData::DoChange() const
184
0
{
185
    // only when needed (old or new Edit cell, or Attribute)?
186
0
    bool bHeightChanged = false;
187
0
    for (const auto & i : maOldValues)
188
0
    {
189
0
        if (rDocShell.AdjustRowHeight(maPos.Row(), maPos.Row(), i.mnTab))
190
0
            bHeightChanged = true;
191
0
    }
192
193
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
194
0
    if (pViewShell)
195
0
    {
196
0
        if (comphelper::LibreOfficeKit::isActive() && bHeightChanged)
197
0
        {
198
0
            ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, maPos.Tab());
199
0
            ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
200
0
                pViewShell, false /* bColumns */, true /* bRows */, true /* bSizes*/,
201
0
                false /* bHidden */, false /* bFiltered */, false /* bGroups */, maPos.Tab());
202
0
        }
203
        // Don't switch tabs if the current view is a sheet view.
204
0
        SCTAB nCurrentTab = pViewShell->GetViewData().GetTabNumber();
205
0
        ScDocument& rDocument = rDocShell.GetDocument();
206
0
        if (rDocument.GetDefaultViewTableNumber(nCurrentTab) != maPos.Tab())
207
0
            pViewShell->SetTabNo(maPos.Tab());
208
0
        pViewShell->MoveCursorAbs(maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false);
209
0
    }
210
211
0
    rDocShell.PostDataChanged();
212
0
}
213
214
void ScUndoEnterData::SetChangeTrack()
215
0
{
216
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
217
0
    if ( pChangeTrack )
218
0
    {
219
0
        mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
220
0
        ScAddress aPos(maPos);
221
0
        for (const Value & rOldValue : maOldValues)
222
0
        {
223
0
            aPos.SetTab(rOldValue.mnTab);
224
0
            sal_uLong nFormat = 0;
225
0
            if (rOldValue.mbHasFormat)
226
0
                nFormat = rOldValue.mnFormat;
227
0
            pChangeTrack->AppendContent(aPos, rOldValue.maCell, nFormat);
228
0
        }
229
0
        if ( mnEndChangeAction > pChangeTrack->GetActionMax() )
230
0
            mnEndChangeAction = 0;       // nothing is appended
231
0
    }
232
0
    else
233
0
        mnEndChangeAction = 0;
234
0
}
235
236
void ScUndoEnterData::Undo()
237
0
{
238
0
    BeginUndo();
239
240
0
    ScDocument& rDoc = rDocShell.GetDocument();
241
0
    for (const Value & rVal : maOldValues)
242
0
    {
243
0
        ScCellValue aNewCell;
244
0
        aNewCell.assign(rVal.maCell, rDoc, ScCloneFlags::StartListening);
245
0
        ScAddress aPos = maPos;
246
0
        aPos.SetTab(rVal.mnTab);
247
0
        aNewCell.release(rDoc, aPos);
248
249
0
        if (rVal.mbHasFormat)
250
0
            rDoc.ApplyAttr(maPos.Col(), maPos.Row(), rVal.mnTab,
251
0
                            SfxUInt32Item(ATTR_VALUE_FORMAT, rVal.mnFormat));
252
0
        else
253
0
        {
254
0
            ScPatternAttr* pPattern(new ScPatternAttr(*rDoc.GetPattern(maPos.Col(), maPos.Row(), rVal.mnTab)));
255
0
            pPattern->ItemSetClearItem(ATTR_VALUE_FORMAT);
256
0
            rDoc.SetPattern(maPos.Col(), maPos.Row(), rVal.mnTab, CellAttributeHolder(pPattern, true));
257
0
        }
258
0
        rDocShell.PostPaintCell(maPos.Col(), maPos.Row(), rVal.mnTab);
259
0
    }
260
261
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
262
0
    size_t nCount = maOldValues.size();
263
0
    if ( pChangeTrack && mnEndChangeAction >= sal::static_int_cast<sal_uLong>(nCount) )
264
0
        pChangeTrack->Undo( mnEndChangeAction - nCount + 1, mnEndChangeAction );
265
266
0
    sc::UndoSheetViewSortData::restore(rDocShell, true);
267
0
    rDoc.SyncSheetViews(maPos.Tab());
268
269
0
    DoChange();
270
271
    // Forward path ran spill resolution at the end of the write operation.
272
    // Replay it so a dynamic array master that collapsed, because the user
273
    // typed a blocker into one of its reference cells, re-expands now that
274
    // the blocker is gone (and vice-versa).
275
0
    rDocShell.ResolveSpilledOutputs();
276
277
0
    EndUndo();
278
279
0
    HelperNotifyChanges::NotifyIfChangesListeners(rDocShell, maPos, maOldValues, u"undo"_ustr);
280
0
}
281
282
void ScUndoEnterData::Redo()
283
0
{
284
0
    BeginRedo();
285
286
0
    ScDocument& rDoc = rDocShell.GetDocument();
287
0
    for (const Value & rOldValue : maOldValues)
288
0
    {
289
0
        SCTAB nTab = rOldValue.mnTab;
290
0
        if (mpNewEditData)
291
0
        {
292
0
            ScAddress aPos = maPos;
293
0
            aPos.SetTab(nTab);
294
            // edit text will be cloned.
295
0
            rDoc.SetEditText(aPos, *mpNewEditData, nullptr);
296
0
        }
297
0
        else
298
0
            rDoc.SetString(maPos.Col(), maPos.Row(), nTab, maNewString);
299
300
0
        rDocShell.PostPaintCell(maPos.Col(), maPos.Row(), nTab);
301
0
    }
302
303
0
    SetChangeTrack();
304
305
0
    sc::UndoSheetViewSortData::restore(rDocShell, false);
306
0
    rDoc.SyncSheetViews(maPos.Tab());
307
308
0
    DoChange();
309
310
0
    rDocShell.ResolveSpilledOutputs();
311
312
0
    EndRedo();
313
314
0
    HelperNotifyChanges::NotifyIfChangesListeners(rDocShell, maPos, maOldValues, u"redo"_ustr);
315
0
}
316
317
void ScUndoEnterData::Repeat(SfxRepeatTarget& rTarget)
318
0
{
319
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
320
0
    {
321
0
        OUString aTemp = maNewString;
322
0
        pViewTarget->GetViewShell().EnterDataAtCursor( aTemp );
323
0
    }
324
0
}
325
326
bool ScUndoEnterData::CanRepeat(SfxRepeatTarget& rTarget) const
327
0
{
328
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
329
0
}
330
331
ScUndoEnterValue::ScUndoEnterValue(
332
    ScDocShell& rNewDocShell, const ScAddress& rNewPos,
333
    ScCellValue aUndoCell, double nVal ) :
334
0
    ScSimpleUndo( rNewDocShell ),
335
0
    aPos        ( rNewPos ),
336
0
    maOldCell(std::move(aUndoCell)),
337
0
    nValue      ( nVal )
338
0
{
339
0
    SetChangeTrack();
340
0
}
341
342
ScUndoEnterValue::~ScUndoEnterValue()
343
0
{
344
0
}
345
346
OUString ScUndoEnterValue::GetComment() const
347
0
{
348
0
    return ScResId( STR_UNDO_ENTERDATA ); // "Input"
349
0
}
350
351
void ScUndoEnterValue::SetChangeTrack()
352
0
{
353
0
    ScDocument& rDoc = rDocShell.GetDocument();
354
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
355
0
    if ( pChangeTrack )
356
0
    {
357
0
        nEndChangeAction = pChangeTrack->GetActionMax() + 1;
358
0
        pChangeTrack->AppendContent(aPos, maOldCell);
359
0
        if ( nEndChangeAction > pChangeTrack->GetActionMax() )
360
0
            nEndChangeAction = 0;       // nothing is appended
361
0
    }
362
0
    else
363
0
        nEndChangeAction = 0;
364
0
}
365
366
void ScUndoEnterValue::Undo()
367
0
{
368
0
    BeginUndo();
369
370
0
    ScDocument& rDoc = rDocShell.GetDocument();
371
0
    ScCellValue aNewCell;
372
0
    aNewCell.assign(maOldCell, rDoc, ScCloneFlags::StartListening);
373
0
    aNewCell.release(rDoc, aPos);
374
375
0
    rDocShell.PostPaintCell( aPos );
376
377
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
378
0
    if ( pChangeTrack )
379
0
        pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
380
381
0
    EndUndo();
382
0
}
383
384
void ScUndoEnterValue::Redo()
385
0
{
386
0
    BeginRedo();
387
388
0
    ScDocument& rDoc = rDocShell.GetDocument();
389
0
    rDoc.SetValue( aPos.Col(), aPos.Row(), aPos.Tab(), nValue );
390
0
    rDocShell.PostPaintCell( aPos );
391
392
0
    SetChangeTrack();
393
394
0
    EndRedo();
395
0
}
396
397
void ScUndoEnterValue::Repeat(SfxRepeatTarget& /* rTarget */)
398
0
{
399
    // makes no sense
400
0
}
401
402
bool ScUndoEnterValue::CanRepeat(SfxRepeatTarget& /* rTarget */) const
403
0
{
404
0
    return false;
405
0
}
406
407
ScUndoSetCell::ScUndoSetCell( ScDocShell& rDocSh, const ScAddress& rPos, ScCellValue aOldVal, ScCellValue aNewVal ) :
408
0
    ScSimpleUndo(rDocSh), maPos(rPos), maOldValue(std::move(aOldVal)), maNewValue(std::move(aNewVal)), mnEndChangeAction(0)
409
0
{
410
0
    SetChangeTrack();
411
0
}
412
413
0
ScUndoSetCell::~ScUndoSetCell() {}
414
415
void ScUndoSetCell::Undo()
416
0
{
417
0
    BeginUndo();
418
0
    SetValue(maOldValue);
419
0
    MoveCursorToCell();
420
0
    rDocShell.PostPaintCell(maPos);
421
422
0
    ScDocument& rDoc = rDocShell.GetDocument();
423
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
424
0
    if (pChangeTrack)
425
0
        pChangeTrack->Undo(mnEndChangeAction, mnEndChangeAction);
426
427
0
    sc::UndoSheetViewSortData::restore(rDocShell, true);
428
429
    // Replay the resolution so dynamic array masters that should re-spill
430
    // or re-expand after the value change are reconciled.
431
0
    rDocShell.ResolveSpilledOutputs();
432
433
0
    EndUndo();
434
0
}
435
436
void ScUndoSetCell::Redo()
437
0
{
438
0
    BeginRedo();
439
0
    SetValue(maNewValue);
440
0
    MoveCursorToCell();
441
0
    rDocShell.PostPaintCell(maPos);
442
0
    SetChangeTrack();
443
444
0
    sc::UndoSheetViewSortData::restore(rDocShell, false);
445
446
0
    rDocShell.ResolveSpilledOutputs();
447
448
0
    EndRedo();
449
0
}
450
451
void ScUndoSetCell::Repeat( SfxRepeatTarget& /*rTarget*/ )
452
0
{
453
    // Makes no sense.
454
0
}
455
456
bool ScUndoSetCell::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
457
0
{
458
0
    return false;
459
0
}
460
461
OUString ScUndoSetCell::GetComment() const
462
0
{
463
0
    return ScResId(STR_UNDO_ENTERDATA); // "Input"
464
0
}
465
466
void ScUndoSetCell::SetChangeTrack()
467
0
{
468
0
    ScDocument& rDoc = rDocShell.GetDocument();
469
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
470
0
    if (pChangeTrack)
471
0
    {
472
0
        mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
473
474
0
        pChangeTrack->AppendContent(maPos, maOldValue);
475
476
0
        if (mnEndChangeAction > pChangeTrack->GetActionMax())
477
0
            mnEndChangeAction = 0;       // Nothing is appended
478
0
    }
479
0
    else
480
0
        mnEndChangeAction = 0;
481
0
}
482
483
void ScUndoSetCell::SetValue( const ScCellValue& rVal )
484
0
{
485
0
    ScDocument& rDoc = rDocShell.GetDocument();
486
487
0
    switch (rVal.getType())
488
0
    {
489
0
        case CELLTYPE_NONE:
490
            // empty cell
491
0
            rDoc.SetEmptyCell(maPos);
492
0
        break;
493
0
        case CELLTYPE_VALUE:
494
0
            rDoc.SetValue(maPos, rVal.getDouble());
495
0
        break;
496
0
        case CELLTYPE_STRING:
497
0
        {
498
0
            ScSetStringParam aParam;
499
0
            aParam.setTextInput();
500
            // Undo only cell content, without setting any number format.
501
0
            aParam.meSetTextNumFormat = ScSetStringParam::Keep;
502
0
            rDoc.SetString(maPos, rVal.getSharedString()->getString(), &aParam);
503
0
        }
504
0
        break;
505
0
        case CELLTYPE_EDIT:
506
0
            rDoc.SetEditText(maPos, std::make_unique<EditTextObject>(*rVal.getEditText()));
507
0
        break;
508
0
        case CELLTYPE_FORMULA:
509
0
            rDoc.SetFormulaCell(maPos, rVal.getFormula()->Clone());
510
0
        break;
511
0
        default:
512
0
            ;
513
0
    }
514
0
}
515
516
void ScUndoSetCell::MoveCursorToCell()
517
0
{
518
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
519
0
    if ( pViewShell )
520
0
    {
521
        // Don't switch tabs if the current view is a sheet view for the target tab.
522
0
        SCTAB nCurrentTab = pViewShell->GetViewData().GetTabNumber();
523
0
        ScDocument& rDocument = rDocShell.GetDocument();
524
0
        if (rDocument.GetDefaultViewTableNumber(nCurrentTab) != maPos.Tab())
525
0
            pViewShell->SetTabNo(maPos.Tab());
526
0
        pViewShell->MoveCursorAbs( maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false );
527
0
    }
528
0
}
529
530
ScUndoPageBreak::ScUndoPageBreak( ScDocShell& rNewDocShell,
531
            SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
532
            bool bNewColumn, bool bNewInsert ) :
533
0
    ScSimpleUndo( rNewDocShell ),
534
0
    nCol( nNewCol ),
535
0
    nRow( nNewRow ),
536
0
    nTab( nNewTab ),
537
0
    bColumn( bNewColumn ),
538
0
    bInsert( bNewInsert )
539
0
{
540
0
}
541
542
ScUndoPageBreak::~ScUndoPageBreak()
543
0
{
544
0
}
545
546
OUString ScUndoPageBreak::GetComment() const
547
0
{
548
    //"Column break" | "Row break"  "insert" | "delete"
549
0
    return bColumn ?
550
0
        ( bInsert ?
551
0
            ScResId( STR_UNDO_INSCOLBREAK ) :
552
0
            ScResId( STR_UNDO_DELCOLBREAK )
553
0
        ) :
554
0
        ( bInsert ?
555
0
            ScResId( STR_UNDO_INSROWBREAK ) :
556
0
            ScResId( STR_UNDO_DELROWBREAK )
557
0
        );
558
0
}
559
560
void ScUndoPageBreak::DoChange( bool bInsertP ) const
561
0
{
562
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
563
564
0
    if (pViewShell)
565
0
    {
566
0
        pViewShell->SetTabNo( nTab );
567
0
        pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
568
569
0
        if (bInsertP)
570
0
            pViewShell->InsertPageBreak(bColumn, false);
571
0
        else
572
0
            pViewShell->DeletePageBreak(bColumn, false);
573
574
0
        rDocShell.GetDocument().InvalidatePageBreaks(nTab);
575
0
    }
576
0
}
577
578
void ScUndoPageBreak::Undo()
579
0
{
580
0
    BeginUndo();
581
0
    DoChange(!bInsert);
582
0
    EndUndo();
583
0
}
584
585
void ScUndoPageBreak::Redo()
586
0
{
587
0
    BeginRedo();
588
0
    DoChange(bInsert);
589
0
    EndRedo();
590
0
}
591
592
void ScUndoPageBreak::Repeat(SfxRepeatTarget& rTarget)
593
0
{
594
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
595
0
    {
596
0
        ScTabViewShell& rViewShell = pViewTarget->GetViewShell();
597
598
0
        if (bInsert)
599
0
            rViewShell.InsertPageBreak(bColumn);
600
0
        else
601
0
            rViewShell.DeletePageBreak(bColumn);
602
0
    }
603
0
}
604
605
bool ScUndoPageBreak::CanRepeat(SfxRepeatTarget& rTarget) const
606
0
{
607
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
608
0
}
609
610
ScUndoPrintZoom::ScUndoPrintZoom( ScDocShell& rNewDocShell,
611
            SCTAB nT, sal_uInt16 nOS, sal_uInt16 nOP, sal_uInt16 nNS, sal_uInt16 nNP ) :
612
0
    ScSimpleUndo( rNewDocShell ),
613
0
    nTab( nT ),
614
0
    nOldScale( nOS ),
615
0
    nOldPages( nOP ),
616
0
    nNewScale( nNS ),
617
0
    nNewPages( nNP )
618
0
{
619
0
}
620
621
ScUndoPrintZoom::~ScUndoPrintZoom()
622
0
{
623
0
}
624
625
OUString ScUndoPrintZoom::GetComment() const
626
0
{
627
0
    return ScResId( STR_UNDO_PRINTSCALE );
628
0
}
629
630
void ScUndoPrintZoom::DoChange( bool bUndo )
631
0
{
632
0
    sal_uInt16 nScale = bUndo ? nOldScale : nNewScale;
633
0
    sal_uInt16 nPages = bUndo ? nOldPages : nNewPages;
634
635
0
    ScDocument& rDoc = rDocShell.GetDocument();
636
0
    OUString aStyleName = rDoc.GetPageStyle( nTab );
637
0
    ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
638
0
    SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
639
0
    OSL_ENSURE( pStyleSheet, "PageStyle not found" );
640
0
    if ( pStyleSheet )
641
0
    {
642
0
        SfxItemSet& rSet = pStyleSheet->GetItemSet();
643
0
        rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) );
644
0
        rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) );
645
646
0
        ScPrintFunc aPrintFunc( rDocShell, rDocShell.GetPrinter(), nTab );
647
0
        aPrintFunc.UpdatePages();
648
0
    }
649
0
}
650
651
void ScUndoPrintZoom::Undo()
652
0
{
653
0
    BeginUndo();
654
0
    DoChange(true);
655
0
    EndUndo();
656
0
}
657
658
void ScUndoPrintZoom::Redo()
659
0
{
660
0
    BeginRedo();
661
0
    DoChange(false);
662
0
    EndRedo();
663
0
}
664
665
void ScUndoPrintZoom::Repeat(SfxRepeatTarget& rTarget)
666
0
{
667
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
668
0
    {
669
0
        ScTabViewShell& rViewShell = pViewTarget->GetViewShell();
670
0
        ScViewData& rViewData = rViewShell.GetViewData();
671
0
        rViewData.GetDocShell()->SetPrintZoom( rViewData.CurrentTabForData(), nNewScale, nNewPages );
672
0
    }
673
0
}
674
675
bool ScUndoPrintZoom::CanRepeat(SfxRepeatTarget& rTarget) const
676
0
{
677
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
678
0
}
679
680
ScUndoThesaurus::ScUndoThesaurus(
681
    ScDocShell& rNewDocShell, SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
682
    ScCellValue aOldText, ScCellValue aNewText ) :
683
0
    ScSimpleUndo( rNewDocShell ),
684
0
    nCol( nNewCol ),
685
0
    nRow( nNewRow ),
686
0
    nTab( nNewTab ),
687
0
    maOldText(std::move(aOldText)),
688
0
    maNewText(std::move(aNewText))
689
0
{
690
0
    SetChangeTrack(maOldText);
691
0
}
692
693
0
ScUndoThesaurus::~ScUndoThesaurus() {}
694
695
OUString ScUndoThesaurus::GetComment() const
696
0
{
697
0
    return ScResId( STR_UNDO_THESAURUS );    // "Thesaurus"
698
0
}
699
700
void ScUndoThesaurus::SetChangeTrack( const ScCellValue& rOldCell )
701
0
{
702
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
703
0
    if ( pChangeTrack )
704
0
    {
705
0
        nEndChangeAction = pChangeTrack->GetActionMax() + 1;
706
0
        pChangeTrack->AppendContent(ScAddress(nCol, nRow, nTab), rOldCell);
707
0
        if ( nEndChangeAction > pChangeTrack->GetActionMax() )
708
0
            nEndChangeAction = 0;       // nothing is appended
709
0
    }
710
0
    else
711
0
        nEndChangeAction = 0;
712
0
}
713
714
void ScUndoThesaurus::DoChange( bool bUndo, const ScCellValue& rText )
715
0
{
716
0
    ScDocument& rDoc = rDocShell.GetDocument();
717
718
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
719
0
    if (pViewShell)
720
0
    {
721
0
        pViewShell->SetTabNo( nTab );
722
0
        pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
723
0
    }
724
725
0
    ScAddress aPos(nCol, nRow, nTab);
726
0
    rText.commit(rDoc, aPos);
727
0
    if (!bUndo)
728
0
        SetChangeTrack(maOldText);
729
730
0
    rDocShell.PostPaintCell( nCol, nRow, nTab );
731
0
}
732
733
void ScUndoThesaurus::Undo()
734
0
{
735
0
    BeginUndo();
736
0
    DoChange(true, maOldText);
737
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
738
0
    if ( pChangeTrack )
739
0
        pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
740
0
    EndUndo();
741
0
}
742
743
void ScUndoThesaurus::Redo()
744
0
{
745
0
    BeginRedo();
746
0
    DoChange(false, maNewText);
747
0
    EndRedo();
748
0
}
749
750
void ScUndoThesaurus::Repeat(SfxRepeatTarget& rTarget)
751
0
{
752
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
753
0
        pViewTarget->GetViewShell().DoThesaurus();
754
0
}
755
756
bool ScUndoThesaurus::CanRepeat(SfxRepeatTarget& rTarget) const
757
0
{
758
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
759
0
}
760
761
762
ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocSh, const ScAddress& rPos,
763
        const ScNoteData& rNoteData, bool bInsert, std::unique_ptr<SdrUndoAction> pDrawUndo ) :
764
0
    ScSimpleUndo( rDocSh ),
765
0
    maPos( rPos ),
766
0
    mpDrawUndo( std::move(pDrawUndo) )
767
0
{
768
0
    OSL_ENSURE( rNoteData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note caption" );
769
0
    if (bInsert)
770
0
    {
771
0
        maNewData = rNoteData;
772
0
    }
773
0
    else
774
0
    {
775
0
        maOldData = rNoteData;
776
0
    }
777
0
}
778
779
ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocSh, const ScAddress& rPos,
780
        ScNoteData aOldData, ScNoteData aNewData, std::unique_ptr<SdrUndoAction> pDrawUndo,
781
        std::unique_ptr<ScThreadedCommentData> pOldThreadedData,
782
        std::unique_ptr<ScThreadedCommentData> pNewThreadedData ) :
783
0
    ScSimpleUndo( rDocSh ),
784
0
    maPos( rPos ),
785
0
    maOldData(std::move( aOldData )),
786
0
    maNewData(std::move( aNewData )),
787
0
    mpOldThreadedData( std::move(pOldThreadedData) ),
788
0
    mpNewThreadedData( std::move(pNewThreadedData) ),
789
0
    mpDrawUndo( std::move(pDrawUndo) )
790
0
{
791
0
    OSL_ENSURE( maOldData.mxCaption || maNewData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note captions" );
792
0
    OSL_ENSURE( !maOldData.mxInitData && !maNewData.mxInitData, "ScUndoReplaceNote::ScUndoReplaceNote - unexpected uninitialized note" );
793
0
}
794
795
ScUndoReplaceNote::~ScUndoReplaceNote()
796
0
{
797
0
    mpDrawUndo.reset();
798
0
}
799
800
void ScUndoReplaceNote::Undo()
801
0
{
802
0
    BeginUndo();
803
0
    DoSdrUndoAction( mpDrawUndo.get(), &rDocShell.GetDocument() );
804
    /*  Undo insert -> remove new note.
805
        Undo remove -> insert old note.
806
        Undo replace -> remove new note, insert old note. */
807
0
    DoRemoveNote( maNewData );
808
0
    DoInsertNote( maOldData, mpOldThreadedData.get() );
809
0
    rDocShell.PostPaintCell( maPos );
810
0
    EndUndo();
811
0
}
812
813
void ScUndoReplaceNote::Redo()
814
0
{
815
0
    BeginRedo();
816
0
    RedoSdrUndoAction( mpDrawUndo.get() );
817
    /*  Redo insert -> insert new note.
818
        Redo remove -> remove old note.
819
        Redo replace -> remove old note, insert new note. */
820
0
    DoRemoveNote( maOldData );
821
0
    DoInsertNote( maNewData, mpNewThreadedData.get() );
822
0
    rDocShell.PostPaintCell( maPos );
823
0
    EndRedo();
824
0
}
825
826
void ScUndoReplaceNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
827
0
{
828
0
}
829
830
bool ScUndoReplaceNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
831
0
{
832
0
    return false;
833
0
}
834
835
OUString ScUndoReplaceNote::GetComment() const
836
0
{
837
0
    return ScResId( maNewData.mxCaption ?
838
0
        (maOldData.mxCaption ? STR_UNDO_EDITNOTE : STR_UNDO_INSERTNOTE) : STR_UNDO_DELETENOTE );
839
0
}
840
841
void ScUndoReplaceNote::DoInsertNote( const ScNoteData& rNoteData, const ScThreadedCommentData* pThreadedData )
842
0
{
843
0
    if( rNoteData.mxCaption )
844
0
    {
845
0
        ScDocument& rDoc = rDocShell.GetDocument();
846
0
        OSL_ENSURE( !rDoc.GetNote(maPos), "ScUndoReplaceNote::DoInsertNote - unexpected cell note" );
847
0
        ScPostIt* pNote = new ScPostIt( rDoc, maPos, rNoteData, false );
848
0
        rDoc.SetNote( maPos, std::unique_ptr<ScPostIt>(pNote) );
849
        // Threaded-comment data lives on ScPostIt outside ScNoteData, so the new
850
        // post-it carries none yet; reattach a fresh clone (undo/redo may fire again).
851
0
        if (pThreadedData)
852
0
            pNote->SetThreadedCommentData(std::make_unique<ScThreadedCommentData>(*pThreadedData));
853
0
        ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, rDoc, maPos, pNote);
854
0
    }
855
0
}
856
857
void ScUndoReplaceNote::DoRemoveNote( const ScNoteData& rNoteData )
858
0
{
859
0
    if( !rNoteData.mxCaption )
860
0
        return;
861
862
0
    ScDocument& rDoc = rDocShell.GetDocument();
863
0
    OSL_ENSURE( rDoc.GetNote(maPos), "ScUndoReplaceNote::DoRemoveNote - missing cell note" );
864
0
    if( std::unique_ptr<ScPostIt> pNote = rDoc.ReleaseNote( maPos ) )
865
0
    {
866
        /*  Forget pointer to caption object to suppress removing the
867
            caption object from the drawing layer while deleting pNote
868
            (removing the caption is done by a drawing undo action). */
869
0
        pNote->ForgetCaption();
870
0
        ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Remove, rDoc, maPos, pNote.get());
871
0
    }
872
0
}
873
874
ScUndoShowHideNote::ScUndoShowHideNote( ScDocShell& rDocSh, const ScAddress& rPos, bool bShow ) :
875
0
    ScSimpleUndo( rDocSh ),
876
0
    maPos( rPos ),
877
0
    mbShown( bShow )
878
0
{
879
0
}
880
881
ScUndoShowHideNote::~ScUndoShowHideNote()
882
0
{
883
0
}
884
885
void ScUndoShowHideNote::Undo()
886
0
{
887
0
    BeginUndo();
888
0
    if( ScPostIt* pNote = rDocShell.GetDocument().GetNote(maPos) )
889
0
        pNote->ShowCaption( maPos, !mbShown );
890
0
    EndUndo();
891
0
}
892
893
void ScUndoShowHideNote::Redo()
894
0
{
895
0
    BeginRedo();
896
0
    if( ScPostIt* pNote = rDocShell.GetDocument().GetNote(maPos) )
897
0
        pNote->ShowCaption( maPos, mbShown );
898
0
    EndRedo();
899
0
}
900
901
void ScUndoShowHideNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
902
0
{
903
0
}
904
905
bool ScUndoShowHideNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
906
0
{
907
0
    return false;
908
0
}
909
910
OUString ScUndoShowHideNote::GetComment() const
911
0
{
912
0
    return ScResId( mbShown ? STR_UNDO_SHOWNOTE : STR_UNDO_HIDENOTE );
913
0
}
914
915
ScUndoDetective::ScUndoDetective( ScDocShell& rNewDocShell,
916
                                    std::unique_ptr<SdrUndoAction> pDraw, const ScDetOpData* pOperation,
917
                                    std::unique_ptr<ScDetOpList> pUndoList ) :
918
0
    ScSimpleUndo( rNewDocShell ),
919
0
    pOldList    ( std::move(pUndoList) ),
920
0
    nAction     ( 0 ),
921
0
    pDrawUndo   ( std::move(pDraw) )
922
0
{
923
0
    bIsDelete = ( pOperation == nullptr );
924
0
    if (!bIsDelete)
925
0
    {
926
0
        nAction = static_cast<sal_uInt16>(pOperation->GetOperation());
927
0
        aPos = pOperation->GetPos();
928
0
    }
929
0
}
930
931
ScUndoDetective::~ScUndoDetective()
932
0
{
933
0
    pDrawUndo.reset();
934
0
    pOldList.reset();
935
0
}
936
937
OUString ScUndoDetective::GetComment() const
938
0
{
939
0
    TranslateId pId = STR_UNDO_DETDELALL;
940
0
    if ( !bIsDelete )
941
0
        switch ( static_cast<ScDetOpType>(nAction) )
942
0
        {
943
0
            case SCDETOP_ADDSUCC:   pId = STR_UNDO_DETADDSUCC;  break;
944
0
            case SCDETOP_DELSUCC:   pId = STR_UNDO_DETDELSUCC;  break;
945
0
            case SCDETOP_ADDPRED:   pId = STR_UNDO_DETADDPRED;  break;
946
0
            case SCDETOP_DELPRED:   pId = STR_UNDO_DETDELPRED;  break;
947
0
            case SCDETOP_ADDERROR:  pId = STR_UNDO_DETADDERROR; break;
948
0
        }
949
950
0
    return ScResId(pId);
951
0
}
952
953
void ScUndoDetective::Undo()
954
0
{
955
0
    BeginUndo();
956
957
0
    ScDocument& rDoc = rDocShell.GetDocument();
958
0
    DoSdrUndoAction(pDrawUndo.get(), &rDoc);
959
960
0
    if (bIsDelete)
961
0
    {
962
0
        if ( pOldList )
963
0
            rDoc.SetDetOpList( std::unique_ptr<ScDetOpList>(new ScDetOpList(*pOldList)) );
964
0
    }
965
0
    else
966
0
    {
967
        // Remove entry from list
968
969
0
        ScDetOpList* pList = rDoc.GetDetOpList();
970
0
        if (pList && pList->Count())
971
0
        {
972
0
            ScDetOpDataVector& rVec = pList->GetDataVector();
973
0
            ScDetOpDataVector::iterator it = rVec.begin() + rVec.size() - 1;
974
0
            if ( it->GetOperation() == static_cast<ScDetOpType>(nAction) && it->GetPos() == aPos )
975
0
                rVec.erase( it);
976
0
            else
977
0
            {
978
0
                OSL_FAIL("Detective entry could not be found in list");
979
0
            }
980
0
        }
981
0
    }
982
983
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
984
0
    if (pViewShell)
985
0
        pViewShell->RecalcPPT();    //! use broadcast instead?
986
987
0
    EndUndo();
988
0
}
989
990
void ScUndoDetective::Redo()
991
0
{
992
0
    BeginRedo();
993
994
0
    RedoSdrUndoAction(pDrawUndo.get());
995
996
0
    ScDocument& rDoc = rDocShell.GetDocument();
997
998
0
    if (bIsDelete)
999
0
        rDoc.ClearDetectiveOperations();
1000
0
    else
1001
0
        rDoc.AddDetectiveOperation( ScDetOpData( aPos, static_cast<ScDetOpType>(nAction) ) );
1002
1003
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1004
0
    if (pViewShell)
1005
0
        pViewShell->RecalcPPT();    //! use broadcast instead?
1006
1007
0
    EndRedo();
1008
0
}
1009
1010
void ScUndoDetective::Repeat(SfxRepeatTarget& /* rTarget */)
1011
0
{
1012
    // makes no sense
1013
0
}
1014
1015
bool ScUndoDetective::CanRepeat(SfxRepeatTarget& /* rTarget */) const
1016
0
{
1017
0
    return false;
1018
0
}
1019
1020
ScUndoRangeNames::ScUndoRangeNames( ScDocShell& rNewDocShell,
1021
                                    std::unique_ptr<ScRangeName> pOld, std::unique_ptr<ScRangeName> pNew, SCTAB nTab ) :
1022
0
    ScSimpleUndo( rNewDocShell ),
1023
0
    pOldRanges  ( std::move(pOld) ),
1024
0
    pNewRanges  ( std::move(pNew) ),
1025
0
    mnTab       ( nTab )
1026
0
{
1027
0
}
1028
1029
ScUndoRangeNames::~ScUndoRangeNames()
1030
0
{
1031
0
    pOldRanges.reset();
1032
0
    pNewRanges.reset();
1033
0
}
1034
1035
OUString ScUndoRangeNames::GetComment() const
1036
0
{
1037
0
    return ScResId( STR_UNDO_RANGENAMES );
1038
0
}
1039
1040
void ScUndoRangeNames::DoChange( bool bUndo )
1041
0
{
1042
0
    ScDocument& rDoc = rDocShell.GetDocument();
1043
0
    rDoc.PreprocessRangeNameUpdate();
1044
1045
0
    if ( bUndo )
1046
0
    {
1047
0
        auto p = std::make_unique<ScRangeName>(*pOldRanges);
1048
0
        if (mnTab >= 0)
1049
0
            rDoc.SetRangeName( mnTab, std::move(p) );
1050
0
        else
1051
0
            rDoc.SetRangeName( std::move(p) );
1052
0
    }
1053
0
    else
1054
0
    {
1055
0
        auto p = std::make_unique<ScRangeName>(*pNewRanges);
1056
0
        if (mnTab >= 0)
1057
0
            rDoc.SetRangeName( mnTab, std::move(p) );
1058
0
        else
1059
0
            rDoc.SetRangeName( std::move(p) );
1060
0
    }
1061
1062
0
    rDoc.CompileHybridFormula();
1063
1064
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
1065
0
}
1066
1067
void ScUndoRangeNames::Undo()
1068
0
{
1069
0
    BeginUndo();
1070
0
    DoChange( true );
1071
0
    EndUndo();
1072
0
}
1073
1074
void ScUndoRangeNames::Redo()
1075
0
{
1076
0
    BeginRedo();
1077
0
    DoChange( false );
1078
0
    EndRedo();
1079
0
}
1080
1081
void ScUndoRangeNames::Repeat(SfxRepeatTarget& /* rTarget */)
1082
0
{
1083
    // makes no sense
1084
0
}
1085
1086
bool ScUndoRangeNames::CanRepeat(SfxRepeatTarget& /* rTarget */) const
1087
0
{
1088
0
    return false;
1089
0
}
1090
1091
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */