diff options
author | António Fernandes <antoniof@gnome.org> | 2022-04-05 16:14:16 +0100 |
---|---|---|
committer | António Fernandes <antoniof@gnome.org> | 2023-01-10 01:11:33 +0000 |
commit | 510a4202d25b82323a1307918b382aab603190eb (patch) | |
tree | 732d9353cb950997ae5b1677bc5a2267f54575c6 | |
parent | b9ac68eb6fb1f7aa5f815f9b15cd789758d62cba (diff) | |
download | nautilus-510a4202d25b82323a1307918b382aab603190eb.tar.gz |
view-model: Use GtkTreeViewModel internally
The view doesn't see any difference yet, but this prepares for
tree expansion support later.
-rw-r--r-- | src/nautilus-view-model.c | 249 | ||||
-rw-r--r-- | src/nautilus-view-model.h | 8 |
2 files changed, 199 insertions, 58 deletions
diff --git a/src/nautilus-view-model.c b/src/nautilus-view-model.c index 5a63c28ae..3642d39f8 100644 --- a/src/nautilus-view-model.c +++ b/src/nautilus-view-model.c @@ -7,11 +7,45 @@ struct _NautilusViewModel GObject parent_instance; GHashTable *map_files_to_model; - GListStore *internal_model; + GHashTable *directory_reverse_map; + + GtkTreeListModel *tree_model; GtkSortListModel *sort_model; GtkMultiSelection *selection_model; + + gboolean expand_as_a_tree; }; +static inline GListStore * +get_directory_store (NautilusViewModel *self, + NautilusFile *directory) +{ + GListStore *store; + + store = g_hash_table_lookup (self->directory_reverse_map, directory); + if (store == NULL) + { + store = G_LIST_STORE (gtk_tree_list_model_get_model (self->tree_model)); + } + + return store; +} + +static inline GtkTreeListRow * +get_child_row (NautilusViewModel *self, + GtkTreeListRow *parent, + guint position) +{ + if (parent != NULL) + { + return gtk_tree_list_row_get_child_row (parent, position); + } + else + { + return gtk_tree_list_model_get_child_row (self->tree_model, position); + } +} + static GType nautilus_view_model_get_item_type (GListModel *list) { @@ -23,12 +57,12 @@ nautilus_view_model_get_n_items (GListModel *list) { NautilusViewModel *self = NAUTILUS_VIEW_MODEL (list); - if (self->internal_model == NULL) + if (self->tree_model == NULL) { return 0; } - return g_list_model_get_n_items (G_LIST_MODEL (self->internal_model)); + return g_list_model_get_n_items (G_LIST_MODEL (self->tree_model)); } static gpointer @@ -36,13 +70,15 @@ nautilus_view_model_get_item (GListModel *list, guint position) { NautilusViewModel *self = NAUTILUS_VIEW_MODEL (list); + g_autoptr (GtkTreeListRow) row = NULL; if (self->sort_model == NULL) { return NULL; } - return g_list_model_get_item (G_LIST_MODEL (self->sort_model), position); + row = g_list_model_get_item (G_LIST_MODEL (self->sort_model), position); + return gtk_tree_list_row_get_item (row); } static void @@ -136,7 +172,7 @@ dispose (GObject *object) self->sort_model = NULL; } - g_clear_object (&self->internal_model); + g_clear_object (&self->tree_model); G_OBJECT_CLASS (nautilus_view_model_parent_class)->dispose (object); } @@ -149,6 +185,7 @@ finalize (GObject *object) G_OBJECT_CLASS (nautilus_view_model_parent_class)->finalize (object); g_hash_table_destroy (self->map_files_to_model); + g_hash_table_destroy (self->directory_reverse_map); } static void @@ -197,6 +234,34 @@ set_property (GObject *object, } } +static GListModel * +create_model_func (GObject *item, + NautilusViewModel *self) +{ + NautilusFile *file; + GListStore *store; + + if (!self->expand_as_a_tree) + { + return NULL; + } + + file = nautilus_view_item_get_file (NAUTILUS_VIEW_ITEM (item)); + if (!nautilus_file_is_directory (file)) + { + return NULL; + } + + store = g_hash_table_lookup (self->directory_reverse_map, file); + if (store == NULL) + { + store = g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM); + g_hash_table_insert (self->directory_reverse_map, file, store); + } + + return g_object_ref (G_LIST_MODEL (store)); +} + static void constructed (GObject *object) { @@ -204,10 +269,15 @@ constructed (GObject *object) G_OBJECT_CLASS (nautilus_view_model_parent_class)->constructed (object); - self->internal_model = g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM); - self->sort_model = gtk_sort_list_model_new (g_object_ref (G_LIST_MODEL (self->internal_model)), NULL); + self->tree_model = gtk_tree_list_model_new (G_LIST_MODEL (g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM)), + FALSE, FALSE, + (GtkTreeListModelCreateModelFunc) create_model_func, + self, NULL); + self->sort_model = gtk_sort_list_model_new (g_object_ref (G_LIST_MODEL (self->tree_model)), NULL); self->selection_model = gtk_multi_selection_new (g_object_ref (G_LIST_MODEL (self->sort_model))); + self->map_files_to_model = g_hash_table_new (NULL, NULL); + self->directory_reverse_map = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); g_signal_connect_swapped (self->sort_model, "items-changed", G_CALLBACK (g_list_model_items_changed), self); @@ -264,14 +334,23 @@ nautilus_view_model_new (void) GtkSorter * nautilus_view_model_get_sorter (NautilusViewModel *self) { - return gtk_sort_list_model_get_sorter (self->sort_model); + GtkTreeListRowSorter *row_sorter; + + row_sorter = GTK_TREE_LIST_ROW_SORTER (gtk_sort_list_model_get_sorter (self->sort_model)); + + return gtk_tree_list_row_sorter_get_sorter (row_sorter); } void nautilus_view_model_set_sorter (NautilusViewModel *self, GtkSorter *sorter) { - gtk_sort_list_model_set_sorter (self->sort_model, sorter); + g_autoptr (GtkTreeListRowSorter) row_sorter = NULL; + + row_sorter = gtk_tree_list_row_sorter_new (NULL); + + gtk_tree_list_row_sorter_set_sorter (row_sorter, sorter); + gtk_sort_list_model_set_sorter (self->sort_model, GTK_SORTER (row_sorter)); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]); } @@ -289,33 +368,15 @@ nautilus_view_model_get_items_from_files (NautilusViewModel *self, GQueue *files) { GList *l; - guint n_items; GQueue *items; - n_items = g_list_model_get_n_items (G_LIST_MODEL (self->internal_model)); items = g_queue_new (); for (l = g_queue_peek_head_link (files); l != NULL; l = l->next) { - NautilusFile *file1; + NautilusViewItem *item; - file1 = NAUTILUS_FILE (l->data); - for (guint i = 0; i < n_items; i++) - { - g_autoptr (NautilusViewItem) item = NULL; - NautilusFile *file2; - g_autofree gchar *file1_uri = NULL; - g_autofree gchar *file2_uri = NULL; - - item = g_list_model_get_item (G_LIST_MODEL (self->internal_model), i); - file2 = nautilus_view_item_get_file (item); - file1_uri = nautilus_file_get_uri (file1); - file2_uri = nautilus_file_get_uri (file2); - if (g_strcmp0 (file1_uri, file2_uri) == 0) - { - g_queue_push_tail (items, item); - break; - } - } + item = nautilus_view_model_get_item_from_file (self, l->data); + g_queue_push_tail (items, item); } return items; @@ -332,62 +393,100 @@ void nautilus_view_model_remove_item (NautilusViewModel *self, NautilusViewItem *item) { + NautilusFile *file; + g_autoptr (NautilusFile) parent = NULL; + GListStore *dir_store; guint i; - if (g_list_store_find (self->internal_model, item, &i)) + file = nautilus_view_item_get_file (item); + parent = nautilus_file_get_parent (file); + dir_store = get_directory_store (self, parent); + if (g_list_store_find (dir_store, item, &i)) { - NautilusFile *file; - - file = nautilus_view_item_get_file (item); - g_list_store_remove (self->internal_model, i); + g_list_store_remove (dir_store, i); g_hash_table_remove (self->map_files_to_model, file); + if (nautilus_file_is_directory (file)) + { + g_hash_table_remove (self->directory_reverse_map, file); + } } } void nautilus_view_model_remove_all_items (NautilusViewModel *self) { - g_list_store_remove_all (self->internal_model); + g_list_store_remove_all (G_LIST_STORE (gtk_tree_list_model_get_model (self->tree_model))); g_hash_table_remove_all (self->map_files_to_model); + g_hash_table_remove_all (self->directory_reverse_map); } void nautilus_view_model_add_item (NautilusViewModel *self, NautilusViewItem *item) { - g_hash_table_insert (self->map_files_to_model, - nautilus_view_item_get_file (item), - item); - g_list_store_append (self->internal_model, item); + NautilusFile *file; + g_autoptr (NautilusFile) parent = NULL; + + file = nautilus_view_item_get_file (item); + parent = nautilus_file_get_parent (file); + + g_list_store_append (get_directory_store (self, parent), item); + g_hash_table_insert (self->map_files_to_model, file, item); +} + +static void +splice_items_into_common_parent (NautilusViewModel *self, + GPtrArray *items, + NautilusFile *common_parent) +{ + GListStore *dir_store; + + dir_store = get_directory_store (self, common_parent); + g_list_store_splice (dir_store, + g_list_model_get_n_items (G_LIST_MODEL (dir_store)), + 0, items->pdata, items->len); } void nautilus_view_model_add_items (NautilusViewModel *self, GQueue *items) { - g_autofree gpointer *array = NULL; + g_autoptr (GPtrArray) array = g_ptr_array_new (); + g_autoptr (NautilusFile) previous_parent = NULL; GList *l; - int i = 0; + NautilusViewItem *item; - /* Sort items before adding them to the internal model. This ensures that - * the first sorted item is become the initial focus and scroll anchor. */ g_queue_sort (items, compare_data_func, self); - array = g_malloc_n (g_queue_get_length (items), - sizeof (NautilusViewItem *)); - for (l = g_queue_peek_head_link (items); l != NULL; l = l->next) { - array[i] = l->data; + g_autoptr (NautilusFile) parent = NULL; + + item = NAUTILUS_VIEW_ITEM (l->data); + parent = nautilus_file_get_parent (nautilus_view_item_get_file (item)); + + if (previous_parent != NULL && previous_parent != parent) + { + /* The pending items share a common parent. */ + splice_items_into_common_parent (self, array, previous_parent); + + /* Clear pending items and start a new with a new parent. */ + g_ptr_array_unref (array); + array = g_ptr_array_new (); + } + g_set_object (&previous_parent, parent); + + g_ptr_array_add (array, item); g_hash_table_insert (self->map_files_to_model, - nautilus_view_item_get_file (l->data), - l->data); - i++; + nautilus_view_item_get_file (item), + item); } - g_list_store_splice (self->internal_model, - g_list_model_get_n_items (G_LIST_MODEL (self->internal_model)), - 0, array, g_queue_get_length (items)); + if (previous_parent != NULL) + { + /* Flush the pending items. */ + splice_items_into_common_parent (self, array, previous_parent); + } } guint @@ -400,10 +499,14 @@ nautilus_view_model_get_index (NautilusViewModel *self, n_items = g_list_model_get_n_items (G_LIST_MODEL (self->sort_model)); while (i < n_items) { + g_autoptr (GtkTreeListRow) row = NULL; g_autoptr (NautilusViewItem) item_i = NULL; - item_i = NAUTILUS_VIEW_ITEM (g_list_model_get_item (G_LIST_MODEL (self->sort_model), i)); - g_warn_if_fail (item_i != NULL); + row = g_list_model_get_item (G_LIST_MODEL (self->sort_model), i); + g_warn_if_fail (GTK_IS_TREE_LIST_ROW (row)); + + item_i = gtk_tree_list_row_get_item (row); + g_warn_if_fail (NAUTILUS_IS_VIEW_ITEM (item_i)); if (item_i == item) { @@ -414,3 +517,37 @@ nautilus_view_model_get_index (NautilusViewModel *self, return G_MAXUINT; } + +void +nautilus_view_model_clear_subdirectory (NautilusViewModel *self, + NautilusViewItem *item) +{ + NautilusFile *file; + GListModel *children; + guint n_children = 0; + + g_return_if_fail (NAUTILUS_IS_VIEW_MODEL (self)); + g_return_if_fail (NAUTILUS_IS_VIEW_ITEM (item)); + + file = nautilus_view_item_get_file (item); + children = G_LIST_MODEL (g_hash_table_lookup (self->directory_reverse_map, file)); + n_children = (children != NULL) ? g_list_model_get_n_items (children) : 0; + for (guint i = 0; i < n_children; i++) + { + g_autoptr (NautilusViewItem) child = g_list_model_get_item (children, i); + + if (nautilus_file_is_directory (nautilus_view_item_get_file (child))) + { + /* Clear recursively */ + nautilus_view_model_clear_subdirectory (self, child); + } + } + g_hash_table_remove (self->directory_reverse_map, file); +} + +void +nautilus_view_model_expand_as_a_tree (NautilusViewModel *self, + gboolean expand_as_a_tree) +{ + self->expand_as_a_tree = expand_as_a_tree; +} diff --git a/src/nautilus-view-model.h b/src/nautilus-view-model.h index 00d857b2e..5f613ca72 100644 --- a/src/nautilus-view-model.h +++ b/src/nautilus-view-model.h @@ -29,7 +29,11 @@ void nautilus_view_model_add_item (NautilusViewModel *self, NautilusViewItem *item); void nautilus_view_model_add_items (NautilusViewModel *self, GQueue *items); -guint nautilus_view_model_get_index (NautilusViewModel *self, - NautilusViewItem *item); +guint nautilus_view_model_get_index (NautilusViewModel *self, + NautilusViewItem *item); +void nautilus_view_model_clear_subdirectory (NautilusViewModel *self, + NautilusViewItem *item); +void nautilus_view_model_expand_as_a_tree (NautilusViewModel *self, + gboolean expand_as_a_tree); G_END_DECLS |