+ enumerator = g_file_enumerate_children_finish (G_FILE (dir), res, &error);
+ if (enumerator == NULL)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0, error);
+ g_error_free (error);
+ }
+ }
+ else
+ {
+ g_file_enumerator_next_files_async (enumerator,
+ g_file_is_native (model->dir) ? 50 * FILES_PER_QUERY : FILES_PER_QUERY,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_files,
+ model);
+ g_object_unref (enumerator);
+ model->dir_monitor = g_file_monitor_directory (model->dir,
+ G_FILE_MONITOR_NONE,
+ model->cancellable,
+ NULL); /* we don't mind if directory monitoring isn't supported, so the GError is NULL here */
+ if (model->dir_monitor)
+ g_signal_connect (model->dir_monitor,
+ "changed",
+ G_CALLBACK (gtk_file_system_model_monitor_change),
+ model);
+ }
+
+ gdk_threads_leave ();
+}
+
+static void
+gtk_file_system_model_set_n_columns (GtkFileSystemModel *model,
+ gint n_columns,
+ va_list args)
+{
+ guint i;
+
+ g_assert (model->files == NULL);
+ g_assert (n_columns > 0);
+
+ model->n_columns = n_columns;
+ model->column_types = g_slice_alloc (sizeof (GType) * n_columns);
+
+ model->node_size = sizeof (FileModelNode) + sizeof (GValue) * (n_columns - 1); /* minus 1 because FileModelNode.values[] has a default size of 1 */
+
+ for (i = 0; i < (guint) n_columns; i++)
+ {
+ GType type = va_arg (args, GType);
+ if (! _gtk_tree_data_list_check_type (type))
+ {
+ g_error ("%s: type %s cannot be a column type for GtkFileSystemModel\n", G_STRLOC, g_type_name (type));
+ return; /* not reached */
+ }
+
+ model->column_types[i] = type;
+ }
+
+ model->sort_list = _gtk_tree_data_list_header_new (n_columns, model->column_types);
+
+ model->files = g_array_sized_new (FALSE, FALSE, model->node_size, FILES_PER_QUERY);
+ /* add editable node at start */
+ g_array_set_size (model->files, 1);
+ memset (get_node (model, 0), 0, model->node_size);
+}
+
+static void
+gtk_file_system_model_set_directory (GtkFileSystemModel *model,
+ GFile * dir,
+ const gchar * attributes)
+{
+ g_assert (G_IS_FILE (dir));
+
+ model->dir = g_object_ref (dir);
+ model->attributes = g_strdup (attributes);
+
+ g_file_enumerate_children_async (model->dir,
+ attributes,
+ G_FILE_QUERY_INFO_NONE,
+ IO_PRIORITY,
+ model->cancellable,
+ gtk_file_system_model_got_enumerator,
+ model);
+
+}
+
+static GtkFileSystemModel *
+_gtk_file_system_model_new_valist (GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ va_list args)
+{
+ GtkFileSystemModel *model;
+
+ model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
+ model->get_func = get_func;
+ model->get_data = get_data;
+
+ gtk_file_system_model_set_n_columns (model, n_columns, args);
+
+ return model;
+}
+
+/**
+ * _gtk_file_system_model_new:
+ * @get_func: function to call for getting a value
+ * @get_data: user data argument passed to @get_func
+ * @n_columns: number of columns
+ * @...: @n_columns #GType types for the columns
+ *
+ * Creates a new #GtkFileSystemModel object. You need to add files
+ * to the list using _gtk_file_system_model_add_and_query_file()
+ * or _gtk_file_system_model_update_file().
+ *
+ * Return value: the newly created #GtkFileSystemModel
+ **/
+GtkFileSystemModel *
+_gtk_file_system_model_new (GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...)
+{
+ GtkFileSystemModel *model;
+ va_list args;
+
+ g_return_val_if_fail (get_func != NULL, NULL);
+ g_return_val_if_fail (n_columns > 0, NULL);
+
+ va_start (args, n_columns);
+ model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
+ va_end (args);
+
+ return model;
+}
+
+/**
+ * _gtk_file_system_model_new_for_directory:
+ * @directory: the directory to show.
+ * @attributes: (allow-none): attributes to immediately load or %NULL for all
+ * @get_func: function that the model should call to query data about a file
+ * @get_data: user data to pass to the @get_func
+ * @n_columns: number of columns
+ * @...: @n_columns #GType types for the columns
+ *
+ * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
+ * object wraps the given @directory as a #GtkTreeModel.
+ * The model will query the given directory with the given @attributes
+ * and add all files inside the directory automatically. If supported,
+ * it will also monitor the drectory and update the model's
+ * contents to reflect changes, if the @directory supports monitoring.
+ *
+ * Return value: the newly created #GtkFileSystemModel
+ **/
+GtkFileSystemModel *
+_gtk_file_system_model_new_for_directory (GFile * dir,
+ const gchar * attributes,
+ GtkFileSystemModelGetValue get_func,
+ gpointer get_data,
+ guint n_columns,
+ ...)
+{
+ GtkFileSystemModel *model;
+ va_list args;
+
+ g_return_val_if_fail (G_IS_FILE (dir), NULL);
+ g_return_val_if_fail (get_func != NULL, NULL);
+ g_return_val_if_fail (n_columns > 0, NULL);
+
+ va_start (args, n_columns);
+ model = _gtk_file_system_model_new_valist (get_func, get_data, n_columns, args);
+ va_end (args);
+
+ gtk_file_system_model_set_directory (model, dir, attributes);
+
+ return model;
+}
+
+static void
+gtk_file_system_model_refilter_all (GtkFileSystemModel *model)
+{
+ guint i;
+
+ if (model->frozen)
+ {
+ model->filter_on_thaw = TRUE;
+ return;
+ }
+
+ freeze_updates (model);
+
+ /* start at index 1, don't change the editable */
+ for (i = 1; i < model->files->len; i++)
+ node_compute_visibility_and_filters (model, i);
+
+ model->filter_on_thaw = FALSE;
+ thaw_updates (model);
+}
+
+/**
+ * _gtk_file_system_model_set_show_hidden:
+ * @model: a #GtkFileSystemModel
+ * @show_hidden: whether hidden files should be displayed
+ *