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.
21 #include "gtkfilesystemmodel.h"
22 #include "gtkfilesystem.h"
23 #include <gtk/gtktreemodel.h>
26 typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
27 typedef struct _FileModelNode FileModelNode;
29 #define GTK_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
30 #define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
31 #define GTK_FILE_SYSTEM_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
33 struct _GtkFileSystemModelClass
35 GObjectClass parent_class;
38 struct _GtkFileSystemModel
40 GObject parent_instance;
42 GtkFileSystem *file_system;
43 GtkFileInfoType types;
45 GtkFileFolder *root_folder;
49 guint show_hidden : 1;
50 guint show_folders : 1;
52 guint folders_only : 1;
61 GtkFileFolder *folder;
63 FileModelNode *children;
64 FileModelNode *parent;
65 GtkFileSystemModel *model;
77 static void gtk_file_system_model_class_init (GtkFileSystemModelClass *class);
78 static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
79 static void gtk_file_system_model_init (GtkFileSystemModel *model);
80 static void gtk_file_system_model_finalize (GObject *object);
82 static GtkTreeModelFlags gtk_file_system_model_get_flags (GtkTreeModel *tree_model);
83 static gint gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model);
84 static GType gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
86 static gboolean gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
89 static GtkTreePath * gtk_file_system_model_get_path (GtkTreeModel *tree_model,
91 static void gtk_file_system_model_get_value (GtkTreeModel *tree_model,
95 static gboolean gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
97 static gboolean gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
100 static gboolean gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
102 static gint gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
104 static gboolean gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
108 static gboolean gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
111 static void gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
113 static void gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
116 static FileModelNode *file_model_node_new (GtkFileSystemModel *model,
118 static void file_model_node_free (FileModelNode *node);
119 static void file_model_node_ref (FileModelNode *node);
120 static void file_model_node_unref (GtkFileSystemModel *model,
121 FileModelNode *node);
123 static const GtkFileInfo *file_model_node_get_info (GtkFileSystemModel *model,
124 FileModelNode *node);
125 static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
126 FileModelNode *node);
127 static void file_model_node_clear (GtkFileSystemModel *model,
128 FileModelNode *node);
129 static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
130 FileModelNode *node);
132 static void deleted_callback (GtkFileFolder *folder,
133 FileModelNode *node);
134 static void files_added_callback (GtkFileFolder *folder,
136 FileModelNode *node);
137 static void files_changed_callback (GtkFileFolder *folder,
139 FileModelNode *node);
140 static void files_removed_callback (GtkFileFolder *folder,
142 FileModelNode *node);
144 static void root_deleted_callback (GtkFileFolder *folder,
145 GtkFileSystemModel *model);
146 static void root_files_added_callback (GtkFileFolder *folder,
148 GtkFileSystemModel *model);
149 static void root_files_changed_callback (GtkFileFolder *folder,
151 GtkFileSystemModel *model);
152 static void root_files_removed_callback (GtkFileFolder *folder,
154 GtkFileSystemModel *model);
157 _gtk_file_system_model_get_type (void)
159 static GType file_system_model_type = 0;
161 if (!file_system_model_type)
163 static const GTypeInfo file_system_model_info =
165 sizeof (GtkFileSystemModelClass),
166 NULL, /* base_init */
167 NULL, /* base_finalize */
168 (GClassInitFunc) gtk_file_system_model_class_init,
169 NULL, /* class_finalize */
170 NULL, /* class_data */
171 sizeof (GtkFileSystemModel),
173 (GInstanceInitFunc) gtk_file_system_model_init,
176 static const GInterfaceInfo file_system_info =
178 (GInterfaceInitFunc) gtk_file_system_model_iface_init, /* interface_init */
179 NULL, /* interface_finalize */
180 NULL /* interface_data */
183 file_system_model_type = g_type_register_static (G_TYPE_OBJECT,
184 "GtkFileSystemModel",
185 &file_system_model_info, 0);
186 g_type_add_interface_static (file_system_model_type,
191 return file_system_model_type;
195 gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
197 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
199 gobject_class->finalize = gtk_file_system_model_finalize;
203 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
205 iface->get_flags = gtk_file_system_model_get_flags;
206 iface->get_n_columns = gtk_file_system_model_get_n_columns;
207 iface->get_column_type = gtk_file_system_model_get_column_type;
208 iface->get_iter = gtk_file_system_model_get_iter;
209 iface->get_path = gtk_file_system_model_get_path;
210 iface->get_value = gtk_file_system_model_get_value;
211 iface->iter_next = gtk_file_system_model_iter_next;
212 iface->iter_children = gtk_file_system_model_iter_children;
213 iface->iter_has_child = gtk_file_system_model_iter_has_child;
214 iface->iter_n_children = gtk_file_system_model_iter_n_children;
215 iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
216 iface->iter_parent = gtk_file_system_model_iter_parent;
217 iface->ref_node = gtk_file_system_model_ref_node;
218 iface->unref_node = gtk_file_system_model_unref_node;
222 gtk_file_system_model_init (GtkFileSystemModel *model)
224 model->show_files = TRUE;
225 model->show_folders = TRUE;
226 model->show_hidden = FALSE;
230 gtk_file_system_model_finalize (GObject *object)
232 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
233 FileModelNode *children;
235 if (model->root_folder)
236 g_object_unref (model->root_folder);
238 children = model->roots;
241 file_model_node_free (children);
242 children = children->next;
247 * ******************** GtkTreeModel methods ********************
250 static GtkTreeModelFlags
251 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
253 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
254 GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
256 if (model->max_depth == 1)
257 flags |= GTK_TREE_MODEL_LIST_ONLY;
263 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
265 return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
269 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
274 case GTK_FILE_SYSTEM_MODEL_URI:
275 return G_TYPE_STRING;
276 case GTK_FILE_SYSTEM_MODEL_INFO:
277 return GTK_TYPE_FILE_INFO;
278 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
279 return G_TYPE_STRING;
281 g_assert_not_reached ();
287 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
295 indices = gtk_tree_path_get_indices (path);
296 depth = gtk_tree_path_get_depth (path);
298 g_return_val_if_fail (depth > 0, FALSE);
300 if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
303 for (i = 1; i < depth; i++)
306 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
314 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
317 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
318 FileModelNode *node = iter->user_data;
320 GtkTreePath *result = gtk_tree_path_new ();
324 FileModelNode *parent = node->parent;
325 FileModelNode *children;
329 children = parent->children;
331 children = model->roots;
333 while (children != node)
335 if (children->is_visible)
337 children = children->next;
340 gtk_tree_path_prepend_index (result, n);
349 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
354 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
355 FileModelNode *node = iter->user_data;
359 case GTK_FILE_SYSTEM_MODEL_URI:
360 g_value_init (value, G_TYPE_STRING);
361 g_value_set_string (value, node->uri);
363 case GTK_FILE_SYSTEM_MODEL_INFO:
364 g_value_init (value, GTK_TYPE_FILE_INFO);
365 g_value_set_boxed (value, file_model_node_get_info (model, node));
367 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
369 const GtkFileInfo *info = file_model_node_get_info (model, node);
370 g_value_init (value, G_TYPE_STRING);
371 g_value_set_string (value, gtk_file_info_get_display_name (info));
375 g_assert_not_reached ();
380 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
383 FileModelNode *node = iter->user_data;
386 while (node && !node->is_visible)
389 iter->user_data = node;
395 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
399 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
400 FileModelNode *children;
404 FileModelNode *parent_node = parent->user_data;
405 children = file_model_node_get_children (model, parent_node);
409 children = model->roots;
412 while (children && !children->is_visible)
413 children = children->next;
415 iter->user_data = children;
417 return children != NULL;
421 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
424 FileModelNode *node = iter->user_data;
425 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
427 if (node->depth == model->max_depth)
431 const GtkFileInfo *info = file_model_node_get_info (model, node);
432 return gtk_file_info_get_is_folder (info);
437 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
440 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
441 FileModelNode *children;
446 FileModelNode *node = iter->user_data;
447 children = file_model_node_get_children (model, node);
451 children = model->roots;
456 if (children->is_visible)
458 children = children->next;
465 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
470 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
471 FileModelNode *children;
475 FileModelNode *parent_node = parent->user_data;
476 children = file_model_node_get_children (model, parent_node);
480 children = model->roots;
483 while (children && !children->is_visible)
484 children = children->next;
486 while (n && children)
489 children = children->next;
490 while (children && !children->is_visible)
491 children = children->next;
494 iter->user_data = children;
496 return children != NULL;
500 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
504 FileModelNode *node = child->user_data;
507 iter->user_data = node;
513 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
516 file_model_node_ref (iter->user_data);
520 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
523 file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
528 * _gtk_file_system_model_new:
529 * @file_system: an object implementing #GtkFileSystem
530 * @root_uri: the URI of root of the file system to display,
531 * or %NULL to display starting from the
532 * root or roots of the fielsystem.
533 * @max_depth: the maximum depth from the children of @root_uri
534 * or the roots of the file system to display in
535 * the file selector). A depth of 0 displays
536 * only the immediate children of @root_uri,
537 * or the roots of the filesystem. -1 for no
539 * @types: a bitmask indicating the types of information
540 * that is desired about the files. This will
541 * determine what information is returned by
542 * _gtk_file_system_model_get_info().
544 * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
545 * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
546 * Using the @root_uri and @max_depth parameters, the tree model
547 * can be restricted to a subportion of the entire file system.
549 * Return value: the newly created #GtkFileSystemModel object.
552 _gtk_file_system_model_new (GtkFileSystem *file_system,
553 const gchar *root_uri,
555 GtkFileInfoType types)
557 GtkFileSystemModel *model;
558 GSList *roots, *tmp_list;
560 g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
562 model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
563 model->file_system = g_object_ref (file_system);
565 model->max_depth = G_MAXUSHORT;
567 model->max_depth = MIN (max_depth, G_MAXUSHORT);
568 model->types = types | GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN;
574 model->root_folder = gtk_file_system_get_folder (file_system, root_uri,
576 NULL); /* NULL-GError */
578 if (model->root_folder &&
579 gtk_file_folder_list_children (model->root_folder,
581 NULL)) /* NULL-GError */
585 g_signal_connect (model->root_folder, "deleted",
586 G_CALLBACK (root_deleted_callback), model);
587 g_signal_connect (model->root_folder, "files_added",
588 G_CALLBACK (root_files_added_callback), model);
589 g_signal_connect (model->root_folder, "files_changed",
590 G_CALLBACK (root_files_changed_callback), model);
591 g_signal_connect (model->root_folder, "files_removed",
592 G_CALLBACK (root_files_removed_callback), model);
596 roots = gtk_file_system_list_roots (file_system);
598 roots = g_slist_sort (roots, (GCompareFunc)strcmp);
600 for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
602 FileModelNode *node = file_model_node_new (model, tmp_list->data);
603 g_free (tmp_list->data);
604 node->is_visible = file_model_node_is_visible (model, node);
605 node->next = model->roots;
609 g_slist_free (roots);
611 model->roots = (FileModelNode *)g_slist_reverse ((GSList *)model->roots);
617 model_refilter_recurse (GtkFileSystemModel *model,
618 FileModelNode *parent,
621 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
623 FileModelNode *nodes;
624 gboolean has_children = FALSE;
626 if (parent && !parent->loaded)
630 nodes = parent->children;
632 nodes = model->roots;
636 FileModelNode *next = nodes->next;
639 gtk_tree_path_append_index (path, i);
641 is_visible = file_model_node_is_visible (model, nodes);
643 if (!is_visible && nodes->is_visible)
645 file_model_node_clear (model, nodes);
646 gtk_tree_model_row_deleted (tree_model, path);
648 nodes->is_visible = FALSE;
650 else if (is_visible && !nodes->is_visible)
654 iter.user_data = nodes;
655 gtk_tree_model_row_inserted (tree_model, path, &iter);
657 nodes->is_visible = TRUE;
660 model_refilter_recurse (model, nodes, path);
668 gtk_tree_path_up (path);
673 if (parent && !has_children)
675 /* Fixme - need to insert dummy node here */
680 * _gtk_file_system_model_set_show_hidden:
681 * @model: a #GtkFileSystemModel
682 * @show_hidden: whether hidden files should be displayed
684 * Sets whether hidden files should be included in the #GtkTreeModel
688 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
689 gboolean show_hidden)
691 show_hidden = show_hidden != FALSE;
693 if (show_hidden != model->show_hidden)
697 model->show_hidden = show_hidden;
699 path = gtk_tree_path_new ();
700 model_refilter_recurse (model, NULL, path);
701 gtk_tree_path_free (path);
706 * _gtk_file_system_model_set_show_folders:
707 * @model: a #GtkFileSystemModel
708 * @show_folders: whether folders should be displayed
710 * Sets whether folders should be included in the #GtkTreeModel for
714 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
715 gboolean show_folders)
717 show_folders = show_folders != FALSE;
719 if (show_folders != model->show_folders)
723 model->show_folders = show_folders;
725 path = gtk_tree_path_new ();
726 model_refilter_recurse (model, NULL, path);
727 gtk_tree_path_free (path);
732 * _gtk_file_system_model_set_show_files:
733 * @model: a #GtkFileSystemModel
734 * @show_files: whether files (as opposed to folders) should
737 * Sets whether files (as opposed to folders) should be included
738 * in the #GtkTreeModel for display.
741 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
744 show_files = show_files != FALSE;
746 if (show_files != model->show_files)
750 model->show_files = show_files;
752 path = gtk_tree_path_new ();
753 model_refilter_recurse (model, NULL, path);
754 gtk_tree_path_free (path);
759 * _gtk_file_system_model_get_info:
760 * @model: a #GtkFileSystemModel
761 * @iter: a #GtkTreeIter pointing to a row of @model
763 * Gets the #GtkFileInfo structure for a particular row
764 * of @model. The information included in this structure
765 * is determined by the @types parameter to
766 * _gtk_file_system_model_new().
768 * Return value: a #GtkFileInfo structure. This structure
769 * is owned by @model and must not be modified or freed.
770 * If you want to save the information for later use,
771 * you must make a copy, since the structure may be
772 * freed on later changes to the file system.
775 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
778 return file_model_node_get_info (model, iter->user_data);
782 * _gtk_file_system_model_get_uri:
783 * @model: a #GtkFileSystemModel
784 * @iter: a #GtkTreeIter pointing to a row of @model
786 * Gets the URI for a particular row in @model.
788 * Return value: the URI. This string is owned by @model and
789 * or freed. If you want to save the URI for later use,
790 * you must make a copy, since the string may be freed
791 * on later changes to the file system.
794 _gtk_file_system_model_get_uri (GtkFileSystemModel *model,
797 FileModelNode *node = iter->user_data;
803 unref_node_and_parents (GtkFileSystemModel *model,
806 file_model_node_unref (model, node);
808 file_model_node_unref (model, node->parent);
811 static FileModelNode *
812 find_child_node (GtkFileSystemModel *model,
813 FileModelNode *parent_node,
816 FileModelNode *children;
819 children = file_model_node_get_children (model, parent_node);
821 children = model->roots;
825 if (children->is_visible &&
826 strcmp (children->uri, uri) == 0)
829 children = children->next;
836 static FileModelNode *
837 find_and_ref_uri (GtkFileSystemModel *model,
841 FileModelNode *parent_node;
842 FileModelNode *child_node;
843 GtkFileFolder *folder;
845 if (!gtk_file_system_get_parent (model->file_system, uri, &parent_uri, NULL))
850 parent_node = find_and_ref_uri (model, parent_uri);
859 child_node = find_child_node (model, parent_node, uri);
862 file_model_node_ref (child_node);
866 folder = gtk_file_system_get_folder (model->file_system,
869 NULL); /* NULL-GError */
871 child_node = find_child_node (model, parent_node, uri);
874 file_model_node_ref (child_node);
879 unref_node_and_parents (model, parent_node);
885 * _gtk_file_system_model_uri_do:
886 * @model: a #GtkFileSystemModel
887 * @uri: a URI pointing to a file in the filesystem
889 * @func: Function to call with the path and iter corresponding
891 * @user_data: data to pass to @func
893 * Locates @uri within @model, referencing
894 * (gtk_tree_model_ref_node ()) all parent nodes,
895 * calls @func passing in the path and iter for @uri,
896 * then unrefs all the parent nodes.
898 * The reason for doing this operation as a callback
899 * is so that if the operation performed with the the
900 * path and iter results in referencing the the node
901 * and/or parent nodes, we don't load all the information
904 * This function is particularly useful for expanding
905 * a #GtkTreeView to a particular point in the file system.
907 * Return value: %TRUE if the URI was successfully
908 * found in @model and @func was called.
911 _gtk_file_system_model_uri_do (GtkFileSystemModel *model,
913 GtkFileSystemModelURIFunc func,
916 FileModelNode *node = find_and_ref_uri (model, uri);
923 iter.user_data = node;
924 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
926 (*func) (model, path, &iter, user_data);
928 gtk_tree_path_free (path);
929 unref_node_and_parents (model, node);
937 static FileModelNode *
938 file_model_node_new (GtkFileSystemModel *model,
941 FileModelNode *node = g_new0 (FileModelNode, 1);
944 node->uri = g_strdup (uri);
950 file_model_node_free (FileModelNode *node)
954 FileModelNode *children;
956 for (children = node->children; children; children = children->next)
957 file_model_node_free (children);
964 gtk_file_info_free (node->info);
967 g_object_unref (node->folder);
972 static const GtkFileInfo *
973 file_model_node_get_info (GtkFileSystemModel *model,
980 node->info = gtk_file_info_new ();
981 gtk_file_info_set_display_name (node->info, "(Empty)");
983 else if (node->parent || model->root_folder)
985 node->info = gtk_file_folder_get_info (node->parent ? node->parent->folder : model->root_folder,
987 NULL); /* NULL-GError */
991 node->info = gtk_file_system_get_root_info (model->file_system,
994 NULL); /* NULL-GError */
1002 file_model_node_is_visible (GtkFileSystemModel *model,
1003 FileModelNode *node)
1005 if (model->show_hidden && model->show_folders && model->show_files)
1009 const GtkFileInfo *info = file_model_node_get_info (model, node);
1010 gboolean is_folder = gtk_file_info_get_is_folder (info);
1012 if (!model->show_folders && is_folder)
1014 if (!model->show_files && !is_folder)
1016 if (!model->show_hidden && gtk_file_info_get_is_hidden (info))
1024 file_model_node_clear (GtkFileSystemModel *model,
1025 FileModelNode *node)
1027 FileModelNode *children;
1031 g_object_unref (node->folder);
1032 node->folder = NULL;
1035 children = node->children;
1036 node->children = NULL;
1037 node->loaded = FALSE;
1041 FileModelNode *next = children->next;
1043 file_model_node_clear (model, children);
1044 file_model_node_free (children);
1049 node->ref_count = 0;
1053 file_model_node_ref (FileModelNode *node)
1059 file_model_node_unref (GtkFileSystemModel *model,
1060 FileModelNode *node)
1063 if (node->ref_count == 0)
1064 file_model_node_clear (model, node);
1067 static FileModelNode *
1068 file_model_node_get_children (GtkFileSystemModel *model,
1069 FileModelNode *node)
1071 if (node->ref_count == 0)
1076 const GtkFileInfo *info = file_model_node_get_info (model, node);
1077 gboolean has_children = FALSE;
1078 gboolean is_folder = node->depth < model->max_depth && gtk_file_info_get_is_folder (info);
1081 node->folder = gtk_file_system_get_folder (model->file_system,
1084 NULL); /* NULL-GError */
1088 GSList *child_uris, *tmp_list;
1090 if (gtk_file_folder_list_children (node->folder, &child_uris, NULL)) /* NULL-GError */
1092 child_uris = g_slist_sort (child_uris, (GCompareFunc)strcmp);
1094 for (tmp_list = child_uris; tmp_list; tmp_list = tmp_list->next)
1096 FileModelNode *child_node = file_model_node_new (model, tmp_list->data);
1097 g_free (tmp_list->data);
1098 child_node->next = node->children;
1099 child_node->parent = node;
1100 child_node->depth = node->depth + 1;
1101 child_node->is_visible = file_model_node_is_visible (model, child_node);
1102 if (child_node->is_visible)
1103 has_children = TRUE;
1104 node->children = child_node;
1106 g_slist_free (child_uris);
1109 node->children = (FileModelNode *)g_slist_reverse ((GSList *)node->children);
1111 g_signal_connect (node->folder, "deleted",
1112 G_CALLBACK (deleted_callback), node);
1113 g_signal_connect (node->folder, "files_added",
1114 G_CALLBACK (files_added_callback), node);
1115 g_signal_connect (node->folder, "files_changed",
1116 G_CALLBACK (files_changed_callback), node);
1117 g_signal_connect (node->folder, "files_removed",
1118 G_CALLBACK (files_removed_callback), node);
1120 g_object_set_data (G_OBJECT (node->folder), "model-node", node);
1123 if (is_folder && !has_children)
1125 /* The hard case ... we claimed this folder had children, but actually
1126 * it didn't. We have to add a dummy child, possibly to remove later.
1128 FileModelNode *child_node = file_model_node_new (model, "***dummy***");
1129 child_node->is_visible = TRUE;
1130 child_node->parent = node;
1131 child_node->is_dummy = TRUE;
1133 node->children = child_node;
1134 node->has_dummy = TRUE;
1137 node->loaded = TRUE;
1140 return node->children;
1144 do_files_added (GtkFileSystemModel *model,
1145 FileModelNode *parent_node,
1148 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1149 FileModelNode *children;
1150 FileModelNode *prev = NULL;
1153 GSList *sorted_uris;
1156 sorted_uris = g_slist_copy (uris);
1157 sorted_uris = g_slist_sort (sorted_uris, (GCompareFunc)strcmp);
1161 iter.user_data = parent_node;
1162 path = gtk_tree_model_get_path (tree_model, &iter);
1163 children = parent_node->children;
1167 path = gtk_tree_path_new ();
1168 children = model->roots;
1171 gtk_tree_path_down (path);
1173 if (parent_node && parent_node->has_dummy)
1176 children = children->next;
1177 gtk_tree_path_next (path);
1180 for (tmp_list = sorted_uris; tmp_list; tmp_list = tmp_list->next)
1182 const gchar *uri = tmp_list->data;
1184 while (children && strcmp (children->uri, uri) < 0)
1187 if (children->is_visible)
1188 gtk_tree_path_next (path);
1190 children = children->next;
1193 if (children && strcmp (children->uri, uri) == 0)
1195 /* Shouldn't happen */
1201 new = file_model_node_new (model, uri);
1204 new->next = children;
1207 else if (parent_node)
1208 parent_node->children = new;
1216 new->parent = parent_node;
1217 new->depth = parent_node->depth + 1;
1220 new->is_visible = file_model_node_is_visible (model, new);
1222 if (new->is_visible)
1224 iter.user_data = new;
1225 path = gtk_tree_model_get_path (tree_model, &iter);
1226 gtk_tree_model_row_inserted (tree_model, path, &iter);
1228 if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1229 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1231 if (parent_node && parent_node->has_dummy)
1233 FileModelNode *dummy = parent_node->children;
1234 GtkTreePath *dummy_path;
1236 parent_node->children = parent_node->children->next;
1237 parent_node->has_dummy = FALSE;
1238 file_model_node_free (dummy);
1240 dummy_path = gtk_tree_path_copy (path);
1241 gtk_tree_path_up (dummy_path);
1242 gtk_tree_path_down (dummy_path);
1244 gtk_tree_model_row_deleted (tree_model, dummy_path);
1245 gtk_tree_path_free (dummy_path);
1248 gtk_tree_path_next (path);
1253 gtk_tree_path_free (path);
1254 g_slist_free (sorted_uris);
1258 do_files_changed (GtkFileSystemModel *model,
1259 FileModelNode *parent_node,
1262 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1263 FileModelNode *children;
1264 FileModelNode *prev = NULL;
1267 GSList *sorted_uris;
1270 sorted_uris = g_slist_copy (uris);
1271 sorted_uris = g_slist_sort (sorted_uris, (GCompareFunc)strcmp);
1275 iter.user_data = parent_node;
1276 path = gtk_tree_model_get_path (tree_model, &iter);
1277 children = parent_node->children;
1281 path = gtk_tree_path_new ();
1282 children = model->roots;
1285 gtk_tree_path_down (path);
1287 if (parent_node && parent_node->has_dummy)
1290 children = children->next;
1291 gtk_tree_path_next (path);
1294 for (tmp_list = sorted_uris; tmp_list; tmp_list = tmp_list->next)
1296 const gchar *uri = tmp_list->data;
1298 while (children && strcmp (children->uri, uri) < 0)
1301 if (children->is_visible)
1302 gtk_tree_path_next (path);
1304 children = children->next;
1307 if (children && strcmp (children->uri, uri) == 0)
1309 gtk_tree_model_row_changed (tree_model, path, &iter);
1313 /* Shouldn't happen */
1317 gtk_tree_path_free (path);
1318 g_slist_free (sorted_uris);
1322 do_files_removed (GtkFileSystemModel *model,
1323 FileModelNode *parent_node,
1326 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1327 FileModelNode *children;
1328 FileModelNode *prev = NULL;
1331 GSList *sorted_uris;
1333 FileModelNode *tmp_child;
1336 sorted_uris = g_slist_copy (uris);
1337 sorted_uris = g_slist_sort (sorted_uris, (GCompareFunc)strcmp);
1341 iter.user_data = parent_node;
1342 path = gtk_tree_model_get_path (tree_model, &iter);
1343 children = parent_node->children;
1347 path = gtk_tree_path_new ();
1348 children = model->roots;
1351 /* Count the number of currently visible children, so that
1352 * can catch when we need to insert a dummy node.
1355 for (tmp_child = children; tmp_child; tmp_child = tmp_child->next)
1357 if (tmp_child->is_visible)
1361 gtk_tree_path_down (path);
1363 if (parent_node && parent_node->has_dummy)
1366 children = children->next;
1367 gtk_tree_path_next (path);
1370 for (tmp_list = sorted_uris; tmp_list; tmp_list = tmp_list->next)
1372 const gchar *uri = tmp_list->data;
1374 while (children && strcmp (children->uri, uri) < 0)
1377 if (children->is_visible)
1378 gtk_tree_path_next (path);
1380 children = children->next;
1383 if (children && strcmp (children->uri, uri) == 0)
1385 FileModelNode *next = children->next;
1387 if (children->is_visible)
1392 FileModelNode *dummy = file_model_node_new (model, "***dummy***");
1393 dummy->is_visible = TRUE;
1394 dummy->parent = parent_node;
1395 dummy->is_dummy = TRUE;
1397 parent_node->children = dummy;
1398 parent_node->has_dummy = TRUE;
1400 iter.user_data = dummy;
1401 gtk_tree_model_row_inserted (tree_model, path, &iter);
1402 gtk_tree_path_next (path);
1409 else if (parent_node)
1410 parent_node->children = next;
1412 model->roots = next;
1414 if (children->is_visible)
1415 gtk_tree_model_row_deleted (tree_model, path);
1417 file_model_node_free (children);
1423 /* Shouldn't happen */
1427 gtk_tree_path_free (path);
1428 g_slist_free (sorted_uris);
1432 deleted_callback (GtkFileFolder *folder,
1433 FileModelNode *node)
1438 files_added_callback (GtkFileFolder *folder,
1440 FileModelNode *node)
1442 do_files_added (node->model, node, uris);
1446 files_changed_callback (GtkFileFolder *folder,
1448 FileModelNode *node)
1450 do_files_changed (node->model, node, uris);
1454 files_removed_callback (GtkFileFolder *folder,
1456 FileModelNode *node)
1458 do_files_removed (node->model, node, uris);
1462 root_deleted_callback (GtkFileFolder *folder,
1463 GtkFileSystemModel *model)
1468 root_files_added_callback (GtkFileFolder *folder,
1470 GtkFileSystemModel *model)
1472 do_files_added (model, NULL, uris);
1476 root_files_changed_callback (GtkFileFolder *folder,
1478 GtkFileSystemModel *model)
1480 do_files_changed (model, NULL, uris);
1484 root_files_removed_callback (GtkFileFolder *folder,
1486 GtkFileSystemModel *model)
1488 do_files_removed (model, NULL, uris);