summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTommy Nguyen <remyabel@gmail.com>2019-12-12 04:49:17 -0500
committerAndreas Kling <awesomekling@gmail.com>2019-12-12 11:19:02 +0100
commit17f3948b153e50db6226834ac34d22ca88f6d7c5 (patch)
treeada194cbb0e77c065c8e661c922381f11686ffe7
parentf26548395e919c69e6332952672f0633aa9f33df (diff)
downloadserenity-17f3948b153e50db6226834ac34d22ca88f6d7c5.zip
FileManager: Add a context menu to the TreeView
This adds a context menu to the TreeView with the ability to copy/paste, create new directories, etc. This does not address the issue mentioned above where using the global application shortcut does not apply to whatever view has focus.
-rw-r--r--Applications/FileManager/main.cpp109
1 files changed, 84 insertions, 25 deletions
diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp
index ccbd71e013..53e20ab85b 100644
--- a/Applications/FileManager/main.cpp
+++ b/Applications/FileManager/main.cpp
@@ -89,18 +89,21 @@ int main(int argc, char** argv)
directory_view->open(location_textbox->text());
};
- tree_view->on_selection_change = [&] {
- auto path = file_system_model->path(tree_view->selection().first());
- if (directory_view->path() == path)
- return;
- directory_view->open(path);
- };
-
auto refresh_tree_view = [&] {
file_system_model->update();
auto current_path = directory_view->path();
+ struct stat st;
+ // If the directory no longer exists, we find a parent that does.
+ 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()) {
+ 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);
@@ -114,6 +117,12 @@ int main(int argc, char** argv)
directory_view->refresh();
};
+ auto directory_context_menu = GMenu::construct("Directory View Directory");
+ auto file_context_menu = GMenu::construct("Directory View File");
+ auto directory_view_context_menu = GMenu::construct("Directory View");
+ auto tree_view_directory_context_menu = GMenu::construct("Tree View Directory");
+ auto tree_view_context_menu = GMenu::construct("Tree View");
+
auto open_parent_directory_action = GAction::create("Open parent directory", { Mod_Alt, Key_Up }, GraphicsBitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"), [&](const GAction&) {
directory_view->open_parent_directory();
});
@@ -172,8 +181,22 @@ int main(int argc, char** argv)
return paths;
};
- auto copy_action = GCommonActions::make_copy_action([&](const GAction&) {
- auto paths = selected_file_paths();
+ auto tree_view_selected_file_paths = [&] {
+ Vector<String> paths;
+ auto& view = tree_view;
+ view->selection().for_each_index([&](const GModelIndex& index) {
+ paths.append(file_system_model->path(index));
+ });
+ return paths;
+ };
+
+ auto copy_action = GCommonActions::make_copy_action([&](const GAction& action) {
+ Vector<String> paths;
+ if (action.activator() == directory_context_menu) {
+ paths = selected_file_paths();
+ } else {
+ paths = tree_view_selected_file_paths();
+ }
if (paths.is_empty())
return;
StringBuilder copy_text;
@@ -206,6 +229,8 @@ int main(int argc, char** argv)
auto error_message = String::format("Could not paste %s.",
current_path.characters());
GMessageBox::show(error_message, "File Manager", GMessageBox::Type::Error);
+ } else {
+ refresh_tree_view();
}
}
});
@@ -216,13 +241,20 @@ int main(int argc, char** argv)
};
auto properties_action
- = GAction::create("Properties...", { Mod_Alt, Key_Return }, GraphicsBitmap::load_from_file("/res/icons/16x16/properties.png"), [&](auto&) {
+ = GAction::create("Properties...", { Mod_Alt, Key_Return }, GraphicsBitmap::load_from_file("/res/icons/16x16/properties.png"), [&](const GAction& action) {
auto& model = directory_view->model();
- auto selected = selected_file_paths();
-
+ String path;
+ Vector<String> selected;
+ if (action.activator() == directory_context_menu) {
+ path = directory_view->path();
+ selected = selected_file_paths();
+ } else {
+ path = file_system_model->path(tree_view->selection().first());
+ selected = tree_view_selected_file_paths();
+ }
RefPtr<PropertiesDialog> properties;
if (selected.is_empty()) {
- properties = PropertiesDialog::construct(model, directory_view->path(), true, window);
+ properties = PropertiesDialog::construct(model, path, true, window);
} else {
properties = PropertiesDialog::construct(model, selected.first(), false, window);
}
@@ -233,8 +265,13 @@ int main(int argc, char** argv)
enum class ConfirmBeforeDelete { No,
Yes };
- auto do_delete = [&](ConfirmBeforeDelete confirm) {
- auto paths = selected_file_paths();
+ auto do_delete = [&](ConfirmBeforeDelete confirm, const GAction& action) {
+ Vector<String> paths;
+ if (action.activator() == directory_context_menu) {
+ paths = selected_file_paths();
+ } else {
+ paths = tree_view_selected_file_paths();
+ }
if (paths.is_empty())
return;
{
@@ -299,12 +336,12 @@ int main(int argc, char** argv)
}
};
- auto force_delete_action = GAction::create("Delete without confirmation", { Mod_Shift, Key_Delete }, [&](const GAction&) {
- do_delete(ConfirmBeforeDelete::No);
+ auto force_delete_action = GAction::create("Delete without confirmation", { Mod_Shift, Key_Delete }, [&](const GAction& action) {
+ do_delete(ConfirmBeforeDelete::No, action);
});
- auto delete_action = GCommonActions::make_delete_action([&](const GAction&) {
- do_delete(ConfirmBeforeDelete::Yes);
+ auto delete_action = GCommonActions::make_delete_action([&](const GAction& action) {
+ do_delete(ConfirmBeforeDelete::Yes, action);
});
delete_action->set_enabled(false);
@@ -372,9 +409,11 @@ int main(int argc, char** argv)
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);
- tree_view->selection().set(new_index);
- tree_view->scroll_into_view(new_index, Orientation::Vertical);
- tree_view->update();
+ if (new_index.is_valid()) {
+ tree_view->selection().set(new_index);
+ tree_view->scroll_into_view(new_index, Orientation::Vertical);
+ tree_view->update();
+ }
go_forward_action->set_enabled(directory_view->path_history_position()
< directory_view->path_history_size() - 1);
@@ -412,14 +451,12 @@ int main(int argc, char** argv)
}
});
- auto directory_context_menu = GMenu::construct();
directory_context_menu->add_action(copy_action);
directory_context_menu->add_action(paste_action);
directory_context_menu->add_action(delete_action);
directory_context_menu->add_separator();
directory_context_menu->add_action(properties_action);
- auto file_context_menu = GMenu::construct();
file_context_menu->add_action(copy_action);
file_context_menu->add_action(paste_action);
file_context_menu->add_action(delete_action);
@@ -428,9 +465,16 @@ int main(int argc, char** argv)
file_context_menu->add_separator();
file_context_menu->add_action(properties_action);
- auto directory_view_context_menu = GMenu::construct();
directory_view_context_menu->add_action(mkdir_action);
+ tree_view_directory_context_menu->add_action(copy_action);
+ tree_view_directory_context_menu->add_action(paste_action);
+ tree_view_directory_context_menu->add_action(delete_action);
+ tree_view_directory_context_menu->add_separator();
+ tree_view_directory_context_menu->add_action(properties_action);
+ tree_view_directory_context_menu->add_separator();
+ tree_view_directory_context_menu->add_action(mkdir_action);
+
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());
@@ -445,6 +489,21 @@ int main(int argc, char** argv)
}
};
+ tree_view->on_selection_change = [&] {
+ auto path = file_system_model->path(tree_view->selection().first());
+ if (directory_view->path() == path)
+ return;
+ directory_view->open(path);
+ copy_action->set_enabled(!tree_view->selection().is_empty());
+ delete_action->set_enabled(!tree_view->selection().is_empty());
+ };
+
+ tree_view->on_context_menu_request = [&](const GModelIndex& index, const GContextMenuEvent& event) {
+ if (index.is_valid()) {
+ tree_view_directory_context_menu->popup(event.screen_position());
+ }
+ };
+
// our initial location is defined as, in order of precedence:
// 1. the first command-line argument (e.g. FileManager /bin)
// 2. the user's home directory