[gtk/ci-file-filters: 5477/5477] GtkFileFilter: Allow case-insensitive patterns




commit d13d308959f516a715d9e4e2471aacec03c58c04
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Jun 3 23:55:48 2021 -0400

    GtkFileFilter: Allow case-insensitive patterns
    
    In the past, we've hardcoded case-insensitive matching
    on Windows, and case-sensitive matching everywhere else.
    
    With this change, we now have a way to explicitly add
    case-insensitive patterns to a filter. We still interpret
    all patterns case-insensitively on Windows.

 demos/gtk-demo/video_player.c |  2 +-
 gtk/gtkfilechooserentry.c     |  2 +-
 gtk/gtkfilefilter.c           | 79 +++++++++++++++++++++++++++++++++++++------
 gtk/gtkfilefilter.h           |  8 ++++-
 tests/testfilechooser.c       |  4 +--
 tests/testgtk.c               |  8 ++---
 6 files changed, 83 insertions(+), 20 deletions(-)
---
diff --git a/demos/gtk-demo/video_player.c b/demos/gtk-demo/video_player.c
index 8b467a25d9..ffd5eaba73 100644
--- a/demos/gtk-demo/video_player.c
+++ b/demos/gtk-demo/video_player.c
@@ -42,7 +42,7 @@ open_clicked_cb (GtkWidget *button,
                                         "_Cancel");
 
   filter = gtk_file_filter_new ();
-  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_filter_add_pattern_full (filter, "*", FALSE);
   gtk_file_filter_set_name (filter, "All Files");
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
   g_object_unref (filter);
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 2bf47a067e..f3a77da9b7 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -716,7 +716,7 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry)
 
       filter = gtk_file_filter_new ();
       pattern = g_strconcat (chooser_entry->file_part, "*", NULL);
-      gtk_file_filter_add_pattern (filter, pattern);
+      gtk_file_filter_add_pattern_full (filter, pattern, FALSE);
 
       _gtk_file_system_model_set_filter (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
                                          filter);
diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c
index 99a82d6845..ee0dec6b1e 100644
--- a/gtk/gtkfilefilter.c
+++ b/gtk/gtkfilefilter.c
@@ -23,7 +23,7 @@
  *
  * `GtkFileFilter` can be used to restrict the files being shown in a
  * `GtkFileChooser`. Files can be filtered based on their name (with
- * [method@Gtk.FileFilter.add_pattern]) or on their mime type (with
+ * [method@Gtk.FileFilter.add_pattern_full]) or on their mime type (with
  * [method@Gtk.FileFilter.add_mime_type]).
  *
  * Filtering by mime types handles aliasing and subclassing of mime
@@ -44,7 +44,7 @@
  * elements and listing the rules within. Specifying a <mime-type>
  * or <pattern> has the same effect as as calling
  * [method@Gtk.FileFilter.add_mime_type] or
- * [method@Gtk.FileFilter.add_pattern].
+ * [method@Gtk.FileFilter.add_pattern_full].
  *
  * An example of a UI definition fragment specifying `GtkFileFilter`
  * rules:
@@ -84,6 +84,7 @@ typedef struct _FilterRule FilterRule;
 
 typedef enum {
   FILTER_RULE_PATTERN,
+  FILTER_RULE_PATTERN_CI,
   FILTER_RULE_MIME_TYPE,
   FILTER_RULE_PIXBUF_FORMATS
 } FilterRuleType;
@@ -182,6 +183,7 @@ filter_rule_free (FilterRule *rule)
   switch (rule->type)
     {
     case FILTER_RULE_PATTERN:
+    case FILTER_RULE_PATTERN_CI:
       g_free (rule->u.pattern);
       break;
     case FILTER_RULE_MIME_TYPE:
@@ -255,6 +257,7 @@ typedef struct
   ParserType     type;
   GString       *string;
   gboolean       parsing;
+  gboolean       ignore_case;
 } SubParserData;
 
 static void
