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




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

    stringsorter: Add a collate-mode property
    
    This lets us change between locale collation,
    filename collation, and plain strcmp.

 gtk/gtkstringsorter.c | 120 ++++++++++++++++++++++++++++++++++++++++++--------
 gtk/gtkstringsorter.h |  25 +++++++++++
 2 files changed, 127 insertions(+), 18 deletions(-)
---
diff --git a/gtk/gtkstringsorter.c b/gtk/gtkstringsorter.c
index 59d2d8737e..3c7c52f30f 100644
--- a/gtk/gtkstringsorter.c
+++ b/gtk/gtkstringsorter.c
@@ -42,6 +42,7 @@ struct _GtkStringSorter
   GtkSorter parent_instance;
 
   gboolean ignore_case;
+  GtkCollateMode collate_mode;
 
   GtkExpression *expression;
 };
@@ -50,6 +51,7 @@ enum {
   PROP_0,
   PROP_EXPRESSION,
   PROP_IGNORE_CASE,
+  PROP_COLLATE_MODE,
   NUM_PROPERTIES
 };
 
@@ -58,12 +60,15 @@ 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)
+gtk_string_sorter_get_key (GtkExpression  *expression,
+                           gboolean        ignore_case,
+                           GtkCollateMode  collate_mode,
+                           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 (collate_mode)
     {
-      s = g_utf8_collate_key (g_value_get_string (&value), -1);
+    case GTK_COLLATE_MODE_NONE:
+      key = s;
+      break;
+    case GTK_COLLATE_MODE_LOCALE:
+      key = g_utf8_collate_key (s, -1);
+      break;
+    case GTK_COLLATE_MODE_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->collate_mode, item1);
+  s2 = gtk_string_sorter_get_key (self->expression, self->ignore_case, self->collate_mode, item2);
 
   result = gtk_ordering_from_cmpfunc (g_strcmp0 (s1, s2));
 
@@ -131,6 +148,7 @@ struct _GtkStringSortKeys
 
   GtkExpression *expression;
   gboolean ignore_case;
+  GtkCollateMode collate_mode;
 };
 
 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->collate_mode, 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->collate_mode = self->collate_mode;
 
   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_COLLATE_MODE:
+      gtk_string_sorter_set_collate_mode (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_COLLATE_MODE:
+      g_value_set_enum (value, self->collate_mode);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -296,13 +323,24 @@ 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:collate-mode: (attributes org.gtk.Property.get=gtk_string_sorter_get_collate_mode 
org.gtk.Property.set=gtk_string_sorter_set_collate_mode)
+   *
+   * The collation mode to use for sorting.
+   */
+  properties[PROP_COLLATE_MODE] =
+      g_param_spec_enum ("collate-mode", NULL, NULL,
+                         GTK_TYPE_COLLATE_MODE,
+                         GTK_COLLATE_MODE_LOCALE,
+                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
 
 }
@@ -311,6 +349,7 @@ static void
 gtk_string_sorter_init (GtkStringSorter *self)
 {
   self->ignore_case = TRUE;
+  self->collate_mode = GTK_COLLATE_MODE_LOCALE;
 
   gtk_sorter_changed_with_keys (GTK_SORTER (self),
                                 GTK_SORTER_CHANGE_DIFFERENT,
@@ -429,3 +468,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_collate_mode: (attributes org.gtk.Method.get_property=collate-mode)
+ * @self: a `GtkStringSorter`
+ *
+ * Gets which collation mode the sorter uses.
+ *
+ * Returns: The collation mode
+ *
+ * Since: 4.10
+ */
+GtkCollateMode
+gtk_string_sorter_get_collate_mode (GtkStringSorter *self)
+{
+  g_return_val_if_fail (GTK_IS_STRING_SORTER (self), GTK_COLLATE_MODE_LOCALE);
+
+  return self->collate_mode;
+}
+
+/**
+ * gtk_string_sorter_set_collate_mode: (attributes org.gtk.Method.set_property=collate-mode)
+ * @self: a `GtkStringSorter`
+ * @collate_mode: the collation mode
+ *
+ * Sets the collation mode to use for sorting.
+ *
+ * Since: 4.10
+ */
+void
+gtk_string_sorter_set_collate_mode (GtkStringSorter *self,
+                                    GtkCollateMode   collate_mode)
+{
+  g_return_if_fail (GTK_IS_STRING_SORTER (self));
+
+  if (self->collate_mode == collate_mode)
+    return;
+
+  self->collate_mode = collate_mode;
+
+  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_COLLATE_MODE]);
+}
diff --git a/gtk/gtkstringsorter.h b/gtk/gtkstringsorter.h
index c340c6fa8d..0bdfb3a042 100644
--- a/gtk/gtkstringsorter.h
+++ b/gtk/gtkstringsorter.h
@@ -47,6 +47,31 @@ GDK_AVAILABLE_IN_ALL
 void                    gtk_string_sorter_set_ignore_case       (GtkStringSorter        *self,
                                                                  gboolean                ignore_case);
 
+/**
+ * GtkCollateMode:
+ * @GTK_COLLATE_MODE_NONE: Don't do any collation
+ * @GTK_COLLATE_MODE_LOCALE: Use [func@GLib.g_utf8_collate_key]
+ * @GTK_COLLATE_MODE_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_COLLATE_MODE_NONE.
+ */
+typedef enum
+{
+  GTK_COLLATE_MODE_NONE,
+  GTK_COLLATE_MODE_LOCALE,
+  GTK_COLLATE_MODE_FILENAME
+} GtkCollateMode;
+
+GDK_AVAILABLE_IN_4_10
+void                    gtk_string_sorter_set_collate_mode      (GtkStringSorter        *self,
+                                                                 GtkCollateMode          collate_mode);
+GDK_AVAILABLE_IN_4_10
+GtkCollateMode          gtk_string_sorter_get_collate_mode      (GtkStringSorter        *self);
+
 G_END_DECLS
 
 #endif /* __GTK_STRING_SORTER_H__ */


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