diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index c54826ffb2..1765f97f71 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -2517,11 +2517,10 @@ gtk_multi_sorter_get_type GtkSortListModel gtk_sort_list_model_new gtk_sort_list_model_new_for_type -gtk_sort_list_model_set_sort_func -gtk_sort_list_model_has_sort +gtk_sort_list_model_set_sorter +gtk_sort_list_model_get_sorter gtk_sort_list_model_set_model gtk_sort_list_model_get_model -gtk_sort_list_model_resort GTK_SORT_LIST_MODEL GTK_IS_SORT_LIST_MODEL diff --git a/gtk/gtksortlistmodel.c b/gtk/gtksortlistmodel.c index ac82bb146a..fc88d6de70 100644 --- a/gtk/gtksortlistmodel.c +++ b/gtk/gtksortlistmodel.c @@ -28,10 +28,10 @@ * SECTION:gtksortlistmodel * @title: GtkSortListModel * @short_description: A list model that sorts its items - * @see_also: #GListModel + * @see_also: #GListModel, #GtkSorter * * #GtkSortListModel is a list model that takes a list model and - * sorts its elements according to a compare function. + * sorts its elements according to a #GtkSorter. * * #GtkSortListModel is a generic model and because of that it * cannot take advantage of any external knowledge when sorting. @@ -42,9 +42,9 @@ enum { PROP_0, - PROP_HAS_SORT, PROP_ITEM_TYPE, PROP_MODEL, + PROP_SORTER, NUM_PROPERTIES }; @@ -54,9 +54,7 @@ struct _GtkSortListModel GType item_type; GListModel *model; - GCompareDataFunc sort_func; - gpointer user_data; - GDestroyNotify user_destroy; + GtkSorter *sorter; GSequence *sorted; /* NULL if sort_func == NULL */ GSequence *unsorted; /* NULL if sort_func == NULL */ @@ -157,6 +155,14 @@ gtk_sort_list_model_remove_items (GtkSortListModel *self, *unmodified_end = end; } +static int +_sort_func (gconstpointer item1, + gconstpointer item2, + gpointer data) +{ + return gtk_sorter_compare (GTK_SORTER (data), (gpointer)item1, (gpointer)item2); +} + static void gtk_sort_list_model_add_items (GtkSortListModel *self, guint position, @@ -173,7 +179,7 @@ gtk_sort_list_model_add_items (GtkSortListModel *self, for (i = 0; i < n_items; i++) { gpointer item = g_list_model_get_item (self->model, position + i); - sorted_iter = g_sequence_insert_sorted (self->sorted, item, self->sort_func, self->user_data); + sorted_iter = g_sequence_insert_sorted (self->sorted, item, _sort_func, self->sorter); g_sequence_insert_before (unsorted_iter, sorted_iter); if (unmodified_start != NULL || unmodified_end != NULL) { @@ -234,6 +240,10 @@ gtk_sort_list_model_set_property (GObject *object, gtk_sort_list_model_set_model (self, g_value_get_object (value)); break; + case PROP_SORTER: + gtk_sort_list_model_set_sorter (self, g_value_get_object (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -250,10 +260,6 @@ gtk_sort_list_model_get_property (GObject *object, switch (prop_id) { - case PROP_HAS_SORT: - g_value_set_boolean (value, self->sort_func != NULL); - break; - case PROP_ITEM_TYPE: g_value_set_gtype (value, self->item_type); break; @@ -262,12 +268,26 @@ gtk_sort_list_model_get_property (GObject *object, g_value_set_object (value, self->model); break; + case PROP_SORTER: + g_value_set_object (value, self->sorter); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static void gtk_sort_list_model_resort (GtkSortListModel *self); + +static void +gtk_sort_list_model_sorter_changed_cb (GtkSorter *sorter, + int change, + GtkSortListModel *self) +{ + gtk_sort_list_model_resort (self); +} + static void gtk_sort_list_model_clear_model (GtkSortListModel *self) { @@ -280,17 +300,23 @@ gtk_sort_list_model_clear_model (GtkSortListModel *self) g_clear_pointer (&self->unsorted, g_sequence_free); } +static void +gtk_sort_list_model_clear_sorter (GtkSortListModel *self) +{ + if (self->sorter == NULL) + return; + + g_signal_handlers_disconnect_by_func (self->sorter, gtk_sort_list_model_sorter_changed_cb, self); + g_clear_object (&self->sorter); +} + static void gtk_sort_list_model_dispose (GObject *object) { GtkSortListModel *self = GTK_SORT_LIST_MODEL (object); gtk_sort_list_model_clear_model (self); - if (self->user_destroy) - self->user_destroy (self->user_data); - self->sort_func = NULL; - self->user_data = NULL; - self->user_destroy = NULL; + gtk_sort_list_model_clear_sorter (self); G_OBJECT_CLASS (gtk_sort_list_model_parent_class)->dispose (object); }; @@ -305,16 +331,16 @@ gtk_sort_list_model_class_init (GtkSortListModelClass *class) gobject_class->dispose = gtk_sort_list_model_dispose; /** - * GtkSortListModel:has-sort: + * GtkSortListModel:sorter: * - * If a sort function is set for this model + * The sorter for this model */ - properties[PROP_HAS_SORT] = - g_param_spec_boolean ("has-sort", - P_("has sort"), - P_("If a sort function is set for this model"), - FALSE, - GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY); + properties[PROP_SORTER] = + g_param_spec_object ("sorter", + P_("Sorter"), + P_("The sorter for this model"), + GTK_TYPE_SORTER, + GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** * GtkSortListModel:item-type: @@ -348,36 +374,30 @@ gtk_sort_list_model_init (GtkSortListModel *self) { } - /** * gtk_sort_list_model_new: * @model: the model to sort - * @sort_func: (allow-none): sort function or %NULL to not sort items - * @user_data: (closure): user data passed to @sort_func - * @user_destroy: destroy notifier for @user_data + * @sorter: (allow-none): the #GtkSorter to sort @model with * - * Creates a new sort list model that uses the @sort_func to sort @model. + * Creates a new sort list model that uses the @sorter to sort @model. * * Returns: a new #GtkSortListModel **/ GtkSortListModel * -gtk_sort_list_model_new (GListModel *model, - GCompareDataFunc sort_func, - gpointer user_data, - GDestroyNotify user_destroy) +gtk_sort_list_model_new (GListModel *model, + GtkSorter *sorter) { GtkSortListModel *result; g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL); + g_return_val_if_fail (sorter == NULL || GTK_IS_SORTER (sorter), NULL); result = g_object_new (GTK_TYPE_SORT_LIST_MODEL, "item-type", g_list_model_get_item_type (model), "model", model, + "sorter", sorter, NULL); - if (sort_func) - gtk_sort_list_model_set_sort_func (result, sort_func, user_data, user_destroy); - return result; } @@ -404,7 +424,7 @@ gtk_sort_list_model_new_for_type (GType item_type) static void gtk_sort_list_model_create_sequences (GtkSortListModel *self) { - if (!self->sort_func || self->model == NULL) + if (self->sorter == NULL || self->model == NULL) return; self->sorted = g_sequence_new (g_object_unref); @@ -413,50 +433,6 @@ gtk_sort_list_model_create_sequences (GtkSortListModel *self) gtk_sort_list_model_add_items (self, 0, g_list_model_get_n_items (self->model), NULL, NULL); } -/** - * gtk_sort_list_model_set_sort_func: - * @self: a #GtkSortListModel - * @sort_func: (allow-none): sort function or %NULL to not sort items - * @user_data: (closure): user data passed to @sort_func - * @user_destroy: destroy notifier for @user_data - * - * Sets the function used to sort items. The function will be called for every - * item and must return an integer less than, equal to, or greater than zero if - * for two items from the model if the first item is considered to be respectively - * less than, equal to, or greater than the second. - **/ -void -gtk_sort_list_model_set_sort_func (GtkSortListModel *self, - GCompareDataFunc sort_func, - gpointer user_data, - GDestroyNotify user_destroy) -{ - guint n_items; - - g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self)); - g_return_if_fail (sort_func != NULL || (user_data == NULL && !user_destroy)); - - if (!sort_func && !self->sort_func) - return; - - if (self->user_destroy) - self->user_destroy (self->user_data); - - g_clear_pointer (&self->unsorted, g_sequence_free); - g_clear_pointer (&self->sorted, g_sequence_free); - self->sort_func = sort_func; - self->user_data = user_data; - self->user_destroy = user_destroy; - - gtk_sort_list_model_create_sequences (self); - - n_items = g_list_model_get_n_items (G_LIST_MODEL (self)); - if (n_items > 1) - g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_SORT]); -} - /** * gtk_sort_list_model_set_model: * @self: a #GtkSortListModel @@ -517,32 +493,7 @@ gtk_sort_list_model_get_model (GtkSortListModel *self) return self->model; } -/** - * gtk_sort_list_model_has_sort: - * @self: a #GtkSortListModel - * - * Checks if a sort function is currently set on @self - * - * Returns: %TRUE if a sort function is set - **/ -gboolean -gtk_sort_list_model_has_sort (GtkSortListModel *self) -{ - g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), FALSE); - - return self->sort_func != NULL; -} - -/** - * gtk_sort_list_model_resort: - * @self: a #GtkSortListModel - * - * Causes @self to resort all items in the model. - * - * Calling this function is necessary when data used by the sort - * function has changed. - **/ -void +static void gtk_sort_list_model_resort (GtkSortListModel *self) { guint n_items; @@ -556,8 +507,59 @@ gtk_sort_list_model_resort (GtkSortListModel *self) if (n_items <= 1) return; - g_sequence_sort (self->sorted, self->sort_func, self->user_data); + g_sequence_sort (self->sorted, _sort_func, self->sorter); g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items); } +/** + * gtk_sort_list_model_set_sorter: + * @self: a #GtkSortListModel + * @sorter: (allow-none): the #GtkSorter to sort @model with + * + * Sets a new sorter on @self. + */ +void +gtk_sort_list_model_set_sorter (GtkSortListModel *self, + GtkSorter *sorter) +{ + guint n_items; + + g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self)); + g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter)); + + gtk_sort_list_model_clear_sorter (self); + + if (sorter) + { + self->sorter = g_object_ref (sorter); + g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sort_list_model_sorter_changed_cb), self); + } + + g_clear_pointer (&self->unsorted, g_sequence_free); + g_clear_pointer (&self->sorted, g_sequence_free); + + gtk_sort_list_model_create_sequences (self); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (self)); + if (n_items > 1) + g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]); +} + +/** + * gtk_sort_list_model_get_sorter: + * @self: a #GtkSortLisTModel + * + * Gets the sorter that is used to sort @self. + * + * Returns: (nullable) (transfer none): the sorter of #self + */ +GtkSorter * +gtk_sort_list_model_get_sorter (GtkSortListModel *self) +{ + g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), NULL); + + return self->sorter; +} diff --git a/gtk/gtksortlistmodel.h b/gtk/gtksortlistmodel.h index 2fbc465dcb..3e009502e2 100644 --- a/gtk/gtksortlistmodel.h +++ b/gtk/gtksortlistmodel.h @@ -27,6 +27,7 @@ #include #include +#include G_BEGIN_DECLS @@ -37,29 +38,23 @@ GDK_AVAILABLE_IN_ALL G_DECLARE_FINAL_TYPE (GtkSortListModel, gtk_sort_list_model, GTK, SORT_LIST_MODEL, GObject) GDK_AVAILABLE_IN_ALL -GtkSortListModel * gtk_sort_list_model_new (GListModel *model, - GCompareDataFunc sort_func, - gpointer user_data, - GDestroyNotify user_destroy); +GtkSortListModel * gtk_sort_list_model_new (GListModel *model, + GtkSorter *sorter); GDK_AVAILABLE_IN_ALL -GtkSortListModel * gtk_sort_list_model_new_for_type (GType item_type); +GtkSortListModel * gtk_sort_list_model_new_for_type (GType item_type); GDK_AVAILABLE_IN_ALL -void gtk_sort_list_model_set_sort_func (GtkSortListModel *self, - GCompareDataFunc sort_func, - gpointer user_data, - GDestroyNotify user_destroy); +void gtk_sort_list_model_set_sorter (GtkSortListModel *self, + GtkSorter *sorter); GDK_AVAILABLE_IN_ALL -gboolean gtk_sort_list_model_has_sort (GtkSortListModel *self); +GtkSorter * gtk_sort_list_model_get_sorter (GtkSortListModel *self); + GDK_AVAILABLE_IN_ALL void gtk_sort_list_model_set_model (GtkSortListModel *self, GListModel *model); GDK_AVAILABLE_IN_ALL GListModel * gtk_sort_list_model_get_model (GtkSortListModel *self); -GDK_AVAILABLE_IN_ALL -void gtk_sort_list_model_resort (GtkSortListModel *self); - G_END_DECLS #endif /* __GTK_SORT_LIST_MODEL_H__ */ diff --git a/gtk/inspector/controllers.c b/gtk/inspector/controllers.c index 64063508a6..2e926675d7 100644 --- a/gtk/inspector/controllers.c +++ b/gtk/inspector/controllers.c @@ -35,6 +35,7 @@ #include "gtkwidgetprivate.h" #include "gtkstack.h" #include "gtkstylecontext.h" +#include "gtkcustomsorter.h" enum { @@ -217,6 +218,7 @@ gtk_inspector_controllers_set_object (GtkInspectorControllers *sl, GtkMapListModel *map_model; GtkFlattenListModel *flatten_model; GtkSortListModel *sort_model; + GtkSorter *sorter; stack = gtk_widget_get_parent (GTK_WIDGET (sl)); page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl)); @@ -237,9 +239,9 @@ gtk_inspector_controllers_set_object (GtkInspectorControllers *sl, flatten_model = gtk_flatten_list_model_new (GTK_TYPE_EVENT_CONTROLLER, G_LIST_MODEL (map_model)); - sort_model = gtk_sort_list_model_new (G_LIST_MODEL (flatten_model), - compare_controllers, - NULL, NULL); + sorter = gtk_custom_sorter_new (compare_controllers, NULL, NULL); + sort_model = gtk_sort_list_model_new (G_LIST_MODEL (flatten_model), sorter); + g_object_unref (sorter); gtk_list_box_bind_model (GTK_LIST_BOX (priv->listbox), G_LIST_MODEL (sort_model), diff --git a/testsuite/gtk/sortlistmodel.c b/testsuite/gtk/sortlistmodel.c index 1fb430aafb..e0ed7e37df 100644 --- a/testsuite/gtk/sortlistmodel.c +++ b/testsuite/gtk/sortlistmodel.c @@ -195,7 +195,13 @@ new_model (gpointer model) g_assert (model == NULL || G_IS_LIST_MODEL (model)); if (model) - result = gtk_sort_list_model_new (model, compare, NULL, NULL); + { + GtkSorter *sorter; + + sorter = gtk_custom_sorter_new (compare, NULL, NULL); + result = gtk_sort_list_model_new (model, sorter); + g_object_unref (sorter); + } else result = gtk_sort_list_model_new_for_type (G_TYPE_OBJECT); @@ -275,9 +281,10 @@ test_set_model (void) } static void -test_set_sort_func (void) +test_set_sorter (void) { GtkSortListModel *sort; + GtkSorter *sorter; GListStore *store; store = new_store ((guint[]) { 4, 8, 2, 6, 10, 0 }); @@ -285,15 +292,19 @@ test_set_sort_func (void) assert_model (sort, "2 4 6 8 10"); assert_changes (sort, ""); - gtk_sort_list_model_set_sort_func (sort, compare_modulo, GUINT_TO_POINTER (5), NULL); + sorter = gtk_custom_sorter_new (compare_modulo, GUINT_TO_POINTER (5), NULL); + gtk_sort_list_model_set_sorter (sort, sorter); + g_object_unref (sorter); assert_model (sort, "10 6 2 8 4"); assert_changes (sort, "0-5+5"); - gtk_sort_list_model_set_sort_func (sort, NULL, NULL, NULL); + gtk_sort_list_model_set_sorter (sort, NULL); assert_model (sort, "4 8 2 6 10"); assert_changes (sort, "0-5+5"); - gtk_sort_list_model_set_sort_func (sort, compare, NULL, NULL); + sorter = gtk_custom_sorter_new (compare, NULL, NULL); + gtk_sort_list_model_set_sorter (sort, sorter); + g_object_unref (sorter); assert_model (sort, "2 4 6 8 10"); /* Technically, this is correct, but we shortcut setting the sort func: * assert_changes (sort, "0-4+4"); */ @@ -395,7 +406,7 @@ main (int argc, char *argv[]) g_test_add_func ("/sortlistmodel/create_empty", test_create_empty); g_test_add_func ("/sortlistmodel/create", test_create); g_test_add_func ("/sortlistmodel/set-model", test_set_model); - g_test_add_func ("/sortlistmodel/set-sort-func", test_set_sort_func); + g_test_add_func ("/sortlistmodel/set-sorter", test_set_sorter); #if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */ g_test_add_func ("/sortlistmodel/add_items", test_add_items); g_test_add_func ("/sortlistmodel/remove_items", test_remove_items);