[gtk/prop-list] Add GtkColumnViewSorter



commit 1e55994e2ef999a1ebfd29d19edd8a5d668c342d
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Dec 3 16:30:05 2019 -0500

    Add GtkColumnViewSorter
    
    This is a sorter which will sort according to
    multiple sorters, allowing each individual sorter
    to be inverted. This will be used with clickable
    column view headers - whenever a header is clicked,
    that columns sorter is prepended to the list of
    sorters, unless it is already the first sorter, in
    which case we invert its order. No sorter can be
    more than once in the list.
    
    Use this in GtkColumnView.

 gtk/gtkcolumnview.c              |  40 +++-----
 gtk/gtkcolumnview.h              |   3 -
 gtk/gtkcolumnviewcolumn.c        |  20 +---
 gtk/gtkcolumnviewcolumnprivate.h |   3 +-
 gtk/gtkcolumnviewprivate.h       |   1 +
 gtk/gtkcolumnviewsorter.c        | 217 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkcolumnviewsorterprivate.h |  52 ++++++++++
 gtk/gtkcolumnviewtitle.c         |  46 ++++-----
 gtk/meson.build                  |   1 +
 9 files changed, 312 insertions(+), 71 deletions(-)
---
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 2995b236bc..d2f1c014e7 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -26,6 +26,7 @@
 #include "gtkcolumnlistitemfactoryprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
 #include "gtkcolumnviewlayoutprivate.h"
+#include "gtkcolumnviewsorterprivate.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkintl.h"
 #include "gtklistview.h"
@@ -377,10 +378,6 @@ gtk_column_view_set_property (GObject      *object,
       gtk_column_view_set_sort_model (self, g_value_get_object (value));
       break;
 
-    case PROP_SORTER:
-      gtk_column_view_set_sorter (self, g_value_get_object (value));
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -465,7 +462,7 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
                          P_("Sorter"),
                          P_("Sorter"),
                          GTK_TYPE_SORTER,
-                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+                         G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
 
@@ -506,6 +503,7 @@ gtk_column_view_init (GtkColumnView *self)
   gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self));
   gtk_widget_set_parent (self->header, GTK_WIDGET (self));
 
+  self->sorter = gtk_column_view_sorter_new ();
   self->factory = gtk_column_list_item_factory_new (self);
   self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory (
         GTK_LIST_ITEM_FACTORY (g_object_ref (self->factory))));
@@ -681,6 +679,7 @@ gtk_column_view_remove_column (GtkColumnView       *self,
         break;
     }
 
+  gtk_column_view_sorter_remove_sorter (self->sorter, gtk_column_view_column_get_sorter (column));
   gtk_column_view_column_set_column_view (column, NULL);
   g_list_store_remove (self->columns, i);
 }
@@ -735,34 +734,23 @@ gtk_column_view_set_sort_model (GtkColumnView *self,
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORT_MODEL]);
 }
 
-void
-gtk_column_view_set_sorter (GtkColumnView *self,
-                            GtkSorter     *sorter)
+GtkSorter *
+gtk_column_view_get_sorter (GtkColumnView *self)
 {
-  int i;
-
-  g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
-  g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), NULL);
 
-  if (!g_set_object (&self->sorter, sorter))
-    return;
+  return self->sorter;
+}
 
-  if (self->sort_model)
-    gtk_sort_list_model_set_sorter (self->sort_model, self->sorter);
+void
+gtk_column_view_active_sorter_changed (GtkColumnView *self)
+{
+  guint i;
 
   for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
     {
       GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
       gtk_column_view_column_active_sorter_changed (column);
+      g_object_unref (column);
     }
-
-  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
-}
-
-GtkSorter *
-gtk_column_view_get_sorter (GtkColumnView *self)
-{
-  g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), NULL);
-
-  return self->sorter;
 }
diff --git a/gtk/gtkcolumnview.h b/gtk/gtkcolumnview.h
index 2b5136d572..178c856b3b 100644
--- a/gtk/gtkcolumnview.h
+++ b/gtk/gtkcolumnview.h
@@ -78,9 +78,6 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_column_view_set_sort_model                  (GtkColumnView          *self,
                                                                  GtkSortListModel       *model);
 GDK_AVAILABLE_IN_ALL
