[gtk/wip/otte/listview: 59/199] Redo sort list model with GtkSorter



commit 0689106aff8affa1fd1683efecb338cdf6b3dcdf
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Dec 2 23:44:22 2019 -0500

    Redo sort list model with GtkSorter
    
    Reshuffle the api to take full advantage
    of GtkSorter. Update all callers.

 docs/reference/gtk/gtk4-sections.txt |   5 +-
 gtk/gtksortlistmodel.c               | 218 ++++++++++++++++++-----------------
 gtk/gtksortlistmodel.h               |  21 ++--
 gtk/inspector/controllers.c          |   8 +-
 testsuite/gtk/sortlistmodel.c        |  23 +++-
 5 files changed, 142 insertions(+), 133 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index d529b9f2bf..31e67e79d0 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -2654,11 +2654,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
 <SUBSECTION Standard>
 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 <gio/gio.h>
 #include <gtk/gtkwidget.h>
+#include <gtk/gtksorter.h>
 
 
 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 deea5b866f..353939100c 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
 {
@@ -214,6 +215,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));
@@ -234,9 +236,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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]