summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/undo
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/source/ui/undo
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sc/source/ui/undo')
-rw-r--r--sc/source/ui/undo/UndoDeleteSparkline.cxx76
-rw-r--r--sc/source/ui/undo/UndoDeleteSparklineGroup.cxx82
-rw-r--r--sc/source/ui/undo/UndoEditSparkline.cxx63
-rw-r--r--sc/source/ui/undo/UndoEditSparklineGroup.cxx65
-rw-r--r--sc/source/ui/undo/UndoGroupSparklines.cxx91
-rw-r--r--sc/source/ui/undo/UndoInsertSparkline.cxx78
-rw-r--r--sc/source/ui/undo/UndoUngroupSparklines.cxx89
-rw-r--r--sc/source/ui/undo/areasave.cxx192
-rw-r--r--sc/source/ui/undo/refundo.cxx176
-rw-r--r--sc/source/ui/undo/target.cxx24
-rw-r--r--sc/source/ui/undo/undobase.cxx616
-rw-r--r--sc/source/ui/undo/undoblk.cxx2437
-rw-r--r--sc/source/ui/undo/undoblk2.cxx186
-rw-r--r--sc/source/ui/undo/undoblk3.cxx1743
-rw-r--r--sc/source/ui/undo/undocell.cxx1048
-rw-r--r--sc/source/ui/undo/undocell2.cxx71
-rw-r--r--sc/source/ui/undo/undoconvert.cxx52
-rw-r--r--sc/source/ui/undo/undodat.cxx1925
-rw-r--r--sc/source/ui/undo/undodraw.cxx107
-rw-r--r--sc/source/ui/undo/undoolk.cxx75
-rw-r--r--sc/source/ui/undo/undorangename.cxx136
-rw-r--r--sc/source/ui/undo/undosort.cxx87
-rw-r--r--sc/source/ui/undo/undostyl.cxx280
-rw-r--r--sc/source/ui/undo/undotab.cxx1570
-rw-r--r--sc/source/ui/undo/undoutil.cxx114
25 files changed, 11383 insertions, 0 deletions
diff --git a/sc/source/ui/undo/UndoDeleteSparkline.cxx b/sc/source/ui/undo/UndoDeleteSparkline.cxx
new file mode 100644
index 000000000..6c9df1809
--- /dev/null
+++ b/sc/source/ui/undo/UndoDeleteSparkline.cxx
@@ -0,0 +1,76 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoDeleteSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoDeleteSparkline::UndoDeleteSparkline(ScDocShell& rDocShell, ScAddress const& rSparklinePosition)
+ : ScSimpleUndo(&rDocShell)
+ , maSparklinePosition(rSparklinePosition)
+{
+}
+
+UndoDeleteSparkline::~UndoDeleteSparkline() {}
+
+void UndoDeleteSparkline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ auto pSparkline = rDocument.GetSparkline(maSparklinePosition);
+ if (!pSparkline)
+ {
+ rDocument.CreateSparkline(maSparklinePosition, mpSparklineGroup);
+ }
+ else
+ {
+ SAL_WARN("sc", "Can't undo deletion if the sparkline at that address already exists.");
+ }
+
+ pDocShell->PostPaintCell(maSparklinePosition);
+
+ EndUndo();
+}
+
+void UndoDeleteSparkline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ if (auto pSparkline = rDocument.GetSparkline(maSparklinePosition))
+ {
+ mpSparklineGroup = pSparkline->getSparklineGroup();
+ rDocument.DeleteSparkline(maSparklinePosition);
+ }
+ else
+ {
+ SAL_WARN("sc", "Can't delete a sparkline that donesn't exist.");
+ }
+
+ pDocShell->PostPaintCell(maSparklinePosition);
+
+ EndRedo();
+}
+
+void UndoDeleteSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoDeleteSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoDeleteSparkline::GetComment() const { return ScResId(STR_UNDO_DELETE_SPARKLINE); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx b/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx
new file mode 100644
index 000000000..9a8e4eb5d
--- /dev/null
+++ b/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx
@@ -0,0 +1,82 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoDeleteSparklineGroup.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <document.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineList.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoDeleteSparklineGroup::UndoDeleteSparklineGroup(
+ ScDocShell& rDocShell, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup, SCTAB nTab)
+ : ScSimpleUndo(&rDocShell)
+ , mpSparklineGroup(pSparklineGroup)
+ , mnTab(nTab)
+{
+}
+
+UndoDeleteSparklineGroup::~UndoDeleteSparklineGroup() {}
+
+void UndoDeleteSparklineGroup::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (auto const& pSparkline : maSparklines)
+ {
+ ScAddress aAddress(pSparkline->getColumn(), pSparkline->getRow(), mnTab);
+ auto* pNewSparkline = rDocument.CreateSparkline(aAddress, mpSparklineGroup);
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+ }
+
+ pDocShell->PostPaintGridAll();
+
+ EndUndo();
+}
+
+void UndoDeleteSparklineGroup::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ auto* pList = rDocument.GetSparklineList(mnTab);
+ if (pList)
+ {
+ maSparklines = pList->getSparklinesFor(mpSparklineGroup);
+
+ for (auto const& pSparkline : maSparklines)
+ {
+ ScAddress aAddress(pSparkline->getColumn(), pSparkline->getRow(), mnTab);
+ rDocument.DeleteSparkline(aAddress);
+ }
+ }
+ pDocShell->PostPaintGridAll();
+
+ EndRedo();
+}
+
+void UndoDeleteSparklineGroup::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoDeleteSparklineGroup::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoDeleteSparklineGroup::GetComment() const
+{
+ return ScResId(STR_UNDO_DELETE_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoEditSparkline.cxx b/sc/source/ui/undo/UndoEditSparkline.cxx
new file mode 100644
index 000000000..b1f6f38f5
--- /dev/null
+++ b/sc/source/ui/undo/UndoEditSparkline.cxx
@@ -0,0 +1,63 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoEditSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoEditSparkline::UndoEditSparkline(ScDocShell& rDocShell,
+ std::shared_ptr<sc::Sparkline> const& rpSparkline, SCTAB nTab,
+ ScRangeList const& rDataRange)
+ : ScSimpleUndo(&rDocShell)
+ , mpSparkline(rpSparkline)
+ , mnTab(nTab)
+ , maOldDataRange(mpSparkline->getInputRange())
+ , maNewDataRange(rDataRange)
+{
+}
+
+UndoEditSparkline::~UndoEditSparkline() = default;
+
+void UndoEditSparkline::Undo()
+{
+ BeginUndo();
+
+ mpSparkline->setInputRange(maOldDataRange);
+
+ pDocShell->PostPaintCell(ScAddress(mpSparkline->getColumn(), mpSparkline->getRow(), mnTab));
+
+ EndUndo();
+}
+
+void UndoEditSparkline::Redo()
+{
+ BeginRedo();
+
+ mpSparkline->setInputRange(maNewDataRange);
+
+ pDocShell->PostPaintCell(ScAddress(mpSparkline->getColumn(), mpSparkline->getRow(), mnTab));
+
+ EndRedo();
+}
+
+void UndoEditSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoEditSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoEditSparkline::GetComment() const { return ScResId(STR_UNDO_EDIT_SPARKLINE); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoEditSparklineGroup.cxx b/sc/source/ui/undo/UndoEditSparklineGroup.cxx
new file mode 100644
index 000000000..8136003d6
--- /dev/null
+++ b/sc/source/ui/undo/UndoEditSparklineGroup.cxx
@@ -0,0 +1,65 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoEditSparklineGroup.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoEditSparklneGroup::UndoEditSparklneGroup(
+ ScDocShell& rDocShell, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup,
+ sc::SparklineAttributes const& rAttributes)
+ : ScSimpleUndo(&rDocShell)
+ , m_pSparklineGroup(pSparklineGroup)
+ , m_aNewAttributes(rAttributes)
+ , m_aOriginalAttributes(pSparklineGroup->getAttributes())
+{
+}
+
+UndoEditSparklneGroup::~UndoEditSparklneGroup() = default;
+
+void UndoEditSparklneGroup::Undo()
+{
+ BeginUndo();
+
+ m_pSparklineGroup->setAttributes(m_aOriginalAttributes);
+ pDocShell->PostPaintGridAll();
+
+ EndUndo();
+}
+
+void UndoEditSparklneGroup::Redo()
+{
+ BeginRedo();
+
+ m_pSparklineGroup->setAttributes(m_aNewAttributes);
+ pDocShell->PostPaintGridAll();
+
+ EndRedo();
+}
+
+void UndoEditSparklneGroup::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoEditSparklneGroup::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoEditSparklneGroup::GetComment() const
+{
+ return ScResId(STR_UNDO_EDIT_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoGroupSparklines.cxx b/sc/source/ui/undo/UndoGroupSparklines.cxx
new file mode 100644
index 000000000..ac2182714
--- /dev/null
+++ b/sc/source/ui/undo/UndoGroupSparklines.cxx
@@ -0,0 +1,91 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoGroupSparklines.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoGroupSparklines::UndoGroupSparklines(
+ ScDocShell& rDocShell, ScRange const& rRange,
+ std::shared_ptr<sc::SparklineGroup> const& rpSparklineGroup)
+ : ScSimpleUndo(&rDocShell)
+ , m_aRange(rRange)
+ , m_pSparklineGroup(rpSparklineGroup)
+{
+}
+
+UndoGroupSparklines::~UndoGroupSparklines() = default;
+
+void UndoGroupSparklines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (auto& rUndoData : m_aUndoData)
+ {
+ rDocument.DeleteSparkline(rUndoData.m_aAddress);
+ auto* pCreated
+ = rDocument.CreateSparkline(rUndoData.m_aAddress, rUndoData.m_pSparklineGroup);
+ pCreated->setInputRange(rUndoData.m_aDataRangeList);
+ }
+
+ m_aUndoData.clear();
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoGroupSparklines::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (ScAddress aAddress = m_aRange.aStart; aAddress.Col() <= m_aRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ aAddress.SetRow(m_aRange.aStart.Row());
+ for (; aAddress.Row() <= m_aRange.aEnd.Row(); aAddress.IncRow())
+ {
+ if (auto pSparkline = rDocument.GetSparkline(aAddress))
+ {
+ m_aUndoData.emplace_back(aAddress, pSparkline->getInputRange(),
+ pSparkline->getSparklineGroup());
+
+ rDocument.DeleteSparkline(aAddress);
+ auto* pCreated = rDocument.CreateSparkline(aAddress, m_pSparklineGroup);
+ pCreated->setInputRange(pSparkline->getInputRange());
+ }
+ }
+ }
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoGroupSparklines::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoGroupSparklines::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoGroupSparklines::GetComment() const { return ScResId(STR_UNDO_GROUP_SPARKLINES); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoInsertSparkline.cxx b/sc/source/ui/undo/UndoInsertSparkline.cxx
new file mode 100644
index 000000000..c35cc3f6d
--- /dev/null
+++ b/sc/source/ui/undo/UndoInsertSparkline.cxx
@@ -0,0 +1,78 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoInsertSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineData.hxx>
+
+namespace sc
+{
+UndoInsertSparkline::UndoInsertSparkline(ScDocShell& rDocShell,
+ std::vector<SparklineData> const& rSparklineDataVector,
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup)
+ : ScSimpleUndo(&rDocShell)
+ , maSparklineDataVector(rSparklineDataVector)
+ , mpSparklineGroup(pSparklineGroup)
+{
+}
+
+UndoInsertSparkline::~UndoInsertSparkline() {}
+
+void UndoInsertSparkline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScRangeList aRanges;
+ for (auto const& rSparklineData : maSparklineDataVector)
+ {
+ rDocument.DeleteSparkline(rSparklineData.maPosition);
+ aRanges.push_back(ScRange(rSparklineData.maPosition));
+ }
+
+ pDocShell->PostPaint(aRanges, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoInsertSparkline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScRangeList aRanges;
+ for (auto const& rSparklineData : maSparklineDataVector)
+ {
+ auto* pCreated = rDocument.CreateSparkline(rSparklineData.maPosition, mpSparklineGroup);
+ pCreated->setInputRange(rSparklineData.maData);
+ aRanges.push_back(ScRange(rSparklineData.maPosition));
+ }
+
+ pDocShell->PostPaint(aRanges, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoInsertSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoInsertSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoInsertSparkline::GetComment() const
+{
+ return ScResId(STR_UNDO_INSERT_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoUngroupSparklines.cxx b/sc/source/ui/undo/UndoUngroupSparklines.cxx
new file mode 100644
index 000000000..fe0201eb6
--- /dev/null
+++ b/sc/source/ui/undo/UndoUngroupSparklines.cxx
@@ -0,0 +1,89 @@
+/* -*- 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/.
+ *
+ */
+
+#include <undo/UndoUngroupSparklines.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoUngroupSparklines::UndoUngroupSparklines(ScDocShell& rDocShell, ScRange const& rRange)
+ : ScSimpleUndo(&rDocShell)
+ , m_aRange(rRange)
+{
+}
+
+UndoUngroupSparklines::~UndoUngroupSparklines() = default;
+
+void UndoUngroupSparklines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (SparklineUndoData& rUndoData : m_aUndoData)
+ {
+ rDocument.DeleteSparkline(rUndoData.m_aAddress);
+ auto* pCreated
+ = rDocument.CreateSparkline(rUndoData.m_aAddress, rUndoData.m_pSparklineGroup);
+ pCreated->setInputRange(rUndoData.m_aDataRangeList);
+ }
+
+ m_aUndoData.clear();
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoUngroupSparklines::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (ScAddress aAddress = m_aRange.aStart; aAddress.Col() <= m_aRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ aAddress.SetRow(m_aRange.aStart.Row());
+ for (; aAddress.Row() <= m_aRange.aEnd.Row(); aAddress.IncRow())
+ {
+ if (auto pSparkline = rDocument.GetSparkline(aAddress))
+ {
+ auto const& rpGroup = pSparkline->getSparklineGroup();
+ m_aUndoData.emplace_back(aAddress, pSparkline->getInputRange(), rpGroup);
+ auto pSparklineGroupCopy
+ = std::make_shared<sc::SparklineGroup>(rpGroup->getAttributes());
+ rDocument.DeleteSparkline(aAddress);
+ auto* pCreated = rDocument.CreateSparkline(aAddress, pSparklineGroupCopy);
+ pCreated->setInputRange(pSparkline->getInputRange());
+ }
+ }
+ }
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoUngroupSparklines::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoUngroupSparklines::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoUngroupSparklines::GetComment() const { return ScResId(STR_UNDO_UNGROUP_SPARKLINES); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/areasave.cxx b/sc/source/ui/undo/areasave.cxx
new file mode 100644
index 000000000..f675c1abc
--- /dev/null
+++ b/sc/source/ui/undo/areasave.cxx
@@ -0,0 +1,192 @@
+/* -*- 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 <sfx2/linkmgr.hxx>
+
+#include <areasave.hxx>
+#include <arealink.hxx>
+#include <document.hxx>
+#include <documentlinkmgr.hxx>
+
+ScAreaLinkSaver::ScAreaLinkSaver( const ScAreaLink& rSource ) :
+ aFileName ( rSource.GetFile() ),
+ aFilterName ( rSource.GetFilter() ),
+ aOptions ( rSource.GetOptions() ),
+ aSourceArea ( rSource.GetSource() ),
+ aDestArea ( rSource.GetDestArea() ),
+ nRefreshDelaySeconds ( rSource.GetRefreshDelaySeconds() ) // seconds
+{
+}
+
+bool ScAreaLinkSaver::IsEqualSource( const ScAreaLink& rCompare ) const
+{
+ return ( aFileName == rCompare.GetFile() &&
+ aFilterName == rCompare.GetFilter() &&
+ aOptions == rCompare.GetOptions() &&
+ aSourceArea == rCompare.GetSource() &&
+ nRefreshDelaySeconds == rCompare.GetRefreshDelaySeconds() );
+}
+
+bool ScAreaLinkSaver::IsEqual( const ScAreaLink& rCompare ) const
+{
+ return ( IsEqualSource( rCompare ) &&
+ aDestArea == rCompare.GetDestArea() );
+}
+
+void ScAreaLinkSaver::WriteToLink( ScAreaLink& rLink ) const
+{
+ rLink.SetDestArea( aDestArea );
+}
+
+void ScAreaLinkSaver::InsertNewLink( ScDocument* pDoc )
+{
+ // (see ScUndoRemoveAreaLink::Undo)
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+
+ if ( pLinkManager && pObjSh )
+ {
+ ScAreaLink* pLink = new ScAreaLink( pObjSh, aFileName, aFilterName, aOptions,
+ aSourceArea, aDestArea.aStart, nRefreshDelaySeconds );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aDestArea );
+ OUString aTmp1(aFilterName), aTmp2(aSourceArea);
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aTmp1, &aTmp2 );
+ pLink->Update();
+ pLink->SetInCreate( false );
+ }
+}
+
+ScAreaLinkSaveCollection::ScAreaLinkSaveCollection() {}
+
+ScAreaLinkSaveCollection::~ScAreaLinkSaveCollection() {}
+
+bool ScAreaLinkSaveCollection::IsEqual( const ScDocument* pDoc ) const
+{
+ // IsEqual can be checked in sequence.
+ // Neither ref-update nor removing links will change the order.
+
+ const sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ if (pLinkManager)
+ {
+ size_t nPos = 0;
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if ( nPos >= size() || !(*this)[nPos].IsEqual( *pAreaLink ) )
+ return false;
+
+ ++nPos;
+ }
+ }
+ if ( nPos < size() )
+ return false; // fewer links in the document than in the save collection
+ }
+
+ return true;
+}
+
+static ScAreaLink* lcl_FindLink( const ::sfx2::SvBaseLinks& rLinks, const ScAreaLinkSaver& rSaver )
+{
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if ( auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase) )
+ if ( rSaver.IsEqualSource( *pAreaLink ) )
+ return pAreaLink; // found
+ }
+ return nullptr; // not found
+}
+
+void ScAreaLinkSaveCollection::Restore( ScDocument* pDoc )
+{
+ // The save collection may contain additional entries that are not in the document.
+ // They must be inserted again.
+ // Entries from the save collection must be searched via source data, as the order
+ // of links changes if deleted entries are re-added to the link manager (always at the end).
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetDocLinkManager().getLinkManager(false);
+ if (!pLinkManager)
+ return;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ size_t nSaveCount = size();
+ for (size_t nPos=0; nPos<nSaveCount; ++nPos)
+ {
+ ScAreaLinkSaver& rSaver = (*this)[nPos];
+ ScAreaLink* pLink = lcl_FindLink( rLinks, rSaver );
+ if ( pLink )
+ rSaver.WriteToLink( *pLink ); // restore output position
+ else
+ rSaver.InsertNewLink( pDoc ); // re-insert deleted link
+ }
+}
+
+std::unique_ptr<ScAreaLinkSaveCollection> ScAreaLinkSaveCollection::CreateFromDoc( const ScDocument* pDoc )
+{
+ std::unique_ptr<ScAreaLinkSaveCollection> pColl;
+
+ sfx2::LinkManager* pLinkManager = const_cast<ScDocument*>(pDoc)->GetLinkManager();
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if (!pColl)
+ pColl.reset(new ScAreaLinkSaveCollection);
+
+ pColl->push_back( ScAreaLinkSaver( *pAreaLink ) );
+ }
+ }
+ }
+
+ return pColl;
+}
+
+ScAreaLinkSaver& ScAreaLinkSaveCollection::operator [](size_t nIndex)
+{
+ return maData[nIndex];
+}
+
+const ScAreaLinkSaver& ScAreaLinkSaveCollection::operator [](size_t nIndex) const
+{
+ return maData[nIndex];
+}
+
+size_t ScAreaLinkSaveCollection::size() const
+{
+ return maData.size();
+}
+
+void ScAreaLinkSaveCollection::push_back(const ScAreaLinkSaver& p)
+{
+ maData.push_back(p);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/refundo.cxx b/sc/source/ui/undo/refundo.cxx
new file mode 100644
index 000000000..d87098720
--- /dev/null
+++ b/sc/source/ui/undo/refundo.cxx
@@ -0,0 +1,176 @@
+/* -*- 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 <refundo.hxx>
+#include <document.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <detdata.hxx>
+#include <prnsave.hxx>
+#include <chartlis.hxx>
+#include <dpobject.hxx>
+#include <areasave.hxx>
+#include <unoreflist.hxx>
+#include <scopetools.hxx>
+#include <refupdatecontext.hxx>
+
+ScRefUndoData::ScRefUndoData( const ScDocument* pDoc ) :
+ pPrintRanges(pDoc->CreatePrintRangeSaver())
+{
+ const ScDBCollection* pOldDBColl = pDoc->GetDBCollection();
+ if (pOldDBColl && !pOldDBColl->empty())
+ pDBCollection.reset(new ScDBCollection(*pOldDBColl));
+
+ const ScRangeName* pOldRanges = pDoc->GetRangeName();
+ if (pOldRanges && !pOldRanges->empty())
+ pRangeName.reset(new ScRangeName(*pOldRanges));
+
+ // when handling Pivot solely keep the range?
+
+ const ScDPCollection* pOldDP = pDoc->GetDPCollection();
+ if (pOldDP && pOldDP->GetCount())
+ pDPCollection.reset(new ScDPCollection(*pOldDP));
+
+ const ScDetOpList* pOldDetOp = pDoc->GetDetOpList();
+ if (pOldDetOp && pOldDetOp->Count())
+ pDetOpList.reset(new ScDetOpList(*pOldDetOp));
+
+ const ScChartListenerCollection* pOldChartLisColl = pDoc->GetChartListenerCollection();
+ if (pOldChartLisColl)
+ pChartListenerCollection.reset(new ScChartListenerCollection(*pOldChartLisColl));
+
+ pAreaLinks = ScAreaLinkSaveCollection::CreateFromDoc(pDoc); // returns NULL if empty
+
+ const_cast<ScDocument*>(pDoc)->BeginUnoRefUndo();
+}
+
+ScRefUndoData::~ScRefUndoData()
+{
+ pDBCollection.reset();
+ pRangeName.reset();
+ pPrintRanges.reset();
+ pDPCollection.reset();
+ pDetOpList.reset();
+ pChartListenerCollection.reset();
+ pAreaLinks.reset();
+}
+
+void ScRefUndoData::DeleteUnchanged( const ScDocument* pDoc )
+{
+ if (pDBCollection)
+ {
+ ScDBCollection* pNewDBColl = pDoc->GetDBCollection();
+ if ( pNewDBColl && *pDBCollection == *pNewDBColl )
+ pDBCollection.reset();
+ }
+ if (pRangeName)
+ {
+ ScRangeName* pNewRanges = pDoc->GetRangeName();
+ if ( pNewRanges && *pRangeName == *pNewRanges )
+ pRangeName.reset();
+ }
+
+ if (pPrintRanges)
+ {
+ std::unique_ptr<ScPrintRangeSaver> pNewRanges = pDoc->CreatePrintRangeSaver();
+ if ( pNewRanges && *pPrintRanges == *pNewRanges )
+ pPrintRanges.reset();
+ }
+
+ if (pDPCollection)
+ {
+ ScDPCollection* pNewDP = const_cast<ScDocument*>(pDoc)->GetDPCollection(); //! const
+ if ( pNewDP && pDPCollection->RefsEqual(*pNewDP) )
+ pDPCollection.reset();
+ }
+
+ if (pDetOpList)
+ {
+ ScDetOpList* pNewDetOp = pDoc->GetDetOpList();
+ if ( pNewDetOp && *pDetOpList == *pNewDetOp )
+ pDetOpList.reset();
+ }
+
+ if ( pChartListenerCollection )
+ {
+ ScChartListenerCollection* pNewChartListenerCollection =
+ pDoc->GetChartListenerCollection();
+ if ( pNewChartListenerCollection &&
+ *pChartListenerCollection == *pNewChartListenerCollection )
+ pChartListenerCollection.reset();
+ }
+
+ if (pAreaLinks)
+ {
+ if ( pAreaLinks->IsEqual( pDoc ) )
+ pAreaLinks.reset();
+ }
+
+ if ( pDoc->HasUnoRefUndo() )
+ {
+ pUnoRefs = const_cast<ScDocument*>(pDoc)->EndUnoRefUndo();
+ if ( pUnoRefs && pUnoRefs->IsEmpty() )
+ {
+ pUnoRefs.reset();
+ }
+ }
+}
+
+void ScRefUndoData::DoUndo( ScDocument* pDoc, bool bUndoRefFirst )
+{
+ if (pDBCollection)
+ pDoc->SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pDBCollection)) );
+ if (pRangeName)
+ pDoc->SetRangeName( std::unique_ptr<ScRangeName>(new ScRangeName(*pRangeName)) );
+
+ if (pPrintRanges)
+ pDoc->RestorePrintRanges(*pPrintRanges);
+
+ if (pDPCollection)
+ {
+ ScDPCollection* pDocDP = pDoc->GetDPCollection();
+ if (pDocDP)
+ pDPCollection->WriteRefsTo( *pDocDP );
+ }
+
+ if (pDetOpList)
+ pDoc->SetDetOpList( std::unique_ptr<ScDetOpList>(new ScDetOpList(*pDetOpList)) );
+
+ // bUndoRefFirst is bSetChartRangeLists
+ if ( pChartListenerCollection )
+ pDoc->SetChartListenerCollection( std::make_unique<ScChartListenerCollection>(
+ *pChartListenerCollection ), bUndoRefFirst );
+
+ if (pDBCollection || pRangeName)
+ {
+ sc::AutoCalcSwitch aACSwitch(*pDoc, false);
+ pDoc->CompileAll();
+
+ sc::SetFormulaDirtyContext aCxt;
+ pDoc->SetAllFormulasDirty(aCxt);
+ }
+
+ if (pAreaLinks)
+ pAreaLinks->Restore( pDoc );
+
+ if ( pUnoRefs )
+ pUnoRefs->Undo( pDoc );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/target.cxx b/sc/source/ui/undo/target.cxx
new file mode 100644
index 000000000..ee220b633
--- /dev/null
+++ b/sc/source/ui/undo/target.cxx
@@ -0,0 +1,24 @@
+/* -*- 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 <target.hxx>
+
+ScTabViewTarget::~ScTabViewTarget() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx
new file mode 100644
index 000000000..8ce8bc9e8
--- /dev/null
+++ b/sc/source/ui/undo/undobase.cxx
@@ -0,0 +1,616 @@
+/* -*- 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 <vcl/virdev.hxx>
+#include <svx/svdundo.hxx>
+
+#include <undobase.hxx>
+#include <refundo.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <undoolk.hxx>
+#include <undodraw.hxx>
+#include <dbdata.hxx>
+#include <attrib.hxx>
+#include <queryparam.hxx>
+#include <subtotalparam.hxx>
+#include <rowheightcontext.hxx>
+#include <column.hxx>
+#include <sortparam.hxx>
+#include <columnspanset.hxx>
+
+
+ScSimpleUndo::ScSimpleUndo( ScDocShell* pDocSh ) :
+ pDocShell( pDocSh ),
+ mnViewShellId(-1)
+{
+ if (ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell())
+ mnViewShellId = pViewShell->GetViewShellId();
+}
+
+ViewShellId ScSimpleUndo::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+bool ScSimpleUndo::SetViewMarkData( const ScMarkData& rMarkData )
+{
+ if ( IsPaintLocked() )
+ return false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !pViewShell )
+ return false;
+
+ pViewShell->SetMarkData( rMarkData );
+ return true;
+}
+
+bool ScSimpleUndo::Merge( SfxUndoAction *pNextAction )
+{
+ // A SdrUndoGroup for updating detective arrows can belong
+ // to each Undo-Action.
+ // DetectiveRefresh is always called next,
+ // the SdrUndoGroup is encapsulated in a ScUndoDraw action.
+ // AddUndoAction is only called with bTryMerg=sal_True
+ // for automatic update.
+
+ if ( !pDetectiveUndo && dynamic_cast<const ScUndoDraw*>( pNextAction) != nullptr )
+ {
+ // Take SdrUndoAction from ScUndoDraw Action,
+ // ScUndoDraw is later deleted by the UndoManager
+
+ ScUndoDraw* pCalcUndo = static_cast<ScUndoDraw*>(pNextAction);
+ pDetectiveUndo = pCalcUndo->ReleaseDrawUndo();
+ return true;
+ }
+
+ return false;
+}
+
+void ScSimpleUndo::BeginUndo()
+{
+ pDocShell->SetInUndo( true );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->HideAllCursors(); // for example due to merged cells
+
+ // detective updates happened last, must be undone first
+ if (pDetectiveUndo)
+ pDetectiveUndo->Undo();
+}
+
+namespace
+{
+ class DisableUndoGuard
+ {
+ private:
+ ScDocument& m_rDoc;
+ bool m_bUndoEnabled;
+ public:
+ explicit DisableUndoGuard(ScDocShell *pDocShell)
+ : m_rDoc(pDocShell->GetDocument())
+ , m_bUndoEnabled(m_rDoc.IsUndoEnabled())
+ {
+ m_rDoc.EnableUndo(false);
+ }
+
+ ~DisableUndoGuard()
+ {
+ m_rDoc.EnableUndo(m_bUndoEnabled);
+ }
+ };
+}
+
+void ScSimpleUndo::EndUndo()
+{
+ {
+ // rhbz#1352881 Temporarily turn off undo generation during
+ // SetDocumentModified
+ DisableUndoGuard aGuard(pDocShell);
+ pDocShell->SetDocumentModified();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateAutoFillMark();
+ pViewShell->UpdateInputHandler();
+ pViewShell->ShowAllCursors();
+ }
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScSimpleUndo::BeginRedo()
+{
+ pDocShell->SetInUndo( true ); //! own Flag for Redo?
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->HideAllCursors(); // for example due to merged cells
+}
+
+void ScSimpleUndo::EndRedo()
+{
+ if (pDetectiveUndo)
+ pDetectiveUndo->Redo();
+
+ {
+ // rhbz#1352881 Temporarily turn off undo generation during
+ // SetDocumentModified
+ DisableUndoGuard aGuard(pDocShell);
+ pDocShell->SetDocumentModified();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateAutoFillMark();
+ pViewShell->UpdateInputHandler();
+ pViewShell->ShowAllCursors();
+ }
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScSimpleUndo::BroadcastChanges( const ScRange& rRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.BroadcastCells(rRange, SfxHintId::ScDataChanged);
+}
+
+namespace {
+
+class SpanBroadcaster : public sc::ColumnSpanSet::ColumnAction
+{
+ ScDocument& mrDoc;
+ SCTAB mnCurTab;
+ SCCOL mnCurCol;
+
+public:
+ explicit SpanBroadcaster( ScDocument& rDoc ) : mrDoc(rDoc), mnCurTab(-1), mnCurCol(-1) {}
+
+ virtual void startColumn( ScColumn* pCol ) override
+ {
+ mnCurTab = pCol->GetTab();
+ mnCurCol = pCol->GetCol();
+ }
+
+ virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
+ {
+ if (!bVal)
+ return;
+
+ ScRange aRange(mnCurCol, nRow1, mnCurTab, mnCurCol, nRow2, mnCurTab);
+ mrDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ };
+};
+
+}
+
+void ScSimpleUndo::BroadcastChanges( const DataSpansType& rSpans )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SpanBroadcaster aBroadcaster(rDoc);
+
+ for (const auto& rEntry : rSpans)
+ {
+ const sc::ColumnSpanSet& rSet = *rEntry.second;
+ rSet.executeColumnAction(rDoc, aBroadcaster);
+ }
+}
+
+void ScSimpleUndo::ShowTable( SCTAB nTab )
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nTab );
+}
+
+void ScSimpleUndo::ShowTable( const ScRange& rRange )
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nStart = rRange.aStart.Tab();
+ SCTAB nEnd = rRange.aEnd.Tab();
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( nTab < nStart || nTab > nEnd ) // if not in range:
+ pViewShell->SetTabNo( nStart ); // at beginning of the range
+ }
+}
+
+ScBlockUndo::ScBlockUndo( ScDocShell* pDocSh, const ScRange& rRange,
+ ScBlockUndoMode eBlockMode ) :
+ ScSimpleUndo( pDocSh ),
+ aBlockRange( rRange ),
+ eMode( eBlockMode )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScBlockUndo::~ScBlockUndo()
+{
+ pDrawUndo.reset();
+}
+
+void ScBlockUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ EnableDrawAdjust( &pDocShell->GetDocument(), false );
+}
+
+void ScBlockUndo::EndUndo()
+{
+ if (eMode == SC_UNDO_AUTOHEIGHT)
+ AdjustHeight();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), true );
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ShowBlock();
+ ScSimpleUndo::EndUndo();
+}
+
+void ScBlockUndo::EndRedo()
+{
+ if (eMode == SC_UNDO_AUTOHEIGHT)
+ AdjustHeight();
+
+ ShowBlock();
+ ScSimpleUndo::EndRedo();
+}
+
+bool ScBlockUndo::AdjustHeight()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ Fraction aZoomX( 1, 1 );
+ Fraction aZoomY = aZoomX;
+ double nPPTX, nPPTY;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ ScViewData& rData = pViewShell->GetViewData();
+ nPPTX = rData.GetPPTX();
+ nPPTY = rData.GetPPTY();
+ aZoomX = rData.GetZoomX();
+ aZoomY = rData.GetZoomY();
+ }
+ else
+ {
+ // Leave zoom at 100
+ nPPTX = ScGlobal::nScreenPPTX;
+ nPPTY = ScGlobal::nScreenPPTY;
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, pVirtDev);
+ bool bRet = rDoc.SetOptimalHeight(
+ aCxt, aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(), aBlockRange.aStart.Tab(), true);
+
+ if (bRet)
+ {
+ // tdf#76183: recalculate objects' positions
+ rDoc.SetDrawPageSize(aBlockRange.aStart.Tab());
+
+ pDocShell->PostPaint( 0, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(),
+ rDoc.MaxCol(), rDoc.MaxRow(), aBlockRange.aEnd.Tab(),
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+ return bRet;
+}
+
+void ScBlockUndo::ShowBlock()
+{
+ if ( IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ ShowTable( aBlockRange ); // with multiple sheets in range each of them is good
+ pViewShell->MoveCursorAbs( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ ScRange aRange = aBlockRange;
+ aRange.aStart.SetTab( nTab );
+ aRange.aEnd.SetTab( nTab );
+ pViewShell->MarkRange( aRange );
+
+ // not through SetMarkArea to MarkData, due to possibly lacking paint
+}
+
+ScMultiBlockUndo::ScMultiBlockUndo(
+ ScDocShell* pDocSh, const ScRangeList& rRanges) :
+ ScSimpleUndo(pDocSh),
+ maBlockRanges(rRanges)
+{
+ mpDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScMultiBlockUndo::~ScMultiBlockUndo()
+{
+ mpDrawUndo.reset();
+}
+
+void ScMultiBlockUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ EnableDrawAdjust(&pDocShell->GetDocument(), false);
+}
+
+void ScMultiBlockUndo::EndUndo()
+{
+ EnableDrawAdjust(&pDocShell->GetDocument(), true);
+ DoSdrUndoAction(mpDrawUndo.get(), &pDocShell->GetDocument());
+
+ ShowBlock();
+ ScSimpleUndo::EndUndo();
+}
+
+void ScMultiBlockUndo::EndRedo()
+{
+ ShowBlock();
+ ScSimpleUndo::EndRedo();
+}
+
+void ScMultiBlockUndo::ShowBlock()
+{
+ if ( IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ if (maBlockRanges.empty())
+ return;
+
+ // Move to the sheet of the first range.
+ ScRange aRange = maBlockRanges.front();
+ ShowTable(aRange);
+ pViewShell->MoveCursorAbs(
+ aRange.aStart.Col(), aRange.aStart.Row(), SC_FOLLOW_JUMP, false, false);
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ aRange.aStart.SetTab(nTab);
+ aRange.aEnd.SetTab(nTab);
+ pViewShell->MarkRange(aRange, false);
+
+ for (size_t i = 1, n = maBlockRanges.size(); i < n; ++i)
+ {
+ aRange = maBlockRanges[i];
+ aRange.aStart.SetTab(nTab);
+ aRange.aEnd.SetTab(nTab);
+ pViewShell->MarkRange(aRange, false, true);
+ }
+}
+
+ScMoveUndo::ScMoveUndo( ScDocShell* pDocSh, ScDocumentUniquePtr pRefDoc, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScSimpleUndo( pDocSh ),
+ pRefUndoDoc( std::move(pRefDoc) ),
+ pRefUndoData( std::move(pRefData) )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (pRefUndoData)
+ pRefUndoData->DeleteUnchanged(&rDoc);
+ pDrawUndo = GetSdrUndoAction( &rDoc );
+}
+
+ScMoveUndo::~ScMoveUndo()
+{
+ pRefUndoData.reset();
+ pRefUndoDoc.reset();
+ pDrawUndo.reset();
+}
+
+void ScMoveUndo::UndoRef()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRange aRange(0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),pRefUndoDoc->GetTableCount()-1);
+ pRefUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::FORMULA, false, rDoc, nullptr, false);
+ if (pRefUndoData)
+ pRefUndoData->DoUndo( &rDoc, false );
+}
+
+void ScMoveUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), false );
+}
+
+void ScMoveUndo::EndUndo()
+{
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() ); // must also be called when pointer is null
+
+ if (pRefUndoDoc)
+ UndoRef();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), true );
+
+ ScSimpleUndo::EndUndo();
+}
+
+ScDBFuncUndo::ScDBFuncUndo( ScDocShell* pDocSh, const ScRange& rOriginal ) :
+ ScSimpleUndo( pDocSh ),
+ aOriginalRange( rOriginal )
+{
+ pAutoDBRange = pDocSh->GetOldAutoDBRange();
+}
+
+ScDBFuncUndo::~ScDBFuncUndo()
+{
+ pAutoDBRange.reset();
+}
+
+void ScDBFuncUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ DoSdrUndoAction( nullptr, &pDocShell->GetDocument() );
+}
+
+void ScDBFuncUndo::EndUndo()
+{
+ ScSimpleUndo::EndUndo();
+
+ if ( !pAutoDBRange )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = rDoc.GetVisibleTab();
+ ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
+ if (!pNoNameData )
+ return;
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
+
+ *pNoNameData = *pAutoDBRange;
+
+ if ( pAutoDBRange->HasAutoFilter() )
+ {
+ // restore AutoFilter buttons
+ pAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ rDoc.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+ pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
+ }
+}
+
+void ScDBFuncUndo::BeginRedo()
+{
+ RedoSdrUndoAction( nullptr );
+ if ( pAutoDBRange )
+ {
+ // move the database range to this function's position again (see ScDocShell::GetDBData)
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDBData* pNoNameData = rDoc.GetAnonymousDBData(aOriginalRange.aStart.Tab());
+ if ( pNoNameData )
+ {
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
+
+ pNoNameData->SetSortParam( ScSortParam() );
+ pNoNameData->SetQueryParam( ScQueryParam() );
+ pNoNameData->SetSubTotalParam( ScSubTotalParam() );
+
+ pNoNameData->SetArea( aOriginalRange.aStart.Tab(),
+ aOriginalRange.aStart.Col(), aOriginalRange.aStart.Row(),
+ aOriginalRange.aEnd.Col(), aOriginalRange.aEnd.Row() );
+
+ pNoNameData->SetByRow( true );
+ pNoNameData->SetAutoFilter( false );
+ // header is always set with the operation in redo
+ }
+ }
+
+ ScSimpleUndo::BeginRedo();
+}
+
+void ScDBFuncUndo::EndRedo()
+{
+ ScSimpleUndo::EndRedo();
+}
+
+ScUndoWrapper::ScUndoWrapper( std::unique_ptr<SfxUndoAction> pUndo ) :
+ pWrappedUndo( std::move(pUndo) ),
+ mnViewShellId( -1 )
+{
+ if (pWrappedUndo)
+ mnViewShellId = pWrappedUndo->GetViewShellId();
+}
+
+ScUndoWrapper::~ScUndoWrapper()
+{
+}
+
+void ScUndoWrapper::ForgetWrappedUndo()
+{
+ pWrappedUndo = nullptr; // don't delete in dtor - pointer must be stored outside
+}
+
+OUString ScUndoWrapper::GetComment() const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->GetComment();
+ return OUString();
+}
+
+ViewShellId ScUndoWrapper::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+OUString ScUndoWrapper::GetRepeatComment(SfxRepeatTarget& rTarget) const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->GetRepeatComment(rTarget);
+ return OUString();
+}
+
+bool ScUndoWrapper::Merge( SfxUndoAction* pNextAction )
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->Merge(pNextAction);
+ else
+ return false;
+}
+
+void ScUndoWrapper::Undo()
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Undo();
+}
+
+void ScUndoWrapper::Redo()
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Redo();
+}
+
+void ScUndoWrapper::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Repeat(rTarget);
+}
+
+bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->CanRepeat(rTarget);
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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: */
diff --git a/sc/source/ui/undo/undoblk2.cxx b/sc/source/ui/undo/undoblk2.cxx
new file mode 100644
index 000000000..52ee421cc
--- /dev/null
+++ b/sc/source/ui/undo/undoblk2.cxx
@@ -0,0 +1,186 @@
+/* -*- 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 <undoblk.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <olinetab.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <target.hxx>
+#include <columnspanset.hxx>
+
+#include <undoolk.hxx>
+
+#include <svx/svdundo.hxx>
+
+/** Change column widths or row heights */
+ScUndoWidthOrHeight::ScUndoWidthOrHeight( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOLROW nNewStart, SCTAB nNewStartTab, SCCOLROW nNewEnd, SCTAB nNewEndTab,
+ ScDocumentUniquePtr pNewUndoDoc, std::vector<sc::ColRowSpan>&& rRanges,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ ScSizeMode eNewMode, sal_uInt16 nNewSizeTwips, bool bNewWidth ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ nStart( nNewStart ),
+ nEnd( nNewEnd ),
+ nStartTab( nNewStartTab ),
+ nEndTab( nNewEndTab ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ pUndoTab( std::move(pNewUndoTab) ),
+ maRanges( std::move(rRanges) ),
+ nNewSize( nNewSizeTwips ),
+ bWidth( bNewWidth ),
+ eMode( eNewMode )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoWidthOrHeight::~ScUndoWidthOrHeight()
+{
+ pUndoDoc.reset();
+ pUndoTab.reset();
+ pDrawUndo.reset();
+}
+
+OUString ScUndoWidthOrHeight::GetComment() const
+{
+ // [ "optimal " ] "Column width" | "row height"
+ return ( bWidth ?
+ ( ( eMode == SC_SIZE_OPTIMAL )?
+ ScResId( STR_UNDO_OPTCOLWIDTH ) :
+ ScResId( STR_UNDO_COLWIDTH )
+ ) :
+ ( ( eMode == SC_SIZE_OPTIMAL )?
+ ScResId( STR_UNDO_OPTROWHEIGHT ) :
+ ScResId( STR_UNDO_ROWHEIGHT )
+ ) );
+}
+
+void ScUndoWidthOrHeight::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOLROW nPaintStart = nStart > 0 ? nStart-1 : static_cast<SCCOLROW>(0);
+
+ if (eMode==SC_SIZE_OPTIMAL)
+ {
+ if ( SetViewMarkData( aMarkData ) )
+ nPaintStart = 0; // paint all, because of changed selection
+ }
+
+ //! outlines from all tables?
+ if (pUndoTab) // Outlines are included when saving ?
+ rDoc.SetOutlineTable( nStartTab, pUndoTab.get() );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (pViewShell)
+ pViewShell->OnLOKSetWidthOrHeight(nStart, bWidth);
+
+ if (bWidth) // Width
+ {
+ pUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, rTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), rTab, InsertDeleteFlags::NONE,
+ false, rDoc);
+ rDoc.UpdatePageBreaks( rTab );
+ pDocShell->PostPaint( static_cast<SCCOL>(nPaintStart), 0, rTab,
+ rDoc.MaxCol(), rDoc.MaxRow(), rTab, PaintPartFlags::Grid | PaintPartFlags::Top );
+ }
+ else // Height
+ {
+ pUndoDoc->CopyToDocument(0, nStart, rTab, rDoc.MaxCol(), nEnd, rTab, InsertDeleteFlags::NONE, false, rDoc);
+ rDoc.UpdatePageBreaks( rTab );
+ pDocShell->PostPaint( 0, nPaintStart, rTab, rDoc.MaxCol(), rDoc.MaxRow(), rTab, PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+ }
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ if (pViewShell)
+ {
+ SCTAB nCurrentTab = pViewShell->GetViewData().GetTabNo();
+ bool bAffectsVisibility = (eMode != SC_SIZE_ORIGINAL && eMode != SC_SIZE_VISOPT);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell, bWidth /* bColumns */, !bWidth /* bRows */,
+ true /* bSizes*/, bAffectsVisibility /* bHidden */, bAffectsVisibility /* bFiltered */,
+ false /* bGroups */, nCurrentTab);
+ pViewShell->UpdateScrollBars(bWidth ? COLUMN_HEADER : ROW_HEADER);
+
+ if ( nCurrentTab < nStartTab || nCurrentTab > nEndTab )
+ pViewShell->SetTabNo( nStartTab );
+ }
+
+ EndUndo();
+}
+
+void ScUndoWidthOrHeight::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bPaintAll = false;
+ if (eMode==SC_SIZE_OPTIMAL)
+ {
+ if ( SetViewMarkData( aMarkData ) )
+ bPaintAll = true; // paint all, because of changed selection
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( nTab < nStartTab || nTab > nEndTab )
+ pViewShell->SetTabNo( nStartTab );
+
+ // SetWidthOrHeight changes current sheet!
+ pViewShell->SetWidthOrHeight(
+ bWidth, maRanges, eMode, nNewSize, false, &aMarkData);
+ }
+
+ // paint grid if selection was changed directly at the MarkData
+ if (bPaintAll)
+ pDocShell->PostPaint( 0, 0, nStartTab, rDoc.MaxCol(), rDoc.MaxRow(), nEndTab, PaintPartFlags::Grid );
+
+ EndRedo();
+}
+
+void ScUndoWidthOrHeight::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SetMarkedWidthOrHeight( bWidth, eMode, nNewSize );
+}
+
+bool ScUndoWidthOrHeight::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx
new file mode 100644
index 000000000..0e8782211
--- /dev/null
+++ b/sc/source/ui/undo/undoblk3.cxx
@@ -0,0 +1,1743 @@
+/* -*- 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 <sal/config.h>
+
+#include <memory>
+
+#include <scitems.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svl/srchitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/app.hxx>
+#include <svx/svdundo.hxx>
+#include <osl/diagnose.h>
+
+#include <undoblk.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <arealink.hxx>
+#include <patattr.hxx>
+#include <target.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <undoolk.hxx>
+#include <undoutil.hxx>
+#include <chgtrack.hxx>
+#include <paramisc.hxx>
+#include <postit.hxx>
+#include <progress.hxx>
+#include <editutil.hxx>
+#include <editdataarray.hxx>
+#include <rowheightcontext.hxx>
+
+// TODO:
+/*A*/ // SetOptimalHeight on Document, when no View
+
+ScUndoDeleteContents::ScUndoDeleteContents(
+ ScDocShell* pNewDocShell,
+ const ScMarkData& rMark, const ScRange& rRange,
+ ScDocumentUniquePtr&& pNewUndoDoc, bool bNewMulti,
+ InsertDeleteFlags nNewFlags, bool bObjects )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( rRange ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ nFlags ( nNewFlags ),
+ bMulti ( bNewMulti ) // unnecessary
+{
+ if (bObjects)
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ if ( !(aMarkData.IsMarked() || aMarkData.IsMultiMarked()) ) // if no cell is selected:
+ aMarkData.SetMarkArea( aRange ); // select cell under cursor
+
+ SetChangeTrack();
+}
+
+ScUndoDeleteContents::~ScUndoDeleteContents()
+{
+ pUndoDoc.reset();
+ pDrawUndo.reset();
+}
+
+OUString ScUndoDeleteContents::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECONTENTS ); // "Delete"
+}
+
+void ScUndoDeleteContents::SetDataSpans( const std::shared_ptr<DataSpansType>& pSpans )
+{
+ mpDataSpans = pSpans;
+}
+
+void ScUndoDeleteContents::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
+ pChangeTrack->AppendContentRange( aRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteContents::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ sal_uInt16 nExtFlags = 0;
+
+ if (bUndo) // only Undo
+ {
+ InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE; // copy either all or none of the content
+ if (nFlags & InsertDeleteFlags::CONTENTS) // (Only the correct ones have been copied into UndoDoc)
+ nUndoFlags |= InsertDeleteFlags::CONTENTS;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nUndoFlags |= InsertDeleteFlags::ATTRIB;
+ if (nFlags & InsertDeleteFlags::EDITATTR) // Edit-Engine attribute
+ nUndoFlags |= InsertDeleteFlags::STRING; // -> Cells will be changed
+ if (nFlags & InsertDeleteFlags::SPARKLINES)
+ nUndoFlags |= InsertDeleteFlags::SPARKLINES;
+ // do not create clones of note captions, they will be restored via drawing undo
+ nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
+
+ ScRange aCopyRange = aRange;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+
+ pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, bMulti, rDoc, &aMarkData);
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ pDocShell->UpdatePaintExt( nExtFlags, aRange ); // content after the change
+ }
+ else // only Redo
+ {
+ pDocShell->UpdatePaintExt( nExtFlags, aRange ); // content before the change
+
+ aMarkData.MarkToMulti();
+ RedoSdrUndoAction( pDrawUndo.get() );
+ // do not delete objects and note captions, they have been removed via drawing undo
+ InsertDeleteFlags nRedoFlags = (nFlags & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+ rDoc.DeleteSelection( nRedoFlags, aMarkData );
+ aMarkData.MarkToSimple();
+
+ SetChangeTrack();
+ }
+
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ {
+ // Broadcast only when the content changes. fdo#74687
+ if (mpDataSpans)
+ BroadcastChanges(*mpDataSpans);
+ else
+ BroadcastChanges(aRange);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustRowHeight(
+ aRange.aStart.Row(), aRange.aEnd.Row(), true ) ) )
+/*A*/ pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( aRange );
+}
+
+void ScUndoDeleteContents::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, aRange);
+}
+
+void ScUndoDeleteContents::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, aRange);
+}
+
+void ScUndoDeleteContents::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DeleteContents( nFlags );
+}
+
+bool ScUndoDeleteContents::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoFillTable::ScUndoFillTable( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti, SCTAB nSrc,
+ InsertDeleteFlags nFlg, ScPasteFunc nFunc, bool bSkip, bool bLink )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ nFlags ( nFlg ),
+ nFunction ( nFunc ),
+ nSrcTab ( nSrc ),
+ bMulti ( bNewMulti ),
+ bSkipEmpty ( bSkip ),
+ bAsLink ( bLink )
+{
+ SetChangeTrack();
+}
+
+ScUndoFillTable::~ScUndoFillTable()
+{
+}
+
+OUString ScUndoFillTable::GetComment() const
+{
+ return ScResId( STR_FILL_TAB );
+}
+
+void ScUndoFillTable::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
+ ScRange aWorkRange(aRange);
+ nStartChangeAction = 0;
+ sal_uLong nTmpAction;
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nSrcTab)
+ {
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+ pChangeTrack->AppendContentRange( aWorkRange, pUndoDoc.get(),
+ nTmpAction, nEndChangeAction );
+ if ( !nStartChangeAction )
+ nStartChangeAction = nTmpAction;
+ }
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoFillTable::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ if (bUndo) // only Undo
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aWorkRange(aRange);
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nSrcTab)
+ {
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+ if (bMulti)
+ rDoc.DeleteSelectionTab( rTab, InsertDeleteFlags::ALL, aMarkData );
+ else
+ rDoc.DeleteAreaTab( aWorkRange, InsertDeleteFlags::ALL );
+ pUndoDoc->CopyToDocument(aWorkRange, InsertDeleteFlags::ALL, bMulti, rDoc, &aMarkData);
+ }
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else // only Redo
+ {
+ aMarkData.MarkToMulti();
+ rDoc.FillTabMarked( nSrcTab, aMarkData, nFlags, nFunction, bSkipEmpty, bAsLink );
+ aMarkData.MarkToSimple();
+ SetChangeTrack();
+ }
+
+ pDocShell->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Extras);
+ pDocShell->PostDataChanged();
+
+ // CellContentChanged comes with the selection
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( !aMarkData.GetTableSelect(nTab) )
+ pViewShell->SetTabNo( nSrcTab );
+
+ pViewShell->DoneBlockMode(); // causes problems otherwise since selection is on the wrong sheet.
+ }
+}
+
+void ScUndoFillTable::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoFillTable::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoFillTable::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->FillTab( nFlags, nFunction, bSkipEmpty, bAsLink );
+}
+
+bool ScUndoFillTable::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoSelectionAttr::ScUndoSelectionAttr( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti,
+ const ScPatternAttr* pNewApply,
+ const SvxBoxItem* pNewOuter, const SvxBoxInfoItem* pNewInner,
+ const ScRange* pRangeCover )
+ : ScSimpleUndo( pNewDocShell ),
+ aMarkData ( rMark ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ mpDataArray(new ScEditDataArray),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ bMulti ( bNewMulti )
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pApplyPattern = const_cast<ScPatternAttr*>(&pPool->Put( *pNewApply ));
+ pLineOuter = pNewOuter ? const_cast<SvxBoxItem*>( &pPool->Put( *pNewOuter ) ) : nullptr;
+ pLineInner = pNewInner ? const_cast<SvxBoxInfoItem*>( &pPool->Put( *pNewInner ) ) : nullptr;
+ aRangeCover = pRangeCover ? *pRangeCover : aRange;
+}
+
+ScUndoSelectionAttr::~ScUndoSelectionAttr()
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->Remove(*pApplyPattern);
+ if (pLineOuter)
+ pPool->Remove(*pLineOuter);
+ if (pLineInner)
+ pPool->Remove(*pLineInner);
+
+ pUndoDoc.reset();
+}
+
+OUString ScUndoSelectionAttr::GetComment() const
+{
+ //"Attribute" "/Lines"
+ return ScResId( pLineOuter ? STR_UNDO_SELATTRLINES : STR_UNDO_SELATTR );
+}
+
+ScEditDataArray* ScUndoSelectionAttr::GetDataArray()
+{
+ return mpDataArray.get();
+}
+
+void ScUndoSelectionAttr::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aEffRange( aRangeCover );
+ if ( rDoc.HasAttrib( aEffRange, HasAttrFlags::Merged ) ) // merged cells?
+ rDoc.ExtendMerge( aEffRange );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aEffRange );
+
+ ChangeEditData(bUndo);
+
+ if (bUndo) // only for Undo
+ {
+ ScRange aCopyRange = aRangeCover;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, rDoc, &aMarkData);
+ }
+ else // only for Redo
+ {
+ aMarkData.MarkToMulti();
+ rDoc.ApplySelectionPattern( *pApplyPattern, aMarkData );
+ aMarkData.MarkToSimple();
+
+ if (pLineOuter)
+ rDoc.ApplySelectionFrame(aMarkData, *pLineOuter, pLineInner);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aEffRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ ShowTable( aRange );
+}
+
+void ScUndoSelectionAttr::ChangeEditData( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const ScEditDataArray::Item* pItem = mpDataArray->First(); pItem; pItem = mpDataArray->Next())
+ {
+ ScAddress aPos(pItem->GetCol(), pItem->GetRow(), pItem->GetTab());
+ if (rDoc.GetCellType(aPos) != CELLTYPE_EDIT)
+ continue;
+
+ if (bUndo)
+ {
+ if (pItem->GetOldData())
+ rDoc.SetEditText(aPos, *pItem->GetOldData(), nullptr);
+ else
+ rDoc.SetEmptyCell(aPos);
+ }
+ else
+ {
+ if (pItem->GetNewData())
+ rDoc.SetEditText(aPos, *pItem->GetNewData(), nullptr);
+ else
+ rDoc.SetEmptyCell(aPos);
+ }
+ }
+}
+
+void ScUndoSelectionAttr::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoSelectionAttr::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoSelectionAttr::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ if (pLineOuter)
+ rViewShell.ApplyPatternLines(*pApplyPattern, *pLineOuter, pLineInner);
+ else
+ rViewShell.ApplySelectionPattern( *pApplyPattern );
+ }
+}
+
+bool ScUndoSelectionAttr::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScRange& rSourceArea,
+ ScDocumentUniquePtr pNewUndoDoc, const ScMarkData& rMark,
+ FillDir eNewFillDir, FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd,
+ double fNewStartValue, double fNewStepValue, double fNewMaxValue )
+ : ScBlockUndo( pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT ),
+ aSource ( rSourceArea ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ eFillDir ( eNewFillDir ),
+ eFillCmd ( eNewFillCmd ),
+ eFillDateCmd ( eNewFillDateCmd ),
+ fStartValue ( fNewStartValue ),
+ fStepValue ( fNewStepValue ),
+ fMaxValue ( fNewMaxValue )
+{
+ SetChangeTrack();
+}
+
+ScUndoAutoFill::~ScUndoAutoFill()
+{
+}
+
+OUString ScUndoAutoFill::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOFILL ); //"Fill"
+}
+
+void ScUndoAutoFill::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoAutoFill::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ ScRange aWorkRange = aBlockRange;
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+ rDoc.DeleteAreaTab( aWorkRange, InsertDeleteFlags::AUTOFILL );
+ pUndoDoc->CopyToDocument(aWorkRange, InsertDeleteFlags::AUTOFILL, false, rDoc);
+
+ // Actually we'd only need to broadcast the cells inserted during
+ // CopyToDocument(), as DeleteAreaTab() broadcasts deleted cells. For
+ // this we'd need to either record the span sets or let
+ // CopyToDocument() broadcast.
+ BroadcastChanges( aWorkRange);
+
+ rDoc.ExtendMerge( aWorkRange, true );
+ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid, nExtFlags );
+ }
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoAutoFill::Redo()
+{
+ BeginRedo();
+
+//! Select sheet
+
+ SCCOLROW nCount = 0;
+ switch (eFillDir)
+ {
+ case FILL_TO_BOTTOM:
+ nCount = aBlockRange.aEnd.Row() - aSource.aEnd.Row();
+ break;
+ case FILL_TO_RIGHT:
+ nCount = aBlockRange.aEnd.Col() - aSource.aEnd.Col();
+ break;
+ case FILL_TO_TOP:
+ nCount = aSource.aStart.Row() - aBlockRange.aStart.Row();
+ break;
+ case FILL_TO_LEFT:
+ nCount = aSource.aStart.Col() - aBlockRange.aStart.Col();
+ break;
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( fStartValue != MAXDOUBLE )
+ {
+ SCCOL nValX = (eFillDir == FILL_TO_LEFT) ? aSource.aEnd.Col() : aSource.aStart.Col();
+ SCROW nValY = (eFillDir == FILL_TO_TOP ) ? aSource.aEnd.Row() : aSource.aStart.Row();
+ SCTAB nTab = aSource.aStart.Tab();
+ rDoc.SetValue( nValX, nValY, nTab, fStartValue );
+ }
+ sal_uLong nProgCount;
+ if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
+ nProgCount = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
+ else
+ nProgCount = aSource.aEnd.Row() - aSource.aStart.Row() + 1;
+ nProgCount *= nCount;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aSource.aStart.Col(), aSource.aStart.Row(),
+ aSource.aEnd.Col(), aSource.aEnd.Row(), &aProgress,
+ aMarkData, nCount,
+ eFillDir, eFillCmd, eFillDateCmd,
+ fStepValue, fMaxValue );
+
+ SetChangeTrack();
+
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ EndRedo();
+}
+
+void ScUndoAutoFill::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ if (eFillCmd==FILL_SIMPLE)
+ rViewShell.FillSimple( eFillDir );
+ else
+ rViewShell.FillSeries( eFillDir, eFillCmd, eFillDateCmd,
+ fStartValue, fStepValue, fMaxValue );
+ }
+}
+
+bool ScUndoAutoFill::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoMerge::ScUndoMerge(ScDocShell* pNewDocShell, const ScCellMergeOption& rOption,
+ bool bMergeContents, ScDocumentUniquePtr pUndoDoc, std::unique_ptr<SdrUndoAction> pDrawUndo)
+ : ScSimpleUndo(pNewDocShell)
+ , maOption(rOption)
+ , mbMergeContents(bMergeContents)
+ , mxUndoDoc(std::move(pUndoDoc))
+ , mpDrawUndo(std::move(pDrawUndo))
+{
+}
+
+ScUndoMerge::~ScUndoMerge()
+{
+ mpDrawUndo.reset();
+}
+
+OUString ScUndoMerge::GetComment() const
+{
+ return ScResId( STR_UNDO_MERGE );
+}
+
+void ScUndoMerge::DoChange( bool bUndo ) const
+{
+ using ::std::set;
+
+ if (maOption.maTabs.empty())
+ // Nothing to do.
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScRange aCurRange = maOption.getSingleRange(ScDocShell::GetCurTab());
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aCurRange);
+
+ for (const SCTAB nTab : maOption.maTabs)
+ {
+ ScRange aRange = maOption.getSingleRange(nTab);
+
+ if (bUndo)
+ // remove merge (contents are copied back below from undo document)
+ rDoc.RemoveMerge( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab() );
+ else
+ {
+ // repeat merge, but do not remove note captions (will be done by drawing redo below)
+ rDoc.DoMerge( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ aRange.aStart.Tab(), false );
+
+ if (maOption.mbCenter)
+ {
+ rDoc.ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(),
+ SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY ) );
+ rDoc.ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(),
+ SvxVerJustifyItem( SvxCellVerJustify::Center, ATTR_VER_JUSTIFY ) );
+ }
+ }
+
+ // undo -> copy back deleted contents
+ if (bUndo && mxUndoDoc)
+ {
+ // If there are note captions to be deleted during Undo they were
+ // kept or moved during the merge and copied to the Undo document
+ // without cloning the caption. Forget the target area's caption
+ // pointer that is identical to the one in the Undo document
+ // instead of deleting it.
+ rDoc.DeleteAreaTab( aRange,
+ InsertDeleteFlags::CONTENTS | InsertDeleteFlags::NOCAPTIONS | InsertDeleteFlags::FORGETCAPTIONS );
+ mxUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, rDoc);
+ }
+
+ // redo -> merge contents again
+ else if (!bUndo && mbMergeContents)
+ {
+ rDoc.DoMergeContents( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ aRange.aStart.Tab() );
+ }
+
+ if (bUndo)
+ DoSdrUndoAction( mpDrawUndo.get(), &rDoc );
+ else
+ RedoSdrUndoAction( mpDrawUndo.get() );
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(nTab);
+ bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow, true);
+ }
+
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+
+ rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ }
+
+ ShowTable(aCurRange);
+}
+
+void ScUndoMerge::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoMerge::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoMerge::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ bool bCont = false;
+ rViewShell.MergeCells( false, bCont, false );
+ }
+}
+
+bool ScUndoMerge::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoFormat::ScUndoAutoFormat( ScDocShell* pNewDocShell,
+ const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc,
+ const ScMarkData& rMark, bool bNewSize, sal_uInt16 nNewFormatNo )
+ : ScBlockUndo( pNewDocShell, rRange, bNewSize ? SC_UNDO_MANUALHEIGHT : SC_UNDO_AUTOHEIGHT ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ aMarkData ( rMark ),
+ bSize ( bNewSize ),
+ nFormatNo ( nNewFormatNo )
+{
+}
+
+ScUndoAutoFormat::~ScUndoAutoFormat()
+{
+}
+
+OUString ScUndoAutoFormat::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOFORMAT ); //"Auto-Format"
+}
+
+void ScUndoAutoFormat::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
+ aMarkData, InsertDeleteFlags::ATTRIB );
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, false, rDoc, &aMarkData);
+
+ // cell heights and widths (InsertDeleteFlags::NONE)
+ if (bSize)
+ {
+ SCCOL nStartX = aBlockRange.aStart.Col();
+ SCROW nStartY = aBlockRange.aStart.Row();
+ SCTAB nStartZ = aBlockRange.aStart.Tab();
+ SCCOL nEndX = aBlockRange.aEnd.Col();
+ SCROW nEndY = aBlockRange.aEnd.Row();
+ SCTAB nEndZ = aBlockRange.aEnd.Tab();
+
+ pUndoDoc->CopyToDocument( nStartX, 0, 0, nEndX, rDoc.MaxRow(), nTabCount-1,
+ InsertDeleteFlags::NONE, false, rDoc, &aMarkData );
+ pUndoDoc->CopyToDocument( 0, nStartY, 0, rDoc.MaxCol(), nEndY, nTabCount-1,
+ InsertDeleteFlags::NONE, false, rDoc, &aMarkData );
+ pDocShell->PostPaint( 0, 0, nStartZ, rDoc.MaxCol(), rDoc.MaxRow(), nEndZ,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top, SC_PF_LINES );
+ }
+ else
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES );
+
+ EndUndo();
+}
+
+void ScUndoAutoFormat::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nStartX = aBlockRange.aStart.Col();
+ SCROW nStartY = aBlockRange.aStart.Row();
+ SCTAB nStartZ = aBlockRange.aStart.Tab();
+ SCCOL nEndX = aBlockRange.aEnd.Col();
+ SCROW nEndY = aBlockRange.aEnd.Row();
+ SCTAB nEndZ = aBlockRange.aEnd.Tab();
+
+ rDoc.AutoFormat( nStartX, nStartY, nEndX, nEndY, nFormatNo, aMarkData );
+
+ if (bSize)
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ Fraction aZoomX(1,1);
+ Fraction aZoomY = aZoomX;
+ double nPPTX,nPPTY;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ ScViewData& rData = pViewShell->GetViewData();
+ nPPTX = rData.GetPPTX();
+ nPPTY = rData.GetPPTY();
+ aZoomX = rData.GetZoomX();
+ aZoomY = rData.GetZoomY();
+ }
+ else
+ {
+ // Keep zoom at 100
+ nPPTX = ScGlobal::nScreenPPTX;
+ nPPTY = ScGlobal::nScreenPPTY;
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, pVirtDev);
+ for (SCTAB nTab=nStartZ; nTab<=nEndZ; nTab++)
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ aDestMark.SetMarkArea( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
+ aDestMark.MarkToMulti();
+
+ // as SC_SIZE_VISOPT
+ for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
+ {
+ CRFlags nOld = rDoc.GetRowFlags(nRow,nTab);
+ bool bHidden = rDoc.RowHidden(nRow, nTab);
+ if ( !bHidden && ( nOld & CRFlags::ManualSize ) )
+ rDoc.SetRowFlags( nRow, nTab, nOld & ~CRFlags::ManualSize );
+ }
+
+ bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartY, nEndY, nTab, true);
+
+ for (SCCOL nCol=nStartX; nCol<=nEndX; nCol++)
+ if (!rDoc.ColHidden(nCol, nTab))
+ {
+ sal_uInt16 nThisSize = STD_EXTRA_WIDTH + rDoc.GetOptimalColWidth( nCol, nTab,
+ pVirtDev, nPPTX, nPPTY, aZoomX, aZoomY, false/*bFormula*/,
+ &aDestMark );
+ rDoc.SetColWidth( nCol, nTab, nThisSize );
+ rDoc.ShowCol( nCol, nTab, true );
+ }
+
+ // tdf#76183: recalculate objects' positions
+ if (bChanged)
+ rDoc.SetDrawPageSize(nTab);
+ }
+
+ pDocShell->PostPaint( 0, 0, nStartZ,
+ rDoc.MaxCol(), rDoc.MaxRow(), nEndZ,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top, SC_PF_LINES);
+ }
+ else
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES );
+
+ EndRedo();
+}
+
+void ScUndoAutoFormat::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->AutoFormat( nFormatNo );
+}
+
+bool ScUndoAutoFormat::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoReplace::ScUndoReplace( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ const OUString& rNewUndoStr, ScDocumentUniquePtr pNewUndoDoc,
+ const SvxSearchItem* pItem )
+ : ScSimpleUndo( pNewDocShell ),
+ aCursorPos ( nCurX, nCurY, nCurZ ),
+ aMarkData ( rMark ),
+ aUndoStr ( rNewUndoStr ),
+ pUndoDoc ( std::move(pNewUndoDoc) )
+{
+ pSearchItem.reset( new SvxSearchItem( *pItem ) );
+ SetChangeTrack();
+}
+
+ScUndoReplace::~ScUndoReplace()
+{
+ pUndoDoc.reset();
+ pSearchItem.reset();
+}
+
+void ScUndoReplace::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( pUndoDoc )
+ { //! UndoDoc includes only the changed cells,
+ // that is why an Iterator can be used
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ }
+ else
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScChangeActionContent* pContent = new ScChangeActionContent(
+ ScRange( aCursorPos) );
+ ScCellValue aCell;
+ aCell.assign(rDoc, aCursorPos);
+ pContent->SetOldValue( aUndoStr, &rDoc );
+ pContent->SetNewValue(aCell, &rDoc);
+ pChangeTrack->Append( pContent );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+OUString ScUndoReplace::GetComment() const
+{
+ return ScResId( STR_UNDO_REPLACE ); // "Replace"
+}
+
+void ScUndoReplace::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ShowTable( aCursorPos.Tab() );
+
+ if (pUndoDoc) // only for ReplaceAll !!
+ {
+ OSL_ENSURE(pSearchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL,
+ "ScUndoReplace:: Wrong Mode");
+
+ SetViewMarkData( aMarkData );
+
+//! selected sheet
+//! select range ?
+
+ // Undo document has no row/column information, thus copy with
+ // bColRowFlags = FALSE to not destroy Outline groups
+
+ InsertDeleteFlags nUndoFlags = (pSearchItem->GetPattern()) ? InsertDeleteFlags::ATTRIB : InsertDeleteFlags::CONTENTS;
+ pUndoDoc->CopyToDocument( 0, 0, 0,
+ rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
+ nUndoFlags, false, rDoc, nullptr, false ); // without row flags
+ pDocShell->PostPaintGridAll();
+ }
+ else if (pSearchItem->GetPattern() &&
+ pSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
+ {
+ OUString aTempStr = pSearchItem->GetSearchString(); // toggle
+ pSearchItem->SetSearchString(pSearchItem->GetReplaceString());
+ pSearchItem->SetReplaceString(aTempStr);
+ rDoc.ReplaceStyle( *pSearchItem,
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
+ aMarkData);
+ pSearchItem->SetReplaceString(pSearchItem->GetSearchString());
+ pSearchItem->SetSearchString(aTempStr);
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ pDocShell->PostPaintGridAll();
+ }
+ else if (pSearchItem->GetCellType() == SvxSearchCellType::NOTE)
+ {
+ ScPostIt* pNote = rDoc.GetNote(aCursorPos);
+ OSL_ENSURE( pNote, "ScUndoReplace::Undo - cell does not contain a note" );
+ if (pNote)
+ pNote->SetText( aCursorPos, aUndoStr );
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ }
+ else
+ {
+ // aUndoStr may contain line breaks
+ if ( aUndoStr.indexOf('\n') != -1 )
+ {
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aUndoStr);
+ rDoc.SetEditText(aCursorPos, rEngine.CreateTextObject());
+ }
+ else
+ rDoc.SetString( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), aUndoStr );
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ pDocShell->PostPaintGridAll();
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoReplace::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ if (pUndoDoc)
+ {
+ if (pViewShell)
+ {
+ SetViewMarkData( aMarkData );
+
+ pViewShell->SearchAndReplace( pSearchItem.get(), false, true );
+ }
+ }
+ else if (pSearchItem->GetPattern() &&
+ pSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
+ {
+ rDoc.ReplaceStyle( *pSearchItem,
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
+ aMarkData);
+ pDocShell->PostPaintGridAll();
+ }
+ else
+ if (pViewShell)
+ pViewShell->SearchAndReplace( pSearchItem.get(), false, true );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoReplace::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SearchAndReplace( pSearchItem.get(), true, false );
+}
+
+bool ScUndoReplace::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// multi-operation (only simple blocks)
+ScUndoTabOp::ScUndoTabOp( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ, ScDocumentUniquePtr pNewUndoDoc,
+ const ScRefAddress& rFormulaCell,
+ const ScRefAddress& rFormulaEnd,
+ const ScRefAddress& rRowCell,
+ const ScRefAddress& rColCell,
+ ScTabOpParam::Mode eMode )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ theFormulaCell ( rFormulaCell ),
+ theFormulaEnd ( rFormulaEnd ),
+ theRowCell ( rRowCell ),
+ theColCell ( rColCell ),
+ meMode(eMode)
+{
+}
+
+ScUndoTabOp::~ScUndoTabOp()
+{
+}
+
+OUString ScUndoTabOp::GetComment() const
+{
+ return ScResId( STR_UNDO_TABOP ); // "Multiple operation"
+}
+
+void ScUndoTabOp::Undo()
+{
+ BeginUndo();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aRange );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aRange );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.DeleteAreaTab( aRange,InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ pUndoDoc->CopyToDocument( aRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc );
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid, nExtFlags );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ EndUndo();
+}
+
+void ScUndoTabOp::Redo()
+{
+ BeginRedo();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aRange );
+
+ ScTabOpParam aParam(theFormulaCell, theFormulaEnd, theRowCell, theColCell, meMode);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->TabOp( aParam, false);
+
+ EndRedo();
+}
+
+void ScUndoTabOp::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoTabOp::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoConversion::ScUndoConversion(
+ ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScDocumentUniquePtr pNewUndoDoc,
+ SCCOL nNewX, SCROW nNewY, SCTAB nNewZ, ScDocumentUniquePtr pNewRedoDoc,
+ const ScConversionParam& rConvParam ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ aCursorPos( nCurX, nCurY, nCurZ ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aNewCursorPos( nNewX, nNewY, nNewZ ),
+ pRedoDoc( std::move(pNewRedoDoc) ),
+ maConvParam( rConvParam )
+{
+ SetChangeTrack();
+}
+
+ScUndoConversion::~ScUndoConversion()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+}
+
+void ScUndoConversion::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( pUndoDoc )
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ else
+ {
+ OSL_FAIL( "ScUndoConversion::SetChangeTrack: no UndoDoc" );
+ nStartChangeAction = nEndChangeAction = 0;
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+OUString ScUndoConversion::GetComment() const
+{
+ OUString aText;
+ switch( maConvParam.GetType() )
+ {
+ case SC_CONVERSION_SPELLCHECK: aText = ScResId( STR_UNDO_SPELLING ); break;
+ case SC_CONVERSION_HANGULHANJA: aText = ScResId( STR_UNDO_HANGULHANJA ); break;
+ case SC_CONVERSION_CHINESE_TRANSL: aText = ScResId( STR_UNDO_CHINESE_TRANSLATION ); break;
+ default: OSL_FAIL( "ScUndoConversion::GetComment - unknown conversion type" );
+ }
+ return aText;
+}
+
+void ScUndoConversion::DoChange( ScDocument* pRefDoc, const ScAddress& rCursorPos )
+{
+ if (pRefDoc)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ShowTable( rCursorPos.Tab() );
+
+ SetViewMarkData( aMarkData );
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ // Undo/Redo-doc has only selected tables
+
+ bool bMulti = aMarkData.IsMultiMarked();
+ pRefDoc->CopyToDocument( 0, 0, 0,
+ rDoc.MaxCol(), rDoc.MaxRow(), nTabCount-1,
+ InsertDeleteFlags::CONTENTS, bMulti, rDoc, &aMarkData );
+
+ // Reset the spell checking results to re-check on paint, otherwise
+ // we show the previous spelling markers (or lack thereof on misspellings).
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ pViewData->GetActiveWin()->ResetAutoSpell();
+ pDocShell->PostPaintGridAll();
+ }
+ else
+ {
+ OSL_FAIL("no Un-/RedoDoc for Un-/RedoSpelling");
+ }
+}
+
+void ScUndoConversion::Undo()
+{
+ BeginUndo();
+ DoChange( pUndoDoc.get(), aCursorPos );
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoConversion::Redo()
+{
+ BeginRedo();
+ DoChange( pRedoDoc.get(), aNewCursorPos );
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoConversion::Repeat( SfxRepeatTarget& rTarget )
+{
+ if( auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
+ pViewTarget->GetViewShell()->DoSheetConversion( maConvParam );
+}
+
+bool ScUndoConversion::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRefConversion::ScUndoRefConversion( ScDocShell* pNewDocShell,
+ const ScRange& aMarkRange, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc, bool bNewMulti) :
+ScSimpleUndo( pNewDocShell ),
+aMarkData ( rMark ),
+pUndoDoc ( std::move(pNewUndoDoc) ),
+pRedoDoc ( std::move(pNewRedoDoc) ),
+aRange ( aMarkRange ),
+bMulti ( bNewMulti )
+{
+ assert(pUndoDoc && pRedoDoc);
+ SetChangeTrack();
+}
+
+ScUndoRefConversion::~ScUndoRefConversion()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+}
+
+OUString ScUndoRefConversion::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoRefConversion::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoRefConversion::DoChange( ScDocument* pRefDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ShowTable(aRange);
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aCopyRange = aRange;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pRefDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, rDoc, &aMarkData );
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoRefConversion::Undo()
+{
+ BeginUndo();
+ if (pUndoDoc)
+ DoChange(pUndoDoc.get());
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoRefConversion::Redo()
+{
+ BeginRedo();
+ if (pRedoDoc)
+ DoChange(pRedoDoc.get());
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoRefConversion::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DoRefConversion();
+}
+
+bool ScUndoRefConversion::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRefreshLink::ScUndoRefreshLink(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pNewUndoDoc)
+ : ScSimpleUndo(pNewDocShell)
+ , xUndoDoc(std::move(pNewUndoDoc))
+{
+}
+
+OUString ScUndoRefreshLink::GetComment() const
+{
+ return ScResId( STR_UNDO_UPDATELINK );
+}
+
+void ScUndoRefreshLink::Undo()
+{
+ BeginUndo();
+
+ bool bMakeRedo = !xRedoDoc;
+ if (bMakeRedo)
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+
+ bool bFirst = true;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (xUndoDoc->HasTable(nTab))
+ {
+ ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
+ if (bMakeRedo)
+ {
+ if (bFirst)
+ xRedoDoc->InitUndo(rDoc, nTab, nTab, true, true);
+ else
+ xRedoDoc->AddUndoTab(nTab, nTab, true, true);
+ bFirst = false;
+ rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL, false, *xRedoDoc);
+ xRedoDoc->SetLink(nTab,
+ rDoc.GetLinkMode(nTab),
+ rDoc.GetLinkDoc(nTab),
+ rDoc.GetLinkFlt(nTab),
+ rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab));
+ xRedoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
+ }
+
+ rDoc.DeleteAreaTab( aRange,InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, false, rDoc);
+ rDoc.SetLink(nTab, xUndoDoc->GetLinkMode(nTab), xUndoDoc->GetLinkDoc(nTab),
+ xUndoDoc->GetLinkFlt(nTab), xUndoDoc->GetLinkOpt(nTab),
+ xUndoDoc->GetLinkTab(nTab),
+ xUndoDoc->GetLinkRefreshDelay(nTab) );
+ rDoc.SetTabBgColor(nTab, xUndoDoc->GetTabBgColor(nTab));
+ }
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+
+ EndUndo();
+}
+
+void ScUndoRefreshLink::Redo()
+{
+ OSL_ENSURE(xRedoDoc, "No RedoDoc for ScUndoRefreshLink::Redo");
+
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (xRedoDoc->HasTable(nTab))
+ {
+ ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
+
+ rDoc.DeleteAreaTab( aRange, InsertDeleteFlags::ALL );
+ xRedoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, false, rDoc);
+ rDoc.SetLink(nTab,
+ xRedoDoc->GetLinkMode(nTab),
+ xRedoDoc->GetLinkDoc(nTab),
+ xRedoDoc->GetLinkFlt(nTab),
+ xRedoDoc->GetLinkOpt(nTab),
+ xRedoDoc->GetLinkTab(nTab),
+ xRedoDoc->GetLinkRefreshDelay(nTab) );
+ rDoc.SetTabBgColor(nTab, xRedoDoc->GetTabBgColor(nTab));
+ }
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+
+ EndUndo();
+}
+
+void ScUndoRefreshLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRefreshLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+static ScAreaLink* lcl_FindAreaLink( const sfx2::LinkManager* pLinkManager, std::u16string_view rDoc,
+ std::u16string_view rFlt, std::u16string_view rOpt,
+ std::u16string_view rSrc, const ScRange& rDest )
+{
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = pLinkManager->GetLinks().size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ if ( pAreaLink->IsEqual( rDoc, rFlt, rOpt, rSrc, rDest ) )
+ return pAreaLink;
+ }
+
+ OSL_FAIL("ScAreaLink not found");
+ return nullptr;
+}
+
+ScUndoInsertAreaLink::ScUndoInsertAreaLink( ScDocShell* pShell,
+ const OUString& rDoc,
+ const OUString& rFlt, const OUString& rOpt,
+ const OUString& rArea, const ScRange& rDestRange,
+ sal_uLong nRefresh )
+ : ScSimpleUndo ( pShell ),
+ aDocName ( rDoc ),
+ aFltName ( rFlt ),
+ aOptions ( rOpt ),
+ aAreaName ( rArea ),
+ aRange ( rDestRange ),
+ nRefreshDelay ( nRefresh )
+{
+}
+
+ScUndoInsertAreaLink::~ScUndoInsertAreaLink()
+{
+}
+
+OUString ScUndoInsertAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERTAREALINK );
+}
+
+void ScUndoInsertAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aDocName, aFltName, aOptions,
+ aAreaName, aRange );
+ if (pLink)
+ pLinkManager->Remove( pLink );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoInsertAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = new ScAreaLink( pDocShell, aDocName, aFltName, aOptions,
+ aAreaName, aRange.aStart, nRefreshDelay );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aRange );
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aDocName, &aFltName, &aAreaName );
+ pLink->Update();
+ pLink->SetInCreate( false );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoInsertAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoInsertAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoRemoveAreaLink::ScUndoRemoveAreaLink( ScDocShell* pShell,
+ const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
+ const OUString& rArea, const ScRange& rDestRange,
+ sal_uLong nRefresh )
+ : ScSimpleUndo ( pShell ),
+ aDocName ( rDoc ),
+ aFltName ( rFlt ),
+ aOptions ( rOpt ),
+ aAreaName ( rArea ),
+ aRange ( rDestRange ),
+ nRefreshDelay ( nRefresh )
+{
+}
+
+ScUndoRemoveAreaLink::~ScUndoRemoveAreaLink()
+{
+}
+
+OUString ScUndoRemoveAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVELINK ); //! own text ??
+}
+
+void ScUndoRemoveAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = new ScAreaLink( pDocShell, aDocName, aFltName, aOptions,
+ aAreaName, aRange.aStart, nRefreshDelay );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aRange );
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aDocName, &aFltName, &aAreaName );
+ pLink->Update();
+ pLink->SetInCreate( false );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoRemoveAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aDocName, aFltName, aOptions,
+ aAreaName, aRange );
+ if (pLink)
+ pLinkManager->Remove( pLink );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoRemoveAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRemoveAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoUpdateAreaLink::ScUndoUpdateAreaLink( ScDocShell* pShell,
+ const OUString& rOldD, const OUString& rOldF, const OUString& rOldO,
+ const OUString& rOldA, const ScRange& rOldR, sal_uLong nOldRD,
+ const OUString& rNewD, const OUString& rNewF, const OUString& rNewO,
+ const OUString& rNewA, const ScRange& rNewR, sal_uLong nNewRD,
+ ScDocumentUniquePtr pUndo, ScDocumentUniquePtr pRedo, bool bDoInsert )
+ : ScSimpleUndo( pShell ),
+ aOldDoc ( rOldD ),
+ aOldFlt ( rOldF ),
+ aOldOpt ( rOldO ),
+ aOldArea ( rOldA ),
+ aOldRange ( rOldR ),
+ aNewDoc ( rNewD ),
+ aNewFlt ( rNewF ),
+ aNewOpt ( rNewO ),
+ aNewArea ( rNewA ),
+ aNewRange ( rNewR ),
+ xUndoDoc ( std::move(pUndo) ),
+ xRedoDoc ( std::move(pRedo) ),
+ nOldRefresh ( nOldRD ),
+ nNewRefresh ( nNewRD ),
+ bWithInsert ( bDoInsert )
+{
+ OSL_ENSURE( aOldRange.aStart == aNewRange.aStart, "AreaLink moved ?" );
+}
+
+OUString ScUndoUpdateAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_UPDATELINK ); //! own text ??
+}
+
+void ScUndoUpdateAreaLink::DoChange( const bool bUndo ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nEndX = std::max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() );
+ SCROW nEndY = std::max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() );
+ SCTAB nEndZ = std::max( aOldRange.aEnd.Tab(), aNewRange.aEnd.Tab() ); //?
+
+ if ( bUndo )
+ {
+ if ( bWithInsert )
+ {
+ rDoc.FitBlock( aNewRange, aOldRange );
+ rDoc.DeleteAreaTab( aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xUndoDoc->UndoToDocument(aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ else
+ {
+ ScRange aCopyRange( aOldRange.aStart, ScAddress(nEndX,nEndY,nEndZ) );
+ rDoc.DeleteAreaTab( aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ }
+ else
+ {
+ if ( bWithInsert )
+ {
+ rDoc.FitBlock( aOldRange, aNewRange );
+ rDoc.DeleteAreaTab( aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ else
+ {
+ ScRange aCopyRange( aOldRange.aStart, ScAddress(nEndX,nEndY,nEndZ) );
+ rDoc.DeleteAreaTab( aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ }
+
+ ScRange aWorkRange( aNewRange.aStart, ScAddress( nEndX, nEndY, nEndZ ) );
+ rDoc.ExtendMerge( aWorkRange, true );
+
+ // Paint
+
+ if ( aNewRange.aEnd.Col() != aOldRange.aEnd.Col() )
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ if ( aNewRange.aEnd.Row() != aOldRange.aEnd.Row() )
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+
+ if ( !pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), aWorkRange.aStart.Tab() ) )
+ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid );
+
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoUpdateAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aNewDoc, aNewFlt, aNewOpt,
+ aNewArea, aNewRange );
+ if (pLink)
+ {
+ pLink->SetSource( aOldDoc, aOldFlt, aOldOpt, aOldArea ); // old data in Link
+ pLink->SetDestArea( aOldRange );
+ pLink->SetRefreshDelay( nOldRefresh );
+ }
+
+ DoChange(true);
+}
+
+void ScUndoUpdateAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aOldDoc, aOldFlt, aOldOpt,
+ aOldArea, aOldRange );
+ if (pLink)
+ {
+ pLink->SetSource( aNewDoc, aNewFlt, aNewOpt, aNewArea ); // new values in link
+ pLink->SetDestArea( aNewRange );
+ pLink->SetRefreshDelay( nNewRefresh );
+ }
+
+ DoChange(false);
+}
+
+void ScUndoUpdateAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoUpdateAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx
new file mode 100644
index 000000000..8323cd824
--- /dev/null
+++ b/sc/source/ui/undo/undocell.cxx
@@ -0,0 +1,1048 @@
+/* -*- 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 <undocell.hxx>
+
+#include <scitems.hxx>
+#include <editeng/editobj.hxx>
+#include <sfx2/app.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <document.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <formulacell.hxx>
+#include <target.hxx>
+#include <undoolk.hxx>
+#include <detdata.hxx>
+#include <stlpool.hxx>
+#include <printfun.hxx>
+#include <rangenam.hxx>
+#include <chgtrack.hxx>
+#include <stringutil.hxx>
+
+namespace HelperNotifyChanges
+{
+ static void NotifyIfChangesListeners(const ScDocShell& rDocShell, const ScAddress &rPos,
+ const ScUndoEnterData::ValuesType &rOldValues)
+ {
+ if (ScModelObj* pModelObj = getMustPropagateChangesModel(rDocShell))
+ {
+ ScRangeList aChangeRanges;
+
+ for (const auto & rOldValue : rOldValues)
+ {
+ aChangeRanges.push_back( ScRange(rPos.Col(), rPos.Row(), rOldValue.mnTab));
+ }
+
+ Notify(*pModelObj, aChangeRanges, "cell-change");
+ }
+ }
+}
+
+
+ScUndoCursorAttr::ScUndoCursorAttr( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScPatternAttr* pOldPat, const ScPatternAttr* pNewPat,
+ const ScPatternAttr* pApplyPat ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ pOldEditData( static_cast<EditTextObject*>(nullptr) ),
+ pNewEditData( static_cast<EditTextObject*>(nullptr) )
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pNewPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pNewPat ) );
+ pOldPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pOldPat ) );
+ pApplyPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pApplyPat ) );
+}
+
+ScUndoCursorAttr::~ScUndoCursorAttr()
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->Remove(*pNewPattern);
+ pPool->Remove(*pOldPattern);
+ pPool->Remove(*pApplyPattern);
+}
+
+OUString ScUndoCursorAttr::GetComment() const
+{
+ //! own text for automatic attribution
+ return ScResId( STR_UNDO_CURSORATTR ); // "Attribute"
+}
+
+void ScUndoCursorAttr::SetEditData( std::unique_ptr<EditTextObject> pOld, std::unique_ptr<EditTextObject> pNew )
+{
+ pOldEditData = std::move(pOld);
+ pNewEditData = std::move(pNew);
+}
+
+void ScUndoCursorAttr::DoChange( const ScPatternAttr* pWhichPattern, const std::unique_ptr<EditTextObject>& pEditData ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAddress aPos(nCol, nRow, nTab);
+ rDoc.SetPattern( nCol, nRow, nTab, *pWhichPattern );
+
+ if (rDoc.GetCellType(aPos) == CELLTYPE_EDIT && pEditData)
+ rDoc.SetEditText(aPos, *pEditData, nullptr);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+ pViewShell->AdjustBlockHeight();
+ }
+
+ const SfxItemSet& rApplySet = pApplyPattern->GetItemSet();
+ bool bPaintExt = ( rApplySet.GetItemState( ATTR_SHADOW ) != SfxItemState::DEFAULT ||
+ rApplySet.GetItemState( ATTR_CONDITIONAL ) != SfxItemState::DEFAULT );
+ bool bPaintRows = ( rApplySet.GetItemState( ATTR_HOR_JUSTIFY ) != SfxItemState::DEFAULT );
+
+ sal_uInt16 nFlags = SC_PF_TESTMERGE;
+ if (bPaintExt)
+ nFlags |= SC_PF_LINES;
+ if (bPaintRows)
+ nFlags |= SC_PF_WHOLEROWS;
+ pDocShell->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, nFlags );
+}
+
+void ScUndoCursorAttr::Undo()
+{
+ BeginUndo();
+ DoChange(pOldPattern, pOldEditData);
+ EndUndo();
+}
+
+void ScUndoCursorAttr::Redo()
+{
+ BeginRedo();
+ DoChange(pNewPattern, pNewEditData);
+ EndRedo();
+}
+
+void ScUndoCursorAttr::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->ApplySelectionPattern( *pApplyPattern );
+}
+
+bool ScUndoCursorAttr::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterData::Value::Value() : mnTab(-1), mbHasFormat(false), mnFormat(0) {}
+
+ScUndoEnterData::ScUndoEnterData(
+ ScDocShell* pNewDocShell, const ScAddress& rPos, ValuesType& rOldValues,
+ const OUString& rNewStr, std::unique_ptr<EditTextObject> pObj ) :
+ ScSimpleUndo( pNewDocShell ),
+ maNewString(rNewStr),
+ mpNewEditData(std::move(pObj)),
+ mnEndChangeAction(0),
+ maPos(rPos)
+{
+ maOldValues.swap(rOldValues);
+
+ SetChangeTrack();
+}
+
+OUString ScUndoEnterData::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoEnterData::DoChange() const
+{
+ // only when needed (old or new Edit cell, or Attribute)?
+ bool bHeightChanged = false;
+ for (const auto & i : maOldValues)
+ {
+ if (pDocShell->AdjustRowHeight(maPos.Row(), maPos.Row(), i.mnTab))
+ bHeightChanged = true;
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ if (comphelper::LibreOfficeKit::isActive() && bHeightChanged)
+ {
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, maPos.Tab());
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell, false /* bColumns */, true /* bRows */, true /* bSizes*/,
+ false /* bHidden */, false /* bFiltered */, false /* bGroups */, maPos.Tab());
+ }
+ pViewShell->SetTabNo(maPos.Tab());
+ pViewShell->MoveCursorAbs(maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false);
+ }
+
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoEnterData::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScAddress aPos(maPos);
+ for (const Value & rOldValue : maOldValues)
+ {
+ aPos.SetTab(rOldValue.mnTab);
+ sal_uLong nFormat = 0;
+ if (rOldValue.mbHasFormat)
+ nFormat = rOldValue.mnFormat;
+ pChangeTrack->AppendContent(aPos, rOldValue.maCell, nFormat);
+ }
+ if ( mnEndChangeAction > pChangeTrack->GetActionMax() )
+ mnEndChangeAction = 0; // nothing is appended
+ }
+ else
+ mnEndChangeAction = 0;
+}
+
+void ScUndoEnterData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const Value & rVal : maOldValues)
+ {
+ ScCellValue aNewCell;
+ aNewCell.assign(rVal.maCell, rDoc, ScCloneFlags::StartListening);
+ ScAddress aPos = maPos;
+ aPos.SetTab(rVal.mnTab);
+ aNewCell.release(rDoc, aPos);
+
+ if (rVal.mbHasFormat)
+ rDoc.ApplyAttr(maPos.Col(), maPos.Row(), rVal.mnTab,
+ SfxUInt32Item(ATTR_VALUE_FORMAT, rVal.mnFormat));
+ else
+ {
+ auto pPattern = std::make_unique<ScPatternAttr>(*rDoc.GetPattern(maPos.Col(), maPos.Row(), rVal.mnTab));
+ pPattern->GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
+ rDoc.SetPattern(maPos.Col(), maPos.Row(), rVal.mnTab, std::move(pPattern));
+ }
+ pDocShell->PostPaintCell(maPos.Col(), maPos.Row(), rVal.mnTab);
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ size_t nCount = maOldValues.size();
+ if ( pChangeTrack && mnEndChangeAction >= sal::static_int_cast<sal_uLong>(nCount) )
+ pChangeTrack->Undo( mnEndChangeAction - nCount + 1, mnEndChangeAction );
+
+ DoChange();
+ EndUndo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, maPos, maOldValues);
+}
+
+void ScUndoEnterData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const Value & rOldValue : maOldValues)
+ {
+ SCTAB nTab = rOldValue.mnTab;
+ if (mpNewEditData)
+ {
+ ScAddress aPos = maPos;
+ aPos.SetTab(nTab);
+ // edit text will be cloned.
+ rDoc.SetEditText(aPos, *mpNewEditData, nullptr);
+ }
+ else
+ rDoc.SetString(maPos.Col(), maPos.Row(), nTab, maNewString);
+
+ pDocShell->PostPaintCell(maPos.Col(), maPos.Row(), nTab);
+ }
+
+ SetChangeTrack();
+
+ DoChange();
+ EndRedo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, maPos, maOldValues);
+}
+
+void ScUndoEnterData::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ OUString aTemp = maNewString;
+ pViewTarget->GetViewShell()->EnterDataAtCursor( aTemp );
+ }
+}
+
+bool ScUndoEnterData::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterValue::ScUndoEnterValue(
+ ScDocShell* pNewDocShell, const ScAddress& rNewPos,
+ const ScCellValue& rUndoCell, double nVal ) :
+ ScSimpleUndo( pNewDocShell ),
+ aPos ( rNewPos ),
+ maOldCell(rUndoCell),
+ nValue ( nVal )
+{
+ SetChangeTrack();
+}
+
+ScUndoEnterValue::~ScUndoEnterValue()
+{
+}
+
+OUString ScUndoEnterValue::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoEnterValue::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendContent(aPos, maOldCell);
+ if ( nEndChangeAction > pChangeTrack->GetActionMax() )
+ nEndChangeAction = 0; // nothing is appended
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoEnterValue::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScCellValue aNewCell;
+ aNewCell.assign(maOldCell, rDoc, ScCloneFlags::StartListening);
+ aNewCell.release(rDoc, aPos);
+
+ pDocShell->PostPaintCell( aPos );
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoEnterValue::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SetValue( aPos.Col(), aPos.Row(), aPos.Tab(), nValue );
+ pDocShell->PostPaintCell( aPos );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoEnterValue::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoEnterValue::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoSetCell::ScUndoSetCell( ScDocShell* pDocSh, const ScAddress& rPos, const ScCellValue& rOldVal, const ScCellValue& rNewVal ) :
+ ScSimpleUndo(pDocSh), maPos(rPos), maOldValue(rOldVal), maNewValue(rNewVal), mnEndChangeAction(0)
+{
+ SetChangeTrack();
+}
+
+ScUndoSetCell::~ScUndoSetCell() {}
+
+void ScUndoSetCell::Undo()
+{
+ BeginUndo();
+ SetValue(maOldValue);
+ MoveCursorToCell();
+ pDocShell->PostPaintCell(maPos);
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if (pChangeTrack)
+ pChangeTrack->Undo(mnEndChangeAction, mnEndChangeAction);
+
+ EndUndo();
+}
+
+void ScUndoSetCell::Redo()
+{
+ BeginRedo();
+ SetValue(maNewValue);
+ MoveCursorToCell();
+ pDocShell->PostPaintCell(maPos);
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoSetCell::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+ // Makes no sense.
+}
+
+bool ScUndoSetCell::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoSetCell::GetComment() const
+{
+ return ScResId(STR_UNDO_ENTERDATA); // "Input"
+}
+
+void ScUndoSetCell::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if (pChangeTrack)
+ {
+ mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
+
+ pChangeTrack->AppendContent(maPos, maOldValue);
+
+ if (mnEndChangeAction > pChangeTrack->GetActionMax())
+ mnEndChangeAction = 0; // Nothing is appended
+ }
+ else
+ mnEndChangeAction = 0;
+}
+
+void ScUndoSetCell::SetValue( const ScCellValue& rVal )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ switch (rVal.meType)
+ {
+ case CELLTYPE_NONE:
+ // empty cell
+ rDoc.SetEmptyCell(maPos);
+ break;
+ case CELLTYPE_VALUE:
+ rDoc.SetValue(maPos, rVal.mfValue);
+ break;
+ case CELLTYPE_STRING:
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ // Undo only cell content, without setting any number format.
+ aParam.meSetTextNumFormat = ScSetStringParam::Keep;
+ rDoc.SetString(maPos, rVal.mpString->getString(), &aParam);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ rDoc.SetEditText(maPos, rVal.mpEditText->Clone());
+ break;
+ case CELLTYPE_FORMULA:
+ rDoc.SetFormulaCell(maPos, rVal.mpFormula->Clone());
+ break;
+ default:
+ ;
+ }
+}
+
+void ScUndoSetCell::MoveCursorToCell()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo( maPos.Tab() );
+ pViewShell->MoveCursorAbs( maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false );
+ }
+}
+
+ScUndoPageBreak::ScUndoPageBreak( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ bool bNewColumn, bool bNewInsert ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ bColumn( bNewColumn ),
+ bInsert( bNewInsert )
+{
+}
+
+ScUndoPageBreak::~ScUndoPageBreak()
+{
+}
+
+OUString ScUndoPageBreak::GetComment() const
+{
+ //"Column break" | "Row break" "insert" | "delete"
+ return bColumn ?
+ ( bInsert ?
+ ScResId( STR_UNDO_INSCOLBREAK ) :
+ ScResId( STR_UNDO_DELCOLBREAK )
+ ) :
+ ( bInsert ?
+ ScResId( STR_UNDO_INSROWBREAK ) :
+ ScResId( STR_UNDO_DELROWBREAK )
+ );
+}
+
+void ScUndoPageBreak::DoChange( bool bInsertP ) const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+
+ if (bInsertP)
+ pViewShell->InsertPageBreak(bColumn, false);
+ else
+ pViewShell->DeletePageBreak(bColumn, false);
+
+ pDocShell->GetDocument().InvalidatePageBreaks(nTab);
+ }
+}
+
+void ScUndoPageBreak::Undo()
+{
+ BeginUndo();
+ DoChange(!bInsert);
+ EndUndo();
+}
+
+void ScUndoPageBreak::Redo()
+{
+ BeginRedo();
+ DoChange(bInsert);
+ EndRedo();
+}
+
+void ScUndoPageBreak::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bInsert)
+ rViewShell.InsertPageBreak(bColumn);
+ else
+ rViewShell.DeletePageBreak(bColumn);
+ }
+}
+
+bool ScUndoPageBreak::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoPrintZoom::ScUndoPrintZoom( ScDocShell* pNewDocShell,
+ SCTAB nT, sal_uInt16 nOS, sal_uInt16 nOP, sal_uInt16 nNS, sal_uInt16 nNP ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nT ),
+ nOldScale( nOS ),
+ nOldPages( nOP ),
+ nNewScale( nNS ),
+ nNewPages( nNP )
+{
+}
+
+ScUndoPrintZoom::~ScUndoPrintZoom()
+{
+}
+
+OUString ScUndoPrintZoom::GetComment() const
+{
+ return ScResId( STR_UNDO_PRINTSCALE );
+}
+
+void ScUndoPrintZoom::DoChange( bool bUndo )
+{
+ sal_uInt16 nScale = bUndo ? nOldScale : nNewScale;
+ sal_uInt16 nPages = bUndo ? nOldPages : nNewPages;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString aStyleName = rDoc.GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) );
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) );
+
+ ScPrintFunc aPrintFunc( pDocShell, pDocShell->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+}
+
+void ScUndoPrintZoom::Undo()
+{
+ BeginUndo();
+ DoChange(true);
+ EndUndo();
+}
+
+void ScUndoPrintZoom::Redo()
+{
+ BeginRedo();
+ DoChange(false);
+ EndRedo();
+}
+
+void ScUndoPrintZoom::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ ScViewData& rViewData = rViewShell.GetViewData();
+ rViewData.GetDocShell()->SetPrintZoom( rViewData.GetTabNo(), nNewScale, nNewPages );
+ }
+}
+
+bool ScUndoPrintZoom::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoThesaurus::ScUndoThesaurus(
+ ScDocShell* pNewDocShell, SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScCellValue& rOldText, const ScCellValue& rNewText ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ maOldText(rOldText),
+ maNewText(rNewText)
+{
+ SetChangeTrack(maOldText);
+}
+
+ScUndoThesaurus::~ScUndoThesaurus() {}
+
+OUString ScUndoThesaurus::GetComment() const
+{
+ return ScResId( STR_UNDO_THESAURUS ); // "Thesaurus"
+}
+
+void ScUndoThesaurus::SetChangeTrack( const ScCellValue& rOldCell )
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendContent(ScAddress(nCol, nRow, nTab), rOldCell);
+ if ( nEndChangeAction > pChangeTrack->GetActionMax() )
+ nEndChangeAction = 0; // nothing is appended
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoThesaurus::DoChange( bool bUndo, const ScCellValue& rText )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+ }
+
+ ScAddress aPos(nCol, nRow, nTab);
+ rText.commit(rDoc, aPos);
+ if (!bUndo)
+ SetChangeTrack(maOldText);
+
+ pDocShell->PostPaintCell( nCol, nRow, nTab );
+}
+
+void ScUndoThesaurus::Undo()
+{
+ BeginUndo();
+ DoChange(true, maOldText);
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoThesaurus::Redo()
+{
+ BeginRedo();
+ DoChange(false, maNewText);
+ EndRedo();
+}
+
+void ScUndoThesaurus::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DoThesaurus();
+}
+
+bool ScUndoThesaurus::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+
+ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rPos,
+ const ScNoteData& rNoteData, bool bInsert, std::unique_ptr<SdrUndoAction> pDrawUndo ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ mpDrawUndo( std::move(pDrawUndo) )
+{
+ OSL_ENSURE( rNoteData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note caption" );
+ if (bInsert)
+ {
+ maNewData = rNoteData;
+ maNewData.mxCaption.setNotOwner();
+ }
+ else
+ {
+ maOldData = rNoteData;
+ maOldData.mxCaption.setNotOwner();
+ }
+}
+
+ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rPos,
+ const ScNoteData& rOldData, const ScNoteData& rNewData, std::unique_ptr<SdrUndoAction> pDrawUndo ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ maOldData( rOldData ),
+ maNewData( rNewData ),
+ mpDrawUndo( std::move(pDrawUndo) )
+{
+ OSL_ENSURE( maOldData.mxCaption || maNewData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note captions" );
+ OSL_ENSURE( !maOldData.mxInitData && !maNewData.mxInitData, "ScUndoReplaceNote::ScUndoReplaceNote - unexpected uninitialized note" );
+ maOldData.mxCaption.setNotOwner();
+ maNewData.mxCaption.setNotOwner();
+}
+
+ScUndoReplaceNote::~ScUndoReplaceNote()
+{
+ mpDrawUndo.reset();
+}
+
+void ScUndoReplaceNote::Undo()
+{
+ BeginUndo();
+ DoSdrUndoAction( mpDrawUndo.get(), &pDocShell->GetDocument() );
+ /* Undo insert -> remove new note.
+ Undo remove -> insert old note.
+ Undo replace -> remove new note, insert old note. */
+ DoRemoveNote( maNewData );
+ DoInsertNote( maOldData );
+ pDocShell->PostPaintCell( maPos );
+ EndUndo();
+}
+
+void ScUndoReplaceNote::Redo()
+{
+ BeginRedo();
+ RedoSdrUndoAction( mpDrawUndo.get() );
+ /* Redo insert -> insert new note.
+ Redo remove -> remove old note.
+ Redo replace -> remove old note, insert new note. */
+ DoRemoveNote( maOldData );
+ DoInsertNote( maNewData );
+ pDocShell->PostPaintCell( maPos );
+ EndRedo();
+}
+
+void ScUndoReplaceNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+}
+
+bool ScUndoReplaceNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoReplaceNote::GetComment() const
+{
+ return ScResId( maNewData.mxCaption ?
+ (maOldData.mxCaption ? STR_UNDO_EDITNOTE : STR_UNDO_INSERTNOTE) : STR_UNDO_DELETENOTE );
+}
+
+void ScUndoReplaceNote::DoInsertNote( const ScNoteData& rNoteData )
+{
+ if( rNoteData.mxCaption )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OSL_ENSURE( !rDoc.GetNote(maPos), "ScUndoReplaceNote::DoInsertNote - unexpected cell note" );
+ ScPostIt* pNote = new ScPostIt( rDoc, maPos, rNoteData, false );
+ rDoc.SetNote( maPos, std::unique_ptr<ScPostIt>(pNote) );
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, &rDoc, maPos, pNote);
+ }
+}
+
+void ScUndoReplaceNote::DoRemoveNote( const ScNoteData& rNoteData )
+{
+ if( !rNoteData.mxCaption )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OSL_ENSURE( rDoc.GetNote(maPos), "ScUndoReplaceNote::DoRemoveNote - missing cell note" );
+ if( std::unique_ptr<ScPostIt> pNote = rDoc.ReleaseNote( maPos ) )
+ {
+ /* Forget pointer to caption object to suppress removing the
+ caption object from the drawing layer while deleting pNote
+ (removing the caption is done by a drawing undo action). */
+ pNote->ForgetCaption();
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Remove, &rDoc, maPos, pNote.get());
+ }
+}
+
+ScUndoShowHideNote::ScUndoShowHideNote( ScDocShell& rDocShell, const ScAddress& rPos, bool bShow ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ mbShown( bShow )
+{
+}
+
+ScUndoShowHideNote::~ScUndoShowHideNote()
+{
+}
+
+void ScUndoShowHideNote::Undo()
+{
+ BeginUndo();
+ if( ScPostIt* pNote = pDocShell->GetDocument().GetNote(maPos) )
+ pNote->ShowCaption( maPos, !mbShown );
+ EndUndo();
+}
+
+void ScUndoShowHideNote::Redo()
+{
+ BeginRedo();
+ if( ScPostIt* pNote = pDocShell->GetDocument().GetNote(maPos) )
+ pNote->ShowCaption( maPos, mbShown );
+ EndRedo();
+}
+
+void ScUndoShowHideNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+}
+
+bool ScUndoShowHideNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoShowHideNote::GetComment() const
+{
+ return ScResId( mbShown ? STR_UNDO_SHOWNOTE : STR_UNDO_HIDENOTE );
+}
+
+ScUndoDetective::ScUndoDetective( ScDocShell* pNewDocShell,
+ std::unique_ptr<SdrUndoAction> pDraw, const ScDetOpData* pOperation,
+ std::unique_ptr<ScDetOpList> pUndoList ) :
+ ScSimpleUndo( pNewDocShell ),
+ pOldList ( std::move(pUndoList) ),
+ nAction ( 0 ),
+ pDrawUndo ( std::move(pDraw) )
+{
+ bIsDelete = ( pOperation == nullptr );
+ if (!bIsDelete)
+ {
+ nAction = static_cast<sal_uInt16>(pOperation->GetOperation());
+ aPos = pOperation->GetPos();
+ }
+}
+
+ScUndoDetective::~ScUndoDetective()
+{
+ pDrawUndo.reset();
+ pOldList.reset();
+}
+
+OUString ScUndoDetective::GetComment() const
+{
+ TranslateId pId = STR_UNDO_DETDELALL;
+ if ( !bIsDelete )
+ switch ( static_cast<ScDetOpType>(nAction) )
+ {
+ case SCDETOP_ADDSUCC: pId = STR_UNDO_DETADDSUCC; break;
+ case SCDETOP_DELSUCC: pId = STR_UNDO_DETDELSUCC; break;
+ case SCDETOP_ADDPRED: pId = STR_UNDO_DETADDPRED; break;
+ case SCDETOP_DELPRED: pId = STR_UNDO_DETDELPRED; break;
+ case SCDETOP_ADDERROR: pId = STR_UNDO_DETADDERROR; break;
+ }
+
+ return ScResId(pId);
+}
+
+void ScUndoDetective::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ DoSdrUndoAction(pDrawUndo.get(), &rDoc);
+
+ if (bIsDelete)
+ {
+ if ( pOldList )
+ rDoc.SetDetOpList( std::unique_ptr<ScDetOpList>(new ScDetOpList(*pOldList)) );
+ }
+ else
+ {
+ // Remove entry from list
+
+ ScDetOpList* pList = rDoc.GetDetOpList();
+ if (pList && pList->Count())
+ {
+ ScDetOpDataVector& rVec = pList->GetDataVector();
+ ScDetOpDataVector::iterator it = rVec.begin() + rVec.size() - 1;
+ if ( it->GetOperation() == static_cast<ScDetOpType>(nAction) && it->GetPos() == aPos )
+ rVec.erase( it);
+ else
+ {
+ OSL_FAIL("Detective entry could not be found in list");
+ }
+ }
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->RecalcPPT(); //! use broadcast instead?
+
+ EndUndo();
+}
+
+void ScUndoDetective::Redo()
+{
+ BeginRedo();
+
+ RedoSdrUndoAction(pDrawUndo.get());
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bIsDelete)
+ rDoc.ClearDetectiveOperations();
+ else
+ rDoc.AddDetectiveOperation( ScDetOpData( aPos, static_cast<ScDetOpType>(nAction) ) );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->RecalcPPT(); //! use broadcast instead?
+
+ EndRedo();
+}
+
+void ScUndoDetective::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoDetective::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoRangeNames::ScUndoRangeNames( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScRangeName> pOld, std::unique_ptr<ScRangeName> pNew, SCTAB nTab ) :
+ ScSimpleUndo( pNewDocShell ),
+ pOldRanges ( std::move(pOld) ),
+ pNewRanges ( std::move(pNew) ),
+ mnTab ( nTab )
+{
+}
+
+ScUndoRangeNames::~ScUndoRangeNames()
+{
+ pOldRanges.reset();
+ pNewRanges.reset();
+}
+
+OUString ScUndoRangeNames::GetComment() const
+{
+ return ScResId( STR_UNDO_RANGENAMES );
+}
+
+void ScUndoRangeNames::DoChange( bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.PreprocessRangeNameUpdate();
+
+ if ( bUndo )
+ {
+ auto p = std::make_unique<ScRangeName>(*pOldRanges);
+ if (mnTab >= 0)
+ rDoc.SetRangeName( mnTab, std::move(p) );
+ else
+ rDoc.SetRangeName( std::move(p) );
+ }
+ else
+ {
+ auto p = std::make_unique<ScRangeName>(*pNewRanges);
+ if (mnTab >= 0)
+ rDoc.SetRangeName( mnTab, std::move(p) );
+ else
+ rDoc.SetRangeName( std::move(p) );
+ }
+
+ rDoc.CompileHybridFormula();
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+}
+
+void ScUndoRangeNames::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoRangeNames::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoRangeNames::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRangeNames::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undocell2.cxx b/sc/source/ui/undo/undocell2.cxx
new file mode 100644
index 000000000..2222afa42
--- /dev/null
+++ b/sc/source/ui/undo/undocell2.cxx
@@ -0,0 +1,71 @@
+/* -*- 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/.
+ */
+
+#include <undocell.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <cellvalues.hxx>
+#include <formulacell.hxx>
+
+namespace sc {
+
+UndoSetCells::UndoSetCells( ScDocShell* pDocSh, const ScAddress& rTopPos ) :
+ ScSimpleUndo(pDocSh), maTopPos(rTopPos) {}
+
+UndoSetCells::~UndoSetCells() {}
+
+void UndoSetCells::DoChange( const CellValues& rValues )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.CopyCellValuesFrom(maTopPos, rValues);
+
+ ScRange aRange(maTopPos);
+ aRange.aEnd.IncRow(rValues.size());
+ BroadcastChanges(aRange);
+ pDocShell->PostPaintGridAll();
+}
+
+void UndoSetCells::Undo()
+{
+ BeginUndo();
+ DoChange(maOldValues);
+ EndUndo();
+}
+
+void UndoSetCells::Redo()
+{
+ BeginRedo();
+ DoChange(maNewValues);
+ EndRedo();
+}
+
+bool UndoSetCells::CanRepeat( SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+OUString UndoSetCells::GetComment() const
+{
+ // "Input"
+ return ScResId(STR_UNDO_ENTERDATA);
+}
+
+void UndoSetCells::SetNewValues( const std::vector<double>& rVals )
+{
+ maNewValues.assign(rVals);
+}
+
+void UndoSetCells::SetNewValues( const std::vector<ScFormulaCell*>& rVals )
+{
+ maNewValues.assign(rVals);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoconvert.cxx b/sc/source/ui/undo/undoconvert.cxx
new file mode 100644
index 000000000..ea9facfc2
--- /dev/null
+++ b/sc/source/ui/undo/undoconvert.cxx
@@ -0,0 +1,52 @@
+/* -*- 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/.
+ */
+
+#include <undoconvert.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <undoutil.hxx>
+
+namespace sc {
+
+UndoFormulaToValue::UndoFormulaToValue( ScDocShell* pDocSh, TableValues& rUndoValues ) :
+ ScSimpleUndo(pDocSh)
+{
+ maUndoValues.swap(rUndoValues);
+}
+
+OUString UndoFormulaToValue::GetComment() const
+{
+ return ScResId(STR_UNDO_FORMULA_TO_VALUE);
+}
+
+void UndoFormulaToValue::Undo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Redo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Execute()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SwapNonEmpty(maUndoValues);
+
+ ScUndoUtil::MarkSimpleBlock(pDocShell, maUndoValues.getRange());
+
+ pDocShell->PostPaint(maUndoValues.getRange(), PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+ rDoc.BroadcastCells(maUndoValues.getRange(), SfxHintId::ScDataChanged);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx
new file mode 100644
index 000000000..1ab89a8b5
--- /dev/null
+++ b/sc/source/ui/undo/undodat.cxx
@@ -0,0 +1,1925 @@
+/* -*- 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 <sfx2/app.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <undodat.hxx>
+#include <undoutil.hxx>
+#include <undoolk.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <olinetab.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <globalnames.hxx>
+#include <target.hxx>
+#include <dbdocfun.hxx>
+#include <olinefun.hxx>
+#include <dpobject.hxx>
+#include <attrib.hxx>
+#include <hints.hxx>
+#include <chgtrack.hxx>
+#include <refundo.hxx>
+#include <markdata.hxx>
+
+// Show or hide outline groups
+
+ScUndoDoOutline::ScUndoDoOutline( ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewColumns,
+ sal_uInt16 nNewLevel, sal_uInt16 nNewEntry, bool bNewShow ) :
+ ScSimpleUndo( pNewDocShell ),
+ nStart( nNewStart ),
+ nEnd( nNewEnd ),
+ nTab( nNewTab ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ bColumns( bNewColumns ),
+ nLevel( nNewLevel ),
+ nEntry( nNewEntry ),
+ bShow( bNewShow )
+{
+}
+
+ScUndoDoOutline::~ScUndoDoOutline()
+{
+}
+
+OUString ScUndoDoOutline::GetComment() const
+{ // Show outline" "Hide outline"
+ return bShow ?
+ ScResId( STR_UNDO_DOOUTLINE ) :
+ ScResId( STR_UNDO_REDOOUTLINE );
+}
+
+void ScUndoDoOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ // perform the inverse function
+
+ if (bShow)
+ pViewShell->HideOutline( bColumns, nLevel, nEntry, false, false );
+ else
+ pViewShell->ShowOutline( bColumns, nLevel, nEntry, false, false );
+
+ // Original column/row status
+ if (bColumns)
+ pUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ else
+ pUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, bColumns, !bColumns,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+ EndUndo();
+}
+
+void ScUndoDoOutline::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bShow)
+ pViewShell->ShowOutline( bColumns, nLevel, nEntry, false );
+ else
+ pViewShell->HideOutline( bColumns, nLevel, nEntry, false );
+
+ EndRedo();
+}
+
+void ScUndoDoOutline::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDoOutline::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible
+}
+
+/** Make or delete outline groups */
+ScUndoMakeOutline::ScUndoMakeOutline( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab, bool bNewColumns, bool bNewMake ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX, nStartY, nStartZ ),
+ aBlockEnd( nEndX, nEndY, nEndZ ),
+ pUndoTable( std::move(pNewUndoTab) ),
+ bColumns( bNewColumns ),
+ bMake( bNewMake )
+{
+}
+
+ScUndoMakeOutline::~ScUndoMakeOutline()
+{
+}
+
+OUString ScUndoMakeOutline::GetComment() const
+{ // "Grouping" "Undo grouping"
+ return bMake ?
+ ScResId( STR_UNDO_MAKEOUTLINE ) :
+ ScResId( STR_UNDO_REMAKEOUTLINE );
+}
+
+void ScUndoMakeOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+
+ rDoc.SetOutlineTable( nTab, pUndoTable.get() );
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation( pViewShell, bColumns ? COLUMN_HEADER : ROW_HEADER, nTab );
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColumns /* bColumns */, !bColumns /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+ EndUndo();
+}
+
+void ScUndoMakeOutline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+
+ if (bMake)
+ pViewShell->MakeOutline( bColumns, false );
+ else
+ pViewShell->RemoveOutline( bColumns, false );
+
+ pDocShell->PostPaint(0,0,aBlockStart.Tab(),rDoc.MaxCol(),rDoc.MaxRow(),aBlockEnd.Tab(),PaintPartFlags::Grid);
+
+ EndRedo();
+}
+
+void ScUndoMakeOutline::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bMake)
+ rViewShell.MakeOutline( bColumns );
+ else
+ rViewShell.RemoveOutline( bColumns );
+ }
+}
+
+bool ScUndoMakeOutline::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoOutlineLevel::ScUndoOutlineLevel( ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ bool bNewColumns, sal_uInt16 nNewLevel )
+ : ScSimpleUndo(pNewDocShell)
+ , nStart(nNewStart)
+ , nEnd(nNewEnd)
+ , nTab(nNewTab)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+ , bColumns(bNewColumns)
+ , nLevel(nNewLevel)
+{
+}
+
+OUString ScUndoOutlineLevel::GetComment() const
+{ // "Select outline level"
+ return ScResId( STR_UNDO_OUTLINELEVEL );
+}
+
+void ScUndoOutlineLevel::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // Original Outline table
+
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+
+ if (bColumns)
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ else
+ xUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, bColumns, !bColumns,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+ EndUndo();
+}
+
+void ScUndoOutlineLevel::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched on or off before this (#46952#) !!!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pViewShell->SelectLevel( bColumns, nLevel, false );
+
+ EndRedo();
+}
+
+void ScUndoOutlineLevel::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SelectLevel( bColumns, nLevel );
+}
+
+bool ScUndoOutlineLevel::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+/** show/hide outline over block marks */
+ScUndoOutlineBlock::ScUndoOutlineBlock( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab, bool bNewShow ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX, nStartY, nStartZ ),
+ aBlockEnd( nEndX, nEndY, nEndZ ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xUndoTable(std::move(pNewUndoTab)),
+ bShow( bNewShow )
+{
+}
+
+OUString ScUndoOutlineBlock::GetComment() const
+{ // "Show outline" "Hide outline"
+ return bShow ?
+ ScResId( STR_UNDO_DOOUTLINEBLK ) :
+ ScResId( STR_UNDO_REDOOUTLINEBLK );
+}
+
+void ScUndoOutlineBlock::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ SCCOLROW nStartCol = aBlockStart.Col();
+ SCCOLROW nEndCol = aBlockEnd.Col();
+ SCCOLROW nStartRow = aBlockStart.Row();
+ SCCOLROW nEndRow = aBlockEnd.Row();
+
+ if (!bShow)
+ { // Size of the hidden blocks
+ size_t nLevel;
+ xUndoTable->GetColArray().FindTouchedLevel(nStartCol, nEndCol, nLevel);
+ xUndoTable->GetColArray().ExtendBlock(nLevel, nStartCol, nEndCol);
+ xUndoTable->GetRowArray().FindTouchedLevel(nStartRow, nEndRow, nLevel);
+ xUndoTable->GetRowArray().ExtendBlock(nLevel, nStartRow, nEndRow);
+ }
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, true /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+
+ pViewShell->OnLOKShowHideColRow(/*columns: */ true, nStartCol - 1);
+ pViewShell->OnLOKShowHideColRow(/*columns: */ false, nStartRow - 1);
+
+ EndUndo();
+}
+
+void ScUndoOutlineBlock::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+ if (bShow)
+ pViewShell->ShowMarkedOutlines( false );
+ else
+ pViewShell->HideMarkedOutlines( false );
+
+ EndRedo();
+}
+
+void ScUndoOutlineBlock::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bShow)
+ rViewShell.ShowMarkedOutlines();
+ else
+ rViewShell.HideMarkedOutlines();
+ }
+}
+
+bool ScUndoOutlineBlock::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveAllOutlines::ScUndoRemoveAllOutlines(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab)
+ : ScSimpleUndo(pNewDocShell)
+ , aBlockStart(nStartX, nStartY, nStartZ)
+ , aBlockEnd(nEndX, nEndY, nEndZ)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+{
+}
+
+OUString ScUndoRemoveAllOutlines::GetComment() const
+{ // "Remove outlines"
+ return ScResId( STR_UNDO_REMOVEALLOTLNS );
+}
+
+void ScUndoRemoveAllOutlines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ SCCOL nStartCol = aBlockStart.Col();
+ SCCOL nEndCol = aBlockEnd.Col();
+ SCROW nStartRow = aBlockStart.Row();
+ SCROW nEndRow = aBlockEnd.Row();
+
+ xUndoDoc->CopyToDocument(nStartCol, 0, nTab, nEndCol, rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, BOTH_HEADERS, nTab);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ true /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+ EndUndo();
+}
+
+void ScUndoRemoveAllOutlines::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nTab = aBlockStart.Tab();
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pViewShell->RemoveAllOutlines( false );
+
+ EndRedo();
+}
+
+void ScUndoRemoveAllOutlines::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RemoveAllOutlines();
+}
+
+bool ScUndoRemoveAllOutlines::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoOutline::ScUndoAutoOutline(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab)
+ : ScSimpleUndo(pNewDocShell)
+ , aBlockStart(nStartX, nStartY, nStartZ)
+ , aBlockEnd(nEndX, nEndY, nEndZ)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+{
+}
+
+OUString ScUndoAutoOutline::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOOUTLINE );
+}
+
+void ScUndoAutoOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoDoc && xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ EndUndo();
+}
+
+void ScUndoAutoOutline::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTab = aBlockStart.Tab();
+ if (pViewShell)
+ {
+ // sheet has to be switched on or off before this (#46952#) !!!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+ }
+
+ ScRange aRange( aBlockStart.Col(), aBlockStart.Row(), nTab,
+ aBlockEnd.Col(), aBlockEnd.Row(), nTab );
+ ScOutlineDocFunc aFunc( *pDocShell );
+ aFunc.AutoOutline( aRange, false );
+
+ // Select in View
+ // If it was called with a multi selection,
+ // then this is now the enclosing range...
+
+ if (pViewShell)
+ pViewShell->MarkRange( aRange );
+
+ EndRedo();
+}
+
+void ScUndoAutoOutline::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->AutoOutline();
+}
+
+bool ScUndoAutoOutline::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoSubTotals::ScUndoSubTotals(ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScSubTotalParam& rNewParam, SCROW nNewEndY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB)
+ : ScDBFuncUndo(pNewDocShell, ScRange(rNewParam.nCol1, rNewParam.nRow1, nNewTab,
+ rNewParam.nCol2, rNewParam.nRow2, nNewTab))
+ , nTab(nNewTab)
+ , aParam(rNewParam)
+ , nNewEndRow(nNewEndY)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+ , xUndoRange(std::move(pNewUndoRange))
+ , xUndoDB(std::move(pNewUndoDB))
+{
+}
+
+OUString ScUndoSubTotals::GetComment() const
+{ // "Subtotals"
+ return ScResId( STR_UNDO_SUBTOTALS );
+}
+
+void ScUndoSubTotals::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (nNewEndRow > aParam.nRow2)
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aParam.nRow2+1, static_cast<SCSIZE>(nNewEndRow-aParam.nRow2) );
+ }
+ else if (nNewEndRow < aParam.nRow2)
+ {
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nNewEndRow+1, static_cast<SCSIZE>(aParam.nRow2-nNewEndRow) );
+ }
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ // Original data and references
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, 0, aParam.nRow1+1, nTab,
+ rDoc.MaxCol(), aParam.nRow2, nTab );
+
+ rDoc.DeleteAreaTab( 0,aParam.nRow1+1, rDoc.MaxCol(),aParam.nRow2, nTab, InsertDeleteFlags::ALL );
+
+ xUndoDoc->CopyToDocument(0, aParam.nRow1+1, nTab, rDoc.MaxCol(), aParam.nRow2, nTab,
+ InsertDeleteFlags::NONE, false, rDoc); // Flags
+ xUndoDoc->UndoToDocument(0, aParam.nRow1+1, nTab, rDoc.MaxCol(), aParam.nRow2, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aParam.nCol1,aParam.nRow1,nTab,
+ aParam.nCol2,aParam.nRow2,nTab );
+
+ if (xUndoRange)
+ rDoc.SetRangeName(std::unique_ptr<ScRangeName>(new ScRangeName(*xUndoRange)));
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB)), true);
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoSubTotals::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aParam.nCol1,aParam.nRow1,nTab,
+ aParam.nCol2,aParam.nRow2,nTab );
+ pViewShell->DoSubTotals( aParam, false );
+
+ EndRedo();
+}
+
+void ScUndoSubTotals::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoSubTotals::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible due to column numbers
+}
+
+ScUndoQuery::ScUndoQuery( ScDocShell* pNewDocShell, SCTAB nNewTab, const ScQueryParam& rParam,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScDBCollection> pNewUndoDB,
+ const ScRange* pOld, bool bSize, const ScRange* pAdvSrc ) :
+ ScDBFuncUndo( pNewDocShell, ScRange( rParam.nCol1, rParam.nRow1, nNewTab,
+ rParam.nCol2, rParam.nRow2, nNewTab ) ),
+ nTab( nNewTab ),
+ aQueryParam( rParam ),
+ xUndoDoc( std::move(pNewUndoDoc) ),
+ xUndoDB( std::move(pNewUndoDB) ),
+ bIsAdvanced( false ),
+ bDestArea( false ),
+ bDoSize( bSize )
+{
+ if ( pOld )
+ {
+ bDestArea = true;
+ aOldDest = *pOld;
+ }
+ if ( pAdvSrc )
+ {
+ bIsAdvanced = true;
+ aAdvSource = *pAdvSrc;
+ }
+
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoQuery::~ScUndoQuery()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoQuery::GetComment() const
+{ // "Filter";
+ return ScResId( STR_UNDO_QUERY );
+}
+
+void ScUndoQuery::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (ScTabViewShell::isAnyEditViewInRange(pViewShell, /*bColumns*/ false, aQueryParam.nRow1, aQueryParam.nRow2))
+ return;
+
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bCopy = !aQueryParam.bInplace;
+ SCCOL nDestEndCol = 0;
+ SCROW nDestEndRow = 0;
+ if (bCopy)
+ {
+ nDestEndCol = aQueryParam.nDestCol + ( aQueryParam.nCol2-aQueryParam.nCol1 );
+ nDestEndRow = aQueryParam.nDestRow + ( aQueryParam.nRow2-aQueryParam.nRow1 );
+
+ ScDBData* pData = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pData)
+ {
+ ScRange aNewDest;
+ pData->GetArea( aNewDest );
+ nDestEndCol = aNewDest.aEnd.Col();
+ nDestEndRow = aNewDest.aEnd.Row();
+ }
+
+ if ( bDoSize && bDestArea )
+ {
+ // aDestRange is the old range
+ rDoc.FitBlock( ScRange(
+ aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab ),
+ aOldDest );
+ }
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell,
+ aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab );
+ rDoc.DeleteAreaTab( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab, InsertDeleteFlags::ALL );
+
+ pViewShell->DoneBlockMode();
+
+ xUndoDoc->CopyToDocument(aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+ // Attributes are always copied (#49287#)
+
+ // rest of the old range
+ if ( bDestArea && !bDoSize )
+ {
+ rDoc.DeleteAreaTab( aOldDest, InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, rDoc);
+ }
+ }
+ else
+ xUndoDoc->CopyToDocument(0, aQueryParam.nRow1, nTab, rDoc.MaxCol(), aQueryParam.nRow2, nTab,
+ InsertDeleteFlags::NONE, false, rDoc);
+
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB )), true);
+
+ if (!bCopy)
+ {
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+ }
+
+ ScRange aDirtyRange( 0 , aQueryParam.nRow1, nTab,
+ rDoc.MaxCol(), aQueryParam.nRow2, nTab );
+ rDoc.SetDirty( aDirtyRange, true );
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+
+ // invalidate cache positions and update cursor and selection
+ pViewShell->OnLOKShowHideColRow(/*bColumns*/ false, aQueryParam.nRow1 - 1);
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+
+ // Paint
+
+ if (bCopy)
+ {
+ SCCOL nEndX = nDestEndCol;
+ SCROW nEndY = nDestEndRow;
+ if (bDestArea)
+ {
+ if ( aOldDest.aEnd.Col() > nEndX )
+ nEndX = aOldDest.aEnd.Col();
+ if ( aOldDest.aEnd.Row() > nEndY )
+ nEndY = aOldDest.aEnd.Row();
+ }
+ if (bDoSize)
+ nEndY = rDoc.MaxRow();
+ pDocShell->PostPaint( aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nEndX, nEndY, aQueryParam.nDestTab, PaintPartFlags::Grid );
+ }
+ else
+ pDocShell->PostPaint( 0, aQueryParam.nRow1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoQuery::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if ( bIsAdvanced )
+ pViewShell->Query( aQueryParam, &aAdvSource, false );
+ else
+ pViewShell->Query( aQueryParam, nullptr, false );
+
+ EndRedo();
+}
+
+void ScUndoQuery::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoQuery::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // does not work due to column numbers
+}
+
+// Show or hide AutoFilter buttons (doesn't include filter settings)
+
+ScUndoAutoFilter::ScUndoAutoFilter( ScDocShell* pNewDocShell, const ScRange& rRange,
+ const OUString& rName, bool bSet ) :
+ ScDBFuncUndo( pNewDocShell, rRange ),
+ aDBName( rName ),
+ bFilterSet( bSet )
+{
+}
+
+ScUndoAutoFilter::~ScUndoAutoFilter()
+{
+}
+
+OUString ScUndoAutoFilter::GetComment() const
+{
+ return ScResId( STR_UNDO_QUERY ); // same as ScUndoQuery
+}
+
+void ScUndoAutoFilter::DoChange( bool bUndo )
+{
+ bool bNewFilter = bUndo ? !bFilterSet : bFilterSet;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDBData* pDBData=nullptr;
+ if (aDBName == STR_DB_LOCAL_NONAME)
+ {
+ SCTAB nTab = aOriginalRange.aStart.Tab();
+ pDBData = rDoc.GetAnonymousDBData(nTab);
+ }
+ else
+ {
+ ScDBCollection* pColl = rDoc.GetDBCollection();
+ pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aDBName));
+ }
+
+ if ( !pDBData )
+ return;
+
+ pDBData->SetAutoFilter( bNewFilter );
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pDBData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+
+ if ( bNewFilter )
+ rDoc.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+ else
+ rDoc.RemoveFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+
+ pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
+}
+
+void ScUndoAutoFilter::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoAutoFilter::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoAutoFilter::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoAutoFilter::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// change database sections (dialog)
+ScUndoDBData::ScUndoDBData( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScDBCollection> pNewUndoColl,
+ std::unique_ptr<ScDBCollection> pNewRedoColl ) :
+ ScSimpleUndo( pNewDocShell ),
+ pUndoColl( std::move(pNewUndoColl) ),
+ pRedoColl( std::move(pNewRedoColl) )
+{
+}
+
+ScUndoDBData::~ScUndoDBData()
+{
+}
+
+OUString ScUndoDBData::GetComment() const
+{ // "Change database range";
+ return ScResId( STR_UNDO_DBDATA );
+}
+
+void ScUndoDBData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // Avoid unnecessary calculations
+ rDoc.PreprocessDBDataUpdate();
+ rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pUndoColl)), true );
+ rDoc.CompileHybridFormula();
+ rDoc.SetAutoCalc( bOldAutoCalc );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+
+ EndUndo();
+}
+
+void ScUndoDBData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // Avoid unnecessary calculations
+ rDoc.PreprocessDBDataUpdate();
+ rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pRedoColl)), true );
+ rDoc.CompileHybridFormula();
+ rDoc.SetAutoCalc( bOldAutoCalc );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+
+ EndRedo();
+}
+
+void ScUndoDBData::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDBData::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible
+}
+
+ScUndoImportData::ScUndoImportData( ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScImportParam& rParam, SCCOL nNewEndX, SCROW nNewEndY,
+ SCCOL nNewFormula,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScDBData> pNewUndoData, std::unique_ptr<ScDBData> pNewRedoData ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nNewTab ),
+ aImportParam( rParam ),
+ nEndCol( nNewEndX ),
+ nEndRow( nNewEndY ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xRedoDoc(std::move(pNewRedoDoc)),
+ xUndoDBData(std::move(pNewUndoData)),
+ xRedoDBData(std::move(pNewRedoData)),
+ nFormulaCols( nNewFormula ),
+ bRedoFilled( false )
+{
+ // redo doc doesn't contain imported data (but everything else)
+}
+
+OUString ScUndoImportData::GetComment() const
+{
+ return ScResId( STR_UNDO_IMPORTDATA );
+}
+
+void ScUndoImportData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab );
+
+ SCTAB nTable;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ ScDBData* pCurrentData = nullptr;
+ if (xUndoDBData && xRedoDBData)
+ {
+ xRedoDBData->GetArea( nTable, nCol1, nRow1, nCol2, nRow2 );
+ pCurrentData = ScUndoUtil::GetOldDBData(xRedoDBData.get(), &rDoc, nTab,
+ nCol1, nRow1, nCol2, nRow2);
+
+ if ( !bRedoFilled )
+ {
+ // read redo data from document at first undo
+ // imported data is deleted later anyway,
+ // so now delete each column after copying to save memory (#41216#)
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // outside of the loop
+ for (SCCOL nCopyCol = nCol1; nCopyCol <= nCol2; nCopyCol++)
+ {
+ rDoc.CopyToDocument(nCopyCol,nRow1,nTab, nCopyCol,nRow2,nTab,
+ InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE, false, *xRedoDoc);
+ rDoc.DeleteAreaTab(nCopyCol, nRow1, nCopyCol, nRow2, nTab, InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE);
+ }
+ rDoc.SetAutoCalc( bOldAutoCalc );
+ bRedoFilled = true;
+ }
+ }
+ bool bMoveCells = xUndoDBData && xRedoDBData &&
+ xRedoDBData->IsDoSize(); // the same in old and new
+ if (bMoveCells)
+ {
+ // Undo: first delete the new data, then FitBlock backwards
+
+ ScRange aOld, aNew;
+ xUndoDBData->GetArea(aOld);
+ xRedoDBData->GetArea(aNew);
+
+ rDoc.DeleteAreaTab( aNew.aStart.Col(), aNew.aStart.Row(),
+ aNew.aEnd.Col(), aNew.aEnd.Row(), nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ aOld.aEnd.SetCol( aOld.aEnd.Col() + nFormulaCols ); // FitBlock also for formulas
+ aNew.aEnd.SetCol( aNew.aEnd.Col() + nFormulaCols );
+ rDoc.FitBlock( aNew, aOld, false ); // backwards
+ }
+ else
+ rDoc.DeleteAreaTab( aImportParam.nCol1,aImportParam.nRow1,
+ nEndCol,nEndRow, nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ xUndoDoc->CopyToDocument(aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol+nFormulaCols,nEndRow,nTab,
+ InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+
+ if (pCurrentData)
+ {
+ *pCurrentData = *xUndoDBData;
+
+ xUndoDBData->GetArea(nTable, nCol1, nRow1, nCol2, nRow2);
+ ScUndoUtil::MarkSimpleBlock( pDocShell, nCol1, nRow1, nTable, nCol2, nRow2, nTable );
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bMoveCells)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+ else
+ pDocShell->PostPaint( aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoImportData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab );
+
+ SCTAB nTable;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ ScDBData* pCurrentData = nullptr;
+ if (xUndoDBData && xRedoDBData)
+ {
+ xUndoDBData->GetArea( nTable, nCol1, nRow1, nCol2, nRow2 );
+ pCurrentData = ScUndoUtil::GetOldDBData(xUndoDBData.get(), &rDoc, nTab,
+ nCol1, nRow1, nCol2, nRow2);
+ }
+ bool bMoveCells = xUndoDBData && xRedoDBData &&
+ xRedoDBData->IsDoSize(); // the same in old and new
+ if (bMoveCells)
+ {
+ // Redo: FitBlock, then delete data (needed for CopyToDocument)
+
+ ScRange aOld, aNew;
+ xUndoDBData->GetArea(aOld);
+ xRedoDBData->GetArea(aNew);
+
+ aOld.aEnd.SetCol( aOld.aEnd.Col() + nFormulaCols ); // FitBlock also for formulas
+ aNew.aEnd.SetCol( aNew.aEnd.Col() + nFormulaCols );
+ rDoc.FitBlock( aOld, aNew );
+
+ rDoc.DeleteAreaTab( aNew.aStart.Col(), aNew.aStart.Row(),
+ aNew.aEnd.Col(), aNew.aEnd.Row(), nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ xRedoDoc->CopyToDocument(aNew, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc); // including formulas
+ }
+ else
+ {
+ rDoc.DeleteAreaTab( aImportParam.nCol1,aImportParam.nRow1,
+ nEndCol,nEndRow, nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+
+ if (pCurrentData)
+ {
+ *pCurrentData = *xRedoDBData;
+
+ xRedoDBData->GetArea(nTable, nCol1, nRow1, nCol2, nRow2);
+ ScUndoUtil::MarkSimpleBlock( pDocShell, nCol1, nRow1, nTable, nCol2, nRow2, nTable );
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bMoveCells)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+ else
+ pDocShell->PostPaint( aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+
+ EndRedo();
+}
+
+void ScUndoImportData::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ SCTAB nDummy;
+ ScImportParam aNewParam(aImportParam);
+ ScDBData* pDBData = rViewShell.GetDBData();
+ pDBData->GetArea( nDummy, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+
+ rViewShell.ImportData( aNewParam );
+ }
+}
+
+bool ScUndoImportData::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ // Repeat only for import using a database range, then xUndoDBData is set
+
+ if (xUndoDBData)
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+ else
+ return false; // Address book
+}
+
+ScUndoRepeatDB::ScUndoRepeatDB( ScDocShell* pNewDocShell, SCTAB nNewTab,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ SCROW nResultEndRow, SCCOL nCurX, SCROW nCurY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB,
+ const ScRange* pOldQ, const ScRange* pNewQ ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX,nStartY,nNewTab ),
+ aBlockEnd( nEndX,nEndY,nNewTab ),
+ nNewEndRow( nResultEndRow ),
+ aCursorPos( nCurX,nCurY,nNewTab ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xUndoTable(std::move(pNewUndoTab)),
+ xUndoRange(std::move(pNewUndoRange)),
+ xUndoDB(std::move(pNewUndoDB)),
+ bQuerySize( false )
+{
+ if ( pOldQ && pNewQ )
+ {
+ aOldQuery = *pOldQ;
+ aNewQuery = *pNewQ;
+ bQuerySize = true;
+ }
+}
+
+OUString ScUndoRepeatDB::GetComment() const
+{
+ return ScResId( STR_UNDO_REPEATDB );
+}
+
+void ScUndoRepeatDB::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ if (bQuerySize)
+ {
+ rDoc.FitBlock( aNewQuery, aOldQuery, false );
+
+ if ( aNewQuery.aEnd.Col() == aOldQuery.aEnd.Col() )
+ {
+ SCCOL nFormulaCols = 0;
+ SCCOL nCol = aOldQuery.aEnd.Col() + 1;
+ SCROW nRow = aOldQuery.aStart.Row() + 1; // test the header
+ while ( nCol <= rDoc.MaxCol() &&
+ rDoc.GetCellType(ScAddress( nCol, nRow, nTab )) == CELLTYPE_FORMULA )
+ {
+ ++nCol;
+ ++nFormulaCols;
+ }
+
+ if ( nFormulaCols > 0 )
+ {
+ ScRange aOldForm = aOldQuery;
+ aOldForm.aStart.SetCol( aOldQuery.aEnd.Col() + 1 );
+ aOldForm.aEnd.SetCol( aOldQuery.aEnd.Col() + nFormulaCols );
+ ScRange aNewForm = aOldForm;
+ aNewForm.aEnd.SetRow( aNewQuery.aEnd.Row() );
+ rDoc.FitBlock( aNewForm, aOldForm, false );
+ }
+ }
+ }
+
+ // TODO Data from Filter in other range are still missing!
+
+ if (nNewEndRow > aBlockEnd.Row())
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aBlockEnd.Row()+1, static_cast<SCSIZE>(nNewEndRow-aBlockEnd.Row()) );
+ }
+ else if (nNewEndRow < aBlockEnd.Row())
+ {
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nNewEndRow+1, static_cast<SCSIZE>(nNewEndRow-aBlockEnd.Row()) );
+ }
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ // Original data and references
+ ScUndoUtil::MarkSimpleBlock( pDocShell, 0, aBlockStart.Row(), nTab,
+ rDoc.MaxCol(), aBlockEnd.Row(), nTab );
+ rDoc.DeleteAreaTab( 0, aBlockStart.Row(),
+ rDoc.MaxCol(), aBlockEnd.Row(), nTab, InsertDeleteFlags::ALL );
+
+ xUndoDoc->CopyToDocument(0, aBlockStart.Row(), nTab, rDoc.MaxCol(), aBlockEnd.Row(), nTab,
+ InsertDeleteFlags::NONE, false, rDoc); // Flags
+ xUndoDoc->UndoToDocument(0, aBlockStart.Row(), nTab, rDoc.MaxCol(), aBlockEnd.Row(), nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart.Col(),aBlockStart.Row(),nTab,
+ aBlockEnd.Col(),aBlockEnd.Row(),nTab );
+
+ if (xUndoRange)
+ rDoc.SetRangeName(std::unique_ptr<ScRangeName>(new ScRangeName(*xUndoRange)));
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB)), true);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoRepeatDB::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart.Col(),aBlockStart.Row(),nTab,
+ aBlockEnd.Col(),aBlockEnd.Row(),nTab );
+ pViewShell->SetCursor( aCursorPos.Col(), aCursorPos.Row() );
+
+ pViewShell->RepeatDB( false );
+
+ EndRedo();
+}
+
+void ScUndoRepeatDB::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RepeatDB();
+}
+
+bool ScUndoRepeatDB::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDataPilot::ScUndoDataPilot( ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pOldDoc, ScDocumentUniquePtr pNewDoc,
+ const ScDPObject* pOldObj, const ScDPObject* pNewObj, bool bMove )
+ : ScSimpleUndo(pNewDocShell)
+ , xOldUndoDoc(std::move(pOldDoc))
+ , xNewUndoDoc(std::move(pNewDoc))
+ , bAllowMove( bMove)
+{
+ if (pOldObj)
+ xOldDPObject.reset(new ScDPObject(*pOldObj));
+ if (pNewObj)
+ xNewDPObject.reset(new ScDPObject(*pNewObj));
+}
+
+OUString ScUndoDataPilot::GetComment() const
+{
+ TranslateId pResId;
+ if (xOldUndoDoc && xNewUndoDoc)
+ pResId = STR_UNDO_PIVOT_MODIFY;
+ else if (xNewUndoDoc)
+ pResId = STR_UNDO_PIVOT_NEW;
+ else
+ pResId = STR_UNDO_PIVOT_DELETE;
+
+ return ScResId(pResId);
+}
+
+void ScUndoDataPilot::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRange aOldRange;
+ ScRange aNewRange;
+
+ if (xNewDPObject && xNewUndoDoc)
+ {
+ aNewRange = xNewDPObject->GetOutRange();
+ rDoc.DeleteAreaTab( aNewRange, InsertDeleteFlags::ALL );
+ xNewUndoDoc->CopyToDocument(aNewRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+ if (xOldDPObject && xOldUndoDoc)
+ {
+ aOldRange = xOldDPObject->GetOutRange();
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xOldUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ // update objects in collection
+ if (xNewDPObject)
+ {
+ // find updated object
+ //! find by name!
+
+ ScDPObject* pDocObj = rDoc.GetDPAtCursor(
+ aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aStart.Tab() );
+ OSL_ENSURE(pDocObj, "DPObject not found");
+ if (pDocObj)
+ {
+ if (xOldDPObject)
+ {
+ // restore old settings
+ xOldDPObject->WriteSourceDataTo( *pDocObj );
+ ScDPSaveData* pData = xOldDPObject->GetSaveData();
+ if (pData)
+ pDocObj->SetSaveData(*pData);
+ pDocObj->SetOutRange(xOldDPObject->GetOutRange());
+ xOldDPObject->WriteTempDataTo( *pDocObj );
+ }
+ else
+ {
+ // delete inserted object
+ rDoc.GetDPCollection()->FreeTable(pDocObj);
+ }
+ }
+ }
+ else if (xOldDPObject)
+ {
+ // re-insert deleted object
+ rDoc.GetDPCollection()->InsertNewTable(std::make_unique<ScDPObject>(*xOldDPObject));
+ }
+
+ if (xNewUndoDoc)
+ pDocShell->PostPaint(aNewRange, PaintPartFlags::Grid, SC_PF_LINES);
+ if (xOldUndoDoc)
+ pDocShell->PostPaint(aOldRange, PaintPartFlags::Grid, SC_PF_LINES);
+ pDocShell->PostDataChanged();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ //! set current sheet
+ }
+
+ if (xNewDPObject)
+ {
+ // notify API objects
+ rDoc.BroadcastUno(ScDataPilotModifiedHint(xNewDPObject->GetName()));
+ }
+
+ EndUndo();
+}
+
+void ScUndoDataPilot::Redo()
+{
+ BeginRedo();
+
+ //! copy output data instead of repeating the change,
+ //! in case external data have changed!
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScDPObject* pSourceObj = nullptr;
+ if (xOldDPObject)
+ {
+ // find object to modify
+ //! find by name!
+
+ ScRange aOldRange = xOldDPObject->GetOutRange();
+ pSourceObj = rDoc.GetDPAtCursor(
+ aOldRange.aStart.Col(), aOldRange.aStart.Row(), aOldRange.aStart.Tab() );
+ OSL_ENSURE(pSourceObj, "DPObject not found");
+ }
+
+ ScDBDocFunc aFunc( *pDocShell );
+ aFunc.DataPilotUpdate(pSourceObj, xNewDPObject.get(), false, false, bAllowMove); // no new undo action
+
+ EndRedo();
+}
+
+void ScUndoDataPilot::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //! allow deletion
+}
+
+bool ScUndoDataPilot::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ //! allow deletion
+ return false;
+}
+
+ScUndoConsolidate::ScUndoConsolidate( ScDocShell* pNewDocShell, const ScArea& rArea,
+ const ScConsolidateParam& rPar, ScDocumentUniquePtr pNewUndoDoc,
+ bool bReference, SCROW nInsCount, std::unique_ptr<ScOutlineTable> pTab,
+ std::unique_ptr<ScDBData> pData )
+ : ScSimpleUndo(pNewDocShell)
+ , aDestArea(rArea)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , aParam(rPar)
+ , bInsRef(bReference)
+ , nInsertCount(nInsCount)
+ , xUndoTab(std::move(pTab))
+ , xUndoData(std::move(pData))
+{
+}
+
+OUString ScUndoConsolidate::GetComment() const
+{
+ return ScResId( STR_UNDO_CONSOLIDATE );
+}
+
+void ScUndoConsolidate::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = aDestArea.nTab;
+
+ ScRange aOldRange;
+ if (xUndoData)
+ xUndoData->GetArea(aOldRange);
+
+ if (bInsRef)
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aDestArea.nRowStart, nInsertCount );
+ rDoc.SetOutlineTable(nTab, xUndoTab.get());
+
+ // Row status
+ xUndoDoc->CopyToDocument(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ // Data and references
+ rDoc.DeleteAreaTab( 0,aDestArea.nRowStart, rDoc.MaxCol(),aDestArea.nRowEnd, nTab, InsertDeleteFlags::ALL );
+ xUndoDoc->UndoToDocument(0, aDestArea.nRowStart, nTab,
+ rDoc.MaxCol(), aDestArea.nRowEnd, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ // Original range
+ if (xUndoData)
+ {
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ pDocShell->PostPaint( 0,aDestArea.nRowStart,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Size );
+ }
+ else
+ {
+ rDoc.DeleteAreaTab( aDestArea.nColStart,aDestArea.nRowStart,
+ aDestArea.nColEnd,aDestArea.nRowEnd, nTab, InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aDestArea.nColStart, aDestArea.nRowStart, nTab,
+ aDestArea.nColEnd, aDestArea.nRowEnd, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ // Original range
+ if (xUndoData)
+ {
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ SCCOL nEndX = aDestArea.nColEnd;
+ SCROW nEndY = aDestArea.nRowEnd;
+ if (xUndoData)
+ {
+ if ( aOldRange.aEnd.Col() > nEndX )
+ nEndX = aOldRange.aEnd.Col();
+ if ( aOldRange.aEnd.Row() > nEndY )
+ nEndY = aOldRange.aEnd.Row();
+ }
+ pDocShell->PostPaint( aDestArea.nColStart, aDestArea.nRowStart, nTab,
+ nEndX, nEndY, nTab, PaintPartFlags::Grid );
+ }
+
+ // Adjust Database range again
+ if (xUndoData)
+ {
+ ScDBCollection* pColl = rDoc.GetDBCollection();
+ if (pColl)
+ {
+ ScDBData* pDocData = pColl->getNamedDBs().findByUpperName(xUndoData->GetUpperName());
+ if (pDocData)
+ *pDocData = *xUndoData;
+ }
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab != nTab )
+ pViewShell->SetTabNo( nTab );
+ }
+
+ EndUndo();
+}
+
+void ScUndoConsolidate::Redo()
+{
+ BeginRedo();
+
+ pDocShell->DoConsolidate( aParam, false );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab != aParam.nTab )
+ pViewShell->SetTabNo( aParam.nTab );
+ }
+
+ EndRedo();
+}
+
+void ScUndoConsolidate::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoConsolidate::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// Change source data of Chart
+void ScUndoChartData::Init()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ aOldRangeListRef = new ScRangeList;
+ rDoc.GetOldChartParameters( aChartName, *aOldRangeListRef, bOldColHeaders, bOldRowHeaders );
+}
+
+ScUndoChartData::ScUndoChartData( ScDocShell* pNewDocShell, const OUString& rName,
+ const ScRange& rNew, bool bColHdr, bool bRowHdr,
+ bool bAdd ) :
+ ScSimpleUndo( pNewDocShell ),
+ aChartName( rName ),
+ bOldColHeaders(false),
+ bOldRowHeaders(false),
+ bNewColHeaders( bColHdr ),
+ bNewRowHeaders( bRowHdr ),
+ bAddRange( bAdd )
+{
+ aNewRangeListRef = new ScRangeList;
+ aNewRangeListRef->push_back( rNew );
+
+ Init();
+}
+
+ScUndoChartData::ScUndoChartData( ScDocShell* pNewDocShell, const OUString& rName,
+ const ScRangeListRef& rNew, bool bColHdr, bool bRowHdr,
+ bool bAdd ) :
+ ScSimpleUndo( pNewDocShell ),
+ aChartName( rName ),
+ bOldColHeaders(false),
+ bOldRowHeaders(false),
+ aNewRangeListRef( rNew ),
+ bNewColHeaders( bColHdr ),
+ bNewRowHeaders( bRowHdr ),
+ bAddRange( bAdd )
+{
+ Init();
+}
+
+ScUndoChartData::~ScUndoChartData()
+{
+}
+
+OUString ScUndoChartData::GetComment() const
+{
+ return ScResId( STR_UNDO_CHARTDATA );
+}
+
+void ScUndoChartData::Undo()
+{
+ BeginUndo();
+
+ pDocShell->GetDocument().UpdateChartArea( aChartName, aOldRangeListRef,
+ bOldColHeaders, bOldRowHeaders, false );
+
+ EndUndo();
+}
+
+void ScUndoChartData::Redo()
+{
+ BeginRedo();
+
+ pDocShell->GetDocument().UpdateChartArea( aChartName, aNewRangeListRef,
+ bNewColHeaders, bNewRowHeaders, bAddRange );
+
+ EndRedo();
+}
+
+void ScUndoChartData::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoChartData::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoDataForm::ScUndoDataForm( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScRefUndoData> pRefData )
+ : ScBlockUndo(pNewDocShell, ScRange( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ), SC_UNDO_SIMPLE)
+ , mxMarkData(new ScMarkData(rMark))
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xRedoDoc(std::move(pNewRedoDoc))
+ , xRefUndoData(std::move(pRefData))
+ , bRedoFilled(false)
+{
+ // pFill1,pFill2,pFill3 are there so the ctor calls for simple paste (without cutting)
+ // don't have to be changed and branched for 641.
+ // They can be removed later.
+
+ if (!mxMarkData->IsMarked()) // no cell marked:
+ mxMarkData->SetMarkArea(aBlockRange); // mark paste block
+
+ if (xRefUndoData)
+ xRefUndoData->DeleteUnchanged(&pDocShell->GetDocument());
+}
+
+OUString ScUndoDataForm::GetComment() const
+{
+ return ScResId( STR_UNDO_PASTE );
+}
+
+void ScUndoDataForm::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ ShowTable( aBlockRange );
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDataForm::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 ScUndoDataForm::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoDataForm::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr);
+}
+
+void ScUndoDataForm::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // RefUndoData for redo is created before first undo
+ // (with DeleteUnchanged after the DoUndo call)
+ bool bCreateRedoData = (bUndo && xRefUndoData && !xRefRedoData);
+ if (bCreateRedoData)
+ xRefRedoData.reset(new ScRefUndoData(&rDoc));
+
+ ScRefUndoData* pWorkRefData = bUndo ? xRefUndoData.get() : xRefRedoData.get();
+
+ bool bPaintAll = false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( bUndo && !bRedoFilled )
+ {
+ if (!xRedoDoc)
+ {
+ bool bColInfo = ( aBlockRange.aStart.Row()==0 && aBlockRange.aEnd.Row()==rDoc.MaxRow() );
+ bool bRowInfo = ( aBlockRange.aStart.Col()==0 && aBlockRange.aEnd.Col()==rDoc.MaxCol() );
+
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ xRedoDoc->InitUndoSelected(rDoc, *mxMarkData, bColInfo, bRowInfo);
+ }
+ // read "redo" data from the document in the first undo
+ // all sheets - CopyToDocument skips those that don't exist in pRedoDoc
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::VALUE, false, *xRedoDoc);
+ bRedoFilled = true;
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aBlockRange );
+
+ for ( sal_uInt16 i=0; i <= ( aBlockRange.aEnd.Col() - aBlockRange.aStart.Col() ); i++ )
+ {
+ OUString aOldString = xUndoDoc->GetString(
+ aBlockRange.aStart.Col()+i, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab());
+ rDoc.SetString( aBlockRange.aStart.Col()+i , aBlockRange.aStart.Row() , aBlockRange.aStart.Tab() , aOldString );
+ }
+
+ if (pWorkRefData)
+ {
+ pWorkRefData->DoUndo( &rDoc, true ); // TRUE = bSetChartRangeLists for SetChartListenerCollection
+ if ( rDoc.RefreshAutoFilter( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), aBlockRange.aStart.Tab() ) )
+ bPaintAll = true;
+ }
+
+ if (bCreateRedoData && xRefRedoData)
+ xRefRedoData->DeleteUnchanged(&rDoc);
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( 0, 0 );
+ }
+
+ ScRange aDrawRange( aBlockRange );
+ rDoc.ExtendMerge( aDrawRange, true ); // only needed for single sheet (text/rtf etc.)
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ if (bPaintAll)
+ {
+ aDrawRange.aStart.SetCol(0);
+ aDrawRange.aStart.SetRow(0);
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
+/*A*/ if (pViewShell)
+ pViewShell->AdjustBlockHeight(false);
+ }
+ else
+ {
+ if ( aBlockRange.aStart.Row() == 0 && aBlockRange.aEnd.Row() == rDoc.MaxRow() ) // whole column
+ {
+ nPaint |= PaintPartFlags::Top;
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+ if ( aBlockRange.aStart.Col() == 0 && aBlockRange.aEnd.Col() == rDoc.MaxCol() ) // whole row
+ {
+ nPaint |= PaintPartFlags::Left;
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+/*A*/ if (pViewShell && pViewShell->AdjustBlockHeight(false))
+ {
+ aDrawRange.aStart.SetCol(0);
+ aDrawRange.aStart.SetRow(0);
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ pDocShell->UpdatePaintExt( nExtFlags, aDrawRange );
+ }
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+
+ pDocShell->PostPaint( aDrawRange, nPaint, nExtFlags );
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undodraw.cxx b/sc/source/ui/undo/undodraw.cxx
new file mode 100644
index 000000000..7204f1643
--- /dev/null
+++ b/sc/source/ui/undo/undodraw.cxx
@@ -0,0 +1,107 @@
+/* -*- 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 <undodraw.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+
+
+ScUndoDraw::ScUndoDraw( std::unique_ptr<SfxUndoAction> pUndo, ScDocShell* pDocSh ) :
+ pDrawUndo( std::move(pUndo) ),
+ pDocShell( pDocSh ),
+ mnViewShellId( -1 )
+{
+ if (ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell())
+ mnViewShellId = pViewShell->GetViewShellId();
+}
+
+ScUndoDraw::~ScUndoDraw()
+{
+}
+
+OUString ScUndoDraw::GetComment() const
+{
+ if (pDrawUndo)
+ return pDrawUndo->GetComment();
+ return OUString();
+}
+
+ViewShellId ScUndoDraw::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+OUString ScUndoDraw::GetRepeatComment(SfxRepeatTarget& rTarget) const
+{
+ if (pDrawUndo)
+ return pDrawUndo->GetRepeatComment(rTarget);
+ return OUString();
+}
+
+bool ScUndoDraw::Merge( SfxUndoAction* pNextAction )
+{
+ if (pDrawUndo)
+ return pDrawUndo->Merge(pNextAction);
+ else
+ return false;
+}
+
+void ScUndoDraw::UpdateSubShell()
+{
+ // #i26822# remove the draw shell if the selected object has been removed
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell();
+ if (pViewShell)
+ pViewShell->UpdateDrawShell();
+}
+
+void ScUndoDraw::Undo()
+{
+ if (pDrawUndo)
+ {
+ pDrawUndo->Undo();
+ pDocShell->SetDrawModified();
+ UpdateSubShell();
+ }
+}
+
+void ScUndoDraw::Redo()
+{
+ if (pDrawUndo)
+ {
+ pDrawUndo->Redo();
+ pDocShell->SetDrawModified();
+ UpdateSubShell();
+ }
+}
+
+void ScUndoDraw::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (pDrawUndo)
+ pDrawUndo->Repeat(rTarget);
+}
+
+bool ScUndoDraw::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (pDrawUndo)
+ return pDrawUndo->CanRepeat(rTarget);
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoolk.cxx b/sc/source/ui/undo/undoolk.cxx
new file mode 100644
index 000000000..519ae20a7
--- /dev/null
+++ b/sc/source/ui/undo/undoolk.cxx
@@ -0,0 +1,75 @@
+/* -*- 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 <svx/svdundo.hxx>
+
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <undoolk.hxx>
+
+std::unique_ptr<SdrUndoAction> GetSdrUndoAction(ScDocument* pDoc)
+{
+ ScDrawLayer* pLayer = pDoc->GetDrawLayer();
+ if (pLayer)
+ return pLayer->GetCalcUndo(); // must exist
+ else
+ return nullptr;
+}
+
+void DoSdrUndoAction(SdrUndoAction* pUndoAction, ScDocument* pDoc)
+{
+ if (pUndoAction)
+ pUndoAction->Undo();
+ else
+ {
+ // if no drawing layer existed when the action was created,
+ // but it was created after that, there is no draw undo action,
+ // and after undo there might be a drawing layer with a wrong page count.
+ // The drawing layer must have been empty in that case, so any missing
+ // pages can just be created now.
+
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SCTAB nTabCount = pDoc->GetTableCount();
+ SCTAB nPages = static_cast<SCTAB>(pDrawLayer->GetPageCount());
+ while (nPages < nTabCount)
+ {
+ pDrawLayer->ScAddPage(nPages);
+ ++nPages;
+ }
+ }
+ }
+}
+
+void RedoSdrUndoAction(SdrUndoAction* pUndoAction)
+{
+ // DoSdrUndoAction/RedoSdrUndoAction is called even if the pointer is null
+ if (pUndoAction)
+ pUndoAction->Redo();
+}
+
+void EnableDrawAdjust(ScDocument* pDoc, bool bEnable)
+{
+ ScDrawLayer* pLayer = pDoc->GetDrawLayer();
+ if (pLayer)
+ pLayer->EnableAdjust(bEnable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undorangename.cxx b/sc/source/ui/undo/undorangename.cxx
new file mode 100644
index 000000000..1b9efafae
--- /dev/null
+++ b/sc/source/ui/undo/undorangename.cxx
@@ -0,0 +1,136 @@
+/* -*- 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/.
+ */
+
+#include <undorangename.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <sfx2/app.hxx>
+
+#include <memory>
+#include <utility>
+
+using ::std::unique_ptr;
+
+ScUndoAllRangeNames::ScUndoAllRangeNames(
+ ScDocShell* pDocSh,
+ const std::map<OUString, ScRangeName*>& rOldNames,
+ const std::map<OUString, std::unique_ptr<ScRangeName>>& rNewNames)
+ : ScSimpleUndo(pDocSh)
+{
+ for (const auto& [rName, pRangeName] : rOldNames)
+ {
+ m_OldNames.insert(std::make_pair(rName, std::make_unique<ScRangeName>(*pRangeName)));
+ }
+
+ for (auto const& it : rNewNames)
+ {
+ m_NewNames.insert(std::make_pair(it.first, std::make_unique<ScRangeName>(*it.second)));
+ }
+}
+
+ScUndoAllRangeNames::~ScUndoAllRangeNames()
+{
+}
+
+void ScUndoAllRangeNames::Undo()
+{
+ DoChange(m_OldNames);
+}
+
+void ScUndoAllRangeNames::Redo()
+{
+ DoChange(m_NewNames);
+}
+
+void ScUndoAllRangeNames::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoAllRangeNames::CanRepeat(SfxRepeatTarget& /*rTarget*/) const
+{
+ return false;
+}
+
+OUString ScUndoAllRangeNames::GetComment() const
+{
+ return ScResId(STR_UNDO_RANGENAMES);
+}
+
+void ScUndoAllRangeNames::DoChange(const std::map<OUString, std::unique_ptr<ScRangeName>>& rNames)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.PreprocessAllRangeNamesUpdate(rNames);
+ rDoc.SetAllRangeNames(rNames);
+ rDoc.CompileHybridFormula();
+
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged));
+}
+
+ScUndoAddRangeData::ScUndoAddRangeData(ScDocShell* pDocSh, const ScRangeData* pRangeData, SCTAB nTab) :
+ ScSimpleUndo(pDocSh),
+ mpRangeData(new ScRangeData(*pRangeData)),
+ mnTab(nTab)
+{
+
+}
+
+ScUndoAddRangeData::~ScUndoAddRangeData()
+{
+}
+
+void ScUndoAddRangeData::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pRangeName = nullptr;
+ if (mnTab == -1)
+ {
+ pRangeName = rDoc.GetRangeName();
+ }
+ else
+ {
+ pRangeName = rDoc.GetRangeName( mnTab );
+ }
+ pRangeName->erase(*mpRangeData);
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+}
+
+void ScUndoAddRangeData::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pRangeName = nullptr;
+ if (mnTab == -1)
+ {
+ pRangeName = rDoc.GetRangeName();
+ }
+ else
+ {
+ pRangeName = rDoc.GetRangeName( mnTab );
+ }
+ pRangeName->insert(new ScRangeData(*mpRangeData));
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+}
+
+void ScUndoAddRangeData::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoAddRangeData::CanRepeat(SfxRepeatTarget& /*rTarget*/) const
+{
+ return false;
+}
+
+OUString ScUndoAddRangeData::GetComment() const
+{
+ return ScResId(STR_UNDO_RANGENAMES);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undosort.cxx b/sc/source/ui/undo/undosort.cxx
new file mode 100644
index 000000000..ed65c760e
--- /dev/null
+++ b/sc/source/ui/undo/undosort.cxx
@@ -0,0 +1,87 @@
+/* -*- 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/.
+ */
+
+#include <undosort.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <undoutil.hxx>
+
+namespace sc {
+
+UndoSort::UndoSort( ScDocShell* pDocSh, const ReorderParam& rParam ) :
+ ScSimpleUndo(pDocSh), maParam(rParam) {}
+
+OUString UndoSort::GetComment() const
+{
+ return ScResId(STR_UNDO_SORT);
+}
+
+void UndoSort::Undo()
+{
+ BeginUndo();
+ Execute(true);
+ EndUndo();
+}
+
+void UndoSort::Redo()
+{
+ BeginRedo();
+ Execute(false);
+ EndRedo();
+}
+
+void UndoSort::Execute( bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sc::ReorderParam aParam = maParam;
+ if (bUndo)
+ aParam.reverse();
+ rDoc.Reorder(aParam);
+
+ ScRange aOverallRange( maParam.maSortRange);
+ if (maParam.maDataAreaExtras.anyExtrasWanted())
+ {
+ aOverallRange.aStart.SetCol( maParam.maDataAreaExtras.mnStartCol);
+ aOverallRange.aStart.SetRow( maParam.maDataAreaExtras.mnStartRow);
+ aOverallRange.aEnd.SetCol( maParam.maDataAreaExtras.mnEndCol);
+ aOverallRange.aEnd.SetRow( maParam.maDataAreaExtras.mnEndRow);
+ }
+
+ if (maParam.mbHasHeaders)
+ {
+ ScRange aMarkRange( aOverallRange);
+ if (maParam.mbByRow)
+ {
+ if (aMarkRange.aStart.Row() > 0)
+ aMarkRange.aStart.IncRow(-1);
+ }
+ else
+ {
+ if (aMarkRange.aStart.Col() > 0)
+ aMarkRange.aStart.IncCol(-1);
+ }
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aMarkRange);
+ }
+ else
+ {
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aOverallRange);
+ }
+
+ rDoc.SetDirty(maParam.maSortRange, true);
+ if (!aParam.mbUpdateRefs)
+ rDoc.BroadcastCells(aParam.maSortRange, SfxHintId::ScDataChanged);
+
+ pDocShell->PostPaint(aOverallRange, PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undostyl.cxx b/sc/source/ui/undo/undostyl.cxx
new file mode 100644
index 000000000..b0c17277a
--- /dev/null
+++ b/sc/source/ui/undo/undostyl.cxx
@@ -0,0 +1,280 @@
+/* -*- 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 <svl/itemset.hxx>
+#include <vcl/virdev.hxx>
+#include <osl/diagnose.h>
+
+#include <undostyl.hxx>
+#include <docsh.hxx>
+#include <docpool.hxx>
+#include <stlpool.hxx>
+#include <printfun.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+// modify style (cell or page style)
+
+ScStyleSaveData::ScStyleSaveData()
+{
+}
+
+ScStyleSaveData::ScStyleSaveData( const ScStyleSaveData& rOther ) :
+ aName( rOther.aName ),
+ aParent( rOther.aParent )
+{
+ if (rOther.moItems)
+ moItems.emplace(*rOther.moItems);
+}
+
+ScStyleSaveData& ScStyleSaveData::operator=( const ScStyleSaveData& rOther )
+{
+ if (this != &rOther)
+ {
+ aName = rOther.aName;
+ aParent = rOther.aParent;
+ if (rOther.moItems)
+ moItems.emplace(*rOther.moItems);
+ else
+ moItems.reset();
+ }
+ return *this;
+}
+
+void ScStyleSaveData::InitFromStyle( const SfxStyleSheetBase* pSource )
+{
+ if ( pSource )
+ {
+ aName = pSource->GetName();
+ aParent = pSource->GetParent();
+ moItems.emplace(const_cast<SfxStyleSheetBase*>(pSource)->GetItemSet());
+ }
+ else
+ {
+ aName.clear();
+ aParent.clear();
+ moItems.reset();
+ }
+}
+
+ScUndoModifyStyle::ScUndoModifyStyle( ScDocShell* pDocSh, SfxStyleFamily eFam,
+ const ScStyleSaveData& rOld, const ScStyleSaveData& rNew ) :
+ ScSimpleUndo( pDocSh ),
+ eFamily( eFam ),
+ aOldData( rOld ),
+ aNewData( rNew )
+{
+}
+
+ScUndoModifyStyle::~ScUndoModifyStyle()
+{
+}
+
+OUString ScUndoModifyStyle::GetComment() const
+{
+ TranslateId pId = (eFamily == SfxStyleFamily::Para) ?
+ STR_UNDO_EDITCELLSTYLE :
+ STR_UNDO_EDITPAGESTYLE;
+ return ScResId(pId);
+}
+
+static void lcl_DocStyleChanged( ScDocument* pDoc, const SfxStyleSheetBase* pStyle, bool bRemoved )
+{
+ //! move to document or docshell
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ pDoc->StyleSheetChanged( pStyle, bRemoved, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->ForgetLastPattern();
+}
+
+void ScUndoModifyStyle::DoChange( ScDocShell* pDocSh, const OUString& rName,
+ SfxStyleFamily eStyleFamily, const ScStyleSaveData& rData )
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ const OUString& aNewName = rData.GetName();
+ bool bDelete = aNewName.isEmpty(); // no new name -> delete style
+ bool bNew = ( rName.isEmpty() && !bDelete ); // creating new style
+
+ SfxStyleSheetBase* pStyle = nullptr;
+ if ( !rName.isEmpty() )
+ {
+ // find old style to modify
+ pStyle = pStlPool->Find( rName, eStyleFamily );
+ OSL_ENSURE( pStyle, "style not found" );
+
+ if ( pStyle && !bDelete )
+ {
+ // set new name
+ pStyle->SetName( aNewName );
+ }
+ }
+ else if ( !bDelete )
+ {
+ // create style (with new name)
+ pStyle = &pStlPool->Make( aNewName, eStyleFamily, SfxStyleSearchBits::UserDefined );
+
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ rDoc.GetPool()->CellStyleCreated( aNewName, rDoc );
+ }
+
+ if ( pStyle )
+ {
+ if ( bDelete )
+ {
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ lcl_DocStyleChanged( &rDoc, pStyle, true ); // TRUE: remove usage of style
+ else
+ rDoc.RemovePageStyleInUse( rName );
+
+ // delete style
+ pStlPool->Remove( pStyle );
+ }
+ else
+ {
+ // modify style
+
+ const OUString& aNewParent = rData.GetParent();
+ if ( aNewParent != pStyle->GetParent() )
+ pStyle->SetParent( aNewParent );
+
+ SfxItemSet& rStyleSet = pStyle->GetItemSet();
+ const std::optional<SfxItemSet>& pNewSet = rData.GetItems();
+ OSL_ENSURE( pNewSet, "no ItemSet for style" );
+ if (pNewSet)
+ rStyleSet.Set( *pNewSet, false );
+
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ {
+ lcl_DocStyleChanged( &rDoc, pStyle, false ); // cell styles: row heights
+ }
+ else
+ {
+ // page styles
+
+ if ( bNew && aNewName != rName )
+ rDoc.RenamePageStyleInUse( rName, aNewName );
+
+ if (pNewSet)
+ rDoc.ModifyStyleSheet( *pStyle, *pNewSet );
+
+ pDocSh->PageStyleModified( aNewName, true );
+ }
+ }
+ }
+
+ pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+
+ //! undo/redo document modifications for deleted styles
+ //! undo/redo modifications of number formatter
+}
+
+void ScUndoModifyStyle::Undo()
+{
+ BeginUndo();
+ DoChange( pDocShell, aNewData.GetName(), eFamily, aOldData );
+ EndUndo();
+}
+
+void ScUndoModifyStyle::Redo()
+{
+ BeginRedo();
+ DoChange( pDocShell, aOldData.GetName(), eFamily, aNewData );
+ EndRedo();
+}
+
+void ScUndoModifyStyle::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoModifyStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // no repeat possible
+}
+
+// apply page style
+
+ScUndoApplyPageStyle::ApplyStyleEntry::ApplyStyleEntry( SCTAB nTab, const OUString& rOldStyle ) :
+ mnTab( nTab ),
+ maOldStyle( rOldStyle )
+{
+}
+
+ScUndoApplyPageStyle::ScUndoApplyPageStyle( ScDocShell* pDocSh, const OUString& rNewStyle ) :
+ ScSimpleUndo( pDocSh ),
+ maNewStyle( rNewStyle )
+{
+}
+
+ScUndoApplyPageStyle::~ScUndoApplyPageStyle()
+{
+}
+
+void ScUndoApplyPageStyle::AddSheetAction( SCTAB nTab, const OUString& rOldStyle )
+{
+ maEntries.emplace_back( nTab, rOldStyle );
+}
+
+OUString ScUndoApplyPageStyle::GetComment() const
+{
+ return ScResId( STR_UNDO_APPLYPAGESTYLE );
+}
+
+void ScUndoApplyPageStyle::Undo()
+{
+ BeginUndo();
+ for( const auto& rEntry : maEntries )
+ {
+ pDocShell->GetDocument().SetPageStyle( rEntry.mnTab, rEntry.maOldStyle );
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), rEntry.mnTab ).UpdatePages();
+ }
+ EndUndo();
+}
+
+void ScUndoApplyPageStyle::Redo()
+{
+ BeginRedo();
+ for( const auto& rEntry : maEntries )
+ {
+ pDocShell->GetDocument().SetPageStyle( rEntry.mnTab, maNewStyle );
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), rEntry.mnTab ).UpdatePages();
+ }
+ EndRedo();
+}
+
+void ScUndoApplyPageStyle::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //! set same page style to current tab
+}
+
+bool ScUndoApplyPageStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undotab.cxx b/sc/source/ui/undo/undotab.cxx
new file mode 100644
index 000000000..bf9379e78
--- /dev/null
+++ b/sc/source/ui/undo/undotab.cxx
@@ -0,0 +1,1570 @@
+/* -*- 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 <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/hint.hxx>
+#include <osl/diagnose.h>
+
+#include <undotab.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <undoolk.hxx>
+#include <target.hxx>
+#include <uiitems.hxx>
+#include <prnsave.hxx>
+#include <printfun.hxx>
+#include <chgtrack.hxx>
+#include <tabprotection.hxx>
+#include <viewdata.hxx>
+#include <progress.hxx>
+#include <markdata.hxx>
+#include <refundo.hxx>
+
+// for ScUndoRenameObject - might me moved to another file later
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <drwlayer.hxx>
+#include <scresid.hxx>
+#include <sheetevents.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::unique_ptr;
+using ::std::vector;
+
+
+ScUndoInsertTab::ScUndoInsertTab( ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ bool bApp,
+ const OUString& rNewName) :
+ ScSimpleUndo( pNewDocShell ),
+ sNewName( rNewName ),
+ nTab( nTabNum ),
+ bAppend( bApp )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+ SetChangeTrack();
+}
+
+ScUndoInsertTab::~ScUndoInsertTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoInsertTab::GetComment() const
+{
+ if (bAppend)
+ return ScResId( STR_UNDO_APPEND_TAB );
+ else
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoInsertTab::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab );
+ pChangeTrack->AppendInsert( aRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoInsertTab::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo(nTab);
+
+ pDocShell->SetInUndo( true ); //! BeginUndo
+ bDrawIsInUndo = true;
+ pViewShell->DeleteTable( nTab, false );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndUndo
+
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoInsertTab::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ if (bAppend)
+ pViewShell->AppendTable( sNewName, false );
+ else
+ {
+ pViewShell->SetTabNo(nTab);
+ pViewShell->InsertTable( sNewName, nTab, false );
+ }
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndRedo
+
+ SetChangeTrack();
+}
+
+void ScUndoInsertTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoInsertTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoInsertTables::ScUndoInsertTables( ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ std::vector<OUString>&& newNameList) :
+ ScSimpleUndo( pNewDocShell ),
+ aNameList( std::move(newNameList) ),
+ nTab( nTabNum )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ SetChangeTrack();
+}
+
+ScUndoInsertTables::~ScUndoInsertTables()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoInsertTables::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoInsertTables::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ nEndChangeAction = 0;
+ ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab );
+ for( size_t i = 0; i < aNameList.size(); i++ )
+ {
+ aRange.aStart.SetTab( sal::static_int_cast<SCTAB>( nTab + i ) );
+ aRange.aEnd.SetTab( sal::static_int_cast<SCTAB>( nTab + i ) );
+ pChangeTrack->AppendInsert( aRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoInsertTables::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo(nTab);
+
+ pDocShell->SetInUndo( true ); //! BeginUndo
+ bDrawIsInUndo = true;
+
+ pViewShell->DeleteTables( nTab, static_cast<SCTAB>(aNameList.size()) );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndUndo
+
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoInsertTables::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ pViewShell->InsertTables( aNameList, nTab, static_cast<SCTAB>(aNameList.size()),false );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndRedo
+
+ SetChangeTrack();
+}
+
+void ScUndoInsertTables::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoInsertTables::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDeleteTab::ScUndoDeleteTab( ScDocShell* pNewDocShell, const vector<SCTAB> &aTab,
+ ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) )
+{
+ theTabs.insert(theTabs.end(), aTab.begin(), aTab.end() );
+ SetChangeTrack();
+}
+
+ScUndoDeleteTab::~ScUndoDeleteTab()
+{
+ theTabs.clear();
+}
+
+OUString ScUndoDeleteTab::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETE_TAB );
+}
+
+void ScUndoDeleteTab::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ sal_uLong nTmpChangeAction;
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ nEndChangeAction = 0;
+ ScRange aRange( 0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), 0 );
+ for ( size_t i = 0; i < theTabs.size(); ++i )
+ {
+ aRange.aStart.SetTab( theTabs[i] );
+ aRange.aEnd.SetTab( theTabs[i] );
+ pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
+ nTmpChangeAction, nEndChangeAction, static_cast<short>(i) );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+static SCTAB lcl_GetVisibleTabBefore( const ScDocument& rDoc, SCTAB nTab )
+{
+ while ( nTab > 0 && !rDoc.IsVisible( nTab ) )
+ --nTab;
+
+ return nTab;
+}
+
+void ScUndoDeleteTab::Undo()
+{
+ BeginUndo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bLink = false;
+ OUString aName;
+
+ for(SCTAB nTab: theTabs)
+ {
+ pRefUndoDoc->GetName( nTab, aName );
+
+ bDrawIsInUndo = true;
+ bool bOk = rDoc.InsertTab(nTab, aName, false, true);
+ bDrawIsInUndo = false;
+ if (bOk)
+ {
+ pRefUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::ALL,false, rDoc);
+
+ OUString aOldName;
+ pRefUndoDoc->GetName( nTab, aOldName );
+ rDoc.RenameTab( nTab, aOldName );
+ if (pRefUndoDoc->IsLinked(nTab))
+ {
+ rDoc.SetLink( nTab, pRefUndoDoc->GetLinkMode(nTab), pRefUndoDoc->GetLinkDoc(nTab),
+ pRefUndoDoc->GetLinkFlt(nTab), pRefUndoDoc->GetLinkOpt(nTab),
+ pRefUndoDoc->GetLinkTab(nTab), pRefUndoDoc->GetLinkRefreshDelay(nTab) );
+ bLink = true;
+ }
+
+ if ( pRefUndoDoc->IsScenario(nTab) )
+ {
+ rDoc.SetScenario( nTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ pRefUndoDoc->GetScenarioData( nTab, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData( nTab, aComment, aColor, nScenFlags );
+ bool bActive = pRefUndoDoc->IsActiveScenario( nTab );
+ rDoc.SetActiveScenario( nTab, bActive );
+ }
+ rDoc.SetVisible( nTab, pRefUndoDoc->IsVisible( nTab ) );
+ rDoc.SetTabBgColor( nTab, pRefUndoDoc->GetTabBgColor(nTab) );
+ auto pSheetEvents = pRefUndoDoc->GetSheetEvents( nTab );
+ rDoc.SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
+ rDoc.SetLayoutRTL( nTab, pRefUndoDoc->IsLayoutRTL( nTab ) );
+
+ if ( pRefUndoDoc->IsTabProtected( nTab ) )
+ rDoc.SetTabProtection(nTab, pRefUndoDoc->GetTabProtection(nTab));
+ }
+ }
+ if (bLink)
+ {
+ pDocShell->UpdateLinks(); // update Link Manager
+ }
+
+ EndUndo(); // Draw-Undo has to be called before Broadcast!
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ for(SCTAB nTab: theTabs)
+ {
+ pDocShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab) );
+ }
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ pDocShell->PostPaint(0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All ); // incl. extras
+
+ // not ShowTable due to SetTabNo(..., sal_True):
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( lcl_GetVisibleTabBefore( rDoc, theTabs[0] ), true );
+}
+
+void ScUndoDeleteTab::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo( lcl_GetVisibleTabBefore( pDocShell->GetDocument(), theTabs.front() ) );
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ pViewShell->DeleteTables( theTabs, false );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( true ); //! EndRedo
+
+ SetChangeTrack();
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoDeleteTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell* pViewShell = pViewTarget->GetViewShell();
+ pViewShell->DeleteTable( pViewShell->GetViewData().GetTabNo() );
+ }
+}
+
+bool ScUndoDeleteTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRenameTab::ScUndoRenameTab( ScDocShell* pNewDocShell,
+ SCTAB nT,
+ const OUString& rOldName,
+ const OUString& rNewName) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab ( nT )
+{
+ sOldName = rOldName;
+ sNewName = rNewName;
+}
+
+ScUndoRenameTab::~ScUndoRenameTab()
+{
+}
+
+OUString ScUndoRenameTab::GetComment() const
+{
+ return ScResId( STR_UNDO_RENAME_TAB );
+}
+
+void ScUndoRenameTab::DoChange( SCTAB nTabP, const OUString& rName ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.RenameTab( nTabP, rName );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) ); // Also Name Box
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+}
+
+void ScUndoRenameTab::Undo()
+{
+ DoChange(nTab, sOldName);
+}
+
+void ScUndoRenameTab::Redo()
+{
+ DoChange(nTab, sNewName);
+}
+
+void ScUndoRenameTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRenameTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoMoveTab::ScUndoMoveTab(
+ ScDocShell* pNewDocShell, std::unique_ptr<vector<SCTAB>> pOldTabs, std::unique_ptr<vector<SCTAB>> pNewTabs,
+ std::unique_ptr<vector<OUString>> pOldNames, std::unique_ptr<vector<OUString>> pNewNames) :
+ ScSimpleUndo( pNewDocShell ),
+ mpOldTabs(std::move(pOldTabs)), mpNewTabs(std::move(pNewTabs)),
+ mpOldNames(std::move(pOldNames)), mpNewNames(std::move(pNewNames))
+{
+ // The sizes differ. Something is wrong.
+ assert(!mpOldNames || mpOldTabs->size() == mpOldNames->size());
+ // The sizes differ. Something is wrong.
+ assert(!mpNewNames || mpNewTabs->size() == mpNewNames->size());
+}
+
+ScUndoMoveTab::~ScUndoMoveTab()
+{
+}
+
+OUString ScUndoMoveTab::GetComment() const
+{
+ return ScResId( STR_UNDO_MOVE_TAB );
+}
+
+void ScUndoMoveTab::DoChange( bool bUndo ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (bUndo) // UnDo
+ {
+ size_t i = mpNewTabs->size();
+ ScProgress aProgress(pDocShell, ScResId(STR_UNDO_MOVE_TAB),
+ i * rDoc.GetCodeCount(), true);
+ for (; i > 0; --i)
+ {
+ SCTAB nDestTab = (*mpNewTabs)[i-1];
+ SCTAB nOldTab = (*mpOldTabs)[i-1];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ rDoc.MoveTab( nDestTab, nOldTab, &aProgress );
+ pViewShell->GetViewData().MoveTab( nDestTab, nOldTab );
+ pViewShell->SetTabNo( nOldTab, true );
+ if (mpOldNames)
+ {
+ const OUString& rOldName = (*mpOldNames)[i-1];
+ rDoc.RenameTab(nOldTab, rOldName);
+ }
+ }
+ }
+ else
+ {
+ size_t n = mpNewTabs->size();
+ ScProgress aProgress(pDocShell, ScResId(STR_UNDO_MOVE_TAB),
+ n * rDoc.GetCodeCount(), true);
+ for (size_t i = 0; i < n; ++i)
+ {
+ SCTAB nDestTab = (*mpNewTabs)[i];
+ SCTAB nNewTab = nDestTab;
+ SCTAB nOldTab = (*mpOldTabs)[i];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ rDoc.MoveTab( nOldTab, nNewTab, &aProgress );
+ pViewShell->GetViewData().MoveTab( nOldTab, nNewTab );
+ pViewShell->SetTabNo( nDestTab, true );
+ if (mpNewNames)
+ {
+ const OUString& rNewName = (*mpNewNames)[i];
+ rDoc.RenameTab(nNewTab, rNewName);
+ }
+ }
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoMoveTab::Undo()
+{
+ DoChange( true );
+}
+
+void ScUndoMoveTab::Redo()
+{
+ DoChange( false );
+}
+
+void ScUndoMoveTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // No Repeat ! ? !
+}
+
+bool ScUndoMoveTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoCopyTab::ScUndoCopyTab(
+ ScDocShell* pNewDocShell,
+ std::unique_ptr<vector<SCTAB>> pOldTabs, std::unique_ptr<vector<SCTAB>> pNewTabs,
+ std::unique_ptr<vector<OUString>> pNewNames) :
+ ScSimpleUndo( pNewDocShell ),
+ mpOldTabs(std::move(pOldTabs)),
+ mpNewTabs(std::move(pNewTabs)),
+ mpNewNames(std::move(pNewNames))
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ // The sizes differ. Something is wrong.
+ assert(!mpNewNames || mpNewTabs->size() == mpNewNames->size());
+}
+
+ScUndoCopyTab::~ScUndoCopyTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoCopyTab::GetComment() const
+{
+ return ScResId( STR_UNDO_COPY_TAB );
+}
+
+void ScUndoCopyTab::DoChange() const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ pViewShell->SetTabNo((*mpOldTabs)[0],true);
+
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoCopyTab::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc ); // before the sheets are deleted
+
+ vector<SCTAB>::const_reverse_iterator itr, itrEnd = mpNewTabs->rend();
+ for (itr = mpNewTabs->rbegin(); itr != itrEnd; ++itr)
+ {
+ SCTAB nDestTab = *itr;
+ if (nDestTab > MAXTAB) // append?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ bDrawIsInUndo = true;
+ rDoc.DeleteTab(nDestTab);
+ bDrawIsInUndo = false;
+ }
+
+ // ScTablesHint broadcasts after all sheets have been deleted,
+ // so sheets and draw pages are in sync!
+
+ for (itr = mpNewTabs->rbegin(); itr != itrEnd; ++itr)
+ {
+ SCTAB nDestTab = *itr;
+ if (nDestTab > MAXTAB) // append?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ pDocShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nDestTab ) );
+ }
+
+ DoChange();
+}
+
+void ScUndoCopyTab::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nDestTab = 0;
+ for (size_t i = 0, n = mpNewTabs->size(); i < n; ++i)
+ {
+ nDestTab = (*mpNewTabs)[i];
+ SCTAB nNewTab = nDestTab;
+ SCTAB nOldTab = (*mpOldTabs)[i];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ bDrawIsInUndo = true;
+ rDoc.CopyTab( nOldTab, nNewTab );
+ bDrawIsInUndo = false;
+
+ pViewShell->GetViewData().MoveTab( nOldTab, nNewTab );
+
+ SCTAB nAdjSource = nOldTab;
+ if ( nNewTab <= nOldTab )
+ ++nAdjSource; // new position of source table after CopyTab
+
+ if ( rDoc.IsScenario(nAdjSource) )
+ {
+ rDoc.SetScenario(nNewTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData(nAdjSource, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData(nNewTab, aComment, aColor, nScenFlags );
+ bool bActive = rDoc.IsActiveScenario(nAdjSource);
+ rDoc.SetActiveScenario(nNewTab, bActive );
+ bool bVisible = rDoc.IsVisible(nAdjSource);
+ rDoc.SetVisible(nNewTab,bVisible );
+ }
+
+ if ( rDoc.IsTabProtected( nAdjSource ) )
+ rDoc.CopyTabProtection(nAdjSource, nNewTab);
+
+ if (mpNewNames)
+ {
+ const OUString& rName = (*mpNewNames)[i];
+ rDoc.RenameTab(nNewTab, rName);
+ }
+ }
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // after the sheets are inserted
+
+ pViewShell->SetTabNo( nDestTab, true ); // after draw-undo
+
+ DoChange();
+
+}
+
+void ScUndoCopyTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // no Repeat ! ? !
+}
+
+bool ScUndoCopyTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoTabColor::ScUndoTabColor(
+ ScDocShell* pNewDocShell, SCTAB nT, const Color& aOTabBgColor, const Color& aNTabBgColor) :
+ ScSimpleUndo( pNewDocShell )
+{
+ ScUndoTabColorInfo aInfo(nT);
+ aInfo.maOldTabBgColor = aOTabBgColor;
+ aInfo.maNewTabBgColor = aNTabBgColor;
+ aTabColorList.push_back(aInfo);
+}
+
+ScUndoTabColor::ScUndoTabColor(
+ ScDocShell* pNewDocShell,
+ ScUndoTabColorInfo::List&& rUndoTabColorList) :
+ ScSimpleUndo(pNewDocShell),
+ aTabColorList(std::move(rUndoTabColorList))
+{
+}
+
+ScUndoTabColor::~ScUndoTabColor()
+{
+}
+
+OUString ScUndoTabColor::GetComment() const
+{
+ if (aTabColorList.size() > 1)
+ return ScResId(STR_UNDO_SET_MULTI_TAB_BG_COLOR);
+ return ScResId(STR_UNDO_SET_TAB_BG_COLOR);
+}
+
+void ScUndoTabColor::DoChange(bool bUndoType) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ size_t nTabColorCount = aTabColorList.size();
+ for (size_t i = 0; i < nTabColorCount; ++i)
+ {
+ const ScUndoTabColorInfo& rTabColor = aTabColorList[i];
+ rDoc.SetTabBgColor(rTabColor.mnTabId,
+ bUndoType ? rTabColor.maOldTabBgColor : rTabColor.maNewTabBgColor);
+ }
+
+ pDocShell->PostPaintExtras();
+ ScDocShellModificator aModificator( *pDocShell );
+ aModificator.SetDocumentModified();
+}
+
+void ScUndoTabColor::Undo()
+{
+ DoChange(true);
+}
+
+void ScUndoTabColor::Redo()
+{
+ DoChange(false);
+}
+
+void ScUndoTabColor::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoTabColor::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoMakeScenario::ScUndoMakeScenario( ScDocShell* pNewDocShell,
+ SCTAB nSrc, SCTAB nDest,
+ const OUString& rN, const OUString& rC,
+ const Color& rCol, ScScenarioFlags nF,
+ const ScMarkData& rMark ) :
+ ScSimpleUndo( pNewDocShell ),
+ mpMarkData(new ScMarkData(rMark)),
+ nSrcTab( nSrc ),
+ nDestTab( nDest ),
+ aName( rN ),
+ aComment( rC ),
+ aColor( rCol ),
+ nFlags( nF )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoMakeScenario::~ScUndoMakeScenario()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoMakeScenario::GetComment() const
+{
+ return ScResId( STR_UNDO_MAKESCENARIO );
+}
+
+void ScUndoMakeScenario::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ pDocShell->SetInUndo( true );
+ bDrawIsInUndo = true;
+ rDoc.DeleteTab( nDestTab );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false );
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ pDocShell->PostPaint(0,0,nDestTab,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All);
+ pDocShell->PostDataChanged();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nSrcTab, true );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoMakeScenario::Redo()
+{
+ SetViewMarkData(*mpMarkData);
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true );
+ bDrawIsInUndo = true;
+
+ pDocShell->MakeScenario( nSrcTab, aName, aComment, aColor, nFlags, *mpMarkData, false );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nDestTab, true );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoMakeScenario::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ pViewTarget->GetViewShell()->MakeScenario( aName, aComment, aColor, nFlags );
+ }
+}
+
+bool ScUndoMakeScenario::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoImportTab::ScUndoImportTab(ScDocShell* pShell,
+ SCTAB nNewTab, SCTAB nNewCount)
+ : ScSimpleUndo(pShell)
+ , nTab(nNewTab)
+ , nCount(nNewCount)
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoImportTab::~ScUndoImportTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoImportTab::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoImportTab::DoChange() const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if (pViewShell)
+ {
+ if(nTab<nTabCount)
+ {
+ pViewShell->SetTabNo(nTab,true);
+ }
+ else
+ {
+ pViewShell->SetTabNo(nTab-1,true);
+ }
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB,
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
+}
+
+void ScUndoImportTab::Undo()
+{
+ // Inserted range names, etc.
+
+ SCTAB i;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bMakeRedo = !xRedoDoc;
+ if (bMakeRedo)
+ {
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ xRedoDoc->InitUndo(rDoc, nTab,nTab+nCount-1, true, true);
+
+ OUString aOldName;
+ for (i=0; i<nCount; i++)
+ {
+ SCTAB nTabPos=nTab+i;
+
+ rDoc.CopyToDocument(0,0,nTabPos, rDoc.MaxCol(),rDoc.MaxRow(),nTabPos, InsertDeleteFlags::ALL,false, *xRedoDoc);
+ rDoc.GetName( nTabPos, aOldName );
+ xRedoDoc->RenameTab(nTabPos, aOldName);
+ xRedoDoc->SetTabBgColor(nTabPos, rDoc.GetTabBgColor(nTabPos));
+
+ if ( rDoc.IsScenario(nTabPos) )
+ {
+ xRedoDoc->SetScenario(nTabPos, true);
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ xRedoDoc->SetScenarioData(nTabPos, aComment, aColor, nScenFlags);
+ bool bActive = rDoc.IsActiveScenario(nTabPos);
+ xRedoDoc->SetActiveScenario(nTabPos, bActive);
+ bool bVisible = rDoc.IsVisible(nTabPos);
+ xRedoDoc->SetVisible(nTabPos, bVisible);
+ }
+
+ if ( rDoc.IsTabProtected( nTabPos ) )
+ xRedoDoc->SetTabProtection(nTabPos, rDoc.GetTabProtection(nTabPos));
+ }
+
+ }
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc ); // before the sheets are deleted
+
+ bDrawIsInUndo = true;
+ for (i=0; i<nCount; i++)
+ rDoc.DeleteTab( nTab );
+ bDrawIsInUndo = false;
+
+ DoChange();
+}
+
+void ScUndoImportTab::Redo()
+{
+ if (!xRedoDoc)
+ {
+ OSL_FAIL("Where is my Redo Document?");
+ return;
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString aName;
+ SCTAB i;
+ for (i=0; i<nCount; i++) // first insert all sheets (#63304#)
+ {
+ SCTAB nTabPos=nTab+i;
+ xRedoDoc->GetName(nTabPos, aName);
+ bDrawIsInUndo = true;
+ rDoc.InsertTab(nTabPos,aName);
+ bDrawIsInUndo = false;
+ }
+ for (i=0; i<nCount; i++) // then copy into inserted sheets
+ {
+ SCTAB nTabPos=nTab+i;
+ xRedoDoc->CopyToDocument(0,0,nTabPos, rDoc.MaxCol(),rDoc.MaxRow(),nTabPos, InsertDeleteFlags::ALL,false, rDoc);
+ rDoc.SetTabBgColor(nTabPos, xRedoDoc->GetTabBgColor(nTabPos));
+
+ if (xRedoDoc->IsScenario(nTabPos))
+ {
+ rDoc.SetScenario(nTabPos, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ xRedoDoc->GetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ bool bActive = xRedoDoc->IsActiveScenario(nTabPos);
+ rDoc.SetActiveScenario(nTabPos, bActive );
+ bool bVisible = xRedoDoc->IsVisible(nTabPos);
+ rDoc.SetVisible(nTabPos,bVisible );
+ }
+
+ if (xRedoDoc->IsTabProtected(nTabPos))
+ rDoc.SetTabProtection(nTabPos, xRedoDoc->GetTabProtection(nTabPos));
+ }
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // after the sheets are inserted
+
+ DoChange();
+}
+
+void ScUndoImportTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoImportTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveLink::ScUndoRemoveLink( ScDocShell* pShell, const OUString& rDocName ) :
+ ScSimpleUndo( pShell ),
+ aDocName( rDocName ),
+ nRefreshDelay( 0 ),
+ nCount( 0 )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pTabs.reset( new SCTAB[nTabCount] );
+ pModes.reset( new ScLinkMode[nTabCount] );
+ pTabNames.reset( new OUString[nTabCount] );
+
+ for (SCTAB i=0; i<nTabCount; i++)
+ {
+ ScLinkMode nMode = rDoc.GetLinkMode(i);
+ if (nMode != ScLinkMode::NONE)
+ if (rDoc.GetLinkDoc(i) == aDocName)
+ {
+ if (!nCount)
+ {
+ aFltName = rDoc.GetLinkFlt(i);
+ aOptions = rDoc.GetLinkOpt(i);
+ nRefreshDelay = rDoc.GetLinkRefreshDelay(i);
+ }
+ else
+ {
+ OSL_ENSURE(aFltName == rDoc.GetLinkFlt(i) &&
+ aOptions == rDoc.GetLinkOpt(i),
+ "different Filter for a Document?");
+ }
+ pTabs[nCount] = i;
+ pModes[nCount] = nMode;
+ pTabNames[nCount] = rDoc.GetLinkTab(i);
+ ++nCount;
+ }
+ }
+}
+
+ScUndoRemoveLink::~ScUndoRemoveLink()
+{
+}
+
+OUString ScUndoRemoveLink::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVELINK );
+}
+
+void ScUndoRemoveLink::DoChange( bool bLink ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (bLink) // establish link
+ rDoc.SetLink( pTabs[i], pModes[i], aDocName, aFltName, aOptions, pTabNames[i], nRefreshDelay );
+ else // remove link
+ rDoc.SetLink( pTabs[i], ScLinkMode::NONE, "", "", "", "", 0 );
+ pDocShell->UpdateLinks();
+}
+
+void ScUndoRemoveLink::Undo()
+{
+ DoChange( true );
+}
+
+void ScUndoRemoveLink::Redo()
+{
+ DoChange( false );
+}
+
+void ScUndoRemoveLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRemoveLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoShowHideTab::ScUndoShowHideTab( ScDocShell* pShell, std::vector<SCTAB>&& newUndoTabs, bool bNewShow ) :
+ ScSimpleUndo( pShell ),
+ undoTabs( std::move(newUndoTabs) ),
+ bShow( bNewShow )
+{
+}
+
+ScUndoShowHideTab::~ScUndoShowHideTab()
+{
+}
+
+void ScUndoShowHideTab::DoChange( bool bShowP ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ for(const SCTAB& nTab : undoTabs)
+ {
+ rDoc.SetVisible( nTab, bShowP );
+ if (pViewShell)
+ pViewShell->SetTabNo(nTab,true);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pDocShell->SetDocumentModified();
+}
+
+void ScUndoShowHideTab::Undo()
+{
+ DoChange(!bShow);
+}
+
+void ScUndoShowHideTab::Redo()
+{
+ DoChange(bShow);
+}
+
+void ScUndoShowHideTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute( bShow ? FID_TABLE_SHOW : FID_TABLE_HIDE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoShowHideTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+OUString ScUndoShowHideTab::GetComment() const
+{
+ TranslateId pId;
+ if (undoTabs.size() > 1)
+ {
+ pId = bShow ? STR_UNDO_SHOWTABS : STR_UNDO_HIDETABS;
+ }
+ else
+ {
+ pId = bShow ? STR_UNDO_SHOWTAB : STR_UNDO_HIDETAB;
+ }
+
+ return ScResId(pId);
+}
+
+ScUndoDocProtect::ScUndoDocProtect(ScDocShell* pShell, unique_ptr<ScDocProtection> && pProtectSettings) :
+ ScSimpleUndo(pShell),
+ mpProtectSettings(std::move(pProtectSettings))
+{
+}
+
+ScUndoDocProtect::~ScUndoDocProtect()
+{
+}
+
+void ScUndoDocProtect::DoProtect(bool bProtect)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bProtect)
+ {
+ // set protection.
+ unique_ptr<ScDocProtection> pCopy(new ScDocProtection(*mpProtectSettings));
+ pCopy->setProtected(true);
+ rDoc.SetDocProtection(pCopy.get());
+ }
+ else
+ {
+ // remove protection.
+ rDoc.SetDocProtection(nullptr);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateLayerLocks();
+ pViewShell->UpdateInputHandler(true); // so that input can be immediately entered again
+ }
+
+ pDocShell->PostPaintGridAll();
+}
+
+void ScUndoDocProtect::Undo()
+{
+ BeginUndo();
+ DoProtect(!mpProtectSettings->isProtected());
+ EndUndo();
+}
+
+void ScUndoDocProtect::Redo()
+{
+ BeginRedo();
+ DoProtect(mpProtectSettings->isProtected());
+ EndRedo();
+}
+
+void ScUndoDocProtect::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoDocProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoDocProtect::GetComment() const
+{
+ TranslateId pId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_DOC : STR_UNDO_UNPROTECT_DOC;
+ return ScResId(pId);
+}
+
+ScUndoTabProtect::ScUndoTabProtect(ScDocShell* pShell, SCTAB nTab, unique_ptr<ScTableProtection> && pProtectSettings) :
+ ScSimpleUndo(pShell),
+ mnTab(nTab),
+ mpProtectSettings(std::move(pProtectSettings))
+{
+}
+
+ScUndoTabProtect::~ScUndoTabProtect()
+{
+}
+
+void ScUndoTabProtect::DoProtect(bool bProtect)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bProtect)
+ {
+ // set protection.
+ unique_ptr<ScTableProtection> pCopy(new ScTableProtection(*mpProtectSettings));
+ pCopy->setProtected(true);
+ rDoc.SetTabProtection(mnTab, pCopy.get());
+ }
+ else
+ {
+ // remove protection.
+ rDoc.SetTabProtection(mnTab, nullptr);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ if (ScTabView* pTabView = pViewShell->GetViewData().GetView())
+ pTabView->SetTabProtectionSymbol( mnTab, bProtect);
+ pViewShell->UpdateLayerLocks();
+ pViewShell->UpdateInputHandler(true); // so that input can be immediately entered again
+ }
+
+ pDocShell->PostPaintGridAll();
+}
+
+void ScUndoTabProtect::Undo()
+{
+ BeginUndo();
+ DoProtect(!mpProtectSettings->isProtected());
+ EndUndo();
+}
+
+void ScUndoTabProtect::Redo()
+{
+ BeginRedo();
+ DoProtect(mpProtectSettings->isProtected());
+ EndRedo();
+}
+
+void ScUndoTabProtect::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoTabProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoTabProtect::GetComment() const
+{
+ TranslateId pId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_TAB : STR_UNDO_UNPROTECT_TAB;
+ return ScResId(pId);
+}
+
+ScUndoPrintRange::ScUndoPrintRange( ScDocShell* pShell, SCTAB nNewTab,
+ std::unique_ptr<ScPrintRangeSaver> pOld, std::unique_ptr<ScPrintRangeSaver> pNew ) :
+ ScSimpleUndo( pShell ),
+ nTab( nNewTab ),
+ pOldRanges( std::move(pOld) ),
+ pNewRanges( std::move(pNew) )
+{
+}
+
+ScUndoPrintRange::~ScUndoPrintRange()
+{
+ pOldRanges.reset();
+ pNewRanges.reset();
+}
+
+void ScUndoPrintRange::DoChange(bool bUndo)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (bUndo)
+ rDoc.RestorePrintRanges( *pOldRanges );
+ else
+ rDoc.RestorePrintRanges( *pNewRanges );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nTab );
+
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), nTab ).UpdatePages();
+
+ if (pViewShell && comphelper::LibreOfficeKit::isActive())
+ {
+ tools::JsonWriter aJsonWriter;
+ if (bUndo)
+ pOldRanges->GetPrintRangesInfo(aJsonWriter);
+ else
+ pNewRanges->GetPrintRangesInfo(aJsonWriter);
+
+ const std::string message = aJsonWriter.extractAsStdString();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_PRINT_RANGES, message.c_str());
+ }
+
+ pDocShell->PostPaint( ScRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab), PaintPartFlags::Grid );
+}
+
+void ScUndoPrintRange::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoPrintRange::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoPrintRange::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoPrintRange::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoPrintRange::GetComment() const
+{
+ return ScResId( STR_UNDO_PRINTRANGES );
+}
+
+ScUndoScenarioFlags::ScUndoScenarioFlags(ScDocShell* pNewDocShell, SCTAB nT,
+ const OUString& rON, const OUString& rNN, const OUString& rOC, const OUString& rNC,
+ const Color& rOCol, const Color& rNCol, ScScenarioFlags nOF, ScScenarioFlags nNF) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab ( nT ),
+ aOldName ( rON ),
+ aNewName ( rNN ),
+ aOldComment ( rOC ),
+ aNewComment ( rNC ),
+ aOldColor ( rOCol ),
+ aNewColor ( rNCol ),
+ nOldFlags (nOF),
+ nNewFlags (nNF)
+{
+}
+
+ScUndoScenarioFlags::~ScUndoScenarioFlags()
+{
+}
+
+OUString ScUndoScenarioFlags::GetComment() const
+{
+ return ScResId( STR_UNDO_EDITSCENARIO );
+}
+
+void ScUndoScenarioFlags::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.RenameTab( nTab, aOldName );
+ rDoc.SetScenarioData( nTab, aOldComment, aOldColor, nOldFlags );
+
+ pDocShell->PostPaintGridAll();
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+
+ if ( aOldName != aNewName )
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoScenarioFlags::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.RenameTab( nTab, aNewName );
+ rDoc.SetScenarioData( nTab, aNewComment, aNewColor, nNewFlags );
+
+ pDocShell->PostPaintGridAll();
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+
+ if ( aOldName != aNewName )
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoScenarioFlags::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // Repeat makes no sense
+}
+
+bool ScUndoScenarioFlags::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// (move to different file?)
+ScUndoRenameObject::ScUndoRenameObject( ScDocShell* pNewDocShell, const OUString& rPN,
+ const OUString& rON, const OUString& rNN ) :
+ ScSimpleUndo( pNewDocShell ),
+ aPersistName( rPN ),
+ aOldName ( rON ),
+ aNewName ( rNN )
+{
+}
+
+ScUndoRenameObject::~ScUndoRenameObject()
+{
+}
+
+OUString ScUndoRenameObject::GetComment() const
+{
+ // string resource shared with title for dialog
+ return ScResId(SCSTR_RENAMEOBJECT);
+}
+
+SdrObject* ScUndoRenameObject::GetObject()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if ( pDrawLayer )
+ {
+ sal_uInt16 nCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nTab);
+ assert(pPage && "Page ?");
+
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
+ static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == aPersistName )
+ {
+ return pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ OSL_FAIL("Object not found");
+ return nullptr;
+}
+
+void ScUndoRenameObject::Undo()
+{
+ BeginUndo();
+ SdrObject* pObj = GetObject();
+ if ( pObj )
+ pObj->SetName( aOldName );
+ EndUndo();
+}
+
+void ScUndoRenameObject::Redo()
+{
+ BeginRedo();
+ SdrObject* pObj = GetObject();
+ if ( pObj )
+ pObj->SetName( aNewName );
+ EndRedo();
+}
+
+void ScUndoRenameObject::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoRenameObject::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoLayoutRTL::ScUndoLayoutRTL( ScDocShell* pShell, SCTAB nNewTab, bool bNewRTL ) :
+ ScSimpleUndo( pShell ),
+ nTab( nNewTab ),
+ bRTL( bNewRTL )
+{
+}
+
+ScUndoLayoutRTL::~ScUndoLayoutRTL()
+{
+}
+
+void ScUndoLayoutRTL::DoChange( bool bNew )
+{
+ pDocShell->SetInUndo( true );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SetLayoutRTL(nTab, bNew, ScObjectHandling::MirrorRTLMode);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo(nTab,true);
+
+ pDocShell->SetDocumentModified();
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScUndoLayoutRTL::Undo()
+{
+ DoChange(!bRTL);
+}
+
+void ScUndoLayoutRTL::Redo()
+{
+ DoChange(bRTL);
+}
+
+void ScUndoLayoutRTL::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute( FID_TAB_RTL, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoLayoutRTL::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+OUString ScUndoLayoutRTL::GetComment() const
+{
+ return ScResId( STR_UNDO_TAB_RTL );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoutil.cxx b/sc/source/ui/undo/undoutil.cxx
new file mode 100644
index 000000000..de9a50ef8
--- /dev/null
+++ b/sc/source/ui/undo/undoutil.cxx
@@ -0,0 +1,114 @@
+/* -*- 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 <undoutil.hxx>
+
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <dbdata.hxx>
+#include <globalnames.hxx>
+#include <global.hxx>
+#include <markdata.hxx>
+#include <osl/diagnose.h>
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ )
+{
+ if ( pDocShell->IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab < nStartZ || nViewTab > nEndZ )
+ pViewShell->SetTabNo( nStartZ );
+
+ const ScRange aMarkRange( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ);
+ pViewShell->DoneBlockMode();
+ pViewShell->MoveCursorAbs( nStartX, nStartY, SC_FOLLOW_JUMP, false, false );
+ pViewShell->InitOwnBlockMode( aMarkRange );
+ pViewShell->GetViewData().GetMarkData().SetMarkArea( aMarkRange );
+ pViewShell->MarkDataChanged();
+}
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScAddress& rBlockStart,
+ const ScAddress& rBlockEnd )
+{
+ MarkSimpleBlock( pDocShell, rBlockStart.Col(), rBlockStart.Row(), rBlockStart.Tab(),
+ rBlockEnd.Col(), rBlockEnd.Row(), rBlockEnd.Tab() );
+}
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScRange& rRange )
+{
+ MarkSimpleBlock( pDocShell, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab() );
+}
+
+ScDBData* ScUndoUtil::GetOldDBData( const ScDBData* pUndoData, ScDocument* pDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ ScDBData* pRet = pDoc->GetDBAtArea( nTab, nCol1, nRow1, nCol2, nRow2 );
+
+ if (!pRet)
+ {
+ bool bWasTemp = false;
+ if ( pUndoData )
+ {
+ const OUString& aName = pUndoData->GetName();
+ if ( aName == STR_DB_LOCAL_NONAME )
+ bWasTemp = true;
+ }
+ OSL_ENSURE(bWasTemp, "Undo: didn't find database range");
+ pRet = pDoc->GetAnonymousDBData(nTab);
+ if (!pRet)
+ {
+ pRet = new ScDBData( STR_DB_LOCAL_NONAME, nTab,
+ nCol1,nRow1, nCol2,nRow2, true,
+ pDoc->HasColHeader( nCol1,nRow1,nCol2,nRow2,nTab ) );
+ pDoc->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pRet));
+ }
+ }
+
+ return pRet;
+}
+
+void ScUndoUtil::PaintMore( ScDocShell* pDocShell,
+ const ScRange& rRange )
+{
+ SCCOL nCol1 = rRange.aStart.Col();
+ SCROW nRow1 = rRange.aStart.Row();
+ SCCOL nCol2 = rRange.aEnd.Col();
+ SCROW nRow2 = rRange.aEnd.Row();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (nCol1 > 0) --nCol1;
+ if (nRow1 > 0) --nRow1;
+ if (nCol2<rDoc.MaxCol()) ++nCol2;
+ if (nRow2<rDoc.MaxRow()) ++nRow2;
+
+ pDocShell->PostPaint( nCol1,nRow1,rRange.aStart.Tab(),
+ nCol2,nRow2,rRange.aEnd.Tab(), PaintPartFlags::Grid );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */