cid#1607171 Data race condition
[LibreOffice.git] / sc / source / ui / undo / undoblk.cxx
blobcd96fa833f2124930dfdcc46e056e639fc8acb99
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <scitems.hxx>
21 #include <utility>
22 #include <vcl/virdev.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <sfx2/app.hxx>
25 #include <comphelper/lok.hxx>
26 #include <osl/diagnose.h>
28 #include <undoblk.hxx>
29 #include <undoutil.hxx>
30 #include <document.hxx>
31 #include <patattr.hxx>
32 #include <docsh.hxx>
33 #include <tabvwsh.hxx>
34 #include <rangenam.hxx>
35 #include <rangeutl.hxx>
36 #include <stlpool.hxx>
37 #include <stlsheet.hxx>
38 #include <globstr.hrc>
39 #include <scresid.hxx>
40 #include <global.hxx>
41 #include <target.hxx>
42 #include <docpool.hxx>
43 #include <docfunc.hxx>
44 #include <attrib.hxx>
45 #include <chgtrack.hxx>
46 #include <transobj.hxx>
47 #include <refundo.hxx>
48 #include <undoolk.hxx>
49 #include <clipparam.hxx>
50 #include <rowheightcontext.hxx>
51 #include <refupdatecontext.hxx>
52 #include <validat.hxx>
53 #include <gridwin.hxx>
54 #include <columnspanset.hxx>
56 #include <memory>
57 #include <set>
59 // TODO:
60 /*A*/ // SetOptimalHeight on Document, if no View
61 /*B*/ // linked sheets
62 /*C*/ // ScArea
63 //? // check later
65 ScUndoInsertCells::ScUndoInsertCells( ScDocShell* pNewDocShell,
66 const ScRange& rRange,
67 SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
68 InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
69 bool bNewPartOfPaste ) :
70 ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
71 aEffRange( rRange ),
72 nCount( nNewCount ),
73 pTabs( std::move(pNewTabs) ),
74 pScenarios( std::move(pNewScenarios) ),
75 eCmd( eNewCmd ),
76 bPartOfPaste( bNewPartOfPaste )
78 ScDocument& rDoc = pDocShell->GetDocument();
79 if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER) // whole row?
81 aEffRange.aStart.SetCol(0);
82 aEffRange.aEnd.SetCol(rDoc.MaxCol());
85 if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER) // whole column?
87 aEffRange.aStart.SetRow(0);
88 aEffRange.aEnd.SetRow(rDoc.MaxRow());
91 SetChangeTrack();
94 ScUndoInsertCells::~ScUndoInsertCells()
98 OUString ScUndoInsertCells::GetComment() const
100 return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS );
103 bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction )
105 // If a paste undo action has already been added, append (detective) action there.
106 if ( pPasteUndo )
107 return pPasteUndo->Merge( pNextAction );
109 if ( bPartOfPaste )
110 if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) )
112 if (dynamic_cast<const ScUndoPaste*>(pWrapper->GetWrappedUndo()))
114 // Store paste action if this is part of paste with inserting cells.
115 // A list action isn't used because Repeat wouldn't work (insert wrong cells).
117 // Pass ownership of the wrapped SfxUndoAction* to pPasteUndO
118 pPasteUndo = pWrapper->ReleaseWrappedUndo();
119 return true;
123 // Call base class for detective handling
124 return ScMoveUndo::Merge( pNextAction );
127 void ScUndoInsertCells::SetChangeTrack()
129 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
130 if ( pChangeTrack )
132 pChangeTrack->AppendInsert( aEffRange );
133 nEndChangeAction = pChangeTrack->GetActionMax();
135 else
136 nEndChangeAction = 0;
139 void ScUndoInsertCells::DoChange( const bool bUndo )
141 ScDocument& rDoc = pDocShell->GetDocument();
142 SCTAB i;
144 if ( bUndo )
146 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
147 if ( pChangeTrack )
148 pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
150 else
151 SetChangeTrack();
153 // refresh of merged cells has to be after inserting/deleting
155 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
156 switch (eCmd)
158 case INS_INSROWS_BEFORE:
159 case INS_INSROWS_AFTER:
160 case INS_CELLSDOWN:
161 for( i=0; i<nCount; i++ )
164 if (bUndo)
165 rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
166 aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
167 else
168 rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
169 aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
171 if (pViewShell)
173 const tools::Long nSign = bUndo ? -1 : 1;
174 pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
177 break;
178 case INS_INSCOLS_BEFORE:
179 case INS_INSCOLS_AFTER:
180 case INS_CELLSRIGHT:
181 for( i=0; i<nCount; i++ )
183 if (bUndo)
184 rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
185 aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
186 else
187 rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
188 aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
190 if (pViewShell)
192 const tools::Long nSign = bUndo ? -1 : 1;
193 pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
196 break;
197 default:
199 // added to avoid warnings
203 ScRange aWorkRange( aEffRange );
204 if ( eCmd == INS_CELLSRIGHT ) // only "shift right" requires refresh of the moved area
205 aWorkRange.aEnd.SetCol(rDoc.MaxCol());
206 for( i=0; i<nCount; i++ )
208 if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
209 aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) )
211 SCCOL nEndCol = aWorkRange.aEnd.Col();
212 SCROW nEndRow = aWorkRange.aEnd.Row();
213 rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
217 // Undo for displaced attributes?
219 PaintPartFlags nPaint = PaintPartFlags::Grid;
221 switch (eCmd)
223 case INS_INSROWS_BEFORE:
224 case INS_INSROWS_AFTER:
225 nPaint |= PaintPartFlags::Left;
226 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
227 break;
228 case INS_CELLSDOWN:
229 for( i=0; i<nCount; i++ )
231 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
232 if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
234 aWorkRange.aStart.SetCol(0);
235 aWorkRange.aEnd.SetCol(rDoc.MaxCol());
236 nPaint |= PaintPartFlags::Left;
239 break;
240 case INS_INSCOLS_BEFORE:
241 case INS_INSCOLS_AFTER:
242 nPaint |= PaintPartFlags::Top; // top bar
243 [[fallthrough]];
244 case INS_CELLSRIGHT:
245 for( i=0; i<nCount; i++ )
247 aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
248 if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) )
249 { // AdjustDraw does not paint PaintPartFlags::Top,
250 aWorkRange.aStart.SetCol(0); // thus solved like this
251 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
252 nPaint |= PaintPartFlags::Left;
255 break;
256 default:
258 // added to avoid warnings
262 for( i=0; i<nCount; i++ )
264 pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
265 aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint );
267 pDocShell->PostDataChanged();
268 if (!pViewShell)
269 return;
271 pViewShell->CellContentChanged();
273 if (!comphelper::LibreOfficeKit::isActive())
274 return;
276 SCTAB nTab = pViewShell->GetViewData().GetTabNo();
277 bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT);
278 bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN);
280 if (bColsAffected)
281 ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
283 if (bRowsAffected)
284 ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
286 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
287 pViewShell,
288 bColsAffected, bRowsAffected,
289 true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
290 true /* bGroups */, nTab);
293 void ScUndoInsertCells::Undo()
295 if ( pPasteUndo )
296 pPasteUndo->Undo(); // undo paste first
298 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
299 BeginUndo();
300 DoChange( true );
301 EndUndo();
303 ScDocument& rDoc = pDocShell->GetDocument();
304 for (SCTAB i = 0; i < nCount; ++i)
305 rDoc.SetDrawPageSize(pTabs[i]);
308 void ScUndoInsertCells::Redo()
310 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
311 BeginRedo();
312 DoChange( false );
313 EndRedo();
315 if ( pPasteUndo )
316 pPasteUndo->Redo(); // redo paste last
318 ScDocument& rDoc = pDocShell->GetDocument();
319 for (SCTAB i = 0; i < nCount; ++i)
320 rDoc.SetDrawPageSize(pTabs[i]);
323 void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget)
325 if (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr)
327 if ( pPasteUndo )
329 // Repeat for paste with inserting cells is handled completely
330 // by the Paste undo action
332 pPasteUndo->Repeat( rTarget );
334 else
335 static_cast<ScTabViewTarget&>(rTarget).GetViewShell()->InsertCells( eCmd );
339 bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const
341 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
344 ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell* pNewDocShell,
345 const ScRange& rRange,
346 SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
347 DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
348 ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
349 aEffRange( rRange ),
350 nCount( nNewCount ),
351 pTabs( std::move(pNewTabs) ),
352 pScenarios( std::move(pNewScenarios) ),
353 eCmd( eNewCmd )
355 ScDocument& rDoc = pDocShell->GetDocument();
356 if (eCmd == DelCellCmd::Rows) // whole row?
358 aEffRange.aStart.SetCol(0);
359 aEffRange.aEnd.SetCol(rDoc.MaxCol());
362 if (eCmd == DelCellCmd::Cols) // whole column?
364 aEffRange.aStart.SetRow(0);
365 aEffRange.aEnd.SetRow(rDoc.MaxRow());
368 SetChangeTrack();
371 ScUndoDeleteCells::~ScUndoDeleteCells()
375 OUString ScUndoDeleteCells::GetComment() const
377 return ScResId( STR_UNDO_DELETECELLS ); // "Delete"
380 void ScUndoDeleteCells::SetChangeTrack()
382 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
383 if ( pChangeTrack )
384 pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(),
385 nStartChangeAction, nEndChangeAction );
386 else
387 nStartChangeAction = nEndChangeAction = 0;
390 void ScUndoDeleteCells::DoChange( const bool bUndo )
392 ScDocument& rDoc = pDocShell->GetDocument();
393 SCTAB i;
395 if ( bUndo )
397 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
398 if ( pChangeTrack )
399 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
401 else
402 SetChangeTrack();
404 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
406 switch (eCmd)
408 case DelCellCmd::Rows:
409 case DelCellCmd::CellsUp:
410 for( i=0; i<nCount; i++ )
412 if (bUndo)
413 rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
414 aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
415 else
416 rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
417 aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
419 if (pViewShell)
421 const tools::Long nSign = bUndo ? 1 : -1;
422 pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
425 break;
426 case DelCellCmd::Cols:
427 case DelCellCmd::CellsLeft:
428 for( i=0; i<nCount; i++ )
430 if (bUndo)
431 rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
432 aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
433 else
434 rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
435 aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
437 if (pViewShell)
439 const tools::Long nSign = bUndo ? 1 : -1;
440 pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
443 break;
444 default:
446 // added to avoid warnings
450 // if Undo, restore references
451 for( i=0; i<nCount && bUndo; i++ )
453 pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
454 InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc);
457 ScRange aWorkRange( aEffRange );
458 if ( eCmd == DelCellCmd::CellsLeft ) // only "shift left" requires refresh of the moved area
459 aWorkRange.aEnd.SetCol(rDoc.MaxCol());
461 for( i=0; i<nCount; i++ )
463 if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
464 aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
466 // #i51445# old merge flag attributes must be deleted also for single cells,
467 // not only for whole columns/rows
469 if ( !bUndo )
471 if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
472 aWorkRange.aEnd.SetCol(rDoc.MaxCol());
473 if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
474 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
475 ScMarkData aMarkData(rDoc.GetSheetLimits());
476 aMarkData.SelectOneTable( aWorkRange.aStart.Tab() );
477 ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
478 aPattern.GetItemSet().Put( ScMergeFlagAttr() );
479 rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(),
480 aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(),
481 aMarkData, aPattern );
484 SCCOL nEndCol = aWorkRange.aEnd.Col();
485 SCROW nEndRow = aWorkRange.aEnd.Row();
486 rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
490 // paint
491 PaintPartFlags nPaint = PaintPartFlags::Grid;
492 switch (eCmd)
494 case DelCellCmd::Rows:
495 nPaint |= PaintPartFlags::Left;
496 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
497 break;
498 case DelCellCmd::CellsUp:
499 for( i=0; i<nCount; i++ )
501 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
502 if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
504 aWorkRange.aStart.SetCol(0);
505 aWorkRange.aEnd.SetCol(rDoc.MaxCol());
506 nPaint |= PaintPartFlags::Left;
509 break;
510 case DelCellCmd::Cols:
511 nPaint |= PaintPartFlags::Top; // top bar
512 [[fallthrough]];
513 case DelCellCmd::CellsLeft:
514 for( i=0; i<nCount; i++ )
516 aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
517 if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) )
519 aWorkRange.aStart.SetCol(0);
520 aWorkRange.aEnd.SetRow(rDoc.MaxRow());
521 nPaint |= PaintPartFlags::Left;
524 break;
525 default:
527 // added to avoid warnings
531 for( i=0; i<nCount; i++ )
533 pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
534 aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES );
536 // Selection not until EndUndo
538 pDocShell->PostDataChanged();
539 // CellContentChanged comes with the selection
541 if (!pViewShell)
542 return;
544 if (!comphelper::LibreOfficeKit::isActive())
545 return;
547 SCTAB nTab = pViewShell->GetViewData().GetTabNo();
548 bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft);
549 bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp);
551 if (bColsAffected)
552 ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
554 if (bRowsAffected)
555 ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
557 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
558 pViewShell,
559 bColsAffected, bRowsAffected,
560 true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
561 true /* bGroups */, nTab);
565 void ScUndoDeleteCells::Undo()
567 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
568 BeginUndo();
569 DoChange( true );
570 EndUndo();
572 ScDocument& rDoc = pDocShell->GetDocument();
574 // Now that DBData have been restored in ScMoveUndo::EndUndo() via its
575 // pRefUndoDoc we can apply the AutoFilter buttons.
576 // Add one row for cases undoing deletion right above a cut AutoFilter
577 // range so the buttons are removed.
578 SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow());
579 for (SCTAB i=0; i < nCount; ++i)
581 rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
582 aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]);
585 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
587 // Selection not until EndUndo
588 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
589 if (pViewShell)
591 for( SCTAB i=0; i<nCount; i++ )
593 pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) );
597 for (SCTAB i = 0; i < nCount; ++i)
598 rDoc.SetDrawPageSize(pTabs[i]);
601 void ScUndoDeleteCells::Redo()
603 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
604 BeginRedo();
605 DoChange( false);
606 EndRedo();
608 ScDocument& rDoc = pDocShell->GetDocument();
610 for (SCTAB i=0; i < nCount; ++i)
612 rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
613 aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]);
616 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
618 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
619 if (pViewShell)
620 pViewShell->DoneBlockMode(); // current way
622 for (SCTAB i = 0; i < nCount; ++i)
623 rDoc.SetDrawPageSize(pTabs[i]);
626 void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget)
628 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
629 pViewTarget->GetViewShell()->DeleteCells( eCmd );
632 bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const
634 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
637 // delete cells in multiselection
638 ScUndoDeleteMulti::ScUndoDeleteMulti(
639 ScDocShell* pNewDocShell,
640 bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
641 std::vector<sc::ColRowSpan>&& rSpans,
642 ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
643 ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
644 mbRows(bNewRows),
645 mbRefresh(bNeedsRefresh),
646 nTab( nNewTab ),
647 maSpans(std::move(rSpans))
649 SetChangeTrack();
652 ScUndoDeleteMulti::~ScUndoDeleteMulti()
656 OUString ScUndoDeleteMulti::GetComment() const
658 return ScResId( STR_UNDO_DELETECELLS ); // like DeleteCells
661 void ScUndoDeleteMulti::DoChange() const
663 SCCOL nStartCol;
664 SCROW nStartRow;
665 PaintPartFlags nPaint;
666 ScDocument& rDoc = pDocShell->GetDocument();
667 if (mbRows)
669 nStartCol = 0;
670 nStartRow = static_cast<SCROW>(maSpans[0].mnStart);
671 nPaint = PaintPartFlags::Grid | PaintPartFlags::Left;
673 else
675 nStartCol = static_cast<SCCOL>(maSpans[0].mnStart);
676 nStartRow = 0;
677 nPaint = PaintPartFlags::Grid | PaintPartFlags::Top;
680 if (mbRefresh)
682 SCCOL nEndCol = rDoc.MaxCol();
683 SCROW nEndRow = rDoc.MaxRow();
684 rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
685 rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
688 pDocShell->PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint );
689 pDocShell->PostDataChanged();
690 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
691 if (pViewShell)
692 pViewShell->CellContentChanged();
694 ShowTable( nTab );
697 void ScUndoDeleteMulti::SetChangeTrack()
699 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
700 if ( pChangeTrack )
702 ScDocument& rDoc = pDocShell->GetDocument();
703 nStartChangeAction = pChangeTrack->GetActionMax() + 1;
704 ScRange aRange( 0, 0, nTab, 0, 0, nTab );
705 if (mbRows)
706 aRange.aEnd.SetCol( rDoc.MaxCol() );
707 else
708 aRange.aEnd.SetRow( rDoc.MaxRow() );
709 // delete in reverse
710 std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
711 for (; ri != riEnd; ++ri)
713 SCCOLROW nEnd = ri->mnEnd;
714 SCCOLROW nStart = ri->mnStart;
715 if (mbRows)
717 aRange.aStart.SetRow( nStart );
718 aRange.aEnd.SetRow( nEnd );
720 else
722 aRange.aStart.SetCol( static_cast<SCCOL>(nStart) );
723 aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) );
725 sal_uLong nDummyStart;
726 pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
727 nDummyStart, nEndChangeAction );
730 else
731 nStartChangeAction = nEndChangeAction = 0;
734 void ScUndoDeleteMulti::Undo()
736 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
737 BeginUndo();
739 ScDocument& rDoc = pDocShell->GetDocument();
741 // reverse delete -> forward insert
742 for (const auto& rSpan : maSpans)
744 SCCOLROW nStart = rSpan.mnStart;
745 SCCOLROW nEnd = rSpan.mnEnd;
746 if (mbRows)
747 rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
748 else
749 rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
752 for (const auto& rSpan : maSpans)
754 SCCOLROW nStart = rSpan.mnStart;
755 SCCOLROW nEnd = rSpan.mnEnd;
756 if (mbRows)
757 pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc);
758 else
759 pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab,
760 static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc);
763 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
764 if ( pChangeTrack )
765 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
767 DoChange();
769 //! redrawing the selection is not possible at the moment
770 //! since no data for selection exist
772 EndUndo();
773 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
776 void ScUndoDeleteMulti::Redo()
778 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
779 BeginRedo();
781 ScDocument& rDoc = pDocShell->GetDocument();
783 // reverse delete
784 std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
785 for (; ri != riEnd; ++ri)
787 SCCOLROW nEnd = ri->mnEnd;
788 SCCOLROW nStart = ri->mnStart;
789 if (mbRows)
790 rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
791 else
792 rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
795 SetChangeTrack();
797 DoChange();
799 EndRedo();
800 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
803 void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget)
805 // if single selection
806 if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
807 pTabViewTarget->GetViewShell()->DeleteCells( DelCellCmd::Rows );
810 bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const
812 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
815 ScUndoCut::ScUndoCut(ScDocShell* pNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd,
816 const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc)
817 : ScBlockUndo(pNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT)
818 , aMarkData(rMark)
819 , pUndoDoc(std::move(pNewUndoDoc))
820 , aExtendedRange(aRange)
822 SetChangeTrack();
825 ScUndoCut::~ScUndoCut()
829 OUString ScUndoCut::GetComment() const
831 return ScResId( STR_UNDO_CUT ); // "cut"
834 void ScUndoCut::SetChangeTrack()
836 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
837 if ( pChangeTrack )
838 pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
839 nStartChangeAction, nEndChangeAction, SC_CACM_CUT );
840 else
841 nStartChangeAction = nEndChangeAction = 0;
844 void ScUndoCut::DoChange( const bool bUndo )
846 ScDocument& rDoc = pDocShell->GetDocument();
847 sal_uInt16 nExtFlags = 0;
849 // do not undo/redo objects and note captions, they are handled via drawing undo
850 InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
852 if (bUndo) // only for Undo
854 // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
855 SCTAB nTabCount = rDoc.GetTableCount();
856 ScRange aCopyRange = aExtendedRange;
857 aCopyRange.aStart.SetTab(0);
858 aCopyRange.aEnd.SetTab(nTabCount-1);
859 pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc);
860 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
861 if ( pChangeTrack )
862 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
864 BroadcastChanges(aCopyRange);
866 else // only for Redo
868 pDocShell->UpdatePaintExt( nExtFlags, aExtendedRange );
869 rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
870 aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags );
871 SetChangeTrack();
874 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
875 if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
876 /*A*/ pDocShell->PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
878 if ( !bUndo ) // draw redo after updating row heights
879 RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
881 pDocShell->PostDataChanged();
882 if (pViewShell)
883 pViewShell->CellContentChanged();
886 void ScUndoCut::Undo()
888 BeginUndo();
889 DoChange( true );
890 EndUndo();
893 void ScUndoCut::Redo()
895 BeginRedo();
896 ScDocument& rDoc = pDocShell->GetDocument();
897 EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
898 DoChange( false );
899 EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
900 EndRedo();
903 void ScUndoCut::Repeat(SfxRepeatTarget& rTarget)
905 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
906 pViewTarget->GetViewShell()->CutToClip();
909 bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const
911 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
914 ScUndoPaste::ScUndoPaste( ScDocShell* pNewDocShell, const ScRangeList& rRanges,
915 const ScMarkData& rMark,
916 ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
917 InsertDeleteFlags nNewFlags,
918 std::unique_ptr<ScRefUndoData> pRefData,
919 bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) :
920 ScMultiBlockUndo( pNewDocShell, rRanges ),
921 aMarkData( rMark ),
922 pUndoDoc( std::move(pNewUndoDoc) ),
923 pRedoDoc( std::move(pNewRedoDoc) ),
924 nFlags( nNewFlags ),
925 pRefUndoData( std::move(pRefData) ),
926 bRedoFilled( bRedoIsFilled )
928 if ( pRefUndoData )
929 pRefUndoData->DeleteUnchanged( &pDocShell->GetDocument() );
931 if ( pOptions )
932 aPasteOptions = *pOptions; // used only for Repeat
934 SetChangeTrack();
937 ScUndoPaste::~ScUndoPaste()
939 pUndoDoc.reset();
940 pRedoDoc.reset();
941 pRefUndoData.reset();
942 pRefRedoData.reset();
945 OUString ScUndoPaste::GetComment() const
947 return ScResId( STR_UNDO_PASTE ); // "paste"
950 void ScUndoPaste::SetChangeTrack()
952 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
953 if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
955 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
957 pChangeTrack->AppendContentRange(maBlockRanges[i], pUndoDoc.get(),
958 nStartChangeAction, nEndChangeAction, SC_CACM_PASTE );
961 else
962 nStartChangeAction = nEndChangeAction = 0;
965 void ScUndoPaste::DoChange(bool bUndo)
967 ScDocument& rDoc = pDocShell->GetDocument();
969 // RefUndoData for redo is created before first undo
970 // (with DeleteUnchanged after the DoUndo call)
971 bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData );
972 if ( bCreateRedoData )
973 pRefRedoData.reset( new ScRefUndoData( &rDoc ) );
975 ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get();
977 // Always back-up either all or none of the content for Undo
978 InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE;
979 if (nFlags & InsertDeleteFlags::CONTENTS)
980 nUndoFlags |= InsertDeleteFlags::CONTENTS;
981 if (nFlags & InsertDeleteFlags::ATTRIB)
982 nUndoFlags |= InsertDeleteFlags::ATTRIB;
984 // do not undo/redo objects and note captions, they are handled via drawing undo
985 nUndoFlags &= ~InsertDeleteFlags::OBJECTS;
986 nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
988 bool bPaintAll = false;
990 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
992 SCTAB nTabCount = rDoc.GetTableCount();
993 if ( bUndo && !bRedoFilled )
995 if (!pRedoDoc)
997 bool bColInfo = true;
998 bool bRowInfo = true;
999 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1001 const ScRange& r = maBlockRanges[i];
1002 bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow());
1003 bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol());
1004 if (!bColInfo && !bRowInfo)
1005 break;
1008 pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
1009 pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo );
1011 // read "redo" data from the document in the first undo
1012 // all sheets - CopyToDocument skips those that don't exist in pRedoDoc
1013 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1015 ScRange aCopyRange = maBlockRanges[i];
1016 aCopyRange.aStart.SetTab(0);
1017 aCopyRange.aEnd.SetTab(nTabCount-1);
1018 rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc);
1019 bRedoFilled = true;
1023 sal_uInt16 nExtFlags = 0;
1024 pDocShell->UpdatePaintExt(nExtFlags, maBlockRanges.Combine());
1026 rDoc.ForgetNoteCaptions(maBlockRanges, false);
1027 aMarkData.MarkToMulti();
1028 rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here
1029 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1030 rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged);
1032 aMarkData.MarkToSimple();
1034 SCTAB nFirstSelected = aMarkData.GetFirstSelected();
1036 if ( !bUndo && pRedoDoc ) // Redo: UndoToDocument before handling RefData
1038 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1040 ScRange aRange = maBlockRanges[i];
1041 aRange.aStart.SetTab(nFirstSelected);
1042 aRange.aEnd.SetTab(nFirstSelected);
1043 pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
1044 for (const auto& rTab : aMarkData)
1046 if (rTab >= nTabCount)
1047 break;
1049 if (rTab == nFirstSelected)
1050 continue;
1052 aRange.aStart.SetTab(rTab);
1053 aRange.aEnd.SetTab(rTab);
1054 pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
1059 if (pWorkRefData)
1061 pWorkRefData->DoUndo( &rDoc, true ); // true = bSetChartRangeLists for SetChartListenerCollection
1062 if (!maBlockRanges.empty() &&
1063 rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab()))
1064 bPaintAll = true;
1067 if ( bCreateRedoData && pRefRedoData )
1068 pRefRedoData->DeleteUnchanged( &rDoc );
1070 if (bUndo) // Undo: UndoToDocument after handling RefData
1072 for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
1074 ScRange aRange = maBlockRanges[i];
1075 for (const auto& rTab : aMarkData)
1077 if (rTab >= nTabCount)
1078 break;
1079 aRange.aStart.SetTab(rTab);
1080 aRange.aEnd.SetTab(rTab);
1081 pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
1086 if ( bUndo )
1088 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1089 if ( pChangeTrack )
1090 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
1092 else
1093 SetChangeTrack();
1095 ScRangeList aDrawRanges(maBlockRanges);
1096 PaintPartFlags nPaint = PaintPartFlags::Grid;
1098 // For sheet geometry invalidation.
1099 bool bColsAffected = false;
1100 bool bRowsAffected = false;
1102 for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i)
1104 ScRange& rDrawRange = aDrawRanges[i];
1105 rDoc.ExtendMerge(rDrawRange, true); // only needed for single sheet (text/rtf etc.)
1106 ScRangeList aRangeList(rDrawRange);
1107 ScMarkData aData(rDoc.GetSheetLimits(), aRangeList);
1108 if (bPaintAll)
1110 rDrawRange.aStart.SetCol(0);
1111 rDrawRange.aStart.SetRow(0);
1112 rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1113 rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1114 nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
1115 if (pViewShell)
1116 pViewShell->AdjustBlockHeight(false, &aData);
1118 else
1120 if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column
1122 nPaint |= PaintPartFlags::Top;
1123 rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1124 bColsAffected = true;
1126 if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row
1128 nPaint |= PaintPartFlags::Left;
1129 rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1130 bRowsAffected = true;
1132 if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData))
1134 rDrawRange.aStart.SetCol(0);
1135 rDrawRange.aStart.SetRow(0);
1136 rDrawRange.aEnd.SetCol(rDoc.MaxCol());
1137 rDrawRange.aEnd.SetRow(rDoc.MaxRow());
1138 nPaint |= PaintPartFlags::Left;
1140 pDocShell->UpdatePaintExt(nExtFlags, rDrawRange);
1144 if ( !bUndo ) // draw redo after updating row heights
1145 RedoSdrUndoAction(mpDrawUndo.get());
1147 pDocShell->PostPaint(aDrawRanges, nPaint, nExtFlags);
1149 pDocShell->PostDataChanged();
1150 if (!pViewShell)
1151 return;
1153 pViewShell->CellContentChanged();
1155 if (bColsAffected || bRowsAffected)
1156 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1157 pViewShell,
1158 bColsAffected, bRowsAffected,
1159 true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
1160 true /* bGroups */, aDrawRanges[0].aStart.Tab());
1163 void ScUndoPaste::Undo()
1165 BeginUndo();
1166 DoChange(true);
1167 if (!maBlockRanges.empty())
1168 ShowTable(maBlockRanges.front());
1169 EndUndo();
1170 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1173 void ScUndoPaste::Redo()
1175 BeginRedo();
1176 ScDocument& rDoc = pDocShell->GetDocument();
1177 EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
1178 DoChange( false );
1179 EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
1180 EndRedo();
1181 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1184 void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
1186 auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget);
1187 if (!pViewTarget)
1188 return;
1190 ScTabViewShell* pViewSh = pViewTarget->GetViewShell();
1191 // keep a reference in case the clipboard is changed during PasteFromClip
1192 const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pViewSh->GetViewData().GetActiveWin()));
1193 if (pOwnClip)
1195 pViewSh->PasteFromClip( nFlags, pOwnClip->GetDocument(),
1196 aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
1197 aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
1198 true ); // allow warning dialog
1202 bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const
1204 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
1207 ScUndoDragDrop::ScUndoDragDrop( ScDocShell* pNewDocShell,
1208 const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
1209 ScDocumentUniquePtr pUndoDocument, bool bScenario ) :
1210 ScMoveUndo( pNewDocShell, std::move(pUndoDocument), nullptr ),
1211 mnPaintExtFlags( 0 ),
1212 aSrcRange( rRange ),
1213 bCut( bNewCut ),
1214 bKeepScenarioFlags( bScenario )
1216 ScAddress aDestEnd(aNewDestPos);
1217 aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row());
1218 aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col());
1219 aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab());
1221 bool bIncludeFiltered = bCut;
1222 if ( !bIncludeFiltered )
1224 // find number of non-filtered rows
1225 SCROW nPastedCount = pDocShell->GetDocument().CountNonFilteredRows(
1226 aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab());
1228 if ( nPastedCount == 0 )
1229 nPastedCount = 1;
1230 aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 );
1233 aDestRange.aStart = aNewDestPos;
1234 aDestRange.aEnd = aDestEnd;
1236 SetChangeTrack();
1239 ScUndoDragDrop::~ScUndoDragDrop()
1243 OUString ScUndoDragDrop::GetComment() const
1244 { // "Move" : "Copy"
1245 return bCut ?
1246 ScResId( STR_UNDO_MOVE ) :
1247 ScResId( STR_UNDO_COPY );
1250 void ScUndoDragDrop::SetChangeTrack()
1252 ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
1253 if ( pChangeTrack )
1255 if ( bCut )
1257 nStartChangeAction = pChangeTrack->GetActionMax() + 1;
1258 pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() );
1259 nEndChangeAction = pChangeTrack->GetActionMax();
1261 else
1262 pChangeTrack->AppendContentRange( aDestRange, pRefUndoDoc.get(),
1263 nStartChangeAction, nEndChangeAction );
1265 else
1266 nStartChangeAction = nEndChangeAction = 0;
1269 void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
1271 PaintPartFlags nPaint = PaintPartFlags::Grid;
1272 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1273 ScDocument& rDoc = pDocShell->GetDocument();
1275 if (pViewShell)
1277 ScopedVclPtrInstance< VirtualDevice > pVirtDev;
1278 ScViewData& rViewData = pViewShell->GetViewData();
1279 sc::RowHeightContext aCxt(
1280 rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(),
1281 pVirtDev);
1283 if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true))
1285 // tdf#76183: recalculate objects' positions
1286 rDoc.SetDrawPageSize(aRange.aStart.Tab());
1287 aRange.aStart.SetCol(0);
1288 aRange.aEnd.SetCol(rDoc.MaxCol());
1289 aRange.aEnd.SetRow(rDoc.MaxRow());
1290 nPaint |= PaintPartFlags::Left;
1294 if ( bKeepScenarioFlags )
1296 // Copy scenario -> also paint scenario boarder
1297 aRange.aStart.SetCol(0);
1298 aRange.aStart.SetRow(0);
1299 aRange.aEnd.SetCol(rDoc.MaxCol());
1300 aRange.aEnd.SetRow(rDoc.MaxRow());
1303 // column/row info (width/height) included if whole columns/rows were copied
1304 if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() )
1306 nPaint |= PaintPartFlags::Left;
1307 aRange.aEnd.SetRow(rDoc.MaxRow());
1309 if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() )
1311 nPaint |= PaintPartFlags::Top;
1312 aRange.aEnd.SetCol(rDoc.MaxCol());
1315 pDocShell->PostPaint( aRange, nPaint, nExtFlags );
1318 void ScUndoDragDrop::DoUndo( ScRange aRange )
1320 ScDocument& rDoc = pDocShell->GetDocument();
1322 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1323 if ( pChangeTrack )
1324 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
1326 // Database range before data, so that the Autofilter button match up in ExtendMerge
1328 ScRange aPaintRange = aRange;
1329 rDoc.ExtendMerge( aPaintRange ); // before deleting
1331 pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
1333 // do not undo objects and note captions, they are handled via drawing undo
1334 InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
1336 // Additionally discard/forget caption ownership during deletion, as
1337 // Drag&Drop is a special case in that the Undo holds captions of the
1338 // transferred target range, which would get deleted and
1339 // SdrGroupUndo::Undo() would attempt to access invalidated captions and
1340 // crash, tdf#92995
1341 InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS;
1343 rDoc.DeleteAreaTab( aRange, nDelFlags );
1344 pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
1345 if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
1346 rDoc.ExtendMerge( aRange, true );
1348 aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
1349 aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
1351 pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
1352 maPaintRanges.Join(aPaintRange);
1354 if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
1356 if (comphelper::LibreOfficeKit::isActive())
1358 pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Col(), true);
1359 pTabViewShell->OnLOKSetWidthOrHeight(aPaintRange.aStart.Row(), false);
1362 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1363 pTabViewShell,
1364 true /* bColumns */, true /* bRows */,
1365 true /* bSizes */, true /* bHidden */, true /* bFiltered */,
1366 true /* bGroups */, aPaintRange.aStart.Tab());
1371 void ScUndoDragDrop::Undo()
1373 mnPaintExtFlags = 0;
1374 maPaintRanges.RemoveAll();
1376 BeginUndo();
1378 if (bCut)
1380 // During undo, we move cells from aDestRange to aSrcRange.
1382 ScDocument& rDoc = pDocShell->GetDocument();
1384 SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
1385 SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
1386 SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
1388 sc::RefUpdateContext aCxt(rDoc);
1389 aCxt.meMode = URM_MOVE;
1390 aCxt.maRange = aSrcRange;
1391 aCxt.mnColDelta = nColDelta;
1392 aCxt.mnRowDelta = nRowDelta;
1393 aCxt.mnTabDelta = nTabDelta;
1395 // Global range names.
1396 ScRangeName* pName = rDoc.GetRangeName();
1397 if (pName)
1398 pName->UpdateReference(aCxt);
1400 SCTAB nTabCount = rDoc.GetTableCount();
1401 for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
1403 // Sheet-local range names.
1404 pName = rDoc.GetRangeName(nTab);
1405 if (pName)
1406 pName->UpdateReference(aCxt, nTab);
1409 ScValidationDataList* pValidList = rDoc.GetValidationList();
1410 if (pValidList)
1412 // Update the references of validation entries.
1413 pValidList->UpdateReference(aCxt);
1416 DoUndo(aDestRange);
1417 DoUndo(aSrcRange);
1419 rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false);
1421 else
1422 DoUndo(aDestRange);
1424 for (size_t i = 0; i < maPaintRanges.size(); ++i)
1426 const ScRange& r = maPaintRanges[i];
1427 PaintArea(r, mnPaintExtFlags);
1430 EndUndo();
1431 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1434 void ScUndoDragDrop::Redo()
1436 BeginRedo();
1438 ScDocument& rDoc = pDocShell->GetDocument();
1439 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1441 EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
1443 // do not undo/redo objects and note captions, they are handled via drawing undo
1444 constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
1446 /* TODO: Redoing note captions is quite tricky due to the fact that a
1447 helper clip document is used. While (re-)pasting the contents to the
1448 destination area, the original pointers to the captions created while
1449 dropping have to be restored. A simple CopyFromClip() would create new
1450 caption objects that are not tracked by drawing undo, and the captions
1451 restored by drawing redo would live without cell note objects pointing
1452 to them. So, first, CopyToClip() and CopyFromClip() are called without
1453 cloning the caption objects. This leads to cell notes pointing to the
1454 wrong captions from source area that will be removed by drawing redo
1455 later. Second, the pointers to the new captions have to be restored.
1456 Sadly, currently these pointers are not stored anywhere but in the list
1457 of drawing undo actions. */
1459 SCTAB nTab;
1460 ScMarkData aSourceMark(rDoc.GetSheetLimits());
1461 for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
1462 aSourceMark.SelectTable( nTab, true );
1464 // do not clone objects and note captions into clipdoc (see above)
1465 // but at least copy notes
1466 ScClipParam aClipParam(aSrcRange, bCut);
1467 rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false);
1469 if (bCut)
1471 ScRange aSrcPaintRange = aSrcRange;
1472 rDoc.ExtendMerge( aSrcPaintRange ); // before deleting
1473 sal_uInt16 nExtFlags = 0;
1474 pDocShell->UpdatePaintExt( nExtFlags, aSrcPaintRange );
1475 rDoc.DeleteAreaTab( aSrcRange, nRedoFlags );
1476 PaintArea( aSrcPaintRange, nExtFlags );
1479 ScMarkData aDestMark(rDoc.GetSheetLimits());
1480 for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
1481 aDestMark.SelectTable( nTab, true );
1483 bool bIncludeFiltered = bCut;
1484 // TODO: restore old note captions instead of cloning new captions...
1485 rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
1487 if (bCut)
1488 for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
1489 rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(),
1490 aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row(), nTab );
1492 // skipped rows and merged cells don't mix
1493 if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
1494 pDocShell->GetDocFunc().UnmergeCells( aDestRange, false, nullptr );
1496 for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
1498 SCCOL nEndCol = aDestRange.aEnd.Col();
1499 SCROW nEndRow = aDestRange.aEnd.Row();
1500 rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(),
1501 nEndCol, nEndRow, nTab, true );
1502 PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab,
1503 nEndCol, nEndRow, nTab ), 0 );
1506 SetChangeTrack();
1508 pClipDoc.reset();
1509 ShowTable( aDestRange.aStart.Tab() );
1511 RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
1512 EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
1514 EndRedo();
1515 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
1517 if (comphelper::LibreOfficeKit::isActive())
1519 SCCOL nStartCol = aDestRange.aStart.Col();
1520 SCROW nStartRow = aDestRange.aStart.Row();
1521 if (bCut)
1523 nStartCol = std::min(nStartCol, aSrcRange.aStart.Col());
1524 nStartRow = std::min(nStartRow, aSrcRange.aStart.Row());
1527 if (ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell())
1529 pTabViewShell->OnLOKSetWidthOrHeight(nStartCol, true);
1530 pTabViewShell->OnLOKSetWidthOrHeight(nStartRow, false);
1532 SCTAB nStartTab = aDestRange.aStart.Tab();
1533 SCTAB nEndTab = aDestRange.aEnd.Tab();
1534 if (bCut)
1536 nStartTab = std::min(nStartTab, aSrcRange.aStart.Tab());
1537 nEndTab = std::max(nEndTab, aSrcRange.aEnd.Tab());
1539 for (nTab = nStartTab; nTab <= nEndTab; ++nTab)
1541 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
1542 pTabViewShell, true /* bColumns */, true /* bRows */,
1543 true /* bSizes */, true /* bHidden */, true /* bFiltered */, true /* bGroups */,
1544 nTab);
1550 void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */)
1554 bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const
1556 return false; // not possible
1559 // Insert list containing range names
1560 // (Insert|Name|Insert =>[List])
1561 ScUndoListNames::ScUndoListNames(ScDocShell* pNewDocShell, const ScRange& rRange,
1562 ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc)
1563 : ScBlockUndo(pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT)
1564 , xUndoDoc(std::move(pNewUndoDoc))
1565 , xRedoDoc(std::move(pNewRedoDoc))
1569 OUString ScUndoListNames::GetComment() const
1571 return ScResId( STR_UNDO_LISTNAMES );
1574 void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const
1576 ScDocument& rDoc = pDocShell->GetDocument();
1578 rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL );
1579 pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc);
1580 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
1581 pDocShell->PostDataChanged();
1582 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1583 if (pViewShell)
1584 pViewShell->CellContentChanged();
1587 void ScUndoListNames::Undo()
1589 BeginUndo();
1590 DoChange(xUndoDoc.get());
1591 EndUndo();
1594 void ScUndoListNames::Redo()
1596 BeginRedo();
1597 DoChange(xRedoDoc.get());
1598 EndRedo();
1601 void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget)
1603 if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
1604 pTabViewTarget->GetViewShell()->InsertNameList();
1607 bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const
1609 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
1612 ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell* pNewDocShell, SCTAB nTab):
1613 ScSimpleUndo( pNewDocShell ),
1614 mnTab(nTab),
1615 mpUndoDoc(createUndoRedoData())
1619 ScUndoConditionalFormat::~ScUndoConditionalFormat()
1623 ScDocumentUniquePtr ScUndoConditionalFormat::createUndoRedoData()
1625 ScDocument& rDoc = pDocShell->GetDocument();
1626 ScDocumentUniquePtr pUndoRedoDoc(new ScDocument(SCDOCMODE_UNDO));
1627 pUndoRedoDoc->InitUndo(rDoc, mnTab, mnTab);
1628 if (const auto* pList = rDoc.GetCondFormList(mnTab))
1629 pUndoRedoDoc->SetCondFormList(new ScConditionalFormatList(*pUndoRedoDoc, *pList), mnTab);
1630 return pUndoRedoDoc;
1633 OUString ScUndoConditionalFormat::GetComment() const
1635 return ScResId( STR_UNDO_CONDFORMAT );
1638 void ScUndoConditionalFormat::Undo()
1640 DoChange(mpUndoDoc.get());
1643 void ScUndoConditionalFormat::Redo()
1645 DoChange(mpRedoDoc.get());
1648 void ScUndoConditionalFormat::DoChange(ScDocument* pSrcDoc)
1650 ScDocument& rDoc = pDocShell->GetDocument();
1652 // Restore all conditional formats in the tab. This is simpler and more reliable, than
1653 // restoring formats in a specific range, and then trying to join selectively the restored
1654 // formats with the other formats in the tab, to get the correct state.
1655 ScRangeList aCombinedRange;
1656 if (const auto* pOldList = rDoc.GetCondFormList(mnTab))
1657 aCombinedRange = pOldList->GetCombinedRange();
1659 if (const auto* pNewList = pSrcDoc->GetCondFormList(mnTab))
1661 for (const auto& cond : *pNewList)
1662 for (const auto& range : cond->GetRange())
1663 aCombinedRange.Join(range);
1664 rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pNewList), mnTab);
1666 else
1668 rDoc.SetCondFormList(nullptr, mnTab);
1670 pDocShell->PostPaint(aCombinedRange, PaintPartFlags::Grid);
1671 pDocShell->PostDataChanged();
1672 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1673 if (pViewShell)
1674 pViewShell->CellContentChanged();
1677 void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& )
1681 bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const
1683 return false;
1686 ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell* pNewDocShell,
1687 ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab):
1688 ScSimpleUndo( pNewDocShell ),
1689 mpUndoDoc(std::move(pUndoDoc)),
1690 mpRedoDoc(std::move(pRedoDoc)),
1691 mnTab(nTab)
1695 ScUndoConditionalFormatList::~ScUndoConditionalFormatList()
1699 OUString ScUndoConditionalFormatList::GetComment() const
1701 return ScResId( STR_UNDO_CONDFORMAT_LIST );
1704 void ScUndoConditionalFormatList::Undo()
1706 DoChange(mpUndoDoc.get());
1709 void ScUndoConditionalFormatList::Redo()
1711 DoChange(mpRedoDoc.get());
1714 void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc)
1716 ScDocument& rDoc = pDocShell->GetDocument();
1718 if (pSrcDoc == mpUndoDoc.get())
1720 mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
1721 mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
1723 else
1725 mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
1726 mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
1728 rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pSrcDoc->GetCondFormList(mnTab)), mnTab);
1730 pDocShell->PostPaintGridAll();
1731 pDocShell->PostDataChanged();
1732 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1733 if (pViewShell)
1734 pViewShell->CellContentChanged();
1737 void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& )
1741 bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const
1743 return false;
1746 ScUndoUseScenario::ScUndoUseScenario( ScDocShell* pNewDocShell,
1747 const ScMarkData& rMark,
1748 /*C*/ const ScArea& rDestArea,
1749 ScDocumentUniquePtr pNewUndoDoc,
1750 OUString aNewName ) :
1751 ScSimpleUndo( pNewDocShell ),
1752 pUndoDoc( std::move(pNewUndoDoc) ),
1753 aMarkData( rMark ),
1754 aName(std::move( aNewName ))
1756 aRange.aStart.SetCol(rDestArea.nColStart);
1757 aRange.aStart.SetRow(rDestArea.nRowStart);
1758 aRange.aStart.SetTab(rDestArea.nTab);
1759 aRange.aEnd.SetCol(rDestArea.nColEnd);
1760 aRange.aEnd.SetRow(rDestArea.nRowEnd);
1761 aRange.aEnd.SetTab(rDestArea.nTab);
1764 ScUndoUseScenario::~ScUndoUseScenario()
1768 OUString ScUndoUseScenario::GetComment() const
1770 return ScResId( STR_UNDO_USESCENARIO );
1773 void ScUndoUseScenario::Undo()
1775 BeginUndo();
1777 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1778 if (pViewShell)
1780 pViewShell->DoneBlockMode();
1781 pViewShell->InitOwnBlockMode( aRange );
1784 ScDocument& rDoc = pDocShell->GetDocument();
1785 rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData );
1786 pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData);
1788 // scenario table
1789 bool bFrame = false;
1790 SCTAB nTab = aRange.aStart.Tab();
1791 SCTAB nEndTab = nTab;
1792 while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) )
1793 ++nEndTab;
1794 for (SCTAB i = nTab+1; i<=nEndTab; i++)
1796 // Flags always
1797 OUString aComment;
1798 Color aColor;
1799 ScScenarioFlags nScenFlags;
1800 pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags );
1801 rDoc.SetScenarioData( i, aComment, aColor, nScenFlags );
1802 bool bActive = pUndoDoc->IsActiveScenario( i );
1803 rDoc.SetActiveScenario( i, bActive );
1804 // For copy-back scenario also consider content
1805 if ( nScenFlags & ScScenarioFlags::TwoWay )
1807 rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL );
1808 pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc);
1810 if ( nScenFlags & ScScenarioFlags::ShowFrame )
1811 bFrame = true;
1814 // if visible borders, then paint all
1815 if (bFrame)
1816 pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras );
1817 else
1818 pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras );
1819 pDocShell->PostDataChanged();
1820 if (pViewShell)
1821 pViewShell->CellContentChanged();
1823 ShowTable( aRange.aStart.Tab() );
1825 EndUndo();
1828 void ScUndoUseScenario::Redo()
1830 SCTAB nTab = aRange.aStart.Tab();
1831 BeginRedo();
1833 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1834 if (pViewShell)
1836 pViewShell->SetTabNo( nTab );
1837 pViewShell->DoneBlockMode();
1838 pViewShell->InitOwnBlockMode( aRange );
1841 pDocShell->UseScenario( nTab, aName, false );
1843 EndRedo();
1846 void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget)
1848 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
1850 OUString aTemp = aName;
1851 pViewTarget->GetViewShell()->UseScenario(aTemp);
1855 bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const
1857 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
1859 ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
1860 return !rViewData.GetDocument().IsScenario( rViewData.GetTabNo() );
1862 return false;
1865 ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell* pNewDocShell,
1866 const ScMarkData& rMark,
1867 const ScRange& rRange,
1868 OUString aName,
1869 ScDocumentUniquePtr pNewUndoDoc ) :
1870 ScSimpleUndo( pNewDocShell ),
1871 aMarkData( rMark ),
1872 pUndoDoc( std::move(pNewUndoDoc) ),
1873 aStyleName(std::move( aName )),
1874 aRange( rRange )
1876 aMarkData.MarkToMulti();
1879 ScUndoSelectionStyle::~ScUndoSelectionStyle()
1883 OUString ScUndoSelectionStyle::GetComment() const
1885 return ScResId( STR_UNDO_APPLYCELLSTYLE );
1888 void ScUndoSelectionStyle::DoChange( const bool bUndo )
1890 ScDocument& rDoc = pDocShell->GetDocument();
1892 SetViewMarkData( aMarkData );
1894 ScRange aWorkRange( aRange );
1895 if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) ) // Merged cells?
1896 rDoc.ExtendMerge( aWorkRange, true );
1898 sal_uInt16 nExtFlags = 0;
1899 pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
1901 if (bUndo) // if Undo then push back all old data again
1903 SCTAB nTabCount = rDoc.GetTableCount();
1904 ScRange aCopyRange = aWorkRange;
1905 aCopyRange.aStart.SetTab(0);
1906 aCopyRange.aEnd.SetTab(nTabCount-1);
1907 pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
1909 else // if Redo, then reapply style
1911 ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
1912 ScStyleSheet* pStyleSheet =
1913 static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
1914 if (!pStyleSheet)
1916 OSL_FAIL("StyleSheet not found");
1917 return;
1919 rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData );
1922 pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
1924 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
1925 if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
1926 /*A*/ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
1928 ShowTable( aWorkRange.aStart.Tab() );
1931 void ScUndoSelectionStyle::Undo()
1933 BeginUndo();
1934 DoChange( true );
1935 EndUndo();
1938 void ScUndoSelectionStyle::Redo()
1940 BeginRedo();
1941 DoChange( false );
1942 EndRedo();
1945 void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget)
1947 if (dynamic_cast<const ScTabViewTarget*>( &rTarget) == nullptr)
1948 return;
1950 ScDocument& rDoc = pDocShell->GetDocument();
1951 ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
1952 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool->
1953 Find( aStyleName, SfxStyleFamily::Para ));
1954 if (!pStyleSheet)
1956 OSL_FAIL("StyleSheet not found");
1957 return;
1960 ScTabViewShell& rViewShell = *static_cast<ScTabViewTarget&>(rTarget).GetViewShell();
1961 rViewShell.SetStyleSheetToMarked( pStyleSheet );
1964 bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const
1966 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
1969 ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell* pNewDocShell, const ScRange& rArea,
1970 ScDocumentUniquePtr pNewUndoDoc, OUString aForm ) :
1971 ScBlockUndo( pNewDocShell, rArea, SC_UNDO_SIMPLE ),
1972 pUndoDoc( std::move(pNewUndoDoc) ),
1973 aFormula(std::move( aForm ))
1975 SetChangeTrack();
1978 ScUndoEnterMatrix::~ScUndoEnterMatrix()
1982 OUString ScUndoEnterMatrix::GetComment() const
1984 return ScResId( STR_UNDO_ENTERMATRIX );
1987 void ScUndoEnterMatrix::SetChangeTrack()
1989 ScDocument& rDoc = pDocShell->GetDocument();
1990 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
1991 if ( pChangeTrack )
1992 pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
1993 nStartChangeAction, nEndChangeAction );
1994 else
1995 nStartChangeAction = nEndChangeAction = 0;
1998 void ScUndoEnterMatrix::Undo()
2000 BeginUndo();
2002 ScDocument& rDoc = pDocShell->GetDocument();
2004 rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
2005 pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
2006 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
2007 pDocShell->PostDataChanged();
2008 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2009 if (pViewShell)
2010 pViewShell->CellContentChanged();
2012 ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
2013 if ( pChangeTrack )
2014 pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
2016 EndUndo();
2019 void ScUndoEnterMatrix::Redo()
2021 BeginRedo();
2023 ScDocument& rDoc = pDocShell->GetDocument();
2025 ScMarkData aDestMark(rDoc.GetSheetLimits());
2026 aDestMark.SelectOneTable( aBlockRange.aStart.Tab() );
2027 aDestMark.SetMarkArea( aBlockRange );
2029 rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
2030 aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
2031 aDestMark, aFormula );
2033 SetChangeTrack();
2035 EndRedo();
2038 void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget)
2040 if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
2042 OUString aTemp = aFormula;
2043 ScDocument& rDoc = pDocShell->GetDocument();
2044 pTabViewTarget->GetViewShell()->EnterMatrix(aTemp, rDoc.GetGrammar());
2048 bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const
2050 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2053 static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark )
2055 OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" );
2056 return rMark.GetMultiMarkArea();
2059 ScUndoIndent::ScUndoIndent( ScDocShell* pNewDocShell, const ScMarkData& rMark,
2060 ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) :
2061 ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2062 aMarkData( rMark ),
2063 pUndoDoc( std::move(pNewUndoDoc) ),
2064 bIsIncrement( bIncrement )
2068 ScUndoIndent::~ScUndoIndent()
2072 OUString ScUndoIndent::GetComment() const
2074 TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT;
2075 return ScResId(pId);
2078 void ScUndoIndent::Undo()
2080 BeginUndo();
2082 ScDocument& rDoc = pDocShell->GetDocument();
2083 SCTAB nTabCount = rDoc.GetTableCount();
2084 ScRange aCopyRange = aBlockRange;
2085 aCopyRange.aStart.SetTab(0);
2086 aCopyRange.aEnd.SetTab(nTabCount-1);
2087 pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2088 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2090 EndUndo();
2093 void ScUndoIndent::Redo()
2095 BeginRedo();
2097 ScDocument& rDoc = pDocShell->GetDocument();
2098 rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData );
2099 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2101 EndRedo();
2104 void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget)
2106 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2107 pViewTarget->GetViewShell()->ChangeIndent( bIsIncrement );
2110 bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const
2112 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2115 ScUndoTransliterate::ScUndoTransliterate( ScDocShell* pNewDocShell, const ScMarkData& rMark,
2116 ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) :
2117 ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2118 aMarkData( rMark ),
2119 pUndoDoc( std::move(pNewUndoDoc) ),
2120 nTransliterationType( nType )
2124 ScUndoTransliterate::~ScUndoTransliterate()
2128 OUString ScUndoTransliterate::GetComment() const
2130 return ScResId( STR_UNDO_TRANSLITERATE );
2133 void ScUndoTransliterate::Undo()
2135 BeginUndo();
2137 ScDocument& rDoc = pDocShell->GetDocument();
2138 SCTAB nTabCount = rDoc.GetTableCount();
2139 ScRange aCopyRange = aBlockRange;
2140 aCopyRange.aStart.SetTab(0);
2141 aCopyRange.aEnd.SetTab(nTabCount-1);
2142 pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData);
2143 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2145 EndUndo();
2148 void ScUndoTransliterate::Redo()
2150 BeginRedo();
2152 ScDocument& rDoc = pDocShell->GetDocument();
2153 rDoc.TransliterateText( aMarkData, nTransliterationType );
2154 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2156 EndRedo();
2159 void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget)
2161 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2162 pViewTarget->GetViewShell()->TransliterateText( nTransliterationType );
2165 bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const
2167 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2170 ScUndoClearItems::ScUndoClearItems( ScDocShell* pNewDocShell, const ScMarkData& rMark,
2171 ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) :
2172 ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
2173 aMarkData( rMark ),
2174 pUndoDoc( std::move(pNewUndoDoc) )
2176 assert(pW && "ScUndoClearItems: Which-Pointer is Null");
2178 sal_uInt16 nCount = 0;
2179 while ( pW[nCount] )
2180 ++nCount;
2181 pWhich.reset( new sal_uInt16[nCount+1] );
2182 for (sal_uInt16 i=0; i<=nCount; i++)
2183 pWhich[i] = pW[i];
2186 ScUndoClearItems::~ScUndoClearItems()
2190 OUString ScUndoClearItems::GetComment() const
2192 return ScResId( STR_UNDO_DELETECONTENTS );
2195 void ScUndoClearItems::Undo()
2197 BeginUndo();
2199 ScDocument& rDoc = pDocShell->GetDocument();
2200 pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2201 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2203 EndUndo();
2206 void ScUndoClearItems::Redo()
2208 BeginRedo();
2210 ScDocument& rDoc = pDocShell->GetDocument();
2211 rDoc.ClearSelectionItems( pWhich.get(), aMarkData );
2212 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2214 EndRedo();
2217 void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget)
2219 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2221 ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
2222 rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false );
2226 bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const
2228 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2231 // remove all line breaks of a table
2232 ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell* pNewDocShell,
2233 SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) :
2234 ScSimpleUndo( pNewDocShell ),
2235 nTab( nNewTab ),
2236 pUndoDoc( std::move(pNewUndoDoc) )
2240 ScUndoRemoveBreaks::~ScUndoRemoveBreaks()
2244 OUString ScUndoRemoveBreaks::GetComment() const
2246 return ScResId( STR_UNDO_REMOVEBREAKS );
2249 void ScUndoRemoveBreaks::Undo()
2251 BeginUndo();
2253 ScDocument& rDoc = pDocShell->GetDocument();
2254 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2256 pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc);
2257 if (pViewShell)
2258 pViewShell->UpdatePageBreakData( true );
2259 pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
2261 EndUndo();
2264 void ScUndoRemoveBreaks::Redo()
2266 BeginRedo();
2268 ScDocument& rDoc = pDocShell->GetDocument();
2269 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2271 rDoc.RemoveManualBreaks(nTab);
2272 rDoc.UpdatePageBreaks(nTab);
2273 if (pViewShell)
2274 pViewShell->UpdatePageBreakData( true );
2275 pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
2277 EndRedo();
2280 void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget)
2282 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2284 ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
2285 rViewShell.RemoveManualBreaks();
2289 bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
2291 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2294 ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
2295 const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) :
2296 ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
2297 pUndoDoc( std::move(pNewUndoDoc) )
2299 maOptions.push_back( rOption);
2302 ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
2303 const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) :
2304 ScBlockUndo( pNewDocShell, rRange, SC_UNDO_SIMPLE ),
2305 pUndoDoc( std::move(pNewUndoDoc) )
2309 ScUndoRemoveMerge::~ScUndoRemoveMerge()
2313 OUString ScUndoRemoveMerge::GetComment() const
2315 return ScResId( STR_UNDO_REMERGE ); // "remove merge"
2318 ScDocument* ScUndoRemoveMerge::GetUndoDoc()
2320 return pUndoDoc.get();
2323 void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption )
2325 maOptions.push_back( rOption);
2328 void ScUndoRemoveMerge::Undo()
2330 using ::std::set;
2332 SetCurTab();
2333 BeginUndo();
2335 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2337 ScDocument& rDoc = pDocShell->GetDocument();
2338 for (const auto & rOption : maOptions)
2340 for (const auto& rTab : rOption.maTabs)
2342 OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!");
2343 if (!pUndoDoc)
2344 continue;
2345 // There is no need to extend merge area because it's already been extended.
2346 ScRange aRange = rOption.getSingleRange(rTab);
2347 rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB);
2348 pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc);
2350 bool bDidPaint = false;
2351 if ( pViewShell )
2353 pViewShell->SetTabNo(rTab);
2354 bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
2356 if (!bDidPaint)
2357 ScUndoUtil::PaintMore(pDocShell, aRange);
2361 EndUndo();
2364 void ScUndoRemoveMerge::Redo()
2366 using ::std::set;
2368 SetCurTab();
2369 BeginRedo();
2371 ScDocument& rDoc = pDocShell->GetDocument();
2372 ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
2374 for (const auto & rOption : maOptions)
2376 for (const SCTAB nTab : rOption.maTabs)
2378 // There is no need to extend merge area because it's already been extended.
2379 ScRange aRange = rOption.getSingleRange(nTab);
2381 const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetUserOrPoolDefaultItem( ATTR_MERGE );
2382 ScPatternAttr aPattern(rDoc.getCellAttributeHelper());
2383 aPattern.GetItemSet().Put( rDefAttr );
2384 rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow,
2385 rOption.mnEndCol, rOption.mnEndRow, nTab,
2386 aPattern );
2388 rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow,
2389 rOption.mnEndCol, rOption.mnEndRow, nTab,
2390 ScMF::Hor | ScMF::Ver );
2392 rDoc.ExtendMerge(aRange, true);
2394 // Paint
2396 bool bDidPaint = false;
2397 if ( pViewShell )
2399 pViewShell->SetTabNo(nTab);
2400 bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
2402 if (!bDidPaint)
2403 ScUndoUtil::PaintMore(pDocShell, aRange);
2407 EndRedo();
2410 void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget)
2412 if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
2413 pViewTarget->GetViewShell()->RemoveMerge();
2416 bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
2418 return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
2421 void ScUndoRemoveMerge::SetCurTab()
2423 SCTAB nCurTab = ScDocShell::GetCurTab();
2424 aBlockRange.aStart.SetTab(nCurTab);
2425 aBlockRange.aEnd.SetTab(nCurTab);
2428 /** set only border, for ScRangeList (StarOne) */
2429 static ScRange lcl_TotalRange( const ScRangeList& rRanges )
2431 ScRange aTotal;
2432 if ( !rRanges.empty() )
2434 aTotal = rRanges[ 0 ];
2435 for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i )
2437 ScRange const & rRange = rRanges[ i ];
2438 if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col());
2439 if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row());
2440 if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab());
2441 if (rRange.aEnd.Col() > aTotal.aEnd.Col() ) aTotal.aEnd.SetCol( rRange.aEnd.Col() );
2442 if (rRange.aEnd.Row() > aTotal.aEnd.Row() ) aTotal.aEnd.SetRow( rRange.aEnd.Row() );
2443 if (rRange.aEnd.Tab() > aTotal.aEnd.Tab() ) aTotal.aEnd.SetTab(rRange.aEnd.Tab() );
2446 return aTotal;
2449 ScUndoBorder::ScUndoBorder(ScDocShell* pNewDocShell,
2450 const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc,
2451 const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner)
2452 : ScBlockUndo(pNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE)
2453 , xUndoDoc(std::move(pNewUndoDoc))
2455 xRanges.reset(new ScRangeList(rRangeList));
2456 xOuter.reset(new SvxBoxItem(rNewOuter));
2457 xInner.reset(new SvxBoxInfoItem(rNewInner));
2460 OUString ScUndoBorder::GetComment() const
2462 return ScResId( STR_UNDO_SELATTRLINES ); //! own string?
2465 void ScUndoBorder::Undo()
2467 BeginUndo();
2469 ScDocument& rDoc = pDocShell->GetDocument();
2470 ScMarkData aMarkData(rDoc.GetSheetLimits());
2471 aMarkData.MarkFromRangeList(*xRanges, false);
2472 xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
2473 pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2475 EndUndo();
2478 void ScUndoBorder::Redo()
2480 BeginRedo();
2482 ScDocument& rDoc = pDocShell->GetDocument(); // call function at docfunc
2483 size_t nCount = xRanges->size();
2484 for (size_t i = 0; i < nCount; ++i )
2486 ScRange const & rRange = (*xRanges)[i];
2487 SCTAB nTab = rRange.aStart.Tab();
2489 ScMarkData aMark(rDoc.GetSheetLimits());
2490 aMark.SetMarkArea( rRange );
2491 aMark.SelectTable( nTab, true );
2493 rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get());
2495 for (size_t i = 0; i < nCount; ++i)
2496 pDocShell->PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
2498 EndRedo();
2501 void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */)
2503 //TODO later (when the function has moved from cellsuno to docfunc)
2506 bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const
2508 return false; // See above
2511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */