From 0c77a5e2868343d31c8974a8996ebde501ea21f4 Mon Sep 17 00:00:00 2001
From: Benedikt Meurer <benny@xfce.org>
Date: Mon, 1 Aug 2005 12:02:57 +0000
Subject: [PATCH] 2005-08-01	Benedikt Meurer <benny@xfce.org>

	* thunar/thunar-list-model.{c,h}: Add new method
	  thunar_list_model_get_paths_for_pattern(), which is used to
	  generate a list of GtkTreePaths for all rows matching a
	  certain pattern.
	* thunar/thunar-details-view.c, thunar/thunar-icon-view.c,
	  thunar/thunar-standard-view.h: Add virtual methods select_all(),
	  unselect_all() and select_path(), and implement them in the details
	  and icon views.
	* thunar/thunar-standard-view-ui.xml, thunar/thunar-standard-view.c,
	  thunar/thunar-window-ui.xml: Add actions "select-all" and
	  "select-by-pattern" to the "Edit" menu.
	* thunar-vfs/thunar-vfs-trash.c: Cosmetic fix.




(Old svn revision: 16430)
---
 ChangeLog                          | 15 ++++++
 thunar-vfs/thunar-vfs-trash.c      |  7 +--
 thunar/thunar-details-view.c       | 47 +++++++++++++++++
 thunar/thunar-icon-view.c          | 35 +++++++++++++
 thunar/thunar-list-model.c         | 44 ++++++++++++++++
 thunar/thunar-list-model.h         | 37 +++++++------
 thunar/thunar-standard-view-ui.xml |  4 ++
 thunar/thunar-standard-view.c      | 83 +++++++++++++++++++++++++++++-
 thunar/thunar-standard-view.h      | 10 ++++
 thunar/thunar-window-ui.xml        |  2 +
 10 files changed, 261 insertions(+), 23 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b1ab79a69..665b0e37e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2005-08-01	Benedikt Meurer <benny@xfce.org>
+
+	* thunar/thunar-list-model.{c,h}: Add new method
+	  thunar_list_model_get_paths_for_pattern(), which is used to
+	  generate a list of GtkTreePaths for all rows matching a
+	  certain pattern.
+	* thunar/thunar-details-view.c, thunar/thunar-icon-view.c,
+	  thunar/thunar-standard-view.h: Add virtual methods select_all(),
+	  unselect_all() and select_path(), and implement them in the details
+	  and icon views.
+	* thunar/thunar-standard-view-ui.xml, thunar/thunar-standard-view.c,
+	  thunar/thunar-window-ui.xml: Add actions "select-all" and
+	  "select-by-pattern" to the "Edit" menu.
+	* thunar-vfs/thunar-vfs-trash.c: Cosmetic fix.
+
 2005-07-31	Benedikt Meurer <benny@xfce.org>
 
 	* thunar/thunar-local-folder.c: Properly disconnect all signal handlers
diff --git a/thunar-vfs/thunar-vfs-trash.c b/thunar-vfs/thunar-vfs-trash.c
index 17565482d..8721ae4f9 100644
--- a/thunar-vfs/thunar-vfs-trash.c
+++ b/thunar-vfs/thunar-vfs-trash.c
@@ -51,6 +51,8 @@
 /* we use g_stat() if possible */
 #if GLIB_CHECK_VERSION(2,6,0)
 #include <glib/gstdio.h>
+#else
+#define g_stat(path, buffer) (stat ((path), (buffer)))
 #endif
 
 
@@ -325,13 +327,8 @@ thunar_vfs_trash_update (ThunarVfsTrash *trash)
   GDir        *dp;
 
   /* stat the files/ subdirectory */
-#if GLIB_CHECK_VERSION(2,6,0)
   if (g_stat (trash->files_directory, &sb) == 0)
     ctime = sb.st_ctime;
-#else
-  if (stat (trash->files_directory, &sb) == 0)
-    ctime = sb.st_ctime;
-#endif
 
   /* update only if the ctimes differ */
   if (G_LIKELY (ctime == trash->update_last_ctime))
