include/svl/undo.hxx             |   10 ++++++++-
 sc/source/ui/drawfunc/fuins2.cxx |    1 
 sc/source/ui/inc/tabvwsh.hxx     |    6 +++++
 sc/source/ui/inc/undomanager.hxx |    1 
 sc/source/ui/view/tabvwshb.cxx   |   21 ++++++++++++++++++--
 svl/source/undo/undo.cxx         |   40 +++++++++++++++++++++++++++++++++++----
 6 files changed, 72 insertions(+), 7 deletions(-)

New commits:
commit 62cda8b744caaa49a831b3a8a35734bb019886c2
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu Feb 29 17:03:31 2024 +0600
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Mar 18 14:34:28 2024 +0100

    cool#8443 let Insert Chart dialog to undo out of order on Cancel
    
    Change-Id: I66d749362c9fb5f2c228f0f5d2c927cc0cf3f89f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164179
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164834
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/include/svl/undo.hxx b/include/svl/undo.hxx
index a7d1e4753712..eca3f4abd4a6 100644
--- a/include/svl/undo.hxx
+++ b/include/svl/undo.hxx
@@ -289,8 +289,11 @@ public:
 
     /** removes a mark given by its ID.
         After the call, the mark ID is invalid.
+
+        @return the index at which the mark was removed, or 
std::numeric_limits<size_t>::max()
+                if failed
     */
-    void            RemoveMark( UndoStackMark const i_mark );
+    size_t RemoveMark(UndoStackMark const i_mark);
 
     /** determines whether the top action on the Undo stack has a given mark
     */
@@ -306,6 +309,11 @@ protected:
     bool    UndoWithContext( SfxUndoContext& i_context );
     bool    RedoWithContext( SfxUndoContext& i_context );
 
+    // Undoes a specific mark on the undo stack, and removes it from the 
undo/redo stack,
+    // but only in case when the redo stack is empty. This is a dangerous 
operation, because
+    // it undoes out of order.
+    void UndoMark(UndoStackMark i_mark);
+
     void    ImplClearRedo_NoLock( bool const i_currentLevel );
 
     /** clears all undo actions on the current level, plus all undo actions on 
superordinate levels,
diff --git a/sc/source/ui/drawfunc/fuins2.cxx b/sc/source/ui/drawfunc/fuins2.cxx
index 959424b40b87..4d34208b7ec6 100644
--- a/sc/source/ui/drawfunc/fuins2.cxx
+++ b/sc/source/ui/drawfunc/fuins2.cxx
@@ -684,6 +684,7 @@ FuInsertChart::FuInsertChart(ScTabViewShell& rViewSh, 
vcl::Window* pWin, ScDrawV
                     }
 
                     pView->AddUndo(std::make_unique<SdrUndoNewObj>(*pObj));
+                    rViewSh.SetInsertWizardUndoMark();
                     rtl::Reference<::svt::DialogClosedListener> pListener = 
new ::svt::DialogClosedListener();
                     pListener->SetDialogClosedLink( rLink );
 
diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
index b457e1167100..490247baa24e 100644
--- a/sc/source/ui/inc/tabvwsh.hxx
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -187,6 +187,10 @@ private:
     OUString   maScope;
 
     std::unique_ptr<ScDragData> m_pDragData;
+
+    // Chart insert wizard's mark to make sure it undoes the correct thing in 
LOK case
+    UndoStackMark m_InsertWizardUndoMark = MARK_INVALID;
+
 private:
     void    Construct( TriState nForceDesignMode );
 
@@ -445,6 +449,8 @@ public:
 
     void SetMoveKeepEdit(bool value) { bMoveKeepEdit = value; };
     bool GetMoveKeepEdit() { return bMoveKeepEdit; };
+
+    void SetInsertWizardUndoMark();
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undomanager.hxx b/sc/source/ui/inc/undomanager.hxx
index 03168dfab980..e36ae179f04e 100644
--- a/sc/source/ui/inc/undomanager.hxx
+++ b/sc/source/ui/inc/undomanager.hxx
@@ -27,6 +27,7 @@ public:
     /// Make these public
     using SdrUndoManager::UndoWithContext;
     using SdrUndoManager::RedoWithContext;
+    using SdrUndoManager::UndoMark;
 
 private:
     static std::optional<ScRange> getAffectedRangeFromUndo(const 
SfxUndoAction*);
diff --git a/sc/source/ui/view/tabvwshb.cxx b/sc/source/ui/view/tabvwshb.cxx
index ad0e757ce0aa..4ab6c9c13cef 100644
--- a/sc/source/ui/view/tabvwshb.cxx
+++ b/sc/source/ui/view/tabvwshb.cxx
@@ -318,8 +318,17 @@ void ScTabViewShell::DeactivateOle()
         pClient->DeactivateObject();
 }
 
+void ScTabViewShell::SetInsertWizardUndoMark()
+{
+    assert(m_InsertWizardUndoMark == MARK_INVALID);
+    m_InsertWizardUndoMark = GetUndoManager()->MarkTopUndoAction();
+}
+
 IMPL_LINK( ScTabViewShell, DialogClosedHdl, 
css::ui::dialogs::DialogClosedEvent*, pEvent, void )
 {
+    assert(m_InsertWizardUndoMark != MARK_INVALID);
+    UndoStackMark nInsertWizardUndoMark = m_InsertWizardUndoMark;
+    m_InsertWizardUndoMark = MARK_INVALID;
     if( pEvent->DialogResult == ui::dialogs::ExecutableDialogResults::CANCEL )
     {
         ScTabView* pTabView = GetViewData().GetView();
@@ -332,8 +341,16 @@ IMPL_LINK( ScTabViewShell, DialogClosedHdl, 
css::ui::dialogs::DialogClosedEvent*
         DeactivateOle();
         pView->UnMarkAll();
 
-        rScDoc.GetUndoManager()->Undo();
-        rScDoc.GetUndoManager()->ClearRedo();
+        auto pUndoManager = rScDoc.GetUndoManager();
+        if (pUndoManager->GetRedoActionCount())
+        {
+            pUndoManager->RemoveMark(nInsertWizardUndoMark);
+        }
+        else
+        {
+            pUndoManager->UndoMark(nInsertWizardUndoMark);
+            pUndoManager->ClearRedo();
+        }
 
         // leave the draw shell
         SetDrawShell( false );
diff --git a/svl/source/undo/undo.cxx b/svl/source/undo/undo.cxx
index 9b90495d593a..96c937c037ad 100644
--- a/svl/source/undo/undo.cxx
+++ b/svl/source/undo/undo.cxx
@@ -34,6 +34,26 @@
 #include <limits.h>
 #include <algorithm>
 
+namespace
+{
+class SfxMarkedUndoContext final : public SfxUndoContext
+{
+public:
+    SfxMarkedUndoContext(SfxUndoManager& manager, UndoStackMark mark)
+    {
+        m_offset = manager.RemoveMark(mark);
+        size_t count = manager.GetUndoActionCount();
+        if (m_offset < count)
+            m_offset = count - m_offset - 1;
+        else
+            m_offset = std::numeric_limits<size_t>::max();
+    }
+    size_t GetUndoOffset() override { return m_offset; }
+
+private:
+    size_t m_offset;
+};
+}
 
 SfxRepeatTarget::~SfxRepeatTarget()
 {
@@ -1086,18 +1106,18 @@ UndoStackMark SfxUndoManager::MarkTopUndoAction()
     return m_xData->mnMarks;
 }
 
-void SfxUndoManager::RemoveMark( UndoStackMark const i_mark )
+size_t SfxUndoManager::RemoveMark(UndoStackMark i_mark)
 {
     UndoManagerGuard aGuard( *m_xData );
 
     if ((m_xData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
     {
-        return; // nothing to remove
+        return std::numeric_limits<size_t>::max(); // nothing to remove
     }
     else if (i_mark == m_xData->mnEmptyMark)
     {
         --m_xData->mnEmptyMark; // never returned from MarkTop => invalid
-        return;
+        return std::numeric_limits<size_t>::max();
     }
 
     for ( size_t i=0; i<m_xData->maUndoArray.maUndoActions.size(); ++i )
@@ -1107,13 +1127,15 @@ void SfxUndoManager::RemoveMark( UndoStackMark const 
i_mark )
         if (markPos != rAction.aMarks.end())
         {
             rAction.aMarks.erase( markPos );
-            return;
+            return i;
         }
     }
     SAL_WARN("svl", "SfxUndoManager::RemoveMark: mark not found!");
         // TODO: this might be too offensive. There are situations where we 
implicitly remove marks
         // without our clients, in particular the client which created the 
mark, having a chance to know
         // about this.
+
+    return std::numeric_limits<size_t>::max();
 }
 
 bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark const i_mark )
@@ -1133,6 +1155,16 @@ bool SfxUndoManager::HasTopUndoActionMark( UndoStackMark 
const i_mark )
 }
 
 
+void SfxUndoManager::UndoMark(UndoStackMark i_mark)
+{
+    SfxMarkedUndoContext context(*this, i_mark); // Removes the mark
+    if (context.GetUndoOffset() == std::numeric_limits<size_t>::max())
+        return; // nothing to undo
+
+    UndoWithContext(context);
+}
+
+
 void SfxUndoManager::RemoveOldestUndoAction()
 {
     UndoManagerGuard aGuard( *m_xData );

Reply via email to