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 <jan...@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 <jan...@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 <jan...@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 <jan...@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 <be...@xfce.org> + * Copyright (c) 2009 Jannis Pohlmann <jan...@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); + } } _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org http://foo-projects.org/mailman/listinfo/xfce4-commits