1 /* GTK - The GIMP Toolkit
2 * gtkfilesystemmodel.c: GtkTreeModel wrapping a GtkFileSystem
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
24 #include "gtkfilechooserprivate.h"
25 #include "gtkfilesystemmodel.h"
26 #include "gtkfilesystem.h"
28 #include "gtkmarshalers.h"
29 #include "gtktreednd.h"
30 #include "gtktreemodel.h"
33 typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
35 #define GTK_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
36 #define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
37 #define GTK_FILE_SYSTEM_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
39 struct _GtkFileSystemModelClass
41 GObjectClass parent_class;
45 void (*finished_loading) (GtkFileSystemModel *model);
49 static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
50 static void gtk_file_system_model_finalize (GObject *object);
51 static void gtk_file_system_model_dispose (GObject *object);
53 static void drag_source_iface_init (GtkTreeDragSourceIface *iface);
55 static GtkTreeModelFlags gtk_file_system_model_get_flags (GtkTreeModel *tree_model);
56 static gint gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model);
57 static GType gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
59 static gboolean gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
62 static GtkTreePath * gtk_file_system_model_get_path (GtkTreeModel *tree_model,
64 static void gtk_file_system_model_get_value (GtkTreeModel *tree_model,
68 static gboolean gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
70 static gboolean gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
73 static gboolean gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
75 static gint gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
77 static gboolean gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
81 static gboolean gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
84 static void gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
86 static void gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
89 static gboolean drag_source_row_draggable (GtkTreeDragSource *drag_source,
91 static gboolean drag_source_drag_data_get (GtkTreeDragSource *drag_source,
93 GtkSelectionData *selection_data);
95 static FileModelNode *file_model_node_new (GtkFileSystemModel *model,
97 static void file_model_node_free (FileModelNode *node);
98 static void file_model_node_ref (FileModelNode *node);
99 static void file_model_node_unref (GtkFileSystemModel *model,
100 FileModelNode *node);
102 static void file_model_node_idle_clear (FileModelNode *node);
103 static void file_model_node_idle_clear_cancel (FileModelNode *node);
104 static void file_model_node_child_unref (FileModelNode *parent);
106 static GFileInfo * file_model_node_get_info (GtkFileSystemModel *model,
107 FileModelNode *node);
108 static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
109 FileModelNode *node);
110 static void file_model_node_clear (GtkFileSystemModel *model,
111 FileModelNode *node);
112 static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
113 FileModelNode *node);
115 static void deleted_callback (GFile *folder,
116 FileModelNode *node);
117 static void files_added_callback (GFile *folder,
119 FileModelNode *node);
120 static void files_changed_callback (GFile *folder,
122 FileModelNode *node);
123 static void files_removed_callback (GFile *folder,
125 FileModelNode *node);
127 static void root_deleted_callback (GFile *folder,
128 GtkFileSystemModel *model);
129 static void root_files_added_callback (GFile *folder,
131 GtkFileSystemModel *model);
132 static void root_files_changed_callback (GFile *folder,
134 GtkFileSystemModel *model);
135 static void root_files_removed_callback (GFile *folder,
137 GtkFileSystemModel *model);
145 static guint file_system_model_signals[LAST_SIGNAL] = { 0 };
149 G_DEFINE_TYPE_WITH_CODE (GtkFileSystemModel, _gtk_file_system_model, G_TYPE_OBJECT,
150 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
151 gtk_file_system_model_iface_init)
152 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
153 drag_source_iface_init))
156 _gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
158 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
160 gobject_class->finalize = gtk_file_system_model_finalize;
161 gobject_class->dispose = gtk_file_system_model_dispose;
163 file_system_model_signals[FINISHED_LOADING] =
164 g_signal_new (I_("finished-loading"),
165 G_OBJECT_CLASS_TYPE (gobject_class),
167 G_STRUCT_OFFSET (GtkFileSystemModelClass, finished_loading),
169 _gtk_marshal_VOID__VOID,
174 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
176 iface->get_flags = gtk_file_system_model_get_flags;
177 iface->get_n_columns = gtk_file_system_model_get_n_columns;
178 iface->get_column_type = gtk_file_system_model_get_column_type;
179 iface->get_iter = gtk_file_system_model_get_iter;
180 iface->get_path = gtk_file_system_model_get_path;
181 iface->get_value = gtk_file_system_model_get_value;
182 iface->iter_next = gtk_file_system_model_iter_next;
183 iface->iter_children = gtk_file_system_model_iter_children;
184 iface->iter_has_child = gtk_file_system_model_iter_has_child;
185 iface->iter_n_children = gtk_file_system_model_iter_n_children;
186 iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
187 iface->iter_parent = gtk_file_system_model_iter_parent;
188 iface->ref_node = gtk_file_system_model_ref_node;
189 iface->unref_node = gtk_file_system_model_unref_node;
193 _gtk_file_system_model_init (GtkFileSystemModel *model)
195 model->show_files = TRUE;
196 model->show_folders = TRUE;
197 model->show_hidden = FALSE;
201 gtk_file_system_model_finalize (GObject *object)
203 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
204 FileModelNode *children, *next;
206 if (model->root_folder)
207 g_object_unref (model->root_folder);
209 if (model->root_file)
210 g_object_unref (model->root_file);
212 if (model->file_system)
213 g_object_unref (model->file_system);
215 children = model->roots;
218 next = children->next;
219 file_model_node_free (children);
223 g_free (model->attributes);
225 G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->finalize (object);
230 gtk_file_system_model_dispose (GObject *object)
232 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
234 if (model->pending_cancellables)
238 for (l = model->pending_cancellables; l; l = l->next)
239 g_cancellable_cancel (l->data);
240 g_slist_free (model->pending_cancellables);
241 model->pending_cancellables = NULL;
244 G_OBJECT_CLASS (_gtk_file_system_model_parent_class)->dispose (object);
248 drag_source_iface_init (GtkTreeDragSourceIface *iface)
250 iface->row_draggable = drag_source_row_draggable;
251 iface->drag_data_get = drag_source_drag_data_get;
252 iface->drag_data_delete = NULL;
256 * ******************** GtkTreeModel methods ********************
259 static GtkTreeModelFlags
260 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
262 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
263 GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
265 if (model->max_depth == 0)
266 flags |= GTK_TREE_MODEL_LIST_ONLY;
272 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
274 return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
278 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
283 case GTK_FILE_SYSTEM_MODEL_INFO:
284 return G_TYPE_FILE_INFO;
285 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
286 return G_TYPE_STRING;
288 g_assert_not_reached ();
294 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
302 indices = gtk_tree_path_get_indices (path);
303 depth = gtk_tree_path_get_depth (path);
305 g_return_val_if_fail (depth > 0, FALSE);
307 if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
310 for (i = 1; i < depth; i++)
313 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
321 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
324 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
325 FileModelNode *node = iter->user_data;
327 GtkTreePath *result = gtk_tree_path_new ();
331 FileModelNode *parent = node->parent;
332 FileModelNode *children;
336 children = parent->children;
338 children = model->roots;
340 while (children != node)
342 if (children->is_visible)
344 children = children->next;
347 gtk_tree_path_prepend_index (result, n);
356 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
361 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
362 FileModelNode *node = iter->user_data;
367 case GTK_FILE_SYSTEM_MODEL_INFO:
368 if (model->has_editable && node == model->roots)
371 info = file_model_node_get_info (model, node);
373 g_value_set_object (value, info);
375 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
377 g_value_init (value, G_TYPE_STRING);
379 if (model->has_editable && node == model->roots)
380 g_value_set_static_string (value, "");
383 GFileInfo *info = file_model_node_get_info (model, node);
385 g_value_set_string (value, g_file_info_get_display_name (info));
390 g_assert_not_reached ();
395 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
398 FileModelNode *node = iter->user_data;
401 while (node && !node->is_visible)
404 iter->user_data = node;
410 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
414 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
415 FileModelNode *children;
419 FileModelNode *parent_node = parent->user_data;
420 children = file_model_node_get_children (model, parent_node);
424 children = model->roots;
427 while (children && !children->is_visible)
428 children = children->next;
430 iter->user_data = children;
432 return children != NULL;
436 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
439 FileModelNode *node = iter->user_data;
440 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
442 if (node->depth == model->max_depth)
446 GFileInfo *info = file_model_node_get_info (model, node);
447 return _gtk_file_info_consider_as_directory (info);
452 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
455 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
456 FileModelNode *children;
461 FileModelNode *node = iter->user_data;
462 children = file_model_node_get_children (model, node);
466 children = model->roots;
471 if (children->is_visible)
473 children = children->next;
480 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
485 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
486 FileModelNode *children;
490 FileModelNode *parent_node = parent->user_data;
491 children = file_model_node_get_children (model, parent_node);
495 children = model->roots;
498 while (children && !children->is_visible)
499 children = children->next;
501 while (n && children)
504 children = children->next;
505 while (children && !children->is_visible)
506 children = children->next;
509 iter->user_data = children;
511 return children != NULL;
515 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
519 FileModelNode *node = child->user_data;
522 iter->user_data = node;
528 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
531 file_model_node_ref (iter->user_data);
535 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
538 file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
543 drag_source_row_draggable (GtkTreeDragSource *drag_source,
546 GtkFileSystemModel *model;
550 model = GTK_FILE_SYSTEM_MODEL (drag_source);
552 if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
555 if (!model->has_editable)
558 node = iter.user_data;
559 return (node != model->roots);
563 drag_source_drag_data_get (GtkTreeDragSource *drag_source,
565 GtkSelectionData *selection_data)
567 GtkFileSystemModel *model;
572 model = GTK_FILE_SYSTEM_MODEL (drag_source);
574 if (!gtk_file_system_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
577 file = _gtk_file_system_model_get_file (model, &iter);
578 g_assert (file != NULL);
580 uris[0] = g_file_get_uri (file);
583 gtk_selection_data_set_uris (selection_data, uris);
590 /* Callback used when the root folder finished loading */
592 root_folder_finished_loading_cb (GFile *folder,
593 GtkFileSystemModel *model)
595 g_signal_emit (model, file_system_model_signals[FINISHED_LOADING], 0);
599 got_root_folder_cb (GCancellable *cancellable,
604 gboolean cancelled = g_cancellable_is_cancelled (cancellable);
605 GtkFileSystemModel *model = data;
608 tmp_list = g_slist_find (model->pending_cancellables, cancellable);
612 model->pending_cancellables = g_slist_delete_link (model->pending_cancellables,
615 if (cancelled || !folder)
618 model->root_folder = g_object_ref (folder);
620 g_signal_connect_object (model->root_folder, "finished-loading",
621 G_CALLBACK (root_folder_finished_loading_cb), model, 0);
622 g_signal_connect_object (model->root_folder, "deleted",
623 G_CALLBACK (root_deleted_callback), model, 0);
624 g_signal_connect_object (model->root_folder, "files-added",
625 G_CALLBACK (root_files_added_callback), model, 0);
626 g_signal_connect_object (model->root_folder, "files-changed",
627 G_CALLBACK (root_files_changed_callback), model, 0);
628 g_signal_connect_object (model->root_folder, "files-removed",
629 G_CALLBACK (root_files_removed_callback), model, 0);
632 g_object_unref (model);
633 g_object_unref (cancellable);
637 * _gtk_file_system_model_new:
638 * @file_system: an object implementing #GtkFileSystem
639 * @root_file: the root file path to show.
640 * @max_depth: the maximum depth from the children of @root_file
641 * or the roots of the file system to display in
642 * the file selector). A depth of 0 displays
643 * only the immediate children of @root_file,
644 * or the roots of the filesystem. -1 for no
646 * @error: location to store error, or %NULL.
648 * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
649 * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
650 * Using the @root_file and @max_depth parameters, the tree model
651 * can be restricted to a subportion of the entire file system.
653 * Return value: the newly created #GtkFileSystemModel object, or NULL if there
657 _gtk_file_system_model_new (GtkFileSystem *file_system,
660 const gchar *attributes,
663 GtkFileSystemModel *model;
664 GCancellable *cancellable;
666 g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
667 g_return_val_if_fail (G_IS_FILE (root_file), NULL);
668 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
670 /* Then, actually create the model and the root nodes */
672 model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
673 model->file_system = g_object_ref (file_system);
675 model->max_depth = G_MAXUSHORT;
677 model->max_depth = MIN (max_depth, G_MAXUSHORT);
679 model->attributes = g_strdup (attributes);
680 model->root_folder = NULL;
681 model->root_file = g_object_ref (root_file);
685 cancellable = _gtk_file_system_get_folder (file_system, root_file,
688 g_object_ref (model));
691 /* In this case got_root_folder_cb() will never be called, so we
692 * need to unref model twice.
694 g_object_unref (model);
695 g_object_unref (model);
697 g_set_error_literal (error,
698 GTK_FILE_CHOOSER_ERROR,
699 GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
700 _("Could not obtain root folder"));
705 model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
711 model_refilter_recurse (GtkFileSystemModel *model,
712 FileModelNode *parent,
715 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
717 FileModelNode *nodes;
718 gboolean has_children = FALSE;
720 if (parent && !parent->loaded)
724 nodes = parent->children;
726 nodes = model->roots;
730 FileModelNode *next = nodes->next;
733 gtk_tree_path_append_index (path, i);
735 is_visible = file_model_node_is_visible (model, nodes);
737 if (!is_visible && nodes->is_visible)
739 file_model_node_clear (model, nodes);
740 gtk_tree_model_row_deleted (tree_model, path);
742 nodes->is_visible = FALSE;
744 else if (is_visible && !nodes->is_visible)
748 iter.user_data = nodes;
749 nodes->is_visible = TRUE;
750 gtk_tree_model_row_inserted (tree_model, path, &iter);
753 model_refilter_recurse (model, nodes, path);
761 gtk_tree_path_up (path);
766 if (parent && !has_children)
768 /* Fixme - need to insert dummy node here */
773 model_refilter_all (GtkFileSystemModel *model)
777 path = gtk_tree_path_new ();
778 model_refilter_recurse (model, NULL, path);
779 gtk_tree_path_free (path);
783 * _gtk_file_system_model_set_show_hidden:
784 * @model: a #GtkFileSystemModel
785 * @show_hidden: whether hidden files should be displayed
787 * Sets whether hidden files should be included in the #GtkTreeModel
791 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
792 gboolean show_hidden)
794 show_hidden = show_hidden != FALSE;
796 if (show_hidden != model->show_hidden)
798 model->show_hidden = show_hidden;
799 model_refilter_all (model);
804 * _gtk_file_system_model_set_show_folders:
805 * @model: a #GtkFileSystemModel
806 * @show_folders: whether folders should be displayed
808 * Sets whether folders should be included in the #GtkTreeModel for
812 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
813 gboolean show_folders)
815 show_folders = show_folders != FALSE;
817 if (show_folders != model->show_folders)
819 model->show_folders = show_folders;
820 model_refilter_all (model);
825 * _gtk_file_system_model_set_show_files:
826 * @model: a #GtkFileSystemModel
827 * @show_files: whether files (as opposed to folders) should
830 * Sets whether files (as opposed to folders) should be included
831 * in the #GtkTreeModel for display.
834 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
837 show_files = show_files != FALSE;
839 if (show_files != model->show_files)
841 model->show_files = show_files;
842 model_refilter_all (model);
847 * _gtk_file_system_model_get_info:
848 * @model: a #GtkFileSystemModel
849 * @iter: a #GtkTreeIter pointing to a row of @model
851 * Gets the #GFileInfo structure for a particular row
852 * of @model. The information included in this structure
853 * is determined by the @types parameter to
854 * _gtk_file_system_model_new().
856 * Return value: a #GFileInfo structure. This structure
857 * is owned by @model and must not be modified or freed.
858 * If you want to save the information for later use,
859 * you must make a copy, since the structure may be
860 * freed on later changes to the file system. If you have
861 * called _gtk_file_system_model_add_editable() and the @iter
862 * corresponds to the row that this function returned, the
863 * return value will be NULL.
866 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
871 node = iter->user_data;
872 if (model->has_editable && node == model->roots)
875 return file_model_node_get_info (model, node);
879 * _gtk_file_system_model_get_file:
880 * @model: a #GtkFileSystemModel
881 * @iter: a #GtkTreeIter pointing to a row of @model
883 * Gets the path for a particular row in @model.
885 * Return value: the file. This object is owned by @model and
886 * or freed. If you want to save the path for later use,
887 * you must take a ref, since the object may be freed
888 * on later changes to the file system.
891 _gtk_file_system_model_get_file (GtkFileSystemModel *model,
894 FileModelNode *node = iter->user_data;
896 if (model->has_editable && node == model->roots)
900 return node->parent->file;
906 unref_node_and_parents (GtkFileSystemModel *model,
909 file_model_node_unref (model, node);
911 file_model_node_unref (model, node->parent);
914 static FileModelNode *
915 find_child_node (GtkFileSystemModel *model,
916 FileModelNode *parent_node,
919 FileModelNode *children;
922 children = file_model_node_get_children (model, parent_node);
924 children = model->roots;
928 if (children->is_visible &&
930 g_file_equal (children->file, file))
933 children = children->next;
940 * _gtk_file_system_model_set_filter:
941 * @mode: a #GtkFileSystemModel
942 * @filter: function to be called for each file
943 * @user_data: data to pass to @filter
945 * Sets a callback called for each file/directory to see whether
946 * it should be included in model. If this function was made
947 * public, we'd want to include a GDestroyNotify as well.
950 _gtk_file_system_model_set_filter (GtkFileSystemModel *model,
951 GtkFileSystemModelFilter filter,
954 g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
956 model->filter_func = filter;
957 model->filter_data = user_data;
959 model_refilter_all (model);
965 GtkFileSystemModel *model;
967 FileModelNode *parent_node;
970 GtkFileSystemModelPathFunc func;
974 /* FIXME: maybe we have to wait on finished-loading? */
976 ref_path_cb (GCancellable *cancellable,
981 struct RefPathData *info = data;
982 gboolean cancelled = g_cancellable_is_cancelled (cancellable);
984 if (!g_slist_find (info->model->pending_cancellables, cancellable))
987 info->model->pending_cancellables = g_slist_remove (info->model->pending_cancellables, cancellable);
989 /* Note that !folder means that the child node was already
990 * found, without using get_folder.
992 if (cancelled || error)
996 info->cleanups = g_slist_prepend (info->cleanups, folder);
997 else if ((info->files != NULL && info->files->next == NULL) /* g_slist_length == 1 */
998 && g_file_equal (info->node->file, info->files->data))
1000 /* Done, now call the function */
1006 iter.user_data = info->node;
1007 path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
1009 (* info->func) (info->model, path, &iter, info->user_data);
1011 gtk_tree_path_free (path);
1017 info->node = find_child_node (info->model, info->parent_node, info->files->data);
1019 file_model_node_ref (info->node);
1025 g_object_unref (info->files->data);
1026 info->files = g_slist_remove (info->files, info->files->data);
1028 if (info->files == NULL)
1030 /* Done, now call the function */
1036 iter.user_data = info->node;
1037 path = gtk_tree_model_get_path (GTK_TREE_MODEL (info->model), &iter);
1039 (* info->func) (info->model, path, &iter, info->user_data);
1041 gtk_tree_path_free (path);
1048 info->parent_node = info->node;
1050 if (info->parent_node->loaded)
1052 info->node = find_child_node (info->model, info->parent_node, info->files->data);
1053 ref_path_cb (NULL, NULL, NULL, info);
1057 GCancellable *cancellable;
1059 cancellable = _gtk_file_system_get_folder (info->model->file_system,
1061 info->model->attributes,
1063 info->model->pending_cancellables =
1064 g_slist_append (info->model->pending_cancellables, cancellable);
1072 unref_node_and_parents (info->model, info->node);
1073 g_slist_foreach (info->files, (GFunc)g_object_unref, NULL);
1074 g_slist_free (info->files);
1075 g_slist_foreach (info->cleanups, (GFunc)g_object_unref, NULL);
1076 g_slist_free (info->cleanups);
1077 g_object_unref (info->model);
1080 g_object_unref (cancellable);
1084 * _gtk_file_system_model_path_do:
1085 * @model: a #GtkFileSystemModel
1086 * @path: a path pointing to a file in the filesystem
1088 * @func: Function to call with the path and iter corresponding
1090 * @user_data: data to pass to @func
1092 * Locates @path within @model, referencing
1093 * (gtk_tree_model_ref_node()) all parent nodes,
1094 * calls @func passing in the path and iter for @path,
1095 * then unrefs all the parent nodes.
1097 * The reason for doing this operation as a callback
1098 * is so that if the operation performed with the
1099 * path and iter results in referencing the node
1100 * and/or parent nodes, we don't load all the information
1103 * This function is particularly useful for expanding
1104 * a #GtkTreeView to a particular point in the file system.
1107 _gtk_file_system_model_path_do (GtkFileSystemModel *model,
1109 GtkFileSystemModelPathFunc func,
1113 GSList *files = NULL;
1114 FileModelNode *node;
1115 struct RefPathData *info;
1117 if (g_file_equal (file, model->root_file))
1120 parent_file = g_file_get_parent (file);
1125 files = g_slist_prepend (files, g_object_ref (file));
1126 while (!g_file_equal (parent_file, model->root_file))
1128 files = g_slist_prepend (files, parent_file);
1129 parent_file = g_file_get_parent (parent_file);
1132 g_slist_foreach (files, (GFunc) g_object_unref, NULL);
1133 g_slist_free (files);
1137 g_object_unref (parent_file);
1142 /* Now we have all paths, except the root path */
1143 node = find_child_node (model, NULL, files->data);
1146 g_slist_foreach (files, (GFunc) g_object_unref, NULL);
1147 g_slist_free (files);
1151 file_model_node_ref (node);
1153 g_object_unref (files->data);
1154 files = g_slist_remove (files, files->data);
1158 /* Done, now call the function */
1164 iter.user_data = node;
1165 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
1167 (* func) (model, path, &iter, user_data);
1169 gtk_tree_path_free (path);
1170 unref_node_and_parents (model, node);
1175 info = g_new0 (struct RefPathData, 1);
1176 info->files = files;
1177 info->model = g_object_ref (model);
1179 info->user_data = user_data;
1182 if (info->node->loaded)
1184 info->parent_node = info->node;
1185 info->node = find_child_node (model, info->parent_node, info->files->data);
1186 ref_path_cb (NULL, NULL, NULL, info);
1190 GCancellable *cancellable;
1192 cancellable = _gtk_file_system_get_folder (model->file_system,
1196 model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
1202 * _gtk_file_system_model_add_editable:
1203 * @model: a #GtkFileSystemModel
1204 * @iter: Location to return the iter corresponding to the editable row
1206 * Adds an "empty" row at the beginning of the model. This does not refer to
1207 * any file, but is a temporary placeholder for a file name that the user will
1208 * type when a corresponding cell is made editable. When your code is done
1209 * using this temporary row, call _gtk_file_system_model_remove_editable().
1212 _gtk_file_system_model_add_editable (GtkFileSystemModel *model, GtkTreeIter *iter)
1214 FileModelNode *node;
1217 g_return_if_fail (!model->has_editable);
1219 model->has_editable = TRUE;
1221 node = file_model_node_new (model, NULL);
1222 node->is_visible = TRUE;
1224 node->next = model->roots;
1225 model->roots = node;
1227 path = gtk_tree_path_new ();
1228 gtk_tree_path_append_index (path, 0);
1229 iter->user_data = node;
1231 gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter);
1233 gtk_tree_path_free (path);
1237 * _gtk_file_system_model_remove_editable:
1238 * @model: a #GtkFileSystemModel
1240 * Removes the "empty" row at the beginning of the model that was
1241 * created with _gtk_file_system_model_add_editable(). You should call
1242 * this function when your code is finished editing this temporary row.
1245 _gtk_file_system_model_remove_editable (GtkFileSystemModel *model)
1248 FileModelNode *node;
1250 g_return_if_fail (model->has_editable);
1252 model->has_editable = FALSE;
1254 node = model->roots;
1255 model->roots = model->roots->next;
1256 file_model_node_free (node);
1258 path = gtk_tree_path_new ();
1259 gtk_tree_path_append_index (path, 0);
1261 gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
1263 gtk_tree_path_free (path);
1266 static FileModelNode *
1267 file_model_node_new (GtkFileSystemModel *model,
1270 FileModelNode *node = g_new0 (FileModelNode, 1);
1272 node->model = model;
1273 node->file = file ? g_object_ref (file) : NULL;
1279 file_model_node_free (FileModelNode *node)
1281 file_model_node_clear (node->model, node);
1284 g_object_unref (node->file);
1287 g_object_unref (node->info);
1293 file_model_node_get_info (GtkFileSystemModel *model,
1294 FileModelNode *node)
1300 node->info = g_file_info_new ();
1301 g_file_info_set_display_name (node->info, _("(Empty)"));
1303 else if (node->parent || model->root_folder)
1305 node->info = _gtk_folder_get_info ((node->parent != NULL) ? node->parent->folder : model->root_folder,
1309 g_assert_not_reached ();
1316 file_model_node_is_visible (GtkFileSystemModel *model,
1317 FileModelNode *node)
1319 if (model->show_folders != model->show_files ||
1320 !model->show_hidden ||
1323 GFileInfo *info = file_model_node_get_info (model, node);
1328 /* File probably disappeared underneath us or resides in a
1329 directory where we have only partial access rights. */
1333 is_folder = _gtk_file_info_consider_as_directory (info);
1335 if (model->show_folders != model->show_files &&
1336 model->show_folders != is_folder)
1339 if (!model->show_hidden &&
1340 (g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info)))
1343 if (model->filter_func &&
1344 !model->filter_func (model, node->file, info, model->filter_data))
1352 file_model_node_clear (GtkFileSystemModel *model,
1353 FileModelNode *node)
1355 FileModelNode *children;
1357 file_model_node_idle_clear_cancel (node);
1359 children = node->children;
1360 node->children = NULL;
1361 node->loaded = FALSE;
1365 FileModelNode *next = children->next;
1367 file_model_node_free (children);
1374 /* Unreffing node->folder may cause roots_changed,
1375 * so we need to be careful about ordering.
1377 GtkFolder *folder = node->folder;
1378 node->folder = NULL;
1380 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (deleted_callback), node);
1381 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_added_callback), node);
1382 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_changed_callback), node);
1383 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_removed_callback), node);
1385 g_object_unref (folder);
1390 file_model_node_ref (FileModelNode *node)
1393 if (node->ref_count == 1 && node->parent)
1394 node->parent->n_referenced_children++;
1398 idle_clear_callback (GtkFileSystemModel *model)
1400 while (model->idle_clears)
1402 FileModelNode *node = model->idle_clears->data;
1403 model->idle_clears = g_slist_delete_link (model->idle_clears, model->idle_clears);
1405 node->idle_clear = FALSE;
1406 file_model_node_clear (node->model, node);
1413 file_model_node_idle_clear (FileModelNode *node)
1415 if (!node->idle_clear)
1417 GtkFileSystemModel *model = node->model;
1419 node->idle_clear = TRUE;
1420 if (!model->idle_clears)
1422 model->idle_clear_source = g_idle_source_new ();
1423 g_source_set_priority (model->idle_clear_source, G_PRIORITY_HIGH);
1424 g_source_set_closure (model->idle_clear_source,
1425 g_cclosure_new_object (G_CALLBACK (idle_clear_callback),
1427 g_source_attach (model->idle_clear_source, NULL);
1430 model->idle_clears = g_slist_prepend (model->idle_clears, node);
1431 node->idle_clear = TRUE;
1436 file_model_node_idle_clear_cancel (FileModelNode *node)
1438 if (node->idle_clear)
1440 GtkFileSystemModel *model = node->model;
1442 model->idle_clears = g_slist_remove (model->idle_clears, node);
1443 if (!model->idle_clears)
1445 g_source_destroy (model->idle_clear_source);
1446 model->idle_clear_source = NULL;
1449 node->idle_clear = FALSE;
1454 file_model_node_unref (GtkFileSystemModel *model,
1455 FileModelNode *node)
1458 if (node->ref_count == 0)
1460 file_model_node_clear (model, node);
1462 file_model_node_child_unref (node->parent);
1467 file_model_node_child_unref (FileModelNode *parent)
1469 parent->n_referenced_children--;
1470 if (parent->n_referenced_children == 0)
1471 file_model_node_idle_clear (parent);
1474 struct GetChildrenData
1476 GtkFileSystemModel *model;
1477 FileModelNode *node;
1481 get_children_get_folder_cb (GCancellable *cancellable,
1483 const GError *error,
1484 gpointer callback_data)
1486 gboolean cancelled = g_cancellable_is_cancelled (cancellable);
1487 struct GetChildrenData *data = callback_data;
1488 FileModelNode *child_node;
1491 tmp_list = g_slist_find (data->model->pending_cancellables, cancellable);
1496 data->model->pending_cancellables = g_slist_delete_link (data->model->pending_cancellables, tmp_list);
1498 if (cancelled || !folder)
1500 /* error, no folder, remove dummy child */
1501 if (data->node->parent && data->node->parent->has_dummy)
1503 data->node->parent->children = NULL;
1504 data->node->parent->has_dummy = FALSE;
1507 file_model_node_free (data->node);
1512 data->node->folder = folder;
1513 data->node->load_pending = FALSE;
1515 g_signal_connect (data->node->folder, "deleted",
1516 G_CALLBACK (deleted_callback), data->node);
1517 g_signal_connect (data->node->folder, "files-added",
1518 G_CALLBACK (files_added_callback), data->node);
1519 g_signal_connect (data->node->folder, "files-changed",
1520 G_CALLBACK (files_changed_callback), data->node);
1521 g_signal_connect (data->node->folder, "files-removed",
1522 G_CALLBACK (files_removed_callback), data->node);
1524 data->node->loaded = TRUE;
1526 /* We claimed this folder had children, so we
1527 * have to add a dummy child, possibly to remove later.
1529 child_node = file_model_node_new (data->model, NULL);
1530 child_node->is_visible = TRUE;
1531 child_node->parent = data->node;
1532 child_node->is_dummy = TRUE;
1534 data->node->children = child_node;
1535 data->node->has_dummy = TRUE;
1537 g_object_set_data (G_OBJECT (data->node->folder), I_("model-node"), data->node);
1540 g_object_unref (data->model);
1543 g_object_unref (cancellable);
1546 static FileModelNode *
1547 file_model_node_get_children (GtkFileSystemModel *model,
1548 FileModelNode *node)
1550 if (node->ref_count == 0)
1553 if (!node->loaded && !node->load_pending)
1555 GFileInfo *info = file_model_node_get_info (model, node);
1556 gboolean has_children = FALSE;
1557 gboolean is_folder = _gtk_file_info_consider_as_directory (info);
1559 file_model_node_idle_clear_cancel (node);
1561 if (node->depth < model->max_depth && is_folder)
1563 struct GetChildrenData *data;
1564 GCancellable *cancellable;
1566 data = g_new (struct GetChildrenData, 1);
1567 data->model = g_object_ref (model);
1571 _gtk_file_system_get_folder (model->file_system,
1574 get_children_get_folder_cb,
1577 model->pending_cancellables = g_slist_append (model->pending_cancellables, cancellable);
1578 node->load_pending = TRUE;
1582 /* The hard case ... we claimed this folder had children, but actually
1583 * it didn't. We have to add a dummy child, possibly to remove later.
1585 FileModelNode *child_node = file_model_node_new (model, NULL);
1586 child_node->is_visible = TRUE;
1587 child_node->parent = node;
1588 child_node->is_dummy = TRUE;
1590 node->children = child_node;
1591 node->has_dummy = TRUE;
1596 return node->children;
1600 file_compare_func (GFile *file1,
1606 uri1 = g_file_get_uri (file1);
1607 uri2 = g_file_get_uri (file2);
1609 result = g_strcmp0 (uri1, uri2);
1618 sort_file_list (GSList *list)
1622 copy = g_slist_copy (list);
1623 return g_slist_sort (copy, (GCompareFunc) file_compare_func);
1627 do_files_added (GtkFileSystemModel *model,
1628 FileModelNode *parent_node,
1631 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1632 FileModelNode *children;
1633 FileModelNode *prev = NULL;
1636 GSList *sorted_files, *tmp_list;
1638 sorted_files = sort_file_list (files);
1642 iter.user_data = parent_node;
1643 path = gtk_tree_model_get_path (tree_model, &iter);
1644 children = parent_node->children;
1648 path = gtk_tree_path_new ();
1649 children = model->roots;
1652 gtk_tree_path_down (path);
1654 if (parent_node && parent_node->has_dummy)
1657 children = children->next;
1658 gtk_tree_path_next (path);
1661 for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
1663 GFile *file = tmp_list->data;
1666 (!children->file || !g_file_equal (children->file, file)))
1669 if (children->is_visible)
1670 gtk_tree_path_next (path);
1672 children = children->next;
1676 children->file && g_file_equal (children->file, file))
1678 /* Shouldn't happen */
1684 new = file_model_node_new (model, file);
1687 new->next = children;
1690 else if (parent_node)
1691 parent_node->children = new;
1699 new->parent = parent_node;
1700 new->depth = parent_node->depth + 1;
1703 new->is_visible = file_model_node_is_visible (model, new);
1705 if (new->is_visible)
1707 iter.user_data = new;
1708 gtk_tree_path_free (path);
1709 path = gtk_tree_model_get_path (tree_model, &iter);
1710 gtk_tree_model_row_inserted (tree_model, path, &iter);
1712 if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1713 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1715 if (parent_node && parent_node->has_dummy)
1717 FileModelNode *dummy = parent_node->children;
1718 GtkTreePath *dummy_path;
1720 parent_node->children = parent_node->children->next;
1721 parent_node->has_dummy = FALSE;
1723 dummy_path = gtk_tree_path_copy (path);
1724 gtk_tree_path_up (dummy_path);
1725 gtk_tree_path_down (dummy_path);
1727 gtk_tree_model_row_deleted (tree_model, dummy_path);
1728 gtk_tree_path_free (dummy_path);
1730 if (dummy->ref_count)
1731 file_model_node_child_unref (parent_node);
1732 file_model_node_free (dummy);
1735 gtk_tree_path_next (path);
1740 gtk_tree_path_free (path);
1741 g_slist_free (sorted_files);
1745 do_files_changed (GtkFileSystemModel *model,
1746 FileModelNode *parent_node,
1749 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1750 FileModelNode *children;
1753 GSList *sorted_files;
1756 sorted_files = sort_file_list (files);
1760 iter.user_data = parent_node;
1761 path = gtk_tree_model_get_path (tree_model, &iter);
1762 children = parent_node->children;
1766 path = gtk_tree_path_new ();
1767 children = model->roots;
1770 gtk_tree_path_down (path);
1772 if (parent_node && parent_node->has_dummy)
1774 children = children->next;
1775 gtk_tree_path_next (path);
1778 for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
1780 GFile *file = tmp_list->data;
1783 (!children->file || !g_file_equal (children->file, file)))
1785 if (children->is_visible)
1786 gtk_tree_path_next (path);
1788 children = children->next;
1792 children->file && g_file_equal (children->file, file))
1794 gtk_tree_model_row_changed (tree_model, path, &iter);
1798 /* Shouldn't happen */
1802 gtk_tree_path_free (path);
1803 g_slist_free (sorted_files);
1807 do_files_removed (GtkFileSystemModel *model,
1808 FileModelNode *parent_node,
1811 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1812 FileModelNode *children;
1813 FileModelNode *prev = NULL;
1816 GSList *sorted_files;
1818 FileModelNode *tmp_child;
1821 sorted_files = sort_file_list (files);
1825 iter.user_data = parent_node;
1826 path = gtk_tree_model_get_path (tree_model, &iter);
1827 children = parent_node->children;
1831 path = gtk_tree_path_new ();
1832 children = model->roots;
1835 /* Count the number of currently visible children, so that
1836 * can catch when we need to insert a dummy node.
1839 for (tmp_child = children; tmp_child; tmp_child = tmp_child->next)
1841 if (tmp_child->is_visible)
1845 gtk_tree_path_down (path);
1847 if (parent_node && parent_node->has_dummy)
1850 children = children->next;
1851 gtk_tree_path_next (path);
1854 for (tmp_list = sorted_files; tmp_list; tmp_list = tmp_list->next)
1856 GFile *file = tmp_list->data;
1859 (!children->file || !g_file_equal (children->file, file)))
1862 if (children->is_visible)
1863 gtk_tree_path_next (path);
1865 children = children->next;
1869 children->file && g_file_equal (children->file, file))
1871 FileModelNode *next = children->next;
1873 if (children->is_visible)
1876 if (parent_node && n_visible == 0)
1878 FileModelNode *dummy = file_model_node_new (model, NULL);
1879 dummy->is_visible = TRUE;
1880 dummy->parent = parent_node;
1881 dummy->is_dummy = TRUE;
1883 parent_node->children = dummy;
1884 parent_node->has_dummy = TRUE;
1886 iter.user_data = dummy;
1887 gtk_tree_model_row_inserted (tree_model, path, &iter);
1888 gtk_tree_path_next (path);
1895 else if (parent_node)
1896 parent_node->children = next;
1898 model->roots = next;
1900 if (parent_node && children->ref_count)
1901 file_model_node_child_unref (parent_node);
1903 if (children->is_visible)
1904 gtk_tree_model_row_deleted (tree_model, path);
1906 file_model_node_free (children);
1912 /* Shouldn't happen */
1916 gtk_tree_path_free (path);
1917 g_slist_free (sorted_files);
1921 deleted_callback (GFile *folder,
1922 FileModelNode *node)
1927 files_added_callback (GFile *folder,
1929 FileModelNode *node)
1931 do_files_added (node->model, node, files);
1935 files_changed_callback (GFile *folder,
1937 FileModelNode *node)
1939 do_files_changed (node->model, node, files);
1943 files_removed_callback (GFile *folder,
1945 FileModelNode *node)
1947 do_files_removed (node->model, node, files);
1951 root_deleted_callback (GFile *folder,
1952 GtkFileSystemModel *model)
1957 root_files_added_callback (GFile *folder,
1959 GtkFileSystemModel *model)
1961 do_files_added (model, NULL, files);
1965 root_files_changed_callback (GFile *folder,
1967 GtkFileSystemModel *model)
1969 do_files_changed (model, NULL, files);
1973 root_files_removed_callback (GFile *folder,
1975 GtkFileSystemModel *model)
1977 do_files_removed (model, NULL, files);