[Xfce4-commits] r29929 - in thunar/branches/migration-to-gio: . thunar

Jannis Pohlmann jannis at xfce.org
Thu May 7 18:42:52 CEST 2009


Author: jannis
Date: 2009-05-07 16:42:51 +0000 (Thu, 07 May 2009)
New Revision: 29929

Added:
   thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.c
   thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.h
Modified:
   thunar/branches/migration-to-gio/ChangeLog
   thunar/branches/migration-to-gio/thunar/Makefile.am
   thunar/branches/migration-to-gio/thunar/thunar-create-dialog.h
   thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.c
   thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.h
   thunar/branches/migration-to-gio/thunar/thunar-standard-view.c
   thunar/branches/migration-to-gio/thunar/thunar-templates-action.c
Log:
	* Makefile.am, thunar/thunar-misc-jobs.{c,h}: Add new file for
	  miscellaneous jobs. Add new job
	  thunar_misc_jobs_load_template_files() which recursively loads all
	  template files/directories as ThunarFile objects from
	  G_USER_DIRECTORY_TEMPLATES.
	* thunar/thunar-gio-extensions.{c,h}: Add new method
	  g_file_new_for_user_special_dir() which creates a GFile for a
	  GUserDirectory and falls back to $HOME (so it's ignored later) if
	  the special dir is not set.
	* thunar/thunar-create-dialog.h, thunar/thunar-standard-view.c,
	  thunar/thunar-templates-action.c: Migrate ThunarTemplatesAction away
	  from ThunarVFS. Use ThunarFile instead of ThunarVfsInfo for the
	  "create-template" signal. Load the templates menu using
	  thunar_misc_jobs_load_template_files().

Modified: thunar/branches/migration-to-gio/ChangeLog
===================================================================
--- thunar/branches/migration-to-gio/ChangeLog	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/ChangeLog	2009-05-07 16:42:51 UTC (rev 29929)
@@ -1,3 +1,20 @@
+2009-05-07	Jannis Pohlmann <jannis at xfce.org>
+
+	* Makefile.am, thunar/thunar-misc-jobs.{c,h}: Add new file for
+	  miscellaneous jobs. Add new job
+	  thunar_misc_jobs_load_template_files() which recursively loads all
+	  template files/directories as ThunarFile objects from 
+	  G_USER_DIRECTORY_TEMPLATES. 
+	* thunar/thunar-gio-extensions.{c,h}: Add new method
+	  g_file_new_for_user_special_dir() which creates a GFile for a
+	  GUserDirectory and falls back to $HOME (so it's ignored later) if
+	  the special dir is not set.
+	* thunar/thunar-create-dialog.h, thunar/thunar-standard-view.c,
+	  thunar/thunar-templates-action.c: Migrate ThunarTemplatesAction away
+	  from ThunarVFS. Use ThunarFile instead of ThunarVfsInfo for the
+	  "create-template" signal. Load the templates menu using
+	  thunar_misc_jobs_load_template_files().
+
 2009-05-05	Jannis Pohlmann <jannis at xfce.org>
 
 	* configure.in.in: Depend on exo-0.3.101svn-r29926 for ExoJob.

Modified: thunar/branches/migration-to-gio/thunar/Makefile.am
===================================================================
--- thunar/branches/migration-to-gio/thunar/Makefile.am	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/Makefile.am	2009-05-07 16:42:51 UTC (rev 29929)
@@ -122,6 +122,8 @@
 	thunar-location-entry.h						\
 	thunar-metafile.c						\
 	thunar-metafile.h						\
+	thunar-misc-jobs.c						\
+	thunar-misc-jobs.h						\
 	thunar-navigator.c						\
 	thunar-navigator.h						\
 	thunar-pango-extensions.c					\

Modified: thunar/branches/migration-to-gio/thunar/thunar-create-dialog.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-create-dialog.h	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/thunar-create-dialog.h	2009-05-07 16:42:51 UTC (rev 29929)
@@ -21,7 +21,7 @@
 #ifndef __THUNAR_CREATE_DIALOG_H__
 #define __THUNAR_CREATE_DIALOG_H__
 
-#include <thunar-vfs/thunar-vfs.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS;
 

Modified: thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.c	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.c	2009-05-07 16:42:51 UTC (rev 29929)
@@ -63,6 +63,22 @@
 
 
 
+GFile *
+g_file_new_for_user_special_dir (GUserDirectory dir)
+{
+  const gchar *path;
+
+  _thunar_return_val_if_fail (dir >= 0 && dir < G_USER_N_DIRECTORIES, NULL);
+
+  path = g_get_user_special_dir (dir);
+  if (path == NULL)
+    path = xfce_get_homedir ();
+
+  return g_file_new_for_path (path);
+}
+
+
+
 gboolean
 g_file_is_root (GFile *file)
 {

Modified: thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.h	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/thunar-gio-extensions.h	2009-05-07 16:42:51 UTC (rev 29929)
@@ -24,16 +24,17 @@
 
 G_BEGIN_DECLS
 
-GFile   *g_file_new_for_home         (void);
-GFile   *g_file_new_for_root         (void);
-GFile   *g_file_new_for_trash        (void);
-GFile   *g_file_new_for_desktop      (void);
+GFile   *g_file_new_for_home              (void);
+GFile   *g_file_new_for_root              (void);
+GFile   *g_file_new_for_trash             (void);
+GFile   *g_file_new_for_desktop           (void);
+GFile   *g_file_new_for_user_special_dir  (GUserDirectory dir);
 
-gboolean g_file_is_root              (GFile       *file);
-gboolean g_file_is_trashed           (GFile       *file);
-gboolean g_file_is_desktop           (GFile       *file);
+gboolean g_file_is_root                   (GFile         *file);
+gboolean g_file_is_trashed                (GFile         *file);
+gboolean g_file_is_desktop                (GFile         *file);
 
-gchar   *g_file_size_humanize        (guint64      size);
+gchar   *g_file_size_humanize             (guint64        size);
 
 /**
  * G_TYPE_FILE_LIST:
@@ -43,20 +44,20 @@
  **/
 #define G_TYPE_FILE_LIST (g_file_list_get_type ())
 
-GType g_file_list_get_type (void);
+GType    g_file_list_get_type             (void);
 
-GList   *g_file_list_new_from_string (const gchar *string);
-gchar   *g_file_list_to_string       (GList       *list);
-GList   *g_file_list_append          (GList       *list,
-                                      GFile       *file);
-GList   *g_file_list_prepend         (GList       *list,
-                                      GFile       *file);
-GList   *g_file_list_copy            (GList       *list);
-void     g_file_list_free            (GList       *list);
+GList   *g_file_list_new_from_string      (const gchar   *string);
+gchar   *g_file_list_to_string            (GList         *list);
+GList   *g_file_list_append               (GList         *list,
+                                           GFile         *file);
+GList   *g_file_list_prepend              (GList         *list,
+                                           GFile         *file);
+GList   *g_file_list_copy                 (GList         *list);
+void     g_file_list_free                 (GList         *list);
 
-gboolean g_volume_is_removable       (GVolume     *volume);
-gboolean g_volume_is_mounted         (GVolume     *volume);
-gboolean g_volume_is_present         (GVolume     *volume);
+gboolean g_volume_is_removable            (GVolume       *volume);
+gboolean g_volume_is_mounted              (GVolume       *volume);
+gboolean g_volume_is_present              (GVolume       *volume);
 
 G_END_DECLS
 

Added: thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.c	                        (rev 0)
+++ thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.c	2009-05-07 16:42:51 UTC (rev 29929)
@@ -0,0 +1,104 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+
+#include <thunar/thunar-io-scan-directory.h>
+#include <thunar/thunar-job.h>
+#include <thunar/thunar-misc-jobs.h>
+#include <thunar/thunar-private.h>
+#include <thunar/thunar-simple-job.h>
+
+
+
+static gboolean
+_thunar_misc_jobs_load_templates (ThunarJob   *job,
+                                  GValueArray *param_values,
+                                  GError     **error)
+{
+  ThunarFile *file;
+  GtkWidget  *menu;
+  GFile      *home_dir;
+  GFile      *templates_dir;
+  GList      *files = NULL;
+  GList      *lp;
+  GList      *paths = NULL;
+
+  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
+  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  _thunar_return_val_if_fail (param_values != NULL && param_values->n_values == 1, FALSE);
+
+  menu = g_value_get_object (g_value_array_get_nth (param_values, 0));
+  g_object_set_data (G_OBJECT (job), "menu", menu);
+
+  home_dir = g_file_new_for_home ();
+  templates_dir = g_file_new_for_user_special_dir (G_USER_DIRECTORY_TEMPLATES);
+
+  if (G_LIKELY (!g_file_equal (templates_dir, home_dir)))
+    {
+      paths = thunar_io_scan_directory (job, templates_dir, 
+                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                        TRUE, NULL);
+
+      /* turn the GFile list into a ThunarFile list */
+      for (lp = g_list_last (paths); 
+           lp != NULL && !exo_job_is_cancelled (EXO_JOB (job));
+           lp = lp->prev)
+        {
+          file = thunar_file_get (lp->data, NULL);
+          if (G_LIKELY (file != NULL))
+            files = g_list_prepend (files, file);
+        }
+
+      /* free the GFile list */
+      g_file_list_free (paths);
+    }
+
+  g_object_unref (templates_dir);
+  g_object_unref (home_dir);
+
+  if (files == NULL || exo_job_is_cancelled (EXO_JOB (job)))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, 
+                   _("No templates installed"));
+
+      return FALSE;
+    }
+  else
+    {
+      if (!thunar_job_files_ready (job, files))
+        thunar_file_list_free (files);
+
+      return TRUE;
+    }
+}
+
+
+
+ThunarJob *
+thunar_misc_jobs_load_template_files (GtkWidget *menu)
+{
+  return thunar_simple_job_launch (_thunar_misc_jobs_load_templates, 1,
+                                   GTK_TYPE_MENU, menu);
+}

Added: thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.h	                        (rev 0)
+++ thunar/branches/migration-to-gio/thunar/thunar-misc-jobs.h	2009-05-07 16:42:51 UTC (rev 29929)
@@ -0,0 +1,32 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
+/*-
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __THUNAR_MISC_JOBS_H__
+#define __THUNAR_MISC_JOBS_H__
+
+#include <thunar/thunar-job.h>
+
+G_BEGIN_DECLS
+
+ThunarJob *thunar_misc_jobs_load_template_files (GtkWidget *menu);
+
+G_END_DECLS
+
+#endif /* !__THUNAR_MISC_JOBS_H__ */

Modified: thunar/branches/migration-to-gio/thunar/thunar-standard-view.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-standard-view.c	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/thunar-standard-view.c	2009-05-07 16:42:51 UTC (rev 29929)
@@ -162,7 +162,7 @@
 static void                 thunar_standard_view_action_create_folder       (GtkAction                *action,
                                                                              ThunarStandardView       *standard_view);
 static void                 thunar_standard_view_action_create_template     (GtkAction                *action,
-                                                                             const ThunarVfsInfo      *info,
+                                                                             const ThunarFile         *file,
                                                                              ThunarStandardView       *standard_view);
 static void                 thunar_standard_view_action_properties          (GtkAction                *action,
                                                                              ThunarStandardView       *standard_view);
@@ -1865,32 +1865,28 @@
 
 static void
 thunar_standard_view_action_create_template (GtkAction           *action,
-                                             const ThunarVfsInfo *info,
+                                             const ThunarFile    *file,
                                              ThunarStandardView  *standard_view)
 {
   ThunarApplication *application;
-  const gchar       *content_type;
   ThunarFile        *current_directory;
-  GFile             *file;
   GList              source_path_list;
   GList              target_path_list;
   gchar             *name;
   gchar             *title;
-  gchar             *uri;
 
-  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
   _thunar_return_if_fail (GTK_IS_ACTION (action));
-  _thunar_return_if_fail (info != NULL);
+  _thunar_return_if_fail (THUNAR_IS_FILE (file));
+  _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
 
   /* generate a title for the create dialog */
-  title = g_strdup_printf (_("Create Document from template \"%s\""), info->display_name);
+  title = g_strdup_printf (_("Create Document from template \"%s\""), 
+                           thunar_file_get_display_name (file));
 
-  content_type = thunar_vfs_mime_info_get_name (info->mime_info);
-
   /* ask the user to enter a name for the new document */
   name = thunar_show_create_dialog (GTK_WIDGET (standard_view), 
-                                    content_type, 
-                                    info->display_name, 
+                                    thunar_file_get_content_type (file), 
+                                    thunar_file_get_display_name (file), 
                                     title);
   if (G_LIKELY (name != NULL))
     {
@@ -1898,12 +1894,8 @@
       current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (standard_view));
       if (G_LIKELY (current_directory != NULL))
         {
-          uri = thunar_vfs_path_dup_uri (info->path);
-          file = g_file_new_for_uri (uri);
-          g_free (uri);
-
           /* fake the source path list */
-          source_path_list.data = file;
+          source_path_list.data = thunar_file_get_file (file);
           source_path_list.next = NULL;
           source_path_list.prev = NULL;
 
@@ -1920,7 +1912,6 @@
 
           /* release the target path */
           g_object_unref (target_path_list.data);
-          g_object_unref (source_path_list.data);
         }
 
       /* release the file name */

Modified: thunar/branches/migration-to-gio/thunar/thunar-templates-action.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-templates-action.c	2009-05-05 22:12:08 UTC (rev 29928)
+++ thunar/branches/migration-to-gio/thunar/thunar-templates-action.c	2009-05-07 16:42:51 UTC (rev 29929)
@@ -1,6 +1,7 @@
 /* $Id$ */
 /*-
  * Copyright (c) 2005-2006 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -21,8 +22,11 @@
 #include <config.h>
 #endif
 
-#include <thunar-vfs/thunar-vfs.h>
+#include <gio/gio.h>
 
+#include <thunar/thunar-icon-factory.h>
+#include <thunar/thunar-job.h>
+#include <thunar/thunar-misc-jobs.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-templates-action.h>
 
@@ -39,10 +43,9 @@
 
 
 static void       thunar_templates_action_class_init        (ThunarTemplatesActionClass *klass);
+static void       thunar_templates_action_init              (ThunarTemplatesAction      *templates_action);
+static void       thunar_templates_action_finalize          (GObject                    *object);
 static GtkWidget *thunar_templates_action_create_menu_item  (GtkAction                  *action);
-static void       thunar_templates_action_fill_menu         (ThunarTemplatesAction      *templates_action,
-                                                             ThunarVfsPath              *templates_path,
-                                                             GtkWidget                  *menu);
 static void       thunar_templates_action_menu_shown        (GtkWidget                  *menu,
                                                              ThunarTemplatesAction      *templates_action);
 
@@ -54,12 +57,14 @@
 
   void (*create_empty_file) (ThunarTemplatesAction *templates_action);
   void (*create_template)   (ThunarTemplatesAction *templates_action,
-                             const ThunarVfsInfo   *info);
+                             const ThunarFile      *file);
 };
 
 struct _ThunarTemplatesAction
 {
-  GtkAction __parent__;
+  GtkAction  __parent__;
+
+  ThunarJob *job;
 };
 
 
@@ -76,21 +81,13 @@
 
   if (G_UNLIKELY (type == G_TYPE_INVALID))
     {
-      static const GTypeInfo info =
-      {
-        sizeof (ThunarTemplatesActionClass),
-        NULL,
-        NULL,
-        (GClassInitFunc) thunar_templates_action_class_init,
-        NULL,
-        NULL,
-        sizeof (ThunarTemplatesAction),
-        0,
-        NULL,
-        NULL,
-      };
-
-      type = g_type_register_static (GTK_TYPE_ACTION, I_("ThunarTemplatesAction"), &info, 0);
+      type = g_type_register_static_simple (GTK_TYPE_ACTION,
+                                            I_("ThunarTemplatesAction"),
+                                            sizeof (ThunarTemplatesActionClass),
+                                            (GClassInitFunc) thunar_templates_action_class_init,
+                                            sizeof (ThunarTemplatesAction),
+                                            (GInstanceInitFunc) thunar_templates_action_init,
+                                            0);
     }
 
   return type;
@@ -102,10 +99,14 @@
 thunar_templates_action_class_init (ThunarTemplatesActionClass *klass)
 {
   GtkActionClass *gtkaction_class;
+  GObjectClass   *gobject_class;
 
   /* determine the parent type class */
   thunar_templates_action_parent_class = g_type_class_peek_parent (klass);
 
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = thunar_templates_action_finalize;
+
   gtkaction_class = GTK_ACTION_CLASS (klass);
   gtkaction_class->create_menu_item = thunar_templates_action_create_menu_item;
 
@@ -127,23 +128,49 @@
   /**
    * ThunarTemplatesAction::create-template:
    * @templates_action : a #ThunarTemplatesAction.
-   * @info             : the #ThunarVfsInfo of the template file.
+   * @file             : the #ThunarFile of the template file.
    *
    * Emitted by @templates_action whenever the user requests to
    * create a new file based on the template referred to by
-   * @info.
+   * @file.
    **/
   templates_action_signals[CREATE_TEMPLATE] =
     g_signal_new (I_("create-template"),
                   G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST,
                   G_STRUCT_OFFSET (ThunarTemplatesActionClass, create_template),
-                  NULL, NULL, g_cclosure_marshal_VOID__BOXED,
-                  G_TYPE_NONE, 1, THUNAR_VFS_TYPE_INFO);
+                  NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, THUNAR_TYPE_FILE);
 }
 
 
 
