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