summaryrefslogtreecommitdiff
path: root/src/file-manager/fm-list-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/file-manager/fm-list-model.c')
-rw-r--r--src/file-manager/fm-list-model.c381
1 files changed, 235 insertions, 146 deletions
diff --git a/src/file-manager/fm-list-model.c b/src/file-manager/fm-list-model.c
index e1f4a5e7c..eb1017213 100644
--- a/src/file-manager/fm-list-model.c
+++ b/src/file-manager/fm-list-model.c
@@ -52,15 +52,12 @@ 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);
-
static GObjectClass *parent_class;
struct FMListModelDetails {
GSequence *files;
- GHashTable *reverse_map; /* map from files to GSequencePtr's */
+ GHashTable *directory_reverse_map; /* map from directory to GSequencePtr's */
+ GHashTable *top_reverse_map; /* map from files in top dir to GSequencePtr's */
int stamp;
@@ -86,6 +83,7 @@ typedef struct FileEntry FileEntry;
struct FileEntry {
NautilusFile *file;
+ GHashTable *reverse_map; /* map from files to GSequencePtr's */
NautilusDirectory *subdirectory;
FileEntry *parent;
GSequence *files;
@@ -105,6 +103,10 @@ static void
file_entry_free (FileEntry *file_entry)
{
nautilus_file_unref (file_entry->file);
+ if (file_entry->reverse_map) {
+ g_hash_table_destroy (file_entry->reverse_map);
+ file_entry->reverse_map = NULL;
+ }
if (file_entry->subdirectory != NULL) {
nautilus_directory_unref (file_entry->subdirectory);
}
@@ -160,6 +162,16 @@ fm_list_model_get_column_type (GtkTreeModel *tree_model, int index)
}
}
+static void
+fm_list_model_ptr_to_iter (FMListModel *model, GSequencePtr ptr, GtkTreeIter *iter)
+{
+ g_assert (!g_sequence_ptr_is_end (ptr));
+ if (iter != NULL) {
+ iter->stamp = model->details->stamp;
+ iter->user_data = ptr;
+ }
+}
+
static gboolean
fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
{
@@ -185,10 +197,7 @@ fm_list_model_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath
files = file_entry->files;
}
- iter->stamp = model->details->stamp;
- iter->user_data = ptr;
-
- g_assert (!g_sequence_ptr_is_end (iter->user_data));
+ fm_list_model_ptr_to_iter (model, ptr, iter);
return TRUE;
}
@@ -494,24 +503,118 @@ fm_list_model_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeI
return TRUE;
}
-gboolean
-fm_list_model_get_tree_iter_from_file (FMListModel *model, NautilusFile *file, GtkTreeIter *iter)
+static GSequencePtr
+lookup_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
+{
+ FileEntry *file_entry;
+ GSequencePtr ptr, parent_ptr;
+
+ parent_ptr = NULL;
+ if (directory) {
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
+ }
+
+ if (parent_ptr) {
+ file_entry = g_sequence_ptr_get_data (parent_ptr);
+ ptr = g_hash_table_lookup (file_entry->reverse_map, file);
+ } else {
+ ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
+ }
+
+ if (ptr) {
+ g_assert (((FileEntry *)g_sequence_ptr_get_data (ptr))->file == file);
+ }
+
+ return ptr;
+}
+
+
+struct GetIters {
+ FMListModel *model;
+ NautilusFile *file;
+ GList *iters;
+};
+
+static void
+dir_to_iters (struct GetIters *data,
+ GHashTable *reverse_map)
{
GSequencePtr ptr;
+
+ ptr = g_hash_table_lookup (reverse_map, data->file);
+ if (ptr) {
+ GtkTreeIter *iter;
+ iter = g_new0 (GtkTreeIter, 1);
+ fm_list_model_ptr_to_iter (data->model, ptr, iter);
+ data->iters = g_list_prepend (data->iters, iter);
+ }
+}
+
+static void
+file_to_iter_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ struct GetIters *data;
+ FileEntry *dir_file_entry;
+
+ data = user_data;
+ dir_file_entry = g_sequence_ptr_get_data ((GSequencePtr)value);
+ dir_to_iters (data, dir_file_entry->reverse_map);
+}
+
+GList *
+fm_list_model_get_all_iters_for_file (FMListModel *model, NautilusFile *file)
+{
+ struct GetIters data;
+
+ data.file = file;
+ data.model = model;
+ data.iters = NULL;
+
+ dir_to_iters (&data, model->details->top_reverse_map);
+ g_hash_table_foreach (model->details->directory_reverse_map,
+ file_to_iter_cb, &data);
+
+ return g_list_reverse (data.iters);
+}
+
+gboolean
+fm_list_model_get_first_iter_for_file (FMListModel *model,
+ NautilusFile *file,
+ GtkTreeIter *iter)
+{
+ GList *list;
+ gboolean res;
+
+ res = FALSE;
+
+ list = fm_list_model_get_all_iters_for_file (model, file);
+ if (list != NULL) {
+ res = TRUE;
+ *iter = *(GtkTreeIter *)list->data;
+ }
+ eel_g_list_free_deep (list);
+
+ return res;
+}
+
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
+gboolean
+fm_list_model_get_tree_iter_from_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory,
+ GtkTreeIter *iter)
+{
+ GSequencePtr ptr;
+ ptr = lookup_file (model, file, directory);
if (!ptr) {
return FALSE;
}
- g_assert (!g_sequence_ptr_is_end (ptr));
- g_assert (((FileEntry *)g_sequence_ptr_get_data (ptr))->file == file);
-
- if (iter != NULL) {
- iter->stamp = model->details->stamp;
- iter->user_data = ptr;
- }
+ fm_list_model_ptr_to_iter (model, ptr, iter);
return TRUE;
}
@@ -545,21 +648,13 @@ fm_list_model_file_entry_compare_func (gconstpointer a,
return result;
}
-static int
-fm_list_model_compare_func (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
+int
+fm_list_model_compare_func (FMListModel *model,
+ NautilusFile *file1,
+ NautilusFile *file2)
{
- NautilusFile *file1;
- NautilusFile *file2;
- FMListModel *model;
int result;
- model = (FMListModel *)user_data;
-
- 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,
@@ -641,12 +736,6 @@ fm_list_model_sort (FMListModel *model)
gtk_tree_path_free (path);
}
-void
-fm_list_model_sort_files (FMListModel *model, GList **files)
-{
- *files = g_list_sort_with_data (*files, fm_list_model_compare_func, model);
-}
-
static gboolean
fm_list_model_get_sort_column_id (GtkTreeSortable *sortable,
gint *sort_column_id,
@@ -716,7 +805,6 @@ each_path_get_data_binder (NautilusDragEachSelectedItemDataGet data_get,
char *uri;
GdkRectangle cell_area;
GtkTreeViewColumn *column;
- GtkTreeIter iter;
info = context;
@@ -728,31 +816,25 @@ each_path_get_data_binder (NautilusDragEachSelectedItemDataGet data_get,
row = l->data;
path = gtk_tree_row_reference_get_path (row);
-
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (info->model),
- &iter, path)) {
- gtk_tree_model_get (GTK_TREE_MODEL (info->model),
- &iter,
- FM_LIST_MODEL_FILE_COLUMN, &file,
- -1);
-
- if (file) {
- gtk_tree_view_get_cell_area
- (info->model->details->drag_view,
- path,
- column,
- &cell_area);
+ file = fm_list_model_file_for_path (info->model, path);
+ if (file) {
+ gtk_tree_view_get_cell_area
+ (info->model->details->drag_view,
+ path,
+ column,
+ &cell_area);
- uri = nautilus_file_get_uri (file);
+ uri = nautilus_file_get_uri (file);
- (*data_get) (uri,
- 0,
- cell_area.y - info->model->details->drag_begin_y,
- cell_area.width, cell_area.height,
- data);
+ (*data_get) (uri,
+ 0,
+ cell_area.y - info->model->details->drag_begin_y,
+ cell_area.width, cell_area.height,
+ data);
- g_free (uri);
- }
+ g_free (uri);
+
+ nautilus_file_unref (file);
}
gtk_tree_path_free (path);
@@ -822,87 +904,65 @@ add_dummy_row (FMListModel *model, FileEntry *parent_entry)
}
gboolean
-fm_list_model_add_file (FMListModel *model, NautilusFile *file)
+fm_list_model_add_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
GtkTreePath *path;
FileEntry *file_entry;
- NautilusFile *parent_file;
GSequencePtr ptr, parent_ptr;
GSequence *files;
gboolean replace_dummy;
+ GHashTable *parent_hash;
- /* We may only add each file once, in one dir. */
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
- if (ptr != NULL) {
- file_entry = g_sequence_ptr_get_data (ptr);
-
- parent_file = nautilus_file_get_parent (file);
- if (parent_file == NULL) {
- return FALSE;
- }
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- parent_file);
- nautilus_file_unref (parent_file);
- if (/* toplevel parent */
- (file_entry->parent == NULL && parent_ptr == NULL) ||
- /* same in-tree parent */
- (file_entry->parent != NULL && parent_ptr != NULL &&
- file_entry->parent->ptr == parent_ptr) ) {
- /* Don't add twice in same place */
- return FALSE;
- }
-
- /* file has a new parent, due to a move
- * this happens because a move results in a
- * CHANGE event and an ADD event, and
- * if the target directory of the move is
- * added to the FMDirectoryView
- * then we won't remove the changed file.
- */
- fm_list_model_remove_file (model, file);
-
- /* Now add it back again in the new place. */
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
+ if (parent_ptr) {
+ file_entry = g_sequence_ptr_get_data (parent_ptr);
+ ptr = g_hash_table_lookup (file_entry->reverse_map, file);
+ } else {
+ file_entry = NULL;
+ ptr = g_hash_table_lookup (model->details->top_reverse_map, file);
}
- nautilus_file_ref (file);
+ if (ptr != NULL) {
+ g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr);
+ return FALSE;
+ }
file_entry = g_new0 (FileEntry, 1);
- file_entry->file = file;
+ file_entry->file = nautilus_file_ref (file);
file_entry->parent = NULL;
file_entry->subdirectory = NULL;
file_entry->files = NULL;
files = model->details->files;
+ parent_hash = model->details->top_reverse_map;
replace_dummy = FALSE;
- 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 */
- model->details->stamp++;
- g_sequence_remove (dummy_ptr);
-
- replace_dummy = TRUE;
- }
+ if (parent_ptr != NULL) {
+ file_entry->parent = g_sequence_ptr_get_data (parent_ptr);
+ parent_hash = file_entry->parent->reverse_map;
+ 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 */
+ model->details->stamp++;
+ 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);
+ g_hash_table_insert (parent_hash, file, file_entry->ptr);
iter.stamp = model->details->stamp;
iter.user_data = file_entry->ptr;
@@ -928,23 +988,21 @@ fm_list_model_add_file (FMListModel *model, NautilusFile *file)
}
void
-fm_list_model_file_changed (FMListModel *model, NautilusFile *file)
+fm_list_model_file_changed (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
GtkTreePath *path;
GSequencePtr ptr;
- ptr = g_hash_table_lookup (model->details->reverse_map, file);
+ ptr = lookup_file (model, file, directory);
if (!ptr) {
return;
}
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;
- }
-
+ fm_list_model_ptr_to_iter (model, ptr, &iter);
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);
@@ -979,7 +1037,8 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
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);
+ child_file_entry->file,
+ file_entry->subdirectory);
} else {
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
gtk_tree_path_append_index (path, 0);
@@ -995,7 +1054,11 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
}
- g_hash_table_remove (model->details->reverse_map, file_entry->file);
+ if (file_entry->parent != NULL) {
+ g_hash_table_remove (file_entry->parent->reverse_map, file_entry->file);
+ } else {
+ g_hash_table_remove (model->details->top_reverse_map, file_entry->file);
+ }
parent_file_entry = file_entry->parent;
if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 1 &&
@@ -1011,6 +1074,8 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
g_signal_emit (model,
list_model_signals[SUBDIRECTORY_UNLOADED], 0,
file_entry->subdirectory);
+ g_hash_table_remove (model->details->directory_reverse_map,
+ file_entry->subdirectory);
}
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), iter);
@@ -1032,11 +1097,12 @@ fm_list_model_remove (FMListModel *model, GtkTreeIter *iter)
}
void
-fm_list_model_remove_file (FMListModel *model, NautilusFile *file)
+fm_list_model_remove_file (FMListModel *model, NautilusFile *file,
+ NautilusDirectory *directory)
{
GtkTreeIter iter;
- if (fm_list_model_get_tree_iter_from_file (model, file, &iter)) {
+ if (fm_list_model_get_tree_iter_from_file (model, file, directory, &iter)) {
fm_list_model_remove (model, &iter);
}
}
@@ -1090,6 +1156,7 @@ fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, Nautilus
{
GtkTreeIter iter;
FileEntry *file_entry;
+ NautilusDirectory *subdirectory;
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) {
return FALSE;
@@ -1101,9 +1168,23 @@ fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, Nautilus
return FALSE;
}
- file_entry->subdirectory = nautilus_directory_get_for_file (file_entry->file);
- nautilus_directory_ref (file_entry->subdirectory);
- *directory = file_entry->subdirectory;
+ subdirectory = nautilus_directory_get_for_file (file_entry->file);
+
+ if (g_hash_table_lookup (model->details->directory_reverse_map,
+ subdirectory) != NULL) {
+ nautilus_directory_unref (subdirectory);
+ g_warning ("Already in directory_reverse_map, failing\n");
+ return FALSE;
+ }
+
+ file_entry->subdirectory = subdirectory,
+ g_hash_table_insert (model->details->directory_reverse_map,
+ subdirectory, file_entry->ptr);
+ file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ /* Return a ref too */
+ nautilus_directory_ref (subdirectory);
+ *directory = subdirectory;
return TRUE;
}
@@ -1114,7 +1195,8 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
{
GSequencePtr child_ptr;
FileEntry *file_entry, *child_file_entry;
-
+ GtkTreeIter child_iter;
+
file_entry = g_sequence_ptr_get_data (iter->user_data);
if (file_entry->file == NULL ||
file_entry->subdirectory == NULL) {
@@ -1131,8 +1213,8 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
/* Don't delete the dummy node */
break;
} else {
- fm_list_model_remove_file (model,
- child_file_entry->file);
+ fm_list_model_ptr_to_iter (model, child_ptr, &child_iter);
+ fm_list_model_remove (model, &child_iter);
}
}
@@ -1142,8 +1224,14 @@ fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter)
file_entry->subdirectory);
/* actually unload */
+ g_hash_table_remove (model->details->directory_reverse_map,
+ file_entry->subdirectory);
nautilus_directory_unref (file_entry->subdirectory);
file_entry->subdirectory = NULL;
+
+ g_assert (g_hash_table_size (file_entry->reverse_map) == 0);
+ g_hash_table_destroy (file_entry->reverse_map);
+ file_entry->reverse_map = NULL;
}
@@ -1386,9 +1474,13 @@ fm_list_model_dispose (GObject *object)
model->details->files = NULL;
}
- if (model->details->reverse_map) {
- g_hash_table_destroy (model->details->reverse_map);
- model->details->reverse_map = NULL;
+ if (model->details->top_reverse_map) {
+ g_hash_table_destroy (model->details->top_reverse_map);
+ model->details->top_reverse_map = NULL;
+ }
+ if (model->details->directory_reverse_map) {
+ g_hash_table_destroy (model->details->directory_reverse_map);
+ model->details->directory_reverse_map = NULL;
}
EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
@@ -1412,7 +1504,8 @@ fm_list_model_init (FMListModel *model)
{
model->details = g_new0 (FMListModelDetails, 1);
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->top_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+ model->details->directory_reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal);
model->details->stamp = g_random_int ();
model->details->sort_attribute = NULL;
model->details->columns = g_ptr_array_new ();
@@ -1526,7 +1619,7 @@ fm_list_model_get_type (void)
struct ChangeDummyData {
FMListModel *model;
- NautilusFile *file;
+ NautilusDirectory *directory;
};
static gboolean
@@ -1545,8 +1638,8 @@ change_dummy_row_callback (gpointer callback_data)
if (data->model != NULL) {
model = data->model;
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- data->file);
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ data->directory);
file_entry = g_sequence_ptr_get_data (parent_ptr);
file_entry->loaded = 1;
@@ -1569,7 +1662,7 @@ change_dummy_row_callback (gpointer callback_data)
}
eel_remove_weak_pointer (&data->model);
- nautilus_file_unref (data->file);
+ nautilus_directory_unref (data->directory);
g_free (data);
return FALSE;
@@ -1578,15 +1671,12 @@ change_dummy_row_callback (gpointer callback_data)
void
fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *directory)
{
- NautilusFile *parent_file;
GSequencePtr parent_ptr;
struct ChangeDummyData *data;
- parent_file = nautilus_directory_get_corresponding_file (directory);
- parent_ptr = g_hash_table_lookup (model->details->reverse_map,
- parent_file);
+ parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map,
+ directory);
if (parent_ptr == NULL) {
- nautilus_file_unref (parent_file);
return;
}
@@ -1596,10 +1686,9 @@ fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *
*/
data = g_new (struct ChangeDummyData, 1);
data->model = model;
- data->file = nautilus_file_ref (parent_file);
+ data->directory = directory;
+ nautilus_directory_ref (directory);
eel_add_weak_pointer (&data->model);
g_timeout_add (LOADING_TO_EMPTY_DELAY, change_dummy_row_callback, data);
-
- nautilus_file_unref (parent_file);
}