diff --git a/thunar/thunar-details-view.c b/thunar/thunar-details-view.c
index 29b893f86..266d07e41 100644
--- a/thunar/thunar-details-view.c
+++ b/thunar/thunar-details-view.c
@@ -32,6 +32,10 @@ static void       thunar_details_view_class_init          (ThunarDetailsViewClas
 static void       thunar_details_view_init                (ThunarDetailsView      *details_view);
 static AtkObject *thunar_details_view_get_accessible      (GtkWidget              *widget);
 static GList     *thunar_details_view_get_selected_items  (ThunarStandardView     *standard_view);
+static void       thunar_details_view_select_all          (ThunarStandardView     *standard_view);
+static void       thunar_details_view_unselect_all        (ThunarStandardView     *standard_view);
+static void       thunar_details_view_select_path         (ThunarStandardView     *standard_view,
+                                                           GtkTreePath            *path);
 static gboolean   thunar_details_view_button_press_event  (GtkTreeView            *tree_view,
                                                            GdkEventButton         *event,
                                                            ThunarDetailsView      *details_view);
@@ -72,6 +76,9 @@ thunar_details_view_class_init (ThunarDetailsViewClass *klass)
 
   thunarstandard_view_class = THUNAR_STANDARD_VIEW_CLASS (klass);
   thunarstandard_view_class->get_selected_items = thunar_details_view_get_selected_items;
+  thunarstandard_view_class->select_all = thunar_details_view_select_all;
+  thunarstandard_view_class->unselect_all = thunar_details_view_unselect_all;
+  thunarstandard_view_class->select_path = thunar_details_view_select_path;
 }
 
 
@@ -223,6 +230,46 @@ thunar_details_view_get_selected_items (ThunarStandardView *standard_view)
 
 
 
