[gtk/filename-sorter] stringsorter: Add a collation property




commit 141aac1a60f64bf8891d5531055cc297a91e8cc0
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Oct 11 12:57:09 2022 -0400

    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.

 gtk/gtkstringsorter.c | 116 +++++++++++++++++++++++++++++++++++++++++++-------
 gtk/gtkstringsorter.h |  26 +++++++++++
 2 files changed, 127 insertions(+), 15 deletions(-)
---
diff --git a/gtk/gtkstringsorter.c b/gtk/gtkstringsorter.c
index 59d2d8737e..87f65da897 100644
--- a/gtk/gtkstringsorter.c
+++ b/gtk/gtkstringsorter.c
@@ -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]);
+}
diff --git a/gtk/gtkstringsorter.h b/gtk/gtkstringsorter.h
index c340c6fa8d..ea61a47061 100644
--- a/gtk/gtkstringsorter.h
+++ b/gtk/gtkstringsorter.h
@@ -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__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]