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/undoblk.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 <scitems.hxx>
21
#include <utility>
22
#include <vcl/virdev.hxx>
23
#include <vcl/weld/WaitObject.hxx>
24
#include <vcl/weld/Window.hxx>
25
#include <editeng/boxitem.hxx>
26
#include <sfx2/app.hxx>
27
#include <comphelper/lok.hxx>
28
#include <osl/diagnose.h>
29
30
#include <undoblk.hxx>
31
#include <undoutil.hxx>
32
#include <document.hxx>
33
#include <patattr.hxx>
34
#include <docsh.hxx>
35
#include <tabvwsh.hxx>
36
#include <rangenam.hxx>
37
#include <rangeutl.hxx>
38
#include <stlpool.hxx>
39
#include <stlsheet.hxx>
40
#include <globstr.hrc>
41
#include <scresid.hxx>
42
#include <global.hxx>
43
#include <target.hxx>
44
#include <docpool.hxx>
45
#include <docfunc.hxx>
46
#include <attrib.hxx>
47
#include <chgtrack.hxx>
48
#include <transobj.hxx>
49
#include <refundo.hxx>
50
#include <undoolk.hxx>
51
#include <clipparam.hxx>
52
#include <tokenarray.hxx>
53
#include <rowheightcontext.hxx>
54
#include <refupdatecontext.hxx>
55
#include <validat.hxx>
56
#include <gridwin.hxx>
57
#include <columnspanset.hxx>
58
59
#include <memory>
60
#include <set>
61
62
// TODO:
63
/*A*/   // SetOptimalHeight on Document, if no View
64
/*B*/   // linked sheets
65
/*C*/   // ScArea
66
//?     // check later
67
68
namespace
69
{
70
/** Refresh the header row to update ScMF::Auto flags. */
71
void refreshAutoFilterForColumnChange(ScDocument& rDocument, SCTAB nTab)
72
0
{
73
0
    ScDBData* pDBData = rDocument.GetAnonymousDBData(nTab);
74
0
    if (!pDBData || !pDBData->HasAutoFilter())
75
0
        return;
76
77
0
    ScRange aRange;
78
0
    pDBData->GetArea(aRange);
79
    // Scan the full header row as stale flags may be outside the range.
80
0
    rDocument.RefreshAutoFilter(0, aRange.aStart.Row(),  rDocument.MaxCol(), aRange.aStart.Row(), nTab);
81
0
}
82
} // end anonymous namespace
83
84
ScUndoInsertCells::ScUndoInsertCells( ScDocShell& rNewDocShell,
85
                                const ScRange& rRange,
86
                                SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
87
                                InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
88
                                bool bNewPartOfPaste ) :
89
0
    ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
90
0
    aEffRange( rRange ),
91
0
    nCount( nNewCount ),
92
0
    pTabs( std::move(pNewTabs) ),
93
0
    pScenarios( std::move(pNewScenarios) ),
94
0
    eCmd( eNewCmd ),
95
0
    bPartOfPaste( bNewPartOfPaste )
96
0
{
97
0
    ScDocument& rDoc = rDocShell.GetDocument();
98
0
    if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER)            // whole row?
99
0
    {
100
0
        aEffRange.aStart.SetCol(0);
101
0
        aEffRange.aEnd.SetCol(rDoc.MaxCol());
102
0
    }
103
104
0
    if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER)            // whole column?
105
0
    {
106
0
        aEffRange.aStart.SetRow(0);
107
0
        aEffRange.aEnd.SetRow(rDoc.MaxRow());
108
0
    }
109
110
0
    SetChangeTrack();
111
0
}
112
113
ScUndoInsertCells::~ScUndoInsertCells()
114
0
{
115
0
}
116
117
OUString ScUndoInsertCells::GetComment() const
118
0
{
119
0
    return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS );
120
0
}
121
122
bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction )
123
0
{
124
    //  If a paste undo action has already been added, append (detective) action there.
125
0
    if ( pPasteUndo )
126
0
        return pPasteUndo->Merge( pNextAction );
127
128
0
    if ( bPartOfPaste )
129
0
        if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) )
130
0
        {
131
0
            if (dynamic_cast<const ScUndoPaste*>(pWrapper->GetWrappedUndo()))
132
0
            {
133
                //  Store paste action if this is part of paste with inserting cells.
134
                //  A list action isn't used because Repeat wouldn't work (insert wrong cells).
135
136
                // Pass ownership of the wrapped SfxUndoAction* to pPasteUndo
137
0
                pPasteUndo = pWrapper->ReleaseWrappedUndo();
138
0
                return true;
139
0
            }
140
0
        }
141
142
    //  Call base class for detective handling
143
0
    return ScMoveUndo::Merge( pNextAction );
144
0
}
145
146
void ScUndoInsertCells::SetChangeTrack()
147
0
{
148
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
149
0
    if ( pChangeTrack )
150
0
    {
151
0
        pChangeTrack->AppendInsert( aEffRange );
152
0
        nEndChangeAction = pChangeTrack->GetActionMax();
153
0
    }
154
0
    else
155
0
        nEndChangeAction = 0;
156
0
}
157
158
void ScUndoInsertCells::DoChange( const bool bUndo )
159
0
{
160
0
    ScDocument& rDoc = rDocShell.GetDocument();
161
0
    SCTAB i;
162
163
0
    if ( bUndo )
164
0
    {
165
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
166
0
        if ( pChangeTrack )
167
0
            pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
168
0
    }
169
0
    else
170
0
        SetChangeTrack();
171
172
    // refresh of merged cells has to be after inserting/deleting
173
174
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
175
0
    switch (eCmd)
176
0
    {
177
0
        case INS_INSROWS_BEFORE:
178
0
        case INS_INSROWS_AFTER:
179
0
        case INS_CELLSDOWN:
180
0
            for( i=0; i<nCount; i++ )
181
0
            {
182
183
0
                if (bUndo)
184
0
                    rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
185
0
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
186
0
                else
187
0
                    rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
188
0
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
189
190
0
                if (pViewShell)
191
0
                {
192
0
                    const tools::Long nSign = bUndo ? -1 : 1;
193
0
                    pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
194
0
                }
195
0
            }
196
0
            break;
197
0
        case INS_INSCOLS_BEFORE:
198
0
        case INS_INSCOLS_AFTER:
199
0
        case INS_CELLSRIGHT:
200
0
            for( i=0; i<nCount; i++ )
201
0
            {
202
0
                if (bUndo)
203
0
                    rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
204
0
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
205
0
                else
206
0
                    rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
207
0
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
208
209
0
                refreshAutoFilterForColumnChange(rDoc, pTabs[i]);
210
211
0
                if (pViewShell)
212
0
                {
213
0
                    const tools::Long nSign = bUndo ? -1 : 1;
214
0
                    pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
215
0
                }
216
0
            }
217
0
            break;
218
0
        default:
219
0
        {
220
            // added to avoid warnings
221
0
        }
222
0
    }
223
224
0
    ScRange aWorkRange( aEffRange );
225
0
    if ( eCmd == INS_CELLSRIGHT )                   // only "shift right" requires refresh of the moved area
226
0
        aWorkRange.aEnd.SetCol(rDoc.MaxCol());
227
0
    for( i=0; i<nCount; i++ )
228
0
    {
229
0
        if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
230
0
            aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) )
231
0
        {
232
0
            SCCOL nEndCol = aWorkRange.aEnd.Col();
233
0
            SCROW nEndRow = aWorkRange.aEnd.Row();
234
0
            rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
235
0
        }
236
0
    }
237
238
    // Undo for displaced attributes?
239
240
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
241
242
0
    switch (eCmd)
243
0
    {
244
0
        case INS_INSROWS_BEFORE:
245
0
        case INS_INSROWS_AFTER:
246
0
            nPaint |= PaintPartFlags::Left;
247
0
            aWorkRange.aEnd.SetRow(rDoc.MaxRow());
248
0
            break;
249
0
        case INS_CELLSDOWN:
250
0
            for( i=0; i<nCount; i++ )
251
0
            {
252
0
                aWorkRange.aEnd.SetRow(rDoc.MaxRow());
253
0
                if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
254
0
                {
255
0
                    aWorkRange.aStart.SetCol(0);
256
0
                    aWorkRange.aEnd.SetCol(rDoc.MaxCol());
257
0
                    nPaint |= PaintPartFlags::Left;
258
0
                }
259
0
            }
260
0
            break;
261
0
        case INS_INSCOLS_BEFORE:
262
0
        case INS_INSCOLS_AFTER:
263
0
            nPaint |= PaintPartFlags::Top;                // top bar
264
0
            [[fallthrough]];
265
0
        case INS_CELLSRIGHT:
266
0
            for( i=0; i<nCount; i++ )
267
0
            {
268
0
                aWorkRange.aEnd.SetCol(rDoc.MaxCol());     // to the far right
269
0
                if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) )
270
0
                {                                   // AdjustDraw does not paint PaintPartFlags::Top,
271
0
                    aWorkRange.aStart.SetCol(0);    // thus solved like this
272
0
                    aWorkRange.aEnd.SetRow(rDoc.MaxRow());
273
0
                    nPaint |= PaintPartFlags::Left;
274
0
                }
275
0
            }
276
0
            break;
277
0
        default:
278
0
        {
279
            // added to avoid warnings
280
0
        }
281
0
    }
282
283
0
    for( i=0; i<nCount; i++ )
284
0
    {
285
0
        rDocShell.PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
286
0
            aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint );
287
0
    }
288
0
    rDocShell.PostDataChanged();
289
0
    if (!pViewShell)
290
0
        return;
291
292
0
    pViewShell->CellContentChanged();
293
294
0
    if (!comphelper::LibreOfficeKit::isActive())
295
0
        return;
296
297
0
    SCTAB nTab = pViewShell->GetViewData().GetTabNumber();
298
0
    bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT);
299
0
    bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN);
300
301
0
    if (bColsAffected)
302
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
303
304
0
    if (bRowsAffected)
305
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
306
307
0
    ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
308
0
            pViewShell,
309
0
            bColsAffected, bRowsAffected,
310
0
            true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
311
0
            true /* bGroups */, nTab);
312
0
}
313
314
void ScUndoInsertCells::Undo()
315
0
{
316
0
    if ( pPasteUndo )
317
0
        pPasteUndo->Undo();     // undo paste first
318
319
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important due to TrackFormulas in UpdateReference
320
0
    BeginUndo();
321
0
    DoChange( true );
322
323
0
    sc::UndoSheetViewSortData::restore(rDocShell, true);
324
325
0
    EndUndo();
326
327
0
    ScDocument& rDoc = rDocShell.GetDocument();
328
0
    for (SCTAB i = 0; i < nCount; ++i)
329
0
        rDoc.SetDrawPageSize(pTabs[i]);
330
0
}
331
332
void ScUndoInsertCells::Redo()
333
0
{
334
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important due to TrackFormulas in UpdateReference
335
0
    BeginRedo();
336
0
    DoChange( false );
337
338
0
    sc::UndoSheetViewSortData::restore(rDocShell, false);
339
340
0
    EndRedo();
341
342
0
    if ( pPasteUndo )
343
0
        pPasteUndo->Redo();     // redo paste last
344
345
0
    ScDocument& rDoc = rDocShell.GetDocument();
346
0
    for (SCTAB i = 0; i < nCount; ++i)
347
0
        rDoc.SetDrawPageSize(pTabs[i]);
348
0
}
349
350
void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget)
351
0
{
352
0
    if (dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr)
353
0
    {
354
0
        if ( pPasteUndo )
355
0
        {
356
            //  Repeat for paste with inserting cells is handled completely
357
            //  by the Paste undo action
358
359
0
            pPasteUndo->Repeat( rTarget );
360
0
        }
361
0
        else
362
0
            static_cast<ScTabViewTarget&>(rTarget).GetViewShell().InsertCells( eCmd );
363
0
    }
364
0
}
365
366
bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const
367
0
{
368
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
369
0
}
370
371
ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell& rNewDocShell,
372
                                const ScRange& rRange,
