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;
48 GSList *dummy_idle_nodes;
52 guint show_hidden : 1;
53 guint show_folders : 1;
55 guint folders_only : 1;
64 GtkFileFolder *folder;
66 FileModelNode *children;
67 FileModelNode *parent;
76 guint has_children : 1;
79 static void gtk_file_system_model_class_init (GtkFileSystemModelClass *class);
80 static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
81 static void gtk_file_system_model_init (GtkFileSystemModel *model);
82 static void gtk_file_system_model_finalize (GObject *object);
84 static GtkTreeModelFlags gtk_file_system_model_get_flags (GtkTreeModel *tree_model);
85 static gint gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model);
86 static GType gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
88 static gboolean gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
91 static GtkTreePath * gtk_file_system_model_get_path (GtkTreeModel *tree_model,
93 static void gtk_file_system_model_get_value (GtkTreeModel *tree_model,
97 static gboolean gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
99 static gboolean gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
101 GtkTreeIter *parent);
102 static gboolean gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
104 static gint gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
106 static gboolean gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
110 static gboolean gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
113 static void gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
115 static void gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
118 static void queue_dummy_idle (GtkFileSystemModel *model,
119 FileModelNode *node);
120 static void unqueue_dummy_idle (GtkFileSystemModel *model,
121 FileModelNode *node);
123 static FileModelNode *file_model_node_new (const gchar *uri);
124 static void file_model_node_free (FileModelNode *node);
125 static void file_model_node_ref (FileModelNode *node);
126 static void file_model_node_unref (GtkFileSystemModel *model,
127 FileModelNode *node);
129 static const GtkFileInfo *file_model_node_get_info (GtkFileSystemModel *model,
130 FileModelNode *node);
131 static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
132 FileModelNode *node);
133 static void file_model_node_clear (GtkFileSystemModel *model,
134 FileModelNode *node);
135 static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
136 FileModelNode *node);
139 _gtk_file_system_model_get_type (void)
141 static GType file_system_model_type = 0;
143 if (!file_system_model_type)
145 static const GTypeInfo file_system_model_info =
147 sizeof (GtkFileSystemModelClass),
148 NULL, /* base_init */
149 NULL, /* base_finalize */
150 (GClassInitFunc) gtk_file_system_model_class_init,
151 NULL, /* class_finalize */
152 NULL, /* class_data */
153 sizeof (GtkFileSystemModel),
155 (GInstanceInitFunc) gtk_file_system_model_init,
158 static const GInterfaceInfo file_system_info =
160 (GInterfaceInitFunc) gtk_file_system_model_iface_init, /* interface_init */
161 NULL, /* interface_finalize */
162 NULL /* interface_data */
165 file_system_model_type = g_type_register_static (G_TYPE_OBJECT,
166 "GtkFileSystemModel",
167 &file_system_model_info, 0);
168 g_type_add_interface_static (file_system_model_type,
173 return file_system_model_type;
177 gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
179 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
181 gobject_class->finalize = gtk_file_system_model_finalize;
185 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
187 iface->get_flags = gtk_file_system_model_get_flags;
188 iface->get_n_columns = gtk_file_system_model_get_n_columns;
189 iface->get_column_type = gtk_file_system_model_get_column_type;
190 iface->get_iter = gtk_file_system_model_get_iter;
191 iface->get_path = gtk_file_system_model_get_path;
192 iface->get_value = gtk_file_system_model_get_value;
193 iface->iter_next = gtk_file_system_model_iter_next;
194 iface->iter_children = gtk_file_system_model_iter_children;
195 iface->iter_has_child = gtk_file_system_model_iter_has_child;
196 iface->iter_n_children = gtk_file_system_model_iter_n_children;
197 iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
198 iface->iter_parent = gtk_file_system_model_iter_parent;
199 iface->ref_node = gtk_file_system_model_ref_node;
200 iface->unref_node = gtk_file_system_model_unref_node;
204 gtk_file_system_model_init (GtkFileSystemModel *model)
206 model->show_files = TRUE;
207 model->show_folders = TRUE;
208 model->show_hidden = FALSE;
212 gtk_file_system_model_finalize (GObject *object)
214 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
215 FileModelNode *children;
217 if (model->root_folder)
218 g_object_unref (model->root_folder);
220 children = model->roots;
223 file_model_node_free (children);
224 children = children->next;
229 * ******************** GtkTreeModel methods ********************
232 static GtkTreeModelFlags
233 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
235 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
236 GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
238 if (model->max_depth == 1)
239 flags |= GTK_TREE_MODEL_LIST_ONLY;
245 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
247 return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
251 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
256 case GTK_FILE_SYSTEM_MODEL_URI:
257 return G_TYPE_STRING;
258 case GTK_FILE_SYSTEM_MODEL_INFO:
259 return GTK_TYPE_FILE_INFO;
260 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
261 return G_TYPE_STRING;
263 g_assert_not_reached ();
269 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
277 indices = gtk_tree_path_get_indices (path);
278 depth = gtk_tree_path_get_depth (path);
280 g_return_val_if_fail (depth > 0, FALSE);
282 if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
285 for (i = 1; i < depth; i++)
288 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
296 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
299 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
300 FileModelNode *node = iter->user_data;
302 GtkTreePath *result = gtk_tree_path_new ();
306 FileModelNode *parent = node->parent;
307 FileModelNode *children;
311 children = parent->children;
313 children = model->roots;
315 while (children != node)
317 if (children->is_visible)
319 children = children->next;
322 gtk_tree_path_prepend_index (result, n);
331 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
336 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
337 FileModelNode *node = iter->user_data;
341 case GTK_FILE_SYSTEM_MODEL_URI:
342 g_value_init (value, G_TYPE_STRING);
343 g_value_set_string (value, node->uri);
345 case GTK_FILE_SYSTEM_MODEL_INFO:
346 g_value_init (value, GTK_TYPE_FILE_INFO);
347 g_value_set_boxed (value, file_model_node_get_info (model, node));
349 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
351 const GtkFileInfo *info = file_model_node_get_info (model, node);
352 g_value_init (value, G_TYPE_STRING);
353 g_value_set_string (value, gtk_file_info_get_display_name (info));
357 g_assert_not_reached ();
362 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
365 FileModelNode *node = iter->user_data;
368 while (node && !node->is_visible)
371 iter->user_data = node;
377 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
381 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
382 FileModelNode *children;
386 FileModelNode *parent_node = parent->user_data;
387 children = file_model_node_get_children (model, parent_node);
391 children = model->roots;
394 while (children && !children->is_visible)
395 children = children->next;
397 iter->user_data = children;
399 return children != NULL;
403 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
406 FileModelNode *node = iter->user_data;
408 /* We never want to go into a directory just to
409 * find out if it has children
412 return node->has_children;
415 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
417 if (node->depth == model->max_depth)
421 const GtkFileInfo *info = file_model_node_get_info (model, node);
422 return gtk_file_info_get_is_folder (info);
428 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
431 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
432 FileModelNode *children;
437 FileModelNode *node = iter->user_data;
438 children = file_model_node_get_children (model, node);
442 children = model->roots;
447 if (children->is_visible)
449 children = children->next;
456 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
461 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
462 FileModelNode *children;
466 FileModelNode *parent_node = parent->user_data;
467 children = file_model_node_get_children (model, parent_node);
471 children = model->roots;
474 while (children && !children->is_visible)
475 children = children->next;
477 while (n && children)
480 children = children->next;
481 while (children && !children->is_visible)
482 children = children->next;
485 iter->user_data = children;
487 return children != NULL;
491 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
495 FileModelNode *node = child->user_data;
498 iter->user_data = node;
504 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
507 file_model_node_ref (iter->user_data);
511 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
514 file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
519 * _gtk_file_system_model_new:
520 * @file_system: an object implementing #GtkFileSystem
521 * @root_uri: the URI of root of the file system to display,
522 * or %NULL to display starting from the
523 * root or roots of the fielsystem.
524 * @max_depth: the maximum depth from the children of @root_uri
525 * or the roots of the file system to display in
526 * the file selector). A depth of 0 displays
527 * only the immediate children of @root_uri,
528 * or the roots of the filesystem. -1 for no
530 * @types: a bitmask indicating the types of information
531 * that is desired about the files. This will
532 * determine what information is returned by
533 * _gtk_file_system_model_get_info().
535 * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
536 * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
537 * Using the @root_uri and @max_depth parameters, the tree model
538 * can be restricted to a subportion of the entire file system.
540 * Return value: the newly created #GtkFileSystemModel object.
543 _gtk_file_system_model_new (GtkFileSystem *file_system,
544 const gchar *root_uri,
546 GtkFileInfoType types)
548 GtkFileSystemModel *model;
549 GSList *roots, *tmp_list;
551 g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
553 model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
554 model->file_system = g_object_ref (file_system);
556 model->max_depth = G_MAXUSHORT;
558 model->max_depth = MIN (max_depth, G_MAXUSHORT);
559 model->types = types | GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN;
565 model->root_folder = gtk_file_system_get_folder (file_system, root_uri,
567 NULL); /* NULL-GError */
569 if (model->root_folder &&
570 gtk_file_folder_list_children (model->root_folder,
572 NULL)) /* NULL-GError */
576 roots = gtk_file_system_list_roots (file_system);
578 roots = g_slist_sort (roots, (GCompareFunc)strcmp);
580 for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
582 FileModelNode *node = file_model_node_new (tmp_list->data);
583 g_free (tmp_list->data);
584 node->is_visible = file_model_node_is_visible (model, node);
585 node->next = model->roots;
589 g_slist_free (roots);
591 model->roots = (FileModelNode *)g_slist_reverse ((GSList *)model->roots);
597 model_refilter_recurse (GtkFileSystemModel *model,
598 FileModelNode *parent,
601 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
603 FileModelNode *nodes;
604 gboolean has_children = FALSE;
606 if (parent && !parent->loaded)
610 nodes = parent->children;
612 nodes = model->roots;
616 FileModelNode *next = nodes->next;
619 gtk_tree_path_append_index (path, i);
621 is_visible = file_model_node_is_visible (model, nodes);
623 if (!is_visible && nodes->is_visible)
625 file_model_node_clear (model, nodes);
626 gtk_tree_model_row_deleted (tree_model, path);
628 nodes->is_visible = FALSE;
630 else if (is_visible && !nodes->is_visible)
634 iter.user_data = nodes;
635 gtk_tree_model_row_inserted (tree_model, path, &iter);
637 nodes->is_visible = TRUE;
640 model_refilter_recurse (model, nodes, path);
648 gtk_tree_path_up (path);
653 if (parent && (has_children != parent->has_children))
657 parent->has_children = has_children;
659 iter.user_data = parent;
660 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
665 * _gtk_file_system_model_set_show_hidden:
666 * @model: a #GtkFileSystemModel
667 * @show_hidden: whether hidden files should be displayed
669 * Sets whether hidden files should be included in the #GtkTreeModel
673 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
674 gboolean show_hidden)
676 show_hidden = show_hidden != FALSE;
678 if (show_hidden != model->show_hidden)
682 model->show_hidden = show_hidden;
684 path = gtk_tree_path_new ();
685 model_refilter_recurse (model, NULL, path);
686 gtk_tree_path_free (path);
691 * _gtk_file_system_model_set_show_folders:
692 * @model: a #GtkFileSystemModel
693 * @show_folders: whether folders should be displayed
695 * Sets whether folders should be included in the #GtkTreeModel for
699 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
700 gboolean show_folders)
702 show_folders = show_folders != FALSE;
704 if (show_folders != model->show_folders)
708 model->show_folders = show_folders;
710 path = gtk_tree_path_new ();
711 model_refilter_recurse (model, NULL, path);
712 gtk_tree_path_free (path);
717 * _gtk_file_system_model_set_show_files:
718 * @model: a #GtkFileSystemModel
719 * @show_files: whether files (as opposed to folders) should
722 * Sets whether files (as opposed to folders) should be included
723 * in the #GtkTreeModel for display.
726 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
729 show_files = show_files != FALSE;
731 if (show_files != model->show_files)
735 model->show_files = show_files;
737 path = gtk_tree_path_new ();
738 model_refilter_recurse (model, NULL, path);
739 gtk_tree_path_free (path);
744 * _gtk_file_system_model_get_info:
745 * @model: a #GtkFileSystemModel
746 * @iter: a #GtkTreeIter pointing to a row of @model
748 * Gets the #GtkFileInfo structure for a particular row
749 * of @model. The information included in this structure
750 * is determined by the @types parameter to
751 * _gtk_file_system_model_new().
753 * Return value: a #GtkFileInfo structure. This structure
754 * is owned by @model and must not be modified or freed.
755 * If you want to save the information for later use,
756 * you must make a copy, since the structure may be
757 * freed on later changes to the file system.
760 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
763 return file_model_node_get_info (model, iter->user_data);
767 * _gtk_file_system_model_get_uri:
768 * @model: a #GtkFileSystemModel
769 * @iter: a #GtkTreeIter pointing to a row of @model
771 * Gets the URI for a particular row in @model.
773 * Return value: the URI. This string is owned by @model and
774 * or freed. If you want to save the URI for later use,
775 * you must make a copy, since the string may be freed
776 * on later changes to the file system.
779 _gtk_file_system_model_get_uri (GtkFileSystemModel *model,
782 FileModelNode *node = iter->user_data;
788 unref_node_and_parents (GtkFileSystemModel *model,
791 file_model_node_unref (model, node);
793 file_model_node_unref (model, node->parent);
796 static FileModelNode *
797 find_and_ref_uri (GtkFileSystemModel *model,
801 FileModelNode *parent_node;
802 FileModelNode *children;
804 if (!gtk_file_system_get_parent (model->file_system, uri, &parent_uri, NULL))
809 parent_node = find_and_ref_uri (model, parent_uri);
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)
828 file_model_node_ref (children);
832 children = children->next;
836 unref_node_and_parents (model, parent_node);
842 * _gtk_file_system_model_uri_do:
843 * @model: a #GtkFileSystemModel
844 * @uri: a URI pointing to a file in the filesystem
846 * @func: Function to call with the path and iter corresponding
848 * @user_data: data to pass to @func
850 * Locates @uri within @model, referencing
851 * (gtk_tree_model_ref_node ()) all parent nodes,
852 * calls @func passing in the path and iter for @uri,
853 * then unrefs all the parent nodes.
855 * The reason for doing this operation as a callback
856 * is so that if the operation performed with the the
857 * path and iter results in referencing the the node
858 * and/or parent nodes, we don't load all the information
861 * This function is particularly useful for expanding
862 * a #GtkTreeView to a particular point in the file system.
864 * Return value: %TRUE if the URI was successfully
865 * found in @model and @func was called.
868 _gtk_file_system_model_uri_do (GtkFileSystemModel *model,
870 GtkFileSystemModelURIFunc func,
873 FileModelNode *node = find_and_ref_uri (model, uri);
880 iter.user_data = node;
881 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
883 (*func) (model, path, &iter, user_data);
885 gtk_tree_path_free (path);
886 unref_node_and_parents (model, node);
895 dummy_idle_callback (GtkFileSystemModel *model)
897 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
900 for (tmp_list = model->dummy_idle_nodes; tmp_list; tmp_list = tmp_list->next)
905 FileModelNode *node = tmp_list->data;
906 g_assert (node->children && !node->children->next && !node->children->children);
908 iter.user_data = node->children;
909 path = gtk_tree_model_get_path (tree_model, &iter);
911 if (node->children->ref_count)
912 gtk_tree_model_row_deleted (tree_model, path);
914 gtk_tree_path_up (path);
915 iter.user_data = node;
916 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
918 gtk_tree_path_free (path);
920 file_model_node_free (node->children);
921 node->children = NULL;
922 node->has_children = FALSE;
923 node->has_dummy = FALSE;
926 model->dummy_idle_nodes = FALSE;
927 model->dummy_idle = NULL;
933 queue_dummy_idle (GtkFileSystemModel *model,
936 model->dummy_idle_nodes = g_slist_prepend (model->dummy_idle_nodes, node);
938 if (!model->dummy_idle)
940 model->dummy_idle = g_idle_source_new ();
941 g_source_set_priority (model->dummy_idle, G_PRIORITY_HIGH_IDLE);
942 g_source_set_closure (model->dummy_idle,
943 g_cclosure_new_object (G_CALLBACK (dummy_idle_callback), G_OBJECT (model)));
944 g_source_attach (model->dummy_idle, NULL);
949 unqueue_dummy_idle (GtkFileSystemModel *model,
952 model->dummy_idle_nodes = g_slist_remove (model->dummy_idle_nodes, node);
954 if (!model->dummy_idle_nodes)
955 g_source_destroy (model->dummy_idle);
958 static FileModelNode *
959 file_model_node_new (const gchar *uri)
961 FileModelNode *node = g_new0 (FileModelNode, 1);
963 node->uri = g_strdup (uri);
969 file_model_node_free (FileModelNode *node)
973 FileModelNode *children;
975 for (children = node->children; children; children = children->next)
976 file_model_node_free (children);
983 gtk_file_info_free (node->info);
986 g_object_unref (node->folder);
991 static const GtkFileInfo *
992 file_model_node_get_info (GtkFileSystemModel *model,
997 if (node->parent && node->parent->has_dummy)
999 node->info = gtk_file_info_new ();
1000 gtk_file_info_set_display_name (node->info, "Loading...");
1002 else if (node->parent || model->root_folder)
1004 node->info = gtk_file_folder_get_info (node->parent ? node->parent->folder : model->root_folder,
1006 NULL); /* NULL-GError */
1010 node->info = gtk_file_system_get_root_info (model->file_system,
1013 NULL); /* NULL-GError */
1021 file_model_node_is_visible (GtkFileSystemModel *model,
1022 FileModelNode *node)
1024 if (model->show_hidden && model->show_folders && model->show_files)
1028 const GtkFileInfo *info = file_model_node_get_info (model, node);
1029 gboolean is_folder = gtk_file_info_get_is_folder (info);
1031 if (!model->show_folders && is_folder)
1033 if (!model->show_files && !is_folder)
1035 if (!model->show_hidden && gtk_file_info_get_is_hidden (info))
1043 file_model_node_clear (GtkFileSystemModel *model,
1044 FileModelNode *node)
1046 FileModelNode *children;
1048 if (node->has_dummy)
1049 unqueue_dummy_idle (model, node);
1053 g_object_unref (node->folder);
1054 node->folder = NULL;
1057 children = node->children;
1058 node->children = NULL;
1059 node->has_children = FALSE;
1060 node->loaded = FALSE;
1064 FileModelNode *next = children->next;
1066 file_model_node_clear (model, children);
1067 file_model_node_free (children);
1072 node->ref_count = 0;
1076 file_model_node_ref (FileModelNode *node)
1082 file_model_node_unref (GtkFileSystemModel *model,
1083 FileModelNode *node)
1086 if (node->ref_count == 0)
1087 file_model_node_clear (model, node);
1090 static FileModelNode *
1091 file_model_node_get_children (GtkFileSystemModel *model,
1092 FileModelNode *node)
1094 if (node->ref_count == 0)
1099 const GtkFileInfo *info = file_model_node_get_info (model, node);
1100 gboolean has_children = FALSE;
1101 gboolean is_folder = node->depth < model->max_depth && gtk_file_info_get_is_folder (info);
1104 node->folder = gtk_file_system_get_folder (model->file_system,
1107 NULL); /* NULL-GError */
1111 GSList *child_uris, *tmp_list;
1113 if (gtk_file_folder_list_children (node->folder, &child_uris, NULL)) /* NULL-GError */
1115 child_uris = g_slist_sort (child_uris, (GCompareFunc)strcmp);
1117 for (tmp_list = child_uris; tmp_list; tmp_list = tmp_list->next)
1119 FileModelNode *child_node = file_model_node_new (tmp_list->data);
1120 g_free (tmp_list->data);
1121 child_node->next = node->children;
1122 child_node->parent = node;
1123 child_node->depth = node->depth + 1;
1124 child_node->is_visible = file_model_node_is_visible (model, child_node);
1125 if (child_node->is_visible)
1126 has_children = TRUE;
1127 node->children = child_node;
1129 g_slist_free (child_uris);
1132 node->children = (FileModelNode *)g_slist_reverse ((GSList *)node->children);
1135 node->has_children = has_children;
1137 if (is_folder && !node->has_children)
1139 /* The hard case ... we claimed this folder had children, but actually
1140 * it didn't. We have to add a dummy child, then remove it later
1142 FileModelNode *child_node = file_model_node_new ("***dummy***");
1143 child_node->is_visible = TRUE;
1144 child_node->parent = node;
1146 node->children = child_node;
1147 node->has_children = TRUE;
1148 node->has_dummy = TRUE;
1150 queue_dummy_idle (model, node);
1153 node->loaded = TRUE;
1156 return node->children;