-void            gtk_column_view_set_sorter                      (GtkColumnView          *self,
-                                                                 GtkSorter              *sorter);
-GDK_AVAILABLE_IN_ALL
 GtkSorter *     gtk_column_view_get_sorter                      (GtkColumnView          *self);
 
 G_END_DECLS
diff --git a/gtk/gtkcolumnviewcolumn.c b/gtk/gtkcolumnviewcolumn.c
index 8f90f0b1f1..17a1c56293 100644
--- a/gtk/gtkcolumnviewcolumn.c
+++ b/gtk/gtkcolumnviewcolumn.c
@@ -32,7 +32,7 @@
 #include "gtksizegroup.h"
 #include "gtkstylecontext.h"
 #include "gtkwidgetprivate.h"
-#include "gtkinvertiblesorter.h"
+#include "gtksorter.h"
 
 /**
  * SECTION:gtkcolumnviewcolumn
@@ -49,7 +49,7 @@ struct _GtkColumnViewColumn
 
   GtkListItemFactory *factory;
   char *title;
-  GtkInvertibleSorter *sorter;
+  GtkSorter *sorter;
 
   /* data for the view */
   GtkColumnView *view;
@@ -122,7 +122,7 @@ gtk_column_view_column_get_property (GObject    *object,
       break;
 
     case PROP_SORTER:
-      g_value_set_object (value, gtk_invertible_sorter_get_sorter (self->sorter));
+      g_value_set_object (value, self->sorter);
       break;
 
     default:
@@ -219,8 +219,6 @@ gtk_column_view_column_init (GtkColumnViewColumn *self)
 {
   self->minimum_size_request = -1;
   self->natural_size_request = -1;
-
-  self->sorter = GTK_INVERTIBLE_SORTER (gtk_invertible_sorter_new (NULL));
 }
 
 /**
@@ -580,11 +578,9 @@ gtk_column_view_column_set_sorter (GtkColumnViewColumn *self,
   g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
   g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
 
-  if (gtk_invertible_sorter_get_sorter (self->sorter) == sorter)
+  if (!g_set_object (&self->sorter, sorter))
     return;
 
-  gtk_invertible_sorter_set_sorter (self->sorter, sorter);
-
   if (self->header)
     gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
 
@@ -596,7 +592,7 @@ gtk_column_view_column_get_sorter (GtkColumnViewColumn *self)
 {
   g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
 
-  return gtk_invertible_sorter_get_sorter (self->sorter);
+  return self->sorter;
 }
 
 void
@@ -605,9 +601,3 @@ gtk_column_view_column_active_sorter_changed (GtkColumnViewColumn *self)
   if (self->header)
     gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
 }
-
-GtkInvertibleSorter *
-gtk_column_view_column_get_invertible_sorter (GtkColumnViewColumn *self)
-{
-  return self->sorter;
-}
diff --git a/gtk/gtkcolumnviewcolumnprivate.h b/gtk/gtkcolumnviewcolumnprivate.h
index 203acbc7dd..5afeffad4f 100644
--- a/gtk/gtkcolumnviewcolumnprivate.h
+++ b/gtk/gtkcolumnviewcolumnprivate.h
@@ -23,7 +23,7 @@
 #include "gtk/gtkcolumnviewcolumn.h"
 
 #include "gtk/gtkcolumnviewcellprivate.h"
-#include "gtk/gtkinvertiblesorter.h"
+
 
 void                    gtk_column_view_column_set_column_view          (GtkColumnViewColumn    *self,
                                                                          GtkColumnView          *view);
@@ -45,6 +45,5 @@ void                    gtk_column_view_column_get_allocation           (GtkColu
                                                                          int                    *offset,
                                                                          int                    *size);
 void                    gtk_column_view_column_active_sorter_changed    (GtkColumnViewColumn    *self);
-GtkInvertibleSorter *   gtk_column_view_column_get_invertible_sorter    (GtkColumnViewColumn    *Self);
 
 #endif  /* __GTK_COLUMN_VIEW_COLUMN_PRIVATE_H__ */
diff --git a/gtk/gtkcolumnviewprivate.h b/gtk/gtkcolumnviewprivate.h
index c356fae508..ee4a7675ba 100644
--- a/gtk/gtkcolumnviewprivate.h
+++ b/gtk/gtkcolumnviewprivate.h
@@ -29,5 +29,6 @@ GtkListItemWidget *     gtk_column_view_get_header_widget       (GtkColumnView
 void                    gtk_column_view_measure_across          (GtkColumnView          *self,
                                                                  int                    *minimum,
                                                                  int                    *natural);
+void                    gtk_column_view_active_sorter_changed   (GtkColumnView          *self);
 
 #endif  /* __GTK_COLUMN_VIEW_PRIVATE_H__ */
diff --git a/gtk/gtkcolumnviewsorter.c b/gtk/gtkcolumnviewsorter.c
new file mode 100644
index 0000000000..685f9ce0df
--- /dev/null
+++ b/gtk/gtkcolumnviewsorter.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtkcolumnviewsorterprivate.h"
+
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+typedef struct
+{
+  GtkSorter *sorter;
+  gboolean   inverted;
+  gulong     changed_id;
+} Sorter;
+ 
+struct _GtkColumnViewSorter
+{
+  GtkSorter parent_instance;
+
+  GArray *sorters;
+};
+
+G_DEFINE_TYPE (GtkColumnViewSorter, gtk_column_view_sorter, GTK_TYPE_SORTER)
+
+static int
+gtk_column_view_sorter_compare (GtkSorter *sorter,
+                                gpointer   item1,
+                                gpointer   item2)
+{
+  GtkColumnViewSorter *self = GTK_COLUMN_VIEW_SORTER (sorter);
+  int result = 0;
+  int i;
+
+  for (i = 0; i < self->sorters->len; i++)
+    {
+      Sorter *s = &g_array_index (self->sorters, Sorter, i);
+
+      result = gtk_sorter_compare (s->sorter, item1, item2);
+      if (s->inverted)
+        result = - result;
+
+      if (result != 0)
+        break;
+    }
+
+  return result;
+}
+
+static void changed_cb (GtkSorter *sorter, int change, gpointer data);
+
+static void
+gtk_column_view_sorter_dispose (GObject *object)
+{
+  GtkColumnViewSorter *self = GTK_COLUMN_VIEW_SORTER (object);
+
+  g_clear_pointer (&self->sorters, g_array_unref);
+
+  G_OBJECT_CLASS (gtk_column_view_sorter_parent_class)->dispose (object);
+}
+
+static void
+gtk_column_view_sorter_class_init (GtkColumnViewSorterClass *class)
+{
+  GtkSorterClass *sorter_class = GTK_SORTER_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  sorter_class->compare = gtk_column_view_sorter_compare;
+
+  object_class->dispose = gtk_column_view_sorter_dispose;
+}
+
+static void
+clear_sorter (gpointer data)
+{
+  Sorter *s = data;
+
+  g_signal_handler_disconnect (s->sorter, s->changed_id);
+  g_object_unref (s->sorter);
+}
+
+static void
+create_sorters (GtkColumnViewSorter *self)
+{
+  self->sorters = g_array_new (FALSE, TRUE, sizeof (Sorter));
+  g_array_set_clear_func (self->sorters, clear_sorter);
+}
+
+static void
+gtk_column_view_sorter_init (GtkColumnViewSorter *self)
+{
+  create_sorters (self);
+}
+
+GtkSorter *
+gtk_column_view_sorter_new (void)
+{
+  return g_object_new (GTK_TYPE_COLUMN_VIEW_SORTER, NULL);
+}
+
+static void
+changed_cb (GtkSorter *sorter, int change, gpointer data)
+{
+  gtk_sorter_changed (GTK_SORTER (data), GTK_SORTER_CHANGE_DIFFERENT);
+}
+
+void
+gtk_column_view_sorter_add_sorter (GtkColumnViewSorter *self,
+                                   GtkSorter           *sorter)
+{
+  Sorter data;
+  Sorter *s;
+  Sorter *s1;
+  int i, j;
+
+  g_return_if_fail (GTK_IS_COLUMN_VIEW_SORTER (self));
+
+  if (self->sorters->len > 0)
+    {
+      s = &g_array_index (self->sorters, Sorter, 0);
+      if (s->sorter == sorter)
+        {
+          s->inverted = !s->inverted;
+          goto out;
+        }
+
+      for (i = 1; i < self->sorters->len; i++)
+        {
+          s = &g_array_index (self->sorters, Sorter, i);
+          if (s->sorter == sorter)
+            {
+              for (j = i - 1; j >= 0; j--)
+                {
+                  s1 = &g_array_index (self->sorters, Sorter, j);
+                  s->sorter = s1->sorter;
+                  s->inverted = s1->inverted;
+                  s = s1;
+                }
+
+              s1->sorter = sorter;
+              s1->inverted = FALSE;
+              goto out;
+            }
+        }
+    }
+
+  data.sorter = g_object_ref (sorter);
+  data.changed_id = g_signal_connect (sorter, "changed", G_CALLBACK (changed_cb), self);
+  data.inverted = FALSE;
+  g_array_append_vals (self->sorters, &data, 1);
+
+out:
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+}
+
+void
+gtk_column_view_sorter_remove_sorter (GtkColumnViewSorter *self,
+                                      GtkSorter           *sorter)
+{
+  int i;
+
+  for (i = 0; i < self->sorters->len; i++)
+    {
+      Sorter *s = &g_array_index (self->sorters, Sorter, i);
+      if (s->sorter == sorter)
+        {
+          g_array_remove_index (self->sorters, i);
+          gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+          break;
+        }
+    }
+}
+
+void
+gtk_column_view_sorter_reset (GtkColumnViewSorter *self)
+{
+  if (self->sorters->len == 0)
+    return;
+
+  g_array_unref (self->sorters);
+  create_sorters (self);
+
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+}
+
+GtkSorter *
+gtk_column_view_sorter_get_active (GtkColumnViewSorter *self,
+                                   gboolean            *inverted)
+{
+  Sorter *s;
+
+  if (self->sorters->len == 0)
+    return NULL;
+
+  s = &g_array_index (self->sorters, Sorter, 0);
+
+  *inverted = s->inverted;
+
+  return s->sorter;
+}
diff --git a/gtk/gtkcolumnviewsorterprivate.h b/gtk/gtkcolumnviewsorterprivate.h
new file mode 100644
index 0000000000..b81f1ad76e
--- /dev/null
+++ b/gtk/gtkcolumnviewsorterprivate.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_COLUMN_VIEW_SORTER_H__
+#define __GTK_COLUMN_VIEW_SORTER_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+#include <gtk/gtksorter.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_SORTER             (gtk_column_view_sorter_get_type ())
+
+G_DECLARE_FINAL_TYPE (GtkColumnViewSorter, gtk_column_view_sorter, GTK, COLUMN_VIEW_SORTER, GtkSorter)
+
+GtkSorter * gtk_column_view_sorter_new (void);
+
+void        gtk_column_view_sorter_add_sorter    (GtkColumnViewSorter *self,
+                                                  GtkSorter           *sorter);
+void        gtk_column_view_sorter_remove_sorter (GtkColumnViewSorter *self,
+                                                  GtkSorter           *sorter);
+
+void        gtk_column_view_sorter_reset         (GtkColumnViewSorter *self);
+
+GtkSorter  *gtk_column_view_sorter_get_active     (GtkColumnViewSorter *self,
+                                                   gboolean            *inverted);
+
+
+G_END_DECLS
+
+#endif /* __GTK_SORTER_H__ */
+
diff --git a/gtk/gtkcolumnviewtitle.c b/gtk/gtkcolumnviewtitle.c
index 8b780e359b..a9b8bcefa6 100644
--- a/gtk/gtkcolumnviewtitle.c
+++ b/gtk/gtkcolumnviewtitle.c
@@ -21,7 +21,9 @@
 
 #include "gtkcolumnviewtitleprivate.h"
 
+#include "gtkcolumnviewprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
+#include "gtkcolumnviewsorterprivate.h"
 #include "gtkintl.h"
 #include "gtklabel.h"
 #include "gtkwidgetprivate.h"
@@ -117,26 +119,15 @@ click_pressed_cb (GtkGestureClick *gesture,
                   GtkWidget       *widget)
 {
   GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
-  GtkInvertibleSorter *sorter;
-  GtkSorter *active_sorter;
-
-  sorter = gtk_column_view_column_get_invertible_sorter (self->column);
-  active_sorter = gtk_column_view_get_sorter (gtk_column_view_column_get_column_view (self->column));
-
-  if (sorter)
-    {
-      if (GTK_SORTER (sorter) == active_sorter)
-        {
-          gtk_invertible_sorter_set_direction (sorter, 1 - gtk_invertible_sorter_get_direction (sorter));
-        }
-      else
-        {
-          gtk_invertible_sorter_set_direction (sorter, GTK_SORT_ASCENDING);
-          gtk_column_view_set_sorter (gtk_column_view_column_get_column_view (self->column), GTK_SORTER 
(sorter));
-        }
-    }
-
-  gtk_column_view_title_update (self);
+  GtkSorter *sorter;
+  GtkColumnView *view;
+  GtkColumnViewSorter *view_sorter;
+
+  sorter = gtk_column_view_column_get_sorter (self->column);
+  view = gtk_column_view_column_get_column_view (self->column);
+  view_sorter = GTK_COLUMN_VIEW_SORTER (gtk_column_view_get_sorter (view));
+  gtk_column_view_sorter_add_sorter (view_sorter, sorter);
+  gtk_column_view_active_sorter_changed (view);
 }
 
 static void
@@ -177,20 +168,25 @@ gtk_column_view_title_new (GtkColumnViewColumn *column)
 void
 gtk_column_view_title_update (GtkColumnViewTitle *self)
 {
-  GtkInvertibleSorter *sorter;
+  GtkSorter *sorter;
   GtkSorter *active_sorter;
+  GtkColumnView *view;
+  GtkColumnViewSorter *view_sorter;
+  gboolean inverted;
 
   gtk_label_set_label (GTK_LABEL (self->title), gtk_column_view_column_get_title (self->column));
 
-  sorter = gtk_column_view_column_get_invertible_sorter (self->column);
-  active_sorter = gtk_column_view_get_sorter (gtk_column_view_column_get_column_view (self->column));
+  sorter = gtk_column_view_column_get_sorter (self->column);
+  view = gtk_column_view_column_get_column_view (self->column);
+  view_sorter = GTK_COLUMN_VIEW_SORTER (gtk_column_view_get_sorter (view));
+  active_sorter = gtk_column_view_sorter_get_active (view_sorter, &inverted);
 
   if (sorter)
     {
       gtk_widget_show (self->sort);
-      if (GTK_SORTER (sorter) == active_sorter)
+      if (sorter == active_sorter)
         {
-          if (gtk_invertible_sorter_get_direction (sorter) == GTK_SORT_ASCENDING)
+          if (inverted)
             gtk_image_set_from_icon_name (GTK_IMAGE (self->sort), "pan-down-symbolic");
           else
             gtk_image_set_from_icon_name (GTK_IMAGE (self->sort), "pan-up-symbolic");
diff --git a/gtk/meson.build b/gtk/meson.build
index 98b304bc0c..fc4a6c7533 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -213,6 +213,7 @@ gtk_public_sources = files([
   'gtkcolorutils.c',
   'gtkcolumnview.c',
   'gtkcolumnviewcolumn.c',
+  'gtkcolumnviewsorter.c',
   'gtkcombobox.c',
   'gtkcomboboxtext.c',
   'gtkcomposetable.c',


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