Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/table/tableundo.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
21
#include <sdr/properties/cellproperties.hxx>
22
#include <editeng/outlobj.hxx>
23
24
#include <cell.hxx>
25
#include "tableundo.hxx"
26
#include <svx/svdotable.hxx>
27
#include "tablerow.hxx"
28
#include "tablecolumn.hxx"
29
30
31
using namespace ::com::sun::star::uno;
32
33
34
namespace sdr::table {
35
36
CellUndo::CellUndo( SdrObject* pObjRef, const CellRef& xCell )
37
0
:   SdrUndoAction(xCell->GetObject().getSdrModelFromSdrObject())
38
0
    ,mxObjRef( pObjRef )
39
0
    ,mxCell( xCell )
40
0
    ,mbUndo( true )
41
0
{
42
0
    if( mxCell.is() && pObjRef )
43
0
    {
44
0
        getDataFromCell( maUndoData );
45
0
        pObjRef->AddObjectUser( *this );
46
0
    }
47
0
}
48
49
CellUndo::~CellUndo()
50
0
{
51
0
    if( auto pObj = mxObjRef.get() )
52
0
        pObj->RemoveObjectUser( *this );
53
0
    dispose();
54
0
}
55
56
void CellUndo::dispose()
57
0
{
58
0
    mxCell.clear();
59
0
    maUndoData.mxProperties.reset();
60
0
    maRedoData.mxProperties.reset();
61
0
    maUndoData.mpOutlinerParaObject.reset();
62
0
    maRedoData.mpOutlinerParaObject.reset();
63
0
}
64
65
void CellUndo::ObjectInDestruction(const SdrObject& )
66
0
{
67
0
    dispose();
68
0
}
69
70
void CellUndo::Undo()
71
0
{
72
0
    if( mxCell.is() && mbUndo )
73
0
    {
74
0
        if( !maRedoData.mxProperties )
75
0
            getDataFromCell( maRedoData );
76
77
0
        setDataToCell( maUndoData );
78
0
        mbUndo = false;
79
0
    }
80
0
}
81
82
void CellUndo::Redo()
83
0
{
84
0
    if( mxCell.is() && !mbUndo )
85
0
    {
86
0
        setDataToCell( maRedoData );
87
0
        mbUndo = true;
88
0
    }
89
0
}
90
91
bool CellUndo::Merge( SfxUndoAction *pNextAction )
92
0
{
93
0
    CellUndo* pNext = dynamic_cast< CellUndo* >( pNextAction );
94
0
    return pNext && pNext->mxCell.get() == mxCell.get();
95
0
}
96
97
void CellUndo::setDataToCell( const Data& rData )
98
0
{
99
0
    if( rData.mxProperties )
100
0
        mxCell->mpProperties.reset(new properties::CellProperties( *rData.mxProperties, *mxObjRef.get(), mxCell.get() ));
101
0
    else
102
0
        mxCell->mpProperties.reset();
103
104
0
    if( rData.mpOutlinerParaObject )
105
0
        mxCell->SetOutlinerParaObject( *rData.mpOutlinerParaObject );
106
0
    else
107
0
        mxCell->RemoveOutlinerParaObject();
108
109
0
    mxCell->msFormula = rData.msFormula;
110
0
    mxCell->mfValue = rData.mfValue;
111
0
    mxCell->mnError = rData.mnError;
112
0
    mxCell->mbMerged = rData.mbMerged;
113
0
    mxCell->mnRowSpan = rData.mnRowSpan;
114
0
    mxCell->mnColSpan = rData.mnColSpan;
115
116
0
    if(auto pObj = mxObjRef.get())
117
0
    {
118
        // #i120201# ActionChanged is not enough, we need to trigger TableLayouter::UpdateBorderLayout()
119
        // and this is done best using ReformatText() for table objects
120
0
        pObj->ActionChanged();
121
0
        pObj->NbcReformatText();
122
0
    }
123
0
}
124
125
void CellUndo::getDataFromCell( Data& rData )
126
0
{
127
0
    if( !(mxObjRef.get().is() && mxCell.is()) )
128
0
        return;
129
130
0
    if( mxCell->mpProperties )
131
0
        rData.mxProperties.reset( mxCell->CloneProperties( *mxObjRef.get(), *mxCell) );
132
133
0
    if( mxCell->GetOutlinerParaObject() )
134
0
        rData.mpOutlinerParaObject = *mxCell->GetOutlinerParaObject();
135
0
    else
136
0
        rData.mpOutlinerParaObject.reset();
137
138
0
    rData.msFormula = mxCell->msFormula;
139
0
    rData.mfValue = mxCell->mfValue;
140
0
    rData.mnError = mxCell->mnError;
141
0
    rData.mbMerged = mxCell->mbMerged;
142
0
    rData.mnRowSpan = mxCell->mnRowSpan;
143
0
    rData.mnColSpan = mxCell->mnColSpan;
144
0
}
145
146
147
// class InsertRowUndo : public SdrUndoAction
148
149
150
static void Dispose( RowVector& rRows )
151
0
{
152
0
    for( auto& rpRow : rRows )
153
0
        rpRow->dispose();
154
0
}
155
156
157
InsertRowUndo::InsertRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aNewRows )
158
0
:   SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
159
0
    ,mxTable( xTable )
