Redo sort list model with GtkSorter
Reshuffle the api to take full advantage of GtkSorter. Update all callers.
This commit is contained in:
@@ -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
|
||||
<SUBSECTION Standard>
|
||||
GTK_SORT_LIST_MODEL
|
||||
GTK_IS_SORT_LIST_MODEL
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user