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 GSource *idle_clear_source;
52 guint show_hidden : 1;
53 guint show_folders : 1;
55 guint folders_only : 1;
64 GtkFileFolder *folder;
66 FileModelNode *children;
67 FileModelNode *parent;
68 GtkFileSystemModel *model;
71 guint n_referenced_children;
82 static void gtk_file_system_model_class_init (GtkFileSystemModelClass *class);
83 static void gtk_file_system_model_iface_init (GtkTreeModelIface *iface);
84 static void gtk_file_system_model_init (GtkFileSystemModel *model);
85 static void gtk_file_system_model_finalize (GObject *object);
87 static GtkTreeModelFlags gtk_file_system_model_get_flags (GtkTreeModel *tree_model);
88 static gint gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model);
89 static GType gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
91 static gboolean gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
94 static GtkTreePath * gtk_file_system_model_get_path (GtkTreeModel *tree_model,
96 static void gtk_file_system_model_get_value (GtkTreeModel *tree_model,
100 static gboolean gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
102 static gboolean gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
104 GtkTreeIter *parent);
105 static gboolean gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
107 static gint gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
109 static gboolean gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
113 static gboolean gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
116 static void gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
118 static void gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
121 static FileModelNode *file_model_node_new (GtkFileSystemModel *model,
122 const GtkFilePath *path);
123 static void file_model_node_free (FileModelNode *node);
124 static void file_model_node_ref (FileModelNode *node);
125 static void file_model_node_unref (GtkFileSystemModel *model,
126 FileModelNode *node);
128 static void file_model_node_idle_clear (FileModelNode *node);
129 static void file_model_node_idle_clear_cancel (FileModelNode *node);
130 static void file_model_node_child_unref (FileModelNode *parent);
132 static const GtkFileInfo *file_model_node_get_info (GtkFileSystemModel *model,
133 FileModelNode *node);
134 static gboolean file_model_node_is_visible (GtkFileSystemModel *model,
135 FileModelNode *node);
136 static void file_model_node_clear (GtkFileSystemModel *model,
137 FileModelNode *node);
138 static FileModelNode * file_model_node_get_children (GtkFileSystemModel *model,
139 FileModelNode *node);
141 static void roots_changed_callback (GtkFileSystem *file_system,
142 GtkFileSystemModel *model);
144 static void deleted_callback (GtkFileFolder *folder,
145 FileModelNode *node);
146 static void files_added_callback (GtkFileFolder *folder,
148 FileModelNode *node);
149 static void files_changed_callback (GtkFileFolder *folder,
151 FileModelNode *node);
152 static void files_removed_callback (GtkFileFolder *folder,
154 FileModelNode *node);
156 static void root_deleted_callback (GtkFileFolder *folder,
157 GtkFileSystemModel *model);
158 static void root_files_added_callback (GtkFileFolder *folder,
160 GtkFileSystemModel *model);
161 static void root_files_changed_callback (GtkFileFolder *folder,
163 GtkFileSystemModel *model);
164 static void root_files_removed_callback (GtkFileFolder *folder,
166 GtkFileSystemModel *model);
169 _gtk_file_system_model_get_type (void)
171 static GType file_system_model_type = 0;
173 if (!file_system_model_type)
175 static const GTypeInfo file_system_model_info =
177 sizeof (GtkFileSystemModelClass),
178 NULL, /* base_init */
179 NULL, /* base_finalize */
180 (GClassInitFunc) gtk_file_system_model_class_init,
181 NULL, /* class_finalize */
182 NULL, /* class_data */
183 sizeof (GtkFileSystemModel),
185 (GInstanceInitFunc) gtk_file_system_model_init,
188 static const GInterfaceInfo file_system_info =
190 (GInterfaceInitFunc) gtk_file_system_model_iface_init, /* interface_init */
191 NULL, /* interface_finalize */
192 NULL /* interface_data */
195 file_system_model_type = g_type_register_static (G_TYPE_OBJECT,
196 "GtkFileSystemModel",
197 &file_system_model_info, 0);
198 g_type_add_interface_static (file_system_model_type,
203 return file_system_model_type;
207 gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
209 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
211 gobject_class->finalize = gtk_file_system_model_finalize;
215 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
217 iface->get_flags = gtk_file_system_model_get_flags;
218 iface->get_n_columns = gtk_file_system_model_get_n_columns;
219 iface->get_column_type = gtk_file_system_model_get_column_type;
220 iface->get_iter = gtk_file_system_model_get_iter;
221 iface->get_path = gtk_file_system_model_get_path;
222 iface->get_value = gtk_file_system_model_get_value;
223 iface->iter_next = gtk_file_system_model_iter_next;
224 iface->iter_children = gtk_file_system_model_iter_children;
225 iface->iter_has_child = gtk_file_system_model_iter_has_child;
226 iface->iter_n_children = gtk_file_system_model_iter_n_children;
227 iface->iter_nth_child = gtk_file_system_model_iter_nth_child;
228 iface->iter_parent = gtk_file_system_model_iter_parent;
229 iface->ref_node = gtk_file_system_model_ref_node;
230 iface->unref_node = gtk_file_system_model_unref_node;
234 gtk_file_system_model_init (GtkFileSystemModel *model)
236 model->show_files = TRUE;
237 model->show_folders = TRUE;
238 model->show_hidden = FALSE;
242 gtk_file_system_model_finalize (GObject *object)
244 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
245 FileModelNode *children;
247 if (model->root_folder)
248 g_object_unref (model->root_folder);
250 children = model->roots;
253 file_model_node_free (children);
254 children = children->next;
259 * ******************** GtkTreeModel methods ********************
262 static GtkTreeModelFlags
263 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
265 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
266 GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
268 if (model->max_depth == 1)
269 flags |= GTK_TREE_MODEL_LIST_ONLY;
275 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
277 return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
281 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
286 case GTK_FILE_SYSTEM_MODEL_INFO:
287 return GTK_TYPE_FILE_INFO;
288 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
289 return G_TYPE_STRING;
291 g_assert_not_reached ();
297 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
305 indices = gtk_tree_path_get_indices (path);
306 depth = gtk_tree_path_get_depth (path);
308 g_return_val_if_fail (depth > 0, FALSE);
310 if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
313 for (i = 1; i < depth; i++)
316 if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
324 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
327 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
328 FileModelNode *node = iter->user_data;
330 GtkTreePath *result = gtk_tree_path_new ();
334 FileModelNode *parent = node->parent;
335 FileModelNode *children;
339 children = parent->children;
341 children = model->roots;
343 while (children != node)
345 if (children->is_visible)
347 children = children->next;
350 gtk_tree_path_prepend_index (result, n);
359 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
364 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
365 FileModelNode *node = iter->user_data;
369 case GTK_FILE_SYSTEM_MODEL_INFO:
370 g_value_init (value, GTK_TYPE_FILE_INFO);
371 g_value_set_boxed (value, file_model_node_get_info (model, node));
373 case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
375 const GtkFileInfo *info = file_model_node_get_info (model, node);
376 g_value_init (value, G_TYPE_STRING);
377 g_value_set_string (value, gtk_file_info_get_display_name (info));
381 g_assert_not_reached ();
386 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
389 FileModelNode *node = iter->user_data;
392 while (node && !node->is_visible)
395 iter->user_data = node;
401 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
405 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
406 FileModelNode *children;
410 FileModelNode *parent_node = parent->user_data;
411 children = file_model_node_get_children (model, parent_node);
415 children = model->roots;
418 while (children && !children->is_visible)
419 children = children->next;
421 iter->user_data = children;
423 return children != NULL;
427 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
430 FileModelNode *node = iter->user_data;
431 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
433 if (node->depth == model->max_depth)
437 const GtkFileInfo *info = file_model_node_get_info (model, node);
438 return gtk_file_info_get_is_folder (info);
443 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
446 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
447 FileModelNode *children;
452 FileModelNode *node = iter->user_data;
453 children = file_model_node_get_children (model, node);
457 children = model->roots;
462 if (children->is_visible)
464 children = children->next;
471 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
476 GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
477 FileModelNode *children;
481 FileModelNode *parent_node = parent->user_data;
482 children = file_model_node_get_children (model, parent_node);
486 children = model->roots;
489 while (children && !children->is_visible)
490 children = children->next;
492 while (n && children)
495 children = children->next;
496 while (children && !children->is_visible)
497 children = children->next;
500 iter->user_data = children;
502 return children != NULL;
506 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
510 FileModelNode *node = child->user_data;
513 iter->user_data = node;
519 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
522 file_model_node_ref (iter->user_data);
526 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
529 file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
534 * _gtk_file_system_model_new:
535 * @file_system: an object implementing #GtkFileSystem
536 * @root_path: the path of root of the file system to display,
537 * or %NULL to display starting from the
538 * root or roots of the fielsystem.
539 * @max_depth: the maximum depth from the children of @root_path
540 * or the roots of the file system to display in
541 * the file selector). A depth of 0 displays
542 * only the immediate children of @root_path,
543 * or the roots of the filesystem. -1 for no
545 * @types: a bitmask indicating the types of information
546 * that is desired about the files. This will
547 * determine what information is returned by
548 * _gtk_file_system_model_get_info().
550 * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
551 * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
552 * Using the @root_path and @max_depth parameters, the tree model
553 * can be restricted to a subportion of the entire file system.
555 * Return value: the newly created #GtkFileSystemModel object.
558 _gtk_file_system_model_new (GtkFileSystem *file_system,
559 const GtkFilePath *root_path,
561 GtkFileInfoType types)
563 GtkFileSystemModel *model;
564 GSList *roots, *tmp_list;
566 g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
568 model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
569 model->file_system = g_object_ref (file_system);
571 model->max_depth = G_MAXUSHORT;
573 model->max_depth = MIN (max_depth, G_MAXUSHORT);
574 model->types = types | GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN;
580 model->root_folder = gtk_file_system_get_folder (file_system, root_path,
582 NULL); /* NULL-GError */
584 if (model->root_folder &&
585 gtk_file_folder_list_children (model->root_folder,
587 NULL)) /* NULL-GError */
591 g_signal_connect_object (model->root_folder, "deleted",
592 G_CALLBACK (root_deleted_callback), model, 0);
593 g_signal_connect_object (model->root_folder, "files-added",
594 G_CALLBACK (root_files_added_callback), model, 0);
595 g_signal_connect_object (model->root_folder, "files-changed",
596 G_CALLBACK (root_files_changed_callback), model, 0);
597 g_signal_connect_object (model->root_folder, "files-removed",
598 G_CALLBACK (root_files_removed_callback), model, 0);
603 roots = gtk_file_system_list_roots (file_system);
604 g_signal_connect_object (file_system, "roots-changed",
605 G_CALLBACK (roots_changed_callback), model, 0);
608 roots = gtk_file_paths_sort (roots);
610 for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
612 FileModelNode *node = file_model_node_new (model, tmp_list->data);
613 gtk_file_path_free (tmp_list->data);
614 node->is_visible = file_model_node_is_visible (model, node);
615 node->next = model->roots;
619 g_slist_free (roots);
621 model->roots = (FileModelNode *)g_slist_reverse ((GSList *)model->roots);
627 model_refilter_recurse (GtkFileSystemModel *model,
628 FileModelNode *parent,
631 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
633 FileModelNode *nodes;
634 gboolean has_children = FALSE;
636 if (parent && !parent->loaded)
640 nodes = parent->children;
642 nodes = model->roots;
646 FileModelNode *next = nodes->next;
649 gtk_tree_path_append_index (path, i);
651 is_visible = file_model_node_is_visible (model, nodes);
653 if (!is_visible && nodes->is_visible)
655 file_model_node_clear (model, nodes);
656 gtk_tree_model_row_deleted (tree_model, path);
658 nodes->is_visible = FALSE;
660 else if (is_visible && !nodes->is_visible)
664 iter.user_data = nodes;
665 gtk_tree_model_row_inserted (tree_model, path, &iter);
667 nodes->is_visible = TRUE;
670 model_refilter_recurse (model, nodes, path);
678 gtk_tree_path_up (path);
683 if (parent && !has_children)
685 /* Fixme - need to insert dummy node here */
690 * _gtk_file_system_model_set_show_hidden:
691 * @model: a #GtkFileSystemModel
692 * @show_hidden: whether hidden files should be displayed
694 * Sets whether hidden files should be included in the #GtkTreeModel
698 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
699 gboolean show_hidden)
701 show_hidden = show_hidden != FALSE;
703 if (show_hidden != model->show_hidden)
707 model->show_hidden = show_hidden;
709 path = gtk_tree_path_new ();
710 model_refilter_recurse (model, NULL, path);
711 gtk_tree_path_free (path);
716 * _gtk_file_system_model_set_show_folders:
717 * @model: a #GtkFileSystemModel
718 * @show_folders: whether folders should be displayed
720 * Sets whether folders should be included in the #GtkTreeModel for
724 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
725 gboolean show_folders)
727 show_folders = show_folders != FALSE;
729 if (show_folders != model->show_folders)
733 model->show_folders = show_folders;
735 path = gtk_tree_path_new ();
736 model_refilter_recurse (model, NULL, path);
737 gtk_tree_path_free (path);
742 * _gtk_file_system_model_set_show_files:
743 * @model: a #GtkFileSystemModel
744 * @show_files: whether files (as opposed to folders) should
747 * Sets whether files (as opposed to folders) should be included
748 * in the #GtkTreeModel for display.
751 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
754 show_files = show_files != FALSE;
756 if (show_files != model->show_files)
760 model->show_files = show_files;
762 path = gtk_tree_path_new ();
763 model_refilter_recurse (model, NULL, path);
764 gtk_tree_path_free (path);
769 * _gtk_file_system_model_get_info:
770 * @model: a #GtkFileSystemModel
771 * @iter: a #GtkTreeIter pointing to a row of @model
773 * Gets the #GtkFileInfo structure for a particular row
774 * of @model. The information included in this structure
775 * is determined by the @types parameter to
776 * _gtk_file_system_model_new().
778 * Return value: a #GtkFileInfo structure. This structure
779 * is owned by @model and must not be modified or freed.
780 * If you want to save the information for later use,
781 * you must make a copy, since the structure may be
782 * freed on later changes to the file system.
785 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
788 return file_model_node_get_info (model, iter->user_data);
792 * _gtk_file_system_model_get_path:
793 * @model: a #GtkFileSystemModel
794 * @iter: a #GtkTreeIter pointing to a row of @model
796 * Gets the path for a particular row in @model.
798 * Return value: the path. This string is owned by @model and
799 * or freed. If you want to save the path for later use,
800 * you must make a copy, since the string may be freed
801 * on later changes to the file system.
804 _gtk_file_system_model_get_path (GtkFileSystemModel *model,
807 FileModelNode *node = iter->user_data;
813 unref_node_and_parents (GtkFileSystemModel *model,
816 file_model_node_unref (model, node);
818 file_model_node_unref (model, node->parent);
821 static FileModelNode *
822 find_child_node (GtkFileSystemModel *model,
823 FileModelNode *parent_node,
824 const GtkFilePath *path)
826 FileModelNode *children;
829 children = file_model_node_get_children (model, parent_node);
831 children = model->roots;
835 if (children->is_visible &&
837 gtk_file_path_compare (children->path, path) == 0)
840 children = children->next;
847 static FileModelNode *
848 find_and_ref_path (GtkFileSystemModel *model,
849 const GtkFilePath *path,
852 GtkFilePath *parent_path;
853 FileModelNode *parent_node;
854 FileModelNode *child_node;
855 GtkFileFolder *folder;
857 if (!gtk_file_system_get_parent (model->file_system, path, &parent_path, NULL))
862 parent_node = find_and_ref_path (model, parent_path, cleanups);
863 gtk_file_path_free (parent_path);
871 child_node = find_child_node (model, parent_node, path);
874 file_model_node_ref (child_node);
878 folder = gtk_file_system_get_folder (model->file_system,
881 NULL); /* NULL-GError */
884 *cleanups = g_slist_prepend (*cleanups, folder);
886 child_node = find_child_node (model, parent_node, path);
889 file_model_node_ref (child_node);
895 unref_node_and_parents (model, parent_node);
901 * _gtk_file_system_model_path_do:
902 * @model: a #GtkFileSystemModel
903 * @path: a path pointing to a file in the filesystem
905 * @func: Function to call with the path and iter corresponding
907 * @user_data: data to pass to @func
909 * Locates @path within @model, referencing
910 * (gtk_tree_model_ref_node ()) all parent nodes,
911 * calls @func passing in the path and iter for @path,
912 * then unrefs all the parent nodes.
914 * The reason for doing this operation as a callback
915 * is so that if the operation performed with the the
916 * path and iter results in referencing the the node
917 * and/or parent nodes, we don't load all the information
920 * This function is particularly useful for expanding
921 * a #GtkTreeView to a particular point in the file system.
923 * Return value: %TRUE if the path was successfully
924 * found in @model and @func was called.
927 _gtk_file_system_model_path_do (GtkFileSystemModel *model,
928 const GtkFilePath *path,
929 GtkFileSystemModelPathFunc func,
932 GSList *cleanups = NULL;
933 FileModelNode *node = find_and_ref_path (model, path, &cleanups);
940 iter.user_data = node;
941 path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
943 (*func) (model, path, &iter, user_data);
945 gtk_tree_path_free (path);
946 unref_node_and_parents (model, node);
949 g_slist_foreach (cleanups, (GFunc)g_object_unref, NULL);
950 g_slist_free (cleanups);
955 static FileModelNode *
956 file_model_node_new (GtkFileSystemModel *model,
957 const GtkFilePath *path)
959 FileModelNode *node = g_new0 (FileModelNode, 1);
962 node->path = path ? gtk_file_path_copy (path) : NULL;
968 file_model_node_free (FileModelNode *node)
970 file_model_node_clear (node->model, node);
973 gtk_file_path_free (node->path);
976 gtk_file_info_free (node->info);
981 static const GtkFileInfo *
982 file_model_node_get_info (GtkFileSystemModel *model,
989 node->info = gtk_file_info_new ();
990 gtk_file_info_set_display_name (node->info, "(Empty)");
992 else if (node->parent || model->root_folder)
994 node->info = gtk_file_folder_get_info (node->parent ? node->parent->folder : model->root_folder,
996 NULL); /* NULL-GError */
1000 node->info = gtk_file_system_get_root_info (model->file_system,
1003 NULL); /* NULL-GError */
1011 file_model_node_is_visible (GtkFileSystemModel *model,
1012 FileModelNode *node)
1014 if (model->show_hidden && model->show_folders && model->show_files)
1018 const GtkFileInfo *info = file_model_node_get_info (model, node);
1019 gboolean is_folder = gtk_file_info_get_is_folder (info);
1021 if (!model->show_folders && is_folder)
1023 if (!model->show_files && !is_folder)
1025 if (!model->show_hidden && gtk_file_info_get_is_hidden (info))
1033 file_model_node_clear (GtkFileSystemModel *model,
1034 FileModelNode *node)
1036 FileModelNode *children;
1038 file_model_node_idle_clear_cancel (node);
1040 children = node->children;
1041 node->children = NULL;
1042 node->loaded = FALSE;
1046 FileModelNode *next = children->next;
1048 file_model_node_free (children);
1055 /* Unreffing node->folder may cause roots_changed,
1056 * so we need to be careful about ordering.
1058 GtkFileFolder *folder = node->folder;
1059 node->folder = NULL;
1061 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (deleted_callback), node);
1062 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_added_callback), node);
1063 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_changed_callback), node);
1064 g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_removed_callback), node);
1066 g_object_unref (folder);
1071 file_model_node_ref (FileModelNode *node)
1074 if (node->ref_count == 1 && node->parent)
1075 node->parent->n_referenced_children++;
1079 idle_clear_callback (GtkFileSystemModel *model)
1081 while (model->idle_clears)
1083 FileModelNode *node = model->idle_clears->data;
1084 model->idle_clears = g_slist_delete_link (model->idle_clears, model->idle_clears);
1086 node->idle_clear = FALSE;
1087 file_model_node_clear (node->model, node);
1094 file_model_node_idle_clear (FileModelNode *node)
1096 if (!node->idle_clear)
1098 GtkFileSystemModel *model = node->model;
1100 node->idle_clear = TRUE;
1101 if (!model->idle_clears)
1103 model->idle_clear_source = g_idle_source_new ();
1104 g_source_set_priority (model->idle_clear_source, G_PRIORITY_HIGH);
1105 g_source_set_closure (model->idle_clear_source,
1106 g_cclosure_new_object (G_CALLBACK (idle_clear_callback),
1108 g_source_attach (model->idle_clear_source, NULL);
1111 model->idle_clears = g_slist_prepend (model->idle_clears, node);
1112 node->idle_clear = TRUE;
1117 file_model_node_idle_clear_cancel (FileModelNode *node)
1119 if (node->idle_clear)
1121 GtkFileSystemModel *model = node->model;
1123 model->idle_clears = g_slist_remove (model->idle_clears, node);
1124 if (!model->idle_clears)
1126 g_source_destroy (model->idle_clear_source);
1127 model->idle_clear_source = NULL;
1130 node->idle_clear = FALSE;
1135 file_model_node_unref (GtkFileSystemModel *model,
1136 FileModelNode *node)
1139 if (node->ref_count == 0)
1141 file_model_node_clear (model, node);
1143 file_model_node_child_unref (node->parent);
1148 file_model_node_child_unref (FileModelNode *parent)
1150 parent->n_referenced_children--;
1151 if (parent->n_referenced_children == 0)
1152 file_model_node_idle_clear (parent);
1155 static FileModelNode *
1156 file_model_node_get_children (GtkFileSystemModel *model,
1157 FileModelNode *node)
1159 if (node->ref_count == 0)
1164 const GtkFileInfo *info = file_model_node_get_info (model, node);
1165 gboolean has_children = FALSE;
1166 gboolean is_folder = node->depth < model->max_depth && gtk_file_info_get_is_folder (info);
1168 file_model_node_idle_clear_cancel (node);
1171 node->folder = gtk_file_system_get_folder (model->file_system,
1174 NULL); /* NULL-GError */
1178 GSList *child_paths, *tmp_list;
1180 if (gtk_file_folder_list_children (node->folder, &child_paths, NULL)) /* NULL-GError */
1182 child_paths = gtk_file_paths_sort (child_paths);
1184 for (tmp_list = child_paths; tmp_list; tmp_list = tmp_list->next)
1186 FileModelNode *child_node = file_model_node_new (model, tmp_list->data);
1187 gtk_file_path_free (tmp_list->data);
1188 child_node->next = node->children;
1189 child_node->parent = node;
1190 child_node->depth = node->depth + 1;
1191 child_node->is_visible = file_model_node_is_visible (model, child_node);
1192 if (child_node->is_visible)
1193 has_children = TRUE;
1194 node->children = child_node;
1196 g_slist_free (child_paths);
1199 node->children = (FileModelNode *)g_slist_reverse ((GSList *)node->children);
1201 g_signal_connect (node->folder, "deleted",
1202 G_CALLBACK (deleted_callback), node);
1203 g_signal_connect (node->folder, "files-added",
1204 G_CALLBACK (files_added_callback), node);
1205 g_signal_connect (node->folder, "files-changed",
1206 G_CALLBACK (files_changed_callback), node);
1207 g_signal_connect (node->folder, "files-removed",
1208 G_CALLBACK (files_removed_callback), node);
1210 g_object_set_data (G_OBJECT (node->folder), "model-node", node);
1213 if (is_folder && !has_children)
1215 /* The hard case ... we claimed this folder had children, but actually
1216 * it didn't. We have to add a dummy child, possibly to remove later.
1218 FileModelNode *child_node = file_model_node_new (model, NULL);
1219 child_node->is_visible = TRUE;
1220 child_node->parent = node;
1221 child_node->is_dummy = TRUE;
1223 node->children = child_node;
1224 node->has_dummy = TRUE;
1227 node->loaded = TRUE;
1230 return node->children;
1234 do_files_added (GtkFileSystemModel *model,
1235 FileModelNode *parent_node,
1238 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1239 FileModelNode *children;
1240 FileModelNode *prev = NULL;
1243 GSList *sorted_paths;
1246 sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1250 iter.user_data = parent_node;
1251 path = gtk_tree_model_get_path (tree_model, &iter);
1252 children = parent_node->children;
1256 path = gtk_tree_path_new ();
1257 children = model->roots;
1260 gtk_tree_path_down (path);
1262 if (parent_node && parent_node->has_dummy)
1265 children = children->next;
1266 gtk_tree_path_next (path);
1269 for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1271 const GtkFilePath *file_path = tmp_list->data;
1274 (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1277 if (children->is_visible)
1278 gtk_tree_path_next (path);
1280 children = children->next;
1284 children->path && gtk_file_path_compare (children->path, file_path) == 0)
1286 /* Shouldn't happen */
1292 new = file_model_node_new (model, file_path);
1295 new->next = children;
1298 else if (parent_node)
1299 parent_node->children = new;
1307 new->parent = parent_node;
1308 new->depth = parent_node->depth + 1;
1311 new->is_visible = file_model_node_is_visible (model, new);
1313 if (new->is_visible)
1315 iter.user_data = new;
1316 path = gtk_tree_model_get_path (tree_model, &iter);
1317 gtk_tree_model_row_inserted (tree_model, path, &iter);
1319 if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1320 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1322 if (parent_node && parent_node->has_dummy)
1324 FileModelNode *dummy = parent_node->children;
1325 GtkTreePath *dummy_path;
1327 parent_node->children = parent_node->children->next;
1328 parent_node->has_dummy = FALSE;
1330 dummy_path = gtk_tree_path_copy (path);
1331 gtk_tree_path_up (dummy_path);
1332 gtk_tree_path_down (dummy_path);
1334 gtk_tree_model_row_deleted (tree_model, dummy_path);
1335 gtk_tree_path_free (dummy_path);
1337 if (dummy->ref_count)
1338 file_model_node_child_unref (parent_node);
1339 file_model_node_free (dummy);
1342 gtk_tree_path_next (path);
1347 gtk_tree_path_free (path);
1348 g_slist_free (sorted_paths);
1352 do_files_changed (GtkFileSystemModel *model,
1353 FileModelNode *parent_node,
1356 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1357 FileModelNode *children;
1358 FileModelNode *prev = NULL;
1361 GSList *sorted_paths;
1364 sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1368 iter.user_data = parent_node;
1369 path = gtk_tree_model_get_path (tree_model, &iter);
1370 children = parent_node->children;
1374 path = gtk_tree_path_new ();
1375 children = model->roots;
1378 gtk_tree_path_down (path);
1380 if (parent_node && parent_node->has_dummy)
1383 children = children->next;
1384 gtk_tree_path_next (path);
1387 for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1389 const GtkFilePath *file_path = tmp_list->data;
1392 (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1395 if (children->is_visible)
1396 gtk_tree_path_next (path);
1398 children = children->next;
1402 children->path && gtk_file_path_compare (children->path, file_path) == 0)
1404 gtk_tree_model_row_changed (tree_model, path, &iter);
1408 /* Shouldn't happen */
1412 gtk_tree_path_free (path);
1413 g_slist_free (sorted_paths);
1417 do_files_removed (GtkFileSystemModel *model,
1418 FileModelNode *parent_node,
1421 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1422 FileModelNode *children;
1423 FileModelNode *prev = NULL;
1426 GSList *sorted_paths;
1428 FileModelNode *tmp_child;
1431 sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1435 iter.user_data = parent_node;
1436 path = gtk_tree_model_get_path (tree_model, &iter);
1437 children = parent_node->children;
1441 path = gtk_tree_path_new ();
1442 children = model->roots;
1445 /* Count the number of currently visible children, so that
1446 * can catch when we need to insert a dummy node.
1449 for (tmp_child = children; tmp_child; tmp_child = tmp_child->next)
1451 if (tmp_child->is_visible)
1455 gtk_tree_path_down (path);
1457 if (parent_node && parent_node->has_dummy)
1460 children = children->next;
1461 gtk_tree_path_next (path);
1464 for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1466 const GtkFilePath *file_path = tmp_list->data;
1469 (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1472 if (children->is_visible)
1473 gtk_tree_path_next (path);
1475 children = children->next;
1479 children->path && gtk_file_path_compare (children->path, file_path) == 0)
1481 FileModelNode *next = children->next;
1483 if (children->is_visible)
1488 FileModelNode *dummy = file_model_node_new (model, NULL);
1489 dummy->is_visible = TRUE;
1490 dummy->parent = parent_node;
1491 dummy->is_dummy = TRUE;
1493 parent_node->children = dummy;
1494 parent_node->has_dummy = TRUE;
1496 iter.user_data = dummy;
1497 gtk_tree_model_row_inserted (tree_model, path, &iter);
1498 gtk_tree_path_next (path);
1505 else if (parent_node)
1506 parent_node->children = next;
1508 model->roots = next;
1510 if (parent_node && children->ref_count)
1511 file_model_node_child_unref (parent_node);
1513 if (children->is_visible)
1514 gtk_tree_model_row_deleted (tree_model, path);
1516 file_model_node_free (children);
1522 /* Shouldn't happen */
1526 gtk_tree_path_free (path);
1527 g_slist_free (sorted_paths);
1531 roots_changed_callback (GtkFileSystem *file_system,
1532 GtkFileSystemModel *model)
1534 GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1537 FileModelNode *children;
1538 FileModelNode *prev = NULL;
1541 new_roots = gtk_file_system_list_roots (file_system);
1542 new_roots = gtk_file_paths_sort (new_roots);
1544 children = model->roots;
1545 tmp_list = new_roots;
1546 path = gtk_tree_path_new ();
1547 gtk_tree_path_down (path);
1549 while (children || tmp_list)
1551 FileModelNode *next = NULL;
1554 if (tmp_list && children)
1555 cmp = gtk_file_path_compare (children->path, tmp_list->data);
1563 next = children->next;
1566 prev->next = children->next;
1568 model->roots = children->next;
1570 if (children->is_visible)
1571 gtk_tree_model_row_deleted (tree_model, path);
1573 file_model_node_free (children);
1579 next = children->next;
1581 if (children->is_visible)
1582 gtk_tree_path_next (path);
1587 FileModelNode *node = file_model_node_new (model, tmp_list->data);
1588 node->is_visible = file_model_node_is_visible (model, node);
1589 node->next = children;
1595 model->roots = node;
1597 if (node->is_visible)
1599 iter.user_data = node;
1600 gtk_tree_model_row_inserted (tree_model, path, &iter);
1602 if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1603 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1605 gtk_tree_path_next (path);
1618 gtk_file_path_free (tmp_list->data);
1619 tmp_list = tmp_list->next;
1623 g_slist_free (new_roots);
1624 gtk_tree_path_free (path);
1628 deleted_callback (GtkFileFolder *folder,
1629 FileModelNode *node)
1634 files_added_callback (GtkFileFolder *folder,
1636 FileModelNode *node)
1638 do_files_added (node->model, node, paths);
1642 files_changed_callback (GtkFileFolder *folder,
1644 FileModelNode *node)
1646 do_files_changed (node->model, node, paths);
1650 files_removed_callback (GtkFileFolder *folder,
1652 FileModelNode *node)
1654 do_files_removed (node->model, node, paths);
1658 root_deleted_callback (GtkFileFolder *folder,
1659 GtkFileSystemModel *model)
1664 root_files_added_callback (GtkFileFolder *folder,
1666 GtkFileSystemModel *model)
1668 do_files_added (model, NULL, paths);
1672 root_files_changed_callback (GtkFileFolder *folder,
1674 GtkFileSystemModel *model)
1676 do_files_changed (model, NULL, paths);
1680 root_files_removed_callback (GtkFileFolder *folder,
1682 GtkFileSystemModel *model)
1684 do_files_removed (model, NULL, paths);