From 4f7eb002ceee645f143f41eed767eb752107d797 Mon Sep 17 00:00:00 2001 From: LarsDW223 Date: Wed, 28 Feb 2018 19:30:09 +0100 Subject: [PATCH] workbench: remove files or directories. The user can now remove a selected file or directory. Closes #711. The user has to confirm the action and is warned that it cannot be undone. In case a directory is removed, then first all files will be removed. The workbench plugin only removes that files in a directory which are displayed in the sidebar. That means files that are not displayed because they do not match the file patterns will not be removed. After removing all files, all sub-directories and finally the selected directory will be removed. This will fail if a directory is not really empty. If removing of a file or directory fails, then a message is output. --- workbench/src/popup_menu.c | 165 +++++++++++++++++++++++++++++++++++-- workbench/src/sidebar.c | 25 +++--- workbench/src/sidebar.h | 6 +- 3 files changed, 177 insertions(+), 19 deletions(-) diff --git a/workbench/src/popup_menu.c b/workbench/src/popup_menu.c index 6b1eb3c38..4099439b6 100644 --- a/workbench/src/popup_menu.c +++ b/workbench/src/popup_menu.c @@ -62,6 +62,7 @@ static struct GtkWidget *remove_bookmark; GtkWidget *new_file; GtkWidget *new_directory; + GtkWidget *remove_file_or_dir; } s_popup_menu; @@ -98,6 +99,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, FALSE); break; case POPUP_CONTEXT_DIRECTORY: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -119,6 +121,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, TRUE); break; case POPUP_CONTEXT_SUB_DIRECTORY: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -140,6 +143,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, TRUE); gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, TRUE); break; case POPUP_CONTEXT_FILE: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -161,6 +165,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, TRUE); gtk_widget_set_sensitive (s_popup_menu.new_file, TRUE); gtk_widget_set_sensitive (s_popup_menu.new_directory, TRUE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, TRUE); break; case POPUP_CONTEXT_BACKGROUND: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -182,6 +187,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, FALSE); break; case POPUP_CONTEXT_WB_BOOKMARK: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -203,6 +209,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, FALSE); break; case POPUP_CONTEXT_PRJ_BOOKMARK: gtk_widget_set_sensitive (s_popup_menu.add_project, TRUE); @@ -224,6 +231,7 @@ void popup_menu_show(POPUP_CONTEXT context, GdkEventButton *event) gtk_widget_set_sensitive (s_popup_menu.subdir_close_all, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_file, FALSE); gtk_widget_set_sensitive (s_popup_menu.new_directory, FALSE); + gtk_widget_set_sensitive (s_popup_menu.remove_file_or_dir, FALSE); break; } gtk_menu_popup(GTK_MENU(s_popup_menu.widget), NULL, NULL, NULL, NULL, @@ -321,7 +329,7 @@ static void popup_menu_on_project_open_all (G_GNUC_UNUSED GtkMenuItem *menuitem, { GPtrArray *list; - list = sidebar_get_selected_project_filelist(); + list = sidebar_get_selected_project_filelist(FALSE); if (list != NULL) { open_all_files_in_list(list); @@ -335,7 +343,7 @@ static void popup_menu_on_project_close_all (G_GNUC_UNUSED GtkMenuItem *menuitem { GPtrArray *list; - list = sidebar_get_selected_project_filelist(); + list = sidebar_get_selected_project_filelist(FALSE); if (list != NULL) { close_all_files_in_list(list); @@ -426,7 +434,7 @@ static void popup_menu_on_directory_open_all (G_GNUC_UNUSED GtkMenuItem *menuite { GPtrArray *list; - list = sidebar_get_selected_directory_filelist(); + list = sidebar_get_selected_directory_filelist(FALSE); if (list != NULL) { open_all_files_in_list(list); @@ -440,7 +448,7 @@ static void popup_menu_on_directory_close_all (G_GNUC_UNUSED GtkMenuItem *menuit { GPtrArray *list; - list = sidebar_get_selected_directory_filelist(); + list = sidebar_get_selected_directory_filelist(FALSE); if (list != NULL) { close_all_files_in_list(list); @@ -502,7 +510,7 @@ static void popup_menu_on_subdir_open_all (G_GNUC_UNUSED GtkMenuItem *menuitem, { GPtrArray *list; - list = sidebar_get_selected_subdir_filelist(); + list = sidebar_get_selected_subdir_filelist(FALSE); if (list != NULL) { open_all_files_in_list(list); @@ -516,7 +524,7 @@ static void popup_menu_on_subdir_close_all (G_GNUC_UNUSED GtkMenuItem *menuitem, { GPtrArray *list; - list = sidebar_get_selected_subdir_filelist(); + list = sidebar_get_selected_subdir_filelist(FALSE); if (list != NULL) { close_all_files_in_list(list); @@ -604,6 +612,145 @@ static void popup_menu_on_new_directory(G_GNUC_UNUSED GtkMenuItem *menuitem, G_G } +/* Handle popup menu item "Remove..." */ +static void popup_menu_on_remove_file_or_dir(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data) +{ + gboolean remove_it, dir, removed_any = FALSE; + gchar *path = NULL, *abs_path = NULL; + SIDEBAR_CONTEXT context; + GPtrArray *files; + + /* Check if a file, a sub-dir or a directory is selected. */ + if (sidebar_file_view_get_selected_context(&context)) + { + if (context.file != NULL) + { + abs_path = g_strdup(context.file); + dir = FALSE; + } + else if (context.subdir != NULL) + { + path = context.subdir; + abs_path = g_strdup(path); + files = sidebar_get_selected_subdir_filelist(TRUE); + dir = TRUE; + } + else if (context.directory != NULL) + { + path = wb_project_dir_get_base_dir(context.directory); + abs_path = get_combined_path(wb_project_get_filename(context.project), path); + files = sidebar_get_selected_directory_filelist(TRUE); + dir = TRUE; + } + } + + if (abs_path == NULL) + { + return; + } + + /* Warn the user. */ + if (dir == FALSE) + { + remove_it = dialogs_show_question(_("Do you really want to remove file \"%s\"?\n\nThis cannot be undone!"), + abs_path); + } + else + { + remove_it = dialogs_show_question(_("Do you really want to remove directory \"%s\" and all files in it?\n\nThis cannot be undone!"), + abs_path); + } + + /* Really remove it? */ + if (remove_it) + { + if (dir == FALSE) + { + if (g_remove(abs_path) != 0) + { + /* Remove file failed. Report error. */ + ui_set_statusbar(TRUE, _("Could not remove file \"%s\"."), + abs_path); + } + else + { + removed_any = TRUE; + } + } + else + { + if (files != NULL) + { + guint index; + gchar *filename; + + /* First remove all files in the directories. */ + for ( index = 0 ; index < files->len ; index++ ) + { + filename = files->pdata[index]; + if (g_file_test(filename, G_FILE_TEST_IS_REGULAR)) + { + if (g_remove(filename) != 0) + { + /* Remove file failed. Report error. */ + ui_set_statusbar(TRUE, _("Could not remove file \"%s\"."), + filename); + } + else + { + removed_any = TRUE; + } + } + } + + /* Now try to remove the directories. + This will only succeed if they are empty. */ + for ( index = 0 ; index < files->len ; index++ ) + { + filename = files->pdata[index]; + if (g_file_test(filename, G_FILE_TEST_IS_DIR)) + { + if (g_rmdir(filename) != 0) + { + /* Remove file failed. Report error. */ + ui_set_statusbar(TRUE, _("Could not remove directory \"%s\"."), + filename); + } + else + { + removed_any = TRUE; + } + } + } + + /* At last try to remove the parent dir. */ + if (g_rmdir(abs_path) != 0) + { + /* Remove file failed. Report error. */ + ui_set_statusbar(TRUE, _("Could not remove directory \"%s\"."), + abs_path); + } + else + { + removed_any = TRUE; + } + + g_ptr_array_free(files, TRUE); + } + } + + /* If anything was removed update the filelist and sidebar. */ + if (removed_any) + { + wb_project_dir_rescan(context.project, context.directory); + sidebar_update(SIDEBAR_CONTEXT_DIRECTORY_RESCANNED, &context); + } + } + + g_free(abs_path); +} + + /** Setup/Initialize the popup menu. * **/ @@ -764,4 +911,10 @@ void popup_menu_init(void) gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_new_directory), NULL); s_popup_menu.new_directory = item; + + item = gtk_menu_item_new_with_mnemonic(_("_Remove...")); + gtk_widget_show(item); + gtk_container_add(GTK_CONTAINER(s_popup_menu.widget), item); + g_signal_connect(item, "activate", G_CALLBACK(popup_menu_on_remove_file_or_dir), NULL); + s_popup_menu.remove_file_or_dir = item; } diff --git a/workbench/src/sidebar.c b/workbench/src/sidebar.c index ba5629180..7df5d0fc1 100644 --- a/workbench/src/sidebar.c +++ b/workbench/src/sidebar.c @@ -1012,7 +1012,7 @@ gboolean sidebar_file_view_get_selected_context(SIDEBAR_CONTEXT *context) } /* Collect all filenames recursively starting from iter and add them to list */ -static void sidebar_get_filelist_for_iter(GPtrArray *list, GtkTreeIter iter) +static void sidebar_get_filelist_for_iter(GPtrArray *list, GtkTreeIter iter, gboolean dirnames) { GtkTreeModel *model; GtkTreeIter childs; @@ -1032,9 +1032,14 @@ static void sidebar_get_filelist_for_iter(GPtrArray *list, GtkTreeIter iter) break; case DATA_ID_DIRECTORY: case DATA_ID_SUB_DIRECTORY: + if (dirnames == TRUE) + { + gtk_tree_model_get(model, &iter, FILEVIEW_COLUMN_ASSIGNED_DATA_POINTER, &filename, -1); + g_ptr_array_add(list, g_strdup(filename)); + } if (gtk_tree_model_iter_children(model, &childs, &iter) == TRUE) { - sidebar_get_filelist_for_iter(list, childs); + sidebar_get_filelist_for_iter(list, childs, dirnames); } break; } @@ -1046,7 +1051,7 @@ static void sidebar_get_filelist_for_iter(GPtrArray *list, GtkTreeIter iter) /* Get the lkist of files belonging to the current selection for id (id = project, directory, sub-directory) */ -static GPtrArray *sidebar_get_selected_filelist (guint id) +static GPtrArray *sidebar_get_selected_filelist (guint id, gboolean dirnames) { GtkTreeModel *model; GPtrArray *list; @@ -1058,7 +1063,7 @@ static GPtrArray *sidebar_get_selected_filelist (guint id) model = gtk_tree_view_get_model(GTK_TREE_VIEW(sidebar.file_view)); if (gtk_tree_model_iter_children(model, &childs, &iter) == TRUE) { - sidebar_get_filelist_for_iter(list, childs); + sidebar_get_filelist_for_iter(list, childs, dirnames); } return list; } @@ -1072,9 +1077,9 @@ static GPtrArray *sidebar_get_selected_filelist (guint id) * @return GPtrArray containing file names or NULL. * **/ -GPtrArray *sidebar_get_selected_project_filelist (void) +GPtrArray *sidebar_get_selected_project_filelist (gboolean dirnames) { - return sidebar_get_selected_filelist(DATA_ID_PROJECT); + return sidebar_get_selected_filelist(DATA_ID_PROJECT, dirnames); } @@ -1083,9 +1088,9 @@ GPtrArray *sidebar_get_selected_project_filelist (void) * @return GPtrArray containing file names or NULL. * **/ -GPtrArray *sidebar_get_selected_directory_filelist (void) +GPtrArray *sidebar_get_selected_directory_filelist (gboolean dirnames) { - return sidebar_get_selected_filelist(DATA_ID_DIRECTORY); + return sidebar_get_selected_filelist(DATA_ID_DIRECTORY, dirnames); } @@ -1094,9 +1099,9 @@ GPtrArray *sidebar_get_selected_directory_filelist (void) * @return GPtrArray containing file names or NULL. * **/ -GPtrArray *sidebar_get_selected_subdir_filelist (void) +GPtrArray *sidebar_get_selected_subdir_filelist (gboolean dirnames) { - return sidebar_get_selected_filelist(DATA_ID_SUB_DIRECTORY); + return sidebar_get_selected_filelist(DATA_ID_SUB_DIRECTORY, dirnames); } /** Setup the sidebar. diff --git a/workbench/src/sidebar.h b/workbench/src/sidebar.h index ec49c60e7..4d630452d 100644 --- a/workbench/src/sidebar.h +++ b/workbench/src/sidebar.h @@ -72,8 +72,8 @@ void sidebar_toggle_selected_project_dir_expansion (void); WB_PROJECT *sidebar_file_view_get_selected_project(GtkTreePath **path); gboolean sidebar_file_view_get_selected_context(SIDEBAR_CONTEXT *context); -GPtrArray *sidebar_get_selected_project_filelist (void); -GPtrArray *sidebar_get_selected_directory_filelist (void); -GPtrArray *sidebar_get_selected_subdir_filelist (void); +GPtrArray *sidebar_get_selected_project_filelist (gboolean dirnames); +GPtrArray *sidebar_get_selected_directory_filelist (gboolean dirnames); +GPtrArray *sidebar_get_selected_subdir_filelist (gboolean dirnames); #endif