From b2c802da4125a3cadf9b8cfdd1123ea547c37ce1 Mon Sep 17 00:00:00 2001 From: Robert Henderson Date: Thu, 22 Dec 2016 20:48:01 +0000 Subject: [PATCH] Confirmation dialog on move to trash / delete (bug #9889) The user may choose to have a confirmation dialog on: - both trash and delete; - delete only (default); - neither trash nor delete. I added a new property to the preferences for this purpose. As there was no space left on the 'Behaviour' page of the preferences dialog, I created a new 'Actions' page. I changed 'files' to 'items' in the delete confirmation dialog text, as 'items' is a better generic description if some of the things being deleted are directories. --- thunar/thunar-application.c | 92 +++++++++++++++++++++++++----------- thunar/thunar-enum-types.c | 95 +++++++++++++++++++++++--------------- thunar/thunar-enum-types.h | 20 ++++++++ thunar/thunar-preferences-dialog.c | 41 ++++++++++++++++ thunar/thunar-preferences.c | 14 ++++++ 5 files changed, 198 insertions(+), 64 deletions(-) diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c index 8ce6683..d9698bd 100644 --- a/thunar/thunar-application.c +++ b/thunar/thunar-application.c @@ -1768,14 +1768,16 @@ thunar_application_unlink_files (ThunarApplication *application, GList *file_list, gboolean permanently) { - GtkWidget *dialog; - GtkWindow *window; - GdkScreen *screen; - GList *path_list = NULL; - GList *lp; - gchar *message; - guint n_path_list = 0; - gint response; + ThunarDeleteConfirmMode delete_confirm_mode; + GtkWidget *dialog; + GtkWindow *window; + GdkScreen *screen; + GList *path_list = NULL; + GList *lp; + gchar *message; + const gchar *yes_button; + guint n_path_list = 0; + gint response; _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent)); _thunar_return_if_fail (THUNAR_IS_APPLICATION (application)); @@ -1796,24 +1798,49 @@ thunar_application_unlink_files (ThunarApplication *application, if (G_UNLIKELY (n_path_list == 0)) return; - /* ask the user to confirm if deleting permanently */ - if (G_UNLIKELY (permanently)) + /* ask the user to confirm */ + g_object_get (G_OBJECT (application->preferences), "misc-delete-confirm", &delete_confirm_mode, NULL); + if (G_UNLIKELY (delete_confirm_mode == THUNAR_DELETE_CONFIRM_ALWAYS || + (delete_confirm_mode == THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY && permanently))) { /* parse the parent pointer */ screen = thunar_util_parse_parent (parent, &window); - /* generate the question to confirm the delete operation */ - if (G_LIKELY (n_path_list == 1)) + /* generate the question to confirm the operation */ + /* if deleting 1 item, display its name in the message, otherwise display the number of items */ + if (G_UNLIKELY (permanently)) { - message = g_strdup_printf (_("Are you sure that you want to\npermanently delete \"%s\"?"), - thunar_file_get_display_name (THUNAR_FILE (file_list->data))); + yes_button = GTK_STOCK_DELETE; + if (G_LIKELY (n_path_list == 1)) + { + message = g_strdup_printf (_("Are you sure that you want to\npermanently delete \"%s\"?"), + thunar_file_get_display_name (THUNAR_FILE (file_list->data))); + } + else + { + message = g_strdup_printf (ngettext ("Are you sure that you want to permanently\ndelete the selected item?", + "Are you sure that you want to permanently\ndelete the %u selected items?", + n_path_list), + n_path_list); + } } else { - message = g_strdup_printf (ngettext ("Are you sure that you want to permanently\ndelete the selected file?", - "Are you sure that you want to permanently\ndelete the %u selected files?", - n_path_list), - n_path_list); + /* text for the button corresponding to 'yes' */ + yes_button = _("Mo_ve to Trash"); + + if (G_LIKELY (n_path_list == 1)) + { + message = g_strdup_printf (_("Are you sure that you want to\nmove \"%s\" to the trash?"), + thunar_file_get_display_name (THUNAR_FILE (file_list->data))); + } + else + { + message = g_strdup_printf (ngettext ("Are you sure that you want to move\nthe selected item to the trash?", + "Are you sure that you want to move\nthe %u selected items to the trash?", + n_path_list), + n_path_list); + } } /* ask the user to confirm the delete operation */ @@ -1826,28 +1853,37 @@ thunar_application_unlink_files (ThunarApplication *application, gtk_window_set_screen (GTK_WINDOW (dialog), screen); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_DELETE, GTK_RESPONSE_YES, + yes_button, GTK_RESPONSE_YES, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - _("If you delete a file, it is permanently lost.")); + if (G_UNLIKELY (permanently)) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + _("If you delete a file, it is permanently lost.")); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free (message); + } + else + { + /* the user was not asked to confirm, so the response defaults to 'yes' */ + response = GTK_RESPONSE_YES; + } - /* perform the delete operation */ - if (G_LIKELY (response == GTK_RESPONSE_YES)) + /* perform the operation */ + if (G_LIKELY (response == GTK_RESPONSE_YES)) + { + if (G_UNLIKELY (permanently)) { /* launch the "Delete" operation */ thunar_application_launch (application, parent, "edit-delete", _("Deleting files..."), unlink_stub, path_list, path_list, NULL); } - } - else - { - /* launch the "Move to Trash" operation */ - thunar_application_trash (application, parent, path_list); + else + { + /* launch the "Move to Trash" operation */ + thunar_application_trash (application, parent, path_list); + } } /* release the path list */ diff --git a/thunar/thunar-enum-types.c b/thunar/thunar-enum-types.c index 479bbcf..e792289 100644 --- a/thunar/thunar-enum-types.c +++ b/thunar/thunar-enum-types.c @@ -162,6 +162,29 @@ thunar_recursive_permissions_get_type (void) GType +thunar_delete_confirm_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + static const GEnumValue values[] = + { + { THUNAR_DELETE_CONFIRM_ALWAYS, "THUNAR_DELETE_CONFIRM_ALWAYS", "always", }, + { THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY, "THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY", "permanent delete only", }, + { THUNAR_DELETE_CONFIRM_NEVER, "THUNAR_DELETE_CONFIRM_NEVER", "never", }, + { 0, NULL, NULL, }, + }; + + type = g_enum_register_static (I_("ThunarDeleteConfirm"), values); + } + + return type; +} + + + +GType thunar_zoom_level_get_type (void) { static GType type = G_TYPE_INVALID; @@ -251,26 +274,26 @@ thunar_icon_size_from_zoom_level (const GValue *src_value, GType thunar_job_response_get_type (void) { - static GType type = G_TYPE_INVALID; + static GType type = G_TYPE_INVALID; if (G_UNLIKELY (type == G_TYPE_INVALID)) { - static const GFlagsValue values[] = + static const GFlagsValue values[] = { - { THUNAR_JOB_RESPONSE_YES, "THUNAR_JOB_RESPONSE_YES", "yes" }, - { THUNAR_JOB_RESPONSE_YES_ALL, "THUNAR_JOB_RESPONSE_YES_ALL", "yes-all" }, - { THUNAR_JOB_RESPONSE_NO, "THUNAR_JOB_RESPONSE_NO", "no" }, - { THUNAR_JOB_RESPONSE_CANCEL, "THUNAR_JOB_RESPONSE_CANCEL", "cancel" }, - { THUNAR_JOB_RESPONSE_NO_ALL, "THUNAR_JOB_RESPONSE_NO_ALL", "no-all" }, - { THUNAR_JOB_RESPONSE_RETRY, "THUNAR_JOB_RESPONSE_RETRY", "retry" }, - { THUNAR_JOB_RESPONSE_FORCE, "THUNAR_JOB_RESPONSE_FORCE", "force" }, - { 0, NULL, NULL } - }; - - type = g_flags_register_static (I_("ThunarJobResponse"), values); + { THUNAR_JOB_RESPONSE_YES, "THUNAR_JOB_RESPONSE_YES", "yes" }, + { THUNAR_JOB_RESPONSE_YES_ALL, "THUNAR_JOB_RESPONSE_YES_ALL", "yes-all" }, + { THUNAR_JOB_RESPONSE_NO, "THUNAR_JOB_RESPONSE_NO", "no" }, + { THUNAR_JOB_RESPONSE_CANCEL, "THUNAR_JOB_RESPONSE_CANCEL", "cancel" }, + { THUNAR_JOB_RESPONSE_NO_ALL, "THUNAR_JOB_RESPONSE_NO_ALL", "no-all" }, + { THUNAR_JOB_RESPONSE_RETRY, "THUNAR_JOB_RESPONSE_RETRY", "retry" }, + { THUNAR_JOB_RESPONSE_FORCE, "THUNAR_JOB_RESPONSE_FORCE", "force" }, + { 0, NULL, NULL } + }; + + type = g_flags_register_static (I_("ThunarJobResponse"), values); } - return type; + return type; } @@ -278,31 +301,31 @@ thunar_job_response_get_type (void) GType thunar_file_mode_get_type (void) { - static GType type = G_TYPE_INVALID; + static GType type = G_TYPE_INVALID; - if (type == G_TYPE_INVALID) + if (type == G_TYPE_INVALID) { - static const GFlagsValue values[] = + static const GFlagsValue values[] = { - { THUNAR_FILE_MODE_SUID, "THUNAR_FILE_MODE_SUID", "suid" }, - { THUNAR_FILE_MODE_SGID, "THUNAR_FILE_MODE_SGID", "sgid" }, - { THUNAR_FILE_MODE_STICKY, "THUNAR_FILE_MODE_STICKY", "sticky" }, - { THUNAR_FILE_MODE_USR_ALL, "THUNAR_FILE_MODE_USR_ALL", "usr-all" }, - { THUNAR_FILE_MODE_USR_READ, "THUNAR_FILE_MODE_USR_READ", "usr-read" }, - { THUNAR_FILE_MODE_USR_WRITE, "THUNAR_FILE_MODE_USR_WRITE", "usr-write" }, - { THUNAR_FILE_MODE_USR_EXEC, "THUNAR_FILE_MODE_USR_EXEC", "usr-exec" }, - { THUNAR_FILE_MODE_GRP_ALL, "THUNAR_FILE_MODE_GRP_ALL", "grp-all" }, - { THUNAR_FILE_MODE_GRP_READ, "THUNAR_FILE_MODE_GRP_READ", "grp-read" }, - { THUNAR_FILE_MODE_GRP_WRITE, "THUNAR_FILE_MODE_GRP_WRITE", "grp-write" }, - { THUNAR_FILE_MODE_GRP_EXEC, "THUNAR_FILE_MODE_GRP_EXEC", "grp-exec" }, - { THUNAR_FILE_MODE_OTH_ALL, "THUNAR_FILE_MODE_OTH_ALL", "oth-all" }, - { THUNAR_FILE_MODE_OTH_READ, "THUNAR_FILE_MODE_OTH_READ", "oth-read" }, - { THUNAR_FILE_MODE_OTH_WRITE, "THUNAR_FILE_MODE_OTH_WRITE", "oth-write" }, - { THUNAR_FILE_MODE_OTH_EXEC, "THUNAR_FILE_MODE_OTH_EXEC", "oth-exec" }, - { 0, NULL, NULL } - }; - + { THUNAR_FILE_MODE_SUID, "THUNAR_FILE_MODE_SUID", "suid" }, + { THUNAR_FILE_MODE_SGID, "THUNAR_FILE_MODE_SGID", "sgid" }, + { THUNAR_FILE_MODE_STICKY, "THUNAR_FILE_MODE_STICKY", "sticky" }, + { THUNAR_FILE_MODE_USR_ALL, "THUNAR_FILE_MODE_USR_ALL", "usr-all" }, + { THUNAR_FILE_MODE_USR_READ, "THUNAR_FILE_MODE_USR_READ", "usr-read" }, + { THUNAR_FILE_MODE_USR_WRITE, "THUNAR_FILE_MODE_USR_WRITE", "usr-write" }, + { THUNAR_FILE_MODE_USR_EXEC, "THUNAR_FILE_MODE_USR_EXEC", "usr-exec" }, + { THUNAR_FILE_MODE_GRP_ALL, "THUNAR_FILE_MODE_GRP_ALL", "grp-all" }, + { THUNAR_FILE_MODE_GRP_READ, "THUNAR_FILE_MODE_GRP_READ", "grp-read" }, + { THUNAR_FILE_MODE_GRP_WRITE, "THUNAR_FILE_MODE_GRP_WRITE", "grp-write" }, + { THUNAR_FILE_MODE_GRP_EXEC, "THUNAR_FILE_MODE_GRP_EXEC", "grp-exec" }, + { THUNAR_FILE_MODE_OTH_ALL, "THUNAR_FILE_MODE_OTH_ALL", "oth-all" }, + { THUNAR_FILE_MODE_OTH_READ, "THUNAR_FILE_MODE_OTH_READ", "oth-read" }, + { THUNAR_FILE_MODE_OTH_WRITE, "THUNAR_FILE_MODE_OTH_WRITE", "oth-write" }, + { THUNAR_FILE_MODE_OTH_EXEC, "THUNAR_FILE_MODE_OTH_EXEC", "oth-exec" }, + { 0, NULL, NULL } + }; + type = g_flags_register_static ("ThunarFileMode", values); } - return type; + return type; } diff --git a/thunar/thunar-enum-types.h b/thunar/thunar-enum-types.h index 9fb34a7..5662234 100644 --- a/thunar/thunar-enum-types.h +++ b/thunar/thunar-enum-types.h @@ -180,6 +180,26 @@ typedef enum GType thunar_recursive_permissions_get_type (void) G_GNUC_CONST; +#define THUNAR_TYPE_DELETE_CONFIRM (thunar_delete_confirm_get_type ()) + +/** + * ThunarDeleteConfirmMode: + * @THUNAR_DELETE_CONFIRM_ALWAYS : show confirm dialog on move to trash and delete. + * @THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY : show confirm dialog on delete only. + * @THUNAR_DELETE_CONFIRM_NEVER : never show confirm dialog. + * + * This mode controls whether Thunar shows a confirmation dialog on delete / move to trash. + **/ +typedef enum +{ + THUNAR_DELETE_CONFIRM_ALWAYS, + THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY, + THUNAR_DELETE_CONFIRM_NEVER, +} ThunarDeleteConfirmMode; + +GType thunar_delete_confirm_get_type (void) G_GNUC_CONST; + + #define THUNAR_TYPE_ZOOM_LEVEL (thunar_zoom_level_get_type ()) /** diff --git a/thunar/thunar-preferences-dialog.c b/thunar/thunar-preferences-dialog.c index 057766e..7dfd9e6 100644 --- a/thunar/thunar-preferences-dialog.c +++ b/thunar/thunar-preferences-dialog.c @@ -581,6 +581,47 @@ thunar_preferences_dialog_init (ThunarPreferencesDialog *dialog) gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); gtk_widget_show (button); + + /* + Actions + */ + label = gtk_label_new (_("Actions")); + vbox = g_object_new (GTK_TYPE_VBOX, "border-width", 12, "spacing", 12, NULL); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + gtk_widget_show (label); + gtk_widget_show (vbox); + + frame = g_object_new (GTK_TYPE_FRAME, "border-width", 0, "shadow-type", GTK_SHADOW_NONE, NULL); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + gtk_widget_show (frame); + + label = gtk_label_new (_("Move to Trash / Delete")); + gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_bold ()); + gtk_frame_set_label_widget (GTK_FRAME (frame), label); + gtk_widget_show (label); + + table = gtk_table_new (1, 2, FALSE); + gtk_table_set_row_spacings (GTK_TABLE (table), 6); + gtk_table_set_col_spacings (GTK_TABLE (table), 12); + gtk_container_set_border_width (GTK_CONTAINER (table), 12); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_widget_show (table); + + label = gtk_label_new_with_mnemonic (_("_Ask for confirmation:")); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + combo = gtk_combo_box_text_new (); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Always")); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Permanent Delete Only")); + gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Never")); + exo_mutual_binding_new (G_OBJECT (dialog->preferences), "misc-delete-confirm", G_OBJECT (combo), "active"); + gtk_table_attach (GTK_TABLE (table), combo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + thunar_gtk_label_set_a11y_relation (GTK_LABEL (label), combo); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo); + gtk_widget_show (combo); + + /* Advanced */ diff --git a/thunar/thunar-preferences.c b/thunar/thunar-preferences.c index 9a86ae1..5beb44c 100644 --- a/thunar/thunar-preferences.c +++ b/thunar/thunar-preferences.c @@ -91,6 +91,7 @@ enum PROP_MISC_TEXT_BESIDE_ICONS, PROP_MISC_THUMBNAIL_MODE, PROP_MISC_FILE_SIZE_BINARY, + PROP_MISC_DELETE_CONFIRM, PROP_SHORTCUTS_ICON_EMBLEMS, PROP_SHORTCUTS_ICON_SIZE, PROP_TREE_ICON_EMBLEMS, @@ -706,6 +707,19 @@ thunar_preferences_class_init (ThunarPreferencesClass *klass) EXO_PARAM_READWRITE); /** + * ThunarPreferences:misc-delete-confirm: + * + * Whether to display a confirmation dialog on delete / move to trash. + **/ + preferences_props[PROP_MISC_DELETE_CONFIRM] = + g_param_spec_enum ("misc-delete-confirm", + NULL, + NULL, + THUNAR_TYPE_DELETE_CONFIRM, + THUNAR_DELETE_CONFIRM_PERM_DELETE_ONLY, + EXO_PARAM_READWRITE); + + /** * ThunarPreferences:shortcuts-icon-emblems: * * Whether to display emblems for file icons (if defined) in the -- 2.1.4