+static void
+thunar_details_view_select_all (ThunarStandardView *standard_view)
+{
+  GtkTreeSelection *selection;
+
+  g_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
+  gtk_tree_selection_select_all (selection);
+}
+
+
+
+static void
+thunar_details_view_unselect_all (ThunarStandardView *standard_view)
+{
+  GtkTreeSelection *selection;
+
+  g_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
+  gtk_tree_selection_unselect_all (selection);
+}
+
+
+
+static void
+thunar_details_view_select_path (ThunarStandardView *standard_view,
+                                 GtkTreePath        *path)
+{
+  GtkTreeSelection *selection;
+
+  g_return_if_fail (THUNAR_IS_DETAILS_VIEW (standard_view));
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (GTK_BIN (standard_view)->child));
+  gtk_tree_selection_select_path (selection, path);
+}
+
+
+
 static gboolean
 thunar_details_view_button_press_event (GtkTreeView       *tree_view,
                                         GdkEventButton    *event,
diff --git a/thunar/thunar-icon-view.c b/thunar/thunar-icon-view.c
index b50ce2ef1..776e39d65 100644
--- a/thunar/thunar-icon-view.c
+++ b/thunar/thunar-icon-view.c
@@ -29,6 +29,10 @@ static void       thunar_icon_view_class_init         (ThunarIconViewClass *klas
 static void       thunar_icon_view_init               (ThunarIconView      *icon_view);
 static AtkObject *thunar_icon_view_get_accessible     (GtkWidget           *widget);
 static GList     *thunar_icon_view_get_selected_items (ThunarStandardView  *standard_view);
+static void       thunar_icon_view_select_all         (ThunarStandardView  *standard_view);
+static void       thunar_icon_view_unselect_all       (ThunarStandardView  *standard_view);
+static void       thunar_icon_view_select_path        (ThunarStandardView  *standard_view,
+                                                       GtkTreePath         *path);
 static void       thunar_icon_view_item_activated     (ExoIconView         *view,
                                                        GtkTreePath         *path,
                                                        ThunarIconView      *icon_view);
@@ -62,6 +66,9 @@ thunar_icon_view_class_init (ThunarIconViewClass *klass)
 
   thunarstandard_view_class = THUNAR_STANDARD_VIEW_CLASS (klass);
   thunarstandard_view_class->get_selected_items = thunar_icon_view_get_selected_items;
+  thunarstandard_view_class->select_all = thunar_icon_view_select_all;
+  thunarstandard_view_class->unselect_all = thunar_icon_view_unselect_all;
+  thunarstandard_view_class->select_path = thunar_icon_view_select_path;
 }
 
 
@@ -116,6 +123,34 @@ thunar_icon_view_get_selected_items (ThunarStandardView *standard_view)
 
 
 
+static void
+thunar_icon_view_select_all (ThunarStandardView *standard_view)
+{
+  g_return_if_fail (THUNAR_IS_ICON_VIEW (standard_view));
+  exo_icon_view_select_all (EXO_ICON_VIEW (GTK_BIN (standard_view)->child));
+}
+
+
+
+static void
+thunar_icon_view_unselect_all (ThunarStandardView *standard_view)
+{
+  g_return_if_fail (THUNAR_IS_ICON_VIEW (standard_view));
+  exo_icon_view_unselect_all (EXO_ICON_VIEW (GTK_BIN (standard_view)->child));
+}
+
+
+
+static void
+thunar_icon_view_select_path (ThunarStandardView *standard_view,
+                              GtkTreePath        *path)
+{
+  g_return_if_fail (THUNAR_IS_ICON_VIEW (standard_view));
+  exo_icon_view_select_path (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), path);
+}
+
+
+
 static void
 thunar_icon_view_item_activated (ExoIconView    *view,
                                  GtkTreePath    *path,
diff --git a/thunar/thunar-list-model.c b/thunar/thunar-list-model.c
index 7d90a2434..6a411f527 100644
--- a/thunar/thunar-list-model.c
+++ b/thunar/thunar-list-model.c
@@ -1892,6 +1892,50 @@ thunar_list_model_get_num_files (ThunarListModel *store)
 
 
 
+/**
+ * thunar_list_model_get_paths_for_pattern:
+ * @store   : a #ThunarListModel instance.
+ * @pattern : the pattern to match.
+ *
+ * Looks up all rows in the @store that match @pattern and returns
+ * a list of #GtkTreePath<!---->s corresponding to the rows.
+ *
+ * The caller is responsible to free the returned list using:
+ * <informalexample><programlisting>
+ * g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ * g_list_free (list);
+ * </programlisting></informalexample>
+ *
+ * Return value: the list of #GtkTreePath<!---->s that match @pattern.
+ **/
+GList*
+thunar_list_model_get_paths_for_pattern (ThunarListModel *store,
+                                         const gchar     *pattern)
+{
+  GPatternSpec *pspec;
+  GList        *paths = NULL;
+  gint          index = 0;
+  Row          *row;
+
+  g_return_val_if_fail (THUNAR_IS_LIST_MODEL (store), NULL);
+  g_return_val_if_fail (g_utf8_validate (pattern, -1, NULL), NULL);
+
+  /* compile the pattern */
+  pspec = g_pattern_spec_new (pattern);
+
+  /* find all rows that match the given pattern */
+  for (row = store->rows; row != NULL; ++index, row = row->next)
+    if (g_pattern_match_string (pspec, thunar_file_get_display_name (row->file)))
+      paths = g_list_prepend (paths, gtk_tree_path_new_from_indices (index, -1));
+
+  /* release the pattern */
+  g_pattern_spec_free (pspec);
+
+  return paths;
+}
+
+
+
 /**
  * thunar_list_model_get_statusbar_text:
  * @store          : a #ThunarListModel instance.
diff --git a/thunar/thunar-list-model.h b/thunar/thunar-list-model.h
index 3c240a135..62e17635e 100644
--- a/thunar/thunar-list-model.h
+++ b/thunar/thunar-list-model.h
@@ -56,30 +56,33 @@ typedef enum
   THUNAR_LIST_MODEL_N_COLUMNS,
 } ThunarListModelColumn;
 
-GType            thunar_list_model_get_type             (void) G_GNUC_CONST;
+GType            thunar_list_model_get_type               (void) G_GNUC_CONST;
 
-ThunarListModel *thunar_list_model_new                  (void);
-ThunarListModel *thunar_list_model_new_with_folder      (ThunarFolder     *folder);
+ThunarListModel *thunar_list_model_new                    (void);
+ThunarListModel *thunar_list_model_new_with_folder        (ThunarFolder     *folder);
 
-ThunarFolder    *thunar_list_model_get_folder           (ThunarListModel  *store);
-void             thunar_list_model_set_folder           (ThunarListModel  *store,
-                                                         ThunarFolder     *folder);
+ThunarFolder    *thunar_list_model_get_folder             (ThunarListModel  *store);
+void             thunar_list_model_set_folder             (ThunarListModel  *store,
+                                                           ThunarFolder     *folder);
 
-gboolean         thunar_list_model_get_folders_first    (ThunarListModel  *store);
-void             thunar_list_model_set_folders_first    (ThunarListModel  *store,
-                                                         gboolean          folders_first);
+gboolean         thunar_list_model_get_folders_first      (ThunarListModel  *store);
+void             thunar_list_model_set_folders_first      (ThunarListModel  *store,
+                                                           gboolean          folders_first);
 
-gboolean         thunar_list_model_get_show_hidden      (ThunarListModel  *store);
-void             thunar_list_model_set_show_hidden      (ThunarListModel  *store,
-                                                         gboolean          show_hidden);
+gboolean         thunar_list_model_get_show_hidden        (ThunarListModel  *store);
+void             thunar_list_model_set_show_hidden        (ThunarListModel  *store,
+                                                           gboolean          show_hidden);
 
-ThunarFile      *thunar_list_model_get_file             (ThunarListModel  *store,
-                                                         GtkTreeIter      *iter);
+ThunarFile      *thunar_list_model_get_file               (ThunarListModel  *store,
+                                                           GtkTreeIter      *iter);
 
-gint             thunar_list_model_get_num_files        (ThunarListModel  *store);
+gint             thunar_list_model_get_num_files          (ThunarListModel  *store);
 
-gchar           *thunar_list_model_get_statusbar_text   (ThunarListModel  *store,
-                                                         GList            *selected_items);
+GList           *thunar_list_model_get_paths_for_pattern  (ThunarListModel  *store,
+                                                           const gchar      *pattern);
+
+gchar           *thunar_list_model_get_statusbar_text     (ThunarListModel  *store,
+                                                           GList            *selected_items);
 
 G_END_DECLS;
 
diff --git a/thunar/thunar-standard-view-ui.xml b/thunar/thunar-standard-view-ui.xml
index e96d0001c..96cab8539 100644
--- a/thunar/thunar-standard-view-ui.xml
+++ b/thunar/thunar-standard-view-ui.xml
@@ -23,6 +23,10 @@
         <menuitem action="cut" name="cut" />
         <menuitem action="paste" name="paste" />
       </placeholder>
+      <placeholder name="placeholder-edit-select-actions">
+        <menuitem action="select-all-files" name="select-all-files" />
+        <menuitem action="select-by-pattern" name="select-by-pattern" />
+      </placeholder>
     </menu>
 
     <menu action="view-menu" name="view-menu">
diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c
index 2a51be347..ba4f5ba19 100644
--- a/thunar/thunar-standard-view.c
+++ b/thunar/thunar-standard-view.c
@@ -83,6 +83,10 @@ static void          thunar_standard_view_action_paste              (GtkAction
                                                                      ThunarStandardView       *standard_view);
 static void          thunar_standard_view_action_paste_into_folder  (GtkAction                *action,
                                                                      ThunarStandardView       *standard_view);
+static void          thunar_standard_view_action_select_all_files   (GtkAction                *action,
+                                                                     ThunarStandardView       *standard_view);
+static void          thunar_standard_view_action_select_by_pattern  (GtkAction                *action,
+                                                                     ThunarStandardView       *standard_view);
 static void          thunar_standard_view_action_show_hidden_files  (GtkToggleAction          *toggle_action,
                                                                      ThunarStandardView       *standard_view);
 static void          thunar_standard_view_loading_unbound           (gpointer                  user_data);
@@ -96,6 +100,8 @@ struct _ThunarStandardViewPrivate
   GtkAction *action_cut;
   GtkAction *action_paste;
   GtkAction *action_paste_into_folder;
+  GtkAction *action_select_all_files;
+  GtkAction *action_select_by_pattern;
   GtkAction *action_show_hidden_files;
 };
 
@@ -108,7 +114,9 @@ static const GtkActionEntry action_entries[] =
   { "copy", GTK_STOCK_COPY, N_ ("_Copy files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_copy), },
   { "cut", GTK_STOCK_CUT, N_ ("Cu_t files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_cut), },
   { "paste", GTK_STOCK_PASTE, N_ ("_Paste files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_paste), },
-  { "paste-into-folder", GTK_STOCK_PASTE, N_ ("Paste files into folder"), NULL, N_ ("_Paste files into the selected folder"), G_CALLBACK (thunar_standard_view_action_paste_into_folder), },
+  { "paste-into-folder", GTK_STOCK_PASTE, N_ ("Paste files into folder"), NULL, N_ ("Paste files into the selected folder"), G_CALLBACK (thunar_standard_view_action_paste_into_folder), },
+  { "select-all-files", NULL, N_ ("Select _all files"), "<control>A", N_ ("Select all files in this window"), G_CALLBACK (thunar_standard_view_action_select_all_files), },
+  { "select-by-pattern", NULL, N_ ("Select by _pattern"), "<control>S", N_ ("Select all files that match a certain pattern"), G_CALLBACK (thunar_standard_view_action_select_by_pattern), },
 };
 
 static const GtkToggleActionEntry toggle_action_entries[] =
@@ -259,6 +267,8 @@ thunar_standard_view_init (ThunarStandardView *standard_view)
   standard_view->priv->action_cut = gtk_action_group_get_action (standard_view->action_group, "cut");
   standard_view->priv->action_paste = gtk_action_group_get_action (standard_view->action_group, "paste");
   standard_view->priv->action_paste_into_folder = gtk_action_group_get_action (standard_view->action_group, "paste-into-folder");
+  standard_view->priv->action_select_all_files = gtk_action_group_get_action (standard_view->action_group, "select-all-files");
+  standard_view->priv->action_select_by_pattern = gtk_action_group_get_action (standard_view->action_group, "select-by-pattern");
   standard_view->priv->action_show_hidden_files = gtk_action_group_get_action (standard_view->action_group, "show-hidden-files");
 
   standard_view->model = thunar_list_model_new ();
@@ -803,6 +813,77 @@ thunar_standard_view_action_paste_into_folder (GtkAction          *action,
 
 
 
+static void
+thunar_standard_view_action_select_all_files (GtkAction          *action,
+                                              ThunarStandardView *standard_view)
+{
+  g_return_if_fail (GTK_IS_ACTION (action));
+  g_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->select_all (standard_view);
+}
+
+
+
+static void
+thunar_standard_view_action_select_by_pattern (GtkAction          *action,
+                                               ThunarStandardView *standard_view)
+{
+  GtkWidget *window;
+  GtkWidget *dialog;
+  GtkWidget *hbox;
+  GtkWidget *label;
+  GtkWidget *entry;
+  GList     *paths;
+  GList     *lp;
+  gint       response;
+
+  g_return_if_fail (GTK_IS_ACTION (action));
+  g_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
+
+  window = gtk_widget_get_toplevel (GTK_WIDGET (standard_view));
+  dialog = gtk_dialog_new_with_buttons (_("Select by pattern"),
+                                        GTK_WINDOW (window),
+                                        GTK_DIALOG_MODAL
+                                        | GTK_DIALOG_NO_SEPARATOR
+                                        | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK, GTK_RESPONSE_OK,
+                                        NULL);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+
+  hbox = g_object_new (GTK_TYPE_HBOX, "border-width", 6, "spacing", 10, NULL);
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  label = gtk_label_new (_("Pattern:"));
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+  gtk_widget_show (label);
+
+  entry = g_object_new (GTK_TYPE_ENTRY, "activates-default", TRUE, NULL);
+  gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+  gtk_widget_show (entry);
+
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
+  if (response == GTK_RESPONSE_OK)
+    {
+      /* select all files that match the entered pattern */
+      paths = thunar_list_model_get_paths_for_pattern (standard_view->model, gtk_entry_get_text (GTK_ENTRY (entry)));
+      THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->unselect_all (standard_view);
+      for (lp = paths; lp != NULL; lp = lp->next)
+        {
+          THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->select_path (standard_view, lp->data);
+          gtk_tree_path_free (lp->data);
+        }
+      g_list_free (paths);
+    }
+
+  gtk_widget_destroy (dialog);
+}
+
+
+
 static void
 thunar_standard_view_action_show_hidden_files (GtkToggleAction    *toggle_action,
                                                ThunarStandardView *standard_view)