+static void
+thunar_templates_action_init (ThunarTemplatesAction *templates_action)
+{
+  templates_action->job = NULL;
+}
+
+
+
+static void
+thunar_templates_action_finalize (GObject *object)
+{
+  ThunarTemplatesAction *templates_action = THUNAR_TEMPLATES_ACTION (object);
+
+  if (templates_action->job != NULL)
+    {
+      g_signal_handlers_disconnect_matched (templates_action->job,
+                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
+                                            templates_action);
+      g_object_unref (templates_action->job);
+    }
+
+  (*G_OBJECT_CLASS (thunar_templates_action_parent_class)->finalize) (object);
+}
+
+
+
 static GtkWidget*
 thunar_templates_action_create_menu_item (GtkAction *action)
 {
@@ -165,256 +192,365 @@
 
 
 
-static gint
-info_compare (gconstpointer a,
-              gconstpointer b)
-{
-  const ThunarVfsInfo *info_a = a;
-  const ThunarVfsInfo *info_b = b;
-  gchar               *name_a;
-  gchar               *name_b;
-  gint                 result;
-
-  /* sort folders before files */
-  if (info_a->type == THUNAR_VFS_FILE_TYPE_DIRECTORY && info_b->type != THUNAR_VFS_FILE_TYPE_DIRECTORY)
-    return -1;
-  else if (info_a->type != THUNAR_VFS_FILE_TYPE_DIRECTORY && info_b->type == THUNAR_VFS_FILE_TYPE_DIRECTORY)
-    return 1;
-
-  /* compare by name */
-  name_a = g_utf8_casefold (info_a->display_name, -1);
-  name_b = g_utf8_casefold (info_b->display_name, -1);
-  result = g_utf8_collate (name_a, name_b);
-  g_free (name_b);
-  g_free (name_a);
-
-  return result;
-}
-
-
-
 static void
 item_activated (GtkWidget             *item,
                 ThunarTemplatesAction *templates_action)
 {
-  const ThunarVfsInfo *info;
+  const ThunarFile *file;
 
   _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
   _thunar_return_if_fail (GTK_IS_WIDGET (item));
 
-  /* check if an info is set for the item (else it's the "Empty File" item) */
-  info = g_object_get_data (G_OBJECT (item), I_("thunar-vfs-info"));
-  if (G_UNLIKELY (info != NULL))
-    g_signal_emit (G_OBJECT (templates_action), templates_action_signals[CREATE_TEMPLATE], 0, info);
+  /* check if a file is set for the item (else it's the "Empty File" item) */
+  file = g_object_get_data (G_OBJECT (item), I_("thunar-file"));
+  if (G_UNLIKELY (file != NULL))
+    {
+      g_signal_emit (G_OBJECT (templates_action), 
+                     templates_action_signals[CREATE_TEMPLATE], 0, file);
+    }
   else
-    g_signal_emit (G_OBJECT (templates_action), templates_action_signals[CREATE_EMPTY_FILE], 0);
+    {
+      g_signal_emit (G_OBJECT (templates_action), 
+                     templates_action_signals[CREATE_EMPTY_FILE], 0);
+    }
 }
 
 
 
-static void
-thunar_templates_action_fill_menu (ThunarTemplatesAction *templates_action,
-                                   ThunarVfsPath         *templates_path,
-                                   GtkWidget             *menu)
+static GtkWidget *
+find_parent_menu (ThunarFile *file,
+                  GList      *dirs,
+                  GList      *items)
 {
-  ThunarVfsInfo *info;
-  ThunarVfsPath *path;
-  GtkIconTheme  *icon_theme;
-  const gchar   *icon_name;
-  const gchar   *name;
-  GtkWidget     *submenu;
-  GtkWidget     *image;
-  GtkWidget     *item;
-  gchar         *absolute_path;
-  gchar         *label;
-  gchar         *dot;
-  GList         *info_list = NULL;
-  GList         *lp;
-  GDir          *dp;
+  GtkWidget *parent_menu = NULL;
+  GFile     *parent;
+  GList     *lp;
+  GList     *ip;
 
-  /* try to open the templates (sub)directory */
-  absolute_path = thunar_vfs_path_dup_string (templates_path);
-  dp = g_dir_open (absolute_path, 0, NULL);
-  g_free (absolute_path);
+  /* determine the parent of the file */
+  parent = g_file_get_parent (thunar_file_get_file (file));
 
-  /* read the directory contents (if opened successfully) */
-  if (G_LIKELY (dp != NULL))
+  /* check if the file has a parent at all */
+  if (parent == NULL)
+    return NULL;
+
+  /* iterate over all dirs and menu items */
+  for (lp = g_list_first (dirs), ip = g_list_first (items); 
+       parent_menu == NULL && lp != NULL && ip != NULL; 
+       lp = lp->next, ip = ip->next)
     {
-      /* process all files within the directory */
-      for (;;)
+      /* check if the current dir/item is the parent of our file */
+      if (g_file_equal (parent, thunar_file_get_file (lp->data)))
         {
-          /* read the name of the next file */
-          name = g_dir_read_name (dp);
-          if (G_UNLIKELY (name == NULL))
-            break;
-          else if (name[0] == '.')
-            continue;
+          /* we want to insert an item for the file in this menu */
+          parent_menu = gtk_menu_item_get_submenu (ip->data);
+        }
+    }
 
-          /* determine the info for that file */
-          path = thunar_vfs_path_relative (templates_path, name);
-          info = thunar_vfs_info_new_for_path (path, NULL);
-          thunar_vfs_path_unref (path);
+  /* destroy the parent GFile */
+  g_object_unref (parent);
 
-          /* add the info (if any) to our list */
-          if (G_LIKELY (info != NULL))
-            info_list = g_list_insert_sorted (info_list, info, info_compare);
-        }
+  return parent_menu;
+}
 