373
                                SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
374
                                DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
375
0
    ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
376
0
    aEffRange( rRange ),
377
0
    nCount( nNewCount ),
378
0
    pTabs( std::move(pNewTabs) ),
379
0
    pScenarios( std::move(pNewScenarios) ),
380
0
    eCmd( eNewCmd )
381
0
{
382
0
    ScDocument& rDoc = rDocShell.GetDocument();
383
0
    if (eCmd == DelCellCmd::Rows)            // whole row?
384
0
    {
385
0
        aEffRange.aStart.SetCol(0);
386
0
        aEffRange.aEnd.SetCol(rDoc.MaxCol());
387
0
    }
388
389
0
    if (eCmd == DelCellCmd::Cols)            // whole column?
390
0
    {
391
0
        aEffRange.aStart.SetRow(0);
392
0
        aEffRange.aEnd.SetRow(rDoc.MaxRow());
393
0
    }
394
395
0
    SetChangeTrack();
396
0
}
397
398
ScUndoDeleteCells::~ScUndoDeleteCells()
399
0
{
400
0
}
401
402
OUString ScUndoDeleteCells::GetComment() const
403
0
{
404
0
    return ScResId( STR_UNDO_DELETECELLS ); // "Delete"
405
0
}
406
407
void ScUndoDeleteCells::SetChangeTrack()
408
0
{
409
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
410
0
    if ( pChangeTrack )
411
0
        pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(),
412
0
            nStartChangeAction, nEndChangeAction );
413
0
    else
414
0
        nStartChangeAction = nEndChangeAction = 0;
415
0
}
416
417
void ScUndoDeleteCells::DoChange( const bool bUndo )
418
0
{
419
0
    ScDocument& rDoc = rDocShell.GetDocument();
420
0
    SCTAB i;
421
422
0
    if ( bUndo )
423
0
    {
424
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
425
0
        if ( pChangeTrack )
426
0
            pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
427
0
    }
428
0
    else
429
0
        SetChangeTrack();
430
431
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
432
433
0
    switch (eCmd)
434
0
    {
435
0
        case DelCellCmd::Rows:
436
0
        case DelCellCmd::CellsUp:
437
0
            for( i=0; i<nCount; i++ )
438
0
            {
439
0
                if (bUndo)
440
0
                    rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
441
0
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
442
0
                else
443
0
                    rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
444
0
                    aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
445
446
0
                if (pViewShell)
447
0
                {
448
0
                    const tools::Long nSign = bUndo ? 1 : -1;
449
0
                    pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
450
0
                }
451
0
            }
452
0
            break;
453
0
        case DelCellCmd::Cols:
454
0
        case DelCellCmd::CellsLeft:
455
0
            for( i=0; i<nCount; i++ )
456
0
            {
457
0
                if (bUndo)
458
0
                    rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
459
0
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
460
0
                else
461
0
                    rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
462
0
                    aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
463
464
0
                if (pViewShell)
465
0
                {
466
0
                    const tools::Long nSign = bUndo ? 1 : -1;
467
0
                    pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
468
0
                }
469
0
            }
470
0
            break;
471
0
        default:
472
0
        {
473
            // added to avoid warnings
474
0
        }
475
0
    }
476
477
    // if Undo, restore references
478
0
    for( i=0; i<nCount && bUndo; i++ )
479
0
    {
480
0
        pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
481
0
            InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc);
482
0
    }
483
484
    // Refresh after all cell operations are done.
485
0
    if (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft)
486
0
    {
487
0
        for (i = 0; i < nCount; i++)
488
0
            refreshAutoFilterForColumnChange(rDoc, pTabs[i]);
489
0
    }
490
491
0
    ScRange aWorkRange( aEffRange );
492
0
    if ( eCmd == DelCellCmd::CellsLeft )        // only "shift left" requires refresh of the moved area
493
0
        aWorkRange.aEnd.SetCol(rDoc.MaxCol());
494
495
0
    for( i=0; i<nCount; i++ )
496
0
    {
497
0
        if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
498
0
            aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
499
0
        {
500
            // #i51445# old merge flag attributes must be deleted also for single cells,
501
            // not only for whole columns/rows
502
503
0
            if ( !bUndo )
504
0
            {
505
0
                if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
506
0
                    aWorkRange.aEnd.SetCol(rDoc.MaxCol());
507
0
                if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
508
0
                    aWorkRange.aEnd.SetRow(rDoc.MaxRow());
509
0
                ScMarkData aMarkData(rDoc.GetSheetLimits());
510
0
                aMarkData.SelectOneTable( aWorkRange.aStart.Tab() );
511
0
                ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
512
0
                aPattern.ItemSetPut(ScMergeFlagAttr());
513
0
                rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(),
514
0
                    aWorkRange.aEnd.Col(),   aWorkRange.aEnd.Row(),
515
0
                    aMarkData, aPattern );
516
0
            }
517
518
0
            SCCOL nEndCol = aWorkRange.aEnd.Col();
519
0
            SCROW nEndRow = aWorkRange.aEnd.Row();
520
0
            rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
521
0
        }
522
0
    }
523
524
    // paint
525
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
526
0
    switch (eCmd)
527
0
    {
528
0
        case DelCellCmd::Rows:
529
0
            nPaint |= PaintPartFlags::Left;
530
0
            aWorkRange.aEnd.SetRow(rDoc.MaxRow());
531
0
            break;
532
0
        case DelCellCmd::CellsUp:
533
0
            for( i=0; i<nCount; i++ )
534
0
            {
535
0
                aWorkRange.aEnd.SetRow(rDoc.MaxRow());
536
0
                if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
537
0
                {
538
0
                    aWorkRange.aStart.SetCol(0);
539
0
                    aWorkRange.aEnd.SetCol(rDoc.MaxCol());
540
0
                    nPaint |= PaintPartFlags::Left;
541
0
                }
542
0
            }
543
0
            break;
544
0
        case DelCellCmd::Cols:
545
0
            nPaint |= PaintPartFlags::Top;                // top bar
546
0
            [[fallthrough]];
547
0
        case DelCellCmd::CellsLeft:
548
0
            for( i=0; i<nCount; i++ )
549
0
            {
550
0
                aWorkRange.aEnd.SetCol(rDoc.MaxCol());     // to the far right
551
0
                if ( rDocShell.AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) )
552
0
                {
553
0
                    aWorkRange.aStart.SetCol(0);
554
0
                    aWorkRange.aEnd.SetRow(rDoc.MaxRow());
555
0
                    nPaint |= PaintPartFlags::Left;
556
0
                }
557
0
            }
558
0
            break;
559
0
        default:
560
0
        {
561
            // added to avoid warnings
562
0
        }
563
0
    }
564
565
0
    for( i=0; i<nCount; i++ )
566
0
    {
567
0
        rDocShell.PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
568
0
            aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES );
569
0
    }
570
    // Selection not until EndUndo
571
572
0
    rDocShell.PostDataChanged();
573
    //  CellContentChanged comes with the selection
574
575
0
    if (!pViewShell)
576
0
        return;
577
578
0
    if (!comphelper::LibreOfficeKit::isActive())
579
0
        return;
580
581
0
    SCTAB nTab = pViewShell->GetViewData().GetTabNumber();
582
0
    bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft);
583
0
    bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp);
584
585
0
    if (bColsAffected)
586
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
587
588
0
    if (bRowsAffected)
589
0
        ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
590
591
0
    ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
592
0
            pViewShell,
593
0
            bColsAffected, bRowsAffected,
594
0
            true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
595
0
            true /* bGroups */, nTab);
596
597
0
}
598
599
void ScUndoDeleteCells::Undo()
600
0
{
601
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important because of TrackFormulas in UpdateReference
602
0
    BeginUndo();
603
0
    DoChange( true );
604
605
0
    sc::UndoSheetViewSortData::restore(rDocShell, true);
606
607
0
    EndUndo();
608
609
0
    ScDocument& rDoc = rDocShell.GetDocument();
610
611
    // Now that DBData have been restored in ScMoveUndo::EndUndo() via its
612
    // pRefUndoDoc we can apply the AutoFilter buttons.
613
    // Add one row for cases undoing deletion right above a cut AutoFilter
614
    // range so the buttons are removed.
615
0
    SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow());
616
0
    for (SCTAB i=0; i < nCount; ++i)
617
0
    {
618
0
        rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
619
0
                aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]);
620
0
    }
621
622
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
623
624
    // Selection not until EndUndo
625
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
626
0
    if (pViewShell)
627
0
    {
628
0
        for( SCTAB i=0; i<nCount; i++ )
629
0
        {
630
0
            pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) );
631
0
        }
632
0
    }
633
634
0
    for (SCTAB i = 0; i < nCount; ++i)
635
0
        rDoc.SetDrawPageSize(pTabs[i]);
636
0
}
637
638
void ScUndoDeleteCells::Redo()
639
0
{
640
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important because of TrackFormulas in UpdateReference
641
0
    BeginRedo();
642
0
    DoChange( false);
643
644
0
    sc::UndoSheetViewSortData::restore(rDocShell, false);
645
646
0
    EndRedo();
647
648
0
    ScDocument& rDoc = rDocShell.GetDocument();
649
650
0
    for (SCTAB i=0; i < nCount; ++i)
651
0
    {
652
0
        rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
653
0
                aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]);
654
0
    }
655
656
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
657
658
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
659
0
    if (pViewShell)
660
0
        pViewShell->DoneBlockMode();            // current way
661
662
0
    for (SCTAB i = 0; i < nCount; ++i)
663
0
        rDoc.SetDrawPageSize(pTabs[i]);
