[PATCH] Add tree functionality to list view



Hi

I've created a draft implementation of a tree view[1], as I thought it's
easier to decide whether it's useful if there is a working
implementation to play with.

I've added auto-expand for dnd which works with the sidebar tree view,
too. This patch may solve some of the problems some users have with
spatial nautilus.

There are probably still some rough edges needing cleanup but it doesn't
work too bad so far. Besides that, expansion state saving and loading
have yet to be added for spatial windows.

Any comments?

Regards,

Jürg

[1] http://mail.gnome.org/archives/nautilus-list/2004-April/msg00125.html
-- 
Juerg Billeter <j bitron ch>
Index: libnautilus-private/nautilus-tree-view-drag-dest.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-tree-view-drag-dest.c,v
retrieving revision 1.7
diff -p -u -r1.7 nautilus-tree-view-drag-dest.c
--- libnautilus-private/nautilus-tree-view-drag-dest.c	2 Jun 2005 16:16:55 -0000	1.7
+++ libnautilus-private/nautilus-tree-view-drag-dest.c	14 Jun 2005 08:53:01 -0000
@@ -54,6 +54,7 @@ struct _NautilusTreeViewDragDestDetails 
 
 	guint highlight_id;
 	guint scroll_id;
+	guint expand_id;
 };
 
 enum {
@@ -133,6 +134,29 @@ remove_scroll_timeout (NautilusTreeViewD
 	}
 }
 
