From 928f16d3608138480def073188210e7c3b6790a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20C=C3=A9sar=20Neves=20Enumo?= Date: Wed, 5 May 2021 14:09:43 -0300 Subject: [PATCH] LibGUI: Remember modified state on undo/redo actions --- .../Applications/TextEditor/MainWidget.cpp | 4 +-- Userland/Libraries/LibGUI/TextDocument.cpp | 10 +++---- Userland/Libraries/LibGUI/TextDocument.h | 5 ++-- Userland/Libraries/LibGUI/UndoStack.cpp | 26 +++++++++++++++++++ Userland/Libraries/LibGUI/UndoStack.h | 6 ++++- 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Userland/Applications/TextEditor/MainWidget.cpp b/Userland/Applications/TextEditor/MainWidget.cpp index 267c10f133..75eb86dba0 100644 --- a/Userland/Applications/TextEditor/MainWidget.cpp +++ b/Userland/Applications/TextEditor/MainWidget.cpp @@ -299,7 +299,7 @@ MainWidget::MainWidget() return; } - editor().document().set_modified(false); + editor().document().set_unmodified(); // FIXME: It would be cool if this would propagate from GUI::TextDocument somehow. window()->set_modified(false); @@ -312,7 +312,7 @@ MainWidget::MainWidget() if (!m_editor->write_to_file(m_path)) { GUI::MessageBox::show(window(), "Unable to save file.\n", "Error", GUI::MessageBox::Type::Error); } else { - editor().document().set_modified(false); + editor().document().set_unmodified(); // FIXME: It would be cool if this would propagate from GUI::TextDocument somehow. window()->set_modified(false); diff --git a/Userland/Libraries/LibGUI/TextDocument.cpp b/Userland/Libraries/LibGUI/TextDocument.cpp index 27042d1696..f42cfa4624 100644 --- a/Userland/Libraries/LibGUI/TextDocument.cpp +++ b/Userland/Libraries/LibGUI/TextDocument.cpp @@ -26,7 +26,7 @@ TextDocument::TextDocument(Client* client) if (client) m_clients.set(client); append_line(make(*this)); - set_modified(false); + set_unmodified(); m_undo_timer = Core::Timer::create_single_shot( 2000, [this] { @@ -94,7 +94,7 @@ bool TextDocument::set_text(const StringView& text) clear_text_guard.disarm(); // FIXME: Should the modified state be cleared on some of the earlier returns as well? - set_modified(false); + set_unmodified(); return true; } @@ -309,8 +309,6 @@ void TextDocument::update_views(Badge) void TextDocument::notify_did_change() { - set_modified(true); - if (m_undo_timer) m_undo_timer->restart(); @@ -887,9 +885,9 @@ const TextDocumentSpan* TextDocument::span_at(const TextPosition& position) cons return nullptr; } -void TextDocument::set_modified(bool modified) +void TextDocument::set_unmodified() { - m_modified = modified; + m_undo_stack.set_current_unmodified(); } } diff --git a/Userland/Libraries/LibGUI/TextDocument.h b/Userland/Libraries/LibGUI/TextDocument.h index 6fa9b1783e..fa1b7beeef 100644 --- a/Userland/Libraries/LibGUI/TextDocument.h +++ b/Userland/Libraries/LibGUI/TextDocument.h @@ -122,8 +122,8 @@ public: virtual bool is_code_document() const { return false; } bool is_empty() const; - bool is_modified() const { return m_modified; } - void set_modified(bool); + bool is_modified() const { return m_undo_stack.is_current_modified(); } + void set_unmodified(); protected: explicit TextDocument(Client* client); @@ -136,7 +136,6 @@ private: HashTable m_clients; bool m_client_notifications_enabled { true }; - bool m_modified { false }; UndoStack m_undo_stack; RefPtr m_undo_timer; diff --git a/Userland/Libraries/LibGUI/UndoStack.cpp b/Userland/Libraries/LibGUI/UndoStack.cpp index 7f32d3e4fb..90f0ae781e 100644 --- a/Userland/Libraries/LibGUI/UndoStack.cpp +++ b/Userland/Libraries/LibGUI/UndoStack.cpp @@ -61,6 +61,14 @@ void UndoStack::push(NonnullOwnPtr&& command) if (m_stack_index > 0) { for (size_t i = 0; i < m_stack_index; i++) m_stack.remove(0); + + if (m_clean_index.has_value()) { + if (m_clean_index.value() < m_stack_index) + m_clean_index.clear(); + else + m_clean_index = m_clean_index.value() - m_stack_index; + } + m_stack_index = 0; finalize_current_combo(); } @@ -78,12 +86,30 @@ void UndoStack::finalize_current_combo() auto undo_commands_container = make(); m_stack.prepend(move(undo_commands_container)); + + if (m_clean_index.has_value()) + m_clean_index = m_clean_index.value() + 1; +} + +void UndoStack::set_current_unmodified() +{ + // Skip empty container + if (can_undo() && m_stack[m_stack_index].m_undo_vector.is_empty()) + m_clean_index = m_stack_index + 1; + else + m_clean_index = m_stack_index; +} + +bool UndoStack::is_current_modified() const +{ + return !m_clean_index.has_value() || m_stack_index != m_clean_index.value(); } void UndoStack::clear() { m_stack.clear(); m_stack_index = 0; + m_clean_index.clear(); } } diff --git a/Userland/Libraries/LibGUI/UndoStack.h b/Userland/Libraries/LibGUI/UndoStack.h index f854171c83..faf4a9a45e 100644 --- a/Userland/Libraries/LibGUI/UndoStack.h +++ b/Userland/Libraries/LibGUI/UndoStack.h @@ -19,13 +19,16 @@ public: void push(NonnullOwnPtr&&); bool can_undo() const { return m_stack_index < m_stack.size() && !m_stack.is_empty(); } - bool can_redo() const { return m_stack_index > 0 && !m_stack.is_empty(); } + bool can_redo() const { return m_stack_index > 0 && !m_stack.is_empty() && m_stack[m_stack_index - 1].m_undo_vector.size() > 0; } void undo(); void redo(); void finalize_current_combo(); + void set_current_unmodified(); + bool is_current_modified() const; + void clear(); private: @@ -35,6 +38,7 @@ private: NonnullOwnPtrVector m_stack; size_t m_stack_index { 0 }; + Optional m_clean_index; }; }