[gtk+/filesystemmodel] add directory monitoring with API to manually add and remove files
- From: Benjamin Otte <otte src gnome org>
- To: svn-commits-list gnome org
- Subject: [gtk+/filesystemmodel] add directory monitoring with API to manually add and remove files
- Date: Wed, 24 Jun 2009 21:13:14 +0000 (UTC)
commit cd91f5bdbe4421d253206bb13137ffdf29d1943d
Author: Benjamin Otte <otte gnome org>
Date: Wed Jun 24 10:12:49 2009 +0200
add directory monitoring with API to manually add and remove files
gtk/gtkfilechooserdefault.c | 2 +-
gtk/gtkfilesystemmodel.c | 233 ++++++++++++++++++++++++++++++++-----------
gtk/gtkfilesystemmodel.h | 8 ++-
3 files changed, 183 insertions(+), 60 deletions(-)
---
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index d5e891a..13e93fc 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -6756,7 +6756,7 @@ file_system_model_got_thumbnail (GObject *object, GAsyncResult *res, gpointer da
copy_attribute (info, queried, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
copy_attribute (info, queried, G_FILE_ATTRIBUTE_STANDARD_ICON);
- _gtk_file_system_update_file (model, file, info, FALSE);
+ _gtk_file_system_model_update_file (model, file, info, FALSE);
g_object_unref (info);
}
diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c
index a5cf03a..ef3df19 100644
--- a/gtk/gtkfilesystemmodel.c
+++ b/gtk/gtkfilesystemmodel.c
@@ -65,7 +65,7 @@ struct _GtkFileSystemModel
GFile * dir; /* directory that's displayed */
guint dir_thaw_source;/* GSource id for unfreezing the model */
char * attributes; /* attributes the file info must contain */
- char * full_attributes;/* attributes the file info should contain */
+ GFileMonitor * dir_monitor; /* directory that is monitored */
GCancellable * cancellable; /* cancellable in use for all operations - cancelled on dispose */
GArray * files; /* array of FileModelNode containing all our files */
@@ -767,6 +767,8 @@ gtk_file_system_model_dispose (GObject *object)
GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
g_cancellable_cancel (model->cancellable);
+ if (model->dir_monitor)
+ g_file_monitor_cancel (model->dir_monitor);
G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->dispose (object);
}
@@ -790,7 +792,10 @@ gtk_file_system_model_finalize (GObject *object)
g_object_unref (model->cancellable);
g_free (model->attributes);
- g_object_unref (model->dir);
+ if (model->dir)
+ g_object_unref (model->dir);
+ if (model->dir_monitor)
+ g_object_unref (model->dir_monitor);
g_hash_table_destroy (model->file_lookup);
_gtk_tree_data_list_header_free (model->sort_list);
@@ -818,25 +823,6 @@ _gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
-/* NB: takes ownership of file and info */
-static void
-gtk_file_system_model_add_node (GtkFileSystemModel *model, GFile *file, GFileInfo *info)
-{
- FileModelNode *node = g_slice_alloc0 (NODE_SIZE (model));
-
- node->file = file;
- node->info = info;
- node->frozen_add = model->frozen ? TRUE : FALSE;
-
- g_array_append_vals (model->files, node, 1);
- g_slice_free1 (NODE_SIZE (model), node);
-
- if (!model->frozen)
- node_set_visible (model, model->files->len -1,
- node_should_be_visible (model, model->files->len - 1));
- gtk_file_system_model_sort_node (model, model->files->len -1);
-}
-
static void
_gtk_file_system_model_init (GtkFileSystemModel *model)
{
@@ -908,7 +894,9 @@ gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer da
continue;
}
file = g_file_get_child (model->dir, name);
- gtk_file_system_model_add_node (model, file, info);
+ _gtk_file_system_model_add_file (model, file, info);
+ g_object_unref (file);
+ g_object_unref (info);
}
g_list_free (files);
}
@@ -946,6 +934,56 @@ gtk_file_system_model_got_files (GObject *object, GAsyncResult *res, gpointer da
}
static void
+gtk_file_system_model_query_done (GObject * object,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GtkFileSystemModel *model = data; /* only a valid pointer if not cancelled */
+ GFile *file = G_FILE (object);
+ GFileInfo *info;
+
+ info = g_file_query_info_finish (file, res, NULL);
+ if (info == NULL)
+ return;
+
+ _gtk_file_system_model_update_file (model, file, info, TRUE);
+}
+
+static void
+gtk_file_system_model_monitor_change (GFileMonitor * monitor,
+ GFile * file,
+ GFile * other_file,
+ GFileMonitorEvent type,
+ GtkFileSystemModel *model)
+{
+ switch (type)
+ {
+ case G_FILE_MONITOR_EVENT_CREATED:
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ /* We can treat all of these the same way */
+ g_file_query_info_async (file,
+ model->attributes,
+ 0,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_query_done,
+ model);
+ break;
+ case G_FILE_MONITOR_EVENT_DELETED:
+ _gtk_file_system_model_remove_file (model, file);
+ break;
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ /* FIXME: use freeze/thaw with this somehow? */
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ default:
+ /* ignore these */
+ break;
+ }
+}
+
+static void
gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer data)
{
GtkFileSystemModel *model = data;
@@ -970,6 +1008,15 @@ gtk_file_system_model_got_enumerator (GObject *dir, GAsyncResult *res, gpointer
gtk_file_system_model_got_files,
model);
g_object_unref (enumerator);
+ model->dir_monitor = g_file_monitor_directory (model->dir,
+ 0,
+ model->cancellable,
+ NULL);
+ if (model->dir_monitor)
+ g_signal_connect (model->dir_monitor,
+ "changed",
+ G_CALLBACK (gtk_file_system_model_monitor_change),
+ model);
}
gdk_threads_leave ();
@@ -1003,28 +1050,42 @@ gtk_file_system_model_set_n_columns (GtkFileSystemModel *model,
model->files = g_array_new (FALSE, FALSE, NODE_SIZE (model));
/* add editable node at start */
- gtk_file_system_model_add_node (model, NULL, NULL);
+ g_array_set_size (model->files, 1);
+ memset (get_node (model, 0), 0, NODE_SIZE (model));
+}
+
+static void
+gtk_file_system_model_set_directory (GtkFileSystemModel *model,
+ GFile * dir,
+ const gchar * attributes)
+{
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (dir == NULL || G_IS_FILE (dir));
+
+ model->dir = g_object_ref (dir);
+ model->attributes = g_strdup (attributes);
+
+ g_object_ref (model);
+ g_file_enumerate_children_async (model->dir,
+ attributes,
+ 0,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_enumerator,
+ model);
+
}
/**
* _gtk_file_system_model_new:
* @directory: the directory to show.
* @attributes: attributes to immediately load or %NULL for all
- * @full_attributes: %NULL or a superset of @attributes
* @error: location to store error, or %NULL.
*
* Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
* object wraps the given @directory as a #GtkTreeModel.
* The model will query the given @attributes immediately and only add
- * files with those attributes present. After all files have been added,
- * @full_attributes will be queried on-demand and the file infos will be
- * updated. The GtkTreeModel::row-changed signal will be emitted when this
- * happens. It is suggested that you only query attributes that are
- * immediately necessary for using this model and add all other attributes
- * to @full_attributes to avoid slow load times. Worst offenders are
- * content type and thumbnails.
- * If @full_attributes is non-%NULL, the model will also initially not
- * follow symlinks to improve load times.
+ * files with those attributes present.
*
* Return value: the newly created #GtkFileSystemModel object, or NULL if there
* was an error.
@@ -1043,8 +1104,6 @@ _gtk_file_system_model_new (GFile * dir,
g_return_val_if_fail (G_IS_FILE (dir), NULL);
model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
- model->dir = g_object_ref (dir);
- model->attributes = g_strdup (attributes);
model->get_func = get_func;
model->get_data = get_data;
@@ -1052,14 +1111,7 @@ _gtk_file_system_model_new (GFile * dir,
gtk_file_system_model_set_n_columns (model, n_columns, args);
va_end (args);
- g_object_ref (model);
- g_file_enumerate_children_async (dir,
- attributes,
- 0,
- IO_PRIORITY,
- model->cancellable,
- gtk_file_system_model_got_enumerator,
- model);
+ gtk_file_system_model_set_directory (model, dir, attributes);
return model;
}
@@ -1171,15 +1223,12 @@ _gtk_file_system_model_get_cancellable (GtkFileSystemModel *model)
* @iter: a #GtkTreeIter pointing to a row of @model
*
* Gets the #GFileInfo structure for a particular row
- * of @model. The information included in this structure
- * is determined by the attributes and full_attributes
- * parameter to _gtk_file_system_model_new(). Note that the
- * full_attributes might not be filled in yet.
+ * of @model.
*
* Return value: a #GFileInfo structure. This structure
* is owned by @model and must not be modified or freed.
- * If you want to save the information for later use,
- * you must make a copy, since the structure may be
+ * If you want to keep the information for later use,
+ * you must take a reference, since the structure may be
* freed on later changes to the file system. If you have
* called _gtk_file_system_model_add_editable() and the @iter
* corresponds to the row that this function returned, the
@@ -1313,20 +1362,87 @@ _gtk_file_system_model_get_iter_for_file (GtkFileSystemModel *model,
}
/**
- * _gtk_file_system_update_file:
+ * _gtk_file_system_model_add_file:
+ * @model: the model
+ * @file: the file to add
+ * @info: the information to associate with the file
+ *
+ * Adds the given @file with its associated @info to the @model.
+ * If the model is frozen, the file will only show up after it is thawn.
+ **/
+void
+_gtk_file_system_model_add_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info)
+{
+ FileModelNode *node;
+
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (G_IS_FILE_INFO (info));
+
+ node = g_slice_alloc0 (NODE_SIZE (model));
+ node->file = g_object_ref (file);
+ if (info)
+ node->info = g_object_ref (info);
+ node->frozen_add = model->frozen ? TRUE : FALSE;
+
+ g_array_append_vals (model->files, node, 1);
+ g_slice_free1 (NODE_SIZE (model), node);
+
+ if (!model->frozen)
+ node_set_visible (model, model->files->len -1,
+ node_should_be_visible (model, model->files->len - 1));
+ gtk_file_system_model_sort_node (model, model->files->len -1);
+}
+
+/**
+ * _gtk_file_system_model_remove_file:
+ * @model: the model
+ * @file: file to remove from the model. The file must have been
+ * added to the model previously
+ *
+ * Removes the given file from the model. If the file is not part of
+ * @model, this function does nothing.
+ **/
+void
+_gtk_file_system_model_remove_file (GtkFileSystemModel *model,
+ GFile *file)
+{
+ FileModelNode *node;
+ guint id;
+
+ g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
+ g_return_if_fail (G_IS_FILE (file));
+
+ id = node_get_for_file (model, file);
+ if (id == 0)
+ return;
+
+ node = get_node (model, id);
+ node_set_visible (model, id, FALSE);
+ g_object_unref (node->file);
+ if (node->info)
+ g_object_unref (node->info);
+ g_array_remove_index (model->files, id);
+}
+
+/**
+ * _gtk_file_system_model_update_file:
* @model: the model
- * @file: the file, which must be part of the model
+ * @file: the file
* @info: the new file info
* @requires_resort: FIXME: get rid of this argument
*
* Tells the file system model that the file changed and that the
- * new @info should be used for it now.
+ * new @info should be used for it now. If the file is not part of
+ * @model, it will get added automatically.
**/
void
-_gtk_file_system_update_file (GtkFileSystemModel *model,
- GFile *file,
- GFileInfo *info,
- gboolean requires_resort)
+_gtk_file_system_model_update_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info,
+ gboolean requires_resort)
{
FileModelNode *node;
guint i, id;
@@ -1337,7 +1453,7 @@ _gtk_file_system_update_file (GtkFileSystemModel *model,
id = node_get_for_file (model, file);
if (id == 0)
- g_assert_not_reached ();
+ _gtk_file_system_model_add_file (model, file, info);
node = get_node (model, id);
if (node->info)
@@ -1498,7 +1614,8 @@ void
_gtk_file_system_model_clear_cache (GtkFileSystemModel *model,
int column)
{
- guint i, start, end;
+ guint i;
+ int start, end;
gboolean changed;
g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
diff --git a/gtk/gtkfilesystemmodel.h b/gtk/gtkfilesystemmodel.h
index cb91fce..a6cc44b 100644
--- a/gtk/gtkfilesystemmodel.h
+++ b/gtk/gtkfilesystemmodel.h
@@ -58,7 +58,13 @@ GFile * _gtk_file_system_model_get_file (GtkFileSystemModel
const GValue * _gtk_file_system_model_get_value (GtkFileSystemModel *model,
GtkTreeIter * iter,
int column);
-void _gtk_file_system_update_file (GtkFileSystemModel *model,
+
+void _gtk_file_system_model_add_file (GtkFileSystemModel *model,
+ GFile *file,
+ GFileInfo *info);
+void _gtk_file_system_model_remove_file (GtkFileSystemModel *model,
+ GFile *file);
+void _gtk_file_system_model_update_file (GtkFileSystemModel *model,
GFile *file,
GFileInfo *info,
gboolean requires_resort);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]