diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:39:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:39:48 +0000 |
commit | 3ade071f273aaa973e44bf95d6b1d4913a18f03b (patch) | |
tree | e2f99d267ae18427645404f215b984afbe73098d /src/nautilus-view-model.c | |
parent | Initial commit. (diff) | |
download | nautilus-3ade071f273aaa973e44bf95d6b1d4913a18f03b.tar.xz nautilus-3ade071f273aaa973e44bf95d6b1d4913a18f03b.zip |
Adding upstream version 43.2.upstream/43.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/nautilus-view-model.c | 422 |
1 files changed, 422 insertions, 0 deletions
diff --git a/src/nautilus-view-model.c b/src/nautilus-view-model.c new file mode 100644 index 0000000..2cb1c47 --- /dev/null +++ b/src/nautilus-view-model.c @@ -0,0 +1,422 @@ +#include "nautilus-view-model.h" +#include "nautilus-view-item.h" +#include "nautilus-global-preferences.h" + +struct _NautilusViewModel +{ + GObject parent_instance; + + GHashTable *map_files_to_model; + GListStore *internal_model; + GtkMultiSelection *selection_model; + GtkSorter *sorter; + gulong sorter_changed_id; +}; + +static GType +nautilus_view_model_get_item_type (GListModel *list) +{ + return NAUTILUS_TYPE_VIEW_ITEM; +} + +static guint +nautilus_view_model_get_n_items (GListModel *list) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (list); + + if (self->internal_model == NULL) + { + return 0; + } + + return g_list_model_get_n_items (G_LIST_MODEL (self->internal_model)); +} + +static gpointer +nautilus_view_model_get_item (GListModel *list, + guint position) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (list); + + if (self->internal_model == NULL) + { + return NULL; + } + + return g_list_model_get_item (G_LIST_MODEL (self->internal_model), position); +} + +static void +nautilus_view_model_list_model_init (GListModelInterface *iface) +{ + iface->get_item_type = nautilus_view_model_get_item_type; + iface->get_n_items = nautilus_view_model_get_n_items; + iface->get_item = nautilus_view_model_get_item; +} + + +static gboolean +nautilus_view_model_is_selected (GtkSelectionModel *model, + guint position) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (model); + GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (self->selection_model); + + return gtk_selection_model_is_selected (selection_model, position); +} + +static GtkBitset * +nautilus_view_model_get_selection_in_range (GtkSelectionModel *model, + guint pos, + guint n_items) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (model); + GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (self->selection_model); + + return gtk_selection_model_get_selection_in_range (selection_model, pos, n_items); +} + +static gboolean +nautilus_view_model_set_selection (GtkSelectionModel *model, + GtkBitset *selected, + GtkBitset *mask) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (model); + GtkSelectionModel *selection_model = GTK_SELECTION_MODEL (self->selection_model); + gboolean res; + + res = gtk_selection_model_set_selection (selection_model, selected, mask); + + return res; +} + + +static void +nautilus_view_model_selection_model_init (GtkSelectionModelInterface *iface) +{ + iface->is_selected = nautilus_view_model_is_selected; + iface->get_selection_in_range = nautilus_view_model_get_selection_in_range; + iface->set_selection = nautilus_view_model_set_selection; +} + +G_DEFINE_TYPE_WITH_CODE (NautilusViewModel, nautilus_view_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, + nautilus_view_model_list_model_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL, + nautilus_view_model_selection_model_init)) + +enum +{ + PROP_0, + PROP_SORTER, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +dispose (GObject *object) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (object); + + if (self->selection_model != NULL) + { + g_signal_handlers_disconnect_by_func (self->selection_model, + gtk_selection_model_selection_changed, + self); + g_object_unref (self->selection_model); + self->selection_model = NULL; + } + + if (self->internal_model != NULL) + { + g_signal_handlers_disconnect_by_func (self->internal_model, + g_list_model_items_changed, + self); + g_object_unref (self->internal_model); + self->internal_model = NULL; + } + + g_clear_signal_handler (&self->sorter_changed_id, self->sorter); + + G_OBJECT_CLASS (nautilus_view_model_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (object); + + G_OBJECT_CLASS (nautilus_view_model_parent_class)->finalize (object); + + g_hash_table_destroy (self->map_files_to_model); + g_clear_object (&self->sorter); +} + +static void +get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (object); + + switch (prop_id) + { + case PROP_SORTER: + { + g_value_set_object (value, nautilus_view_model_get_sorter (self)); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } + } +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (object); + + switch (prop_id) + { + case PROP_SORTER: + { + nautilus_view_model_set_sorter (self, g_value_get_object (value)); + } + break; + + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } + } +} + +static void +constructed (GObject *object) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (object); + + G_OBJECT_CLASS (nautilus_view_model_parent_class)->constructed (object); + + self->internal_model = g_list_store_new (NAUTILUS_TYPE_VIEW_ITEM); + self->selection_model = gtk_multi_selection_new (g_object_ref (G_LIST_MODEL (self->internal_model))); + self->map_files_to_model = g_hash_table_new (NULL, NULL); + + g_signal_connect_swapped (self->internal_model, "items-changed", + G_CALLBACK (g_list_model_items_changed), self); + g_signal_connect_swapped (self->selection_model, "selection-changed", + G_CALLBACK (gtk_selection_model_selection_changed), self); +} + +static void +nautilus_view_model_class_init (NautilusViewModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = dispose; + object_class->finalize = finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->constructed = constructed; + + properties[PROP_SORTER] = + g_param_spec_object ("sorter", + "", "", + GTK_TYPE_SORTER, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +nautilus_view_model_init (NautilusViewModel *self) +{ +} + +static gint +compare_data_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (user_data); + + if (self->sorter == NULL) + { + return GTK_ORDERING_EQUAL; + } + + return gtk_sorter_compare (self->sorter, (gpointer) a, (gpointer) b); +} + +static void +on_sorter_changed (GtkSorter *sorter, + GtkSorterChange change, + gpointer user_data) +{ + NautilusViewModel *self = NAUTILUS_VIEW_MODEL (user_data); + + g_list_store_sort (self->internal_model, compare_data_func, self); +} + +NautilusViewModel * +nautilus_view_model_new (void) +{ + return g_object_new (NAUTILUS_TYPE_VIEW_MODEL, NULL); +} + +GtkSorter * +nautilus_view_model_get_sorter (NautilusViewModel *self) +{ + return self->sorter; +} + +void +nautilus_view_model_set_sorter (NautilusViewModel *self, + GtkSorter *sorter) +{ + if (self->sorter != NULL) + { + g_clear_signal_handler (&self->sorter_changed_id, self->sorter); + } + + if (g_set_object (&self->sorter, sorter)) + { + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]); + } + + if (self->sorter != NULL) + { + self->sorter_changed_id = g_signal_connect (self->sorter, "changed", + G_CALLBACK (on_sorter_changed), self); + g_list_store_sort (self->internal_model, compare_data_func, self); + } +} + +GQueue * +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; + + 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; + } + } + } + + return items; +} + +NautilusViewItem * +nautilus_view_model_get_item_from_file (NautilusViewModel *self, + NautilusFile *file) +{ + return g_hash_table_lookup (self->map_files_to_model, file); +} + +void +nautilus_view_model_remove_item (NautilusViewModel *self, + NautilusViewItem *item) +{ + guint i; + + if (g_list_store_find (self->internal_model, item, &i)) + { + NautilusFile *file; + + file = nautilus_view_item_get_file (item); + g_list_store_remove (self->internal_model, i); + g_hash_table_remove (self->map_files_to_model, file); + } +} + +void +nautilus_view_model_remove_all_items (NautilusViewModel *self) +{ + g_list_store_remove_all (self->internal_model); + g_hash_table_remove_all (self->map_files_to_model); +} + +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_insert_sorted (self->internal_model, item, compare_data_func, self); +} + +void +nautilus_view_model_add_items (NautilusViewModel *self, + GQueue *items) +{ + g_autofree gpointer *array = NULL; + GList *l; + int i = 0; + + /* 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_hash_table_insert (self->map_files_to_model, + nautilus_view_item_get_file (l->data), + l->data); + i++; + } + + 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)); + + g_list_store_sort (self->internal_model, compare_data_func, self); +} + +guint +nautilus_view_model_get_index (NautilusViewModel *self, + NautilusViewItem *item) +{ + guint i = G_MAXUINT; + gboolean found; + + found = g_list_store_find (self->internal_model, item, &i); + g_warn_if_fail (found); + + return i; +} |