filechooserentry: Use a GtkFileSystemModel

Replace the usage of a list store and a GtkFolder with a
GtkFileSystemModel. This improves performance and reduces code size.
This commit is contained in:
Benjamin Otte 2011-11-03 18:27:36 +01:00
parent 06a64daefc
commit a1e0c1e042

View File

@ -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);
}