summaryrefslogtreecommitdiff
path: root/gtk/gtksorter.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-12-02 23:43:14 -0500
committerMatthias Clasen <mclasen@redhat.com>2020-05-30 17:48:44 -0400
commitb2b847f3657eeac02f18797a6757cb9325d9bc19 (patch)
treee5f8f97c6c20573706c260e124905a9510ee9ca7 /gtk/gtksorter.c
parentcb15ec0257830b267c1027b0a10e21fdfc20d979 (diff)
downloadgtk+-b2b847f3657eeac02f18797a6757cb9325d9bc19.tar.gz
Add GtkSorter
This is a helper object for sorting, similar to GtkFilter.
Diffstat (limited to 'gtk/gtksorter.c')
-rw-r--r--gtk/gtksorter.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/gtk/gtksorter.c b/gtk/gtksorter.c
new file mode 100644
index 0000000000..22ef6c4644
--- /dev/null
+++ b/gtk/gtksorter.c
@@ -0,0 +1,207 @@
+/*
+ * 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 "gtksorter.h"
+
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+/**
+ * SECTION:gtksorter
+ * @title: GtkSorter
+ * @Short_description: Sorting items
+ * @See_also: #GtkSortListModel
+ *
+ * #GtkSorter is the way to describe sorting criteria.
+ * Its primary user is #GtkSortListModel.
+ *
+ * The model will use a sorter to determine the order in which its items should appear
+ * by calling gtk_sorter_compare() for pairs of items.
+ *
+ * Sorters may change their sorting behavior through their lifetime. In that case,
+ * they call gtk_sorter_changed(), which will emit the #GtkSorter::changed signal to
+ * notify that the sort order is no longer valid and should be updated by calling
+ * gtk_sorter_compare() again.
+ *
+ * GTK provides various pre-made sorter implementations for common sorting operations.
+ * #GtkColumnView has built-in support for sorting lists via the #GtkColumnViewColumn:sorter
+ * property, where the user can change the sorting by clicking on list headers.
+ *
+ * Of course, in particular for large lists, it is also possible to subclass #GtkSorter
+ * and provide one's own sorter.
+ */
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+G_DEFINE_TYPE (GtkSorter, gtk_sorter, G_TYPE_OBJECT)
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static GtkOrdering
+gtk_sorter_default_compare (GtkSorter *self,
+ gpointer item1,
+ gpointer item2)
+{
+ g_critical ("Sorter of type '%s' does not implement GtkSorter::compare", G_OBJECT_TYPE_NAME (self));
+
+ return GTK_ORDERING_EQUAL;
+}
+
+static GtkSorterOrder
+gtk_sorter_default_get_order (GtkSorter *self)
+{
+ return GTK_SORTER_ORDER_PARTIAL;
+}
+
+static void
+gtk_sorter_class_init (GtkSorterClass *class)
+{
+ class->compare = gtk_sorter_default_compare;
+ class->get_order = gtk_sorter_default_get_order;
+
+ /**
+ * GtkSorter::changed:
+ * @self: The #GtkSorter
+ * @change: how the sorter changed
+ *
+ * This signal is emitted whenever the sorter changed. Users of the sorter
+ * should then update the sort order again via gtk_sorter_compare().
+ *
+ * #GtkSortListModel handles this signal automatically.
+ *
+ * Depending on the @change parameter, it may be possible to update
+ * the sort order without a full resorting. Refer to the #GtkSorterChange
+ * documentation for details.
+ */
+ signals[CHANGED] =
+ g_signal_new (I_("changed"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_SORTER_CHANGE);
+ g_signal_set_va_marshaller (signals[CHANGED],
+ G_TYPE_FROM_CLASS (class),
+ g_cclosure_marshal_VOID__ENUMv);
+}
+
+static void
+gtk_sorter_init (GtkSorter *self)
+{
+}
+
+/**
+ * gtk_sorter_compare:
+ * @self: a #GtkSorter
+ * @item1: (type GObject) (transfer none): first item to compare
+ * @item2: (type GObject) (transfer none): second item to compare
+ *
+ * Compares two given items according to the sort order implemented
+ * by the sorter.
+ *
+ * Sorters implement a partial order:
+ * * It is reflexive, ie a = a
+ * * It is antisymmetric, ie if a < b and b < a, then a = b
+ * * It is transitive, ie given any 3 items with a ≤ b and b ≤ c,
+ * then a ≤ c
+ *
+ * The sorter may signal it conforms to additional constraints
+ * via the return value of gtk_sorter_get_order().
+ *
+ * Returns: %GTK_ORDERING_EQUAL if @item1 == @item2,
+ * %GTK_ORDERING_SMALLER if @item1 < @item2,
+ * %GTK_ORDERING_LARGER if @item1 > @item2
+ */
+GtkOrdering
+gtk_sorter_compare (GtkSorter *self,
+ gpointer item1,
+ gpointer item2)
+{
+ GtkOrdering result;
+
+ g_return_val_if_fail (GTK_IS_SORTER (self), GTK_ORDERING_EQUAL);
+ g_return_val_if_fail (item1 && item2, GTK_ORDERING_EQUAL);
+
+ if (item1 == item2)
+ return GTK_ORDERING_EQUAL;
+
+ result = GTK_SORTER_GET_CLASS (self)->compare (self, item1, item2);
+
+#ifdef G_ENABLE_DEBUG
+ if (result < -1 || result > 1)
+ {
+ g_critical ("A sorter of type \"%s\" returned %d, which is not a valid GtkOrdering result.\n"
+ "Did you forget to call gtk_ordering_from_cmpfunc()?",
+ G_OBJECT_TYPE_NAME (self), (int) result);
+ }
+#endif
+
+ return result;
+}
+
+/**
+ * gtk_sorter_get_order:
+ * @self: a #GtkSorter
+ *
+ * Gets the order that @self conforms to. See #GtkSorterOrder for details
+ * of the possible return values.
+ *
+ * This function is intended to allow optimizations.
+ *
+ * Returns: The order
+ **/
+GtkSorterOrder
+gtk_sorter_get_order (GtkSorter *self)
+{
+ g_return_val_if_fail (GTK_IS_SORTER (self), GTK_SORTER_ORDER_PARTIAL);
+
+ return GTK_SORTER_GET_CLASS (self)->get_order (self);
+}
+
+/**
+ * gtk_sorter_changed:
+ * @self: a #GtkSorter
+ * @change: How the sorter changed
+ *
+ * Emits the #GtkSorter::changed signal to notify all users of the sorter
+ * that it has changed. Users of the sorter should then update the sort
+ * order via gtk_sorter_compare().
+ *
+ * Depending on the @change parameter, it may be possible to update
+ * the sort order without a full resorting. Refer to the #GtkSorterChange
+ * documentation for details.
+ *
+ * This function is intended for implementors of #GtkSorter subclasses and
+ * should not be called from other functions.
+ */
+void
+gtk_sorter_changed (GtkSorter *self,
+ GtkSorterChange change)
+{
+ g_return_if_fail (GTK_IS_SORTER (self));
+
+ g_signal_emit (self, signals[CHANGED], 0, change);
+}