160
0
    ,mnIndex( nIndex )
161
0
    ,mbUndo( true )
162
0
{
163
0
    maRows.swap( aNewRows );
164
0
}
165
166
167
InsertRowUndo::~InsertRowUndo()
168
0
{
169
0
    if( !mbUndo )
170
0
        Dispose( maRows );
171
0
}
172
173
174
void InsertRowUndo::Undo()
175
0
{
176
0
    if( mxTable.is() )
177
0
    {
178
0
        mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) );
179
0
        mbUndo = false;
180
0
    }
181
0
}
182
183
184
void InsertRowUndo::Redo()
185
0
{
186
0
    if( mxTable.is() )
187
0
    {
188
0
        mxTable->UndoRemoveRows( mnIndex, maRows );
189
0
        mbUndo = true;
190
0
    }
191
0
}
192
193
194
// class RemoveRowUndo : public SdrUndoAction
195
196
197
RemoveRowUndo::RemoveRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aRemovedRows )
198
0
:   SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
199
0
    ,mxTable( xTable )
200
0
    ,mnIndex( nIndex )
201
0
    ,mbUndo( true )
202
0
{
203
0
    maRows.swap( aRemovedRows );
204
0
}
205
206
207
RemoveRowUndo::~RemoveRowUndo()
208
0
{
209
0
    if( mbUndo )
210
0
        Dispose( maRows );
211
0
}
212
213
214
void RemoveRowUndo::Undo()
215
0
{
216
0
    if( mxTable.is() )
217
0
    {
218
0
        mxTable->UndoRemoveRows( mnIndex, maRows );
219
0
        mbUndo = false;
220
0
    }
221
0
}
222
223
224
void RemoveRowUndo::Redo()
225
0
{
226
0
    if( mxTable.is() )
227
0
    {
228
0
        mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) );
229
0
        mbUndo = true;
230
0
    }
231
0
}
232
233
234
// class InsertColUndo : public SdrUndoAction
235
236
237
static void Dispose( ColumnVector& rCols )
238
0
{
239
0
    for( auto& rpCol : rCols )
240
0
        rpCol->dispose();
241
0
}
242
243
244
static void Dispose( CellVector& rCells )
245
0
{
246
0
    for( auto& rpCell : rCells )
247
0
        rpCell->dispose();
248
0
}
249
250
251
InsertColUndo::InsertColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells  )
252
846
:   SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
253
846
    ,mxTable( xTable )
254
846
    ,mnIndex( nIndex )
255
846
    ,mbUndo( true )
256
846
{
257
846
    maColumns.swap( aNewCols );
258
846
    maCells.swap( aCells );
259
846
}
260
261
262
InsertColUndo::~InsertColUndo()
263
846
{
264
846
    if( !mbUndo )
265
0
    {
266
0
        Dispose( maColumns );
267
0
        Dispose( maCells );
268
0
    }
269
846
}
270
271
272
void InsertColUndo::Undo()
273
0
{
274
0
    if( mxTable.is() )
275
0
    {
276
0
        mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) );
