summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/undo/undoblk.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/undo/undoblk.cxx')
-rw-r--r--sc/source/ui/undo/undoblk.cxx2437
1 files changed, 2437 insertions, 0 deletions
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
new file mode 100644
index 000000000..e3b10f78b
--- /dev/null
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -0,0 +1,2437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <vcl/virdev.hxx>
+#include <editeng/boxitem.hxx>
+#include <sfx2/app.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <undoblk.hxx>
+#include <undoutil.hxx>
+#include <document.hxx>
+#include <patattr.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <rangenam.hxx>
+#include <rangeutl.hxx>
+#include <stlpool.hxx>
+#include <stlsheet.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <target.hxx>
+#include <docpool.hxx>
+#include <docfunc.hxx>
+#include <attrib.hxx>
+#include <chgtrack.hxx>
+#include <transobj.hxx>
+#include <refundo.hxx>
+#include <undoolk.hxx>
+#include <clipparam.hxx>
+#include <rowheightcontext.hxx>
+#include <refupdatecontext.hxx>
+#include <validat.hxx>
+#include <gridwin.hxx>
+#include <columnspanset.hxx>
+
+#include <memory>
+#include <set>
+
+// TODO:
+/*A*/ // SetOptimalHeight on Document, if no View
+/*B*/ // linked sheets
+/*C*/ // ScArea
+//? // check later
+
+ScUndoInsertCells::ScUndoInsertCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
+ bool bNewPartOfPaste ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ aEffRange( rRange ),
+ nCount( nNewCount ),
+ pTabs( std::move(pNewTabs) ),
+ pScenarios( std::move(pNewScenarios) ),
+ eCmd( eNewCmd ),
+ bPartOfPaste( bNewPartOfPaste )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER) // whole row?
+ {
+ aEffRange.aStart.SetCol(0);
+ aEffRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER) // whole column?
+ {
+ aEffRange.aStart.SetRow(0);
+ aEffRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ SetChangeTrack();
+}
+
+ScUndoInsertCells::~ScUndoInsertCells()
+{
+}
+
+OUString ScUndoInsertCells::GetComment() const
+{
+ return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS );
+}
+
+bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction )
+{
+ // If a paste undo action has already been added, append (detective) action there.
+ if ( pPasteUndo )
+ return pPasteUndo->Merge( pNextAction );
+
+ if ( bPartOfPaste )
+ if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) )
+ {
+ SfxUndoAction* pWrappedAction = pWrapper->GetWrappedUndo();
+ if ( dynamic_cast<const ScUndoPaste*>( pWrappedAction) )
+ {
+ // Store paste action if this is part of paste with inserting cells.
+ // A list action isn't used because Repeat wouldn't work (insert wrong cells).
+
+ pPasteUndo.reset( pWrappedAction );
+ pWrapper->ForgetWrappedUndo(); // pWrapper is deleted by UndoManager
+ return true;
+ }
+ }
+
+ // Call base class for detective handling
+ return ScMoveUndo::Merge( pNextAction );
+}
+
+void ScUndoInsertCells::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ pChangeTrack->AppendInsert( aEffRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoInsertCells::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB i;
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ // refresh of merged cells has to be after inserting/deleting
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ switch (eCmd)
+ {
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ case INS_CELLSDOWN:
+ for( i=0; i<nCount; i++ )
+ {
+
+ if (bUndo)
+ rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ else
+ rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? -1 : 1;
+ pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ }
+ }
+ break;
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ case INS_CELLSRIGHT:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ else
+ rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? -1 : 1;
+ pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ ScRange aWorkRange( aEffRange );
+ if ( eCmd == INS_CELLSRIGHT ) // only "shift right" requires refresh of the moved area
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ for( i=0; i<nCount; i++ )
+ {
+ if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) )
+ {
+ SCCOL nEndCol = aWorkRange.aEnd.Col();
+ SCROW nEndRow = aWorkRange.aEnd.Row();
+ rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
+ }
+ }
+
+ // Undo for displaced attributes?
+
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+
+ switch (eCmd)
+ {
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ nPaint |= PaintPartFlags::Left;
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ break;
+ case INS_CELLSDOWN:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ nPaint |= PaintPartFlags::Top; // top bar
+ [[fallthrough]];
+ case INS_CELLSRIGHT:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) )
+ { // AdjustDraw does not paint PaintPartFlags::Top,
+ aWorkRange.aStart.SetCol(0); // thus solved like this
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ for( i=0; i<nCount; i++ )
+ {
+ pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint );
+ }
+ pDocShell->PostDataChanged();
+ if (!pViewShell)
+ return;
+
+ pViewShell->CellContentChanged();
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT);
+ bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN);
+
+ if (bColsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
+
+ if (bRowsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+}
+
+void ScUndoInsertCells::Undo()
+{
+ if ( pPasteUndo )
+ pPasteUndo->Undo(); // undo paste first
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoInsertCells::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+
+ if ( pPasteUndo )
+ pPasteUndo->Redo(); // redo paste last
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr)
+ {
+ if ( pPasteUndo )
+ {
+ // Repeat for paste with inserting cells is handled completely
+ // by the Paste undo action
+
+ pPasteUndo->Repeat( rTarget );
+ }
+ else
+ static_cast<ScTabViewTarget&>(rTarget).GetViewShell()->InsertCells( eCmd );
+ }
+}
+
+bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ aEffRange( rRange ),
+ nCount( nNewCount ),
+ pTabs( std::move(pNewTabs) ),
+ pScenarios( std::move(pNewScenarios) ),
+ eCmd( eNewCmd )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (eCmd == DelCellCmd::Rows) // whole row?
+ {
+ aEffRange.aStart.SetCol(0);
+ aEffRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ if (eCmd == DelCellCmd::Cols) // whole column?
+ {
+ aEffRange.aStart.SetRow(0);
+ aEffRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ SetChangeTrack();
+}
+
+ScUndoDeleteCells::~ScUndoDeleteCells()
+{
+}
+
+OUString ScUndoDeleteCells::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECELLS ); // "Delete"
+}
+
+void ScUndoDeleteCells::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteCells::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB i;
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ switch (eCmd)
+ {
+ case DelCellCmd::Rows:
+ case DelCellCmd::CellsUp:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ else
+ rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? 1 : -1;
+ pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ }
+ }
+ break;
+ case DelCellCmd::Cols:
+ case DelCellCmd::CellsLeft:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ else
+ rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? 1 : -1;
+ pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // if Undo, restore references
+ for( i=0; i<nCount && bUndo; i++ )
+ {
+ pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc);
+ }
+
+ ScRange aWorkRange( aEffRange );
+ if ( eCmd == DelCellCmd::CellsLeft ) // only "shift left" requires refresh of the moved area
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+
+ for( i=0; i<nCount; i++ )
+ {
+ if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ // #i51445# old merge flag attributes must be deleted also for single cells,
+ // not only for whole columns/rows
+
+ if ( !bUndo )
+ {
+ if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.SelectOneTable( aWorkRange.aStart.Tab() );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(),
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(),
+ aMarkData, aPattern );
+ }
+
+ SCCOL nEndCol = aWorkRange.aEnd.Col();
+ SCROW nEndRow = aWorkRange.aEnd.Row();
+ rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
+ }
+ }
+
+ // paint
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ switch (eCmd)
+ {
+ case DelCellCmd::Rows:
+ nPaint |= PaintPartFlags::Left;
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ break;
+ case DelCellCmd::CellsUp:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ case DelCellCmd::Cols:
+ nPaint |= PaintPartFlags::Top; // top bar
+ [[fallthrough]];
+ case DelCellCmd::CellsLeft:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) )
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ for( i=0; i<nCount; i++ )
+ {
+ pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES );
+ }
+ // Selection not until EndUndo
+
+ pDocShell->PostDataChanged();
+ // CellContentChanged comes with the selection
+
+ if (!pViewShell)
+ return;
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft);
+ bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp);
+
+ if (bColsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
+
+ if (bRowsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+}
+
+void ScUndoDeleteCells::Undo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // Now that DBData have been restored in ScMoveUndo::EndUndo() via its
+ // pRefUndoDoc we can apply the AutoFilter buttons.
+ // Add one row for cases undoing deletion right above a cut AutoFilter
+ // range so the buttons are removed.
+ SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow());
+ for (SCTAB i=0; i < nCount; ++i)
+ {
+ rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
+ aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ // Selection not until EndUndo
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ for( SCTAB i=0; i<nCount; i++ )
+ {
+ pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) );
+ }
+ }
+
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoDeleteCells::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginRedo();
+ DoChange( false);
+ EndRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ for (SCTAB i=0; i < nCount; ++i)
+ {
+ rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
+ aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->DoneBlockMode(); // current way
+
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
+ pViewTarget->GetViewShell()->DeleteCells( eCmd );
+}
+
+bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// delete cells in multiselection
+ScUndoDeleteMulti::ScUndoDeleteMulti(
+ ScDocShell* pNewDocShell,
+ bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
+ std::vector<sc::ColRowSpan>&& rSpans,
+ ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ mbRows(bNewRows),
+ mbRefresh(bNeedsRefresh),
+ nTab( nNewTab ),
+ maSpans(std::move(rSpans))
+{
+ SetChangeTrack();
+}
+
+ScUndoDeleteMulti::~ScUndoDeleteMulti()
+{
+}
+
+OUString ScUndoDeleteMulti::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECELLS ); // like DeleteCells
+}
+
+void ScUndoDeleteMulti::DoChange() const
+{
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ PaintPartFlags nPaint;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (mbRows)
+ {
+ nStartCol = 0;
+ nStartRow = static_cast<SCROW>(maSpans[0].mnStart);
+ nPaint = PaintPartFlags::Grid | PaintPartFlags::Left;
+ }
+ else
+ {
+ nStartCol = static_cast<SCCOL>(maSpans[0].mnStart);
+ nStartRow = 0;
+ nPaint = PaintPartFlags::Grid | PaintPartFlags::Top;
+ }
+
+ if (mbRefresh)
+ {
+ SCCOL nEndCol = rDoc.MaxCol();
+ SCROW nEndRow = rDoc.MaxRow();
+ rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
+ rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
+ }
+
+ pDocShell->PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( nTab );
+}
+
+void ScUndoDeleteMulti::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScRange aRange( 0, 0, nTab, 0, 0, nTab );
+ if (mbRows)
+ aRange.aEnd.SetCol( rDoc.MaxCol() );
+ else
+ aRange.aEnd.SetRow( rDoc.MaxRow() );
+ // delete in reverse
+ std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
+ for (; ri != riEnd; ++ri)
+ {
+ SCCOLROW nEnd = ri->mnEnd;
+ SCCOLROW nStart = ri->mnStart;
+ if (mbRows)
+ {
+ aRange.aStart.SetRow( nStart );
+ aRange.aEnd.SetRow( nEnd );
+ }
+ else
+ {
+ aRange.aStart.SetCol( static_cast<SCCOL>(nStart) );
+ aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) );
+ }
+ sal_uLong nDummyStart;
+ pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
+ nDummyStart, nEndChangeAction );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteMulti::Undo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // reverse delete -> forward insert
+ for (const auto& rSpan : maSpans)
+ {
+ SCCOLROW nStart = rSpan.mnStart;
+ SCCOLROW nEnd = rSpan.mnEnd;
+ if (mbRows)
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
+ else
+ rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
+ }
+
+ for (const auto& rSpan : maSpans)
+ {
+ SCCOLROW nStart = rSpan.mnStart;
+ SCCOLROW nEnd = rSpan.mnEnd;
+ if (mbRows)
+ pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc);
+ else
+ pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ DoChange();
+
+ //! redrawing the selection is not possible at the moment
+ //! since no data for selection exist
+
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDeleteMulti::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // reverse delete
+ std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
+ for (; ri != riEnd; ++ri)
+ {
+ SCCOLROW nEnd = ri->mnEnd;
+ SCCOLROW nStart = ri->mnStart;
+ if (mbRows)
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
+ else
+ rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
+ }
+
+ SetChangeTrack();
+
+ DoChange();
+
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget)
+{
+ // if single selection
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pTabViewTarget->GetViewShell()->DeleteCells( DelCellCmd::Rows );
+}
+
+bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoCut::ScUndoCut(ScDocShell* pNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd,
+ const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc)
+ : ScBlockUndo(pNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT)
+ , aMarkData(rMark)
+ , pUndoDoc(std::move(pNewUndoDoc))
+ , aExtendedRange(aRange)
+{
+ SetChangeTrack();
+}
+
+ScUndoCut::~ScUndoCut()
+{
+}
+
+OUString ScUndoCut::GetComment() const
+{
+ return ScResId( STR_UNDO_CUT ); // "cut"
+}
+
+void ScUndoCut::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction, SC_CACM_CUT );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoCut::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_uInt16 nExtFlags = 0;
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ if (bUndo) // only for Undo
+ {
+ // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aExtendedRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc);
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ BroadcastChanges(aCopyRange);
+ }
+ else // only for Redo
+ {
+ pDocShell->UpdatePaintExt( nExtFlags, aExtendedRange );
+ rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags );
+ SetChangeTrack();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoCut::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoCut::Redo()
+{
+ BeginRedo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+ DoChange( false );
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+ EndRedo();
+}
+
+void ScUndoCut::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->CutToClip();
+}
+
+bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoPaste::ScUndoPaste( ScDocShell* pNewDocShell, const ScRangeList& rRanges,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ InsertDeleteFlags nNewFlags,
+ std::unique_ptr<ScRefUndoData> pRefData,
+ bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) :
+ ScMultiBlockUndo( pNewDocShell, rRanges ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ pRedoDoc( std::move(pNewRedoDoc) ),
+ nFlags( nNewFlags ),
+ pRefUndoData( std::move(pRefData) ),
+ bRedoFilled( bRedoIsFilled )
+{
+ if ( pRefUndoData )
+ pRefUndoData->DeleteUnchanged( &pDocShell->GetDocument() );
+
+ if ( pOptions )
+ aPasteOptions = *pOptions; // used only for Repeat
+
+ SetChangeTrack();
+}
+
+ScUndoPaste::~ScUndoPaste()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+ pRefUndoData.reset();
+ pRefRedoData.reset();
+}
+
+OUString ScUndoPaste::GetComment() const
+{
+ return ScResId( STR_UNDO_PASTE ); // "paste"
+}
+
+void ScUndoPaste::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ pChangeTrack->AppendContentRange(maBlockRanges[i], pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction, SC_CACM_PASTE );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoPaste::DoChange(bool bUndo)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // RefUndoData for redo is created before first undo
+ // (with DeleteUnchanged after the DoUndo call)
+ bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData );
+ if ( bCreateRedoData )
+ pRefRedoData.reset( new ScRefUndoData( &rDoc ) );
+
+ ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get();
+
+ // Always back-up either all or none of the content for Undo
+ InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE;
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ nUndoFlags |= InsertDeleteFlags::CONTENTS;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nUndoFlags |= InsertDeleteFlags::ATTRIB;
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ nUndoFlags &= ~InsertDeleteFlags::OBJECTS;
+ nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
+
+ bool bPaintAll = false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( bUndo && !bRedoFilled )
+ {
+ if (!pRedoDoc)
+ {
+ bool bColInfo = true;
+ bool bRowInfo = true;
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ const ScRange& r = maBlockRanges[i];
+ bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow());
+ bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol());
+ if (!bColInfo && !bRowInfo)
+ break;
+ }
+
+ pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo );
+ }
+ // read "redo" data from the document in the first undo
+ // all sheets - CopyToDocument skips those that don't exist in pRedoDoc
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aCopyRange = maBlockRanges[i];
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc);
+ bRedoFilled = true;
+ }
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt(nExtFlags, maBlockRanges.Combine());
+
+ rDoc.ForgetNoteCaptions(maBlockRanges, false);
+ aMarkData.MarkToMulti();
+ rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged);
+
+ aMarkData.MarkToSimple();
+
+ SCTAB nFirstSelected = aMarkData.GetFirstSelected();
+
+ if ( !bUndo && pRedoDoc ) // Redo: UndoToDocument before handling RefData
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aRange = maBlockRanges[i];
+ aRange.aStart.SetTab(nFirstSelected);
+ aRange.aEnd.SetTab(nFirstSelected);
+ pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab == nFirstSelected)
+ continue;
+
+ aRange.aStart.SetTab(rTab);
+ aRange.aEnd.SetTab(rTab);
+ pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
+ }
+ }
+ }
+
+ if (pWorkRefData)
+ {
+ pWorkRefData->DoUndo( &rDoc, true ); // true = bSetChartRangeLists for SetChartListenerCollection
+ if (!maBlockRanges.empty() &&
+ rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab()))
+ bPaintAll = true;
+ }
+
+ if ( bCreateRedoData && pRefRedoData )
+ pRefRedoData->DeleteUnchanged( &rDoc );
+
+ if (bUndo) // Undo: UndoToDocument after handling RefData
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aRange = maBlockRanges[i];
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ aRange.aStart.SetTab(rTab);
+ aRange.aEnd.SetTab(rTab);
+ pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
+ }
+ }
+ }
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ ScRangeList aDrawRanges(maBlockRanges);
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+
+ // For sheet geometry invalidation.
+ bool bColsAffected = false;
+ bool bRowsAffected = false;
+
+ for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i)
+ {
+ ScRange& rDrawRange = aDrawRanges[i];
+ rDoc.ExtendMerge(rDrawRange, true); // only needed for single sheet (text/rtf etc.)
+ ScRangeList aRangeList(rDrawRange);
+ ScMarkData aData(rDoc.GetSheetLimits(), aRangeList);
+ if (bPaintAll)
+ {
+ rDrawRange.aStart.SetCol(0);
+ rDrawRange.aStart.SetRow(0);
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
+ if (pViewShell)
+ pViewShell->AdjustBlockHeight(false, &aData);
+ }
+ else
+ {
+ if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column
+ {
+ nPaint |= PaintPartFlags::Top;
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ bColsAffected = true;
+ }
+ if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row
+ {
+ nPaint |= PaintPartFlags::Left;
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ bRowsAffected = true;
+ }
+ if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData))
+ {
+ rDrawRange.aStart.SetCol(0);
+ rDrawRange.aStart.SetRow(0);
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ pDocShell->UpdatePaintExt(nExtFlags, rDrawRange);
+ }
+ }
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction(mpDrawUndo.get());
+
+ pDocShell->PostPaint(aDrawRanges, nPaint, nExtFlags);
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ if (bColsAffected || bRowsAffected)
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, aDrawRanges[0].aStart.Tab());
+}
+
+void ScUndoPaste::Undo()
+{
+ BeginUndo();
+ DoChange(true);
+ if (!maBlockRanges.empty())
+ ShowTable(maBlockRanges.front());
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoPaste::Redo()
+{
+ BeginRedo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+ DoChange( false );
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
+{
+ auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget);
+ if (!pViewTarget)
+ return;
+
+ ScTabViewShell* pViewSh = pViewTarget->GetViewShell();
+ // keep a reference in case the clipboard is changed during PasteFromClip
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pViewSh->GetViewData().GetActiveWin()));
+ if (pOwnClip)
+ {
+ pViewSh->PasteFromClip( nFlags, pOwnClip->GetDocument(),
+ aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
+ aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
+ true ); // allow warning dialog
+ }
+}
+
+bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDragDrop::ScUndoDragDrop( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
+ ScDocumentUniquePtr pUndoDocument, bool bScenario ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), nullptr ),
+ mnPaintExtFlags( 0 ),
+ aSrcRange( rRange ),
+ bCut( bNewCut ),
+ bKeepScenarioFlags( bScenario )
+{
+ ScAddress aDestEnd(aNewDestPos);
+ aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row());
+ aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col());
+ aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab());
+
+ bool bIncludeFiltered = bCut;
+ if ( !bIncludeFiltered )
+ {
+ // find number of non-filtered rows
+ SCROW nPastedCount = pDocShell->GetDocument().CountNonFilteredRows(
+ aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab());
+
+ if ( nPastedCount == 0 )
+ nPastedCount = 1;
+ aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 );
+ }
+
+ aDestRange.aStart = aNewDestPos;
+ aDestRange.aEnd = aDestEnd;
+
+ SetChangeTrack();
+}
+
+ScUndoDragDrop::~ScUndoDragDrop()
+{
+}
+
+OUString ScUndoDragDrop::GetComment() const
+{ // "Move" : "Copy"
+ return bCut ?
+ ScResId( STR_UNDO_MOVE ) :
+ ScResId( STR_UNDO_COPY );
+}
+
+void ScUndoDragDrop::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( bCut )
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ pChangeTrack->AppendContentRange( aDestRange, pRefUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
+{
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (pViewShell)
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ ScViewData& rViewData = pViewShell->GetViewData();
+ sc::RowHeightContext aCxt(
+ rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(),
+ pVirtDev);
+
+ if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true))
+ {
+ // tdf#76183: recalculate objects' positions
+ rDoc.SetDrawPageSize(aRange.aStart.Tab());
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+
+ if ( bKeepScenarioFlags )
+ {
+ // Copy scenario -> also paint scenario boarder
+ aRange.aStart.SetCol(0);
+ aRange.aStart.SetRow(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ // column/row info (width/height) included if whole columns/rows were copied
+ if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() )
+ {
+ nPaint |= PaintPartFlags::Left;
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+ if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ nPaint |= PaintPartFlags::Top;
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ pDocShell->PostPaint( aRange, nPaint, nExtFlags );
+}
+
+void ScUndoDragDrop::DoUndo( ScRange aRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ // Database range before data, so that the Autofilter button match up in ExtendMerge
+
+ ScRange aPaintRange = aRange;
+ rDoc.ExtendMerge( aPaintRange ); // before deleting
+
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
+
+ // do not undo objects and note captions, they are handled via drawing undo
+ InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ // Additionally discard/forget caption ownership during deletion, as
+ // Drag&Drop is a special case in that the Undo holds captions of the
+ // transferred target range, which would get deleted and
+ // SdrGroupUndo::Undo() would attempt to access invalidated captions and
+ // crash, tdf#92995
+ InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS;
+
+ rDoc.DeleteAreaTab( aRange, nDelFlags );
+ pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
+ if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
+ rDoc.ExtendMerge( aRange, true );
+
+ aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
+ aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
+
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
+ maPaintRanges.Join(aPaintRange);
+}
+
+void ScUndoDragDrop::Undo()
+{
+ mnPaintExtFlags = 0;
+ maPaintRanges.RemoveAll();
+
+ BeginUndo();
+
+ if (bCut)
+ {
+ // During undo, we move cells from aDestRange to aSrcRange.
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
+ SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
+ SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
+
+ sc::RefUpdateContext aCxt(rDoc);
+ aCxt.meMode = URM_MOVE;
+ aCxt.maRange = aSrcRange;
+ aCxt.mnColDelta = nColDelta;
+ aCxt.mnRowDelta = nRowDelta;
+ aCxt.mnTabDelta = nTabDelta;
+
+ // Global range names.
+ ScRangeName* pName = rDoc.GetRangeName();
+ if (pName)
+ pName->UpdateReference(aCxt);
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ // Sheet-local range names.
+ pName = rDoc.GetRangeName(nTab);
+ if (pName)
+ pName->UpdateReference(aCxt, nTab);
+ }
+
+ ScValidationDataList* pValidList = rDoc.GetValidationList();
+ if (pValidList)
+ {
+ // Update the references of validation entries.
+ pValidList->UpdateReference(aCxt);
+ }
+
+ DoUndo(aDestRange);
+ DoUndo(aSrcRange);
+
+ rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false);
+ }
+ else
+ DoUndo(aDestRange);
+
+ for (size_t i = 0; i < maPaintRanges.size(); ++i)
+ {
+ const ScRange& r = maPaintRanges[i];
+ PaintArea(r, mnPaintExtFlags);
+ }
+
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDragDrop::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ /* TODO: Redoing note captions is quite tricky due to the fact that a
+ helper clip document is used. While (re-)pasting the contents to the
+ destination area, the original pointers to the captions created while
+ dropping have to be restored. A simple CopyFromClip() would create new
+ caption objects that are not tracked by drawing undo, and the captions
+ restored by drawing redo would live without cell note objects pointing
+ to them. So, first, CopyToClip() and CopyFromClip() are called without
+ cloning the caption objects. This leads to cell notes pointing to the
+ wrong captions from source area that will be removed by drawing redo
+ later. Second, the pointers to the new captions have to be restored.
+ Sadly, currently these pointers are not stored anywhere but in the list
+ of drawing undo actions. */
+
+ SCTAB nTab;
+ ScMarkData aSourceMark(rDoc.GetSheetLimits());
+ for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
+ aSourceMark.SelectTable( nTab, true );
+
+ // do not clone objects and note captions into clipdoc (see above)
+ // but at least copy notes
+ ScClipParam aClipParam(aSrcRange, bCut);
+ rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false);
+
+ if (bCut)
+ {
+ ScRange aSrcPaintRange = aSrcRange;
+ rDoc.ExtendMerge( aSrcPaintRange ); // before deleting
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aSrcPaintRange );
+ rDoc.DeleteAreaTab( aSrcRange, nRedoFlags );
+ PaintArea( aSrcPaintRange, nExtFlags );
+ }
+
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
+ aDestMark.SelectTable( nTab, true );
+
+ bool bIncludeFiltered = bCut;
+ // TODO: restore old note captions instead of cloning new captions...
+ rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
+
+ if (bCut)
+ for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
+ rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(),
+ aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row(), nTab );
+
+ // skipped rows and merged cells don't mix
+ if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
+ pDocShell->GetDocFunc().UnmergeCells( aDestRange, false, nullptr );
+
+ for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
+ {
+ SCCOL nEndCol = aDestRange.aEnd.Col();
+ SCROW nEndRow = aDestRange.aEnd.Row();
+ rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ nEndCol, nEndRow, nTab, true );
+ PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab,
+ nEndCol, nEndRow, nTab ), 0 );
+ }
+
+ SetChangeTrack();
+
+ pClipDoc.reset();
+ ShowTable( aDestRange.aStart.Tab() );
+
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // not possible
+}
+
+// Insert list containing range names
+// (Insert|Name|Insert =>[List])
+ScUndoListNames::ScUndoListNames(ScDocShell* pNewDocShell, const ScRange& rRange,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc)
+ : ScBlockUndo(pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xRedoDoc(std::move(pNewRedoDoc))
+{
+}
+
+OUString ScUndoListNames::GetComment() const
+{
+ return ScResId( STR_UNDO_LISTNAMES );
+}
+
+void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL );
+ pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoListNames::Undo()
+{
+ BeginUndo();
+ DoChange(xUndoDoc.get());
+ EndUndo();
+}
+
+void ScUndoListNames::Redo()
+{
+ BeginRedo();
+ DoChange(xRedoDoc.get());
+ EndRedo();
+}
+
+void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
+ pTabViewTarget->GetViewShell()->InsertNameList();
+}
+
+bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, const ScRange& rRange):
+ ScSimpleUndo( pNewDocShell ),
+ mpUndoDoc(std::move(pUndoDoc)),
+ mpRedoDoc(std::move(pRedoDoc)),
+ maRange(rRange)
+{
+}
+
+ScUndoConditionalFormat::~ScUndoConditionalFormat()
+{
+}
+
+OUString ScUndoConditionalFormat::GetComment() const
+{
+ return ScResId( STR_UNDO_CONDFORMAT );
+}
+
+void ScUndoConditionalFormat::Undo()
+{
+ DoChange(mpUndoDoc.get());
+}
+
+void ScUndoConditionalFormat::Redo()
+{
+ DoChange(mpRedoDoc.get());
+}
+
+void ScUndoConditionalFormat::DoChange(ScDocument* pSrcDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( maRange, InsertDeleteFlags::ALL );
+ pSrcDoc->CopyToDocument(maRange, InsertDeleteFlags::ALL, false, rDoc);
+ pDocShell->PostPaint( maRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& )
+{
+}
+
+bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab):
+ ScSimpleUndo( pNewDocShell ),
+ mpUndoDoc(std::move(pUndoDoc)),
+ mpRedoDoc(std::move(pRedoDoc)),
+ mnTab(nTab)
+{
+}
+
+ScUndoConditionalFormatList::~ScUndoConditionalFormatList()
+{
+}
+
+OUString ScUndoConditionalFormatList::GetComment() const
+{
+ return ScResId( STR_UNDO_CONDFORMAT_LIST );
+}
+
+void ScUndoConditionalFormatList::Undo()
+{
+ DoChange(mpUndoDoc.get());
+}
+
+void ScUndoConditionalFormatList::Redo()
+{
+ DoChange(mpRedoDoc.get());
+}
+
+void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (pSrcDoc == mpUndoDoc.get())
+ {
+ mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
+ mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
+ }
+ else
+ {
+ mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
+ mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
+ }
+ rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pSrcDoc->GetCondFormList(mnTab)), mnTab);
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& )
+{
+}
+
+bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+ScUndoUseScenario::ScUndoUseScenario( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+/*C*/ const ScArea& rDestArea,
+ ScDocumentUniquePtr pNewUndoDoc,
+ const OUString& rNewName ) :
+ ScSimpleUndo( pNewDocShell ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aMarkData( rMark ),
+ aName( rNewName )
+{
+ aRange.aStart.SetCol(rDestArea.nColStart);
+ aRange.aStart.SetRow(rDestArea.nRowStart);
+ aRange.aStart.SetTab(rDestArea.nTab);
+ aRange.aEnd.SetCol(rDestArea.nColEnd);
+ aRange.aEnd.SetRow(rDestArea.nRowEnd);
+ aRange.aEnd.SetTab(rDestArea.nTab);
+}
+
+ScUndoUseScenario::~ScUndoUseScenario()
+{
+}
+
+OUString ScUndoUseScenario::GetComment() const
+{
+ return ScResId( STR_UNDO_USESCENARIO );
+}
+
+void ScUndoUseScenario::Undo()
+{
+ BeginUndo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->DoneBlockMode();
+ pViewShell->InitOwnBlockMode( aRange );
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData );
+ pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData);
+
+ // scenario table
+ bool bFrame = false;
+ SCTAB nTab = aRange.aStart.Tab();
+ SCTAB nEndTab = nTab;
+ while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) )
+ ++nEndTab;
+ for (SCTAB i = nTab+1; i<=nEndTab; i++)
+ {
+ // Flags always
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData( i, aComment, aColor, nScenFlags );
+ bool bActive = pUndoDoc->IsActiveScenario( i );
+ rDoc.SetActiveScenario( i, bActive );
+ // For copy-back scenario also consider content
+ if ( nScenFlags & ScScenarioFlags::TwoWay )
+ {
+ rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL );
+ pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc);
+ }
+ if ( nScenFlags & ScScenarioFlags::ShowFrame )
+ bFrame = true;
+ }
+
+ // if visible borders, then paint all
+ if (bFrame)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras );
+ else
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras );
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( aRange.aStart.Tab() );
+
+ EndUndo();
+}
+
+void ScUndoUseScenario::Redo()
+{
+ SCTAB nTab = aRange.aStart.Tab();
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->DoneBlockMode();
+ pViewShell->InitOwnBlockMode( aRange );
+ }
+
+ pDocShell->UseScenario( nTab, aName, false );
+
+ EndRedo();
+}
+
+void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ OUString aTemp = aName;
+ pViewTarget->GetViewShell()->UseScenario(aTemp);
+ }
+}
+
+bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
+ return !rViewData.GetDocument().IsScenario( rViewData.GetTabNo() );
+ }
+ return false;
+}
+
+ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ const ScRange& rRange,
+ const OUString& rName,
+ ScDocumentUniquePtr pNewUndoDoc ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aStyleName( rName ),
+ aRange( rRange )
+{
+ aMarkData.MarkToMulti();
+}
+
+ScUndoSelectionStyle::~ScUndoSelectionStyle()
+{
+}
+
+OUString ScUndoSelectionStyle::GetComment() const
+{
+ return ScResId( STR_UNDO_APPLYCELLSTYLE );
+}
+
+void ScUndoSelectionStyle::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aWorkRange( aRange );
+ if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) ) // Merged cells?
+ rDoc.ExtendMerge( aWorkRange, true );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+
+ if (bUndo) // if Undo then push back all old data again
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aWorkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ }
+ else // if Redo, then reapply style
+ {
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ ScStyleSheet* pStyleSheet =
+ static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
+ if (!pStyleSheet)
+ {
+ OSL_FAIL("StyleSheet not found");
+ return;
+ }
+ rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData );
+ }
+
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ ShowTable( aWorkRange.aStart.Tab() );
+}
+
+void ScUndoSelectionStyle::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoSelectionStyle::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (dynamic_cast<const ScTabViewTarget*>( &rTarget) == nullptr)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool->
+ Find( aStyleName, SfxStyleFamily::Para ));
+ if (!pStyleSheet)
+ {
+ OSL_FAIL("StyleSheet not found");
+ return;
+ }
+
+ ScTabViewShell& rViewShell = *static_cast<ScTabViewTarget&>(rTarget).GetViewShell();
+ rViewShell.SetStyleSheetToMarked( pStyleSheet );
+}
+
+bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell* pNewDocShell, const ScRange& rArea,
+ ScDocumentUniquePtr pNewUndoDoc, const OUString& rForm ) :
+ ScBlockUndo( pNewDocShell, rArea, SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aFormula( rForm )
+{
+ SetChangeTrack();
+}
+
+ScUndoEnterMatrix::~ScUndoEnterMatrix()
+{
+}
+
+OUString ScUndoEnterMatrix::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERMATRIX );
+}
+
+void ScUndoEnterMatrix::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoEnterMatrix::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoEnterMatrix::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( aBlockRange.aStart.Tab() );
+ aDestMark.SetMarkArea( aBlockRange );
+
+ rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
+ aDestMark, aFormula );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
+ {
+ OUString aTemp = aFormula;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pTabViewTarget->GetViewShell()->EnterMatrix(aTemp, rDoc.GetGrammar());
+ }
+}
+
+bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark )
+{
+ OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" );
+ return rMark.GetMultiMarkArea();
+}
+
+ScUndoIndent::ScUndoIndent( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ bIsIncrement( bIncrement )
+{
+}
+
+ScUndoIndent::~ScUndoIndent()
+{
+}
+
+OUString ScUndoIndent::GetComment() const
+{
+ TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT;
+ return ScResId(pId);
+}
+
+void ScUndoIndent::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoIndent::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->ChangeIndent( bIsIncrement );
+}
+
+bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoTransliterate::ScUndoTransliterate( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ nTransliterationType( nType )
+{
+}
+
+ScUndoTransliterate::~ScUndoTransliterate()
+{
+}
+
+OUString ScUndoTransliterate::GetComment() const
+{
+ return ScResId( STR_UNDO_TRANSLITERATE );
+}
+
+void ScUndoTransliterate::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoTransliterate::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.TransliterateText( aMarkData, nTransliterationType );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->TransliterateText( nTransliterationType );
+}
+
+bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoClearItems::ScUndoClearItems( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+ OSL_ENSURE( pW, "ScUndoClearItems: Which-Pointer is Null" );
+
+ sal_uInt16 nCount = 0;
+ while ( pW[nCount] )
+ ++nCount;
+ pWhich.reset( new sal_uInt16[nCount+1] );
+ for (sal_uInt16 i=0; i<=nCount; i++)
+ pWhich[i] = pW[i];
+}
+
+ScUndoClearItems::~ScUndoClearItems()
+{
+}
+
+OUString ScUndoClearItems::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECONTENTS );
+}
+
+void ScUndoClearItems::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoClearItems::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.ClearSelectionItems( pWhich.get(), aMarkData );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
+ rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false );
+ }
+}
+
+bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// remove all line breaks of a table
+ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell* pNewDocShell,
+ SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nNewTab ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+}
+
+ScUndoRemoveBreaks::~ScUndoRemoveBreaks()
+{
+}
+
+OUString ScUndoRemoveBreaks::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVEBREAKS );
+}
+
+void ScUndoRemoveBreaks::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc);
+ if (pViewShell)
+ pViewShell->UpdatePageBreakData( true );
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+
+ EndUndo();
+}
+
+void ScUndoRemoveBreaks::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ rDoc.RemoveManualBreaks(nTab);
+ rDoc.UpdatePageBreaks(nTab);
+ if (pViewShell)
+ pViewShell->UpdatePageBreakData( true );
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+
+ EndRedo();
+}
+
+void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ rViewShell.RemoveManualBreaks();
+ }
+}
+
+bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+ maOptions.push_back( rOption);
+}
+
+ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScBlockUndo( pNewDocShell, rRange, SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+}
+
+ScUndoRemoveMerge::~ScUndoRemoveMerge()
+{
+}
+
+OUString ScUndoRemoveMerge::GetComment() const
+{
+ return ScResId( STR_UNDO_REMERGE ); // "remove merge"
+}
+
+ScDocument* ScUndoRemoveMerge::GetUndoDoc()
+{
+ return pUndoDoc.get();
+}
+
+void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption )
+{
+ maOptions.push_back( rOption);
+}
+
+void ScUndoRemoveMerge::Undo()
+{
+ using ::std::set;
+
+ SetCurTab();
+ BeginUndo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const auto & rOption : maOptions)
+ {
+ for (const auto& rTab : rOption.maTabs)
+ {
+ OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!");
+ if (!pUndoDoc)
+ continue;
+ // There is no need to extend merge area because it's already been extended.
+ ScRange aRange = rOption.getSingleRange(rTab);
+ rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB);
+ pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc);
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(rTab);
+ bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
+ }
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+ }
+ }
+
+ EndUndo();
+}
+
+void ScUndoRemoveMerge::Redo()
+{
+ using ::std::set;
+
+ SetCurTab();
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ for (const auto & rOption : maOptions)
+ {
+ for (const SCTAB nTab : rOption.maTabs)
+ {
+ // There is no need to extend merge area because it's already been extended.
+ ScRange aRange = rOption.getSingleRange(nTab);
+
+ const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( rDefAttr );
+ rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow,
+ rOption.mnEndCol, rOption.mnEndRow, nTab,
+ aPattern );
+
+ rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow,
+ rOption.mnEndCol, rOption.mnEndRow, nTab,
+ ScMF::Hor | ScMF::Ver );
+
+ rDoc.ExtendMerge(aRange, true);
+
+ // Paint
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(nTab);
+ bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
+ }
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+ }
+ }
+
+ EndRedo();
+}
+
+void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RemoveMerge();
+}
+
+bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+void ScUndoRemoveMerge::SetCurTab()
+{
+ SCTAB nCurTab = ScDocShell::GetCurTab();
+ aBlockRange.aStart.SetTab(nCurTab);
+ aBlockRange.aEnd.SetTab(nCurTab);
+}
+
+/** set only border, for ScRangeList (StarOne) */
+static ScRange lcl_TotalRange( const ScRangeList& rRanges )
+{
+ ScRange aTotal;
+ if ( !rRanges.empty() )
+ {
+ aTotal = rRanges[ 0 ];
+ for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = rRanges[ i ];
+ if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col());
+ if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row());
+ if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab());
+ if (rRange.aEnd.Col() > aTotal.aEnd.Col() ) aTotal.aEnd.SetCol( rRange.aEnd.Col() );
+ if (rRange.aEnd.Row() > aTotal.aEnd.Row() ) aTotal.aEnd.SetRow( rRange.aEnd.Row() );
+ if (rRange.aEnd.Tab() > aTotal.aEnd.Tab() ) aTotal.aEnd.SetTab(rRange.aEnd.Tab() );
+ }
+ }
+ return aTotal;
+}
+
+ScUndoBorder::ScUndoBorder(ScDocShell* pNewDocShell,
+ const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc,
+ const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner)
+ : ScBlockUndo(pNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE)
+ , xUndoDoc(std::move(pNewUndoDoc))
+{
+ xRanges.reset(new ScRangeList(rRangeList));
+ xOuter.reset(new SvxBoxItem(rNewOuter));
+ xInner.reset(new SvxBoxInfoItem(rNewInner));
+}
+
+OUString ScUndoBorder::GetComment() const
+{
+ return ScResId( STR_UNDO_SELATTRLINES ); //! own string?
+}
+
+void ScUndoBorder::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList(*xRanges, false);
+ xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoBorder::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument(); // call function at docfunc
+ size_t nCount = xRanges->size();
+ for (size_t i = 0; i < nCount; ++i )
+ {
+ ScRange const & rRange = (*xRanges)[i];
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rRange );
+ aMark.SelectTable( nTab, true );
+
+ rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get());
+ }
+ for (size_t i = 0; i < nCount; ++i)
+ pDocShell->PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //TODO later (when the function has moved from cellsuno to docfunc)
+}
+
+bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // See above
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */