diff options
author | Matthias Clasen <mclasen@redhat.com> | 2021-06-03 23:55:48 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2021-06-04 21:10:01 -0400 |
commit | 9ac22c1088a404cc74945e71c15ac3ad7ac5e0d9 (patch) | |
tree | 90ca181c431e52d0323169d213eec4c773a5df92 | |
parent | 47400e4bd849092b8b6a4404844a4fb042ae86a9 (diff) | |
download | gtk+-9ac22c1088a404cc74945e71c15ac3ad7ac5e0d9.tar.gz |
GtkFileFilter: Add suffix matches
This is less flexible than a glob pattern, but it is
explicitly case-insensitive, to match the behavior
on Windows.
Fixes: #3705
-rw-r--r-- | gtk/gtkfilefilter.c | 104 | ||||
-rw-r--r-- | gtk/gtkfilefilter.h | 6 | ||||
-rw-r--r-- | tests/testgtk.c | 4 |
3 files changed, 102 insertions, 12 deletions
diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c index 99a82d6845..22b1616881 100644 --- a/gtk/gtkfilefilter.c +++ b/gtk/gtkfilefilter.c @@ -23,8 +23,8 @@ * * `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_mime_type]). + * [method@Gtk.FileFilter.add_pattern] or [method@Gtk.FileFilter.add_suffix]) + * or on their mime type (with [method@Gtk.FileFilter.add_mime_type]). * * Filtering by mime types handles aliasing and subclassing of mime * types; e.g. a filter for text/plain also matches a file with mime @@ -40,11 +40,13 @@ * # GtkFileFilter as GtkBuildable * * The `GtkFileFilter` implementation of the `GtkBuildable` interface - * supports adding rules using the <mime-types> and <patterns> - * elements and listing the rules within. Specifying a <mime-type> - * or <pattern> has the same effect as as calling + * supports adding rules using the `<mime-types>` and `<patterns>` and + * `<suffixes>` elements and listing the rules within. Specifying a + * `<mime-type>` or `<pattern>` or `<suffix>` has the same effect as + * as calling * [method@Gtk.FileFilter.add_mime_type] or - * [method@Gtk.FileFilter.add_pattern]. + * [method@Gtk.FileFilter.add_pattern] or + * [method@Gtk.FileFilter.add_suffix]. * * An example of a UI definition fragment specifying `GtkFileFilter` * rules: @@ -57,8 +59,10 @@ * </mime-types> * <patterns> * <pattern>*.txt</pattern> - * <pattern>*.png</pattern> * </patterns> + * <suffixes> + * <suffix>png</suffix> + * </suffixes> * </object> * ``` */ @@ -85,6 +89,7 @@ typedef struct _FilterRule FilterRule; typedef enum { FILTER_RULE_PATTERN, FILTER_RULE_MIME_TYPE, + FILTER_RULE_SUFFIX, FILTER_RULE_PIXBUF_FORMATS } FilterRuleType; @@ -182,6 +187,7 @@ filter_rule_free (FilterRule *rule) switch (rule->type) { case FILTER_RULE_PATTERN: + case FILTER_RULE_SUFFIX: g_free (rule->u.pattern); break; case FILTER_RULE_MIME_TYPE: @@ -245,7 +251,8 @@ gtk_file_filter_class_init (GtkFileFilterClass *class) typedef enum { PARSE_MIME_TYPES, - PARSE_PATTERNS + PARSE_PATTERNS, + PARSE_SUFFIXES } ParserType; typedef struct @@ -295,6 +302,13 @@ parser_start_element (GtkBuildableParseContext *context, data->parsing = TRUE; } + else if (strcmp (element_name, "suffix") == 0) + { + if (!_gtk_builder_check_parent (data->builder, context, "suffixes", error)) + return; + + data->parsing = TRUE; + } else { _gtk_builder_error_unhandled_tag (data->builder, context, @@ -334,6 +348,9 @@ parser_end_element (GtkBuildableParseContext *context, case PARSE_PATTERNS: gtk_file_filter_add_pattern (data->filter, data->string->str); break; + case PARSE_SUFFIXES: + gtk_file_filter_add_suffix (data->filter, data->string->str); + break; default: break; } @@ -382,6 +399,17 @@ gtk_file_filter_buildable_custom_tag_start (GtkBuildable *buildable, *parser = sub_parser; *parser_data = data; } + else if (strcmp (tagname, "suffixes") == 0) + { + data = g_slice_new0 (SubParserData); + data->string = g_string_new (""); + data->type = PARSE_SUFFIXES; + data->filter = GTK_FILE_FILTER (buildable); + data->builder = builder; + + *parser = sub_parser; + *parser_data = data; + } return data != NULL; } @@ -422,7 +450,8 @@ 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], + * [method@Gtk.FileFilter.add_suffix] or * [method@Gtk.FileFilter.add_pixbuf_formats]. * * To create a filter that accepts any file, use: @@ -543,6 +572,10 @@ gtk_file_filter_add_mime_type (GtkFileFilter *filter, * @pattern: a shell style glob * * Adds a rule allowing a shell style glob to a filter. + * + * Note that it depends on the platform whether pattern + * matching ignores case or not. On Windows, it does, on + * other platforms, it doesn't. */ void gtk_file_filter_add_pattern (GtkFileFilter *filter, @@ -562,6 +595,36 @@ gtk_file_filter_add_pattern (GtkFileFilter *filter, } /** + * gtk_file_filter_add_suffix: + * @filter: a `GtkFileFilter` + * @suffix: filename suffix to match + * + * Adds a suffix match rule to a filter. + * + * This is similar to adding a match for the pattern + * "*.@suffix". + * + * In contrast to pattern matches, suffix matches + * are *always* case-insensitive. + */ +void +gtk_file_filter_add_suffix (GtkFileFilter *filter, + const char *suffix) +{ + FilterRule *rule; + + g_return_if_fail (GTK_IS_FILE_FILTER (filter)); + g_return_if_fail (suffix != NULL); + + rule = g_slice_new (FilterRule); + rule->type = FILTER_RULE_SUFFIX; + rule->u.pattern = g_strconcat ("*.", suffix, NULL); + + file_filter_add_attribute (filter, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME); + file_filter_add_rule (filter, rule); +} + +/** * gtk_file_filter_add_pixbuf_formats: * @filter: a `GtkFileFilter` * @@ -657,6 +720,7 @@ NSArray * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter) break; case FILTER_RULE_PATTERN: + case FILTER_RULE_SUFFIX: { // patterns will need to be stripped of their leading *. GString *pattern = g_string_new (rule->u.pattern); @@ -725,6 +789,10 @@ _gtk_file_filter_get_as_patterns (GtkFileFilter *filter) break; case FILTER_RULE_PATTERN: + case FILTER_RULE_SUFFIX: + /* Note: we don't make the suffix pattern explicitly + * case-insensitive, since this is only used on Windows + */ g_ptr_array_add (array, g_strdup (rule->u.pattern)); break; @@ -794,9 +862,14 @@ 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 ignore_case = FALSE; switch (rule->type) { + case FILTER_RULE_SUFFIX: + ignore_case = TRUE; + G_GNUC_FALLTHROUGH; + case FILTER_RULE_PATTERN: { const char *display_name; @@ -804,7 +877,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, ignore_case)) return TRUE; } } @@ -863,6 +936,17 @@ gtk_file_filter_to_gvariant (GtkFileFilter *filter) g_variant_builder_add (&builder, "(us)", 0, rule->u.pattern); break; + case FILTER_RULE_SUFFIX: + { + /* 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++) diff --git a/gtk/gtkfilefilter.h b/gtk/gtkfilefilter.h index 5232dfb0ae..e14d70d823 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 void gtk_file_filter_add_pattern (GtkFileFilter *filter, const char *pattern); + +GDK_AVAILABLE_IN_4_4 +void gtk_file_filter_add_suffix (GtkFileFilter *filter, + const char *suffix); + GDK_AVAILABLE_IN_ALL void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter); diff --git a/tests/testgtk.c b/tests/testgtk.c index 077d16136b..1b8cbf4cbe 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_suffix (filter, "doc"); + gtk_file_filter_add_suffix (filter, "txt"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); g_object_unref (filter); |