From bd5c79aff2bb9e843179b881b59133660a4e3519 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 9 May 2019 01:24:37 +0200 Subject: [PATCH] LibGUI: Start working on a file picker dialog (GFilePicker). Have LibGUI adopt GDirectoryModel from FileManager since it fits perfectly for the needs of a file picker. --- Applications/FileManager/DirectoryView.cpp | 6 +- Applications/FileManager/DirectoryView.h | 8 +-- Applications/FileManager/Makefile | 1 - Kernel/sync.sh | 1 + .../GDirectoryModel.cpp | 30 ++++----- .../GDirectoryModel.h | 10 +-- LibGUI/GFilePicker.cpp | 65 +++++++++++++++++++ LibGUI/GFilePicker.h | 9 ++- LibGUI/Makefile | 2 + 9 files changed, 103 insertions(+), 29 deletions(-) rename Applications/FileManager/DirectoryModel.cpp => LibGUI/GDirectoryModel.cpp (92%) rename Applications/FileManager/DirectoryModel.h => LibGUI/GDirectoryModel.h (85%) create mode 100644 LibGUI/GFilePicker.cpp diff --git a/Applications/FileManager/DirectoryView.cpp b/Applications/FileManager/DirectoryView.cpp index 6d9204862c..a6177b1462 100644 --- a/Applications/FileManager/DirectoryView.cpp +++ b/Applications/FileManager/DirectoryView.cpp @@ -3,7 +3,7 @@ DirectoryView::DirectoryView(GWidget* parent) : GStackWidget(parent) - , m_model(DirectoryModel::create()) + , m_model(GDirectoryModel::create()) { set_active_widget(nullptr); m_item_view = new GItemView(this); @@ -12,9 +12,9 @@ DirectoryView::DirectoryView(GWidget* parent) m_table_view = new GTableView(this); m_table_view->set_model(GSortingProxyModel::create(m_model.copy_ref())); - m_table_view->model()->set_key_column_and_sort_order(DirectoryModel::Column::Name, GSortOrder::Ascending); + m_table_view->model()->set_key_column_and_sort_order(GDirectoryModel::Column::Name, GSortOrder::Ascending); - m_item_view->set_model_column(DirectoryModel::Column::Name); + m_item_view->set_model_column(GDirectoryModel::Column::Name); m_item_view->on_model_notification = [this] (const GModelNotification& notification) { if (notification.type() == GModelNotification::Type::ModelUpdated) { diff --git a/Applications/FileManager/DirectoryView.h b/Applications/FileManager/DirectoryView.h index 564d859237..f657999a7b 100644 --- a/Applications/FileManager/DirectoryView.h +++ b/Applications/FileManager/DirectoryView.h @@ -3,8 +3,8 @@ #include #include #include +#include #include -#include "DirectoryModel.h" class DirectoryView final : public GStackWidget { public: @@ -26,14 +26,14 @@ public: ViewMode view_mode() const { return m_view_mode; } private: - DirectoryModel& model() { return *m_model; } - const DirectoryModel& model() const { return *m_model; } + GDirectoryModel& model() { return *m_model; } + const GDirectoryModel& model() const { return *m_model; } void set_status_message(const String&); ViewMode m_view_mode { Invalid }; - Retained m_model; + Retained m_model; GTableView* m_table_view { nullptr }; GItemView* m_item_view { nullptr }; diff --git a/Applications/FileManager/Makefile b/Applications/FileManager/Makefile index 059c1a282e..b360b66d16 100644 --- a/Applications/FileManager/Makefile +++ b/Applications/FileManager/Makefile @@ -1,7 +1,6 @@ include ../../Makefile.common OBJS = \ - DirectoryModel.o \ DirectoryView.o \ main.o diff --git a/Kernel/sync.sh b/Kernel/sync.sh index ce6013398a..705e14cc97 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -79,6 +79,7 @@ cp -v ../Shell/Shell mnt/bin/Shell ln -s Shell mnt/bin/sh cp -v kernel.map mnt/ cp -v ../Demos/HelloWorld/HelloWorld mnt/bin/HelloWorld +ln -s HelloWorld mnt/bin/hw # Run local sync script, if it exists if [ -f sync-local.sh ]; then diff --git a/Applications/FileManager/DirectoryModel.cpp b/LibGUI/GDirectoryModel.cpp similarity index 92% rename from Applications/FileManager/DirectoryModel.cpp rename to LibGUI/GDirectoryModel.cpp index 42a25a453e..9c0c32570f 100644 --- a/Applications/FileManager/DirectoryModel.cpp +++ b/LibGUI/GDirectoryModel.cpp @@ -1,4 +1,4 @@ -#include "DirectoryModel.h" +#include "GDirectoryModel.h" #include #include #include @@ -20,7 +20,7 @@ static CLockable>>& thumbnail_cache() int thumbnail_thread(void* model_ptr) { - auto& model = *(DirectoryModel*)model_ptr; + auto& model = *(GDirectoryModel*)model_ptr; for (;;) { sleep(1); Vector to_generate; @@ -54,7 +54,7 @@ int thumbnail_thread(void* model_ptr) } } -DirectoryModel::DirectoryModel() +GDirectoryModel::GDirectoryModel() { create_thread(thumbnail_thread, this); @@ -76,21 +76,21 @@ DirectoryModel::DirectoryModel() endgrent(); } -DirectoryModel::~DirectoryModel() +GDirectoryModel::~GDirectoryModel() { } -int DirectoryModel::row_count(const GModelIndex&) const +int GDirectoryModel::row_count(const GModelIndex&) const { return m_directories.size() + m_files.size(); } -int DirectoryModel::column_count(const GModelIndex&) const +int GDirectoryModel::column_count(const GModelIndex&) const { return Column::__Count; } -String DirectoryModel::column_name(int column) const +String GDirectoryModel::column_name(int column) const { switch (column) { case Column::Icon: return ""; @@ -104,7 +104,7 @@ String DirectoryModel::column_name(int column) const ASSERT_NOT_REACHED(); } -GModel::ColumnMetadata DirectoryModel::column_metadata(int column) const +GModel::ColumnMetadata GDirectoryModel::column_metadata(int column) const { switch (column) { case Column::Icon: return { 16, TextAlignment::Center }; @@ -118,7 +118,7 @@ GModel::ColumnMetadata DirectoryModel::column_metadata(int column) const ASSERT_NOT_REACHED(); } -GIcon DirectoryModel::icon_for(const Entry& entry) const +GIcon GDirectoryModel::icon_for(const Entry& entry) const { if (S_ISDIR(entry.mode)) return m_directory_icon; @@ -184,7 +184,7 @@ static String permission_string(mode_t mode) return builder.to_string(); } -String DirectoryModel::name_for_uid(uid_t uid) const +String GDirectoryModel::name_for_uid(uid_t uid) const { auto it = m_user_names.find(uid); if (it == m_user_names.end()) @@ -192,7 +192,7 @@ String DirectoryModel::name_for_uid(uid_t uid) const return (*it).value; } -String DirectoryModel::name_for_gid(uid_t gid) const +String GDirectoryModel::name_for_gid(uid_t gid) const { auto it = m_user_names.find(gid); if (it == m_user_names.end()) @@ -200,7 +200,7 @@ String DirectoryModel::name_for_gid(uid_t gid) const return (*it).value; } -GVariant DirectoryModel::data(const GModelIndex& index, Role role) const +GVariant GDirectoryModel::data(const GModelIndex& index, Role role) const { ASSERT(is_valid(index)); auto& entry = this->entry(index.row()); @@ -233,7 +233,7 @@ GVariant DirectoryModel::data(const GModelIndex& index, Role role) const return { }; } -void DirectoryModel::update() +void GDirectoryModel::update() { DIR* dirp = opendir(m_path.characters()); if (!dirp) { @@ -271,7 +271,7 @@ void DirectoryModel::update() did_update(); } -void DirectoryModel::open(const String& a_path) +void GDirectoryModel::open(const String& a_path) { FileSystemPath canonical_path(a_path); auto path = canonical_path.string(); @@ -286,7 +286,7 @@ void DirectoryModel::open(const String& a_path) set_selected_index(index(0, 0)); } -void DirectoryModel::activate(const GModelIndex& index) +void GDirectoryModel::activate(const GModelIndex& index) { if (!index.is_valid()) return; diff --git a/Applications/FileManager/DirectoryModel.h b/LibGUI/GDirectoryModel.h similarity index 85% rename from Applications/FileManager/DirectoryModel.h rename to LibGUI/GDirectoryModel.h index 7a3c3e168c..7bc5d38aaa 100644 --- a/Applications/FileManager/DirectoryModel.h +++ b/LibGUI/GDirectoryModel.h @@ -4,11 +4,11 @@ #include #include -class DirectoryModel final : public GModel { +class GDirectoryModel final : public GModel { friend int thumbnail_thread(void*); public: - static Retained create() { return adopt(*new DirectoryModel); } - virtual ~DirectoryModel() override; + static Retained create() { return adopt(*new GDirectoryModel); } + virtual ~GDirectoryModel() override; enum Column { Icon = 0, @@ -36,7 +36,7 @@ public: Function on_thumbnail_progress; private: - DirectoryModel(); + GDirectoryModel(); String name_for_uid(uid_t) const; String name_for_gid(gid_t) const; @@ -51,7 +51,7 @@ private: mutable RetainPtr thumbnail; bool is_directory() const { return S_ISDIR(mode); } bool is_executable() const { return mode & S_IXUSR; } - String full_path(const DirectoryModel& model) const { return String::format("%s/%s", model.path().characters(), name.characters()); } + String full_path(const GDirectoryModel& model) const { return String::format("%s/%s", model.path().characters(), name.characters()); } }; const Entry& entry(int index) const diff --git a/LibGUI/GFilePicker.cpp b/LibGUI/GFilePicker.cpp new file mode 100644 index 0000000000..bf4c61c41d --- /dev/null +++ b/LibGUI/GFilePicker.cpp @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include + +GFilePicker::GFilePicker(const String& path, CObject* parent) + : GDialog(parent) + , m_model(GDirectoryModel::create()) +{ + set_title("GFilePicker"); + set_rect(200, 200, 400, 300); + set_main_widget(new GWidget); + main_widget()->set_layout(make(Orientation::Vertical)); + main_widget()->layout()->set_margins({ 4, 0, 4, 0 }); + main_widget()->layout()->set_spacing(4); + main_widget()->set_fill_with_background_color(true); + main_widget()->set_background_color(Color::LightGray); + m_view = new GTableView(main_widget()); + m_view->set_model(*m_model); + model().open("/"); + + auto* lower_container = new GWidget(main_widget()); + lower_container->set_layout(make(Orientation::Vertical)); + lower_container->layout()->set_spacing(4); + lower_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + lower_container->set_preferred_size({ 0, 60 }); + + auto* filename_container = new GWidget(lower_container); + filename_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + filename_container->set_preferred_size({ 0, 20 }); + filename_container->set_layout(make(Orientation::Horizontal)); + auto* filename_label = new GLabel("File name:", filename_container); + filename_label->set_text_alignment(TextAlignment::CenterLeft); + filename_label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + filename_label->set_preferred_size({ 60, 0 }); + auto* filename_textbox = new GTextBox(filename_container); + + auto* button_container = new GWidget(lower_container); + button_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + button_container->set_preferred_size({ 0, 20 }); + button_container->set_layout(make(Orientation::Horizontal)); + button_container->layout()->set_spacing(4); + + auto* cancel_button = new GButton(button_container); + cancel_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + cancel_button->set_preferred_size({ 80, 0 }); + cancel_button->set_caption("Cancel"); + cancel_button->on_click = [this] (auto&) { + done(ExecCancel); + }; + + auto* ok_button = new GButton(button_container); + ok_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + ok_button->set_preferred_size({ 80, 0 }); + ok_button->set_caption("OK"); + ok_button->on_click = [this] (auto&) { + done(ExecOK); + }; +} + +GFilePicker::~GFilePicker() +{ +} diff --git a/LibGUI/GFilePicker.h b/LibGUI/GFilePicker.h index 5e1c830ba6..e470d71227 100644 --- a/LibGUI/GFilePicker.h +++ b/LibGUI/GFilePicker.h @@ -1,11 +1,18 @@ #include +#include + +class GDirectoryModel; class GFilePicker final : public GDialog { public: - GFilePicker(); + GFilePicker(const String& path = "/", CObject* parent = nullptr); virtual ~GFilePicker() override; virtual const char* class_name() const override { return "GFilePicker"; } private: + GDirectoryModel& model() { return *m_model; } + + GTableView* m_view { nullptr }; + Retained m_model; }; diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 9e27ced8fd..766cc49db9 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -49,6 +49,8 @@ LIBGUI_OBJS = \ GFrame.o \ GTreeView.o \ GFileSystemModel.o \ + GFilePicker.o \ + GDirectoryModel.o \ GSplitter.o \ GSpinBox.o \ GGroupBox.o \