-      /* close the directory handle */
-      g_dir_close (dp);
+
+
+static gint
+compare_files (ThunarFile *a,
+               ThunarFile *b)
+{
+  GFile *file_a;
+  GFile *file_b;
+  GFile *parent_a;
+  GFile *parent_b;
+
+  file_a = thunar_file_get_file (a);
+  file_b = thunar_file_get_file (b);
+
+  /* check whether the files are equal */
+  if (g_file_equal (file_a, file_b))
+    return 0;
+  
+  /* directories always come first */
+  if (thunar_file_get_kind (a) == G_FILE_TYPE_DIRECTORY 
+      && thunar_file_get_kind (b) != G_FILE_TYPE_DIRECTORY)
+    {
+      return -1;
     }
+  else if (thunar_file_get_kind (a) != G_FILE_TYPE_DIRECTORY 
+           && thunar_file_get_kind (b) == G_FILE_TYPE_DIRECTORY)
+    {
+      return 1;
+    }
 
-  /* check if we have any infos */
-  if (G_UNLIKELY (info_list == NULL))
-    return;
+  /* ancestors come first */
+  if (g_file_has_prefix (file_b, file_a))
+    return -1;
+  else if (g_file_has_prefix (file_a, file_b))
+    return 1;
 
-  /* determine the icon theme for the menu */
-  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (menu));
+  parent_a = g_file_get_parent (file_a);
+  parent_b = g_file_get_parent (file_b);
 
