/* * 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 . * * Authors: Matthias Clasen */ #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); }