[gtk/wip/otte/listview] multi-selection: Implement persistence
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview] multi-selection: Implement persistence
- Date: Mon, 7 Jan 2019 01:28:08 +0000 (UTC)
commit 437fa857f4dbf80f1297eb9cbadc757f113aaa5e
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Jan 6 20:26:10 2019 -0500
multi-selection: Implement persistence
This is not very efficient for Ctrl-A.
No way around it.
gtk/gtkmultiselection.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
---
diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c
index cede5266da..e9c963f0b4 100644
--- a/gtk/gtkmultiselection.c
+++ b/gtk/gtkmultiselection.c
@@ -46,6 +46,17 @@ struct _GtkMultiSelection
guint last_selected;
};
+/*
+ * We store a set of positions for selected items. This can be maintained
+ * efficiently as long as it consists of a small number of ranges. I
+ * degenerate cases such as 'every second item in the list', it will
+ * be O(|model|).
+ *
+ * To implement persistence across add/remove changes in the underlying
+ * model (for example, resorting), we mark the selected objects, which
+ * is also going to be O(|model|) in the 'select all' case.
+ */
+
struct _GtkMultiSelectionClass
{
GObjectClass parent_class;
@@ -102,6 +113,38 @@ gtk_multi_selection_is_selected (GtkSelectionModel *model,
return gtk_set_contains (self->selected, position);
}
+static void
+mark_selected (GtkMultiSelection *self, gboolean in)
+{
+ GtkSetIter iter;
+ guint pos;
+
+ gtk_set_iter_init (&iter, self->selected);
+ while (gtk_set_iter_next (&iter, &pos))
+ {
+ /* Mark the object as being selected in this multiselection.
+ * See gtk_multi_selection_items_changed_cb, where this is
+ * used to identify objects that were removed and readded.
+ */
+ GObject *obj = g_list_model_get_item (self->model, pos);
+ g_object_set_data (obj, "GtkMultiSelection", in ? self : NULL);
+ g_object_unref (obj);
+ }
+}
+
+static void
+mark_range (GtkMultiSelection *self, guint first, guint n_items, gboolean in)
+{
+ guint pos;
+
+ for (pos = first; pos < first + n_items; pos++)
+ {
+ GObject *obj = g_list_model_get_item (self->model, pos);
+ g_object_set_data (obj, "GtkMultiSelection", in ? self : NULL);
+ g_object_unref (obj);
+ }
+}
+
static gboolean
gtk_multi_selection_select_range (GtkSelectionModel *model,
guint position,
@@ -111,7 +154,11 @@ gtk_multi_selection_select_range (GtkSelectionModel *model,
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
if (exclusive)
- gtk_set_remove_all (self->selected);
+ {
+ mark_selected (self, FALSE);
+ gtk_set_remove_all (self->selected);
+ }
+ mark_range (self, position, n_items, TRUE);
gtk_set_add_range (self->selected, position, n_items);
gtk_selection_model_selection_changed (model, position, n_items);
@@ -125,6 +172,7 @@ gtk_multi_selection_unselect_range (GtkSelectionModel *model,
{
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
+ mark_range (self, position, n_items, FALSE);
gtk_set_remove_range (self->selected, position, n_items);
gtk_selection_model_selection_changed (model, position, n_items);
@@ -202,8 +250,18 @@ gtk_multi_selection_items_changed_cb (GListModel *model,
guint added,
GtkMultiSelection *self)
{
+ guint pos;
+
gtk_set_remove_range (self->selected, position, removed);
gtk_set_shift (self->selected, position, (int)added - (int)removed);
+ for (pos = position; pos < position + added; pos++)
+ {
+ GObject *obj = g_list_model_get_item (self->model, pos);
+ if (g_object_get_data (obj, "GtkMultiSelection") == self)
+ gtk_set_add_item (self->selected, pos);
+ g_object_unref (obj);
+ }
+
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]