277
0
        mbUndo = false;
278
0
    }
279
0
}
280
281
282
void InsertColUndo::Redo()
283
0
{
284
0
    if( mxTable.is() )
285
0
    {
286
0
        mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells );
287
0
        mbUndo = true;
288
0
    }
289
0
}
290
291
292
// class RemoveColUndo : public SdrUndoAction
293
294
295
RemoveColUndo::RemoveColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells )
296
0
:   SdrUndoAction(xTable->getSdrTableObj()->getSdrModelFromSdrObject())
297
0
    ,mxTable( xTable )
298
0
    ,mnIndex( nIndex )
299
0
    ,mbUndo( true )
300
0
{
301
0
    maColumns.swap( aNewCols );
302
0
    maCells.swap( aCells );
303
0
}
304
305
306
RemoveColUndo::~RemoveColUndo()
307
0
{
308
0
    if( mbUndo )
309
0
    {
310
0
        Dispose( maColumns );
311
0
        Dispose( maCells );
312
0
    }
313
0
}
314
315
316
void RemoveColUndo::Undo()
317
0
{
318
0
    if( mxTable.is() )
319
0
    {
320
0
        mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells );
321
0
        mbUndo = false;
322
0
    }
323
0
}
324
325
326
void RemoveColUndo::Redo()
327
0
{
328
0
    if( mxTable.is() )
329
0
    {
330
0
        mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) );
331
0
        mbUndo = true;
332
0
    }
333
0
}
334
335
336
// class TableColumnUndo : public SdrUndoAction
337
338
339
TableColumnUndo::TableColumnUndo( const TableColumnRef& xCol )
340
0
:   SdrUndoAction(xCol->mxTableModel->getSdrTableObj()->getSdrModelFromSdrObject())
341
0
    ,mxCol( xCol )
342
0
    ,mbHasRedoData( false )
343
0
{
344
0
    getData( maUndoData );
345
0
}
346
347
348
TableColumnUndo::~TableColumnUndo()
349
0
{
350
0
}
351
352
353
void TableColumnUndo::Undo()
354
0
{
355
0
    if( !mbHasRedoData )
356
0
    {
357
0
        getData( maRedoData );
358
0
        mbHasRedoData = true;
359
0
    }
360
0
    setData( maUndoData );
361
0
}
362
363
364
void TableColumnUndo::Redo()
365
0
{
366
0
    setData( maRedoData );
367
0
}
368
369
370
bool TableColumnUndo::Merge( SfxUndoAction *pNextAction )
371
0
{
372
0
    TableColumnUndo* pNext = dynamic_cast< TableColumnUndo* >( pNextAction );
373
0
    return pNext && pNext->mxCol == mxCol;
374
0
}
375
376
377
void TableColumnUndo::setData( const Data& rData )
378
0
{
379
0
    mxCol->mnColumn = rData.mnColumn;
380
0
    mxCol->mnWidth = rData.mnWidth;
381
0
    mxCol->mbOptimalWidth = rData.mbOptimalWidth;
382
0
    mxCol->mbIsVisible = rData.mbIsVisible;
383
0
    mxCol->mbIsStartOfNewPage = rData.mbIsStartOfNewPage;
384
0
    mxCol->maName = rData.maName;
385
386
    // Trigger re-layout of the table.
387
0
    mxCol->getModel()->setModified(true);
388
0
}
389
390
391
void TableColumnUndo::getData( Data& rData )
392
0
{
393
0
    rData.mnColumn = mxCol->mnColumn;
394
0
    rData.mnWidth = mxCol->mnWidth;
395
0
    rData.mbOptimalWidth = mxCol->mbOptimalWidth;
396
0
    rData.mbIsVisible = mxCol->mbIsVisible;
397
0
    rData.mbIsStartOfNewPage = mxCol->mbIsStartOfNewPage;
398
0
    rData.maName = mxCol->maName;
399
0
}
400
401
402
// class TableRowUndo : public SdrUndoAction
403
404
405
TableRowUndo::TableRowUndo( const TableRowRef& xRow )
406
0
:   SdrUndoAction(xRow->mxTableModel->getSdrTableObj()->getSdrModelFromSdrObject())
407
0
    , mxRow( xRow )
