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