]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilesystemmodel.c
Add a stock icon to the "Add bookmark" button.
[~andy/gtk] / gtk / gtkfilesystemmodel.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilesystemmodel.c: GtkTreeModel wrapping a GtkFileSystem
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #include <string.h>
22
23 #include "gtkfilesystemmodel.h"
24 #include "gtkfilesystem.h"
25 #include "gtkintl.h"
26 #include "gtktreemodel.h"
27
28 typedef struct _GtkFileSystemModelClass GtkFileSystemModelClass;
29 typedef struct _FileModelNode           FileModelNode;
30
31 #define GTK_FILE_SYSTEM_MODEL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
32 #define GTK_IS_FILE_SYSTEM_MODEL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_MODEL))
33 #define GTK_FILE_SYSTEM_MODEL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_MODEL, GtkFileSystemModelClass))
34
35 struct _GtkFileSystemModelClass
36 {
37   GObjectClass parent_class;
38 };
39
40 struct _GtkFileSystemModel
41 {
42   GObject parent_instance;
43
44   GtkFileSystem  *file_system;
45   GtkFileInfoType types;
46   FileModelNode  *roots;
47   GtkFileFolder  *root_folder;
48
49   GtkFileSystemModelFilter filter_func;
50   gpointer filter_data;
51
52   GSList *idle_clears;
53   GSource *idle_clear_source;
54
55   gushort max_depth;
56   
57   guint show_hidden : 1;
58   guint show_folders : 1;
59   guint show_files : 1;
60   guint folders_only : 1;
61 };
62
63 struct _FileModelNode
64 {
65   GtkFilePath *path;
66   FileModelNode *next;
67
68   GtkFileInfo *info;
69   GtkFileFolder *folder;
70   
71   FileModelNode *children;
72   FileModelNode *parent;
73   GtkFileSystemModel *model;
74
75   guint ref_count;
76   guint n_referenced_children;
77
78   gushort depth;
79
80   guint has_dummy : 1;
81   guint is_dummy : 1;
82   guint is_visible : 1;
83   guint loaded : 1;
84   guint idle_clear : 1;
85 };
86
87 static void gtk_file_system_model_class_init   (GtkFileSystemModelClass *class);
88 static void gtk_file_system_model_iface_init   (GtkTreeModelIface       *iface);
89 static void gtk_file_system_model_init         (GtkFileSystemModel      *model);
90 static void gtk_file_system_model_finalize     (GObject                 *object);
91
92 static GtkTreeModelFlags gtk_file_system_model_get_flags       (GtkTreeModel *tree_model);
93 static gint              gtk_file_system_model_get_n_columns   (GtkTreeModel *tree_model);
94 static GType             gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
95                                                                 gint          index);
96 static gboolean          gtk_file_system_model_get_iter        (GtkTreeModel *tree_model,
97                                                                 GtkTreeIter  *iter,
98                                                                 GtkTreePath  *path);
99 static GtkTreePath *     gtk_file_system_model_get_path        (GtkTreeModel *tree_model,
100                                                                 GtkTreeIter  *iter);
101 static void              gtk_file_system_model_get_value       (GtkTreeModel *tree_model,
102                                                                 GtkTreeIter  *iter,
103                                                                 gint          column,
104                                                                 GValue       *value);
105 static gboolean          gtk_file_system_model_iter_next       (GtkTreeModel *tree_model,
106                                                                 GtkTreeIter  *iter);
107 static gboolean          gtk_file_system_model_iter_children   (GtkTreeModel *tree_model,
108                                                                 GtkTreeIter  *iter,
109                                                                 GtkTreeIter  *parent);
110 static gboolean          gtk_file_system_model_iter_has_child  (GtkTreeModel *tree_model,
111                                                                 GtkTreeIter  *iter);
112 static gint              gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
113                                                                 GtkTreeIter  *iter);
114 static gboolean          gtk_file_system_model_iter_nth_child  (GtkTreeModel *tree_model,
115                                                                 GtkTreeIter  *iter,
116                                                                 GtkTreeIter  *parent,
117                                                                 gint          n);
118 static gboolean          gtk_file_system_model_iter_parent     (GtkTreeModel *tree_model,
119                                                                 GtkTreeIter  *iter,
120                                                                 GtkTreeIter  *child);
121 static void              gtk_file_system_model_ref_node        (GtkTreeModel *tree_model,
122                                                                 GtkTreeIter  *iter);
123 static void              gtk_file_system_model_unref_node      (GtkTreeModel *tree_model,
124                                                                 GtkTreeIter  *iter);
125
126 static FileModelNode *file_model_node_new        (GtkFileSystemModel *model,
127                                                   const GtkFilePath  *path);
128 static void           file_model_node_free       (FileModelNode      *node);
129 static void           file_model_node_ref        (FileModelNode      *node);
130 static void           file_model_node_unref      (GtkFileSystemModel *model,
131                                                   FileModelNode      *node);
132
133 static void file_model_node_idle_clear        (FileModelNode *node);
134 static void file_model_node_idle_clear_cancel (FileModelNode *node);
135 static void file_model_node_child_unref       (FileModelNode *parent);
136
137 static const GtkFileInfo *file_model_node_get_info     (GtkFileSystemModel *model,
138                                                         FileModelNode      *node);
139 static gboolean           file_model_node_is_visible   (GtkFileSystemModel *model,
140                                                         FileModelNode      *node);
141 static void               file_model_node_clear        (GtkFileSystemModel *model,
142                                                         FileModelNode      *node);
143 static FileModelNode *    file_model_node_get_children (GtkFileSystemModel *model,
144                                                         FileModelNode      *node);
145
146 static void roots_changed_callback (GtkFileSystem      *file_system,
147                                     GtkFileSystemModel *model);
148                                     
149 static void deleted_callback       (GtkFileFolder *folder,
150                                     FileModelNode *node);
151 static void files_added_callback   (GtkFileFolder *folder,
152                                     GSList        *paths,
153                                     FileModelNode *node);
154 static void files_changed_callback (GtkFileFolder *folder,
155                                     GSList        *paths,
156                                     FileModelNode *node);
157 static void files_removed_callback (GtkFileFolder *folder,
158                                     GSList        *paths,
159                                     FileModelNode *node);
160
161 static void root_deleted_callback       (GtkFileFolder      *folder,
162                                          GtkFileSystemModel *model);
163 static void root_files_added_callback   (GtkFileFolder      *folder,
164                                          GSList             *paths,
165                                          GtkFileSystemModel *model);
166 static void root_files_changed_callback (GtkFileFolder      *folder,
167                                          GSList             *paths,
168                                          GtkFileSystemModel *model);
169 static void root_files_removed_callback (GtkFileFolder      *folder,
170                                          GSList             *paths,
171                                          GtkFileSystemModel *model);
172
173 GType
174 _gtk_file_system_model_get_type (void)
175 {
176   static GType file_system_model_type = 0;
177
178   if (!file_system_model_type)
179     {
180       static const GTypeInfo file_system_model_info =
181       {
182         sizeof (GtkFileSystemModelClass),
183         NULL,           /* base_init */
184         NULL,           /* base_finalize */
185         (GClassInitFunc) gtk_file_system_model_class_init,
186         NULL,           /* class_finalize */
187         NULL,           /* class_data */
188         sizeof (GtkFileSystemModel),
189         0,              /* n_preallocs */
190         (GInstanceInitFunc) gtk_file_system_model_init,
191       };
192       
193       static const GInterfaceInfo file_system_info =
194       {
195         (GInterfaceInitFunc) gtk_file_system_model_iface_init, /* interface_init */
196         NULL,                                                 /* interface_finalize */
197         NULL                                                  /* interface_data */
198       };
199
200       file_system_model_type = g_type_register_static (G_TYPE_OBJECT,
201                                                       "GtkFileSystemModel",
202                                                       &file_system_model_info, 0);
203       g_type_add_interface_static (file_system_model_type,
204                                    GTK_TYPE_TREE_MODEL,
205                                    &file_system_info);
206     }
207
208   return file_system_model_type;
209 }
210
211 static void
212 gtk_file_system_model_class_init (GtkFileSystemModelClass *class)
213 {
214   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
215   
216   gobject_class->finalize = gtk_file_system_model_finalize;
217 }
218
219 static void
220 gtk_file_system_model_iface_init (GtkTreeModelIface *iface)
221 {
222   iface->get_flags =       gtk_file_system_model_get_flags;
223   iface->get_n_columns =   gtk_file_system_model_get_n_columns;
224   iface->get_column_type = gtk_file_system_model_get_column_type;
225   iface->get_iter =        gtk_file_system_model_get_iter;
226   iface->get_path =        gtk_file_system_model_get_path;
227   iface->get_value =       gtk_file_system_model_get_value;
228   iface->iter_next =       gtk_file_system_model_iter_next;
229   iface->iter_children =   gtk_file_system_model_iter_children;
230   iface->iter_has_child =  gtk_file_system_model_iter_has_child;
231   iface->iter_n_children = gtk_file_system_model_iter_n_children;
232   iface->iter_nth_child =  gtk_file_system_model_iter_nth_child;
233   iface->iter_parent =     gtk_file_system_model_iter_parent;
234   iface->ref_node =        gtk_file_system_model_ref_node;
235   iface->unref_node =      gtk_file_system_model_unref_node;
236 }
237
238 static void
239 gtk_file_system_model_init (GtkFileSystemModel *model)
240 {
241   model->show_files = TRUE;
242   model->show_folders = TRUE;
243   model->show_hidden = FALSE;
244 }
245
246 static void
247 gtk_file_system_model_finalize (GObject *object)
248 {
249   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (object);
250   FileModelNode *children;
251
252   if (model->root_folder)
253     g_object_unref (model->root_folder);
254
255   children = model->roots;
256   while (children)
257     {
258       file_model_node_free (children);
259       children = children->next;
260     }
261 }
262
263 /*
264  * ******************** GtkTreeModel methods ********************
265  */
266
267 static GtkTreeModelFlags
268 gtk_file_system_model_get_flags (GtkTreeModel *tree_model)
269 {
270   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
271   GtkTreeModelFlags flags = GTK_TREE_MODEL_ITERS_PERSIST;
272
273   if (model->max_depth == 1)
274     flags |= GTK_TREE_MODEL_LIST_ONLY;
275
276   return flags;
277 }
278
279 static gint
280 gtk_file_system_model_get_n_columns (GtkTreeModel *tree_model)
281 {
282   return GTK_FILE_SYSTEM_MODEL_N_COLUMNS;
283 }
284
285 static GType
286 gtk_file_system_model_get_column_type (GtkTreeModel *tree_model,
287                                        gint          index)
288 {
289   switch (index)
290     {
291     case GTK_FILE_SYSTEM_MODEL_INFO:
292       return GTK_TYPE_FILE_INFO; 
293     case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
294       return G_TYPE_STRING;
295    default:
296       g_assert_not_reached ();
297       return G_TYPE_NONE;
298     }
299 }
300
301 static gboolean
302 gtk_file_system_model_get_iter (GtkTreeModel *tree_model,
303                                 GtkTreeIter  *iter,
304                                 GtkTreePath  *path)
305 {
306   GtkTreeIter parent;
307   gint *indices;
308   gint depth, i;
309
310   indices = gtk_tree_path_get_indices (path);
311   depth = gtk_tree_path_get_depth (path);
312
313   g_return_val_if_fail (depth > 0, FALSE);
314
315   if (!gtk_tree_model_iter_nth_child (tree_model, iter, NULL, indices[0]))
316     return FALSE;
317
318   for (i = 1; i < depth; i++)
319     {
320       parent = *iter;
321       if (!gtk_tree_model_iter_nth_child (tree_model, iter, &parent, indices[i]))
322         return FALSE;
323     }
324
325   return TRUE;
326 }
327
328 static GtkTreePath *
329 gtk_file_system_model_get_path (GtkTreeModel *tree_model,
330                                 GtkTreeIter  *iter)
331 {
332   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
333   FileModelNode *node = iter->user_data;
334
335   GtkTreePath *result = gtk_tree_path_new ();
336
337   while (node)
338     {
339       FileModelNode *parent = node->parent;
340       FileModelNode *children;
341       int n = 0;
342
343       if (parent)
344         children = parent->children;
345       else
346         children = model->roots;
347
348       while (children != node)
349         {
350           if (children->is_visible)
351             n++;
352           children = children->next;
353         }
354       
355       gtk_tree_path_prepend_index (result, n);
356
357       node = parent;
358     }
359
360   return result;
361 }
362
363 static void
364 gtk_file_system_model_get_value (GtkTreeModel *tree_model,
365                                  GtkTreeIter  *iter,
366                                  gint          column,
367                                  GValue       *value)
368 {
369   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
370   FileModelNode *node = iter->user_data;
371   
372   switch (column)
373     {
374     case GTK_FILE_SYSTEM_MODEL_INFO:
375       g_value_init (value, GTK_TYPE_FILE_INFO);
376       g_value_set_boxed (value, file_model_node_get_info (model, node));
377       break;
378     case GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME:
379       {
380         const GtkFileInfo *info = file_model_node_get_info (model, node);
381         g_value_init (value, G_TYPE_STRING);
382         g_value_set_string (value, gtk_file_info_get_display_name (info));
383       }
384       break;
385     default:
386       g_assert_not_reached ();
387     }
388 }
389
390 static gboolean
391 gtk_file_system_model_iter_next (GtkTreeModel *tree_model,
392                                  GtkTreeIter  *iter)
393 {
394   FileModelNode *node = iter->user_data;
395
396   node = node->next;
397   while (node && !node->is_visible)
398     node = node->next;
399   
400   iter->user_data = node;
401
402   return node != NULL;
403 }
404
405 static gboolean
406 gtk_file_system_model_iter_children (GtkTreeModel *tree_model,
407                                      GtkTreeIter  *iter,
408                                      GtkTreeIter  *parent)
409 {
410   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
411   FileModelNode *children;
412
413   if (parent)
414     {
415       FileModelNode *parent_node = parent->user_data;
416       children = file_model_node_get_children (model, parent_node);
417     }
418   else
419     {
420       children = model->roots;
421     }
422
423   while (children && !children->is_visible)
424     children = children->next;
425
426   iter->user_data = children;
427
428   return children != NULL;
429 }
430
431 static gboolean
432 gtk_file_system_model_iter_has_child (GtkTreeModel *tree_model,
433                                       GtkTreeIter  *iter)
434 {
435   FileModelNode *node = iter->user_data;
436   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
437
438   if (node->depth == model->max_depth)
439     return FALSE;
440   else
441     {
442       const GtkFileInfo *info = file_model_node_get_info (model, node);
443       return gtk_file_info_get_is_folder (info);
444     }
445 }
446
447 static gint
448 gtk_file_system_model_iter_n_children (GtkTreeModel *tree_model,
449                                        GtkTreeIter  *iter)
450 {
451   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
452   FileModelNode *children;
453   gint n = 0;
454
455   if (iter)
456     {
457       FileModelNode *node = iter->user_data;
458       children = file_model_node_get_children (model, node);
459     }
460   else
461     {
462       children = model->roots;
463     }
464
465   while (children)
466     {
467       if (children->is_visible)
468         n++;
469       children = children->next;
470     }
471
472   return n;
473 }
474
475 static gboolean
476 gtk_file_system_model_iter_nth_child (GtkTreeModel *tree_model,
477                                       GtkTreeIter  *iter,
478                                       GtkTreeIter  *parent,
479                                       gint          n)
480 {
481   GtkFileSystemModel *model = GTK_FILE_SYSTEM_MODEL (tree_model);
482   FileModelNode *children;
483
484   if (parent)
485     {
486       FileModelNode *parent_node = parent->user_data;
487       children = file_model_node_get_children (model, parent_node);
488     }
489   else
490     {
491       children = model->roots;
492     }
493
494   while (children && !children->is_visible)
495     children = children->next;
496
497   while (n && children)
498     {
499       n--;
500       children = children->next;
501       while (children && !children->is_visible)
502         children = children->next;
503     }
504
505   iter->user_data = children;
506
507   return children != NULL;
508 }
509
510 static gboolean
511 gtk_file_system_model_iter_parent (GtkTreeModel *tree_model,
512                                    GtkTreeIter  *iter,
513                                    GtkTreeIter  *child)
514 {
515   FileModelNode *node = child->user_data;
516   
517   node = node->parent;
518   iter->user_data = node;
519
520   return node != NULL;
521 }
522
523 static void
524 gtk_file_system_model_ref_node (GtkTreeModel *tree_model,
525                                 GtkTreeIter  *iter)
526 {
527   file_model_node_ref (iter->user_data);
528 }
529
530 static void
531 gtk_file_system_model_unref_node (GtkTreeModel *tree_model,
532                                   GtkTreeIter  *iter)
533 {
534   file_model_node_unref (GTK_FILE_SYSTEM_MODEL (tree_model),
535                          iter->user_data);
536 }
537
538 /**
539  * _gtk_file_system_model_new:
540  * @file_system: an object implementing #GtkFileSystem
541  * @root_path: the path of root of the file system to display,
542  *            or %NULL to display starting from the
543  *            root or roots of the fielsystem.
544  * @max_depth: the maximum depth from the children of @root_path
545  *             or the roots of the file system to display in
546  *             the file selector). A depth of 0 displays
547  *             only the immediate children of @root_path,
548  *             or the roots of the filesystem. -1 for no
549  *             maximum depth.
550  * @types: a bitmask indicating the types of information
551  *         that is desired about the files. This will
552  *         determine what information is returned by
553  *         _gtk_file_system_model_get_info().
554  *
555  * Creates a new #GtkFileSystemModel object. The #GtkFileSystemModel
556  * object wraps a #GtkFileSystem interface as a #GtkTreeModel.
557  * Using the @root_path and @max_depth parameters, the tree model
558  * can be restricted to a subportion of the entire file system.
559  * 
560  * Return value: the newly created #GtkFileSystemModel object.
561  **/
562 GtkFileSystemModel *
563 _gtk_file_system_model_new (GtkFileSystem     *file_system,
564                             const GtkFilePath *root_path,
565                             gint               max_depth,
566                             GtkFileInfoType    types)
567 {
568   GtkFileSystemModel *model;
569   GSList *roots = NULL;
570   GSList *tmp_list;
571
572   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
573
574   model = g_object_new (GTK_TYPE_FILE_SYSTEM_MODEL, NULL);
575   model->file_system = g_object_ref (file_system);
576   if (max_depth < 0)
577     model->max_depth = G_MAXUSHORT;
578   else
579     model->max_depth = MIN (max_depth, G_MAXUSHORT);
580   model->types = types | GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN;
581
582   if (root_path)
583     {
584       GSList *child_paths;
585       
586       model->root_folder = gtk_file_system_get_folder (file_system, root_path,
587                                                        model->types,
588                                                        NULL);   /* NULL-GError */
589
590       if (model->root_folder &&
591           gtk_file_folder_list_children (model->root_folder,
592                                          &child_paths,
593                                          NULL)) /* NULL-GError */
594         {
595           roots = child_paths;
596           
597           g_signal_connect_object (model->root_folder, "deleted",
598                                    G_CALLBACK (root_deleted_callback), model, 0);
599           g_signal_connect_object (model->root_folder, "files-added",
600                                    G_CALLBACK (root_files_added_callback), model, 0);
601           g_signal_connect_object (model->root_folder, "files-changed",
602                                    G_CALLBACK (root_files_changed_callback), model, 0);
603           g_signal_connect_object (model->root_folder, "files-removed",
604                                    G_CALLBACK (root_files_removed_callback), model, 0);
605         }
606     }
607   else
608     {
609       roots = gtk_file_system_list_roots (file_system);
610       g_signal_connect_object (file_system, "roots-changed",
611                                G_CALLBACK (roots_changed_callback), model, 0);
612     }
613
614   roots = gtk_file_paths_sort (roots);
615   
616   for (tmp_list = roots; tmp_list; tmp_list = tmp_list->next)
617     {
618       FileModelNode *node = file_model_node_new (model, tmp_list->data);
619       gtk_file_path_free (tmp_list->data);
620       node->is_visible = file_model_node_is_visible (model, node);
621       node->next = model->roots;
622       node->depth = 0;
623       model->roots = node;
624     }
625   g_slist_free (roots);
626
627   model->roots = (FileModelNode *)g_slist_reverse ((GSList *)model->roots);
628   
629   return model;
630 }
631
632 static void
633 model_refilter_recurse (GtkFileSystemModel *model,
634                         FileModelNode      *parent,
635                         GtkTreePath        *path)
636 {
637   GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
638   int i = 0;
639   FileModelNode *nodes;
640   gboolean has_children = FALSE;
641
642   if (parent && !parent->loaded)
643     return;
644
645   if (parent)
646     nodes = parent->children;
647   else
648     nodes = model->roots;
649
650   while (nodes)
651     {
652       FileModelNode *next = nodes->next;
653       gboolean is_visible;
654       
655       gtk_tree_path_append_index (path, i);
656
657       is_visible = file_model_node_is_visible (model, nodes);
658       
659       if (!is_visible && nodes->is_visible)
660         {
661           file_model_node_clear (model, nodes);
662           gtk_tree_model_row_deleted (tree_model, path);
663
664           nodes->is_visible = FALSE;
665         }
666       else if (is_visible && !nodes->is_visible)
667         {
668           GtkTreeIter iter;
669
670           iter.user_data = nodes;
671           gtk_tree_model_row_inserted (tree_model, path, &iter);
672
673           nodes->is_visible = TRUE;
674         }
675       else
676         model_refilter_recurse (model, nodes, path);
677
678       if (is_visible)
679         {
680           has_children = TRUE;
681           i++;
682         }
683       
684       gtk_tree_path_up (path);
685       
686       nodes = next;
687     }
688
689   if (parent && !has_children)
690     {
691       /* Fixme - need to insert dummy node here */
692     }
693 }
694
695 static void
696 model_refilter_all (GtkFileSystemModel *model)
697 {
698   GtkTreePath *path;
699
700   path = gtk_tree_path_new ();
701   model_refilter_recurse (model, NULL, path);
702   gtk_tree_path_free (path);
703 }
704
705 /**
706  * _gtk_file_system_model_set_show_hidden:
707  * @model: a #GtkFileSystemModel
708  * @show_hidden: whether hidden files should be displayed
709  * 
710  * Sets whether hidden files should be included in the #GtkTreeModel
711  * for display.
712  **/
713 void
714 _gtk_file_system_model_set_show_hidden (GtkFileSystemModel *model,
715                                         gboolean            show_hidden)
716 {
717   show_hidden = show_hidden != FALSE;
718
719   if (show_hidden != model->show_hidden)
720     {
721       model->show_hidden = show_hidden;
722       model_refilter_all (model);
723     }
724 }
725
726 /**
727  * _gtk_file_system_model_set_show_folders:
728  * @model: a #GtkFileSystemModel
729  * @show_folders: whether folders should be displayed
730  * 
731  * Sets whether folders should be included in the #GtkTreeModel for
732  * display.
733  **/
734 void
735 _gtk_file_system_model_set_show_folders (GtkFileSystemModel *model,
736                                          gboolean            show_folders)
737 {
738   show_folders = show_folders != FALSE;
739
740   if (show_folders != model->show_folders)
741     {
742       model->show_folders = show_folders;
743       model_refilter_all (model);
744     }
745 }
746
747 /**
748  * _gtk_file_system_model_set_show_files:
749  * @model: a #GtkFileSystemModel
750  * @show_files: whether files (as opposed to folders) should
751  *              be displayed.
752  * 
753  * Sets whether files (as opposed to folders) should be included
754  * in the #GtkTreeModel for display.
755  **/
756 void
757 _gtk_file_system_model_set_show_files (GtkFileSystemModel *model,
758                                        gboolean            show_files)
759 {
760   show_files = show_files != FALSE;
761
762   if (show_files != model->show_files)
763     {
764       model->show_files = show_files;
765       model_refilter_all (model);
766     }
767 }
768
769 /**
770  * _gtk_file_system_model_get_info:
771  * @model: a #GtkFileSystemModel
772  * @iter: a #GtkTreeIter pointing to a row of @model
773  * 
774  * Gets the #GtkFileInfo structure for a particular row
775  * of @model. The information included in this structure
776  * is determined by the @types parameter to
777  * _gtk_file_system_model_new().
778  * 
779  * Return value: a #GtkFileInfo structure. This structure
780  *   is owned by @model and must not be modified or freed.
781  *   If you want to save the information for later use,
782  *   you must make a copy, since the structure may be
783  *   freed on later changes to the file system.
784  **/
785 const GtkFileInfo *
786 _gtk_file_system_model_get_info (GtkFileSystemModel *model,
787                                  GtkTreeIter        *iter)
788 {
789   return file_model_node_get_info (model, iter->user_data);
790 }
791
792 /**
793  * _gtk_file_system_model_get_path:
794  * @model: a #GtkFileSystemModel
795  * @iter: a #GtkTreeIter pointing to a row of @model
796  * 
797  * Gets the path for a particular row in @model. 
798  *
799  * Return value: the path. This string is owned by @model and
800  *   or freed. If you want to save the path for later use,
801  *   you must make a copy, since the string may be freed
802  *   on later changes to the file system.
803  **/
804 const GtkFilePath *
805 _gtk_file_system_model_get_path (GtkFileSystemModel *model,
806                                  GtkTreeIter        *iter)
807 {
808   FileModelNode *node = iter->user_data;
809
810   if (node->is_dummy)
811     return node->parent->path;
812   else
813     return node->path;
814 }
815
816 static void
817 unref_node_and_parents (GtkFileSystemModel *model,
818                         FileModelNode      *node)
819 {
820   file_model_node_unref (model, node);
821   if (node->parent)
822     file_model_node_unref (model, node->parent);
823 }
824
825 static FileModelNode *
826 find_child_node (GtkFileSystemModel *model,
827                  FileModelNode      *parent_node,
828                  const GtkFilePath  *path)
829 {
830   FileModelNode *children;
831   
832   if (parent_node)
833     children = file_model_node_get_children (model, parent_node);
834   else
835     children = model->roots;
836
837   while (children)
838     {
839       if (children->is_visible &&
840           children->path &&
841           gtk_file_path_compare (children->path, path) == 0)
842         return children;
843
844       children = children->next;
845     }
846
847   return NULL;
848 }
849                  
850
851 static FileModelNode *
852 find_and_ref_path (GtkFileSystemModel  *model,
853                    const GtkFilePath   *path,
854                    GSList             **cleanups)
855 {
856   GtkFilePath *parent_path;
857   FileModelNode *parent_node;
858   FileModelNode *child_node;
859   GtkFileFolder *folder;
860
861   if (!gtk_file_system_get_parent (model->file_system, path, &parent_path, NULL))
862     return NULL;
863
864   if (parent_path)
865     {
866       parent_node = find_and_ref_path (model, parent_path, cleanups);
867       gtk_file_path_free (parent_path);
868
869       if (!parent_node)
870         return NULL;
871     }
872   else
873     parent_node = NULL;
874
875   child_node = find_child_node (model, parent_node, path);
876   if (child_node)
877     {
878       file_model_node_ref (child_node);
879       return child_node;
880     }
881
882   folder = gtk_file_system_get_folder (model->file_system,
883                                        path,
884                                        model->types,
885                                        NULL);   /* NULL-GError */
886   if (folder)
887     {
888       *cleanups = g_slist_prepend (*cleanups, folder);
889
890       child_node = find_child_node (model, parent_node, path);
891       if (child_node)
892         {
893           file_model_node_ref (child_node);
894           return child_node;
895         }
896     }
897
898   if (parent_node)
899     unref_node_and_parents (model, parent_node);
900
901   return NULL;
902 }
903
904 /**
905  * _gtk_file_system_model_set_filter:
906  * @mode: a #GtkFileSystemModel
907  * @filter: function to be called for each file
908  * @user_data: data to pass to @filter
909  * 
910  * Sets a callback called for each file/directory to see whether
911  * it should be included in model. If this function was made
912  * public, we'd want to include a GDestroyNotify as well.
913  **/
914 void
915 _gtk_file_system_model_set_filter (GtkFileSystemModel      *model,
916                                    GtkFileSystemModelFilter filter,
917                                    gpointer                 user_data)
918 {
919   g_return_if_fail (GTK_IS_FILE_SYSTEM_MODEL (model));
920   
921   model->filter_func = filter;
922   model->filter_data = user_data;
923
924   model_refilter_all (model);
925 }
926
927 /**
928  * _gtk_file_system_model_path_do:
929  * @model: a #GtkFileSystemModel
930  * @path: a path pointing to a file in the filesystem
931  *       for @model.
932  * @func: Function to call with the path and iter corresponding
933  *        to @path.
934  * @user_data: data to pass to @func
935  * 
936  * Locates @path within @model, referencing
937  * (gtk_tree_model_ref_node ()) all parent nodes,
938  * calls @func passing in the path and iter for @path,
939  * then unrefs all the parent nodes.
940  *
941  * The reason for doing this operation as a callback
942  * is so that if the operation performed with the the
943  * path and iter results in referencing the the node
944  * and/or parent nodes, we don't load all the information
945  * about the nodes.
946  *
947  * This function is particularly useful for expanding
948  * a #GtkTreeView to a particular point in the file system.
949  * 
950  * Return value: %TRUE if the path was successfully
951  *  found in @model and @func was called.
952  **/
953 gboolean
954 _gtk_file_system_model_path_do (GtkFileSystemModel       *model,
955                                const GtkFilePath         *path,
956                                GtkFileSystemModelPathFunc func,
957                                gpointer                   user_data)
958 {
959   GSList *cleanups = NULL;
960   FileModelNode *node = find_and_ref_path (model, path, &cleanups);
961
962   if (node)
963     {
964       GtkTreeIter iter;
965       GtkTreePath *path;
966
967       iter.user_data = node;
968       path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
969
970       (*func) (model, path, &iter, user_data);
971
972       gtk_tree_path_free (path);
973       unref_node_and_parents (model, node);
974     }
975
976   g_slist_foreach (cleanups, (GFunc)g_object_unref, NULL);
977   g_slist_free (cleanups);
978
979   return node != NULL;
980 }
981
982 static FileModelNode *
983 file_model_node_new (GtkFileSystemModel *model,
984                      const GtkFilePath  *path)
985 {
986   FileModelNode *node = g_new0 (FileModelNode, 1);
987
988   node->model = model;
989   node->path = path ? gtk_file_path_copy (path) : NULL;
990
991   return node;
992 }
993
994 static void
995 file_model_node_free (FileModelNode *node)
996 {
997   file_model_node_clear (node->model, node);
998   
999   if (node->path)
1000     gtk_file_path_free (node->path);
1001
1002   if (node->info)
1003     gtk_file_info_free (node->info);
1004
1005   g_free (node);
1006 }
1007
1008 static const GtkFileInfo *
1009 file_model_node_get_info (GtkFileSystemModel *model,
1010                           FileModelNode      *node)
1011 {
1012   if (!node->info)
1013     {
1014       if (node->is_dummy)
1015         {
1016           node->info = gtk_file_info_new ();
1017           gtk_file_info_set_display_name (node->info, _("(Empty)"));
1018         }
1019       else if (node->parent || model->root_folder)
1020         {
1021           node->info = gtk_file_folder_get_info (node->parent ? node->parent->folder : model->root_folder,
1022                                                  node->path,
1023                                                  NULL); /* NULL-GError */
1024         }
1025       else
1026         {
1027           node->info = gtk_file_system_get_root_info (model->file_system,
1028                                                       node->path,
1029                                                       model->types,
1030                                                       NULL);  /* NULL-GError */
1031         }
1032     }
1033
1034   return node->info;
1035 }
1036
1037 static gboolean
1038 file_model_node_is_visible (GtkFileSystemModel *model,
1039                             FileModelNode      *node)
1040 {
1041   if (model->show_hidden && model->show_folders && model->show_files)
1042     return TRUE;
1043   else
1044     {
1045       const GtkFileInfo *info = file_model_node_get_info (model, node);
1046       gboolean is_folder = gtk_file_info_get_is_folder (info);
1047
1048       if (!model->show_folders && is_folder)
1049         return FALSE;
1050       if (!model->show_files && !is_folder)
1051         return FALSE;
1052       if (!model->show_hidden && gtk_file_info_get_is_hidden (info))
1053         return FALSE;
1054       if (model->filter_func && !model->filter_func (model, node->path, info, model->filter_data))
1055         return FALSE;
1056
1057       return TRUE;
1058     }
1059 }
1060
1061 static void
1062 file_model_node_clear (GtkFileSystemModel *model,
1063                        FileModelNode      *node)
1064 {
1065   FileModelNode *children;
1066   
1067   file_model_node_idle_clear_cancel (node);
1068   
1069   children = node->children;
1070   node->children = NULL;
1071   node->loaded = FALSE;
1072   
1073   while (children)
1074     {
1075       FileModelNode *next = children->next;
1076       
1077       file_model_node_free (children);
1078       
1079       children = next;
1080     }
1081
1082   if (node->folder)
1083     {
1084       /* Unreffing node->folder may cause roots_changed,
1085        * so we need to be careful about ordering.
1086        */
1087       GtkFileFolder *folder = node->folder;
1088       node->folder = NULL;
1089
1090       g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (deleted_callback), node);
1091       g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_added_callback), node);
1092       g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_changed_callback), node);
1093       g_signal_handlers_disconnect_by_func (folder, G_CALLBACK (files_removed_callback), node);
1094       
1095       g_object_unref (folder);
1096     }
1097 }
1098
1099 static void
1100 file_model_node_ref (FileModelNode *node)
1101 {
1102   node->ref_count++;
1103   if (node->ref_count == 1 && node->parent)
1104     node->parent->n_referenced_children++;
1105 }
1106
1107 static gboolean
1108 idle_clear_callback (GtkFileSystemModel *model)
1109 {
1110   while (model->idle_clears)
1111     {
1112       FileModelNode *node = model->idle_clears->data;
1113       model->idle_clears = g_slist_delete_link (model->idle_clears, model->idle_clears);
1114
1115       node->idle_clear = FALSE;
1116       file_model_node_clear (node->model, node);
1117     }
1118
1119   return FALSE;
1120 }
1121  
1122 static void
1123 file_model_node_idle_clear (FileModelNode *node)
1124 {
1125   if (!node->idle_clear)
1126     {
1127       GtkFileSystemModel *model = node->model;
1128
1129       node->idle_clear = TRUE;
1130       if (!model->idle_clears)
1131         {
1132           model->idle_clear_source = g_idle_source_new ();
1133           g_source_set_priority (model->idle_clear_source, G_PRIORITY_HIGH);
1134           g_source_set_closure (model->idle_clear_source,
1135                                 g_cclosure_new_object (G_CALLBACK (idle_clear_callback),
1136                                                        G_OBJECT (model)));
1137           g_source_attach (model->idle_clear_source, NULL);
1138         }
1139
1140       model->idle_clears = g_slist_prepend (model->idle_clears, node);
1141       node->idle_clear = TRUE;
1142     }
1143 }
1144
1145 static void
1146 file_model_node_idle_clear_cancel (FileModelNode *node)
1147 {
1148   if (node->idle_clear)
1149     {
1150       GtkFileSystemModel *model = node->model;
1151
1152       model->idle_clears = g_slist_remove (model->idle_clears, node);
1153       if (!model->idle_clears)
1154         {
1155           g_source_destroy (model->idle_clear_source);
1156           model->idle_clear_source = NULL;
1157         }
1158       
1159       node->idle_clear = FALSE;
1160     }
1161 }
1162
1163 static void
1164 file_model_node_unref (GtkFileSystemModel *model,
1165                        FileModelNode       *node)
1166 {
1167   node->ref_count--;
1168   if (node->ref_count == 0)
1169     {
1170       file_model_node_clear (model, node);
1171       if (node->parent)
1172         file_model_node_child_unref (node->parent);
1173     }
1174 }
1175
1176 static void
1177 file_model_node_child_unref (FileModelNode *parent)
1178 {
1179   parent->n_referenced_children--;
1180   if (parent->n_referenced_children == 0)
1181     file_model_node_idle_clear (parent);
1182 }
1183
1184 static FileModelNode *
1185 file_model_node_get_children (GtkFileSystemModel *model,
1186                               FileModelNode      *node)
1187 {
1188   if (node->ref_count == 0)
1189     return NULL;
1190
1191   if (!node->loaded)
1192     {
1193       const GtkFileInfo *info = file_model_node_get_info (model, node);
1194       gboolean has_children = FALSE;
1195       gboolean is_folder = node->depth < model->max_depth && gtk_file_info_get_is_folder (info);
1196
1197       file_model_node_idle_clear_cancel (node);
1198
1199       if (is_folder)
1200         node->folder = gtk_file_system_get_folder (model->file_system,
1201                                                    node->path,
1202                                                    model->types,
1203                                                    NULL);       /* NULL-GError */
1204
1205       if (node->folder)
1206         {
1207           GSList *child_paths, *tmp_list;
1208           
1209           if (gtk_file_folder_list_children (node->folder, &child_paths, NULL)) /* NULL-GError */
1210             {
1211               child_paths = gtk_file_paths_sort (child_paths);
1212
1213               for (tmp_list = child_paths; tmp_list; tmp_list = tmp_list->next)
1214                 {
1215                   FileModelNode *child_node = file_model_node_new (model, tmp_list->data);
1216                   gtk_file_path_free (tmp_list->data);
1217                   child_node->next = node->children;
1218                   child_node->parent = node;
1219                   child_node->depth = node->depth + 1;
1220                   child_node->is_visible = file_model_node_is_visible (model, child_node);
1221                   if (child_node->is_visible)
1222                     has_children = TRUE;
1223                   node->children = child_node;
1224                 }
1225               g_slist_free (child_paths);
1226             }
1227
1228           node->children = (FileModelNode *)g_slist_reverse ((GSList *)node->children);
1229
1230           g_signal_connect (node->folder, "deleted",
1231                             G_CALLBACK (deleted_callback), node);
1232           g_signal_connect (node->folder, "files-added",
1233                             G_CALLBACK (files_added_callback), node);
1234           g_signal_connect (node->folder, "files-changed",
1235                             G_CALLBACK (files_changed_callback), node);
1236           g_signal_connect (node->folder, "files-removed",
1237                             G_CALLBACK (files_removed_callback), node);
1238
1239           g_object_set_data (G_OBJECT (node->folder), "model-node", node);
1240         }
1241       
1242       if (is_folder && !has_children)
1243         {
1244           /* The hard case ... we claimed this folder had children, but actually
1245            * it didn't. We have to add a dummy child, possibly to remove later.
1246            */
1247           FileModelNode *child_node = file_model_node_new (model, NULL);
1248           child_node->is_visible = TRUE;
1249           child_node->parent = node;
1250           child_node->is_dummy = TRUE;
1251
1252           node->children = child_node;
1253           node->has_dummy = TRUE;
1254         }
1255
1256       node->loaded = TRUE;
1257     }
1258
1259   return node->children;
1260 }
1261
1262 static void
1263 do_files_added (GtkFileSystemModel *model,
1264                 FileModelNode      *parent_node,
1265                 GSList             *paths)
1266 {
1267   GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1268   FileModelNode *children;
1269   FileModelNode *prev = NULL;
1270   GtkTreeIter iter;
1271   GtkTreePath *path;
1272   GSList *sorted_paths;
1273   GSList *tmp_list;
1274
1275   sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1276   
1277   if (parent_node)
1278     {
1279       iter.user_data = parent_node;
1280       path = gtk_tree_model_get_path (tree_model, &iter);
1281       children = parent_node->children;
1282     }
1283   else
1284     {
1285       path = gtk_tree_path_new ();
1286       children = model->roots;
1287     }
1288
1289   gtk_tree_path_down (path);
1290   
1291   if (parent_node && parent_node->has_dummy)
1292     {
1293       prev = children;
1294       children = children->next;
1295       gtk_tree_path_next (path);
1296     }
1297
1298   for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1299     {
1300       const GtkFilePath *file_path = tmp_list->data;
1301       
1302       while (children &&
1303              (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1304         {
1305           prev = children;
1306           if (children->is_visible)
1307             gtk_tree_path_next (path);
1308           
1309           children = children->next;
1310         }
1311   
1312       if (children &&
1313           children->path && gtk_file_path_compare (children->path, file_path) == 0)
1314         {
1315           /* Shouldn't happen */
1316         }
1317       else
1318         {
1319           FileModelNode *new;
1320           
1321           new = file_model_node_new (model, file_path);
1322           
1323           if (children)
1324             new->next = children;
1325           if (prev)
1326             prev->next = new;
1327           else if (parent_node)
1328             parent_node->children = new;
1329           else
1330             model->roots = new;
1331
1332           prev = new;
1333           
1334           if (parent_node)
1335             {
1336               new->parent = parent_node;
1337               new->depth = parent_node->depth + 1;
1338             }
1339           
1340           new->is_visible = file_model_node_is_visible (model, new);
1341           
1342           if (new->is_visible)
1343             {
1344               iter.user_data = new;
1345               path = gtk_tree_model_get_path (tree_model, &iter);
1346               gtk_tree_model_row_inserted (tree_model, path, &iter);
1347               
1348               if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1349                 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1350               
1351               if (parent_node && parent_node->has_dummy)
1352                 {
1353                   FileModelNode *dummy = parent_node->children;
1354                   GtkTreePath *dummy_path;
1355                   
1356                   parent_node->children = parent_node->children->next;
1357                   parent_node->has_dummy = FALSE;
1358
1359                   dummy_path = gtk_tree_path_copy (path);
1360                   gtk_tree_path_up (dummy_path);
1361                   gtk_tree_path_down (dummy_path);
1362                   
1363                   gtk_tree_model_row_deleted (tree_model, dummy_path);
1364                   gtk_tree_path_free (dummy_path);
1365
1366                   if (dummy->ref_count)
1367                     file_model_node_child_unref (parent_node);
1368                   file_model_node_free (dummy);
1369                 }
1370               
1371               gtk_tree_path_next (path);
1372             }
1373         }
1374     }
1375
1376   gtk_tree_path_free (path);
1377   g_slist_free (sorted_paths);
1378 }
1379
1380 static void
1381 do_files_changed (GtkFileSystemModel *model,
1382                   FileModelNode      *parent_node,
1383                   GSList             *paths)
1384 {
1385   GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1386   FileModelNode *children;
1387   FileModelNode *prev = NULL;
1388   GtkTreeIter iter;
1389   GtkTreePath *path;
1390   GSList *sorted_paths;
1391   GSList *tmp_list;
1392
1393   sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1394   
1395   if (parent_node)
1396     {
1397       iter.user_data = parent_node;
1398       path = gtk_tree_model_get_path (tree_model, &iter);
1399       children = parent_node->children;
1400     }
1401   else
1402     {
1403       path = gtk_tree_path_new ();
1404       children = model->roots;
1405     }
1406
1407   gtk_tree_path_down (path);
1408   
1409   if (parent_node && parent_node->has_dummy)
1410     {
1411       prev = children;
1412       children = children->next;
1413       gtk_tree_path_next (path);
1414     }
1415
1416   for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1417     {
1418       const GtkFilePath *file_path = tmp_list->data;
1419       
1420       while (children &&
1421              (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1422         {
1423           prev = children;
1424           if (children->is_visible)
1425             gtk_tree_path_next (path);
1426           
1427           children = children->next;
1428         }
1429   
1430       if (children &&
1431           children->path && gtk_file_path_compare (children->path, file_path) == 0)
1432         {
1433           gtk_tree_model_row_changed (tree_model, path, &iter);
1434         }
1435       else
1436         {
1437           /* Shouldn't happen */
1438         }
1439     }
1440
1441   gtk_tree_path_free (path);
1442   g_slist_free (sorted_paths);
1443 }
1444
1445 static void
1446 do_files_removed (GtkFileSystemModel *model,
1447                   FileModelNode      *parent_node,
1448                   GSList             *paths)
1449 {
1450   GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1451   FileModelNode *children;
1452   FileModelNode *prev = NULL;
1453   GtkTreeIter iter;
1454   GtkTreePath *path;
1455   GSList *sorted_paths;
1456   GSList *tmp_list;
1457   FileModelNode *tmp_child;
1458   gint n_visible;
1459
1460   sorted_paths = gtk_file_paths_sort (g_slist_copy (paths));
1461   
1462   if (parent_node)
1463     {
1464       iter.user_data = parent_node;
1465       path = gtk_tree_model_get_path (tree_model, &iter);
1466       children = parent_node->children;
1467     }
1468   else
1469     {
1470       path = gtk_tree_path_new ();
1471       children = model->roots;
1472     }
1473
1474   /* Count the number of currently visible children, so that
1475    * can catch when we need to insert a dummy node.
1476    */
1477   n_visible = 0;
1478   for (tmp_child = children; tmp_child; tmp_child = tmp_child->next)
1479     {
1480       if (tmp_child->is_visible)
1481         n_visible++;
1482     }
1483
1484   gtk_tree_path_down (path);
1485   
1486   if (parent_node && parent_node->has_dummy)
1487     {
1488       prev = children;
1489       children = children->next;
1490       gtk_tree_path_next (path);
1491     }
1492
1493   for (tmp_list = sorted_paths; tmp_list; tmp_list = tmp_list->next)
1494     {
1495       const GtkFilePath *file_path = tmp_list->data;
1496       
1497       while (children &&
1498              (!children->path || gtk_file_path_compare (children->path, file_path) < 0))
1499         {
1500           prev = children;
1501           if (children->is_visible)
1502             gtk_tree_path_next (path);
1503           
1504           children = children->next;
1505         }
1506   
1507       if (children &&
1508           children->path && gtk_file_path_compare (children->path, file_path) == 0)
1509         {
1510           FileModelNode *next = children->next;
1511
1512           if (children->is_visible)
1513             n_visible--;
1514           
1515           if (n_visible == 0)
1516             {
1517               FileModelNode *dummy = file_model_node_new (model, NULL);
1518               dummy->is_visible = TRUE;
1519               dummy->parent = parent_node;
1520               dummy->is_dummy = TRUE;
1521
1522               parent_node->children = dummy;
1523               parent_node->has_dummy = TRUE;
1524
1525               iter.user_data = dummy;
1526               gtk_tree_model_row_inserted (tree_model, path, &iter);
1527               gtk_tree_path_next (path);
1528
1529               prev = dummy;
1530             }
1531           
1532           if (prev)
1533             prev->next = next;
1534           else if (parent_node)
1535             parent_node->children = next;
1536           else
1537             model->roots = next;
1538
1539           if (parent_node && children->ref_count)
1540             file_model_node_child_unref (parent_node);
1541               
1542           if (children->is_visible)
1543             gtk_tree_model_row_deleted (tree_model, path);
1544
1545           file_model_node_free (children);
1546
1547           children = next;
1548         }
1549       else
1550         {
1551           /* Shouldn't happen */
1552         }
1553     }
1554
1555   gtk_tree_path_free (path);
1556   g_slist_free (sorted_paths);
1557 }
1558
1559 static void
1560 roots_changed_callback (GtkFileSystem      *file_system,
1561                         GtkFileSystemModel *model)
1562 {
1563   GtkTreeModel *tree_model = GTK_TREE_MODEL (model);
1564   GSList *new_roots;
1565   GSList *tmp_list;
1566   FileModelNode *children;
1567   FileModelNode *prev = NULL;
1568   GtkTreePath *path;
1569       
1570   new_roots = gtk_file_system_list_roots (file_system);
1571   new_roots = gtk_file_paths_sort (new_roots);
1572
1573   children = model->roots;
1574   tmp_list = new_roots;
1575   path = gtk_tree_path_new ();
1576   gtk_tree_path_down (path);
1577
1578   while (children || tmp_list)
1579     {
1580       FileModelNode *next = NULL;
1581       int cmp;
1582
1583       if (tmp_list && children)
1584         cmp = gtk_file_path_compare (children->path, tmp_list->data);
1585       else if (children)
1586         cmp = -1;
1587       else
1588         cmp = 1;
1589
1590       if (cmp < 0)
1591         {
1592           next = children->next;
1593           
1594           if (prev)
1595             prev->next = children->next;
1596           else
1597             model->roots = children->next;
1598
1599           if (children->is_visible)
1600             gtk_tree_model_row_deleted (tree_model, path);
1601
1602           file_model_node_free (children);
1603         }
1604       else if (cmp == 0)
1605         {
1606           /* Already there
1607            */
1608           next = children->next;
1609           prev = children;
1610           if (children->is_visible)
1611             gtk_tree_path_next (path);
1612         }
1613       else 
1614         {
1615           GtkTreeIter iter;
1616           FileModelNode *node = file_model_node_new (model, tmp_list->data);
1617           node->is_visible = file_model_node_is_visible (model, node);
1618           node->next = children;
1619           node->depth = 0;
1620
1621           if (prev)
1622             prev->next = node;
1623           else
1624             model->roots = node;
1625
1626           if (node->is_visible)
1627             {
1628               iter.user_data = node;
1629               gtk_tree_model_row_inserted (tree_model, path, &iter);
1630
1631               if (gtk_file_system_model_iter_has_child (tree_model, &iter))
1632                 gtk_tree_model_row_has_child_toggled (tree_model, path, &iter);
1633               
1634               gtk_tree_path_next (path);
1635             }
1636           
1637           prev = node;
1638         }
1639
1640       if (cmp <= 0)
1641         {
1642           children = next;
1643         }
1644
1645       if (cmp >= 0)
1646         {
1647           gtk_file_path_free (tmp_list->data);
1648           tmp_list = tmp_list->next;
1649         }
1650     }
1651   
1652   g_slist_free (new_roots);
1653   gtk_tree_path_free (path);
1654 }
1655
1656 static void
1657 deleted_callback (GtkFileFolder      *folder,
1658                   FileModelNode      *node)
1659 {
1660 }
1661
1662 static void
1663 files_added_callback (GtkFileFolder      *folder,
1664                       GSList             *paths,
1665                       FileModelNode      *node)
1666 {
1667   do_files_added (node->model, node, paths);
1668 }
1669
1670 static void
1671 files_changed_callback (GtkFileFolder      *folder,
1672                         GSList             *paths,
1673                         FileModelNode      *node)
1674 {
1675   do_files_changed (node->model, node, paths);
1676 }
1677
1678 static void
1679 files_removed_callback (GtkFileFolder      *folder,
1680                         GSList             *paths,
1681                         FileModelNode      *node)
1682 {
1683   do_files_removed (node->model, node, paths);
1684 }
1685
1686 static void
1687 root_deleted_callback (GtkFileFolder      *folder,
1688                        GtkFileSystemModel *model)
1689 {
1690 }
1691
1692 static void
1693 root_files_added_callback (GtkFileFolder      *folder,
1694                            GSList             *paths,
1695                            GtkFileSystemModel *model)
1696 {
1697   do_files_added (model, NULL, paths);
1698 }
1699
1700 static void
1701 root_files_changed_callback (GtkFileFolder      *folder,
1702                              GSList             *paths,
1703                              GtkFileSystemModel *model)
1704 {
1705   do_files_changed (model, NULL, paths);
1706 }
1707
1708 static void
1709 root_files_removed_callback (GtkFileFolder      *folder,
1710                              GSList             *paths,
1711                              GtkFileSystemModel *model)
1712 {
1713   do_files_removed (model, NULL, paths);
1714 }