408
0
    , mbHasRedoData( false )
409
0
{
410
0
    getData( maUndoData );
411
0
}
412
413
414
TableRowUndo::~TableRowUndo()
415
0
{
416
0
}
417
418
419
void TableRowUndo::Undo()
420
0
{
421
0
    if( !mbHasRedoData )
422
0
    {
423
0
        getData( maRedoData );
424
0
        mbHasRedoData = true;
425
0
    }
426
0
    setData( maUndoData );
427
0
}
428
429
430
void TableRowUndo::Redo()
431
0
{
432
0
    setData( maRedoData );
433
0
}
434
435
436
bool TableRowUndo::Merge( SfxUndoAction *pNextAction )
437
0
{
438
0
    TableRowUndo* pNext = dynamic_cast< TableRowUndo* >( pNextAction );
439
0
    return pNext && pNext->mxRow == mxRow;
440
0
}
441
442
443
void TableRowUndo::setData( const Data& rData )
444
0
{
445
0
    mxRow->mnRow = rData.mnRow;
446
0
    mxRow->mnHeight = rData.mnHeight;
447
0
    mxRow->mbOptimalHeight = rData.mbOptimalHeight;
448
0
    mxRow->mbIsVisible = rData.mbIsVisible;
449
0
    mxRow->mbIsStartOfNewPage = rData.mbIsStartOfNewPage;
450
0
    mxRow->maName = rData.maName;
451
452
    // Trigger re-layout of the table.
453
0
    mxRow->getModel()->setModified(true);
454
0
 }
455
456
457
void TableRowUndo::getData( Data& rData )
458
0
{
459
0
    rData.mnRow = mxRow->mnRow;
460
0
    rData.mnHeight = mxRow->mnHeight;
461
0
    rData.mbOptimalHeight = mxRow->mbOptimalHeight;
462
0
    rData.mbIsVisible = mxRow->mbIsVisible;
463
0
    rData.mbIsStartOfNewPage = mxRow->mbIsStartOfNewPage;
464
0
    rData.maName = mxRow->maName;
465
0
}
466
467
468
TableStyleUndo::TableStyleUndo( const SdrTableObj& rTableObj )
469
0
:   SdrUndoAction(rTableObj.getSdrModelFromSdrObject())
470
0
    ,mxObjRef( const_cast< sdr::table::SdrTableObj*>( &rTableObj ) )
471
0
    ,mbHasRedoData(false)
472
0
{
473
0
    getData( maUndoData );
474
0
}
475
476
void TableStyleUndo::Undo()
477
0
{
478
0
    if( !mbHasRedoData )
479
0
    {
480
0
        getData( maRedoData );
481
0
        mbHasRedoData = true;
482
0
    }
483
0
    setData( maUndoData );
484
0
}
485
486
void TableStyleUndo::Redo()
487
0
{
488
0
    setData( maRedoData );
489
0
}
490
491
void TableStyleUndo::setData( const Data& rData )
492
0
{
493
0
    rtl::Reference<SdrTableObj> pTableObj = mxObjRef.get();
494
0
    if( pTableObj )
495
0
    {
496
0
        pTableObj->setTableStyle( rData.mxTableStyle );
497
0
        pTableObj->setTableStyleSettings( rData.maSettings );
498
0
    }
499
0
}
500
501
void TableStyleUndo::getData( Data& rData )
502
0
{
503
0
    rtl::Reference<SdrTableObj> pTableObj = mxObjRef.get();
504
0
    if( pTableObj )
505
0
    {
506
0
        rData.maSettings = pTableObj->getTableStyleSettings();
507
0
        rData.mxTableStyle = pTableObj->getTableStyle();
508
0
    }
509
0
}
510
511
}
512
513
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */