From c6f8fb502bb69b69bbc03b4d528ba24873977c81 Mon Sep 17 00:00:00 2001
From: Sergios - Anestis Kefalidis <sergioskefalidis@gmail.com>
Date: Sat, 10 Jul 2021 13:07:07 +0300
Subject: [PATCH] Provide additional menu item for trashed files: "restore and
 open folder" (Issue #382)

        Issue #382
        MR !118
---
 thunar/thunar-application.c |   4 +-
 thunar/thunar-enum-types.h  |  15 +++++
 thunar/thunar-launcher.c    |  32 +++++++++++
 thunar/thunar-launcher.h    |   2 +
 thunar/thunar-menu.c        |   7 ++-
 thunar/thunar-window.c      | 111 ++++++++++++++++++++++++++++++++----
 thunar/thunar-window.h      |   4 +-
 7 files changed, 158 insertions(+), 17 deletions(-)

diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c
index 0e45aacb0..52a88c6db 100644
--- a/thunar/thunar-application.c
+++ b/thunar/thunar-application.c
@@ -1372,7 +1372,7 @@ thunar_application_open_window (ThunarApplication *application,
           list = g_list_last (list);
 
           if (directory != NULL)
-              thunar_window_notebook_add_new_tab (THUNAR_WINDOW (list->data), directory, TRUE);
+              thunar_window_notebook_add_new_tab (THUNAR_WINDOW (list->data), directory, THUNAR_NEW_TAB_BEHAVIOR_SWITCH);
           
           /* bring the window to front */
           gtk_window_present (list->data);
@@ -1592,7 +1592,7 @@ thunar_application_process_files_finish (ThunarBrowser *browser,
               g_object_unref (parent);
 
               files = g_list_append (files, thunar_file_get_file (file));
-              thunar_window_select_files (THUNAR_WINDOW (window), files);
+              thunar_window_show_and_select_files (THUNAR_WINDOW (window), files);
               g_list_free (files);
             }
         }
diff --git a/thunar/thunar-enum-types.h b/thunar/thunar-enum-types.h
index 5fe3960bb..b0908a4ce 100644
--- a/thunar/thunar-enum-types.h
+++ b/thunar/thunar-enum-types.h
@@ -326,6 +326,21 @@ typedef enum /*< flags >*/
 
 GType thunar_file_mode_get_type (void) G_GNUC_CONST;
 
+
+
+/**
+ * ThunarNewTabBehavior:
+ * @THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE   : switching to the new tab or not is controlled by a preference.
+ * @THUNAR_NEW_TAB_BEHAVIOR_SWITCH              : switch to the new tab.
+ * @THUNAR_NEW_TAB_BEHAVIOR_STAY                : stay at the current tab.
+ **/
+typedef enum
+{
+    THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE,
+    THUNAR_NEW_TAB_BEHAVIOR_SWITCH,
+    THUNAR_NEW_TAB_BEHAVIOR_STAY
+} ThunarNewTabBehavior;
+
 G_END_DECLS;
 
 #endif /* !__THUNAR_ENUM_TYPES_H__ */
diff --git a/thunar/thunar-launcher.c b/thunar/thunar-launcher.c
index 26a4d37a1..324b50311 100644
--- a/thunar/thunar-launcher.c
+++ b/thunar/thunar-launcher.c
@@ -284,6 +284,7 @@ static XfceGtkActionEntry thunar_launcher_action_entries[] =
     {THUNAR_LAUNCHER_ACTION_CREATE_DOCUMENT,    "<Actions>/ThunarStandardView/create-document",   "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Create _Document"),    N_ ("Create a new document from a template"),                                                    "document-new",                                G_CALLBACK (NULL),                                       },
 
     {THUNAR_LAUNCHER_ACTION_RESTORE,            "<Actions>/ThunarLauncher/restore",               "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Restore"),            NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_restore),             },
+    { THUNAR_LAUNCHER_ACTION_RESTORE_SHOW,      "<Actions>/ThunarLauncher/restore-show",          "",                  XFCE_GTK_MENU_ITEM,       N_ ("_Restore and Show"),   N_ ("_Restore and show the file(s)"),             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_restore_and_show),    },
     {THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH,      "<Actions>/ThunarLauncher/move-to-trash",         "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("Mo_ve to Trash"),      NULL,                                                                                            "user-trash",                                  G_CALLBACK (thunar_launcher_action_trash_delete),        },
     {THUNAR_LAUNCHER_ACTION_DELETE,             "<Actions>/ThunarLauncher/delete",                "",                  XFCE_GTK_IMAGE_MENU_ITEM, N_ ("_Delete"),             NULL,                                                                                            "edit-delete",                                 G_CALLBACK (thunar_launcher_action_delete),              },
     {THUNAR_LAUNCHER_ACTION_DELETE,             "<Actions>/ThunarLauncher/delete-2",              "<Shift>Delete",     XFCE_GTK_IMAGE_MENU_ITEM, NULL,                       NULL,                                             NULL,                                                                                         G_CALLBACK (thunar_launcher_action_delete),              },
@@ -1587,6 +1588,18 @@ thunar_launcher_append_menu_item (ThunarLauncher       *launcher,
           }
         return NULL;
 
+      case THUNAR_LAUNCHER_ACTION_RESTORE_SHOW:
+        if (launcher->files_are_selected && thunar_file_is_trashed (launcher->current_directory))
+          {
+            tooltip_text = ngettext ("Restore the selected file to its original location and open the location in a new window/tab",
+                                     "Restore the selected files to their original locations and open the locations in a new window/tab", launcher->n_files_to_process);
+            item = xfce_gtk_menu_item_new (action_entry->menu_item_label_text, tooltip_text, action_entry->accel_path,
+                                           action_entry->callback, G_OBJECT (launcher), menu);
+            gtk_widget_set_sensitive (item, thunar_file_is_writable (launcher->current_directory));
+            return item;
+          }
+      return NULL;
+
       case THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH:
         if (!thunar_launcher_show_trash (launcher))
           return NULL;
@@ -2370,6 +2383,25 @@ thunar_launcher_action_restore (ThunarLauncher *launcher)
 }
 
 
+
+void
+thunar_launcher_action_restore_and_show (ThunarLauncher *launcher)
+{
+  ThunarApplication *application;
+
+  _thunar_return_if_fail (THUNAR_IS_LAUNCHER (launcher));
+
+  if (launcher->files_are_selected == FALSE || !thunar_file_is_trashed (launcher->current_directory))
+    return;
+
+  /* restore the selected files */
+  application = thunar_application_get ();
+  thunar_application_restore_files (application, launcher->widget, launcher->files_to_process, launcher->new_files_created_closure);
+  g_object_unref (G_OBJECT (application));
+}
+
+
+
 static void
 thunar_launcher_action_move_to_trash (ThunarLauncher *launcher)
 {
diff --git a/thunar/thunar-launcher.h b/thunar/thunar-launcher.h
index 9b88e9079..7e27f2d7b 100644
--- a/thunar/thunar-launcher.h
+++ b/thunar/thunar-launcher.h
@@ -57,6 +57,7 @@ typedef enum
   THUNAR_LAUNCHER_ACTION_CREATE_FOLDER,
   THUNAR_LAUNCHER_ACTION_CREATE_DOCUMENT,
   THUNAR_LAUNCHER_ACTION_RESTORE,
+  THUNAR_LAUNCHER_ACTION_RESTORE_SHOW,
   THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH,
   THUNAR_LAUNCHER_ACTION_DELETE,
   THUNAR_LAUNCHER_ACTION_TRASH_DELETE,
@@ -110,6 +111,7 @@ void            thunar_launcher_set_selection                        (ThunarLaun
                                                                       GFile                          *selected_location);
 void            thunar_launcher_action_empty_trash                   (ThunarLauncher                 *launcher);
 void            thunar_launcher_action_restore                       (ThunarLauncher                 *launcher);
+void            thunar_launcher_action_restore_and_show              (ThunarLauncher                 *launcher);
 
 
 G_END_DECLS;
diff --git a/thunar/thunar-menu.c b/thunar/thunar-menu.c
index 4d3a11652..a5d32c88b 100644
--- a/thunar/thunar-menu.c
+++ b/thunar/thunar-menu.c
@@ -305,8 +305,11 @@ thunar_menu_add_sections (ThunarMenu         *menu,
     }
   if (menu_sections & THUNAR_MENU_SECTION_RESTORE)
     {
-      if (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RESTORE, FALSE) != NULL)
-         xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
+      item_added = FALSE;
+      item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RESTORE, FALSE) != NULL);
+      item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RESTORE_SHOW, FALSE) != NULL);
+      if (item_added)
+        xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu));
     }
   if (menu_sections & THUNAR_MENU_SECTION_REMOVE_FROM_RECENT)
     {
diff --git a/thunar/thunar-window.c b/thunar/thunar-window.c
index 5573df1a0..769c545e8 100644
--- a/thunar/thunar-window.c
+++ b/thunar/thunar-window.c
@@ -252,6 +252,8 @@ static void      thunar_window_update_window_icon         (ThunarWindow
 static void      thunar_window_create_menu                (ThunarWindow           *window,
                                                            ThunarWindowAction      action,
                                                            GCallback               cb_update_menu);
+static void      thunar_window_select_files               (ThunarWindow           *window,
+                                                           GList                  *files_to_select);
 static void      thunar_window_update_file_menu           (ThunarWindow           *window,
                                                            GtkWidget              *menu);
 static void      thunar_window_update_edit_menu           (ThunarWindow           *window,
@@ -735,7 +737,7 @@ thunar_window_init (ThunarWindow *window)
   g_object_bind_property (G_OBJECT (window), "current-directory", G_OBJECT (window->launcher), "current-directory", G_BINDING_SYNC_CREATE);
   g_signal_connect_swapped (G_OBJECT (window->launcher), "change-directory", G_CALLBACK (thunar_window_set_current_directory), window);
   g_signal_connect_swapped (G_OBJECT (window->launcher), "open-new-tab", G_CALLBACK (thunar_window_notebook_open_new_tab), window);
-  g_signal_connect_swapped (G_OBJECT (window->launcher), "new-files-created", G_CALLBACK (thunar_window_select_files), window);
+  g_signal_connect_swapped (G_OBJECT (window->launcher), "new-files-created", G_CALLBACK (thunar_window_show_and_select_files), window);
   thunar_launcher_append_accelerators (window->launcher, window->accel_group);
 
   /* determine the default window size from the preferences */
@@ -953,6 +955,94 @@ thunar_window_screen_changed (GtkWidget *widget,
 }
 
 
+
+static void
+hash_table_entry_show_and_select_files (gpointer key, gpointer list, gpointer application)
+{
+  ThunarFile *original_dir  = NULL;
+  GList      *window_list   = NULL;
+
+  _thunar_return_if_fail (key != NULL);
+  _thunar_return_if_fail (list != NULL);
+  _thunar_return_if_fail (application != NULL);
+
+  /* open directory */
+  original_dir = thunar_file_get_for_uri (key, NULL);
+  thunar_application_open_window (application, original_dir, NULL, NULL, FALSE);
+
+  /* select files */
+  window_list = thunar_application_get_windows (application);
+  window_list = g_list_last (window_list); /* this will be the topmost Window */
+  thunar_window_select_files (THUNAR_WINDOW (window_list->data), list);
+
+  /* free memory */
+  g_list_free (window_list);
+  g_object_unref (original_dir);
+}
+
+
+
+/**
+ * thunar_window_show_and_select_files:
+ * @window            : a #ThunarWindow instance.
+ * @files_to_select   : a list of #GFile<!---->s
+ *
+ * Visually selects the files, given by the list. If the files are being restored from the trash folder
+ * new tabs are opened and then the files are selected.
+ **/
+void
+thunar_window_show_and_select_files (ThunarWindow *window,
+                                     GList        *files_to_select)
+{
+  gboolean      restore_and_show_in_progress;
+
+  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
+
+  restore_and_show_in_progress = thunar_file_is_trash (window->current_directory) && thunar_g_file_is_trashed (files_to_select->data) == FALSE;
+  if (restore_and_show_in_progress)
+    {
+      ThunarApplication *application;
+      GHashTable        *restore_show_table; /* <string, GList<GFile*>> */
+      const gchar       *original_uri;
+      GFile             *original_dir_file;
+      gchar             *original_dir_path;
+
+      /* prepare hashtable */
+      restore_show_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (void(*) (void*))thunar_g_list_free_full);
+      for (GList *lp = files_to_select; lp != NULL; lp = lp->next)
+        {
+          original_dir_file = g_file_get_parent (lp->data);
+          original_uri =  g_file_get_uri (lp->data);
+          original_dir_path = g_file_get_uri (original_dir_file);
+
+          if (g_hash_table_contains (restore_show_table, original_dir_path) == FALSE)
+            {
+              GList *list = g_list_prepend (NULL, g_file_new_for_commandline_arg (original_uri));
+              g_hash_table_insert (restore_show_table, original_dir_path, list);
+            }
+          else
+            {
+              GList *list = g_hash_table_lookup (restore_show_table, original_dir_path);
+              list = g_list_append (list, g_file_new_for_commandline_arg (original_uri));
+            }
+
+          g_object_unref (original_dir_file);
+        }
+      /* open tabs and show files */
+      application = thunar_application_get();
+      g_hash_table_foreach (restore_show_table, hash_table_entry_show_and_select_files, application);
+      /* free memory */
+      g_hash_table_destroy (restore_show_table);
+      g_object_unref (application);
+    }
+  else
+    {
+      thunar_window_select_files (window, files_to_select);
+    }
+}
+
+
+
 /**
  * thunar_window_select_files:
  * @window            : a #ThunarWindow instance.
@@ -960,15 +1050,13 @@ thunar_window_screen_changed (GtkWidget *widget,
  *
  * Visually selects the files, given by the list
  **/
-void
+static void
 thunar_window_select_files (ThunarWindow *window,
                             GList        *files_to_select)
 {
   GList        *thunar_files = NULL;
   ThunarFolder *thunar_folder;
 
-  _thunar_return_if_fail (THUNAR_IS_WINDOW (window));
-
   /* If possible, reload the current directory to make sure new files got added to the view */
   thunar_folder = thunar_folder_get_for_file (window->current_directory);
   if (thunar_folder != NULL)
@@ -2339,9 +2427,9 @@ thunar_window_split_view_is_active (ThunarWindow *window)
 
 
 void
-thunar_window_notebook_add_new_tab (ThunarWindow *window,
-                                    ThunarFile   *directory,
-                                    gboolean      force_switch_to_new_tab)
+thunar_window_notebook_add_new_tab (ThunarWindow        *window,
+                                    ThunarFile          *directory,
+                                    ThunarNewTabBehavior behavior)
 {
   ThunarHistory *history = NULL;
   GtkWidget     *view;
@@ -2364,7 +2452,8 @@ thunar_window_notebook_add_new_tab (ThunarWindow *window,
 
   /* switch to the new view */
   g_object_get (G_OBJECT (window->preferences), "misc-switch-to-new-tab", &switch_to_new_tab, NULL);
-  if (switch_to_new_tab == TRUE || force_switch_to_new_tab == TRUE)
+  if ((behavior == THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE && switch_to_new_tab == TRUE)
+    || behavior == THUNAR_NEW_TAB_BEHAVIOR_SWITCH)
     {
       page_num = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook_selected), view);
       gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook_selected), page_num);
@@ -2380,7 +2469,7 @@ void
 thunar_window_notebook_open_new_tab (ThunarWindow *window,
                                       ThunarFile  *directory)
 {
-  thunar_window_notebook_add_new_tab (window, directory, FALSE /* don't override `misc-switch-to-new-tab` preference */);
+  thunar_window_notebook_add_new_tab (window, directory, THUNAR_NEW_TAB_BEHAVIOR_FOLLOW_PREFERENCE);
 }
 
 
@@ -2756,7 +2845,7 @@ thunar_window_action_open_new_tab (ThunarWindow *window,
                                    GtkWidget    *menu_item)
 {
   /* open new tab with current directory as default */
-  thunar_window_notebook_add_new_tab (window, thunar_window_get_current_directory (window), TRUE /* force tab switch */);
+  thunar_window_notebook_add_new_tab (window, thunar_window_get_current_directory (window), THUNAR_NEW_TAB_BEHAVIOR_SWITCH);
 }
 
 
@@ -4644,7 +4733,7 @@ thunar_window_open_home_clicked   (GtkWidget      *button,
       if (open_in_tab)
         {
           page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (window->notebook_selected));
-          thunar_window_notebook_add_new_tab (window, window->current_directory, TRUE);
+          thunar_window_notebook_add_new_tab (window, window->current_directory, THUNAR_NEW_TAB_BEHAVIOR_SWITCH);
           thunar_window_action_open_home (window);
           gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook_selected), page_num);
         }
diff --git a/thunar/thunar-window.h b/thunar/thunar-window.h
index a214220aa..c20942b56 100644
--- a/thunar/thunar-window.h
+++ b/thunar/thunar-window.h
@@ -122,7 +122,7 @@ void                      thunar_window_notebook_open_new_tab               (Thu
                                                                              ThunarFile          *directory);
 void                      thunar_window_notebook_add_new_tab                (ThunarWindow        *window,
                                                                              ThunarFile          *directory,
-                                                                             gboolean             force_switch_to_new_tab);
+                                                                             ThunarNewTabBehavior behavior);
 void                      thunar_window_notebook_remove_tab                 (ThunarWindow        *window,
                                                                              gint                 tab);
 void                      thunar_window_notebook_set_current_tab            (ThunarWindow        *window,
@@ -137,7 +137,7 @@ void                      thunar_window_redirect_menu_tooltips_to_statusbar (Thu
                                                                              GtkMenu             *menu);
 const XfceGtkActionEntry* thunar_window_get_action_entry                    (ThunarWindow        *window,
                                                                              ThunarWindowAction   action);
- void                     thunar_window_select_files                        (ThunarWindow        *window,
+ void                     thunar_window_show_and_select_files               (ThunarWindow        *window,
                                                                              GList               *files_to_select);
 G_END_DECLS;
 
-- 
GitLab