diff --git a/thunar/thunar-standard-view.h b/thunar/thunar-standard-view.h
index 8dde3eb1a..d92920144 100644
--- a/thunar/thunar-standard-view.h
+++ b/thunar/thunar-standard-view.h
@@ -44,6 +44,16 @@ struct _ThunarStandardViewClass
   /* Returns the list of currently selected GtkTreePath's, where
    * both the list and the items are owned by the caller. */
   GList *(*get_selected_items) (ThunarStandardView *standard_view);
+
+  /* Selects all items in the view */
+  void   (*select_all)         (ThunarStandardView *standard_view);
+
+  /* Unselects all items in the view */
+  void   (*unselect_all)       (ThunarStandardView *standard_view);
+
+  /* Selects the given item */
+  void   (*select_path)        (ThunarStandardView *standard_view,
+                                GtkTreePath        *path);
 };
 
 struct _ThunarStandardView
diff --git a/thunar/thunar-window-ui.xml b/thunar/thunar-window-ui.xml
index 53daef88c..6519b02ea 100644
--- a/thunar/thunar-window-ui.xml
+++ b/thunar/thunar-window-ui.xml
@@ -22,6 +22,8 @@
 
     <menu action="edit-menu" name="edit-menu">
       <placeholder name="placeholder-edit-clipboard-actions" />
+      <separator />
+      <placeholder name="placeholder-edit-select-actions" />
     </menu>
 
     <menu action="view-menu" name="view-menu">
-- 
GitLab