-  /* add menu items for all infos */
-  for (lp = info_list; lp != NULL; lp = lp->next)
+  if (g_file_equal (parent_a, parent_b))
     {
-      /* determine the info */
-      info = lp->data;
+      g_object_unref (parent_a);
+      g_object_unref (parent_b);
 
-      /* check if we have a regular file or a directory here */
-      if (G_LIKELY (info->type == THUNAR_VFS_FILE_TYPE_REGULAR))
+      /* compare siblings by their display name */
+      return g_utf8_collate (thunar_file_get_display_name (a),
+                             thunar_file_get_display_name (b));
+    }
+
+  /* again, ancestors come first */
+  if (g_file_has_prefix (file_b, parent_a))
+    {
+      g_object_unref (parent_a);
+      g_object_unref (parent_b);
+
+      return -1;
+    }
+  else if (g_file_has_prefix (file_a, parent_b))
+    {
+      g_object_unref (parent_a);
+      g_object_unref (parent_b);
+
+      return 1;
+    }
+
+  g_object_unref (parent_a);
+  g_object_unref (parent_b);
+
+  return 0;
+}
+
+
+
+static gboolean
+thunar_templates_action_files_ready (ThunarJob             *job,
+                                     GList                 *files,
+                                     ThunarTemplatesAction *templates_action)
+{
+  ThunarIconFactory *icon_factory;
+  ThunarFile        *file;
+  GdkPixbuf         *icon;
+  GtkWidget         *menu;
+  GtkWidget         *parent_menu;
+  GtkWidget         *submenu;
+  GtkWidget         *image;
+  GtkWidget         *item;
+  GList             *lp;
+  GList             *dirs = NULL;
+  GList             *items = NULL;
+  GList             *parent_menus = NULL;
+  GList             *pp;
+  gchar             *label;
+  gchar             *dot;
+
+  /* determine the menu to add the items and submenus to */
+  menu = g_object_get_data (G_OBJECT (job), "menu");
+
+  /* do nothing if there is no menu */
+  if (menu == NULL)
+    return FALSE;
+
+  /* get the icon factory */
+  icon_factory = thunar_icon_factory_get_default ();
+
+  /* sort items so that directories come before files and ancestors come 
+   * before descendants */
+  files = g_list_sort (files, (GCompareFunc) compare_files);
+
+  for (lp = g_list_first (files); lp != NULL; lp = lp->next)
+    {
+      file = lp->data;
+      
+      /* determine the parent menu for this file/directory */
+      parent_menu = find_parent_menu (file, dirs, items);
+      parent_menu = parent_menu == NULL ? menu : parent_menu;
+
+      if (thunar_file_get_kind (file) == G_FILE_TYPE_DIRECTORY)
         {
+          /* allocate a new submenu for the directory */
+          submenu = gtk_menu_new ();
+          exo_gtk_object_ref_sink (GTK_OBJECT (submenu));
+          gtk_menu_set_screen (GTK_MENU (submenu), gtk_widget_get_screen (menu));
+
+          /* allocate a new menu item for the directory */
+          item = gtk_image_menu_item_new_with_label (thunar_file_get_display_name (file));
+          gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
+
+          /* prepend the directory, its item and the parent menu it should 
+           * later be added to to the respective lists */
+          dirs = g_list_prepend (dirs, file);
+          items = g_list_prepend (items, item);
+          parent_menus = g_list_prepend (parent_menus, parent_menu);
+        }
+      else
+        {
           /* generate a label by stripping off the extension */
-          label = g_strdup (info->display_name);
+          label = g_strdup (thunar_file_get_display_name (file));
           dot = g_utf8_strrchr (label, -1, '.');
           if (G_LIKELY (dot != NULL))
             *dot = '\0';
 
           /* allocate a new menu item */
           item = gtk_image_menu_item_new_with_label (label);
-          g_object_set_data_full (G_OBJECT (item), I_("thunar-vfs-info"), thunar_vfs_info_ref (info), (GDestroyNotify) thunar_vfs_info_unref);
-          g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (item_activated), templates_action);
-          gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+          g_object_set_data_full (G_OBJECT (item), I_("thunar-file"), 
+                                  g_object_ref (file), g_object_unref);
+          g_signal_connect (item, "activate", G_CALLBACK (item_activated), 
+                            templates_action);
+          gtk_menu_shell_append (GTK_MENU_SHELL (parent_menu), item);
           gtk_widget_show (item);
-
-          /* lookup the icon for the mime type of that file */
-          icon_name = thunar_vfs_mime_info_lookup_icon_name (info->mime_info, icon_theme);
-
-          /* generate an image based on the named icon */
-          image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
-          gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-          gtk_widget_show (image);
-
-          /* cleanup */
-          g_free (label);
         }
-      else if (info->type == THUNAR_VFS_FILE_TYPE_DIRECTORY)
-        {
-          /* allocate a new submenu for the directory */
-          submenu = gtk_menu_new ();
-          exo_gtk_object_ref_sink (GTK_OBJECT (submenu));
-          gtk_menu_set_screen (GTK_MENU (submenu), gtk_widget_get_screen (menu));
 
-          /* fill the submenu from the folder contents */
-          thunar_templates_action_fill_menu (templates_action, info->path, submenu);
+      /* determine the icon for this file/directory */
+      icon = thunar_icon_factory_load_file_icon (icon_factory, file,
+                                                 THUNAR_FILE_ICON_STATE_DEFAULT,
+                                                 GTK_ICON_SIZE_MENU);
 
-          /* check if any items were added to the submenu */
-          if (G_LIKELY (GTK_MENU_SHELL (submenu)->children != NULL))
-            {
-              /* hook up the submenu */
-              item = gtk_image_menu_item_new_with_label (info->display_name);
-              gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
-              gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-              gtk_widget_show (item);
+      /* allocate an image based on the icon */
+      image = gtk_image_new_from_pixbuf (icon);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      gtk_widget_show (image);
 
-              /* lookup the icon for the mime type of that file */
-              icon_name = thunar_vfs_mime_info_lookup_icon_name (info->mime_info, icon_theme);
+      /* release the icon reference */
+      g_object_unref (icon);
+    }
 
-              /* generate an image based on the named icon */
-              image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
-              gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-              gtk_widget_show (image);
-            }
+  /* add all non-empty directory items to their parent menu */
+  for (lp = items, pp = parent_menus; 
+       lp != NULL && pp != NULL; 
+       lp = lp->next, pp = pp->next)
+    {
+      /* determine the submenu for this directory item */
+      submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (lp->data));
 
-          /* cleanup */
-          g_object_unref (G_OBJECT (submenu));
+      if (GTK_MENU_SHELL (submenu)->children == NULL)
+        {
+          /* the directory submenu is empty, destroy it */
+          gtk_widget_destroy (lp->data);
         }
+      else
+        {
+          /* the directory has template files, so add it to its parent menu */
+          gtk_menu_shell_prepend (GTK_MENU_SHELL (pp->data), lp->data);
+          gtk_widget_show (lp->data);
+        }
     }
 
-  /* release the info list */
-  thunar_vfs_info_list_free (info_list);
+  /* destroy lists */
+  g_list_free (dirs);
+  g_list_free (items);
+  g_list_free (parent_menus);
+
+  /* release the icon factory */
+  g_object_unref (icon_factory);
+
+  /* let the job destroy the file list */
+  return FALSE;
 }
 
 
 
 static void
-thunar_templates_action_menu_shown (GtkWidget             *menu,
+thunar_templates_action_load_error (ThunarJob             *job,
+                                    GError                *error,
                                     ThunarTemplatesAction *templates_action)
 {
-  ThunarVfsPath *templates_path;
-  ThunarVfsPath *home_path;
-  GtkWidget     *image;
-  GtkWidget     *item;
-  GList         *children;
-  gchar         *templates_dir = NULL;
+  GtkWidget *item;
+  GtkWidget *menu;
 
+  _thunar_return_if_fail (THUNAR_IS_JOB (job));
+  _thunar_return_if_fail (error != NULL);
   _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
-  _thunar_return_if_fail (GTK_IS_MENU_SHELL (menu));
+  _thunar_return_if_fail (templates_action->job == job);
 
-  /* drop all existing children of the menu first */
-  children = gtk_container_get_children (GTK_CONTAINER (menu));
-  g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
-  g_list_free (children);
+  menu = g_object_get_data (G_OBJECT (job), "menu");
 
-  /* determine the path to the ~/Templates folder */
-  home_path = thunar_vfs_path_get_for_home ();
-
-  templates_dir = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES));
-  if (G_UNLIKELY (templates_dir == NULL))
+  /* check if any items were added to the menu */
+  if (G_LIKELY (menu != NULL && GTK_MENU_SHELL (menu)->children == NULL))
     {
-      templates_dir = g_build_filename (G_DIR_SEPARATOR_S, xfce_get_homedir (),
-                                        "Templates", NULL);
+      /* tell the user that no templates were found */
+      item = gtk_menu_item_new_with_label (error->message);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_set_sensitive (item, FALSE);
+      gtk_widget_show (item);
     }
+}
 
-  templates_path = thunar_vfs_path_new (templates_dir, NULL);
-  if (G_UNLIKELY (templates_path == NULL))
-    templates_path = thunar_vfs_path_relative (home_path,"Templates");
 
-  g_free (templates_dir);
 
-  thunar_vfs_path_unref (home_path);
+static void
+thunar_templates_action_load_finished (ThunarJob             *job,
+                                       ThunarTemplatesAction *templates_action)
+{
+  GtkWidget *image;
+  GtkWidget *item;
+  GtkWidget *menu;
 
-  if (!exo_str_is_equal (g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES), 
-                         xfce_get_homedir ()))
-    {
-      /* fill the menu with files/folders from the ~/Templates folder */
-      thunar_templates_action_fill_menu (templates_action, templates_path, menu);
-    }
+  _thunar_return_if_fail (THUNAR_IS_JOB (job));
+  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
+  _thunar_return_if_fail (templates_action->job == job);
 
-  /* check if any items were added to the menu */
-  if (G_UNLIKELY (GTK_MENU_SHELL (menu)->children == NULL))
+  menu = g_object_get_data (G_OBJECT (job), "menu");
+  if (G_LIKELY (menu != NULL))
     {
-      /* tell the user that no templates were found */
-      item = gtk_menu_item_new_with_label (_("No Templates installed"));
+      /* append a menu separator */
+      item = gtk_separator_menu_item_new ();
       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-      gtk_widget_set_sensitive (item, FALSE);
       gtk_widget_show (item);
+
+      /* add the "Empty File" item */
+      item = gtk_image_menu_item_new_with_mnemonic (_("_Empty File"));
+      g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (item_activated), 
+                        templates_action);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+      gtk_widget_show (item);
+
+      /* add the icon for the emtpy file item */
+      image = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU);
+      gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+      gtk_widget_show (image);
     }
 
-  /* append a menu separator */
-  item = gtk_separator_menu_item_new ();
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show (item);
+  g_signal_handlers_disconnect_matched (job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
+                                        templates_action);
+  g_object_unref (job);
+}
 
-  /* add the "Empty File" item */
-  item = gtk_image_menu_item_new_with_mnemonic (_("_Empty File"));
-  g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (item_activated), templates_action);
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-  gtk_widget_show (item);
 
-  /* add the icon for the emtpy file item */
-  image = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
-  gtk_widget_show (image);
 
-  /* cleanup */
-  thunar_vfs_path_unref (templates_path);
+static void
+thunar_templates_action_menu_shown (GtkWidget             *menu,
+                                    ThunarTemplatesAction *templates_action)
+{
+  GList *children;
+
+  _thunar_return_if_fail (THUNAR_IS_TEMPLATES_ACTION (templates_action));
+  _thunar_return_if_fail (GTK_IS_MENU_SHELL (menu));
+
+  /* drop all existing children of the menu first */
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  g_list_foreach (children, (GFunc) gtk_widget_destroy, NULL);
+  g_list_free (children);
+
+  if (G_LIKELY (templates_action->job == NULL))
+    {
+      templates_action->job = thunar_misc_jobs_load_template_files (menu);
+      g_object_add_weak_pointer (G_OBJECT (templates_action->job),
+                                 (gpointer) &templates_action->job);
+
+      g_signal_connect (templates_action->job, "files-ready",
+                        G_CALLBACK (thunar_templates_action_files_ready), 
+                        templates_action);
+      g_signal_connect (templates_action->job, "error",
+                        G_CALLBACK (thunar_templates_action_load_error), 
+                        templates_action);
+      g_signal_connect (templates_action->job, "finished",
+                        G_CALLBACK (thunar_templates_action_load_finished), 
+                        templates_action);
+    }
 }
 
 




More information about the Xfce4-commits mailing list