summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gtk/gtk4-sections.txt3
-rw-r--r--gtk/gtkmultiselection.c63
-rw-r--r--gtk/gtkmultiselection.h3
-rw-r--r--gtk/gtknoselection.c58
-rw-r--r--gtk/gtknoselection.h3
-rw-r--r--gtk/gtksingleselection.c71
-rw-r--r--gtk/gtksingleselection.h23
-rw-r--r--testsuite/gtk/multiselection.c54
-rw-r--r--testsuite/gtk/singleselection.c52
9 files changed, 296 insertions, 34 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 15bdac5bc3..b02457dca8 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -422,6 +422,7 @@ gtk_selection_model_get_type
GtkNoSelection
gtk_no_selection_new
gtk_no_selection_get_model
+gtk_no_selection_set_model
<SUBSECTION Private>
gtk_no_selection_get_type
</SECTION>
@@ -433,6 +434,7 @@ GtkSingleSelection
GTK_INVALID_LIST_POSITION
gtk_single_selection_new
gtk_single_selection_get_model
+gtk_single_selection_set_model
gtk_single_selection_get_selected
gtk_single_selection_set_selected
gtk_single_selection_get_selected_item
@@ -450,6 +452,7 @@ gtk_single_selection_get_type
GtkMultiSelection
gtk_multi_selection_new
gtk_multi_selection_get_model
+gtk_multi_selection_set_model
<SUBSECTION Private>
gtk_multi_selection_get_type
</SECTION>
diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c
index ad6d3857de..4dd93b5234 100644
--- a/gtk/gtkmultiselection.c
+++ b/gtk/gtkmultiselection.c
@@ -70,6 +70,9 @@ gtk_multi_selection_get_n_items (GListModel *list)
{
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
+ if (self->model == NULL)
+ return 0;
+
return g_list_model_get_n_items (self->model);
}
@@ -79,6 +82,9 @@ gtk_multi_selection_get_item (GListModel *list,
{
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
+ if (self->model == NULL)
+ return NULL;
+
return g_list_model_get_item (self->model, position);
}
@@ -172,7 +178,7 @@ gtk_multi_selection_set_selection (GtkSelectionModel *model,
max = gtk_bitset_get_maximum (changes);
/* sanity check */
- n_items = g_list_model_get_n_items (self->model);
+ n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
if (max >= n_items)
{
gtk_bitset_remove_range_closed (changes, n_items, max);
@@ -289,12 +295,7 @@ gtk_multi_selection_set_property (GObject *object,
switch (prop_id)
{
case PROP_MODEL:
- self->model = g_value_dup_object (value);
- g_warn_if_fail (self->model != NULL);
- g_signal_connect (self->model,
- "items-changed",
- G_CALLBACK (gtk_multi_selection_items_changed_cb),
- self);
+ gtk_multi_selection_set_model (self, g_value_get_object (value));
break;
default:
@@ -355,7 +356,7 @@ gtk_multi_selection_class_init (GtkMultiSelectionClass *klass)
P_("Model"),
P_("List managed by this selection"),
G_TYPE_LIST_MODEL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -400,3 +401,49 @@ gtk_multi_selection_get_model (GtkMultiSelection *self)
return self->model;
}
+
+/**
+ * gtk_multi_selection_set_model:
+ * @self: a #GtkMultiSelection
+ * @model: (allow-none): A #GListModel to wrap
+ *
+ * Sets the model that @self should wrap. If @model is %NULL, @self
+ * will be empty.
+ **/
+void
+gtk_multi_selection_set_model (GtkMultiSelection *self,
+ GListModel *model)
+{
+ guint n_items_before;
+
+ g_return_if_fail (GTK_IS_MULTI_SELECTION (self));
+ g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+
+ if (self->model == model)
+ return;
+
+ n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
+ gtk_multi_selection_clear_model (self);
+
+ if (model)
+ {
+ self->model = g_object_ref (model);
+ g_signal_connect (self->model,
+ "items-changed",
+ G_CALLBACK (gtk_multi_selection_items_changed_cb),
+ self);
+ gtk_multi_selection_items_changed_cb (self->model,
+ 0,
+ n_items_before,
+ g_list_model_get_n_items (model),
+ self);
+ }
+ else
+ {
+ gtk_bitset_remove_all (self->selected);
+ g_hash_table_remove_all (self->items);
+ g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, 0);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
+}
diff --git a/gtk/gtkmultiselection.h b/gtk/gtkmultiselection.h
index 92074683c0..69c8a69028 100644
--- a/gtk/gtkmultiselection.h
+++ b/gtk/gtkmultiselection.h
@@ -35,6 +35,9 @@ GListModel * gtk_multi_selection_new (GListModel *mo
GDK_AVAILABLE_IN_ALL
GListModel * gtk_multi_selection_get_model (GtkMultiSelection *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_multi_selection_set_model (GtkMultiSelection *self,
+ GListModel *model);
G_END_DECLS
diff --git a/gtk/gtknoselection.c b/gtk/gtknoselection.c
index 652b148735..8027d003b2 100644
--- a/gtk/gtknoselection.c
+++ b/gtk/gtknoselection.c
@@ -68,15 +68,21 @@ gtk_no_selection_get_n_items (GListModel *list)
{
GtkNoSelection *self = GTK_NO_SELECTION (list);
+ if (self->model == NULL)
+ return 0;
+
return g_list_model_get_n_items (self->model);
}
static gpointer
gtk_no_selection_get_item (GListModel *list,
- guint position)
+ guint position)
{
GtkNoSelection *self = GTK_NO_SELECTION (list);
+ if (self->model == NULL)
+ return NULL;
+
return g_list_model_get_item (self->model, position);
}
@@ -130,9 +136,9 @@ gtk_no_selection_clear_model (GtkNoSelection *self)
static void
gtk_no_selection_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GtkNoSelection *self = GTK_NO_SELECTION (object);
@@ -140,10 +146,7 @@ gtk_no_selection_set_property (GObject *object,
switch (prop_id)
{
case PROP_MODEL:
- gtk_no_selection_clear_model (self);
- self->model = g_value_dup_object (value);
- g_signal_connect_swapped (self->model, "items-changed",
- G_CALLBACK (g_list_model_items_changed), self);
+ gtk_no_selection_set_model (self, g_value_get_object (value));
break;
default:
@@ -201,7 +204,7 @@ gtk_no_selection_class_init (GtkNoSelectionClass *klass)
P_("The model"),
P_("The model being managed"),
G_TYPE_LIST_MODEL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -245,3 +248,40 @@ gtk_no_selection_get_model (GtkNoSelection *self)
return self->model;
}
+/**
+ * gtk_no_selection_set_model:
+ * @self: a #GtkNoSelection
+ * @model: (allow-none): A #GListModel to wrap
+ *
+ * Sets the model that @self should wrap. If @model is %NULL, this
+ * model will be empty.
+ **/
+void
+gtk_no_selection_set_model (GtkNoSelection *self,
+ GListModel *model)
+{
+ guint n_items_before;
+
+ g_return_if_fail (GTK_IS_NO_SELECTION (self));
+ g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+
+ if (self->model == model)
+ return;
+
+ n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
+ gtk_no_selection_clear_model (self);
+
+ if (model)
+ {
+ self->model = g_object_ref (model);
+ g_signal_connect_swapped (self->model, "items-changed",
+ G_CALLBACK (g_list_model_items_changed), self);
+ }
+
+ g_list_model_items_changed (G_LIST_MODEL (self),
+ 0,
+ n_items_before,
+ model ? g_list_model_get_n_items (self->model) : 0);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
+}
diff --git a/gtk/gtknoselection.h b/gtk/gtknoselection.h
index e6341df409..09f027c9d9 100644
--- a/gtk/gtknoselection.h
+++ b/gtk/gtknoselection.h
@@ -34,6 +34,9 @@ GtkNoSelection * gtk_no_selection_new (GListModel
GDK_AVAILABLE_IN_ALL
GListModel * gtk_no_selection_get_model (GtkNoSelection *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_no_selection_set_model (GtkNoSelection *self,
+ GListModel *model);
G_END_DECLS
diff --git a/gtk/gtksingleselection.c b/gtk/gtksingleselection.c
index 70f0beab27..209f6524e8 100644
--- a/gtk/gtksingleselection.c
+++ b/gtk/gtksingleselection.c
@@ -80,6 +80,9 @@ gtk_single_selection_get_n_items (GListModel *list)
{
GtkSingleSelection *self = GTK_SINGLE_SELECTION (list);
+ if (self->model == NULL)
+ return 0;
+
return g_list_model_get_n_items (self->model);
}
@@ -89,6 +92,9 @@ gtk_single_selection_get_item (GListModel *list,
{
GtkSingleSelection *self = GTK_SINGLE_SELECTION (list);
+ if (self->model == NULL)
+ return NULL;
+
return g_list_model_get_item (self->model, position);
}
@@ -305,12 +311,7 @@ gtk_single_selection_set_property (GObject *object,
break;
case PROP_MODEL:
- gtk_single_selection_clear_model (self);
- self->model = g_value_dup_object (value);
- g_signal_connect (self->model, "items-changed",
- G_CALLBACK (gtk_single_selection_items_changed_cb), self);
- if (self->autoselect)
- gtk_single_selection_set_selected (self, 0);
+ gtk_single_selection_set_model (self, g_value_get_object (value));
break;
case PROP_SELECTED:
@@ -438,7 +439,7 @@ gtk_single_selection_class_init (GtkSingleSelectionClass *klass)
P_("The model"),
P_("The model being managed"),
G_TYPE_LIST_MODEL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -485,6 +486,62 @@ gtk_single_selection_get_model (GtkSingleSelection *self)
}
/**
+ * gtk_single_selection_set_model:
+ * @self: a #GtkSingleSelection
+ * @model: (allow-none): A #GListModel to wrap
+ *
+ * Sets the model that @self should wrap. If @model is %NULL, @self
+ * will be empty.
+ **/
+void
+gtk_single_selection_set_model (GtkSingleSelection *self,
+ GListModel *model)
+{
+ guint n_items_before;
+
+ g_return_if_fail (GTK_IS_SINGLE_SELECTION (self));
+ g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
+
+ if (self->model == model)
+ return;
+
+ g_object_freeze_notify (G_OBJECT (self));
+
+ n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
+ gtk_single_selection_clear_model (self);
+
+ if (model)
+ {
+ self->model = g_object_ref (model);
+ g_signal_connect (self->model, "items-changed",
+ G_CALLBACK (gtk_single_selection_items_changed_cb), self);
+ gtk_single_selection_items_changed_cb (self->model,
+ 0,
+ n_items_before,
+ g_list_model_get_n_items (model),
+ self);
+ }
+ else
+ {
+ if (self->selected != GTK_INVALID_LIST_POSITION)
+ {
+ self->selected = GTK_INVALID_LIST_POSITION;
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+ }
+ if (self->selected_item)
+ {
+ g_clear_object (&self->selected_item);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
+ }
+ g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, 0);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
+
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+/**
* gtk_single_selection_get_selected:
* @self: a #GtkSingleSelection
*
diff --git a/gtk/gtksingleselection.h b/gtk/gtksingleselection.h
index f9bbcae9e9..edfb1fe5c1 100644
--- a/gtk/gtksingleselection.h
+++ b/gtk/gtksingleselection.h
@@ -35,22 +35,25 @@ GtkSingleSelection * gtk_single_selection_new (GListModel
GDK_AVAILABLE_IN_ALL
GListModel * gtk_single_selection_get_model (GtkSingleSelection *self);
GDK_AVAILABLE_IN_ALL
-guint gtk_single_selection_get_selected (GtkSingleSelection *self);
+void gtk_single_selection_set_model (GtkSingleSelection *self,
+ GListModel *model);
GDK_AVAILABLE_IN_ALL
-void gtk_single_selection_set_selected (GtkSingleSelection *self,
- guint position);
+guint gtk_single_selection_get_selected (GtkSingleSelection *self);
GDK_AVAILABLE_IN_ALL
-gpointer gtk_single_selection_get_selected_item (GtkSingleSelection *self);
+void gtk_single_selection_set_selected (GtkSingleSelection *self,
+ guint position);
GDK_AVAILABLE_IN_ALL
-gboolean gtk_single_selection_get_autoselect (GtkSingleSelection *self);
+gpointer gtk_single_selection_get_selected_item (GtkSingleSelection *self);
GDK_AVAILABLE_IN_ALL
-void gtk_single_selection_set_autoselect (GtkSingleSelection *self,
- gboolean autoselect);
+gboolean gtk_single_selection_get_autoselect (GtkSingleSelection *self);
GDK_AVAILABLE_IN_ALL
-gboolean gtk_single_selection_get_can_unselect (GtkSingleSelection *self);
+void gtk_single_selection_set_autoselect (GtkSingleSelection *self,
+ gboolean autoselect);
GDK_AVAILABLE_IN_ALL
-void gtk_single_selection_set_can_unselect (GtkSingleSelection *self,
- gboolean can_unselect);
+gboolean gtk_single_selection_get_can_unselect (GtkSingleSelection *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_single_selection_set_can_unselect (GtkSingleSelection *self,
+ gboolean can_unselect);
G_END_DECLS
diff --git a/testsuite/gtk/multiselection.c b/testsuite/gtk/multiselection.c
index 1fd32bce71..970a6c4a6a 100644
--- a/testsuite/gtk/multiselection.c
+++ b/testsuite/gtk/multiselection.c
@@ -613,6 +613,59 @@ test_selection_filter (void)
g_object_unref (store);
g_object_unref (selection);
}
+
+static void
+test_set_model (void)
+{
+ GtkSelectionModel *selection;
+ GListStore *store;
+ GListModel *m1, *m2;
+ gboolean ret;
+
+ store = new_store (1, 5, 1);
+ m1 = G_LIST_MODEL (store);
+ m2 = G_LIST_MODEL (gtk_slice_list_model_new (m1, 0, 3));
+ selection = new_model (store);
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ ret = gtk_selection_model_select_range (selection, 1, 3, FALSE);
+ g_assert_true (ret);
+ assert_selection (selection, "2 3 4");
+ assert_selection_changes (selection, "1:3");
+
+ /* we retain the selected item across model changes */
+ gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
+ assert_changes (selection, "0-5+3");
+ assert_selection (selection, "2 3");
+ assert_selection_changes (selection, "");
+
+ gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), NULL);
+ assert_changes (selection, "0-3");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
+ assert_changes (selection, "0+3");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ ret = gtk_selection_model_select_all (selection);
+ g_assert_true (ret);
+ assert_selection (selection, "1 2 3");
+ assert_selection_changes (selection, "0:3");
+
+ /* we retain no selected item across model changes */
+ gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m1);
+ assert_changes (selection, "0-3+5");
+ assert_selection (selection, "1 2 3");
+ assert_selection_changes (selection, "");
+
+ g_object_unref (m2);
+ g_object_unref (m1);
+ g_object_unref (selection);
+}
+
int
main (int argc, char *argv[])
{
@@ -633,6 +686,7 @@ main (int argc, char *argv[])
g_test_add_func ("/multiselection/readd", test_readd);
g_test_add_func ("/multiselection/set_selection", test_set_selection);
g_test_add_func ("/multiselection/selection-filter", test_selection_filter);
+ g_test_add_func ("/multiselection/set-model", test_set_model);
return g_test_run ();
}
diff --git a/testsuite/gtk/singleselection.c b/testsuite/gtk/singleselection.c
index 81b96e90d0..90356345da 100644
--- a/testsuite/gtk/singleselection.c
+++ b/testsuite/gtk/singleselection.c
@@ -644,6 +644,57 @@ test_query_range (void)
g_object_unref (selection);
}
+static void
+test_set_model (void)
+{
+ GtkSelectionModel *selection;
+ GListStore *store;
+ GListModel *m1, *m2;
+
+ store = new_store (1, 5, 1);
+ m1 = G_LIST_MODEL (store);
+ m2 = G_LIST_MODEL (gtk_slice_list_model_new (m1, 0, 3));
+ selection = new_model (store, TRUE, TRUE);
+ assert_selection (selection, "1");
+ assert_selection_changes (selection, "");
+
+ /* we retain the selected item across model changes */
+ gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
+ assert_changes (selection, "0-5+3");
+ assert_selection (selection, "1");
+ assert_selection_changes (selection, "");
+
+ gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), NULL);
+ assert_changes (selection, "0-3");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
+ gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
+ assert_changes (selection, "0+3");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ /* we retain no selected item across model changes */
+ gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m1);
+ assert_changes (selection, "0-3+5");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (selection), 4);
+ assert_selection (selection, "5");
+ assert_selection_changes (selection, "4:1");
+
+ gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
+ assert_changes (selection, "0-5+3");
+ assert_selection (selection, "");
+ assert_selection_changes (selection, "");
+
+ g_object_unref (m2);
+ g_object_unref (m1);
+ g_object_unref (selection);
+}
+
int
main (int argc, char *argv[])
{
@@ -662,6 +713,7 @@ main (int argc, char *argv[])
g_test_add_func ("/singleselection/persistence", test_persistence);
g_test_add_func ("/singleselection/query-range", test_query_range);
g_test_add_func ("/singleselection/changes", test_changes);
+ g_test_add_func ("/singleselection/set-model", test_set_model);
return g_test_run ();
}