+static int
+expand_timeout (gpointer data)
+{
+	GtkTreeView *tree_view;
+	GtkTreePath *drop_path;
+	
+	tree_view = GTK_TREE_VIEW (data);
+	
+	gtk_tree_view_get_drag_dest_row (tree_view, &drop_path, NULL);
+	gtk_tree_view_expand_row (tree_view, drop_path, FALSE);
+
+	return FALSE;
+}
+
+static void
+remove_expand_timeout (NautilusTreeViewDragDest *dest)
+{
+	if (dest->details->expand_id) {
+		g_source_remove (dest->details->expand_id);
+		dest->details->expand_id = 0;
+	}
+}
+
 static gboolean
 highlight_expose (GtkWidget *widget,
 		  GdkEventExpose *event,
@@ -369,7 +393,9 @@ drag_motion_callback (GtkWidget *widget,
 {
 	NautilusTreeViewDragDest *dest;
 	GtkTreePath *path;
-	GtkTreePath *drop_path;
+	GtkTreePath *drop_path, *old_drop_path;
+	GtkTreeModel *model;
+	GtkTreeIter drop_iter;
 	GtkTreeViewDropPosition pos;
 	guint action;
 
@@ -386,10 +412,27 @@ drag_motion_callback (GtkWidget *widget,
 	
 	action = get_drop_action (dest, context, drop_path);
 	
+	gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (widget), &old_drop_path,
+					 NULL);
+	
 	if (action) {
 		set_drag_dest_row (dest, drop_path);
+		model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+		if (drop_path == NULL || (old_drop_path != NULL &&
+		    gtk_tree_path_compare (old_drop_path, drop_path) != 0)) {
+			remove_expand_timeout (dest);
+		}
+		if (dest->details->expand_id == 0 && drop_path != NULL) {
+			gtk_tree_model_get_iter (model, &drop_iter, drop_path);
+			if (gtk_tree_model_iter_has_child (model, &drop_iter)) {
+				dest->details->expand_id = g_timeout_add (500,
+						expand_timeout,
+						dest->details->tree_view);
+			}
+		}
 	} else {
 		clear_drag_dest_row (dest);
+		remove_expand_timeout (dest);
 	}
 	
 	if (path) {
@@ -427,6 +470,7 @@ drag_leave_callback (GtkWidget *widget,
 	free_drag_data (dest);
 
 	remove_scroll_timeout (dest);
+	remove_expand_timeout (dest);
 }
 
 static void
@@ -612,6 +656,7 @@ drag_drop_callback (GtkWidget *widget,
 
 	get_drag_data (dest, context, time);
 	remove_scroll_timeout (dest);
+	remove_expand_timeout (dest);
 	clear_drag_dest_row (dest);
 	
 	return TRUE;
@@ -626,6 +671,7 @@ tree_view_weak_notify (gpointer user_dat
 	dest = NAUTILUS_TREE_VIEW_DRAG_DEST (user_data);
 	
 	remove_scroll_timeout (dest);
+	remove_expand_timeout (dest);
 
 	dest->details->tree_view = NULL;
 }
@@ -644,6 +690,7 @@ nautilus_tree_view_drag_dest_dispose (GO
 	}
 	
 	remove_scroll_timeout (dest);
+	remove_expand_timeout (dest);
 
 	EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
 }
Index: src/file-manager/fm-directory-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.c,v
retrieving revision 1.688
diff -p -u -r1.688 fm-directory-view.c
--- src/file-manager/fm-directory-view.c	11 Jun 2005 18:27:17 -0000	1.688
+++ src/file-manager/fm-directory-view.c	14 Jun 2005 08:53:02 -0000
@@ -249,6 +249,8 @@ struct FMDirectoryViewDetails
 	NautilusFile *file_monitored_for_open_with;
 	GtkActionGroup *open_with_action_group;
 	guint open_with_merge_id;
+
+	GList *sub_directory_list;
 };
 
 typedef enum {
@@ -2080,6 +2082,7 @@ done_loading (FMDirectoryView *view)
 	view->details->loading = FALSE;
 }
 
+
 typedef struct {
 	GHashTable *debuting_uris;
 	GList	   *added_files;
@@ -2276,7 +2279,19 @@ copy_move_done_callback (GHashTable *deb
 static gboolean
 real_file_still_belongs (FMDirectoryView *view, NautilusFile *file)
 {
-	return nautilus_directory_contains_file (view->details->model, file);
+	gboolean result;
+	GList *node;
+	NautilusDirectory *directory;
+	
+	result = nautilus_directory_contains_file (view->details->model, file);
+
+	for (node = view->details->sub_directory_list; !result && node != NULL;
+	     node = node->next) {
+		directory = NAUTILUS_DIRECTORY (node->data);
+		result |= nautilus_directory_contains_file (directory, file);
+	}
+	
+	return result;
 }
 
 static gboolean
@@ -2739,6 +2754,88 @@ fm_directory_view_queue_file_change (FMD
 	queue_pending_files (view, &singleton_list, &view->details->new_changed_files);
 }
 
+void
+fm_directory_view_add_sub_directory (FMDirectoryView  *view,
+				     NautilusDirectory*directory)
+{
+	NautilusFileAttributes attributes;
+
+	if (g_list_find (view->details->sub_directory_list, directory) == NULL) {
+		nautilus_directory_ref (directory);
+
+		attributes = nautilus_icon_factory_get_required_file_attributes ();
+		attributes |= NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
+			NAUTILUS_FILE_ATTRIBUTE_METADATA |
+			NAUTILUS_FILE_ATTRIBUTE_MIME_TYPE |
+			NAUTILUS_FILE_ATTRIBUTE_DISPLAY_NAME |
+			NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO;
+
+		nautilus_directory_file_monitor_add (directory,
+						     &view->details->model,
+						     view->details->show_hidden_files,
+						     view->details->show_backup_files,
+						     attributes,
+						     files_added_callback, view);
+
+	    	g_signal_connect
+			(directory, "files_added",
+			 G_CALLBACK (files_added_callback), view);
+		g_signal_connect
+			(directory, "files_changed",
+			 G_CALLBACK (files_changed_callback), view);
+ 
+		view->details->sub_directory_list = g_list_append (
+				view->details->sub_directory_list, directory);
+	}
+}
+
+static void
+real_remove_sub_directory (FMDirectoryView  *view,
+			   NautilusDirectory*directory)
+{
+	view->details->sub_directory_list = g_list_remove (
+				view->details->sub_directory_list, directory);
+
+	g_signal_handlers_disconnect_by_func (directory,
+					      G_CALLBACK (files_added_callback),
+					      view);
+	g_signal_handlers_disconnect_by_func (directory,
+					      G_CALLBACK (files_changed_callback),
+					      view);
+
+	nautilus_directory_file_monitor_remove (directory, &view->details->model);
+
+	nautilus_directory_unref (directory);
+}
+
+void
+fm_directory_view_remove_sub_directory (FMDirectoryView  *view,
+					NautilusDirectory*directory)
+{
+	GList *node;
+	NautilusFile *parent, *file1, *file2;
+	NautilusDirectory *subdir;
+	
+	parent = nautilus_directory_get_corresponding_file (directory);
+	
+	for (node = view->details->sub_directory_list; node != NULL;) {
+		file1 = nautilus_directory_get_corresponding_file (node->data);
+		while (file1 != parent && file1 != NULL) {
+			file2 = nautilus_file_get_parent (file1);
+			nautilus_file_unref (file1);
+			file1 = file2;
+		}
+		subdir = NAUTILUS_DIRECTORY (node->data);
+		node = node->next;
+		if (file1 == parent) {
+			real_remove_sub_directory (view, subdir);
+		}
+		if (file1 != NULL) {
+			nautilus_file_unref (file1);
+		}
+	}
+}
+
 /**
  * fm_directory_view_clear:
  *
@@ -6881,19 +6979,21 @@ fm_directory_view_notify_selection_chang
 		if (eel_g_list_exactly_one_item (selection)) {
 			file = NAUTILUS_FILE (selection->data);
 			
-			if (nautilus_file_needs_slow_mime_type (file)) {
-				nautilus_file_call_when_ready
-					(file,
-					 NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE,
-					 NULL,
+			if (file != NULL) {
+				if (nautilus_file_needs_slow_mime_type (file)) {
+					nautilus_file_call_when_ready
+						(file,
+						 NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE,
+						 NULL,
+						 NULL);
+				}
+
+				nautilus_file_call_when_ready 
+					(file, 
+					 NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI,
+					 NULL, 
 					 NULL);
 			}
-
-			nautilus_file_call_when_ready 
-				(file, 
-				 NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI,
-				 NULL, 
-				 NULL);
 		}
 
 		nautilus_file_list_free (selection);
@@ -7369,6 +7469,11 @@ load_directory (FMDirectoryView *view,
 	 * of old selection.
 	 */
 	schedule_update_menus (view);
+	
+	while (view->details->sub_directory_list != NULL) {
+		real_remove_sub_directory (view,
+				view->details->sub_directory_list->data);
+	}
 
 	disconnect_model_handlers (view);
 
Index: src/file-manager/fm-directory-view.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.h,v
retrieving revision 1.138
diff -p -u -r1.138 fm-directory-view.h
--- src/file-manager/fm-directory-view.h	2 Jun 2005 10:48:55 -0000	1.138
+++ src/file-manager/fm-directory-view.h	14 Jun 2005 08:53:02 -0000
@@ -392,5 +392,9 @@ void                fm_directory_view_ha
 									int               y);
 void                fm_directory_view_freeze_updates                   (FMDirectoryView  *view);
 void                fm_directory_view_unfreeze_updates                 (FMDirectoryView  *view);
+void                fm_directory_view_add_sub_directory                (FMDirectoryView  *view,
+									NautilusDirectory*directory);
+void                fm_directory_view_remove_sub_directory             (FMDirectoryView  *view,
+									NautilusDirectory*directory);
 
 #endif /* FM_DIRECTORY_VIEW_H */
Index: src/file-manager/fm-list-model.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-list-model.c,v
retrieving revision 1.35
diff -p -u -r1.35 fm-list-model.c
--- src/file-manager/fm-list-model.c	2 Jun 2005 16:16:55 -0000	1.35
+++ src/file-manager/fm-list-model.c	14 Jun 2005 08:53:03 -0000
@@ -33,10 +33,15 @@
 #include <eel/eel-glib-extensions.h>
 #include <gtk/gtktreednd.h>
 #include <gtk/gtktreesortable.h>
+#include <libgnome/gnome-i18n.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
 #include <libnautilus-private/nautilus-dnd.h>
 #include <gsequence/gsequence.h>
 
+static int fm_list_model_file_entry_compare_func (gconstpointer a,
+				       gconstpointer b,
+				       gpointer      user_data);
+
 static int fm_list_model_compare_func (gconstpointer a,
 				       gconstpointer b,
 				       gpointer      user_data);
@@ -59,6 +64,8 @@ struct FMListModelDetails {
 	int drag_begin_y;
 
 	GPtrArray *columns;
+	
+	GList *sub_dirs_done;
 };
 
 typedef struct {
@@ -67,6 +74,13 @@ typedef struct {
 	GList *path_list;
 } DragDataGetInfo;
 
+typedef struct _FileEntry {
+	NautilusFile *file;
+	struct _FileEntry *parent;
+	GSequence *files;
+	GSequencePtr ptr;
+} FileEntry;
+
 static const GtkTargetEntry drag_types [] = {
 	{ NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
 	{ NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
@@ -76,10 +90,20 @@ static const GtkTargetEntry drag_types [
 
 static GtkTargetList *drag_target_list = NULL;
 
+static void
+file_entry_free (FileEntry *file_entry)
+{
+	nautilus_file_unref (file_entry->file);
+	if (file_entry->files != NULL) {
+		g_sequence_free (file_entry->files);
+	}
+	g_free (file_entry);
+}
+
 static guint
 fm_list_model_get_flags (GtkTreeModel *tree_model)
 {
-	return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+	return GTK_TREE_MODEL_ITERS_PERSIST;
 }
 
 static int
@@ -124,19 +148,27 @@ static gboolean
 fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
 {
 	FMListModel *model;
+	GSequence *files;
 	GSequencePtr ptr;
-	int i;
+	FileEntry *file_entry;
+	int i, d;
 	
 	model = (FMListModel *)tree_model;
+	ptr = NULL;
+	
+	files = model->details->files;
+	for (d = 0; d < gtk_tree_path_get_depth (path); d++) {
+		i = gtk_tree_path_get_indices (path)[d];
 
-	i = gtk_tree_path_get_indices (path)[0];
+		if (files == NULL || i >= g_sequence_get_length (files)) {
+			return FALSE;
+		}
 
-	if (i >= g_sequence_get_length (model->details->files)) {
-		return FALSE;
+		ptr = g_sequence_get_ptr_at_pos (files, i);
+		file_entry = g_sequence_ptr_get_data (ptr);
+		files = file_entry->files;
 	}
 
-	ptr = g_sequence_get_ptr_at_pos (model->details->files, i);
-
 	iter->stamp = model->details->stamp;
 	iter->user_data = ptr;
 
@@ -150,6 +182,9 @@ fm_list_model_get_path (GtkTreeModel *tr
 {
 	GtkTreePath *path;
 	FMListModel *model;
+	GSequencePtr ptr;
+	FileEntry *file_entry;
+
 
 	model = (FMListModel *)tree_model;
 	
@@ -161,7 +196,16 @@ fm_list_model_get_path (GtkTreeModel *tr
 	}
 	
 	path = gtk_tree_path_new ();
-	gtk_tree_path_append_index (path, g_sequence_ptr_get_position (iter->user_data));
+	ptr = iter->user_data;
+	while (ptr != NULL) {
+		gtk_tree_path_prepend_index (path, g_sequence_ptr_get_position (ptr));
+		file_entry = g_sequence_ptr_get_data (ptr);
+		if (file_entry->parent != NULL) {
+			ptr = file_entry->parent->ptr;
+		} else {
+			ptr = NULL;
+		}
+	}
 
 	return path;
 }
@@ -170,6 +214,7 @@ static void
 fm_list_model_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column, GValue *value)
 {
 	FMListModel *model;
+	FileEntry *file_entry;
 	NautilusFile *file;
 	char *str;
 	GdkPixbuf *icon;
@@ -185,7 +230,8 @@ fm_list_model_get_value (GtkTreeModel *t
 	g_return_if_fail (model->details->stamp == iter->stamp);
 	g_return_if_fail (!g_sequence_ptr_is_end (iter->user_data));
 
-	file = g_sequence_ptr_get_data (iter->user_data);
+	file_entry = g_sequence_ptr_get_data (iter->user_data);
+	file = file_entry->file;
 	
 	switch (column) {
 	case FM_LIST_MODEL_FILE_COLUMN:
@@ -202,36 +248,38 @@ fm_list_model_get_value (GtkTreeModel *t
 	case FM_LIST_MODEL_LARGEST_ICON_COLUMN:
 		g_value_init (value, GDK_TYPE_PIXBUF);
 
-		zoom_level = fm_list_model_get_zoom_level_from_column_id (column);
-		icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
-
-		modifier = NULL;
-		if (model->details->drag_view != NULL) {
-			GtkTreePath *path_a, *path_b;
-			
-			gtk_tree_view_get_drag_dest_row (model->details->drag_view,
-							 &path_a,
-							 NULL);
-			if (path_a != NULL) {
-				path_b = gtk_tree_model_get_path (tree_model, iter);
+		if (file != NULL) {
+			zoom_level = fm_list_model_get_zoom_level_from_column_id (column);
+			icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
 
-				if (gtk_tree_path_compare (path_a, path_b) == 0) {
-					modifier = "accept";
+			modifier = NULL;
+			if (model->details->drag_view != NULL) {
+				GtkTreePath *path_a, *path_b;
+				
+				gtk_tree_view_get_drag_dest_row (model->details->drag_view,
+								 &path_a,
+								 NULL);
+				if (path_a != NULL) {
+					path_b = gtk_tree_model_get_path (tree_model, iter);
+
+					if (gtk_tree_path_compare (path_a, path_b) == 0) {
+						modifier = "accept";
+					}
+						
+					gtk_tree_path_free (path_a);
+					gtk_tree_path_free (path_b);
 				}
-					
-				gtk_tree_path_free (path_a);
-				gtk_tree_path_free (path_b);
 			}
-		}
-		
-		if (nautilus_file_has_open_window (file)) {
-			modifier = "visiting";
-		}
-		
-		icon = nautilus_icon_factory_get_pixbuf_for_file_force_size (file, modifier, icon_size);
+			
+			if (nautilus_file_has_open_window (file)) {
+				modifier = "visiting";
+			}
+			
+			icon = nautilus_icon_factory_get_pixbuf_for_file_force_size (file, modifier, icon_size);
 
-		g_value_set_object (value, icon);
-		g_object_unref (icon);
+			g_value_set_object (value, icon);
+			g_object_unref (icon);
+		}
 		break;
 	case FM_LIST_MODEL_SMALLEST_EMBLEM_COLUMN:
 	case FM_LIST_MODEL_SMALLER_EMBLEM_COLUMN:
@@ -242,39 +290,41 @@ fm_list_model_get_value (GtkTreeModel *t
 	case FM_LIST_MODEL_LARGEST_EMBLEM_COLUMN:
 		g_value_init (value, GDK_TYPE_PIXBUF);
 
-		parent_file = nautilus_file_get_parent (file);
-		emblems_to_ignore = eel_string_list_new_from_string (NAUTILUS_FILE_EMBLEM_NAME_TRASH, TRUE);
-		if (parent_file) {
-			if (!nautilus_file_can_write (parent_file)) {
-				eel_string_list_prepend (emblems_to_ignore, NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE);
+		if (file != NULL) {
+			parent_file = nautilus_file_get_parent (file);
+			emblems_to_ignore = eel_string_list_new_from_string (NAUTILUS_FILE_EMBLEM_NAME_TRASH, TRUE);
+			if (parent_file) {
+				if (!nautilus_file_can_write (parent_file)) {
+					eel_string_list_prepend (emblems_to_ignore, NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE);
+				}
+				nautilus_file_unref (parent_file);
 			}
-			nautilus_file_unref (parent_file);
-		}
-		emblem_icons = nautilus_icon_factory_get_emblem_icons_for_file (file, emblems_to_ignore);
-		eel_string_list_free (emblems_to_ignore);
+			emblem_icons = nautilus_icon_factory_get_emblem_icons_for_file (file, emblems_to_ignore);
+			eel_string_list_free (emblems_to_ignore);
 
-		if (emblem_icons != NULL) {
-			zoom_level = fm_list_model_get_zoom_level_from_emblem_column_id (column);
-			icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
-			icon = nautilus_icon_factory_get_pixbuf_for_icon_force_size (
-				emblem_icons->data, NULL, icon_size,
-				NULL, NULL, FALSE, NULL);
-			eel_g_list_free_deep (emblem_icons);
-	
-			g_value_set_object (value, icon);
+			if (emblem_icons != NULL) {
+				zoom_level = fm_list_model_get_zoom_level_from_emblem_column_id (column);
+				icon_size = nautilus_get_icon_size_for_zoom_level (zoom_level);
+				icon = nautilus_icon_factory_get_pixbuf_for_icon_force_size (
+					emblem_icons->data, NULL, icon_size,
+					NULL, NULL, FALSE, NULL);
+				eel_g_list_free_deep (emblem_icons);
+		
+				g_value_set_object (value, icon);
 
-			if (icon != NULL) { 
-				g_object_unref (icon);
+				if (icon != NULL) { 
+					g_object_unref (icon);
+				}
 			}
 		}
 		break;
 	case FM_LIST_MODEL_FILE_NAME_IS_EDITABLE_COLUMN:
 		g_value_init (value, G_TYPE_BOOLEAN);
 		
-                g_value_set_boolean (value, nautilus_file_can_rename (file));
+                g_value_set_boolean (value, file != NULL && nautilus_file_can_rename (file));
                 break;
  	default:
-		if (column >= FM_LIST_MODEL_NUM_COLUMNS || column < FM_LIST_MODEL_NUM_COLUMNS + model->details->columns->len) {
+ 		if (column >= FM_LIST_MODEL_NUM_COLUMNS || column < FM_LIST_MODEL_NUM_COLUMNS + model->details->columns->len) {
 			NautilusColumn *nautilus_column;
 			char *attribute;
 			nautilus_column = model->details->columns->pdata[column - FM_LIST_MODEL_NUM_COLUMNS];
@@ -283,9 +333,13 @@ fm_list_model_get_value (GtkTreeModel *t
 			g_object_get (nautilus_column, 
 				      "attribute", &attribute, 
 				      NULL);
-			str = nautilus_file_get_string_attribute_with_default (file, 
+			if (file != NULL) {
+				str = nautilus_file_get_string_attribute_with_default (file, 
 									       attribute);
-			g_value_set_string_take_ownership (value, str);
+				g_value_set_string_take_ownership (value, str);
+			} else if (!strcmp (attribute, "name")) {
+				g_value_set_string (value, _("Loading..."));
+			}
 			g_free (attribute);
 		} else {
 			g_assert_not_reached ();
@@ -311,19 +365,26 @@ static gboolean
 fm_list_model_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
 {
 	FMListModel *model;
+	GSequence *files;
+	FileEntry *file_entry;
 
 	model = (FMListModel *)tree_model;
 	
-	if (parent != NULL) {
-		return FALSE;
+	if (parent == NULL) {
+		file_entry = NULL;
+		files = model->details->files;
+	} else {
+
+		file_entry = g_sequence_ptr_get_data (parent->user_data);
+		files = file_entry->files;
 	}
 
-	if (g_sequence_get_length (model->details->files) == 0) {
+	if (files == NULL || g_sequence_get_length (files) == 0) {
 		return FALSE;
 	}
-
+	
 	iter->stamp = model->details->stamp;
-	iter->user_data = g_sequence_get_begin_ptr (model->details->files);
+	iter->user_data = g_sequence_get_begin_ptr (files);
 
 	return TRUE;
 }
@@ -331,23 +392,34 @@ fm_list_model_iter_children (GtkTreeMode
 static gboolean
 fm_list_model_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
 {
-	return FALSE;
+	FileEntry *file_entry;
+	
+	if (iter == NULL) {
+		return !fm_list_model_is_empty (FM_LIST_MODEL (tree_model));
+	}
+
+	file_entry = g_sequence_ptr_get_data (iter->user_data);
+
+	return (file_entry->files != NULL && g_sequence_get_length (file_entry->files) > 0);
 }
 
 static int
 fm_list_model_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
 {
 	FMListModel *model;
+	GSequence *files;
+	FileEntry *file_entry;
 
 	model = (FMListModel *)tree_model;
 
 	if (iter == NULL) {
-		return g_sequence_get_length (model->details->files);
+		files = model->details->files;
+	} else {
+		file_entry = g_sequence_ptr_get_data (iter->user_data);
+		files = file_entry->files;
 	}
 
-	g_return_val_if_fail (model->details->stamp == iter->stamp, -1);
-
-	return 0;
+	return g_sequence_get_length (files);
 }
 
 static gboolean
@@ -355,14 +427,19 @@ fm_list_model_iter_nth_child (GtkTreeMod
 {
 	FMListModel *model;
 	GSequencePtr child;
+	GSequence *files;
+	FileEntry *file_entry;
 
 	model = (FMListModel *)tree_model;
 	
 	if (parent != NULL) {
-		return FALSE;
+		file_entry = g_sequence_ptr_get_data (parent->user_data);
+		files = file_entry->files;
+	} else {
+		files = model->details->files;
 	}
 
-	child = g_sequence_get_ptr_at_pos (model->details->files, n);
+	child = g_sequence_get_ptr_at_pos (files, n);
 
 	if (g_sequence_ptr_is_end (child)) {
 		return FALSE;
@@ -377,7 +454,21 @@ fm_list_model_iter_nth_child (GtkTreeMod
 static gboolean
 fm_list_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
 {
-	return FALSE;
+	FMListModel *model;
+	FileEntry *file_entry;
+	
+	model = (FMListModel *)tree_model;
+	
+	file_entry = g_sequence_ptr_get_data (child->user_data);
+	
+	if (file_entry->parent == NULL) {
+		return FALSE;
+	}
+
+	iter->stamp = model->details->stamp;
+	iter->user_data = file_entry->parent->ptr;
+	
+	return TRUE;
 }
 
 gboolean
@@ -392,7 +483,7 @@ fm_list_model_get_tree_iter_from_file (F
 	}
 
 	g_assert (!g_sequence_ptr_is_end (ptr));
-	g_assert (g_sequence_ptr_get_data (ptr) == file);
+	g_assert (((FileEntry *)g_sequence_ptr_get_data (ptr))->file == file);
 	
 	if (iter != NULL) {
 		iter->stamp = model->details->stamp;
@@ -403,6 +494,35 @@ fm_list_model_get_tree_iter_from_file (F
 }
 
 static int
+fm_list_model_file_entry_compare_func (gconstpointer a,
+			    gconstpointer b,
+			    gpointer      user_data)
+{
+	FileEntry *file_entry1;
+	FileEntry *file_entry2;
+	FMListModel *model;
+	int result;
+
+	model = (FMListModel *)user_data;
+
+	file_entry1 = (FileEntry *)a;
+	file_entry2 = (FileEntry *)b;
+	
+	if (file_entry1->file != NULL && file_entry2->file != NULL) {
+		result = nautilus_file_compare_for_sort_by_attribute (file_entry1->file, file_entry2->file,
+							      model->details->sort_attribute,
+							      model->details->sort_directories_first,
+							      (model->details->order == GTK_SORT_DESCENDING));
+	} else if (file_entry1->file == NULL) {
+		return -1;
+	} else {
+		return 1;
+	}
+
+	return result;
+}
+
+static int
 fm_list_model_compare_func (gconstpointer a,
 			    gconstpointer b,
 			    gpointer      user_data)
@@ -416,7 +536,7 @@ fm_list_model_compare_func (gconstpointe
 
 	file1 = (NautilusFile *)a;
 	file2 = (NautilusFile *)b;
-
+	
 	result = nautilus_file_compare_for_sort_by_attribute (file1, file2,
 							      model->details->sort_attribute,
 							      model->details->sort_directories_first,
@@ -426,16 +546,14 @@ fm_list_model_compare_func (gconstpointe
 }
 
 static void
-fm_list_model_sort (FMListModel *model)
+fm_list_model_sort_file_entries (FMListModel *model, GSequence *files, GtkTreePath *path)
 {
-	GSequence *files;
 	GSequencePtr *old_order;
-	GtkTreePath *path;
 	int *new_order;
 	int length;
 	int i;
+	FileEntry *file_entry;
 
-	files = model->details->files;
 	length = g_sequence_get_length (files);
 
 	if (length <= 1) {
@@ -446,12 +564,19 @@ fm_list_model_sort (FMListModel *model)
 	old_order = g_new (GSequencePtr, length);
 	for (i = 0; i < length; ++i) {
 		GSequencePtr ptr = g_sequence_get_ptr_at_pos (files, i);
+		
+		file_entry = g_sequence_ptr_get_data (ptr);
+		if (file_entry->files != NULL) {
+			gtk_tree_path_append_index (path, i);
+			fm_list_model_sort_file_entries (model, file_entry->files, path);
+			gtk_tree_path_up (path);
+		}
 
 		old_order[i] = ptr;
 	}
 
 	/* sort */
-	g_sequence_sort (files, fm_list_model_compare_func, model);
+	g_sequence_sort (files, fm_list_model_file_entry_compare_func, model);
 
 	/* generate new order */
 	new_order = g_new (int, length);
@@ -461,17 +586,27 @@ fm_list_model_sort (FMListModel *model)
 	}
 
 	/* Let the world know about our new order */
-	path = gtk_tree_path_new ();
 
 	g_assert (new_order != NULL);
 	gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
 				       path, NULL, new_order);
 
-	gtk_tree_path_free (path);
 	g_free (old_order);
 	g_free (new_order);
 }
 
+static void
+fm_list_model_sort (FMListModel *model)
+{
+	GtkTreePath *path;
+
+	path = gtk_tree_path_new ();
+
+	fm_list_model_sort_file_entries (model, model->details->files, path);
+
+	gtk_tree_path_free (path);
+}
+
 void
 fm_list_model_sort_files (FMListModel *model, GList **files)
 {
@@ -632,31 +767,89 @@ fm_list_model_multi_drag_data_delete (Eg
 	return TRUE;
 }
 
-void
+gboolean
 fm_list_model_add_file (FMListModel *model, NautilusFile *file)
 {
-	GtkTreeIter iter;
-	GtkTreePath *path;
-	GSequencePtr new_ptr;
+	GtkTreeIter iter, child_iter;
+	GtkTreePath *path, *child_path;
+	FileEntry *file_entry, *child_file_entry;
+	NautilusFile *parent_file;
+	GSequencePtr parent_ptr;
+	GSequence *files;
+	gboolean replace_dummy;
 	
 	/* We may only add each file once. */
 	if (fm_list_model_get_tree_iter_from_file (model, file, NULL)) {
-		return;
+		return FALSE;
 	}
 
 	nautilus_file_ref (file);
 	
-	new_ptr = g_sequence_insert_sorted (model->details->files, file,
-					    fm_list_model_compare_func, model);
+	file_entry = g_new0 (FileEntry, 1);
+	file_entry->file = file;
+	file_entry->parent = NULL;
+	file_entry->files = g_sequence_new ((GDestroyNotify)file_entry_free);
+	
+	files = model->details->files;
+	
+	replace_dummy = FALSE;
 
-	g_hash_table_insert (model->details->reverse_map, file, new_ptr);
+	parent_file = nautilus_file_get_parent (file);
+	if (parent_file != NULL) {
+		parent_ptr = g_hash_table_lookup (model->details->reverse_map,
+						  parent_file);
+		if (parent_ptr != NULL) {
+			file_entry->parent = g_sequence_ptr_get_data (parent_ptr);
+			files = file_entry->parent->files;
+			if (g_sequence_get_length (files) == 1) {
+				GSequencePtr dummy_ptr = g_sequence_get_ptr_at_pos (files, 0);
+				FileEntry *dummy_entry = g_sequence_ptr_get_data (dummy_ptr);
+				if (dummy_entry->file == NULL) {
+					/* replace the dummy loading entry */
+					iter.stamp = model->details->stamp;
+					iter.user_data = dummy_ptr;
+
+					g_sequence_remove (dummy_ptr);
+					
+					replace_dummy = TRUE;
+				}
+			}
+		}
+	}
+	
+	file_entry->ptr = g_sequence_insert_sorted (files, file_entry,
+					    fm_list_model_file_entry_compare_func, model);
+
+	g_hash_table_insert (model->details->reverse_map, file, file_entry->ptr);
 	
 	iter.stamp = model->details->stamp;
-	iter.user_data = new_ptr;
+	iter.user_data = file_entry->ptr;
 
 	path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
-	gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+	if (replace_dummy) {
+		gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+	} else {
+		gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+	}
+	if (nautilus_file_is_directory (file)) {
+	
+		child_file_entry = g_new0 (FileEntry, 1);
+		child_file_entry->parent = file_entry;
+		child_file_entry->ptr = g_sequence_insert_sorted (file_entry->files, child_file_entry,
+					    fm_list_model_file_entry_compare_func, model);
+		child_iter.stamp = model->details->stamp;
+		child_iter.user_data = child_file_entry->ptr;
+
+		child_path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &child_iter);
+		gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), child_path, &child_iter);
+		gtk_tree_path_free (child_path);
+
+		gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
+						      path, &iter);
+	}
 	gtk_tree_path_free (path);
+	
+	return TRUE;
 }
 
 void
@@ -671,7 +864,7 @@ fm_list_model_file_changed (FMListModel 
 		return;
 	}
 
-	g_sequence_ptr_sort_changed (ptr, fm_list_model_compare_func, model);
+	g_sequence_ptr_sort_changed (ptr, fm_list_model_file_entry_compare_func, model);
 
 	if (!fm_list_model_get_tree_iter_from_file (model, file, &iter)) {
 		return;
@@ -698,18 +891,45 @@ fm_list_model_get_length (FMListModel *m
 static void
 fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
 {
-	GSequencePtr ptr;
+	GSequencePtr ptr, child_ptr;
+	FileEntry *file_entry, *child_file_entry;
 	GtkTreePath *path;
+	GtkTreeIter parent_iter;
 
 	path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
 	ptr = iter->user_data;
+	file_entry = g_sequence_ptr_get_data (ptr);
+	
+	if (file_entry->files != NULL) {
+		while (g_sequence_get_length (file_entry->files) > 0) {
+			child_ptr = g_sequence_get_begin_ptr (file_entry->files);
+			child_file_entry = g_sequence_ptr_get_data (child_ptr);
+			if (child_file_entry->file != NULL) {
+				fm_list_model_remove_file (model, child_file_entry->file);
+			} else {
+				g_sequence_remove (child_ptr);
+			}
 
-	g_hash_table_remove (model->details->reverse_map, g_sequence_ptr_get_data (ptr));
+		}
+	}
+
+	g_hash_table_remove (model->details->reverse_map, file_entry->file);
+	file_entry = file_entry->parent;
 	g_sequence_remove (ptr);
 
 	model->details->stamp++;
-	
 	gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+	
+	if (file_entry != NULL) {
+		if (g_sequence_get_length (file_entry->files) == 0) {
+			gtk_tree_path_up (path);
+			parent_iter.stamp = model->details->stamp;
+			parent_iter.user_data = file_entry->ptr;
+			gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
+							      path, &parent_iter);
+		}
+	}
+	
 	gtk_tree_path_free (path);
 }
 
@@ -723,20 +943,33 @@ fm_list_model_remove_file (FMListModel *
 	}
 }
 
-void
-fm_list_model_clear (FMListModel *model)
+static void
+fm_list_model_clear_directory (FMListModel *model, GSequence *files)
 {
 	GtkTreeIter iter;
+	FileEntry *file_entry;
+	
+	while (g_sequence_get_length (files) > 0) {
+		iter.user_data = g_sequence_get_begin_ptr (files);
 
-	g_return_if_fail (model != NULL);
-
-	while (g_sequence_get_length (model->details->files) > 0) {
+		file_entry = g_sequence_ptr_get_data (iter.user_data);
+		if (file_entry->files != NULL) {
+			fm_list_model_clear_directory (model, file_entry->files);
+		}
+		
 		iter.stamp = model->details->stamp;
-		iter.user_data = g_sequence_get_begin_ptr (model->details->files);
 		fm_list_model_remove (model, &iter);
 	}
 }
 
+void
+fm_list_model_clear (FMListModel *model)
+{
+	g_return_if_fail (model != NULL);
+
+	fm_list_model_clear_directory (model, model->details->files);
+}
+
 NautilusFile *
 fm_list_model_file_for_path (FMListModel *model, GtkTreePath *path)
 {
@@ -1017,7 +1250,7 @@ static void
 fm_list_model_init (FMListModel *model)
 {
 	model->details = g_new0 (FMListModelDetails, 1);
-	model->details->files = g_sequence_new ((GDestroyNotify)nautilus_file_unref);
+	model->details->files = g_sequence_new ((GDestroyNotify)file_entry_free);
 	model->details->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 	model->details->stamp = g_random_int ();
 	model->details->sort_attribute = NULL;
@@ -1119,3 +1352,79 @@ fm_list_model_get_type (void)
 	
 	return object_type;
 }
+
+static gboolean
+sub_directory_done_loading_idle_callback (gpointer data)
+{
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	FileEntry *file_entry, *dummy_entry;
+	NautilusFile *parent_file;
+	GSequencePtr parent_ptr, dummy_ptr;
+	GSequence *files;
+	FMListModel *model;
+	
+	model = FM_LIST_MODEL (data);
+	
+	while (model->details->sub_dirs_done != NULL) {
+		parent_file = nautilus_directory_get_corresponding_file (model->details->sub_dirs_done->data);
+		model->details->sub_dirs_done = g_list_remove (
+					model->details->sub_dirs_done,
+					model->details->sub_dirs_done->data);
+		parent_ptr = g_hash_table_lookup (model->details->reverse_map,
+						  parent_file);
+		nautilus_file_unref (parent_file);
+		if (parent_ptr == NULL) {
+			continue;
+		}
+		
+		file_entry = g_sequence_ptr_get_data (parent_ptr);
+		files = file_entry->files;
+		if (g_sequence_get_length (files) == 0) {
+			continue;
+		}
+
+		dummy_ptr = g_sequence_get_ptr_at_pos (files, 0);
+		dummy_entry = g_sequence_ptr_get_data (dummy_ptr);
+		if (dummy_entry->file != NULL) {
+			/* real file */
+			continue;
+		}
+		
+		iter.stamp = model->details->stamp;
+		iter.user_data = dummy_ptr;
+
+		path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+
+		g_sequence_remove (dummy_ptr);
+		
+		model->details->stamp++;
+		gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+		
+		if (g_sequence_get_length (files) == 0) {
+			iter.stamp = model->details->stamp;
+			iter.user_data = parent_ptr;
+			gtk_tree_path_up (path);
+			gtk_tree_model_row_has_child_toggled (
+				GTK_TREE_MODEL (model),
+				path, &iter);
+			
+		}
+
+		gtk_tree_path_free (path);
+	}
+	
+	return FALSE;
+}
+
+void
+fm_list_model_sub_directory_done_loading (FMListModel *model, NautilusDirectory *directory)
+{
+	model->details->sub_dirs_done = g_list_append (model->details->sub_dirs_done, directory);
+	
+	/* We want lower priority than the idle that handles displaying pending
+	files to avoid collapsing a tree node just because the files haven't
+	been added yet. */
+	g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 20,
+			 sub_directory_done_loading_idle_callback, model, NULL);
+}
Index: src/file-manager/fm-list-model.h
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-list-model.h,v
retrieving revision 1.13
diff -p -u -r1.13 fm-list-model.h
--- src/file-manager/fm-list-model.h	2 Jun 2005 16:16:55 -0000	1.13
+++ src/file-manager/fm-list-model.h	14 Jun 2005 08:53:03 -0000
@@ -26,6 +26,7 @@
 #include <gtk/gtktreeview.h>
 #include <gdk/gdkdnd.h>
 #include <libnautilus-private/nautilus-file.h>
+#include <libnautilus-private/nautilus-directory.h>
 #include <libnautilus-private/nautilus-icon-factory.h>
 #include <libnautilus-extension/nautilus-column.h>
 
@@ -70,7 +71,7 @@ typedef struct {
 } FMListModelClass;
 
 GType    fm_list_model_get_type                          (void);
-void     fm_list_model_add_file                          (FMListModel          *model,
+gboolean fm_list_model_add_file                          (FMListModel          *model,
 							  NautilusFile         *file);
 void     fm_list_model_file_changed                      (FMListModel          *model,
 							  NautilusFile         *file);
@@ -115,4 +116,8 @@ int               fm_list_model_add_colu
 					    NautilusColumn *column);
 int               fm_list_model_get_column_number (FMListModel *model,
 						   const char *column_name);
+						   
+void              fm_list_model_sub_directory_done_loading (FMListModel       *model,
+							    NautilusDirectory *directory);
+						   
 #endif /* FM_LIST_MODEL_H */
Index: src/file-manager/fm-list-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-list-view.c,v
retrieving revision 1.245
diff -p -u -r1.245 fm-list-view.c
--- src/file-manager/fm-list-view.c	2 Jun 2005 16:16:55 -0000	1.245
+++ src/file-manager/fm-list-view.c	14 Jun 2005 08:53:03 -0000
@@ -430,8 +430,10 @@ motion_notify_callback (GtkWidget *widge
 				gtk_drag_set_icon_default (context);
 			}
 		}		      
+		return TRUE;
 	}
-	return TRUE;
+	
+	return FALSE;
 }
 
 static void
@@ -458,6 +460,8 @@ button_press_callback (GtkWidget *widget
 	static gint64 last_click_time = 0;
 	static int click_count = 0;
 	int double_click_time;
+	int expander_size, horizontal_separator;
+	NautilusFile *file;
 
 	view = FM_LIST_VIEW (callback_data);
 	tree_view = GTK_TREE_VIEW (widget);
@@ -543,12 +547,25 @@ button_press_callback (GtkWidget *widget
 				call_parent = FALSE;
 			} 
 			
+			file = fm_list_model_file_for_path (view->details->model, path);
+			if (file == NULL) {
+				/* this is the dummy loading node */
+				call_parent = FALSE;
+			} else {
+				nautilus_file_unref (file);
+			}
+
 			if ((event->button == 1 || event->button == 2) &&
 			    ((event->state & GDK_CONTROL_MASK) != 0 ||
 			     (event->state & GDK_SHIFT_MASK) == 0)) {
 				view->details->row_selected_on_button_down = gtk_tree_selection_path_is_selected (selection, path);
 				if (view->details->row_selected_on_button_down) {
-					call_parent = FALSE;
+					gtk_widget_style_get (widget,
+						"expander-size", &expander_size,
+						"horizontal-separator", &horizontal_separator,
+						NULL);
+					call_parent = (event->x <= horizontal_separator / 2 +
+						gtk_tree_path_get_depth (path) * expander_size);
 				} else if  ((event->state & GDK_CONTROL_MASK) != 0) {
 					call_parent = FALSE;
 					gtk_tree_selection_select_path (selection, path);
@@ -611,7 +628,7 @@ button_release_callback (GtkWidget *widg
 		stop_drag_check (view);
 		if (!view->details->drag_started) {
 			fm_list_view_did_not_drag (view, event);
-			return TRUE;
+			//return TRUE;
 		}
 	}
 	return FALSE;
@@ -739,6 +756,38 @@ popup_menu_callback (GtkWidget *widget, 
 	return TRUE;
 }
 
+static void
+sub_directory_done_loading_callback (NautilusDirectory *directory, FMListView *view)
+{
+	fm_list_model_sub_directory_done_loading (view->details->model, directory);
+}
+
+static void
+row_expanded_callback (GtkTreeView *treeview, GtkTreeIter *iter, GtkTreePath *path, gpointer callback_data)
+{
+ 	FMListView *view;
+ 	NautilusFile *file;
+ 	NautilusDirectory *directory;
+
+	view = FM_LIST_VIEW (callback_data);
+
+	file = fm_list_model_file_for_path (view->details->model, path);
+	directory = nautilus_directory_get_for_file (file);
+
+	fm_directory_view_add_sub_directory (FM_DIRECTORY_VIEW (view), directory);
+	
+	if (nautilus_directory_are_all_files_seen (directory)) {
+		fm_list_model_sub_directory_done_loading (view->details->model,
+							  directory);
+	} else {
+		g_signal_connect_object (directory, "done_loading",
+			G_CALLBACK (sub_directory_done_loading_callback),
+			view, 0);
+	}
+	
+	nautilus_directory_unref (directory);
+}
+
 static gboolean
 key_press_callback (GtkWidget *widget, GdkEventKey *event, gpointer callback_data)
 {
@@ -1069,6 +1118,8 @@ create_and_set_up_tree_view (FMListView 
 				 G_CALLBACK (key_press_callback), view, 0);
 	g_signal_connect_object (view->details->tree_view, "popup_menu",
                                  G_CALLBACK (popup_menu_callback), view, 0);
+	g_signal_connect_object (view->details->tree_view, "row_expanded",
+                                 G_CALLBACK (row_expanded_callback), view, 0);
 	
 	view->details->model = g_object_new (FM_TYPE_LIST_MODEL, NULL);
 	gtk_tree_view_set_model (view->details->tree_view, GTK_TREE_MODEL (view->details->model));
@@ -1180,7 +1231,15 @@ create_and_set_up_tree_view (FMListView 
 static void
 fm_list_view_add_file (FMDirectoryView *view, NautilusFile *file)
 {
-	fm_list_model_add_file (FM_LIST_VIEW (view)->details->model, file);
+	FMListModel *model;
+	
+	model = FM_LIST_VIEW (view)->details->model;
+	if (!fm_list_model_add_file (model, file)) {
+		fm_directory_view_remove_sub_directory (view,
+					nautilus_directory_get_for_file (file));
+		fm_list_model_remove_file (model, file);
+		fm_list_model_add_file (model, file);
+	}
 }
 
 static GList *
@@ -1374,8 +1433,10 @@ fm_list_view_get_selection_foreach_func 
 			    FM_LIST_MODEL_FILE_COLUMN, &file,
 			    -1);
 
-	nautilus_file_ref (file);
-	(* list) = g_list_prepend ((* list), file);
+	if (file != NULL) {
+		nautilus_file_ref (file);
+		(* list) = g_list_prepend ((* list), file);
+	}
 }
 
 static GList *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]