stringsorter: Add a collation property

The new property lets us choose between
Unicode collation, filename collation, and
plain strcmp.

This will be used in the filechooser.
This commit is contained in:
Matthias Clasen 2022-10-11 12:57:09 -04:00
parent 8ba7840528
commit 141aac1a60
2 changed files with 127 additions and 15 deletions

View File

@ -42,6 +42,7 @@ struct _GtkStringSorter
GtkSorter parent_instance;
gboolean ignore_case;
GtkCollation collation;
GtkExpression *expression;
};
@ -50,6 +51,7 @@ enum {
PROP_0,
PROP_EXPRESSION,
PROP_IGNORE_CASE,
PROP_COLLATION,
NUM_PROPERTIES
};
@ -60,10 +62,13 @@ static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
static char *
gtk_string_sorter_get_key (GtkExpression *expression,
gboolean ignore_case,
GtkCollation collation,
gpointer item1)
{
GValue value = G_VALUE_INIT;
const char *string;
char *s;
char *key;
if (expression == NULL)
return NULL;
@ -71,23 +76,35 @@ gtk_string_sorter_get_key (GtkExpression *expression,
if (!gtk_expression_evaluate (expression, item1, &value))
return NULL;
/* If strings are NULL, order them before "". */
if (ignore_case)
{
char *t;
string = g_value_get_string (&value);
t = g_utf8_casefold (g_value_get_string (&value), -1);
s = g_utf8_collate_key (t, -1);
g_free (t);
}
if (ignore_case)
s = g_utf8_casefold (string, -1);
else
s = (char *) string;
switch (collation)
{
s = g_utf8_collate_key (g_value_get_string (&value), -1);
case GTK_COLLATION_NONE:
key = s;
break;
case GTK_COLLATION_UNICODE:
key = g_utf8_collate_key (s, -1);
break;
case GTK_COLLATION_FILENAME:
key = g_utf8_collate_key_for_filename (s, -1);
break;
default:
g_assert_not_reached ();
break;
}
if (s != string)
g_free (s);
g_value_unset (&value);
return s;
return key;
}
static GtkOrdering
@ -102,8 +119,8 @@ gtk_string_sorter_compare (GtkSorter *sorter,
if (self->expression == NULL)
return GTK_ORDERING_EQUAL;
s1 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item1);
s2 = gtk_string_sorter_get_key (self->expression, self->ignore_case, item2);
s1 = gtk_string_sorter_get_key (self->expression, self->ignore_case, self->collation, item1);
s2 = gtk_string_sorter_get_key (self->expression, self->ignore_case, self->collation, item2);
result = gtk_ordering_from_cmpfunc (g_strcmp0 (s1, s2));
@ -131,6 +148,7 @@ struct _GtkStringSortKeys
GtkExpression *expression;
gboolean ignore_case;
GtkCollation collation;
};
static void
@ -173,7 +191,7 @@ gtk_string_sort_keys_init_key (GtkSortKeys *keys,
GtkStringSortKeys *self = (GtkStringSortKeys *) keys;
char **key = (char **) key_memory;
*key = gtk_string_sorter_get_key (self->expression, self->ignore_case, item);
*key = gtk_string_sorter_get_key (self->expression, self->ignore_case, self->collation, item);
}
static void
@ -209,6 +227,7 @@ gtk_string_sort_keys_new (GtkStringSorter *self)
result->expression = gtk_expression_ref (self->expression);
result->ignore_case = self->ignore_case;
result->collation = self->collation;
return (GtkSortKeys *) result;
}
@ -231,13 +250,17 @@ gtk_string_sorter_set_property (GObject *object,
gtk_string_sorter_set_ignore_case (self, g_value_get_boolean (value));
break;
case PROP_COLLATION:
gtk_string_sorter_set_collation (self, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
static void
gtk_string_sorter_get_property (GObject *object,
guint prop_id,
GValue *value,
@ -255,6 +278,10 @@ gtk_string_sorter_get_property (GObject *object,
g_value_set_boolean (value, self->ignore_case);
break;
case PROP_COLLATION:
g_value_set_enum (value, self->collation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -296,13 +323,26 @@ gtk_string_sorter_class_init (GtkStringSorterClass *class)
/**
* GtkStringSorter:ignore-case: (attributes org.gtk.Property.get=gtk_string_sorter_get_ignore_case org.gtk.Property.set=gtk_string_sorter_set_ignore_case)
*
* If matching is case sensitive.
* If sorting is case sensitive.
*/
properties[PROP_IGNORE_CASE] =
g_param_spec_boolean ("ignore-case", NULL, NULL,
TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkStringSorter:collation: (attributes org.gtk.Property.get=gtk_string_sorter_get_collation org.gtk.Property.set=gtk_string_sorter_set_collation)
*
* The collation method to use for sorting.
*
* Since: 4.10
*/
properties[PROP_COLLATION] =
g_param_spec_enum ("collationmode", NULL, NULL,
GTK_TYPE_COLLATION,
GTK_COLLATION_UNICODE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
}
@ -311,6 +351,7 @@ static void
gtk_string_sorter_init (GtkStringSorter *self)
{
self->ignore_case = TRUE;
self->collation = GTK_COLLATION_UNICODE;
gtk_sorter_changed_with_keys (GTK_SORTER (self),
GTK_SORTER_CHANGE_DIFFERENT,
@ -429,3 +470,48 @@ gtk_string_sorter_set_ignore_case (GtkStringSorter *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_CASE]);
}
/**
* gtk_string_sorter_get_collation: (attributes org.gtk.Method.get_property=collation)
* @self: a `GtkStringSorter`
*
* Gets which collation method the sorter uses.
*
* Returns: The collation method
*
* Since: 4.10
*/
GtkCollation
gtk_string_sorter_get_collation (GtkStringSorter *self)
{
g_return_val_if_fail (GTK_IS_STRING_SORTER (self), GTK_COLLATION_UNICODE);
return self->collation;
}
/**
* gtk_string_sorter_set_collation: (attributes org.gtk.Method.set_property=collation)
* @self: a `GtkStringSorter`
* @collation: the collation method
*
* Sets the collation method to use for sorting.
*
* Since: 4.10
*/
void
gtk_string_sorter_set_collation (GtkStringSorter *self,
GtkCollation collation)
{
g_return_if_fail (GTK_IS_STRING_SORTER (self));
if (self->collation == collation)
return;
self->collation = collation;
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_COLLATION]);
}

View File

@ -47,6 +47,32 @@ GDK_AVAILABLE_IN_ALL
void gtk_string_sorter_set_ignore_case (GtkStringSorter *self,
gboolean ignore_case);
/**
* GtkCollation:
* @GTK_COLLATION_NONE: Don't do any collation
* @GTK_COLLATION_UNICODE: Use [func@GLib.g_utf8_collate_key]
* @GTK_COLLATION_FILENAME: Use [func@GLib.g_utf8_collate_key_for_filename]
*
* Describes how a [class@Gtk.StringSorter] turns strings into sort keys to
* compare them.
*
* Note that the result of sorting will in general depend on the current locale
* unless the mode is @GTK_COLLATION_NONE.
*/
typedef enum
{
GTK_COLLATION_NONE,
GTK_COLLATION_UNICODE,
GTK_COLLATION_FILENAME
} GtkCollation;
GDK_AVAILABLE_IN_4_10
void gtk_string_sorter_set_collation (GtkStringSorter *self,
GtkCollation collation);
GDK_AVAILABLE_IN_4_10
GtkCollation gtk_string_sorter_get_collation (GtkStringSorter *self);
G_END_DECLS
#endif /* __GTK_STRING_SORTER_H__ */