From a1e0c1e042e2fa41212f44ecafb81e7d0bc33e18 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 3 Nov 2011 18:27:36 +0100 Subject: [PATCH] filechooserentry: Use a GtkFileSystemModel Replace the usage of a list store and a GtkFolder with a GtkFileSystemModel. This improves performance and reduces code size. --- gtk/gtkfilechooserentry.c | 201 ++++++++++++-------------------------- 1 file changed, 65 insertions(+), 136 deletions(-) diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c index 1a517139e6..901d3e67c7 100644 --- a/gtk/gtkfilechooserentry.c +++ b/gtk/gtkfilechooserentry.c @@ -27,6 +27,7 @@ #include "gtkcelllayout.h" #include "gtkcellrenderertext.h" #include "gtkentry.h" +#include "gtkfilesystemmodel.h" #include "gtklabel.h" #include "gtkmain.h" #include "gtksizerequest.h" @@ -72,10 +73,6 @@ struct _GtkFileChooserEntry gchar *file_part; gint file_part_pos; - /* Folder being loaded or already loaded */ - GtkFolder *current_folder; - GCancellable *load_folder_cancellable; - LoadCompleteAction load_complete_action; GtkTreeModel *completion_store; @@ -154,8 +151,9 @@ typedef enum { static RefreshStatus refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, RefreshMode refresh_mode); -static void finished_loading_cb (GtkFolder *folder, - gpointer data); +static void finished_loading_cb (GtkFileSystemModel *model, + GError *error, + GtkFileChooserEntry *chooser_entry); static void autocomplete (GtkFileChooserEntry *chooser_entry); static void install_start_autocompletion_idle (GtkFileChooserEntry *chooser_entry); static void remove_completion_feedback (GtkFileChooserEntry *chooser_entry); @@ -244,9 +242,6 @@ gtk_file_chooser_entry_finalize (GObject *object) if (chooser_entry->base_folder) g_object_unref (chooser_entry->base_folder); - if (chooser_entry->current_folder) - g_object_unref (chooser_entry->current_folder); - if (chooser_entry->current_folder_file) g_object_unref (chooser_entry->current_folder_file); @@ -258,19 +253,6 @@ gtk_file_chooser_entry_finalize (GObject *object) static void discard_loading_and_current_folder_file (GtkFileChooserEntry *chooser_entry) { - if (chooser_entry->current_folder) - { - g_signal_handlers_disconnect_by_func (chooser_entry->current_folder, - G_CALLBACK (finished_loading_cb), chooser_entry); - g_object_unref (chooser_entry->current_folder); - chooser_entry->current_folder = NULL; - } - if (chooser_entry->load_folder_cancellable) - { - g_cancellable_cancel (chooser_entry->load_folder_cancellable); - chooser_entry->load_folder_cancellable = NULL; - } - if (chooser_entry->current_folder_file) { g_object_unref (chooser_entry->current_folder_file); @@ -478,7 +460,6 @@ find_common_prefix (GtkFileChooserEntry *chooser_entry, return FALSE; g_assert (parsed_folder_file != NULL - && chooser_entry->current_folder != NULL && g_file_equal (parsed_folder_file, chooser_entry->current_folder_file)); g_object_unref (parsed_folder_file); @@ -980,7 +961,6 @@ explicitly_complete (GtkFileChooserEntry *chooser_entry) { CommonPrefixResult result; - g_assert (chooser_entry->current_folder != NULL); g_assert (chooser_entry->current_folder_loaded); /* FIXME: see what Emacs does in case there is no common prefix, or there is more than one match: @@ -1054,7 +1034,7 @@ start_explicit_completion (GtkFileChooserEntry *chooser_entry) case REFRESH_OK: g_assert (chooser_entry->current_folder_file != NULL); - if (chooser_entry->current_folder && chooser_entry->current_folder_loaded) + if (chooser_entry->current_folder_loaded) explicitly_complete (chooser_entry); else { @@ -1212,53 +1192,49 @@ discard_completion_store (GtkFileChooserEntry *chooser_entry) chooser_entry->completion_store = NULL; } +static gboolean +completion_store_set (GtkFileSystemModel *model, + GFile *file, + GFileInfo *info, + int column, + GValue *value, + gpointer data) +{ + switch (column) + { + case FILE_COLUMN: + g_value_set_object (value, file); + break; + case DISPLAY_NAME_COLUMN: + if (_gtk_file_info_consider_as_directory (info)) + g_value_take_string (value, g_strconcat (g_file_info_get_display_name (info), G_DIR_SEPARATOR_S, NULL)); + else + g_value_set_string (value, g_file_info_get_display_name (info)); + break; + default: + g_assert_not_reached (); + break; + } + + return TRUE; +} + /* Fills the completion store from the contents of the current folder */ static void populate_completion_store (GtkFileChooserEntry *chooser_entry) { - GSList *files; - GSList *tmp_list; - discard_completion_store (chooser_entry); - files = _gtk_folder_list_children (chooser_entry->current_folder); - - chooser_entry->completion_store = GTK_TREE_MODEL (gtk_list_store_new (N_COLUMNS, - G_TYPE_STRING, - G_TYPE_FILE)); - - for (tmp_list = files; tmp_list; tmp_list = tmp_list->next) - { - GFileInfo *info; - GFile *file; - - file = tmp_list->data; - - info = _gtk_folder_get_info (chooser_entry->current_folder, file); - - if (info) - { - gchar *display_name = g_strdup (g_file_info_get_display_name (info)); - GtkTreeIter iter; - - if (_gtk_file_info_consider_as_directory (info)) - display_name = g_strconcat (g_file_info_get_display_name (info), G_DIR_SEPARATOR_S, NULL); - else - display_name = g_strdup (g_file_info_get_display_name (info)); - - gtk_list_store_append (GTK_LIST_STORE (chooser_entry->completion_store), &iter); - gtk_list_store_set (GTK_LIST_STORE (chooser_entry->completion_store), &iter, - DISPLAY_NAME_COLUMN, display_name, - FILE_COLUMN, file, - -1); - - g_object_unref (info); - g_free (display_name); - } - } - - g_slist_foreach (files, (GFunc) g_object_unref, NULL); - g_slist_free (files); + chooser_entry->completion_store = GTK_TREE_MODEL ( + _gtk_file_system_model_new_for_directory (chooser_entry->current_folder_file, + "standard::name,standard::display-name,standard::type", + completion_store_set, + chooser_entry, + N_COLUMNS, + G_TYPE_STRING, + G_TYPE_FILE)); + g_signal_connect (chooser_entry->completion_store, "finished-loading", + G_CALLBACK (finished_loading_cb), chooser_entry); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (chooser_entry->completion_store), DISPLAY_NAME_COLUMN, GTK_SORT_ASCENDING); @@ -1296,7 +1272,6 @@ perform_load_complete_action (GtkFileChooserEntry *chooser_entry) static void finish_folder_load (GtkFileChooserEntry *chooser_entry) { - populate_completion_store (chooser_entry); perform_load_complete_action (chooser_entry); gtk_widget_set_tooltip_text (GTK_WIDGET (chooser_entry), NULL); @@ -1304,29 +1279,11 @@ finish_folder_load (GtkFileChooserEntry *chooser_entry) /* Callback when the current folder finishes loading */ static void -finished_loading_cb (GtkFolder *folder, - gpointer data) +finished_loading_cb (GtkFileSystemModel *model, + GError *error, + GtkFileChooserEntry *chooser_entry) { - GtkFileChooserEntry *chooser_entry = GTK_FILE_CHOOSER_ENTRY (data); - chooser_entry->current_folder_loaded = TRUE; - finish_folder_load (chooser_entry); -} - -/* Callback when the current folder's handle gets obtained (not necessarily loaded completely) */ -static void -load_directory_get_folder_callback (GCancellable *cancellable, - GtkFolder *folder, - const GError *error, - gpointer data) -{ - gboolean cancelled = g_cancellable_is_cancelled (cancellable); - GtkFileChooserEntry *chooser_entry = data; - - if (cancellable != chooser_entry->load_folder_cancellable) - goto out; - - chooser_entry->load_folder_cancellable = NULL; if (error) { @@ -1344,26 +1301,11 @@ load_directory_get_folder_callback (GCancellable *cancellable, beep (chooser_entry); pop_up_completion_feedback (chooser_entry, error->message); } + + return; } - if (cancelled || error) - goto out; - - g_assert (folder != NULL); - chooser_entry->current_folder = g_object_ref (folder); - - discard_completion_store (chooser_entry); - - chooser_entry->current_folder_loaded = _gtk_folder_is_finished_loading (chooser_entry->current_folder); - if (chooser_entry->current_folder_loaded) - finish_folder_load (chooser_entry); - else - g_signal_connect (chooser_entry->current_folder, "finished-loading", - G_CALLBACK (finished_loading_cb), chooser_entry); - -out: - g_object_unref (chooser_entry); - g_object_unref (cancellable); + finish_folder_load (chooser_entry); } static RefreshStatus @@ -1373,8 +1315,7 @@ reload_current_folder (GtkFileChooserEntry *chooser_entry, g_assert (folder_file != NULL); if (chooser_entry->current_folder_file - && g_file_equal (folder_file, chooser_entry->current_folder_file) - && chooser_entry->load_folder_cancellable) + && g_file_equal (folder_file, chooser_entry->current_folder_file)) return REFRESH_OK; if (chooser_entry->current_folder_file) @@ -1387,13 +1328,9 @@ reload_current_folder (GtkFileChooserEntry *chooser_entry, return REFRESH_NOT_LOCAL; chooser_entry->current_folder_file = g_object_ref (folder_file); + chooser_entry->current_folder_loaded = FALSE; - chooser_entry->load_folder_cancellable = - _gtk_file_system_get_folder (chooser_entry->file_system, - chooser_entry->current_folder_file, - "standard::name,standard::display-name,standard::type", - load_directory_get_folder_callback, - g_object_ref (chooser_entry)); + populate_completion_store (chooser_entry); return REFRESH_OK; } @@ -1492,14 +1429,10 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, g_assert (/* we are OK and we have a current folder file and (loading process or folder handle)... */ ((result == REFRESH_OK) - && (chooser_entry->current_folder_file != NULL) - && (((chooser_entry->load_folder_cancellable != NULL) && (chooser_entry->current_folder == NULL)) - || ((chooser_entry->load_folder_cancellable == NULL) && (chooser_entry->current_folder != NULL)))) + && (chooser_entry->current_folder_file != NULL)) /* ... OR we have an error, and we don't have a current folder file nor a loading process nor a folder handle */ || ((result != REFRESH_OK) - && (chooser_entry->current_folder_file == NULL) - && (chooser_entry->load_folder_cancellable == NULL) - && (chooser_entry->current_folder == NULL))); + && (chooser_entry->current_folder_file == NULL))); return result; } @@ -1507,8 +1440,7 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry, static void autocomplete (GtkFileChooserEntry *chooser_entry) { - if (!(chooser_entry->current_folder != NULL - && chooser_entry->current_folder_loaded + if (!(chooser_entry->current_folder_loaded && gtk_editable_get_position (GTK_EDITABLE (chooser_entry)) == gtk_entry_get_text_length (GTK_ENTRY (chooser_entry)))) return; @@ -1527,7 +1459,7 @@ start_autocompletion (GtkFileChooserEntry *chooser_entry) case REFRESH_OK: g_assert (chooser_entry->current_folder_file != NULL); - if (chooser_entry->current_folder && chooser_entry->current_folder_loaded) + if (chooser_entry->current_folder_loaded) autocomplete (chooser_entry); else chooser_entry->load_complete_action = LOAD_COMPLETE_AUTOCOMPLETE; @@ -1803,22 +1735,19 @@ gboolean _gtk_file_chooser_entry_get_is_folder (GtkFileChooserEntry *chooser_entry, GFile *file) { - gboolean retval = FALSE; + GtkTreeIter iter; + GFileInfo *info; - if (chooser_entry->current_folder) - { - GFileInfo *file_info; + if (chooser_entry->completion_store == NULL || + !_gtk_file_system_model_get_iter_for_file (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store), + &iter, + file)) + return FALSE; - file_info = _gtk_folder_get_info (chooser_entry->current_folder, file); + info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store), + &iter); - if (file_info) - { - retval = _gtk_file_info_consider_as_directory (file_info); - g_object_unref (file_info); - } - } - - return retval; + return _gtk_file_info_consider_as_directory (info); }