Re: [PATCH] Add tree functionality to list view
- From: Juerg Billeter <j bitron ch>
- To: Alexander Larsson <alexl redhat com>
- Cc: nautilus-list gnome org
- Subject: Re: [PATCH] Add tree functionality to list view
- Date: Tue, 14 Jun 2005 21:50:44 +0200
On Die, 2005-06-14 at 18:38 +0200, Jürg Billeter wrote:
> On Die, 2005-06-14 at 18:04 +0200, Alexander Larsson wrote:
> > Here are some more detailed review comments:
> > [...]
The attached patch should fix all mentioned issues except multiple
gtk_tree_model_rows_reordered calls and remove subdirectories on
row_collapsed as commented on in my previous reply.
Regards,
Jürg
--
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 19:43:53 -0000
@@ -54,6 +54,7 @@ struct _NautilusTreeViewDragDestDetails
guint highlight_id;
guint scroll_id;
+ guint expand_id;
};
enum {
@@ -133,6 +134,33 @@ 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);
+
+ if (drop_path) {
+ gtk_tree_view_expand_row (tree_view, drop_path, FALSE);
+ gtk_tree_path_free (drop_path);
+ }
+
+ 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 +397,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 +416,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) {
@@ -400,6 +447,10 @@ drag_motion_callback (GtkWidget *widget,
gtk_tree_path_free (drop_path);
}
+ if (old_drop_path) {
+ gtk_tree_path_free (old_drop_path);
+ }
+
if (dest->details->scroll_id == 0) {
dest->details->scroll_id =
g_timeout_add (150,
@@ -427,6 +478,7 @@ drag_leave_callback (GtkWidget *widget,
free_drag_data (dest);
remove_scroll_timeout (dest);
+ remove_expand_timeout (dest);
}
static void
@@ -612,6 +664,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 +679,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 +698,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 19:43:58 -0000
@@ -249,6 +249,8 @@ struct FMDirectoryViewDetails
NautilusFile *file_monitored_for_open_with;
GtkActionGroup *open_with_action_group;
guint open_with_merge_id;
+
+ GList *subdirectory_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,20 @@ 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);
+ GList *node;
+
+ if (nautilus_directory_contains_file (view->details->model, file)) {
+ return TRUE;
+ }
+
+ for (node = view->details->subdirectory_list; node != NULL; node = node->next) {
+ if (nautilus_directory_contains_file (NAUTILUS_DIRECTORY (node->data),
+ file)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
static gboolean
@@ -2739,6 +2755,88 @@ fm_directory_view_queue_file_change (FMD
queue_pending_files (view, &singleton_list, &view->details->new_changed_files);
}
+void
+fm_directory_view_add_subdirectory (FMDirectoryView *view,
+ NautilusDirectory*directory)
+{
+ NautilusFileAttributes attributes;
+
+ if (g_list_find (view->details->subdirectory_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->subdirectory_list = g_list_prepend (
+ view->details->subdirectory_list, directory);
+ }
+}
+
+static void
+real_remove_subdirectory (FMDirectoryView *view,
+ NautilusDirectory*directory)
+{
+ view->details->subdirectory_list = g_list_remove (
+ view->details->subdirectory_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_subdirectory (FMDirectoryView *view,
+ NautilusDirectory*directory)
+{
+ GList *node;
+ NautilusFile *parent, *file1, *file2;
+ NautilusDirectory *subdir;
+
+ parent = nautilus_directory_get_corresponding_file (directory);
+
+ for (node = view->details->subdirectory_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_subdirectory (view, subdir);
+ }
+ if (file1 != NULL) {
+ nautilus_file_unref (file1);
+ }
+ }
+}
+
/**
* fm_directory_view_clear:
*
@@ -7369,6 +7468,11 @@ load_directory (FMDirectoryView *view,
* of old selection.
*/
schedule_update_menus (view);
+
+ while (view->details->subdirectory_list != NULL) {
+ real_remove_subdirectory (view,
+ view->details->subdirectory_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 19:43:58 -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_subdirectory (FMDirectoryView *view,
+ NautilusDirectory*directory);
+void fm_directory_view_remove_subdirectory (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 19:43:59 -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);
@@ -67,6 +72,16 @@ typedef struct {
GList *path_list;
} DragDataGetInfo;
+typedef struct FileEntry FileEntry;
+
+struct FileEntry {
+ NautilusFile *file;
+ FileEntry *parent;
+ GSequence *files;
+ GSequencePtr ptr;
+ guint loaded : 1;
+};
+
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 +91,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 +149,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 +183,9 @@ fm_list_model_get_path (GtkTreeModel *tr
{
GtkTreePath *path;
FMListModel *model;
+ GSequencePtr ptr;
+ FileEntry *file_entry;
+
model = (FMListModel *)tree_model;
@@ -161,7 +197,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 +215,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 +231,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 +249,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 +291,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 +334,17 @@ 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")) {
+ if (file_entry->loaded) {
+ g_value_set_string (value, _("(Empty)"));
+ } else {
+ g_value_set_string (value, _("Loading..."));
+ }
+ }
g_free (attribute);
} else {
g_assert_not_reached ();
@@ -311,19 +370,24 @@ 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) {
+ 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 +395,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 +430,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 +457,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 +486,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 +497,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 +539,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 +549,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 +567,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 +589,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 +770,87 @@ 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);
+ nautilus_file_unref (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 */
+ 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 +865,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 +892,52 @@ 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 dummy_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 {
+ gtk_tree_path_append_index (path, 0);
+ g_sequence_remove (child_ptr);
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ gtk_tree_path_up (path);
+ }
- g_hash_table_remove (model->details->reverse_map, g_sequence_ptr_get_data (ptr));
- g_sequence_remove (ptr);
+ }
+ }
+
+ g_hash_table_remove (model->details->reverse_map, file_entry->file);
+
+ if (file_entry->parent && g_sequence_get_length (file_entry->parent->files) == 1) {
+ /* this is the last child, change it to a dummy node */
+ dummy_iter.stamp = model->details->stamp++;
+ dummy_iter.user_data = ptr;
+
+ nautilus_file_unref (file_entry->file);
+ file_entry->file = NULL;
+ file_entry->loaded = TRUE;
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path,
+ &dummy_iter);
+ } else {
+ g_sequence_remove (ptr);
- model->details->stamp++;
+ model->details->stamp++;
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+ }
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
gtk_tree_path_free (path);
}
@@ -723,20 +951,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 +1258,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 +1360,46 @@ fm_list_model_get_type (void)
return object_type;
}
+
+void
+fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *directory)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ FileEntry *file_entry, *dummy_entry;
+ NautilusFile *parent_file;
+ GSequencePtr parent_ptr, dummy_ptr;
+ GSequence *files;
+
+ parent_file = nautilus_directory_get_corresponding_file (directory);
+ parent_ptr = g_hash_table_lookup (model->details->reverse_map,
+ parent_file);
+ nautilus_file_unref (parent_file);
+ if (parent_ptr == NULL) {
+ return;
+ }
+
+ file_entry = g_sequence_ptr_get_data (parent_ptr);
+ files = file_entry->files;
+ if (g_sequence_get_length (files) == 0) {
+ return;
+ }
+
+ 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 */
+ return;
+ }
+
+ dummy_entry->loaded = 1;
+
+ iter.stamp = model->details->stamp;
+ iter.user_data = dummy_ptr;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
+
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+
+ gtk_tree_path_free (path);
+}
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 19:43:59 -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_subdirectory_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 19:44:01 -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
+subdirectory_done_loading_callback (NautilusDirectory *directory, FMListView *view)
+{
+ fm_list_model_subdirectory_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_subdirectory (FM_DIRECTORY_VIEW (view), directory);
+
+ if (nautilus_directory_are_all_files_seen (directory)) {
+ fm_list_model_subdirectory_done_loading (view->details->model,
+ directory);
+ } else {
+ g_signal_connect_object (directory, "done_loading",
+ G_CALLBACK (subdirectory_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_subdirectory (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]