From b778804d207dc2d774e93e37b6ccfa0765417b63 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 11 Jul 2020 06:47:26 -0600 Subject: [PATCH] LibGUI: Add ModelClient abstract class and allow registering clients This solves a problem where the SortingProxyModel doesn't receive the on_update call because other code overwrote the handler later on. --- Applications/Browser/BookmarksBarWidget.cpp | 10 +++-- Applications/Browser/BookmarksBarWidget.h | 6 ++- Applications/FileManager/DirectoryView.cpp | 22 +++++----- Applications/FileManager/DirectoryView.h | 5 ++- Libraries/LibGUI/FilePicker.cpp | 27 ++++++------ Libraries/LibGUI/FilePicker.h | 6 ++- Libraries/LibGUI/Forward.h | 1 + Libraries/LibGUI/Model.cpp | 15 ++++++- Libraries/LibGUI/Model.h | 11 ++++- Libraries/LibGUI/ModelSelection.cpp | 27 +++++++++--- Libraries/LibGUI/ModelSelection.h | 18 ++++++++ Libraries/LibGUI/SortingProxyModel.cpp | 48 +++++++++++++-------- Libraries/LibGUI/SortingProxyModel.h | 8 +++- 13 files changed, 144 insertions(+), 60 deletions(-) diff --git a/Applications/Browser/BookmarksBarWidget.cpp b/Applications/Browser/BookmarksBarWidget.cpp index 0f9240d345..d7a5fc6060 100644 --- a/Applications/Browser/BookmarksBarWidget.cpp +++ b/Applications/Browser/BookmarksBarWidget.cpp @@ -88,16 +88,18 @@ BookmarksBarWidget::BookmarksBarWidget(const String& bookmarks_file, bool enable BookmarksBarWidget::~BookmarksBarWidget() { + if (m_model) + m_model->unregister_client(*this); } void BookmarksBarWidget::set_model(RefPtr model) { if (model == m_model) return; + if (m_model) + m_model->unregister_client(*this); m_model = move(model); - m_model->on_update = [&]() { - did_update_model(); - }; + m_model->register_client(*this); } void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event) @@ -106,7 +108,7 @@ void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event) update_content_size(); } -void BookmarksBarWidget::did_update_model() +void BookmarksBarWidget::on_model_update(unsigned) { for (auto* child : child_widgets()) { child->remove_from_parent(); diff --git a/Applications/Browser/BookmarksBarWidget.h b/Applications/Browser/BookmarksBarWidget.h index 96e8313fcd..0880e6bfa6 100644 --- a/Applications/Browser/BookmarksBarWidget.h +++ b/Applications/Browser/BookmarksBarWidget.h @@ -27,11 +27,13 @@ #pragma once #include +#include #include namespace Browser { -class BookmarksBarWidget final : public GUI::Widget { +class BookmarksBarWidget final : public GUI::Widget + , private GUI::ModelClient { C_OBJECT(BookmarksBarWidget) public: static BookmarksBarWidget& the(); @@ -52,7 +54,7 @@ public: private: BookmarksBarWidget(const String&, bool enabled); - virtual void did_update_model(); + virtual void on_model_update(unsigned) override; virtual void resize_event(GUI::ResizeEvent&) override; void update_content_size(); diff --git a/Applications/FileManager/DirectoryView.cpp b/Applications/FileManager/DirectoryView.cpp index 4873277dca..e188e96111 100644 --- a/Applications/FileManager/DirectoryView.cpp +++ b/Applications/FileManager/DirectoryView.cpp @@ -95,16 +95,7 @@ DirectoryView::DirectoryView() on_path_change(model().root_path()); }; - // NOTE: We're using the on_update hook on the GUI::SortingProxyModel here instead of - // the GUI::FileSystemModel's hook. This is because GUI::SortingProxyModel has already - // installed an on_update hook on the GUI::FileSystemModel internally. - // FIXME: This is an unfortunate design. We should come up with something better. - m_table_view->model()->on_update = [this] { - for_each_view_implementation([](auto& view) { - view.selection().clear(); - }); - update_statusbar(); - }; + m_model->register_client(*this); m_model->on_thumbnail_progress = [this](int done, int total) { if (on_thumbnail_progress) @@ -169,6 +160,17 @@ DirectoryView::DirectoryView() DirectoryView::~DirectoryView() { + m_model->unregister_client(*this); +} + +void DirectoryView::on_model_update(unsigned flags) +{ + if (flags & GUI::Model::UpdateFlag::InvalidateAllIndexes) { + for_each_view_implementation([](auto& view) { + view.selection().clear(); + }); + } + update_statusbar(); } void DirectoryView::set_view_mode(ViewMode mode) diff --git a/Applications/FileManager/DirectoryView.h b/Applications/FileManager/DirectoryView.h index b0c8efe3e4..1bef4e4b2b 100644 --- a/Applications/FileManager/DirectoryView.h +++ b/Applications/FileManager/DirectoryView.h @@ -34,7 +34,8 @@ #include #include -class DirectoryView final : public GUI::StackWidget { +class DirectoryView final : public GUI::StackWidget + , private GUI::ModelClient { C_OBJECT(DirectoryView) public: virtual ~DirectoryView() override; @@ -94,6 +95,8 @@ private: DirectoryView(); const GUI::FileSystemModel& model() const { return *m_model; } + virtual void on_model_update(unsigned) override; + void handle_activation(const GUI::ModelIndex&); void set_status_message(const StringView&); diff --git a/Libraries/LibGUI/FilePicker.cpp b/Libraries/LibGUI/FilePicker.cpp index d9e1f8e129..9c27cd3a9d 100644 --- a/Libraries/LibGUI/FilePicker.cpp +++ b/Libraries/LibGUI/FilePicker.cpp @@ -106,11 +106,11 @@ FilePicker::FilePicker(Mode mode, const StringView& file_name, const StringView& #endif toolbar.set_has_frame(false); - auto& location_textbox = upper_container.add(); - location_textbox.set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); - location_textbox.set_preferred_size(0, 22); - location_textbox.set_text(path); - location_textbox.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-folder.png")); + m_location_textbox = upper_container.add(); + m_location_textbox->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + m_location_textbox->set_preferred_size(0, 22); + m_location_textbox->set_text(path); + m_location_textbox->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-folder.png")); m_view = vertical_container.add(); m_view->set_model(SortingProxyModel::create(*m_model)); @@ -122,14 +122,10 @@ FilePicker::FilePicker(Mode mode, const StringView& file_name, const StringView& m_view->set_column_hidden(FileSystemModel::Column::Inode, true); m_view->set_column_hidden(FileSystemModel::Column::SymlinkTarget, true); m_model->set_root_path(path); + m_model->register_client(*this); - m_model->on_update = [&] { - location_textbox.set_text(m_model->root_path()); - clear_preview(); - }; - - location_textbox.on_return_pressed = [&] { - m_model->set_root_path(location_textbox.text()); + m_location_textbox->on_return_pressed = [this] { + m_model->set_root_path(m_location_textbox->text()); }; auto open_parent_directory_action = Action::create("Open parent directory", { Mod_Alt, Key_Up }, Gfx::Bitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"), [this](const Action&) { @@ -270,6 +266,13 @@ FilePicker::FilePicker(Mode mode, const StringView& file_name, const StringView& FilePicker::~FilePicker() { + m_model->unregister_client(*this); +} + +void FilePicker::on_model_update(unsigned) +{ + m_location_textbox->set_text(m_model->root_path()); + clear_preview(); } void FilePicker::set_preview(const LexicalPath& path) diff --git a/Libraries/LibGUI/FilePicker.h b/Libraries/LibGUI/FilePicker.h index f3d3b44d83..aaf1147ed9 100644 --- a/Libraries/LibGUI/FilePicker.h +++ b/Libraries/LibGUI/FilePicker.h @@ -31,10 +31,11 @@ #include #include #include +#include namespace GUI { -class FilePicker final : public Dialog { +class FilePicker final : public Dialog, private ModelClient { C_OBJECT(FilePicker) public: enum class Mode { @@ -55,6 +56,8 @@ private: void clear_preview(); void on_file_return(); + virtual void on_model_update(unsigned) override; + FilePicker(Mode type = Mode::Open, const StringView& file_name = "Untitled", const StringView& path = Core::StandardPaths::home_directory(), Window* parent_window = nullptr); static String ok_button_name(Mode mode) @@ -74,6 +77,7 @@ private: LexicalPath m_selected_file; RefPtr m_filename_textbox; + RefPtr m_location_textbox; RefPtr m_preview_container; RefPtr m_preview_image; RefPtr