summaryrefslogtreecommitdiff
path: root/Applications/FileManager
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@gmail.com>2020-01-10 18:58:00 +0300
committerAndreas Kling <awesomekling@gmail.com>2020-01-10 17:45:59 +0100
commitfdeb91e000f57407334c7cfdd11ccd7c97dd51c6 (patch)
tree1e68a3045aebeb9e3bd04ea2eac5298651540b6d /Applications/FileManager
parent0f18a16e2c855a99e5c261793a8d36565b410a72 (diff)
downloadserenity-fdeb91e000f57407334c7cfdd11ccd7c97dd51c6.zip
LibGUI+FileManager: Merge GDirectoryModel into GFileSystemModel
We used to have two different models for displaying file system contents: the FileManager-grade table-like directory model, which exposed rich data (such as file icons with integrated image previews) about contents of a single directory, and the tree-like GFileSystemModel, which only exposed a tree of file names with very basic info about them. This commit unifies the two. The new GFileSystemModel can be used both as a tree-like and as a table-like model, or in fact in both ways simultaneously. It exposes rich data about a file system subtree rooted at the given root. The users of the two previous models are all ported to use this new model.
Diffstat (limited to 'Applications/FileManager')
-rw-r--r--Applications/FileManager/DirectoryView.cpp43
-rw-r--r--Applications/FileManager/DirectoryView.h10
-rw-r--r--Applications/FileManager/PropertiesDialog.cpp9
-rw-r--r--Applications/FileManager/PropertiesDialog.h6
-rw-r--r--Applications/FileManager/main.cpp44
5 files changed, 60 insertions, 52 deletions
diff --git a/Applications/FileManager/DirectoryView.cpp b/Applications/FileManager/DirectoryView.cpp
index 9de5fa4b92..928a0a1e90 100644
--- a/Applications/FileManager/DirectoryView.cpp
+++ b/Applications/FileManager/DirectoryView.cpp
@@ -27,13 +27,13 @@ void DirectoryView::handle_activation(const GModelIndex& index)
if (!index.is_valid())
return;
dbgprintf("on activation: %d,%d, this=%p, m_model=%p\n", index.row(), index.column(), this, m_model.ptr());
- auto& entry = model().entry(index.row());
- auto path = canonicalized_path(String::format("%s/%s", model().path().characters(), entry.name.characters()));
- if (entry.is_directory()) {
+ auto& node = model().node(index);
+ auto path = node.full_path(model());
+ if (node.is_directory()) {
open(path);
return;
}
- if (entry.is_executable()) {
+ if (node.is_executable()) {
if (fork() == 0) {
int rc = execl(path.characters(), path.characters(), nullptr);
if (rc < 0)
@@ -83,7 +83,7 @@ void DirectoryView::handle_activation(const GModelIndex& index)
DirectoryView::DirectoryView(GWidget* parent)
: GStackWidget(parent)
- , m_model(GDirectoryModel::create())
+ , m_model(GFileSystemModel::create())
{
set_active_widget(nullptr);
m_item_view = GItemView::construct(this);
@@ -92,22 +92,25 @@ DirectoryView::DirectoryView(GWidget* parent)
m_table_view = GTableView::construct(this);
m_table_view->set_model(GSortingProxyModel::create(m_model));
- m_table_view->model()->set_key_column_and_sort_order(GDirectoryModel::Column::Name, GSortOrder::Ascending);
+ m_table_view->model()->set_key_column_and_sort_order(GFileSystemModel::Column::Name, GSortOrder::Ascending);
- m_item_view->set_model_column(GDirectoryModel::Column::Name);
+ m_item_view->set_model_column(GFileSystemModel::Column::Name);
- m_model->on_path_change = [this] {
+ m_model->on_root_path_change = [this] {
m_table_view->selection().clear();
m_item_view->selection().clear();
if (on_path_change)
- on_path_change(model().path());
+ on_path_change(model().root_path());
};
// NOTE: We're using the on_update hook on the GSortingProxyModel here instead of
- // the GDirectoryModel's hook. This is because GSortingProxyModel has already
- // installed an on_update hook on the GDirectoryModel internally.
+ // the GFileSystemModel's hook. This is because GSortingProxyModel has already
+ // installed an on_update hook on the GFileSystemModel 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();
};
@@ -180,7 +183,7 @@ void DirectoryView::add_path_to_history(const StringView& path)
void DirectoryView::open(const StringView& path)
{
add_path_to_history(path);
- model().open(path);
+ model().set_root_path(path);
}
void DirectoryView::set_status_message(const StringView& message)
@@ -191,9 +194,9 @@ void DirectoryView::set_status_message(const StringView& message)
void DirectoryView::open_parent_directory()
{
- auto path = String::format("%s/..", model().path().characters());
+ auto path = String::format("%s/..", model().root_path().characters());
add_path_to_history(path);
- model().open(path);
+ model().set_root_path(path);
}
void DirectoryView::refresh()
@@ -205,24 +208,25 @@ void DirectoryView::open_previous_directory()
{
if (m_path_history_position > 0) {
m_path_history_position--;
- model().open(m_path_history[m_path_history_position]);
+ model().set_root_path(m_path_history[m_path_history_position]);
}
}
void DirectoryView::open_next_directory()
{
if (m_path_history_position < m_path_history.size() - 1) {
m_path_history_position++;
- model().open(m_path_history[m_path_history_position]);
+ model().set_root_path(m_path_history[m_path_history_position]);
}
}
void DirectoryView::update_statusbar()
{
+ size_t total_size = model().node({}).total_size;
if (current_view().selection().is_empty()) {
set_status_message(String::format("%d item%s (%s)",
model().row_count(),
model().row_count() != 1 ? "s" : "",
- human_readable_size(model().bytes_in_files()).characters()));
+ human_readable_size(total_size).characters()));
return;
}
@@ -230,8 +234,9 @@ void DirectoryView::update_statusbar()
size_t selected_byte_count = 0;
current_view().selection().for_each_index([&](auto& index) {
- auto size_index = current_view().model()->index(index.row(), GDirectoryModel::Column::Size);
- auto file_size = current_view().model()->data(size_index).to_int();
+ auto& model = *current_view().model();
+ auto size_index = model.sibling(index.row(), GFileSystemModel::Column::Size, model.parent_index(index));
+ auto file_size = model.data(size_index).to_int();
selected_byte_count += file_size;
});
diff --git a/Applications/FileManager/DirectoryView.h b/Applications/FileManager/DirectoryView.h
index e9feeca8ba..2e314f8e60 100644
--- a/Applications/FileManager/DirectoryView.h
+++ b/Applications/FileManager/DirectoryView.h
@@ -1,7 +1,7 @@
#pragma once
#include <AK/Vector.h>
-#include <LibGUI/GDirectoryModel.h>
+#include <LibGUI/GFileSystemModel.h>
#include <LibGUI/GItemView.h>
#include <LibGUI/GStackWidget.h>
#include <LibGUI/GTableView.h>
@@ -13,7 +13,7 @@ public:
virtual ~DirectoryView() override;
void open(const StringView& path);
- String path() const { return model().path(); }
+ String path() const { return model().root_path(); }
void open_parent_directory();
void open_previous_directory();
void open_next_directory();
@@ -55,11 +55,11 @@ public:
callback(*m_item_view);
}
- GDirectoryModel& model() { return *m_model; }
+ GFileSystemModel& model() { return *m_model; }
private:
explicit DirectoryView(GWidget* parent);
- const GDirectoryModel& model() const { return *m_model; }
+ const GFileSystemModel& model() const { return *m_model; }
void handle_activation(const GModelIndex&);
@@ -68,7 +68,7 @@ private:
ViewMode m_view_mode { Invalid };
- NonnullRefPtr<GDirectoryModel> m_model;
+ NonnullRefPtr<GFileSystemModel> m_model;
int m_path_history_position { 0 };
Vector<String> m_path_history;
void add_path_to_history(const StringView& path);
diff --git a/Applications/FileManager/PropertiesDialog.cpp b/Applications/FileManager/PropertiesDialog.cpp
index bde03b9e53..9b7a67029b 100644
--- a/Applications/FileManager/PropertiesDialog.cpp
+++ b/Applications/FileManager/PropertiesDialog.cpp
@@ -9,7 +9,7 @@
#include <stdio.h>
#include <unistd.h>
-PropertiesDialog::PropertiesDialog(GDirectoryModel& model, String path, bool disable_rename, CObject* parent)
+PropertiesDialog::PropertiesDialog(GFileSystemModel& model, String path, bool disable_rename, CObject* parent)
: GDialog(parent)
, m_model(model)
{
@@ -92,8 +92,8 @@ PropertiesDialog::PropertiesDialog(GDirectoryModel& model, String path, bool dis
properties.append({ "Size:", String::format("%zu bytes", st.st_size) });
properties.append({ "Owner:", String::format("%s (%lu)", user_pw->pw_name, static_cast<u32>(user_pw->pw_uid)) });
properties.append({ "Group:", String::format("%s (%lu)", group_pw->pw_name, static_cast<u32>(group_pw->pw_uid)) });
- properties.append({ "Created at:", GDirectoryModel::timestamp_string(st.st_ctime) });
- properties.append({ "Last modified:", GDirectoryModel::timestamp_string(st.st_mtime) });
+ properties.append({ "Created at:", GFileSystemModel::timestamp_string(st.st_ctime) });
+ properties.append({ "Last modified:", GFileSystemModel::timestamp_string(st.st_mtime) });
make_property_value_pairs(properties, general_tab);
@@ -127,7 +127,6 @@ PropertiesDialog::~PropertiesDialog() {}
void PropertiesDialog::update()
{
- m_model.update();
m_icon->set_icon(const_cast<GraphicsBitmap*>(m_model.icon_for_file(m_mode, m_name).bitmap_for_size(32)));
set_title(String::format("Properties of \"%s\"", m_name.characters()));
}
@@ -146,7 +145,7 @@ void PropertiesDialog::permission_changed(mode_t mask, bool set)
String PropertiesDialog::make_full_path(String name)
{
- return String::format("%s/%s", m_model.path().characters(), name.characters());
+ return String::format("%s/%s", m_model.root_path().characters(), name.characters());
}
bool PropertiesDialog::apply_changes()
diff --git a/Applications/FileManager/PropertiesDialog.h b/Applications/FileManager/PropertiesDialog.h
index d4f3e6d709..7561eee805 100644
--- a/Applications/FileManager/PropertiesDialog.h
+++ b/Applications/FileManager/PropertiesDialog.h
@@ -4,7 +4,7 @@
#include <LibCore/CFile.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GDialog.h>
-#include <LibGUI/GDirectoryModel.h>
+#include <LibGUI/GFileSystemModel.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GTextBox.h>
@@ -14,7 +14,7 @@ public:
virtual ~PropertiesDialog() override;
private:
- explicit PropertiesDialog(GDirectoryModel&, String, bool disable_rename, CObject* parent = nullptr);
+ PropertiesDialog(GFileSystemModel&, String, bool disable_rename, CObject* parent = nullptr);
struct PropertyValuePair {
String property;
@@ -58,7 +58,7 @@ private:
void update();
String make_full_path(String name);
- GDirectoryModel& m_model;
+ GFileSystemModel& m_model;
RefPtr<GButton> m_apply_button;
RefPtr<GTextBox> m_name_box;
RefPtr<GLabel> m_icon;
diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp
index 118d6ae6ef..d3f64ba9f8 100644
--- a/Applications/FileManager/main.cpp
+++ b/Applications/FileManager/main.cpp
@@ -70,10 +70,17 @@ int main(int argc, char** argv)
auto splitter = GSplitter::construct(Orientation::Horizontal, widget);
auto tree_view = GTreeView::construct(splitter);
- auto file_system_model = GFileSystemModel::create("/", GFileSystemModel::Mode::DirectoriesOnly);
- tree_view->set_model(file_system_model);
+ auto directories_model = GFileSystemModel::create("/", GFileSystemModel::Mode::DirectoriesOnly);
+ tree_view->set_model(directories_model);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Icon, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Size, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Owner, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Group, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Permissions, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::ModificationTime, true);
+ tree_view->set_column_hidden(GFileSystemModel::Column::Inode, true);
tree_view->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
- tree_view->set_preferred_size(200, 0);
+ tree_view->set_preferred_size(150, 0);
auto directory_view = DirectoryView::construct(splitter);
auto statusbar = GStatusBar::construct(widget);
@@ -91,7 +98,7 @@ int main(int argc, char** argv)
};
auto refresh_tree_view = [&] {
- file_system_model->update();
+ directories_model->update();
auto current_path = directory_view->path();
@@ -100,17 +107,13 @@ int main(int argc, char** argv)
while (lstat(current_path.characters(), &st) != 0) {
directory_view->open_parent_directory();
current_path = directory_view->path();
- if (current_path == file_system_model->root_path()) {
+ if (current_path == directories_model->root_path()) {
break;
}
}
- // not exactly sure why i have to reselect the root node first, but the index() fails if I dont
- auto root_index = file_system_model->index(file_system_model->root_path());
- tree_view->selection().set(root_index);
-
- // reselect the existing folder in the tree
- auto new_index = file_system_model->index(current_path);
+ // Reselect the existing folder in the tree.
+ auto new_index = directories_model->index(current_path, GFileSystemModel::Column::Name);
tree_view->selection().set(new_index);
tree_view->scroll_into_view(new_index, Orientation::Vertical);
tree_view->update();
@@ -175,7 +178,8 @@ int main(int argc, char** argv)
auto& view = directory_view->current_view();
auto& model = *view.model();
view.selection().for_each_index([&](const GModelIndex& index) {
- auto name_index = model.index(index.row(), GDirectoryModel::Column::Name);
+ auto parent_index = model.parent_index(index);
+ auto name_index = model.index(index.row(), GFileSystemModel::Column::Name, parent_index);
auto path = model.data(name_index, GModel::Role::Custom).to_string();
paths.append(path);
});
@@ -186,7 +190,7 @@ int main(int argc, char** argv)
Vector<String> paths;
auto& view = tree_view;
view->selection().for_each_index([&](const GModelIndex& index) {
- paths.append(file_system_model->path(index));
+ paths.append(directories_model->full_path(index));
});
return paths;
};
@@ -254,9 +258,10 @@ int main(int argc, char** argv)
path = directory_view->path();
selected = selected_file_paths();
} else {
- path = file_system_model->path(tree_view->selection().first());
+ path = directories_model->full_path(tree_view->selection().first());
selected = tree_view_selected_file_paths();
}
+
RefPtr<PropertiesDialog> properties;
if (selected.is_empty()) {
properties = PropertiesDialog::construct(model, path, true, window);
@@ -413,7 +418,7 @@ int main(int argc, char** argv)
directory_view->on_path_change = [&](const String& new_path) {
window->set_title(String::format("File Manager: %s", new_path.characters()));
location_textbox->set_text(new_path);
- auto new_index = file_system_model->index(new_path);
+ auto new_index = directories_model->index(new_path, GFileSystemModel::Column::Name);
if (new_index.is_valid()) {
tree_view->selection().set(new_index);
tree_view->scroll_into_view(new_index, Orientation::Vertical);
@@ -482,20 +487,19 @@ int main(int argc, char** argv)
directory_view->on_context_menu_request = [&](const GAbstractView&, const GModelIndex& index, const GContextMenuEvent& event) {
if (index.is_valid()) {
- auto& entry = directory_view->model().entry(index.row());
+ auto& node = directory_view->model().node(index);
- if (entry.is_directory()) {
+ if (node.is_directory())
directory_context_menu->popup(event.screen_position());
- } else {
+ else
file_context_menu->popup(event.screen_position());
- }
} else {
directory_view_context_menu->popup(event.screen_position());
}
};
tree_view->on_selection_change = [&] {
- auto path = file_system_model->path(tree_view->selection().first());
+ auto path = directories_model->full_path(tree_view->selection().first());
if (directory_view->path() == path)
return;
directory_view->open(path);