664
0
}
665
666
void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget)
667
0
{
668
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
669
0
        pViewTarget->GetViewShell().DeleteCells( eCmd );
670
0
}
671
672
bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const
673
0
{
674
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
675
0
}
676
677
// delete cells in multiselection
678
ScUndoDeleteMulti::ScUndoDeleteMulti(
679
    ScDocShell& rNewDocShell,
680
    bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
681
    std::vector<sc::ColRowSpan>&& rSpans,
682
    ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
683
0
    ScMoveUndo( rNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
684
0
    mbRows(bNewRows),
685
0
    mbRefresh(bNeedsRefresh),
686
0
    nTab( nNewTab ),
687
0
    maSpans(std::move(rSpans))
688
0
{
689
0
    SetChangeTrack();
690
0
}
691
692
ScUndoDeleteMulti::~ScUndoDeleteMulti()
693
0
{
694
0
}
695
696
OUString ScUndoDeleteMulti::GetComment() const
697
0
{
698
0
    return ScResId( STR_UNDO_DELETECELLS );  // like DeleteCells
699
0
}
700
701
void ScUndoDeleteMulti::DoChange() const
702
0
{
703
0
    SCCOL nStartCol;
704
0
    SCROW nStartRow;
705
0
    PaintPartFlags nPaint;
706
0
    ScDocument& rDoc = rDocShell.GetDocument();
707
0
    if (mbRows)
708
0
    {
709
0
        nStartCol = 0;
710
0
        nStartRow = static_cast<SCROW>(maSpans[0].mnStart);
711
0
        nPaint = PaintPartFlags::Grid | PaintPartFlags::Left;
712
0
    }
713
0
    else
714
0
    {
715
0
        nStartCol = static_cast<SCCOL>(maSpans[0].mnStart);
716
0
        nStartRow = 0;
717
0
        nPaint = PaintPartFlags::Grid | PaintPartFlags::Top;
718
0
    }
719
720
0
    if (mbRefresh)
721
0
    {
722
0
        SCCOL nEndCol = rDoc.MaxCol();
723
0
        SCROW nEndRow = rDoc.MaxRow();
724
0
        rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
725
0
        rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
726
0
    }
727
728
0
    rDocShell.PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint );
729
0
    rDocShell.PostDataChanged();
730
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
731
0
    if (pViewShell)
732
0
        pViewShell->CellContentChanged();
733
734
0
    ShowTable( nTab );
735
0
}
736
737
void ScUndoDeleteMulti::SetChangeTrack()
738
0
{
739
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
740
0
    if ( pChangeTrack )
741
0
    {
742
0
        ScDocument& rDoc = rDocShell.GetDocument();
743
0
        nStartChangeAction = pChangeTrack->GetActionMax() + 1;
744
0
        ScRange aRange( 0, 0, nTab, 0, 0, nTab );
745
0
        if (mbRows)
746
0
            aRange.aEnd.SetCol( rDoc.MaxCol() );
747
0
        else
748
0
            aRange.aEnd.SetRow( rDoc.MaxRow() );
749
        // delete in reverse
750
0
        std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
751
0
        for (; ri != riEnd; ++ri)
752
0
        {
753
0
            SCCOLROW nEnd = ri->mnEnd;
754
0
            SCCOLROW nStart = ri->mnStart;
755
0
            if (mbRows)
756
0
            {
757
0
                aRange.aStart.SetRow( nStart );
758
0
                aRange.aEnd.SetRow( nEnd );
759
0
            }
760
0
            else
761
0
            {
762
0
                aRange.aStart.SetCol( static_cast<SCCOL>(nStart) );
763
0
                aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) );
764
0
            }
765
0
            sal_uLong nDummyStart;
766
0
            pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
767
0
                nDummyStart, nEndChangeAction );
768
0
        }
769
0
    }
770
0
    else
771
0
        nStartChangeAction = nEndChangeAction = 0;
772
0
}
773
774
void ScUndoDeleteMulti::Undo()
775
0
{
776
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important because of TrackFormulas in UpdateReference
777
0
    BeginUndo();
778
779
0
    ScDocument& rDoc = rDocShell.GetDocument();
780
781
    // reverse delete -> forward insert
782
0
    for (const auto& rSpan : maSpans)
783
0
    {
784
0
        SCCOLROW nStart = rSpan.mnStart;
785
0
        SCCOLROW nEnd = rSpan.mnEnd;
786
0
        if (mbRows)
787
0
            rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
788
0
        else
789
0
            rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
790
0
    }
791
792
0
    for (const auto& rSpan : maSpans)
793
0
    {
794
0
        SCCOLROW nStart = rSpan.mnStart;
795
0
        SCCOLROW nEnd = rSpan.mnEnd;
796
0
        if (mbRows)
797
0
            pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc);
798
0
        else
799
0
            pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab,
800
0
                    static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc);
801
0
    }
802
803
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
804
0
    if ( pChangeTrack )
805
0
        pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
806
807
0
    DoChange();
808
809
    //! redrawing the selection is not possible at the moment
810
    //! since no data for selection exist
811
812
0
    EndUndo();
813
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
814
0
}
815
816
void ScUndoDeleteMulti::Redo()
817
0
{
818
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );     // important because of TrackFormulas in UpdateReference
819
0
    BeginRedo();
820
821
0
    ScDocument& rDoc = rDocShell.GetDocument();
822
823
    // reverse delete
824
0
    std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
825
0
    for (; ri != riEnd; ++ri)
826
0
    {
827
0
        SCCOLROW nEnd = ri->mnEnd;
828
0
        SCCOLROW nStart = ri->mnStart;
829
0
        if (mbRows)
830
0
            rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
831
0
        else
832
0
            rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
833
0
    }
834
835
0
    SetChangeTrack();
836
837
0
    DoChange();
838
839
0
    EndRedo();
840
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
841
0
}
842
843
void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget)
844
0
{
845
    // if single selection
846
0
    if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
847
0
        pTabViewTarget->GetViewShell().DeleteCells( DelCellCmd::Rows );
848
0
}
849
850
bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const
851
0
{
852
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
853
0
}
854
855
ScUndoCut::ScUndoCut(ScDocShell& rNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd,
856
                     const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc)
857
0
    : ScBlockUndo(rNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT)
858
0
    , aMarkData(rMark)
859
0
    , pUndoDoc(std::move(pNewUndoDoc))
860
0
    , aExtendedRange(aRange)
861
0
{
862
0
    SetChangeTrack();
863
0
}
864
865
ScUndoCut::~ScUndoCut()
866
0
{
867
0
}
868
869
OUString ScUndoCut::GetComment() const
870
0
{
871
0
    return ScResId( STR_UNDO_CUT ); // "cut"
872
0
}
873
874
void ScUndoCut::SetChangeTrack()
875
0
{
876
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
877
0
    if ( pChangeTrack )
878
0
        pChangeTrack->AppendContentRange( aBlockRange, *pUndoDoc,
879
0
            nStartChangeAction, nEndChangeAction, SC_CACM_CUT );
880
0
    else
881
0
        nStartChangeAction = nEndChangeAction = 0;
882
0
}
883
884
void ScUndoCut::DoChange( const bool bUndo )
885
0
{
886
0
    ScDocument& rDoc = rDocShell.GetDocument();
887
0
    sal_uInt16 nExtFlags = 0;
888
889
    // do not undo/redo objects and note captions, they are handled via drawing undo
890
0
    InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
891
892
0
    if (bUndo)  // only for Undo
893
0
    {
894
        //  all sheets - CopyToDocument skips those that don't exist in pUndoDoc
895
0
        SCTAB nTabCount = rDoc.GetTableCount();
896
0
        ScRange aCopyRange = aExtendedRange;
897
0
        aCopyRange.aStart.SetTab(0);
898
0
        aCopyRange.aEnd.SetTab(nTabCount-1);
899
0
        pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc);
900
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
901
0
        if ( pChangeTrack )
902
0
            pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
903
904
0
        BroadcastChanges(aCopyRange);
905
0
    }
906
0
    else        // only for Redo
907
0
    {
908
0
        rDocShell.UpdatePaintExt( nExtFlags, aExtendedRange );
909
0
        rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
910
0
                          aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags );
911
0
        SetChangeTrack();
912
0
    }
913
914
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
915
0
    if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
916
0
/*A*/   rDocShell.PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
917
918
0
    if ( !bUndo )                               //   draw redo after updating row heights
919
0
        RedoSdrUndoAction( pDrawUndo.get() );         //! include in ScBlockUndo?
920
921
0
    rDocShell.PostDataChanged();
922
0
    if (pViewShell)
923
0
        pViewShell->CellContentChanged();
924
0
}
925
926
void ScUndoCut::Undo()
927
0
{
928
0
    BeginUndo();
929
0
    DoChange( true );
930
0
    EndUndo();
931
0
}
932
933
void ScUndoCut::Redo()
934
0
{
935
0
    BeginRedo();
936
0
    ScDocument& rDoc = rDocShell.GetDocument();
937
0
    EnableDrawAdjust( &rDoc, false );                //! include in ScBlockUndo?
938
0
    DoChange( false );
939
0
    EnableDrawAdjust( &rDoc, true );                 //! include in ScBlockUndo?
940
0
    EndRedo();
941
0
}
942
943
void ScUndoCut::Repeat(SfxRepeatTarget& rTarget)
944
0
{
945
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
946
0
        pViewTarget->GetViewShell().CutToClip();
947
0
}
948
949
bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const
950
0
{
951
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
952
0
}
953
954
ScUndoPaste::ScUndoPaste( ScDocShell& rNewDocShell, const ScRangeList& rRanges,
955
                const ScMarkData& rMark,
956
                ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
957
                InsertDeleteFlags nNewFlags,
958
                std::unique_ptr<ScRefUndoData> pRefData,
959
                bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) :
960
0
    ScMultiBlockUndo( rNewDocShell, rRanges ),
961
0
    aMarkData( rMark ),
962
0
    pUndoDoc( std::move(pNewUndoDoc) ),
963
0
    pRedoDoc( std::move(pNewRedoDoc) ),
964
0
    nFlags( nNewFlags ),
965
0
    pRefUndoData( std::move(pRefData) ),
966
0
    bRedoFilled( bRedoIsFilled )
967
0
{
968
0
    if ( pRefUndoData )
969
0
        pRefUndoData->DeleteUnchanged( rDocShell.GetDocument() );
970
971
0
    if ( pOptions )
972
0
        aPasteOptions = *pOptions;      // used only for Repeat
973
974
0
    SetChangeTrack();
975
0
}
976
977
ScUndoPaste::~ScUndoPaste()
978
0
{
979
0
    pUndoDoc.reset();
980
0
    pRedoDoc.reset();
981
0
    pRefUndoData.reset();
982
0
    pRefRedoData.reset();
983
0
}
984
985
OUString ScUndoPaste::GetComment() const
986
0
{
987
0
    return ScResId( STR_UNDO_PASTE ); // "paste"
988
0
}
989
990
void ScUndoPaste::SetChangeTrack()
991
0
{
992
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
993
0
    if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
994
0
    {
995
0
        for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
996
0
        {
997
0
            pChangeTrack->AppendContentRange(maBlockRanges[i], *pUndoDoc,
998
0
                nStartChangeAction, nEndChangeAction, SC_CACM_PASTE );
999
0
        }
1000
0
    }
1001
0
    else
1002
0
        nStartChangeAction = nEndChangeAction = 0;
1003
0
}
1004
1005
void ScUndoPaste::DoChange(bool bUndo)
1006
0
{
1007
0
    ScDocument& rDoc = rDocShell.GetDocument();
1008
1009
    //  RefUndoData for redo is created before first undo
1010
    //  (with DeleteUnchanged after the DoUndo call)
1011
0
    bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData );
1012
0
    if ( bCreateRedoData )
1013
0
        pRefRedoData.reset( new ScRefUndoData( rDoc ) );
1014
1015
0
    ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get();
1016
1017
    // Always back-up either all or none of the content for Undo
1018
0
    InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE;
1019
0
    if (nFlags & InsertDeleteFlags::CONTENTS)
1020
0
        nUndoFlags |= InsertDeleteFlags::CONTENTS;
1021
0
    if (nFlags & InsertDeleteFlags::ATTRIB)
1022
0
        nUndoFlags |= InsertDeleteFlags::ATTRIB;
1023
1024
    // do not undo/redo objects and note captions, they are handled via drawing undo
1025
0
    nUndoFlags &= ~InsertDeleteFlags::OBJECTS;
