summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2021-06-03 23:55:48 -0400
committerMatthias Clasen <mclasen@redhat.com>2021-06-04 21:10:01 -0400
commit9ac22c1088a404cc74945e71c15ac3ad7ac5e0d9 (patch)
tree90ca181c431e52d0323169d213eec4c773a5df92
parent47400e4bd849092b8b6a4404844a4fb042ae86a9 (diff)
downloadgtk+-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.c104
-rw-r--r--gtk/gtkfilefilter.h6
-rw-r--r--tests/testgtk.c4
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);