@@ -267,9 +270,23 @@ parser_start_element (GtkBuildableParseContext  *context,
 {
   SubParserData *data = (SubParserData*)user_data;
 
-  if (!g_markup_collect_attributes (element_name, names, values, error,
-                                    G_MARKUP_COLLECT_INVALID, NULL, NULL,
-                                    G_MARKUP_COLLECT_INVALID))
+  if (strcmp (element_name, "patterns") == 0)
+    {
+      gboolean ignore_case = FALSE;
+
+      if (!g_markup_collect_attributes (element_name, names, values, error,
+                                        G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "ignore-case", 
&ignore_case,
+                                        G_MARKUP_COLLECT_INVALID))
+        {
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      data->ignore_case = ignore_case;
+    }
+  else if (!g_markup_collect_attributes (element_name, names, values, error,
+                                         G_MARKUP_COLLECT_INVALID, NULL, NULL,
+                                         G_MARKUP_COLLECT_INVALID))
     {
       _gtk_builder_prefix_error (data->builder, context, error);
       return;
@@ -332,7 +349,7 @@ parser_end_element (GtkBuildableParseContext  *context,
           gtk_file_filter_add_mime_type (data->filter, data->string->str);
           break;
         case PARSE_PATTERNS:
-          gtk_file_filter_add_pattern (data->filter, data->string->str);
+          gtk_file_filter_add_pattern_full (data->filter, data->string->str, data->ignore_case);
           break;
         default:
           break;
@@ -422,13 +439,13 @@ gtk_file_filter_buildable_init (GtkBuildableIface *iface)
  * Such a filter doesn’t accept any files, so is not
  * particularly useful until you add rules with
  * [method@Gtk.FileFilter.add_mime_type],
- * [method@Gtk.FileFilter.add_pattern], or
+ * [method@Gtk.FileFilter.add_pattern_full], or
  * [method@Gtk.FileFilter.add_pixbuf_formats].
  *
  * To create a filter that accepts any file, use:
  * ```c
  * GtkFileFilter *filter = gtk_file_filter_new ();
- * gtk_file_filter_add_pattern (filter, "*");
+ * gtk_file_filter_add_pattern_full (filter, "*", FALSE);
  * ```
  *
  * Returns: a new `GtkFileFilter`
@@ -543,10 +560,30 @@ gtk_file_filter_add_mime_type (GtkFileFilter *filter,
  * @pattern: a shell style glob
  *
  * Adds a rule allowing a shell style glob to a filter.
+ *
+ * Deprecated: 4.4: Use gtk_file_filter_add_pattern_full()
  */
 void
 gtk_file_filter_add_pattern (GtkFileFilter *filter,
                              const char    *pattern)
+{
+  gtk_file_filter_add_pattern_full (filter, pattern, FALSE);
+}
+
+/**
+ * gtk_file_filter_add_pattern_full:
+ * @filter: a `GtkFileFilter`
+ * @pattern: a shell style glob
+ * @ignore_case: whether to ignore case differences
+ *
+ * Adds a rule allowing a shell style glob to a filter.
+ *
+ * Since: 4.4
+ */
+void
+gtk_file_filter_add_pattern_full (GtkFileFilter *filter,
+                                  const char    *pattern,
+                                  gboolean       ignore_case)
 {
   FilterRule *rule;
 
@@ -554,7 +591,7 @@ gtk_file_filter_add_pattern (GtkFileFilter *filter,
   g_return_if_fail (pattern != NULL);
 
   rule = g_slice_new (FilterRule);
-  rule->type = FILTER_RULE_PATTERN;
+  rule->type = ignore_case ? FILTER_RULE_PATTERN_CI : FILTER_RULE_PATTERN;
   rule->u.pattern = g_strdup (pattern);
 
   file_filter_add_attribute (filter, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
@@ -657,6 +694,7 @@ NSArray * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter)
           break;
 
         case FILTER_RULE_PATTERN:
+        case FILTER_RULE_PATTERN_CI:
           {
             // patterns will need to be stripped of their leading *.
             GString *pattern = g_string_new (rule->u.pattern);
@@ -725,6 +763,7 @@ _gtk_file_filter_get_as_patterns (GtkFileFilter *filter)
           break;
 
         case FILTER_RULE_PATTERN:
+        case FILTER_RULE_PATTERN_CI:
           g_ptr_array_add (array, g_strdup (rule->u.pattern));
           break;
 
@@ -794,9 +833,13 @@ gtk_file_filter_match (GtkFilter *filter,
   for (tmp_list = file_filter->rules; tmp_list; tmp_list = tmp_list->next)
     {
       FilterRule *rule = tmp_list->data;
+      gboolean casefold = FALSE;
 
       switch (rule->type)
         {
+        case FILTER_RULE_PATTERN_CI:
+          casefold = TRUE;
+          G_GNUC_FALLTHROUGH;
         case FILTER_RULE_PATTERN:
           {
             const char *display_name;
@@ -804,7 +847,7 @@ gtk_file_filter_match (GtkFilter *filter,
             display_name = g_file_info_get_display_name (info);
             if (display_name)
               {
-                if (_gtk_fnmatch (rule->u.pattern, display_name, FALSE, FALSE))
+                if (_gtk_fnmatch (rule->u.pattern, display_name, FALSE, casefold))
                   return TRUE;
               }
           }
@@ -863,6 +906,17 @@ gtk_file_filter_to_gvariant (GtkFileFilter *filter)
           g_variant_builder_add (&builder, "(us)", 0, rule->u.pattern);
           break;
 
+        case FILTER_RULE_PATTERN_CI:
+          {
+            /* Tweak the glob, since the filechooser portal has no api
+             * for case-insensitive globs
+             */
+            char *pattern = _gtk_make_ci_glob_pattern (rule->u.pattern);
+            g_variant_builder_add (&builder, "(us)", 0, pattern);
+            g_free (pattern);
+          }
+          break;
+
         case FILTER_RULE_MIME_TYPE:
         case FILTER_RULE_PIXBUF_FORMATS:
           for (i = 0; rule->u.content_types[i]; i++)
@@ -908,7 +962,10 @@ gtk_file_filter_new_from_gvariant (GVariant *variant)
       switch (type)
         {
         case 0:
-          gtk_file_filter_add_pattern (filter, tmp);
+          gtk_file_filter_add_pattern_full (filter, tmp, FALSE);
+          break;
+        case 2:
+          gtk_file_filter_add_pattern_full (filter, tmp, TRUE);
           break;
         case 1:
           gtk_file_filter_add_mime_type (filter, tmp);
diff --git a/gtk/gtkfilefilter.h b/gtk/gtkfilefilter.h
index 5232dfb0ae..485c725833 100644
--- a/gtk/gtkfilefilter.h
+++ b/gtk/gtkfilefilter.h
@@ -48,9 +48,15 @@ const char *    gtk_file_filter_get_name           (GtkFileFilter *filter);
 GDK_AVAILABLE_IN_ALL
 void            gtk_file_filter_add_mime_type      (GtkFileFilter *filter,
                                                     const char    *mime_type);
-GDK_AVAILABLE_IN_ALL
+
+GDK_DEPRECATED_IN_4_4_FOR(gtk_file_filter_add_pattern_full)
 void            gtk_file_filter_add_pattern        (GtkFileFilter *filter,
                                                     const char    *pattern);
+
+GDK_AVAILABLE_IN_4_4
+void            gtk_file_filter_add_pattern_full   (GtkFileFilter *filter,
+                                                    const char    *pattern,
+                                                    gboolean       ignore_case);
 GDK_AVAILABLE_IN_ALL
 void            gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
 
diff --git a/tests/testfilechooser.c b/tests/testfilechooser.c
index c06f636884..ac118b7550 100644
--- a/tests/testfilechooser.c
+++ b/tests/testfilechooser.c
@@ -310,7 +310,7 @@ main (int argc, char **argv)
   /* Filters */
   filter = gtk_file_filter_new ();
   gtk_file_filter_set_name (filter, "All Files");
-  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_filter_add_pattern_full (filter, "*", FALSE);
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
 
   /* Make this filter the default */
@@ -319,7 +319,7 @@ main (int argc, char **argv)
 
   filter = gtk_file_filter_new ();
   gtk_file_filter_set_name (filter, "Starts with D");
-  gtk_file_filter_add_pattern (filter, "D*");
+  gtk_file_filter_add_pattern_full (filter, "D*", FALSE);
   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
   g_object_unref (filter);
 
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 077d16136b..8e325d911a 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -5576,8 +5576,8 @@ native_filter_changed (GtkWidget *combo,
     case 1:   /* pattern */
       filter = gtk_file_filter_new ();
       gtk_file_filter_set_name (filter, "Text");
-      gtk_file_filter_add_pattern (filter, "*.doc");
-      gtk_file_filter_add_pattern (filter, "*.txt");
+      gtk_file_filter_add_pattern_full (filter, "*.doc", FALSE);
+      gtk_file_filter_add_pattern_full (filter, "*.txt", FALSE);
       gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
       g_object_unref (filter);
 
@@ -5590,7 +5590,7 @@ native_filter_changed (GtkWidget *combo,
 
       filter = gtk_file_filter_new ();
       gtk_file_filter_set_name (filter, "All");
-      gtk_file_filter_add_pattern (filter, "*");
+      gtk_file_filter_add_pattern_full (filter, "*", FALSE);
       gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
       g_object_unref (filter);
       break;
@@ -5604,7 +5604,7 @@ native_filter_changed (GtkWidget *combo,
 
       filter = gtk_file_filter_new ();
       gtk_file_filter_set_name (filter, "All");
-      gtk_file_filter_add_pattern (filter, "*");
+      gtk_file_filter_add_pattern_full (filter, "*", FALSE);
       gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
       gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), filter);
       g_object_unref (filter);


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