1026
0
    nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
1027
1028
0
    bool bPaintAll = false;
1029
1030
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1031
1032
0
    SCTAB nTabCount = rDoc.GetTableCount();
1033
0
    if ( bUndo && !bRedoFilled )
1034
0
    {
1035
0
        if (!pRedoDoc)
1036
0
        {
1037
0
            bool bColInfo = true;
1038
0
            bool bRowInfo = true;
1039
0
            for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1040
0
            {
1041
0
                const ScRange& r = maBlockRanges[i];
1042
0
                bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow());
1043
0
                bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol());
1044
0
                if (!bColInfo && !bRowInfo)
1045
0
                    break;
1046
0
            }
1047
1048
0
            pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
1049
0
            pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo );
1050
0
        }
1051
        //  read "redo" data from the document in the first undo
1052
        //  all sheets - CopyToDocument skips those that don't exist in pRedoDoc
1053
0
        for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1054
0
        {
1055
0
            ScRange aCopyRange = maBlockRanges[i];
1056
0
            aCopyRange.aStart.SetTab(0);
1057
0
            aCopyRange.aEnd.SetTab(nTabCount-1);
1058
0
            rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc);
1059
0
            bRedoFilled = true;
1060
0
        }
1061
0
    }
1062
1063
0
    sal_uInt16 nExtFlags = 0;
1064
0
    rDocShell.UpdatePaintExt(nExtFlags, maBlockRanges.Combine());
1065
    // tdf#167042 - cell comments texts should not be deleted but
1066
    // the note text should be remembered in maNoteData to be able
1067
    // to later reconstruct a caption from it.
1068
0
    rDoc.ForgetNoteCaptions(maBlockRanges, true);
1069
0
    aMarkData.MarkToMulti();
1070
0
    rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here
1071
0
    for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1072
0
        rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged);
1073
1074
0
    aMarkData.MarkToSimple();
1075
1076
0
    SCTAB nFirstSelected = aMarkData.GetFirstSelected();
1077
1078
0
    if ( !bUndo && pRedoDoc )       // Redo: UndoToDocument before handling RefData
1079
0
    {
1080
0
        for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1081
0
        {
1082
0
            ScRange aRange = maBlockRanges[i];
1083
0
            aRange.aStart.SetTab(nFirstSelected);
1084
0
            aRange.aEnd.SetTab(nFirstSelected);
1085
0
            pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
1086
0
            for (const auto& rTab : aMarkData)
1087
0
            {
1088
0
                if (rTab >= nTabCount)
1089
0
                    break;
1090
1091
0
                if (rTab == nFirstSelected)
1092
0
                    continue;
1093
1094
0
                aRange.aStart.SetTab(rTab);
1095
0
                aRange.aEnd.SetTab(rTab);
1096
0
                pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
1097
0
            }
1098
0
        }
1099
0
    }
1100
1101
0
    if (pWorkRefData)
1102
0
    {
1103
0
        pWorkRefData->DoUndo( rDoc, true );     // true = bSetChartRangeLists for SetChartListenerCollection
1104
0
        if (!maBlockRanges.empty() &&
1105
0
            rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab()))
1106
0
            bPaintAll = true;
1107
0
    }
1108
1109
0
    if ( bCreateRedoData && pRefRedoData )
1110
0
        pRefRedoData->DeleteUnchanged( rDoc );
1111
1112
0
    if (bUndo)      // Undo: UndoToDocument after handling RefData
1113
0
    {
1114
0
        for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1115
0
        {
1116
0
            ScRange aRange = maBlockRanges[i];
1117
0
            for (const auto& rTab : aMarkData)
1118
0
            {
1119
0
                if (rTab >= nTabCount)
1120
0
                    break;
1121
0
                aRange.aStart.SetTab(rTab);
1122
0
                aRange.aEnd.SetTab(rTab);
1123
0
                pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
1124
0
            }
1125
0
        }
1126
0
    }
1127
1128
0
    if ( bUndo )
1129
0
    {
1130
0
        ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1131
0
        if ( pChangeTrack )
1132
0
            pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
1133
0
    }
1134
0
    else
1135
0
        SetChangeTrack();
1136
1137
0
    ScRangeList aDrawRanges(maBlockRanges);
1138
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1139
1140
    // For sheet geometry invalidation.
1141
0
    bool bColsAffected = false;
1142
0
    bool bRowsAffected = false;
1143
1144
0
    for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i)
1145
0
    {
1146
0
        ScRange& rDrawRange = aDrawRanges[i];
1147
0
        rDoc.ExtendMerge(rDrawRange, true);      // only needed for single sheet (text/rtf etc.)
1148
0
        ScRangeList aRangeList(rDrawRange);
1149
0
        ScMarkData aData(rDoc.GetSheetLimits(), aRangeList);
1150
0
        if (bPaintAll)
1151
0
        {
1152
0
            rDrawRange.aStart.SetCol(0);
1153
0
            rDrawRange.aStart.SetRow(0);
1154
0
            rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1155
0
            rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1156
0
            nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
1157
0
            if (pViewShell)
1158
0
                pViewShell->AdjustBlockHeight(false, &aData);
1159
0
        }
1160
0
        else
1161
0
        {
1162
0
            if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column
1163
0
            {
1164
0
                nPaint |= PaintPartFlags::Top;
1165
0
                rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1166
0
                bColsAffected = true;
1167
0
            }
1168
0
            if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row
1169
0
            {
1170
0
                nPaint |= PaintPartFlags::Left;
1171
0
                rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1172
0
                bRowsAffected = true;
1173
0
            }
1174
0
            if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData))
1175
0
            {
1176
0
                rDrawRange.aStart.SetCol(0);
1177
0
                rDrawRange.aStart.SetRow(0);
1178
0
                rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1179
0
                rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1180
0
                nPaint |= PaintPartFlags::Left;
1181
0
            }
1182
0
            rDocShell.UpdatePaintExt(nExtFlags, rDrawRange);
1183
0
        }
1184
0
    }
1185
1186
0
    if ( !bUndo )                               //   draw redo after updating row heights
1187
0
        RedoSdrUndoAction(mpDrawUndo.get());
1188
1189
0
    rDocShell.PostPaint(aDrawRanges, nPaint, nExtFlags);
1190
1191
0
    rDocShell.PostDataChanged();
1192
0
    if (!pViewShell)
1193
0
        return;
1194
1195
0
    pViewShell->CellContentChanged();
1196
1197
0
    if (bColsAffected || bRowsAffected)
1198
0
        ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1199
0
            pViewShell,
1200
0
            bColsAffected, bRowsAffected,
1201
0
            true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
1202
0
            true /* bGroups */, aDrawRanges[0].aStart.Tab());
1203
0
}
1204
1205
void ScUndoPaste::Undo()
1206
0
{
1207
0
    BeginUndo();
1208
0
    DoChange(true);
1209
0
    if (!maBlockRanges.empty())
1210
0
        ShowTable(maBlockRanges.front());
1211
0
    EndUndo();
1212
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1213
0
}
1214
1215
void ScUndoPaste::Redo()
1216
0
{
1217
0
    BeginRedo();
1218
0
    ScDocument& rDoc = rDocShell.GetDocument();
1219
0
    EnableDrawAdjust( &rDoc, false );                //! include in ScBlockUndo?
1220
0
    DoChange( false );
1221
0
    EnableDrawAdjust( &rDoc, true );                 //! include in ScBlockUndo?
1222
0
    EndRedo();
1223
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1224
0
}
1225
1226
void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
1227
0
{
1228
0
    auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget);
1229
0
    if (!pViewTarget)
1230
0
        return;
1231
1232
0
    ScTabViewShell& rViewSh = pViewTarget->GetViewShell();
1233
    // keep a reference in case the clipboard is changed during PasteFromClip
1234
0
    const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewSh.GetViewData().GetActiveWin()));
1235
0
    if (pOwnClip)
1236
0
    {
1237
0
        rViewSh.PasteFromClip( nFlags, pOwnClip->GetDocument(),
1238
0
                                aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
1239
0
                                aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
1240
0
                                true );     // allow warning dialog
1241
0
    }
1242
0
}
1243
1244
bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const
1245
0
{
1246
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
1247
0
}
1248
1249
ScUndoDragDrop::ScUndoDragDrop( ScDocShell& rNewDocShell,
1250
                    const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
1251
                    ScDocumentUniquePtr pUndoDocument, bool bScenario ) :
1252
0
    ScMoveUndo( rNewDocShell, std::move(pUndoDocument), nullptr ),
1253
0
    mnPaintExtFlags( 0 ),
1254
0
    aSrcRange( rRange ),
1255
0
    bCut( bNewCut ),
1256
0
    bKeepScenarioFlags( bScenario )
1257
0
{
1258
0
    ScAddress aDestEnd(aNewDestPos);
1259
0
    aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row());
1260
0
    aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col());
1261
0
    aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab());
1262
1263
0
    bool bIncludeFiltered = bCut;
1264
0
    if ( !bIncludeFiltered )
1265
0
    {
1266
        // find number of non-filtered rows
1267
0
        SCROW nPastedCount = rDocShell.GetDocument().CountNonFilteredRows(
1268
0
            aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab());
1269
1270
0
        if ( nPastedCount == 0 )
1271
0
            nPastedCount = 1;
1272
0
        aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 );
1273
0
    }
1274
1275
0
    aDestRange.aStart = aNewDestPos;
1276
0
    aDestRange.aEnd = aDestEnd;
1277
1278
0
    SetChangeTrack();
1279
0
}
1280
1281
ScUndoDragDrop::~ScUndoDragDrop()
1282
0
{
1283
0
}
1284
1285
OUString ScUndoDragDrop::GetComment() const
1286
0
{   // "Move" : "Copy"
1287
0
    return bCut ?
1288
0
        ScResId( STR_UNDO_MOVE ) :
1289
0
        ScResId( STR_UNDO_COPY );
1290
0
}
1291
1292
void ScUndoDragDrop::SetChangeTrack()
1293
0
{
1294
0
    ScChangeTrack* pChangeTrack = rDocShell.GetDocument().GetChangeTrack();
1295
0
    if ( pChangeTrack )
1296
0
    {
1297
0
        if ( bCut )
1298
0
        {
1299
0
            nStartChangeAction = pChangeTrack->GetActionMax() + 1;
1300
0
            pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() );
1301
0
            nEndChangeAction = pChangeTrack->GetActionMax();
1302
0
        }
1303
0
        else
1304
0
            pChangeTrack->AppendContentRange( aDestRange, *pRefUndoDoc,
1305
0
                nStartChangeAction, nEndChangeAction );
1306
0
    }
1307
0
    else
1308
0
        nStartChangeAction = nEndChangeAction = 0;
1309
0
}
1310
1311
void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
1312
0
{
1313
0
    PaintPartFlags nPaint = PaintPartFlags::Grid;
1314
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1315
0
    ScDocument& rDoc = rDocShell.GetDocument();
1316
1317
0
    if (pViewShell)
1318
0
    {
1319
0
        ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1320
0
        ScViewData& rViewData = pViewShell->GetViewData();
1321
0
        sc::RowHeightContext aCxt(
1322
0
            rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(),
1323
0
            pVirtDev);
1324
1325
0
        if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true))
