stringsorter: Implement GtkSortKeys

This commit is contained in:
Benjamin Otte 2020-07-15 20:28:45 +02:00
parent 814c88fbc1
commit 0970077af9

View File

@ -22,6 +22,7 @@
#include "gtkstringsorter.h"
#include "gtkintl.h"
#include "gtksorterprivate.h"
#include "gtktypebuiltins.h"
/**
@ -58,70 +59,58 @@ G_DEFINE_TYPE (GtkStringSorter, gtk_string_sorter, GTK_TYPE_SORTER)
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
static char *
gtk_string_sorter_get_key (GtkExpression *expression,
gboolean ignore_case,
gpointer item1)
{
GValue value = G_VALUE_INIT;
char *s;
if (expression == NULL)
return NULL;
if (!gtk_expression_evaluate (expression, item1, &value))
return NULL;
/* If strings are NULL, order them before "". */
if (ignore_case)
{
char *t;
t = g_utf8_casefold (g_value_get_string (&value), -1);
s = g_utf8_collate_key (t, -1);
g_free (t);
}
else
{
s = g_utf8_collate_key (g_value_get_string (&value), -1);
}
g_value_unset (&value);
return s;
}
static GtkOrdering
gtk_string_sorter_compare (GtkSorter *sorter,
gpointer item1,
gpointer item2)
{
GtkStringSorter *self = GTK_STRING_SORTER (sorter);
GValue value1 = G_VALUE_INIT;
GValue value2 = G_VALUE_INIT;
const char *s1, *s2;
gboolean res1, res2;
char *s1, *s2;
GtkOrdering result;
if (self->expression == NULL)
return GTK_ORDERING_EQUAL;
res1 = gtk_expression_evaluate (self->expression, item1, &value1);
res2 = gtk_expression_evaluate (self->expression, item2, &value2);
s1 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item1);
s2 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item2);
/* If items don't evaluate, order them at the end, so they aren't
* in the way. */
if (!res1)
{
result = res2 ? GTK_ORDERING_LARGER : GTK_ORDERING_EQUAL;
goto out;
}
else if (!res2)
{
result = GTK_ORDERING_SMALLER;
goto out;
}
result = gtk_ordering_from_cmpfunc (g_strcmp0 (s1, s2));
s1 = g_value_get_string (&value1);
s2 = g_value_get_string (&value2);
/* If strings are NULL, order them before "". */
if (s1 == NULL)
{
result = s2 == NULL ? GTK_ORDERING_EQUAL : GTK_ORDERING_SMALLER;
goto out;
}
else if (s2 == NULL)
{
result = GTK_ORDERING_LARGER;
goto out;
}
if (self->ignore_case)
{
char *t1, *t2;
t1 = g_utf8_casefold (s1, -1);
t2 = g_utf8_casefold (s2, -1);
result = gtk_ordering_from_cmpfunc (g_utf8_collate (t1, t2));
g_free (t1);
g_free (t2);
}
else
result = gtk_ordering_from_cmpfunc (g_utf8_collate (s1, s2));
out:
g_value_unset (&value1);
g_value_unset (&value2);
g_free (s1);
g_free (s2);
return result;
}
@ -137,6 +126,95 @@ gtk_string_sorter_get_order (GtkSorter *sorter)
return GTK_SORTER_ORDER_PARTIAL;
}
typedef struct _GtkStringSortKeys GtkStringSortKeys;
struct _GtkStringSortKeys
{
GtkSortKeys keys;
GtkExpression *expression;
gboolean ignore_case;
};
static void
gtk_string_sort_keys_free (GtkSortKeys *keys)
{
GtkStringSortKeys *self = (GtkStringSortKeys *) keys;
gtk_expression_unref (self->expression);
g_slice_free (GtkStringSortKeys, self);
}
static int
gtk_string_sort_keys_compare (gconstpointer a,
gconstpointer b,
gpointer unused)
{
const char *sa = *(const char **) a;
const char *sb = *(const char **) b;
if (sa == NULL)
return sb == NULL ? GTK_ORDERING_EQUAL : GTK_ORDERING_LARGER;
else if (sb == NULL)
return GTK_ORDERING_SMALLER;
return gtk_ordering_from_cmpfunc (strcmp (sa, sb));
}
static gboolean
gtk_string_sort_keys_is_compatible (GtkSortKeys *keys,
GtkSortKeys *other)
{
return FALSE;
}
static void
gtk_string_sort_keys_init_key (GtkSortKeys *keys,
gpointer item,
gpointer key_memory)
{
GtkStringSortKeys *self = (GtkStringSortKeys *) keys;
char **key = (char **) key_memory;
*key = gtk_string_sorter_get_key (self->expression, self->ignore_case, item);
}
static void
gtk_string_sort_keys_clear_key (GtkSortKeys *keys,
gpointer key_memory)
{
char **key = (char **) key_memory;
g_free (*key);
}
static const GtkSortKeysClass GTK_STRING_SORT_KEYS_CLASS =
{
gtk_string_sort_keys_free,
gtk_string_sort_keys_compare,
gtk_string_sort_keys_is_compatible,
gtk_string_sort_keys_init_key,
gtk_string_sort_keys_clear_key,
};
static GtkSortKeys *
gtk_string_sort_keys_new (GtkStringSorter *self)
{
GtkStringSortKeys *result;
if (self->expression == NULL)
return gtk_sort_keys_new_equal ();
result = gtk_sort_keys_new (GtkStringSortKeys,
&GTK_STRING_SORT_KEYS_CLASS,
sizeof (char *),
sizeof (char *));
result->expression = gtk_expression_ref (self->expression);
result->ignore_case = self->ignore_case;
return (GtkSortKeys *) result;
}
static void
gtk_string_sorter_set_property (GObject *object,
guint prop_id,
@ -239,6 +317,10 @@ static void
gtk_string_sorter_init (GtkStringSorter *self)
{
self->ignore_case = TRUE;
gtk_sorter_changed_with_keys (GTK_SORTER (self),
GTK_SORTER_CHANGE_DIFFERENT,
gtk_string_sort_keys_new (self));
}
/**
@ -306,7 +388,9 @@ gtk_string_sorter_set_expression (GtkStringSorter *self,
if (expression)
self->expression = gtk_expression_ref (expression);
gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
gtk_sorter_changed_with_keys (GTK_SORTER (self),
GTK_SORTER_CHANGE_DIFFERENT,
gtk_string_sort_keys_new (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]);
}
@ -345,7 +429,9 @@ gtk_string_sorter_set_ignore_case (GtkStringSorter *self,
self->ignore_case = ignore_case;
gtk_sorter_changed (GTK_SORTER (self), ignore_case ? GTK_SORTER_CHANGE_LESS_STRICT : GTK_SORTER_CHANGE_MORE_STRICT);
gtk_sorter_changed_with_keys (GTK_SORTER (self),
ignore_case ? GTK_SORTER_CHANGE_LESS_STRICT : GTK_SORTER_CHANGE_MORE_STRICT,
gtk_string_sort_keys_new (self));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_CASE]);
}