From 14b83ee12ff971acd1e8626ac12ffd6456e7299f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 23 Jan 2020 21:04:59 +0100 Subject: [PATCH] LibGUI: Give GTextDocument access to the GTextEditor during commands It's useful for the GTextDocument to have access to the initiating GTextEditor widget during the initial execution of a command. Since commands are executed via calls to GUndoCommand::redo(), we do this by wrapping the invocation of redo() in a new helper called GTextDocumentUndoCommand::execute_from(GTextDocument::Client). This is then used to fetch the current auto-indentation feature state and the soft tab width, both used by text insertion. --- Libraries/LibGUI/GTextDocument.cpp | 16 +++--- Libraries/LibGUI/GTextDocument.h | 78 +++++++++++++++++------------- Libraries/LibGUI/GTextEditor.h | 6 ++- 3 files changed, 57 insertions(+), 43 deletions(-) diff --git a/Libraries/LibGUI/GTextDocument.cpp b/Libraries/LibGUI/GTextDocument.cpp index f12b38be16..e751ca533e 100644 --- a/Libraries/LibGUI/GTextDocument.cpp +++ b/Libraries/LibGUI/GTextDocument.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include GTextDocument::GTextDocument(Client* client) @@ -427,7 +428,7 @@ InsertTextCommand::InsertTextCommand(GTextDocument& document, const String& text void InsertTextCommand::redo() { - auto new_cursor = m_document.insert_at(m_range.start(), m_text); + auto new_cursor = m_document.insert_at(m_range.start(), m_text, m_client); // NOTE: We don't know where the range ends until after doing redo(). // This is okay since we always do redo() after adding this to the undo stack. m_range.set_end(new_cursor); @@ -464,26 +465,25 @@ void GTextDocument::update_undo_timer() m_undo_stack.finalize_current_combo(); } -GTextPosition GTextDocument::insert_at(const GTextPosition& position, const StringView& text) +GTextPosition GTextDocument::insert_at(const GTextPosition& position, const StringView& text, const Client* client) { GTextPosition cursor = position; for (size_t i = 0; i < text.length(); ++i) - cursor = insert_at(cursor, text[i]); + cursor = insert_at(cursor, text[i], client); return cursor; } -GTextPosition GTextDocument::insert_at(const GTextPosition& position, char ch) +GTextPosition GTextDocument::insert_at(const GTextPosition& position, char ch, const Client* client) { - // FIXME: We need these from GTextEditor! - bool m_automatic_indentation_enabled = true; - size_t m_soft_tab_width = 4; + bool automatic_indentation_enabled = client ? client->is_automatic_indentation_enabled() : false; + size_t m_soft_tab_width = client ? client->soft_tab_width() : 4; bool at_head = position.column() == 0; bool at_tail = position.column() == line(position.line()).length(); if (ch == '\n') { if (at_tail || at_head) { String new_line_contents; - if (m_automatic_indentation_enabled && at_tail) { + if (automatic_indentation_enabled && at_tail) { size_t leading_spaces = 0; auto& old_line = lines()[position.line()]; for (size_t i = 0; i < old_line.length(); ++i) { diff --git a/Libraries/LibGUI/GTextDocument.h b/Libraries/LibGUI/GTextDocument.h index 1d302dcde8..fb974c3221 100644 --- a/Libraries/LibGUI/GTextDocument.h +++ b/Libraries/LibGUI/GTextDocument.h @@ -40,6 +40,7 @@ class GTextEditor; class GTextDocument; class GTextDocumentLine; +class GTextDocumentUndoCommand; struct GTextDocumentSpan { GTextRange range; @@ -50,37 +51,6 @@ struct GTextDocumentSpan { void* data { nullptr }; }; -class GTextDocumentUndoCommand : public GCommand { -public: - GTextDocumentUndoCommand(GTextDocument&); - virtual ~GTextDocumentUndoCommand(); - -protected: - GTextDocument& m_document; -}; - -class InsertTextCommand : public GTextDocumentUndoCommand { -public: - InsertTextCommand(GTextDocument&, const String&, const GTextPosition&); - virtual void undo() override; - virtual void redo() override; - -private: - String m_text; - GTextRange m_range; -}; - -class RemoveTextCommand : public GTextDocumentUndoCommand { -public: - RemoveTextCommand(GTextDocument&, const String&, const GTextRange&); - virtual void undo() override; - virtual void redo() override; - -private: - String m_text; - GTextRange m_range; -}; - class GTextDocument : public RefCounted { public: enum class SearchShouldWrap { @@ -98,6 +68,9 @@ public: virtual void document_did_change() = 0; virtual void document_did_set_text() = 0; virtual void document_did_set_cursor(const GTextPosition&) = 0; + + virtual bool is_automatic_indentation_enabled() const = 0; + virtual int soft_tab_width() const = 0; }; static NonnullRefPtr create(Client* client = nullptr) @@ -157,8 +130,8 @@ public: void notify_did_change(); void set_all_cursors(const GTextPosition&); - GTextPosition insert_at(const GTextPosition&, char); - GTextPosition insert_at(const GTextPosition&, const StringView&); + GTextPosition insert_at(const GTextPosition&, char, const Client* = nullptr); + GTextPosition insert_at(const GTextPosition&, const StringView&, const Client* = nullptr); void remove(const GTextRange&); private: @@ -201,3 +174,42 @@ private: // NOTE: This vector is null terminated. Vector m_text; }; + +class GTextDocumentUndoCommand : public GCommand { +public: + GTextDocumentUndoCommand(GTextDocument&); + virtual ~GTextDocumentUndoCommand(); + + void execute_from(const GTextDocument::Client& client) + { + m_client = &client; + redo(); + m_client = nullptr; + } + +protected: + GTextDocument& m_document; + const GTextDocument::Client* m_client { nullptr }; +}; + +class InsertTextCommand : public GTextDocumentUndoCommand { +public: + InsertTextCommand(GTextDocument&, const String&, const GTextPosition&); + virtual void undo() override; + virtual void redo() override; + +private: + String m_text; + GTextRange m_range; +}; + +class RemoveTextCommand : public GTextDocumentUndoCommand { +public: + RemoveTextCommand(GTextDocument&, const String&, const GTextRange&); + virtual void undo() override; + virtual void redo() override; + +private: + String m_text; + GTextRange m_range; +}; diff --git a/Libraries/LibGUI/GTextEditor.h b/Libraries/LibGUI/GTextEditor.h index c6ac1af6fd..a845569fb2 100644 --- a/Libraries/LibGUI/GTextEditor.h +++ b/Libraries/LibGUI/GTextEditor.h @@ -60,9 +60,11 @@ public: bool is_readonly() const { return m_readonly; } void set_readonly(bool); - bool is_automatic_indentation_enabled() const { return m_automatic_indentation_enabled; } + virtual bool is_automatic_indentation_enabled() const final { return m_automatic_indentation_enabled; } void set_automatic_indentation_enabled(bool enabled) { m_automatic_indentation_enabled = enabled; } + virtual int soft_tab_width() const final { return m_soft_tab_width; } + bool is_line_wrapping_enabled() const { return m_line_wrapping_enabled; } void set_line_wrapping_enabled(bool); @@ -202,7 +204,7 @@ private: inline void execute(Args&&... args) { auto command = make(*m_document, forward(args)...); - command->redo(); + command->execute_from(*this); m_document->add_to_undo_stack(move(command)); }