diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sc/source/ui/undo | |
parent | Initial commit. (diff) | |
download | libreoffice-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')
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: */ |