1326
0
        {
1327
            // tdf#76183: recalculate objects' positions
1328
0
            rDoc.SetDrawPageSize(aRange.aStart.Tab());
1329
0
            aRange.aStart.SetCol(0);
1330
0
            aRange.aEnd.SetCol(rDoc.MaxCol());
1331
0
            aRange.aEnd.SetRow(rDoc.MaxRow());
1332
0
            nPaint |= PaintPartFlags::Left;
1333
0
        }
1334
0
    }
1335
1336
0
    if ( bKeepScenarioFlags )
1337
0
    {
1338
        //  Copy scenario -> also paint scenario boarder
1339
0
        aRange.aStart.SetCol(0);
1340
0
        aRange.aStart.SetRow(0);
1341
0
        aRange.aEnd.SetCol(rDoc.MaxCol());
1342
0
        aRange.aEnd.SetRow(rDoc.MaxRow());
1343
0
    }
1344
1345
    //  column/row info (width/height) included if whole columns/rows were copied
1346
0
    if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() )
1347
0
    {
1348
0
        nPaint |= PaintPartFlags::Left;
1349
0
        aRange.aEnd.SetRow(rDoc.MaxRow());
1350
0
    }
1351
0
    if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() )
1352
0
    {
1353
0
        nPaint |= PaintPartFlags::Top;
1354
0
        aRange.aEnd.SetCol(rDoc.MaxCol());
1355
0
    }
1356
1357
0
    rDocShell.PostPaint( aRange, nPaint, nExtFlags );
1358
0
}
1359
1360
void ScUndoDragDrop::DoUndo( ScRange aRange )
1361
0
{
1362
0
    ScDocument& rDoc = rDocShell.GetDocument();
1363
1364
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1365
0
    if ( pChangeTrack )
1366
0
        pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
1367
1368
    // Database range before data, so that the Autofilter button match up in ExtendMerge
1369
1370
0
    ScRange aPaintRange = aRange;
1371
0
    rDoc.ExtendMerge( aPaintRange );           // before deleting
1372
1373
0
    rDocShell.UpdatePaintExt(mnPaintExtFlags, aPaintRange);
1374
1375
    // do not undo objects and note captions, they are handled via drawing undo
1376
0
    InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
1377
1378
    // Additionally discard/forget caption ownership during deletion, as
1379
    // Drag&Drop is a special case in that the Undo holds captions of the
1380
    // transferred target range, which would get deleted and
1381
    // SdrGroupUndo::Undo() would attempt to access invalidated captions and
1382
    // crash, tdf#92995
1383
0
    InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS;
1384
1385
0
    rDoc.DeleteAreaTab( aRange, nDelFlags );
1386
0
    pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
1387
0
    if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
1388
0
        rDoc.ExtendMerge( aRange, true );
1389
1390
0
    aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
1391
0
    aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
1392
1393
0
    rDocShell.UpdatePaintExt(mnPaintExtFlags, aPaintRange);
1394
0
    maPaintRanges.Join(aPaintRange);
1395
1396
0
    if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
1397
0
    {
1398
0
        if (comphelper::LibreOfficeKit::isActive())
1399
0
        {
1400
0
            pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Col(), true);
1401
0
            pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Row(), false);
1402
0
        }
1403
1404
0
        ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1405
0
            pTabViewShell,
1406
0
            true /* bColumns */, true /* bRows */,
1407
0
            true /* bSizes */, true /* bHidden */, true /* bFiltered */,
1408
0
            true /* bGroups */, aPaintRange.aStart.Tab());
1409
0
    }
1410
1411
0
}
1412
1413
void ScUndoDragDrop::Undo()
1414
0
{
1415
0
    mnPaintExtFlags = 0;
1416
0
    maPaintRanges.RemoveAll();
1417
1418
0
    BeginUndo();
1419
1420
0
    if (bCut)
1421
0
    {
1422
        // During undo, we move cells from aDestRange to aSrcRange.
1423
1424
0
        ScDocument& rDoc = rDocShell.GetDocument();
1425
1426
0
        SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
1427
0
        SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
1428
0
        SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
1429
1430
0
        sc::RefUpdateContext aCxt(rDoc);
1431
0
        aCxt.meMode = URM_MOVE;
1432
0
        aCxt.maRange = aSrcRange;
1433
0
        aCxt.mnColDelta = nColDelta;
1434
0
        aCxt.mnRowDelta = nRowDelta;
1435
0
        aCxt.mnTabDelta = nTabDelta;
1436
1437
        // Global range names.
1438
0
        ScRangeName& rName = rDoc.GetRangeName();
1439
0
        rName.UpdateReference(aCxt);
1440
1441
0
        SCTAB nTabCount = rDoc.GetTableCount();
1442
0
        for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
1443
0
        {
1444
            // Sheet-local range names.
1445
0
            ScRangeName* pName = rDoc.GetRangeName(nTab);
1446
0
            if (pName)
1447
0
                pName->UpdateReference(aCxt, nTab);
1448
0
        }
1449
1450
0
        ScValidationDataList* pValidList = rDoc.GetValidationList();
1451
0
        if (pValidList)
1452
0
        {
1453
            // Update the references of validation entries.
1454
0
            pValidList->UpdateReference(aCxt);
1455
0
        }
1456
1457
0
        DoUndo(aDestRange);
1458
0
        DoUndo(aSrcRange);
1459
1460
0
        rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false);
1461
0
    }
1462
0
    else
1463
0
        DoUndo(aDestRange);
1464
1465
0
    for (size_t i = 0; i < maPaintRanges.size(); ++i)
1466
0
    {
1467
0
        const ScRange& r = maPaintRanges[i];
1468
0
        PaintArea(r, mnPaintExtFlags);
1469
0
    }
1470
1471
0
    EndUndo();
1472
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1473
0
}
1474
1475
void ScUndoDragDrop::Redo()
1476
0
{
1477
0
    BeginRedo();
1478
1479
0
    ScDocument& rDoc = rDocShell.GetDocument();
1480
0
    ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1481
1482
0
    EnableDrawAdjust( &rDoc, false );                //! include in ScBlockUndo?
1483
1484
    // do not undo/redo objects and note captions, they are handled via drawing undo
1485
0
    constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
1486
1487
    /*  TODO: Redoing note captions is quite tricky due to the fact that a
1488
        helper clip document is used. While (re-)pasting the contents to the
1489
        destination area, the original pointers to the captions created while
1490
        dropping have to be restored. A simple CopyFromClip() would create new
1491
        caption objects that are not tracked by drawing undo, and the captions
1492
        restored by drawing redo would live without cell note objects pointing
1493
        to them. So, first, CopyToClip() and CopyFromClip() are called without
1494
        cloning the caption objects. This leads to cell notes pointing to the
1495
        wrong captions from source area that will be removed by drawing redo
1496
        later. Second, the pointers to the new captions have to be restored.
1497
        Sadly, currently these pointers are not stored anywhere but in the list
1498
        of drawing undo actions. */
1499
1500
0
    SCTAB nTab;
1501
0
    ScMarkData aSourceMark(rDoc.GetSheetLimits());
1502
0
    for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
1503
0
        aSourceMark.SelectTable( nTab, true );
1504
1505
    // do not clone objects and note captions into clipdoc (see above)
1506
    // but at least copy notes
1507
0
    ScClipParam aClipParam(aSrcRange, bCut);
1508
0
    rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false);
1509
1510
0
    if (bCut)
1511
0
    {
1512
0
        ScRange aSrcPaintRange = aSrcRange;
1513
0
        rDoc.ExtendMerge( aSrcPaintRange );            // before deleting
1514
0
        sal_uInt16 nExtFlags = 0;
1515
0
        rDocShell.UpdatePaintExt( nExtFlags, aSrcPaintRange );
1516
0
        rDoc.DeleteAreaTab( aSrcRange, nRedoFlags );
1517
0
        PaintArea( aSrcPaintRange, nExtFlags );
1518
0
    }
1519
1520
0
    ScMarkData aDestMark(rDoc.GetSheetLimits());
1521
0
    for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
1522
0
        aDestMark.SelectTable( nTab, true );
1523
1524
0
    bool bIncludeFiltered = bCut;
1525
    // TODO: restore old note captions instead of cloning new captions...
1526
0
    rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
1527
1528
0
    if (bCut)
1529
0
        for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
1530
0
            rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(),
1531
0
                                     aSrcRange.aEnd.Col(),   aSrcRange.aEnd.Row(), nTab );
1532
1533
    // skipped rows and merged cells don't mix
1534
0
    if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1535
0
        rDocShell.GetDocFunc().UnmergeCells( aDestRange, false, nullptr );
1536
1537
0
    for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
1538
0
    {
1539
0
        SCCOL nEndCol = aDestRange.aEnd.Col();
1540
0
        SCROW nEndRow = aDestRange.aEnd.Row();
1541
0
        rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(),
1542
0
                            nEndCol, nEndRow, nTab, true );
1543
0
        PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab,
1544
0
                            nEndCol, nEndRow, nTab ), 0 );
1545
0
    }
1546
1547
0
    SetChangeTrack();
1548
1549
0
    pClipDoc.reset();
1550
0
    ShowTable( aDestRange.aStart.Tab() );
1551
1552
0
    RedoSdrUndoAction( pDrawUndo.get() );        //! include in ScBlockUndo?
1553
0
    EnableDrawAdjust( &rDoc, true );             //! include in ScBlockUndo?
1554
1555
0
    EndRedo();
1556
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1557
1558
0
    if (comphelper::LibreOfficeKit::isActive())
1559
0
    {
1560
0
        SCCOL nStartCol = aDestRange.aStart.Col();
1561
0
        SCROW nStartRow = aDestRange.aStart.Row();
1562
0
        if (bCut)
1563
0
        {
1564
0
            nStartCol = std::min(nStartCol, aSrcRange.aStart.Col());
1565
0
            nStartRow = std::min(nStartRow, aSrcRange.aStart.Row());
1566
0
        }
1567
1568
0
        if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
1569
0
        {
1570
0
            pTabViewShell->OnLOKSetWidthOrHeight(nStartCol, true);
1571
0
            pTabViewShell->OnLOKSetWidthOrHeight(nStartRow, false);
1572
1573
0
            SCTAB nStartTab = aDestRange.aStart.Tab();
1574
0
            SCTAB nEndTab = aDestRange.aEnd.Tab();
1575
0
            if (bCut)
1576
0
            {
1577
0
                nStartTab = std::min(nStartTab, aSrcRange.aStart.Tab());
1578
0
                nEndTab = std::max(nEndTab, aSrcRange.aEnd.Tab());
1579
0
            }
1580
0
            for (nTab = nStartTab; nTab <= nEndTab; ++nTab)
1581
0
            {
1582
0
                ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1583
0
                    pTabViewShell, true /* bColumns */, true /* bRows */,
1584
0
                    true /* bSizes */, true /* bHidden */, true /* bFiltered */, true /* bGroups */,
1585
0
                    nTab);
1586
0
            }
1587
0
        }
1588
0
    }
1589
0
}
1590
1591
void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */)
1592
0
{
1593
0
}
1594
1595
bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const
1596
0
{
1597
0
    return false;           // not possible
1598
0
}
1599
1600
// Insert list containing range names
1601
// (Insert|Name|Insert =>[List])
1602
ScUndoListNames::ScUndoListNames(ScDocShell& rNewDocShell, const ScRange& rRange,
1603
                                 ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc)
1604
0
    : ScBlockUndo(rNewDocShell, rRange, SC_UNDO_AUTOHEIGHT)
1605
0
    , xUndoDoc(std::move(pNewUndoDoc))
1606
0
    , xRedoDoc(std::move(pNewRedoDoc))
1607
0
{
1608
0
}
1609
1610
OUString ScUndoListNames::GetComment() const
1611
0
{
1612
0
    return ScResId( STR_UNDO_LISTNAMES );
1613
0
}
1614
1615
void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const
1616
0
{
1617
0
    ScDocument& rDoc = rDocShell.GetDocument();
1618
1619
0
    rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL );
1620
0
    pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc);
1621
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid );
1622
0
    rDocShell.PostDataChanged();
1623
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1624
0
    if (pViewShell)
1625
0
        pViewShell->CellContentChanged();
1626
0
}
1627
1628
void ScUndoListNames::Undo()
1629
0
{
1630
0
    BeginUndo();
1631
0
    DoChange(xUndoDoc.get());
1632
0
    EndUndo();
1633
0
}
1634
1635
void ScUndoListNames::Redo()
1636
0
{
1637
0
    BeginRedo();
1638
0
    DoChange(xRedoDoc.get());
1639
0
    EndRedo();
1640
0
}
1641
1642
void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget)
1643
0
{
1644
0
    if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
1645
0
        pTabViewTarget->GetViewShell().InsertNameList();
1646
0
}
1647
1648
bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const
1649
0
{
1650
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
1651
0
}
1652
1653
ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell& rNewDocShell, SCTAB nTab):
1654
0
    ScSimpleUndo( rNewDocShell ),
1655
0
    mnTab(nTab),
1656
0
    mpUndoDoc(createUndoRedoData())
1657
0
{
1658
0
}
1659
1660
ScUndoConditionalFormat::~ScUndoConditionalFormat()
1661
0
{
1662
0
}
1663
1664
ScDocumentUniquePtr ScUndoConditionalFormat::createUndoRedoData()
1665
0
{
1666
0
    ScDocument& rDoc = rDocShell.GetDocument();
1667
0
    ScDocumentUniquePtr pUndoRedoDoc(new ScDocument(SCDOCMODE_UNDO));
1668
0
    pUndoRedoDoc->InitUndo(rDoc, mnTab, mnTab);
1669
0
    if (const auto* pList = rDoc.GetCondFormList(mnTab))
1670
0
        pUndoRedoDoc->SetCondFormList(pList->Clone(*pUndoRedoDoc), mnTab);
1671
0
    return pUndoRedoDoc;
1672
0
}
1673
1674
OUString ScUndoConditionalFormat::GetComment() const
1675
0
{
1676
0
    return ScResId( STR_UNDO_CONDFORMAT );
1677
0
}
1678
1679
void ScUndoConditionalFormat::Undo()
1680
0
{
1681
0
    DoChange(mpUndoDoc.get());
1682
0
}
1683
1684
void ScUndoConditionalFormat::Redo()
1685
0
{
1686
0
    DoChange(mpRedoDoc.get());
1687
0
}
1688
1689
void ScUndoConditionalFormat::DoChange(const ScDocument* pSrcDoc)
1690
0
{
1691
0
    ScDocument& rDoc = rDocShell.GetDocument();
1692
1693
    // Restore all conditional formats in the tab. This is simpler and more reliable, than
1694
    // restoring formats in a specific range, and then trying to join selectively the restored
1695
    // formats with the other formats in the tab, to get the correct state.
1696
0
    ScRangeList aCombinedRange;
1697
0
    if (const auto* pOldList = rDoc.GetCondFormList(mnTab))
1698
0
    {
1699
0
        aCombinedRange = pOldList->GetCombinedRange();
1700
        // Clear all existing CF keys from cells' attributes
1701
0
        for (auto& pFormat : *pOldList)
1702
0
            rDoc.RemoveCondFormatData(aCombinedRange, mnTab, pFormat->GetKey());
1703
0
    }
1704
1705
0
    if (const auto* pNewList = pSrcDoc->GetCondFormList(mnTab))
1706
0
    {
1707
0
        for (const auto& cond : *pNewList)
1708
0
        {
1709
            // Restore the CF keys to cell attributes
1710
0
            rDoc.AddCondFormatData(cond->GetRange(), mnTab, cond->GetKey());
1711
0
            for (const auto& range : cond->GetRange())
1712
0
                aCombinedRange.Join(range);
1713
0
        }
1714
0
        rDoc.SetCondFormList(pNewList->Clone(rDoc), mnTab);
1715
0
    }
1716
0
    else
1717
0
    {
1718
0
        rDoc.SetCondFormList(nullptr, mnTab);
1719
0
    }
1720
0
    rDocShell.PostPaint(aCombinedRange, PaintPartFlags::Grid);
1721
0
    rDocShell.PostDataChanged();
1722
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1723
0
    if (pViewShell)
1724
0
        pViewShell->CellContentChanged();
1725
0
}
1726
1727
void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& )
1728
0
{
1729
0
}
1730
1731
bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const
1732
0
{
1733
0
    return false;
1734
0
}
1735
1736
ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell& rNewDocShell,
1737
        ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab):
1738
0
    ScSimpleUndo( rNewDocShell ),
1739
0
    mpUndoDoc(std::move(pUndoDoc)),
1740
0
    mpRedoDoc(std::move(pRedoDoc)),
1741
0
    mnTab(nTab)
1742
0
{
1743
0
}
1744
1745
ScUndoConditionalFormatList::~ScUndoConditionalFormatList()
1746
0
{
1747
0
}
1748
1749
OUString ScUndoConditionalFormatList::GetComment() const
1750
0
{
1751
0
    return ScResId( STR_UNDO_CONDFORMAT_LIST );
1752
0
}
1753
1754
void ScUndoConditionalFormatList::Undo()
1755
0
{
1756
0
    DoChange(mpUndoDoc.get());
1757
0
}
1758
1759
void ScUndoConditionalFormatList::Redo()
1760
0
{
1761
0
    DoChange(mpRedoDoc.get());
1762
0
}
1763
1764
void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc)
1765
0
{
1766
0
    ScDocument& rDoc = rDocShell.GetDocument();
1767
1768
0
    if (pSrcDoc == mpUndoDoc.get())
1769
0
    {
1770
0
        mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
1771
0
        mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
1772
0
    }
1773
0
    else
1774
0
    {
1775
0
        mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
1776
0
        mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
1777
0
    }
1778
0
    rDoc.SetCondFormList(pSrcDoc->GetCondFormList(mnTab)->Clone(rDoc), mnTab);
1779
1780
0
    rDocShell.PostPaintGridAll();
1781
0
    rDocShell.PostDataChanged();
1782
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1783
0
    if (pViewShell)
1784
0
        pViewShell->CellContentChanged();
1785
0
}
1786
1787
void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& )
1788
0
{
1789
0
}
1790
1791
bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const
1792
0
{
1793
0
    return false;
1794
0
}
1795
1796
ScUndoUseScenario::ScUndoUseScenario( ScDocShell& rNewDocShell,
1797
                        const ScMarkData& rMark,
1798
                        const ScArea& rDestArea,
1799
                              ScDocumentUniquePtr pNewUndoDoc,
1800
                        OUString aNewName ) :
1801
0
    ScSimpleUndo( rNewDocShell ),
1802
0
    pUndoDoc( std::move(pNewUndoDoc) ),
1803
0
    aMarkData( rMark ),
1804
0
    aName(std::move( aNewName ))
1805
0
{
1806
0
    aRange.aStart.SetCol(rDestArea.nColStart);
1807
0
    aRange.aStart.SetRow(rDestArea.nRowStart);
1808
0
    aRange.aStart.SetTab(rDestArea.nTab);
1809
0
    aRange.aEnd.SetCol(rDestArea.nColEnd);
1810
0
    aRange.aEnd.SetRow(rDestArea.nRowEnd);
1811
0
    aRange.aEnd.SetTab(rDestArea.nTab);
1812
0
}
1813
1814
ScUndoUseScenario::~ScUndoUseScenario()
1815
0
{
1816
0
}
1817
1818
OUString ScUndoUseScenario::GetComment() const
1819
0
{
1820
0
    return ScResId( STR_UNDO_USESCENARIO );
1821
0
}
1822
1823
void ScUndoUseScenario::Undo()
1824
0
{
1825
0
    BeginUndo();
1826
1827
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1828
0
    if (pViewShell)
1829
0
    {
1830
0
        pViewShell->DoneBlockMode();
1831
0
        pViewShell->InitOwnBlockMode( aRange );
1832
0
    }
1833
1834
0
    ScDocument& rDoc = rDocShell.GetDocument();
1835
0
    rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData );
1836
0
    pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData);
1837
1838
    // scenario table
1839
0
    bool bFrame = false;
1840
0
    SCTAB nTab = aRange.aStart.Tab();
1841
0
    SCTAB nEndTab = nTab;
1842
0
    while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) )
1843
0
        ++nEndTab;
1844
0
    for (SCTAB i = nTab+1; i<=nEndTab; i++)
1845
0
    {
1846
        // Flags always
1847
0
        OUString aComment;
1848
0
        Color  aColor;
1849
0
        ScScenarioFlags nScenFlags;
1850
0
        pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags );
1851
0
        rDoc.SetScenarioData( i, aComment, aColor, nScenFlags );
1852
0
        bool bActive = pUndoDoc->IsActiveScenario( i );
1853
0
        rDoc.SetActiveScenario( i, bActive );
1854
        //  For copy-back scenario also consider content
1855
0
        if ( nScenFlags & ScScenarioFlags::TwoWay )
1856
0
        {
1857
0
            rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL );
1858
0
            pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc);
1859
0
        }
1860
0
        if ( nScenFlags & ScScenarioFlags::ShowFrame )
1861
0
            bFrame = true;
1862
0
    }
1863
1864
    // if visible borders, then paint all
1865
0
    if (bFrame)
1866
0
        rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras );
1867
0
    else
1868
0
        rDocShell.PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras );
1869
0
    rDocShell.PostDataChanged();
1870
0
    if (pViewShell)
1871
0
        pViewShell->CellContentChanged();
1872
1873
0
    ShowTable( aRange.aStart.Tab() );
1874
1875
0
    EndUndo();
1876
0
}
1877
1878
void ScUndoUseScenario::Redo()
1879
0
{
1880
0
    SCTAB nTab = aRange.aStart.Tab();
1881
0
    BeginRedo();
1882
1883
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1884
0
    if (pViewShell)
1885
0
    {
1886
0
        pViewShell->SetTabNo( nTab );
1887
0
        pViewShell->DoneBlockMode();
1888
0
        pViewShell->InitOwnBlockMode( aRange );
1889
0
    }
1890
1891
0
    rDocShell.UseScenario( nTab, aName, false );
1892
1893
0
    EndRedo();
1894
0
}
1895
1896
void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget)
1897
0
{
1898
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
1899
0
    {
1900
0
        OUString aTemp = aName;
1901
0
        pViewTarget->GetViewShell().UseScenario(aTemp);
1902
0
    }
1903
0
}
1904
1905
bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const
1906
0
{
1907
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
1908
0
    {
1909
0
        ScViewData& rViewData = pViewTarget->GetViewShell().GetViewData();
1910
0
        return !rViewData.GetDocument().IsScenario( rViewData.CurrentTabForData() );
1911
0
    }
1912
0
    return false;
1913
0
}
1914
1915
ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell& rNewDocShell,
1916
                                      const ScMarkData& rMark,
1917
                                      const ScRange& rRange,
1918
                                      OUString aName,
1919
                                            ScDocumentUniquePtr pNewUndoDoc ) :
1920
0
    ScSimpleUndo( rNewDocShell ),
1921
0
    aMarkData( rMark ),
1922
0
    pUndoDoc( std::move(pNewUndoDoc) ),
1923
0
    aStyleName(std::move( aName )),
1924
0
    aRange( rRange )
1925
0
{
1926
0
    aMarkData.MarkToMulti();
1927
0
}
1928
1929
ScUndoSelectionStyle::~ScUndoSelectionStyle()
1930
0
{
1931
0
}
1932
1933
OUString ScUndoSelectionStyle::GetComment() const
1934
0
{
1935
0
    return ScResId( STR_UNDO_APPLYCELLSTYLE );
1936
0
}
1937
1938
void ScUndoSelectionStyle::DoChange( const bool bUndo )
1939
0
{
1940
0
    ScDocument& rDoc = rDocShell.GetDocument();
1941
1942
0
    SetViewMarkData( aMarkData );
1943
1944
0
    ScRange aWorkRange( aRange );
1945
0
    if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) )        // Merged cells?
1946
0
        rDoc.ExtendMerge( aWorkRange, true );
1947
1948
0
    sal_uInt16 nExtFlags = 0;
1949
0
    rDocShell.UpdatePaintExt( nExtFlags, aWorkRange );
1950
1951
0
    if (bUndo)      // if Undo then push back all old data again
1952
0
    {
1953
0
        SCTAB nTabCount = rDoc.GetTableCount();
1954
0
        ScRange aCopyRange = aWorkRange;
1955
0
        aCopyRange.aStart.SetTab(0);
1956
0
        aCopyRange.aEnd.SetTab(nTabCount-1);
1957
0
        pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
1958
0
    }
1959
0
    else            // if Redo, then reapply style
1960
0
    {
1961
0
        ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
1962
0
        ScStyleSheet* pStyleSheet =
1963
0
            static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
1964
0
        if (!pStyleSheet)
1965
0
        {
1966
0
            OSL_FAIL("StyleSheet not found");
1967
0
            return;
1968
0
        }
1969
0
        rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData );
1970
0
    }
1971
1972
0
    rDocShell.UpdatePaintExt( nExtFlags, aWorkRange );
1973
1974
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1975
0
    if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
1976
0
/*A*/   rDocShell.PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
1977
1978
0
    ShowTable( aWorkRange.aStart.Tab() );
1979
0
}
1980
1981
void ScUndoSelectionStyle::Undo()
1982
0
{
1983
0
    BeginUndo();
1984
0
    DoChange( true );
1985
0
    EndUndo();
1986
0
}
1987
1988
void ScUndoSelectionStyle::Redo()
1989
0
{
1990
0
    BeginRedo();
1991
0
    DoChange( false );
1992
0
    EndRedo();
1993
0
}
1994
1995
void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget)
1996
0
{
1997
0
    if (dynamic_cast<const ScTabViewTarget*>( &rTarget) ==  nullptr)
1998
0
        return;
1999
2000
0
    ScDocument& rDoc = rDocShell.GetDocument();
2001
0
    ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
2002
0
    ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool->
2003
0
                                        Find( aStyleName, SfxStyleFamily::Para ));
2004
0
    if (!pStyleSheet)
2005
0
    {
2006
0
        OSL_FAIL("StyleSheet not found");
2007
0
        return;
2008
0
    }
2009
2010
0
    ScTabViewShell& rViewShell = static_cast<ScTabViewTarget&>(rTarget).GetViewShell();
2011
0
    rViewShell.SetStyleSheetToMarked( pStyleSheet );
2012
0
}
2013
2014
bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const
2015
0
{
2016
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2017
0
}
2018
2019
ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell& rNewDocShell, const ScRange& rArea,
2020
                                      ScDocumentUniquePtr pNewUndoDoc, OUString aForm,
2021
                                      std::unique_ptr<ScTokenArray> pArray,
2022
                                      bool bDynamicArrayMaster) :
2023
0
    ScBlockUndo( rNewDocShell, rArea, SC_UNDO_SIMPLE ),
2024
0
    pUndoDoc( std::move(pNewUndoDoc) ),
2025
0
    aFormula(std::move( aForm )),
2026
0
    pTokenArray(std::move(pArray)),
2027
0
    mbDynamicArrayMaster(bDynamicArrayMaster)
2028
0
{
2029
0
    SetChangeTrack();
2030
0
}
2031
2032
ScUndoEnterMatrix::~ScUndoEnterMatrix()
2033
0
{
2034
0
}
2035
2036
OUString ScUndoEnterMatrix::GetComment() const
2037
0
{
2038
0
    return ScResId( STR_UNDO_ENTERMATRIX );
2039
0
}
2040
2041
void ScUndoEnterMatrix::SetChangeTrack()
2042
0
{
2043
0
    ScDocument& rDoc = rDocShell.GetDocument();
2044
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2045
0
    if ( pChangeTrack )
2046
0
        pChangeTrack->AppendContentRange( aBlockRange, *pUndoDoc,
2047
0
            nStartChangeAction, nEndChangeAction );
2048
0
    else
2049
0
        nStartChangeAction = nEndChangeAction = 0;
2050
0
}
2051
2052
void ScUndoEnterMatrix::Undo()
2053
0
{
2054
0
    BeginUndo();
2055
2056
0
    ScDocument& rDoc = rDocShell.GetDocument();
2057
2058
0
    rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
2059
0
    pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
2060
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid );
2061
0
    rDocShell.PostDataChanged();
2062
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2063
0
    if (pViewShell)
2064
0
        pViewShell->CellContentChanged();
2065
2066
0
    ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2067
0
    if ( pChangeTrack )
2068
0
        pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
2069
2070
0
    EndUndo();
2071
0
}
2072
2073
void ScUndoEnterMatrix::Redo()
2074
0
{
2075
0
    BeginRedo();
2076
2077
0
    ScDocument& rDoc = rDocShell.GetDocument();
2078
2079
0
    ScMarkData aDestMark(rDoc.GetSheetLimits());
2080
0
    aDestMark.SelectOneTable( aBlockRange.aStart.Tab() );
2081
0
    aDestMark.SetMarkArea( aBlockRange );
2082
2083
0
    rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
2084
0
                               aBlockRange.aEnd.Col(),   aBlockRange.aEnd.Row(),
2085
0
                               aDestMark, aFormula, pTokenArray.get(),
2086
0
                               formula::FormulaGrammar::GRAM_DEFAULT,
2087
0
                               mbDynamicArrayMaster);
2088
2089
0
    SetChangeTrack();
2090
2091
0
    EndRedo();
2092
0
}
2093
2094
void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget)
2095
0
{
2096
0
    if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
2097
0
    {
2098
0
        OUString aTemp = aFormula;
2099
0
        ScDocument& rDoc = rDocShell.GetDocument();
2100
0
        pTabViewTarget->GetViewShell().EnterMatrix(aTemp, rDoc.GetGrammar());
2101
0
    }
2102
0
}
2103
2104
bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const
2105
0
{
2106
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2107
0
}
2108
2109
static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark )
2110
0
{
2111
0
    OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" );
2112
0
    return rMark.GetMultiMarkArea();
2113
0
}
2114
2115
ScUndoIndent::ScUndoIndent( ScDocShell& rNewDocShell, const ScMarkData& rMark,
2116
                            ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) :
2117
0
    ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2118
0
    aMarkData( rMark ),
2119
0
    pUndoDoc( std::move(pNewUndoDoc) ),
2120
0
    bIsIncrement( bIncrement )
2121
0
{
2122
0
}
2123
2124
ScUndoIndent::~ScUndoIndent()
2125
0
{
2126
0
}
2127
2128
OUString ScUndoIndent::GetComment() const
2129
0
{
2130
0
    TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT;
2131
0
    return ScResId(pId);
2132
0
}
2133
2134
void ScUndoIndent::Undo()
2135
0
{
2136
0
    BeginUndo();
2137
2138
0
    ScDocument& rDoc = rDocShell.GetDocument();
2139
0
    SCTAB nTabCount = rDoc.GetTableCount();
2140
0
    ScRange aCopyRange = aBlockRange;
2141
0
    aCopyRange.aStart.SetTab(0);
2142
0
    aCopyRange.aEnd.SetTab(nTabCount-1);
2143
0
    pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2144
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2145
2146
0
    EndUndo();
2147
0
}
2148
2149
void ScUndoIndent::Redo()
2150
0
{
2151
0
    BeginRedo();
2152
2153
0
    ScDocument& rDoc = rDocShell.GetDocument();
2154
0
    rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData );
2155
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2156
2157
0
    EndRedo();
2158
0
}
2159
2160
void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget)
2161
0
{
2162
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2163
0
        pViewTarget->GetViewShell().ChangeIndent( bIsIncrement );
2164
0
}
2165
2166
bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const
2167
0
{
2168
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2169
0
}
2170
2171
ScUndoTransliterate::ScUndoTransliterate( ScDocShell& rNewDocShell, const ScMarkData& rMark,
2172
                            ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) :
2173
0
    ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2174
0
    aMarkData( rMark ),
2175
0
    pUndoDoc( std::move(pNewUndoDoc) ),
2176
0
    nTransliterationType( nType )
2177
0
{
2178
0
}
2179
2180
ScUndoTransliterate::~ScUndoTransliterate()
2181
0
{
2182
0
}
2183
2184
OUString ScUndoTransliterate::GetComment() const
2185
0
{
2186
0
    return ScResId( STR_UNDO_TRANSLITERATE );
2187
0
}
2188
2189
void ScUndoTransliterate::Undo()
2190
0
{
2191
0
    BeginUndo();
2192
2193
0
    ScDocument& rDoc = rDocShell.GetDocument();
2194
0
    SCTAB nTabCount = rDoc.GetTableCount();
2195
0
    ScRange aCopyRange = aBlockRange;
2196
0
    aCopyRange.aStart.SetTab(0);
2197
0
    aCopyRange.aEnd.SetTab(nTabCount-1);
2198
0
    pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData);
2199
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2200
2201
0
    EndUndo();
2202
0
}
2203
2204
void ScUndoTransliterate::Redo()
2205
0
{
2206
0
    BeginRedo();
2207
2208
0
    ScDocument& rDoc = rDocShell.GetDocument();
2209
0
    rDoc.TransliterateText( aMarkData, nTransliterationType );
2210
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2211
2212
0
    EndRedo();
2213
0
}
2214
2215
void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget)
2216
0
{
2217
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2218
0
        pViewTarget->GetViewShell().TransliterateText( nTransliterationType );
2219
0
}
2220
2221
bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const
2222
0
{
2223
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2224
0
}
2225
2226
ScUndoClearItems::ScUndoClearItems( ScDocShell& rNewDocShell, const ScMarkData& rMark,
2227
                            ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) :
2228
0
    ScBlockUndo( rNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2229
0
    aMarkData( rMark ),
2230
0
    pUndoDoc( std::move(pNewUndoDoc) )
2231
0
{
2232
0
    assert(pW && "ScUndoClearItems: Which-Pointer is Null");
2233
2234
0
    sal_uInt16 nCount = 0;
2235
0
    while ( pW[nCount] )
2236
0
        ++nCount;
2237
0
    pWhich.reset( new sal_uInt16[nCount+1] );
2238
0
    for (sal_uInt16 i=0; i<=nCount; i++)
2239
0
        pWhich[i] = pW[i];
2240
0
}
2241
2242
ScUndoClearItems::~ScUndoClearItems()
2243
0
{
2244
0
}
2245
2246
OUString ScUndoClearItems::GetComment() const
2247
0
{
2248
0
    return ScResId( STR_UNDO_DELETECONTENTS );
2249
0
}
2250
2251
void ScUndoClearItems::Undo()
2252
0
{
2253
0
    BeginUndo();
2254
2255
0
    ScDocument& rDoc = rDocShell.GetDocument();
2256
0
    pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2257
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2258
2259
0
    EndUndo();
2260
0
}
2261
2262
void ScUndoClearItems::Redo()
2263
0
{
2264
0
    BeginRedo();
2265
2266
0
    ScDocument& rDoc = rDocShell.GetDocument();
2267
0
    rDoc.ClearSelectionItems( pWhich.get(), aMarkData );
2268
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2269
2270
0
    EndRedo();
2271
0
}
2272
2273
void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget)
2274
0
{
2275
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2276
0
    {
2277
0
        ScViewData& rViewData = pViewTarget->GetViewShell().GetViewData();
2278
0
        rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false );
2279
0
    }
2280
0
}
2281
2282
bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const
2283
0
{
2284
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2285
0
}
2286
2287
// remove all line breaks of a table
2288
ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell& rNewDocShell,
2289
                                    SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) :
2290
0
    ScSimpleUndo( rNewDocShell ),
2291
0
    nTab( nNewTab ),
2292
0
    pUndoDoc( std::move(pNewUndoDoc) )
2293
0
{
2294
0
}
2295
2296
ScUndoRemoveBreaks::~ScUndoRemoveBreaks()
2297
0
{
2298
0
}
2299
2300
OUString ScUndoRemoveBreaks::GetComment() const
2301
0
{
2302
0
    return ScResId( STR_UNDO_REMOVEBREAKS );
2303
0
}
2304
2305
void ScUndoRemoveBreaks::Undo()
2306
0
{
2307
0
    BeginUndo();
2308
2309
0
    ScDocument& rDoc = rDocShell.GetDocument();
2310
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2311
2312
0
    pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc);
2313
0
    if (pViewShell)
2314
0
        pViewShell->UpdatePageBreakData( true );
2315
0
    rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
2316
2317
0
    EndUndo();
2318
0
}
2319
2320
void ScUndoRemoveBreaks::Redo()
2321
0
{
2322
0
    BeginRedo();
2323
2324
0
    ScDocument& rDoc = rDocShell.GetDocument();
2325
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2326
2327
0
    rDoc.RemoveManualBreaks(nTab);
2328
0
    rDoc.UpdatePageBreaks(nTab);
2329
0
    if (pViewShell)
2330
0
        pViewShell->UpdatePageBreakData( true );
2331
0
    rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
2332
2333
0
    EndRedo();
2334
0
}
2335
2336
void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget)
2337
0
{
2338
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2339
0
    {
2340
0
        ScTabViewShell& rViewShell = pViewTarget->GetViewShell();
2341
0
        rViewShell.RemoveManualBreaks();
2342
0
    }
2343
0
}
2344
2345
bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
2346
0
{
2347
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2348
0
}
2349
2350
ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell& rNewDocShell,
2351
                                      const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) :
2352
0
    ScBlockUndo( rNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
2353
0
    pUndoDoc( std::move(pNewUndoDoc) )
2354
0
{
2355
0
    maOptions.push_back( rOption);
2356
0
}
2357
2358
ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell& rNewDocShell,
2359
                                      const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) :
2360
0
    ScBlockUndo( rNewDocShell, rRange, SC_UNDO_SIMPLE ),
2361
0
    pUndoDoc( std::move(pNewUndoDoc) )
2362
0
{
2363
0
}
2364
2365
ScUndoRemoveMerge::~ScUndoRemoveMerge()
2366
0
{
2367
0
}
2368
2369
OUString ScUndoRemoveMerge::GetComment() const
2370
0
{
2371
0
    return ScResId( STR_UNDO_REMERGE );  // "remove merge"
2372
0
}
2373
2374
ScDocument* ScUndoRemoveMerge::GetUndoDoc()
2375
0
{
2376
0
    return pUndoDoc.get();
2377
0
}
2378
2379
void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption )
2380
0
{
2381
0
    maOptions.push_back( rOption);
2382
0
}
2383
2384
void ScUndoRemoveMerge::Undo()
2385
0
{
2386
0
    SetCurTab();
2387
0
    BeginUndo();
2388
2389
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2390
2391
0
    ScDocument& rDoc = rDocShell.GetDocument();
2392
0
    for (const auto & rOption : maOptions)
2393
0
    {
2394
0
        for (const auto& rTab : rOption.maTabs)
2395
0
        {
2396
0
            OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!");
2397
0
            if (!pUndoDoc)
2398
0
                continue;
2399
            // There is no need to extend merge area because it's already been extended.
2400
0
            ScRange aRange = rOption.getSingleRange(rTab);
2401
0
            rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB);
2402
0
            pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc);
2403
2404
0
            bool bDidPaint = false;
2405
0
            if ( pViewShell )
2406
0
            {
2407
0
                pViewShell->SetTabNo(rTab);
2408
0
                bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
2409
0
            }
2410
0
            if (!bDidPaint)
2411
0
                ScUndoUtil::PaintMore(rDocShell, aRange);
2412
0
        }
2413
0
    }
2414
2415
0
    EndUndo();
2416
0
}
2417
2418
void ScUndoRemoveMerge::Redo()
2419
0
{
2420
0
    SetCurTab();
2421
0
    BeginRedo();
2422
2423
0
    ScDocument& rDoc = rDocShell.GetDocument();
2424
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2425
2426
0
    for (const auto & rOption : maOptions)
2427
0
    {
2428
0
        for (const SCTAB nTab : rOption.maTabs)
2429
0
        {
2430
            // There is no need to extend merge area because it's already been extended.
2431
0
            ScRange aRange = rOption.getSingleRange(nTab);
2432
2433
0
            const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
2434
0
            ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
2435
0
            aPattern.ItemSetPut(rDefAttr);
2436
0
            rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow,
2437
0
                    rOption.mnEndCol, rOption.mnEndRow, nTab,
2438
0
                    aPattern );
2439
2440
0
            rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow,
2441
0
                    rOption.mnEndCol, rOption.mnEndRow, nTab,
2442
0
                    ScMF::Hor | ScMF::Ver );
2443
2444
0
            rDoc.ExtendMerge(aRange, true);
2445
2446
            //  Paint
2447
2448
0
            bool bDidPaint = false;
2449
0
            if ( pViewShell )
2450
0
            {
2451
0
                pViewShell->SetTabNo(nTab);
2452
0
                bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
2453
0
            }
2454
0
            if (!bDidPaint)
2455
0
                ScUndoUtil::PaintMore(rDocShell, aRange);
2456
0
        }
2457
0
    }
2458
2459
0
    EndRedo();
2460
0
}
2461
2462
void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget)
2463
0
{
2464
0
    if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2465
0
        pViewTarget->GetViewShell().RemoveMerge();
2466
0
}
2467
2468
bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
2469
0
{
2470
0
    return dynamic_cast<const ScTabViewTarget*>( &rTarget) !=  nullptr;
2471
0
}
2472
2473
void ScUndoRemoveMerge::SetCurTab()
2474
0
{
2475
0
    SCTAB nCurTab = ScDocShell::GetCurTab();
2476
0
    aBlockRange.aStart.SetTab(nCurTab);
2477
0
    aBlockRange.aEnd.SetTab(nCurTab);
2478
0
}
2479
2480
/** set only border, for ScRangeList (StarOne) */
2481
static ScRange lcl_TotalRange( const ScRangeList& rRanges )
2482
0
{
2483
0
    ScRange aTotal;
2484
0
    if ( !rRanges.empty() )
2485
0
    {
2486
0
        aTotal = rRanges[ 0 ];
2487
0
        for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i )
2488
0
        {
2489
0
            ScRange const & rRange = rRanges[ i ];
2490
0
            if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col());
2491
0
            if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row());
2492
0
            if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab());
2493
0
            if (rRange.aEnd.Col()   > aTotal.aEnd.Col()  ) aTotal.aEnd.SetCol(  rRange.aEnd.Col()  );
2494
0
            if (rRange.aEnd.Row()   > aTotal.aEnd.Row()  ) aTotal.aEnd.SetRow(  rRange.aEnd.Row()  );
2495
0
            if (rRange.aEnd.Tab()   > aTotal.aEnd.Tab()  ) aTotal.aEnd.SetTab(rRange.aEnd.Tab()    );
2496
0
        }
2497
0
    }
2498
0
    return aTotal;
2499
0
}
2500
2501
ScUndoBorder::ScUndoBorder(ScDocShell& rNewDocShell,
2502
                           const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc,
2503
                           const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner)
2504
0
    : ScBlockUndo(rNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE)
2505
0
    , xUndoDoc(std::move(pNewUndoDoc))
2506
0
{
2507
0
    xRanges.reset(new ScRangeList(rRangeList));
2508
0
    xOuter.reset(new SvxBoxItem(rNewOuter));
2509
0
    xInner.reset(new SvxBoxInfoItem(rNewInner));
2510
0
}
2511
2512
OUString ScUndoBorder::GetComment() const
2513
0
{
2514
0
    return ScResId( STR_UNDO_SELATTRLINES );     //! own string?
2515
0
}
2516
2517
void ScUndoBorder::Undo()
2518
0
{
2519
0
    BeginUndo();
2520
2521
0
    ScDocument& rDoc = rDocShell.GetDocument();
2522
0
    ScMarkData aMarkData(rDoc.GetSheetLimits());
2523
0
    aMarkData.MarkFromRangeList(*xRanges, false);
2524
0
    xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2525
0
    rDocShell.PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2526
2527
0
    EndUndo();
2528
0
}
2529
2530
void ScUndoBorder::Redo()
2531
0
{
2532
0
    BeginRedo();
2533
2534
0
    ScDocument& rDoc = rDocShell.GetDocument();        // call function at docfunc
2535
0
    size_t nCount = xRanges->size();
2536
0
    for (size_t i = 0; i < nCount; ++i )
2537
0
    {
2538
0
        ScRange const & rRange = (*xRanges)[i];
2539
0
        SCTAB nTab = rRange.aStart.Tab();
2540
2541
0
        ScMarkData aMark(rDoc.GetSheetLimits());
2542
0
        aMark.SetMarkArea( rRange );
2543
0
        aMark.SelectTable( nTab, true );
2544
2545
0
        rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get());
2546
0
    }
2547
0
    for (size_t i = 0; i < nCount; ++i)
2548
0
        rDocShell.PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2549
2550
0
    EndRedo();
2551
0
}
2552
2553
void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */)
2554
0
{
2555
    //TODO later (when the function has moved from cellsuno to docfunc)
2556
0
}
2557
2558
bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const
2559
0
{
2560
0
    return false;   // See above
2561
0
}
2562
2563
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */