From 2c6a597d7767d38fc5c8e743dd57f13733c1287f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 30 Mar 2019 03:27:25 +0100 Subject: [PATCH] FileManager: Make the tree view follow the directory view navigations. --- AK/FileSystemPath.cpp | 1 + AK/FileSystemPath.h | 3 +++ Applications/FileManager/main.cpp | 5 ++++- LibGUI/GAbstractView.cpp | 4 ++++ LibGUI/GAbstractView.h | 3 +-- LibGUI/GFileSystemModel.cpp | 24 ++++++++++++++++++++++++ LibGUI/GFileSystemModel.h | 1 + LibGUI/GModel.cpp | 3 +++ LibGUI/GTreeView.cpp | 29 +++++++++++++++++++++++++++++ LibGUI/GTreeView.h | 2 ++ 10 files changed, 72 insertions(+), 3 deletions(-) diff --git a/AK/FileSystemPath.cpp b/AK/FileSystemPath.cpp index 2a3a556d27..971bbf52bd 100644 --- a/AK/FileSystemPath.cpp +++ b/AK/FileSystemPath.cpp @@ -40,6 +40,7 @@ bool FileSystemPath::canonicalize(bool resolve_symbolic_links) builder.append('/'); builder.append(cpart); } + m_parts = move(canonical_parts); m_string = builder.to_string(); return true; } diff --git a/AK/FileSystemPath.h b/AK/FileSystemPath.h index d56625dcaf..64827157a7 100644 --- a/AK/FileSystemPath.h +++ b/AK/FileSystemPath.h @@ -14,9 +14,12 @@ public: String basename() const { return m_basename; } + const Vector& parts() const { return m_parts; } + private: bool canonicalize(bool resolve_symbolic_links = false); + Vector m_parts; String m_string; String m_basename; bool m_is_valid { false }; diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index 708a6c9aec..1b8ba22f1e 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -166,9 +166,12 @@ int main(int argc, char** argv) main_toolbar->add_action(view_as_icons_action.copy_ref()); main_toolbar->add_action(view_as_table_action.copy_ref()); - directory_view->on_path_change = [window, location_textbox] (const String& new_path) { + directory_view->on_path_change = [window, location_textbox, &file_system_model, tree_view] (const String& new_path) { window->set_title(String::format("FileManager: %s", new_path.characters())); location_textbox->set_text(new_path); + file_system_model->set_selected_index(file_system_model->index(new_path)); + tree_view->scroll_into_view(file_system_model->selected_index(), Orientation::Vertical); + tree_view->update(); }; directory_view->on_status_message = [statusbar] (String message) { diff --git a/LibGUI/GAbstractView.cpp b/LibGUI/GAbstractView.cpp index b1f64ae7d4..5c2c704342 100644 --- a/LibGUI/GAbstractView.cpp +++ b/LibGUI/GAbstractView.cpp @@ -35,3 +35,7 @@ void GAbstractView::did_update_model() { model_notification(GModelNotification(GModelNotification::ModelUpdated)); } + +void GAbstractView::did_update_selection() +{ +} diff --git a/LibGUI/GAbstractView.h b/LibGUI/GAbstractView.h index 99fa48e9cd..5048d26048 100644 --- a/LibGUI/GAbstractView.h +++ b/LibGUI/GAbstractView.h @@ -14,10 +14,9 @@ public: GModel* model() { return m_model.ptr(); } const GModel* model() const { return m_model.ptr(); } - void scroll_into_view(const GModelIndex&, Orientation); - virtual bool accepts_focus() const override { return true; } virtual void did_update_model(); + virtual void did_update_selection(); Function on_model_notification; diff --git a/LibGUI/GFileSystemModel.cpp b/LibGUI/GFileSystemModel.cpp index b13b863838..b7500df2fb 100644 --- a/LibGUI/GFileSystemModel.cpp +++ b/LibGUI/GFileSystemModel.cpp @@ -92,6 +92,30 @@ struct GFileSystemModel::Node { } }; +GModelIndex GFileSystemModel::index(const String& path) const +{ + FileSystemPath canonical_path(path); + const Node* node = m_root; + if (canonical_path.string() == "/") + return m_root->index(*this); + for (int i = 0; i < canonical_path.parts().size(); ++i) { + auto& part = canonical_path.parts()[i]; + bool found = false; + for (auto& child : node->children) { + if (child->name == part) { + node = child; + found = true; + if (i == canonical_path.parts().size() - 1) + return node->index(*this); + break; + } + } + if (!found) + return { }; + } + return { }; +} + String GFileSystemModel::path(const GModelIndex& index) const { if (!index.is_valid()) diff --git a/LibGUI/GFileSystemModel.h b/LibGUI/GFileSystemModel.h index 6e409fc4e0..1169f467de 100644 --- a/LibGUI/GFileSystemModel.h +++ b/LibGUI/GFileSystemModel.h @@ -15,6 +15,7 @@ public: String root_path() const { return m_root_path; } String path(const GModelIndex&) const; + GModelIndex index(const String& path) const; virtual int row_count(const GModelIndex& = GModelIndex()) const override; virtual int column_count(const GModelIndex& = GModelIndex()) const override; diff --git a/LibGUI/GModel.cpp b/LibGUI/GModel.cpp index 4f7742f0da..0447b27d02 100644 --- a/LibGUI/GModel.cpp +++ b/LibGUI/GModel.cpp @@ -41,6 +41,9 @@ void GModel::set_selected_index(const GModelIndex& index) m_selected_index = index; if (on_selection_changed) on_selection_changed(index); + for_each_view([] (auto& view) { + view.did_update_selection(); + }); if (m_activates_on_selection && is_valid(index)) activate(index); } diff --git a/LibGUI/GTreeView.cpp b/LibGUI/GTreeView.cpp index b91c35ec6d..475e3cdd81 100644 --- a/LibGUI/GTreeView.cpp +++ b/LibGUI/GTreeView.cpp @@ -270,3 +270,32 @@ void GTreeView::paint_event(GPaintEvent& event) return IterationDecision::Continue; }); } + +void GTreeView::scroll_into_view(const GModelIndex& a_index, Orientation orientation) +{ + if (!a_index.is_valid()) + return; + Rect found_rect; + traverse_in_paint_order([&] (const GModelIndex& index, const Rect& rect, int) { + if (index == a_index) { + found_rect = rect; + return IterationDecision::Abort; + } + return IterationDecision::Continue; + }); + GScrollableWidget::scroll_into_view(found_rect, orientation); +} + +void GTreeView::did_update_selection() +{ + ASSERT(model()); + auto& model = *this->model(); + auto index = model.selected_index(); + if (!index.is_valid()) + return; + auto parent = index.parent(); + while (parent.is_valid()) { + ensure_metadata_for_index(parent).open = true; + parent = parent.parent(); + } +} diff --git a/LibGUI/GTreeView.h b/LibGUI/GTreeView.h index 3b251ac58f..6bf92778e8 100644 --- a/LibGUI/GTreeView.h +++ b/LibGUI/GTreeView.h @@ -7,6 +7,7 @@ public: explicit GTreeView(GWidget*); virtual ~GTreeView() override; + virtual void scroll_into_view(const GModelIndex&, Orientation); virtual const char* class_name() const override { return "GTreeView"; } GModelIndex index_at_content_position(const Point&) const; @@ -14,6 +15,7 @@ public: protected: virtual void paint_event(GPaintEvent&) override; virtual void mousedown_event(GMouseEvent&) override; + virtual void did_update_selection() override; private: int item_height() const { return 16; }