diff options
| author | Matthias Clasen <mclasen@redhat.com> | 2020-07-05 20:32:05 +0000 |
|---|---|---|
| committer | Matthias Clasen <mclasen@redhat.com> | 2020-07-05 20:32:05 +0000 |
| commit | 6267c8469b8ce41fe55e215c444c1e50bab120e1 (patch) | |
| tree | a2a003dcbcb07830c30b9daaaed247bddef81f09 | |
| parent | d65214fa4e8dee5df735d6a43bb85825823f1e18 (diff) | |
| parent | 5a2f791bddd90f65a2d867ab1df061c3d786b6d2 (diff) | |
| download | gtk+-6267c8469b8ce41fe55e215c444c1e50bab120e1.tar.gz | |
Merge branch 'file-filter2' into 'master'
Make GtkFileFilter a GtkFilter
See merge request GNOME/gtk!2190
| -rw-r--r-- | docs/reference/gtk/gtk4-docs.xml | 4 | ||||
| -rw-r--r-- | docs/reference/gtk/gtk4-sections.txt | 7 | ||||
| -rw-r--r-- | gtk/gtkfilechooserentry.c | 58 | ||||
| -rw-r--r-- | gtk/gtkfilefilter.c | 559 | ||||
| -rw-r--r-- | gtk/gtkfilefilter.h | 67 | ||||
| -rw-r--r-- | gtk/gtkfilesystemmodel.c | 60 | ||||
| -rw-r--r-- | tests/testfilechooser.c | 22 | ||||
| -rw-r--r-- | tests/testgtk.c | 5 | ||||
| -rw-r--r-- | testsuite/gtk/builder.c | 14 |
9 files changed, 313 insertions, 483 deletions
diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml index 643fc0ebc1..3e2751c6b7 100644 --- a/docs/reference/gtk/gtk4-docs.xml +++ b/docs/reference/gtk/gtk4-docs.xml @@ -54,8 +54,9 @@ <section> <xi:include href="xml/gtkfilter.xml" /> <xi:include href="xml/gtkcustomfilter.xml" /> - <xi:include href="xml/gtkstringfilter.xml" /> <xi:include href="xml/gtkmultifilter.xml" /> + <xi:include href="xml/gtkstringfilter.xml" /> + <xi:include href="xml/gtkfilefilter.xml" /> </section> <xi:include href="xml/gtkflattenlistmodel.xml" /> <xi:include href="xml/gtkmaplistmodel.xml" /> @@ -285,7 +286,6 @@ <xi:include href="xml/gtkfilechoosernative.xml" /> <xi:include href="xml/gtkfilechooserdialog.xml" /> <xi:include href="xml/gtkfilechooserwidget.xml" /> - <xi:include href="xml/gtkfilefilter.xml" /> <xi:include href="xml/gtkfontchooser.xml" /> <xi:include href="xml/gtkfontbutton.xml" /> <xi:include href="xml/gtkfontchooserwidget.xml" /> diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index c6da63ac74..5edc931771 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -1413,18 +1413,13 @@ GtkFileChooserButtonPrivate <SECTION> <FILE>gtkfilefilter</FILE> GtkFileFilter -GtkFileFilterInfo -GtkFileFilterFlags -GtkFileFilterFunc gtk_file_filter_new gtk_file_filter_set_name gtk_file_filter_get_name gtk_file_filter_add_mime_type gtk_file_filter_add_pattern gtk_file_filter_add_pixbuf_formats -gtk_file_filter_add_custom -gtk_file_filter_get_needed -gtk_file_filter_filter +gtk_file_filter_get_attributes <SUBSECTION Serialization> gtk_file_filter_new_from_gvariant diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c index 60d6e3bff4..695d3db352 100644 --- a/gtk/gtkfilechooserentry.c +++ b/gtk/gtkfilechooserentry.c @@ -33,6 +33,7 @@ #include "gtkintl.h" #include "gtkmarshalers.h" #include "gtkfilefilterprivate.h" +#include "gtkfilter.h" #include "gtkeventcontrollerfocus.h" typedef struct _GtkFileChooserEntryClass GtkFileChooserEntryClass; @@ -194,65 +195,22 @@ match_func (GtkEntryCompletion *compl, * current file filter (e.g. just jpg files) here. */ if (chooser_entry->current_filter != NULL) { - char *mime_type = NULL; - gboolean matches; GFile *file; - GFileInfo *file_info; - GtkFileFilterInfo filter_info; - GtkFileFilterFlags needed_flags; + GFileInfo *info; file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store), iter); - file_info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store), - iter); + info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store), + iter); /* We always allow navigating into subfolders, so don't ever filter directories */ - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR) + if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR) return TRUE; - needed_flags = gtk_file_filter_get_needed (chooser_entry->current_filter); - - filter_info.display_name = g_file_info_get_display_name (file_info); - filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME; - - if (needed_flags & GTK_FILE_FILTER_MIME_TYPE) - { - const char *s = g_file_info_get_content_type (file_info); - if (s != NULL) - { - mime_type = g_content_type_get_mime_type (s); - if (mime_type != NULL) - { - filter_info.mime_type = mime_type; - filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE; - } - } - } - - if (needed_flags & GTK_FILE_FILTER_FILENAME) - { - const char *path = g_file_get_path (file); - if (path != NULL) - { - filter_info.filename = path; - filter_info.contains |= GTK_FILE_FILTER_FILENAME; - } - } - - if (needed_flags & GTK_FILE_FILTER_URI) - { - const char *uri = g_file_get_uri (file); - if (uri) - { - filter_info.uri = uri; - filter_info.contains |= GTK_FILE_FILTER_URI; - } - } - - matches = gtk_file_filter_filter (chooser_entry->current_filter, &filter_info); + if (!g_file_info_has_attribute (info, "standard::file")) + g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file)); - g_free (mime_type); - return matches; + return gtk_filter_match (GTK_FILTER (chooser_entry->current_filter), info); } return TRUE; diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c index 33ad641065..c2b8bb5537 100644 --- a/gtk/gtkfilefilter.c +++ b/gtk/gtkfilefilter.c @@ -18,15 +18,14 @@ /** * SECTION:gtkfilefilter - * @Short_description: A filter for selecting a file subset + * @Short_description: Filtering files * @Title: GtkFileFilter * @see_also: #GtkFileChooser * * A GtkFileFilter can be used to restrict the files being shown in a * #GtkFileChooser. Files can be filtered based on their name (with - * gtk_file_filter_add_pattern()), on their mime type (with - * gtk_file_filter_add_mime_type()), or by a custom filter function - * (with gtk_file_filter_add_custom()). + * gtk_file_filter_add_pattern()) or on their mime type (with + * gtk_file_filter_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 @@ -34,9 +33,10 @@ * text/plain. Note that #GtkFileFilter allows wildcards for the * subtype of a mime type, so you can e.g. filter for image/\*. * - * Normally, filters are used by adding them to a #GtkFileChooser, - * see gtk_file_chooser_add_filter(), but it is also possible - * to manually use a filter on a file with gtk_file_filter_filter(). + * Normally, file filters are used by adding them to a #GtkFileChooser + * (see gtk_file_chooser_add_filter()), but it is also possible to + * manually use a file filter on any #GtkFilterListModel containing + * #GFileInfo objects. * * # GtkFileFilter as GtkBuildable * @@ -73,6 +73,7 @@ #include "gtkbuilderprivate.h" #include "gtkintl.h" #include "gtkprivate.h" +#include "gtkfilter.h" typedef struct _GtkFileFilterClass GtkFileFilterClass; typedef struct _FilterRule FilterRule; @@ -84,39 +85,32 @@ typedef struct _FilterRule FilterRule; typedef enum { FILTER_RULE_PATTERN, FILTER_RULE_MIME_TYPE, - FILTER_RULE_PIXBUF_FORMATS, - FILTER_RULE_CUSTOM + FILTER_RULE_PIXBUF_FORMATS } FilterRuleType; struct _GtkFileFilterClass { - GInitiallyUnownedClass parent_class; + GtkFilterClass parent_class; }; struct _GtkFileFilter { - GInitiallyUnowned parent_instance; + GtkFilter parent_instance; gchar *name; GSList *rules; - GtkFileFilterFlags needed; + char **attributes; }; struct _FilterRule { FilterRuleType type; - GtkFileFilterFlags needed; - + union { - gchar *pattern; - gchar *mime_type; + char *pattern; + char **content_types; GSList *pixbuf_formats; - struct { - GtkFileFilterFunc func; - gpointer data; - GDestroyNotify notify; - } custom; } u; }; @@ -156,7 +150,12 @@ static void gtk_file_filter_buildable_custom_tag_end (GtkBuildable const gchar *tagname, gpointer data); -G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, G_TYPE_INITIALLY_UNOWNED, +static gboolean gtk_file_filter_match (GtkFilter *filter, + gpointer item); +static GtkFilterMatch gtk_file_filter_get_strictness (GtkFilter *filter); + + +G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, GTK_TYPE_FILTER, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_file_filter_buildable_init)) @@ -169,11 +168,15 @@ static void gtk_file_filter_class_init (GtkFileFilterClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkFilterClass *filter_class = GTK_FILTER_CLASS (class); gobject_class->set_property = gtk_file_filter_set_property; gobject_class->get_property = gtk_file_filter_get_property; gobject_class->finalize = gtk_file_filter_finalize; + filter_class->get_strictness = gtk_file_filter_get_strictness; + filter_class->match = gtk_file_filter_match; + /** * GtkFileFilter:name: * @@ -197,18 +200,12 @@ filter_rule_free (FilterRule *rule) { switch (rule->type) { - case FILTER_RULE_MIME_TYPE: - g_free (rule->u.mime_type); - break; case FILTER_RULE_PATTERN: g_free (rule->u.pattern); break; - case FILTER_RULE_CUSTOM: - if (rule->u.custom.notify) - rule->u.custom.notify (rule->u.custom.data); - break; + case FILTER_RULE_MIME_TYPE: case FILTER_RULE_PIXBUF_FORMATS: - g_slist_free (rule->u.pixbuf_formats); + g_strfreev (rule->u.content_types); break; default: g_assert_not_reached (); @@ -261,6 +258,7 @@ gtk_file_filter_finalize (GObject *object) GtkFileFilter *filter = GTK_FILE_FILTER (object); g_slist_free_full (filter->rules, (GDestroyNotify)filter_rule_free); + g_strfreev (filter->attributes); g_free (filter->name); @@ -436,21 +434,22 @@ gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable, } } - /** * gtk_file_filter_new: - * + * * Creates a new #GtkFileFilter with no rules added to it. + * * Such a filter doesn’t accept any files, so is not * particularly useful until you add rules with * gtk_file_filter_add_mime_type(), gtk_file_filter_add_pattern(), - * or gtk_file_filter_add_custom(). To create a filter - * that accepts any file, use: + * or gtk_file_filter_add_pixbuf_formats(). + * + * To create a filter that accepts any file, use: * |[<!-- language="C" --> * GtkFileFilter *filter = gtk_file_filter_new (); * gtk_file_filter_add_pattern (filter, "*"); * ]| - * + * * Returns: a new #GtkFileFilter **/ GtkFileFilter * @@ -464,14 +463,14 @@ gtk_file_filter_new (void) * @filter: a #GtkFileFilter * @name: (allow-none): the human-readable-name for the filter, or %NULL * to remove any existing name. - * - * Sets the human-readable name of the filter; this is the string - * that will be displayed in the file selector user interface if - * there is a selectable list of filters. + * + * Sets a human-readable name of the filter; this is the string + * that will be displayed in the file chooser if there is a selectable + * list of filters. **/ void gtk_file_filter_set_name (GtkFileFilter *filter, - const gchar *name) + const gchar *name) { g_return_if_fail (GTK_IS_FILE_FILTER (filter)); @@ -487,18 +486,18 @@ gtk_file_filter_set_name (GtkFileFilter *filter, /** * gtk_file_filter_get_name: * @filter: a #GtkFileFilter - * + * * Gets the human-readable name for the filter. See gtk_file_filter_set_name(). - * + * * Returns: (nullable): The human-readable name of the filter, - * or %NULL. This value is owned by GTK+ and must not + * or %NULL. This value is owned by GTK and must not * be modified or freed. **/ const gchar * gtk_file_filter_get_name (GtkFileFilter *filter) { g_return_val_if_fail (GTK_IS_FILE_FILTER (filter), NULL); - + return filter->name; } @@ -506,31 +505,53 @@ static void file_filter_add_rule (GtkFileFilter *filter, FilterRule *rule) { - filter->needed |= rule->needed; filter->rules = g_slist_append (filter->rules, rule); + + gtk_filter_changed (GTK_FILTER (filter), GTK_FILTER_CHANGE_LESS_STRICT); +} + +static void +file_filter_add_attribute (GtkFileFilter *filter, + const char *attribute) +{ + int i; + + if (filter->attributes) + for (i = 0; filter->attributes[i]; i++) + { + if (strcmp (filter->attributes[i], attribute) == 0) + return; + } + else + i = 0; + + filter->attributes = (char **)g_renew (char **, filter->attributes, i + 2); + filter->attributes[i] = g_strdup (attribute); + filter->attributes[i + 1] = NULL; } /** * gtk_file_filter_add_mime_type: * @filter: A #GtkFileFilter * @mime_type: name of a MIME type - * + * * Adds a rule allowing a given mime type to @filter. **/ void gtk_file_filter_add_mime_type (GtkFileFilter *filter, - const gchar *mime_type) + const gchar *mime_type) { FilterRule *rule; - + g_return_if_fail (GTK_IS_FILE_FILTER (filter)); g_return_if_fail (mime_type != NULL); rule = g_slice_new (FilterRule); rule->type = FILTER_RULE_MIME_TYPE; - rule->needed = GTK_FILE_FILTER_MIME_TYPE; - rule->u.mime_type = g_strdup (mime_type); + rule->u.content_types = g_new0 (char *, 2); + rule->u.content_types[0] = g_content_type_from_mime_type (mime_type); + file_filter_add_attribute (filter, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); file_filter_add_rule (filter, rule); } @@ -552,90 +573,76 @@ gtk_file_filter_add_pattern (GtkFileFilter *filter, rule = g_slice_new (FilterRule); rule->type = FILTER_RULE_PATTERN; - rule->needed = GTK_FILE_FILTER_DISPLAY_NAME; rule->u.pattern = g_strdup (pattern); + 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 - * + * * Adds a rule allowing image files in the formats supported * by GdkPixbuf. + * + * This is equivalent to calling gtk_file_filter_add_mime_type() + * for all the supported mime types. **/ void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter) { FilterRule *rule; - + GPtrArray *array; + GSList *formats, *l; + g_return_if_fail (GTK_IS_FILE_FILTER (filter)); rule = g_slice_new (FilterRule); rule->type = FILTER_RULE_PIXBUF_FORMATS; - rule->needed = GTK_FILE_FILTER_MIME_TYPE; - rule->u.pixbuf_formats = gdk_pixbuf_get_formats (); - file_filter_add_rule (filter, rule); -} + array = g_ptr_array_new (); -/** - * gtk_file_filter_add_custom: - * @filter: a #GtkFileFilter - * @needed: bitfield of flags indicating the information that the custom - * filter function needs. - * @func: callback function; if the function returns %TRUE, then - * the file will be displayed. - * @data: data to pass to @func - * @notify: function to call to free @data when it is no longer needed. - * - * Adds rule to a filter that allows files based on a custom callback - * function. The bitfield @needed which is passed in provides information - * about what sorts of information that the filter function needs; - * this allows GTK+ to avoid retrieving expensive information when - * it isn’t needed by the filter. - **/ -void -gtk_file_filter_add_custom (GtkFileFilter *filter, - GtkFileFilterFlags needed, - GtkFileFilterFunc func, - gpointer data, - GDestroyNotify notify) -{ - FilterRule *rule; - - g_return_if_fail (GTK_IS_FILE_FILTER (filter)); - g_return_if_fail (func != NULL); + formats = gdk_pixbuf_get_formats (); + for (l = formats; l; l = l->next) + { + int i; + char **mime_types; - rule = g_slice_new (FilterRule); - rule->type = FILTER_RULE_CUSTOM; - rule->needed = needed; - rule->u.custom.func = func; - rule->u.custom.data = data; - rule->u.custom.notify = notify; + mime_types = gdk_pixbuf_format_get_mime_types (l->data); + + for (i = 0; mime_types[i] != NULL; i++) + { + g_ptr_array_add (array, g_content_type_from_mime_type (mime_types[i])); + } + } + g_slist_free (formats); + + g_ptr_array_add (array, NULL); + + rule->u.content_types = (char **)g_ptr_array_free (array, FALSE); + file_filter_add_attribute (filter, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); file_filter_add_rule (filter, rule); } /** - * gtk_file_filter_get_needed: + * gtk_file_filter_get_attributes: * @filter: a #GtkFileFilter * - * Gets the fields that need to be filled in for the #GtkFileFilterInfo + * Gets the attributes that need to be filled in for the #GFileInfo * passed to gtk_file_filter_filter() * * This function will not typically be used by applications; it * is intended principally for use in the implementation of * #GtkFileChooser. * - * Returns: bitfield of flags indicating needed fields when - * calling gtk_file_filter_filter() + * Returns: (transfer none): the attributes **/ -GtkFileFilterFlags -gtk_file_filter_get_needed (GtkFileFilter *filter) +const char ** +gtk_file_filter_get_attributes (GtkFileFilter *filter) { - return filter->needed; + return (const char **)filter->attributes; } #ifdef GDK_WINDOWING_QUARTZ @@ -652,65 +659,65 @@ NSArray * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter) FilterRule *rule = tmp_list->data; switch (rule->type) - { - case FILTER_RULE_CUSTOM: - [array release]; - return NULL; - break; - case FILTER_RULE_MIME_TYPE: - { - // convert mime-types to UTI - NSString *mime_type_nsstring = [NSString stringWithUTF8String: rule->u.mime_type]; - NSString *uti_nsstring = (NSString *) UTTypeCreatePreferredIdentifierForTag (kUTTagClassMIMEType, (CFStringRef) mime_type_nsstring, NULL); - if (uti_nsstring == NULL) - { - [array release]; - return NULL; - } - [array addObject:uti_nsstring]; - } - break; - case FILTER_RULE_PATTERN: - { - // patterns will need to be stripped of their leading *. - GString *pattern = g_string_new (rule->u.pattern); - if (strncmp (pattern->str, "*.", 2) == 0) - { - pattern = g_string_erase (pattern, 0, 2); - } - else if (strncmp (pattern->str, "*", 1) == 0) - { - pattern = g_string_erase (pattern, 0, 1); - } - gchar *pattern_c = g_string_free (pattern, FALSE); - NSString *pattern_nsstring = [NSString stringWithUTF8String:pattern_c]; - g_free (pattern_c); - [pattern_nsstring retain]; - [array addObject:pattern_nsstring]; - } - break; - case FILTER_RULE_PIXBUF_FORMATS: - { - GSList *list; - - for (list = rule->u.pixbuf_formats; list; list = list->next) - { - int i; - gchar **extensions; - - extensions = gdk_pixbuf_format_get_extensions (list->data); - - for (i = 0; extensions[i] != NULL; i++) - { - NSString *extension = [NSString stringWithUTF8String: extensions[i]]; - [extension retain]; - [array addObject:extension]; - } - g_strfreev (extensions); - } - break; - } - } + { + case FILTER_RULE_MIME_TYPE: + { + // convert mime-types to UTI + NSString *mime_type_nsstring = [NSString stringWithUTF8String: rule->u.content_types[0]]; + NSString *uti_nsstring = (NSString *) UTTypeCreatePreferredIdentifierForTag (kUTTagClassMIMEType, (CFStringRef) mime_type_nsstring, NULL); + if (uti_nsstring == NULL) + { + [array release]; + return NULL; + } + [array addObject:uti_nsstring]; + } + break; + + case FILTER_RULE_PATTERN: + { + // patterns will need to be stripped of their leading *. + GString *pattern = g_string_new (rule->u.pattern); + if (strncmp (pattern->str, "*.", 2) == 0) + { + pattern = g_string_erase (pattern, 0, 2); + } + else if (strncmp (pattern->str, "*", 1) == 0) + { + pattern = g_string_erase (pattern, 0, 1); + } + gchar *pattern_c = g_string_free (pattern, FALSE); + NSString *pattern_nsstring = [NSString stringWithUTF8String:pattern_c]; + g_free (pattern_c); + [pattern_nsstring retain]; + [array addObject:pattern_nsstring]; + } + break; + + case FILTER_RULE_PIXBUF_FORMATS: + { + GSList *formats, *l; + + formats = gdk_pixbuf_get_formats (); + for (l = formats; l; l = l->next) + { + int i; + gchar **extensions; + + extensions = gdk_pixbuf_format_get_extensions (l->data); + + for (i = 0; extensions[i] != NULL; i++) + { + NSString *extension = [NSString stringWithUTF8String: extensions[i]]; + [extension retain]; + [array addObject:extension]; + } + g_strfreev (extensions); + } + g_slist_free (formats); + break; + } + } } return array; } @@ -729,131 +736,150 @@ _gtk_file_filter_get_as_patterns (GtkFileFilter *filter) FilterRule *rule = tmp_list->data; switch (rule->type) - { - case FILTER_RULE_CUSTOM: - case FILTER_RULE_MIME_TYPE: + { + case FILTER_RULE_MIME_TYPE: g_ptr_array_free (array, TRUE); return NULL; - break; - case FILTER_RULE_PATTERN: + break; + + case FILTER_RULE_PATTERN: g_ptr_array_add (array, g_strdup (rule->u.pattern)); - break; - case FILTER_RULE_PIXBUF_FORMATS: - { - GSList *list; + break; - for (list = rule->u.pixbuf_formats; list; list = list->next) - { - int i; - gchar **extensions; + case FILTER_RULE_PIXBUF_FORMATS: + { + GSList *formats, *l; + + formats = gdk_pixbuf_get_formats (); + for (l = formats; l; l = l->next) + { + int i; + char **extensions; - extensions = gdk_pixbuf_format_get_extensions (list->data); + extensions = gdk_pixbuf_format_get_extensions (l->data); - for (i = 0; extensions[i] != NULL; i++) + for (i = 0; extensions[i] != NULL; i++) g_ptr_array_add (array, g_strdup_printf ("*.%s", extensions[i])); - g_strfreev (extensions); - } - break; - } + g_strfreev (extensions); + } + g_slist_free (formats); + break; + } default: break; - } + } } g_ptr_array_add (array, NULL); /* Null terminate */ return (char **)g_ptr_array_free (array, FALSE); } -/** - * gtk_file_filter_filter: - * @filter: a #GtkFileFilter - * @filter_info: a #GtkFileFilterInfo containing information - * about a file. - * - * Tests whether a file should be displayed according to @filter. - * The #GtkFileFilterInfo @filter_info should include - * the fields returned from gtk_file_filter_get_needed(). - * - * This function will not typically be used by applications; it - * is intended principally for use in the implementation of - * #GtkFileChooser. - * - * Returns: %TRUE if the file should be displayed - **/ -gboolean -gtk_file_filter_filter (GtkFileFilter *filter, - const GtkFileFilterInfo *filter_info) +static GtkFilterMatch +gtk_file_filter_get_strictness (GtkFilter *filter) +{ + GtkFileFilter *file_filter = GTK_FILE_FILTER (filter); + + /* Handle only the documented cases for 'match all' + * and match none. There are of course other ways to + * make filters that do this. + */ + if (file_filter->rules == NULL) + return GTK_FILTER_MATCH_NONE; + + if (file_filter->rules->next == NULL) + { + FilterRule *rule = file_filter->rules->data; + if (rule->type == FILTER_RULE_PATTERN && + strcmp (rule->u.pattern, "*") == 0) + return GTK_FILTER_MATCH_ALL; + } + + return GTK_FILTER_MATCH_SOME; +} + +static gboolean +gtk_file_filter_match (GtkFilter *filter, + gpointer item) { + GtkFileFilter *file_filter = GTK_FILE_FILTER (filter); + GFileInfo *info = item; GSList *tmp_list; - for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next) + if (!G_IS_FILE_INFO (item)) + return TRUE; + + for (tmp_list = file_filter->rules; tmp_list; tmp_list = tmp_list->next) { FilterRule *rule = tmp_list->data; - if ((filter_info->contains & rule->needed) != rule->needed) - continue; - switch (rule->type) - { - case FILTER_RULE_MIME_TYPE: - if (filter_info->mime_type != NULL) - { - gchar *filter_content_type, *rule_content_type; - gboolean match; - - filter_content_type = g_content_type_from_mime_type (filter_info->mime_type); - rule_content_type = g_content_type_from_mime_type (rule->u.mime_type); - match = filter_content_type != NULL && - rule_content_type != NULL && - g_content_type_is_a (filter_content_type, rule_content_type); - g_free (filter_content_type); - g_free (rule_content_type); - - if (match) - return TRUE; - } - break; - case FILTER_RULE_PATTERN: - if (filter_info->display_name != NULL && - _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE)) - return TRUE; - break; - case FILTER_RULE_PIXBUF_FORMATS: - { - GSList *list; - - if (!filter_info->mime_type) - break; - - for (list = rule->u.pixbuf_formats; list; list = list->next) - { - int i; - gchar **mime_types; - - mime_types = gdk_pixbuf_format_get_mime_types (list->data); - - for (i = 0; mime_types[i] != NULL; i++) - { - if (strcmp (mime_types[i], filter_info->mime_type) == 0) - { - g_strfreev (mime_types); - return TRUE; - } - } - - g_strfreev (mime_types); - } - break; - } - case FILTER_RULE_CUSTOM: - if (rule->u.custom.func (filter_info, rule->u.custom.data)) - return TRUE; - break; + { + case FILTER_RULE_PATTERN: + { + const char *display_name; + + display_name = g_file_info_get_display_name (info); + if (display_name) + { + if (_gtk_fnmatch (rule->u.pattern, display_name, FALSE)) + return TRUE; + } + } + break; + + case FILTER_RULE_MIME_TYPE: + case FILTER_RULE_PIXBUF_FORMATS: + { + const char *filter_content_type; + + filter_content_type = g_file_info_get_content_type (info); + if (filter_content_type) + { + int i; + + for (i = 0; rule->u.content_types[i]; i++) + { + if (g_content_type_is_a (filter_content_type, rule->u.content_types[i])) + return TRUE; + } + } + } + break; + + { + const char *filter_content_type; + + filter_content_type = g_file_info_get_content_type (info); + if (filter_content_type) + { + GSList *list; + + for (list = rule->u.pixbuf_formats; list; list = list->next) + { + int i; + char **mime_types; + + mime_types = gdk_pixbuf_format_get_mime_types (list->data); + + for (i = 0; mime_types[i] != NULL; i++) + { + if (strcmp (mime_types[i], filter_content_type) == 0) + { + g_strfreev (mime_types); + return TRUE; + } + } + + g_strfreev (mime_types); + } + } + } + break; default: break; - } + } } return FALSE; @@ -877,33 +903,20 @@ gtk_file_filter_to_gvariant (GtkFileFilter *filter) for (l = filter->rules; l; l = l->next) { FilterRule *rule = l->data; + int i; switch (rule->type) { case FILTER_RULE_PATTERN: g_variant_builder_add (&builder, "(us)", 0, rule->u.pattern); break; + case FILTER_RULE_MIME_TYPE: - g_variant_builder_add (&builder, "(us)", 1, rule->u.mime_type); - break; case FILTER_RULE_PIXBUF_FORMATS: - { - GSList *f; - - for (f = rule->u.pixbuf_formats; f; f = f->next) - { - GdkPixbufFormat *fmt = f->data; - gchar **mime_types; - int i; - - mime_types = gdk_pixbuf_format_get_mime_types (fmt); - for (i = 0; mime_types[i]; i++) - g_variant_builder_add (&builder, "(us)", 1, mime_types[i]); - g_strfreev (mime_types); - } - } + for (i = 0; rule->u.content_types[i]; i++) + g_variant_builder_add (&builder, "(us)", 1, rule->u.content_types[i]); break; - case FILTER_RULE_CUSTOM: + default: break; } diff --git a/gtk/gtkfilefilter.h b/gtk/gtkfilefilter.h index c3ee9eb3f1..1adc1139d7 100644 --- a/gtk/gtkfilefilter.h +++ b/gtk/gtkfilefilter.h @@ -33,62 +33,6 @@ G_BEGIN_DECLS #define GTK_IS_FILE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FILTER)) typedef struct _GtkFileFilter GtkFileFilter; -typedef struct _GtkFileFilterInfo GtkFileFilterInfo; - -/** - * GtkFileFilterFlags: - * @GTK_FILE_FILTER_FILENAME: the filename of the file being tested - * @GTK_FILE_FILTER_URI: the URI for the file being tested - * @GTK_FILE_FILTER_DISPLAY_NAME: the string that will be used to - * display the file in the file chooser - * @GTK_FILE_FILTER_MIME_TYPE: the mime type of the file - * - * These flags indicate what parts of a #GtkFileFilterInfo struct - * are filled or need to be filled. - */ -typedef enum { - GTK_FILE_FILTER_FILENAME = 1 << 0, - GTK_FILE_FILTER_URI = 1 << 1, - GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2, - GTK_FILE_FILTER_MIME_TYPE = 1 << 3 -} GtkFileFilterFlags; - -/** - * GtkFileFilterFunc: - * @filter_info: a #GtkFileFilterInfo that is filled according - * to the @needed flags passed to gtk_file_filter_add_custom() - * @data: (closure): user data passed to gtk_file_filter_add_custom() - * - * The type of function that is used with custom filters, see - * gtk_file_filter_add_custom(). - * - * Returns: %TRUE if the file should be displayed - */ -typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info, - gpointer data); - -/** - * GtkFileFilterInfo: - * @contains: Flags indicating which of the following fields need - * are filled - * @filename: the filename of the file being tested - * @uri: the URI for the file being tested - * @display_name: the string that will be used to display the file - * in the file chooser - * @mime_type: the mime type of the file - * - * A #GtkFileFilterInfo is used to pass information about the - * tested file to gtk_file_filter_filter(). - */ -struct _GtkFileFilterInfo -{ - GtkFileFilterFlags contains; - - const gchar *filename; - const gchar *uri; - const gchar *display_name; - const gchar *mime_type; -}; GDK_AVAILABLE_IN_ALL GType gtk_file_filter_get_type (void) G_GNUC_CONST; @@ -109,18 +53,9 @@ void gtk_file_filter_add_pattern (GtkFileFilter *filter, const gchar *pattern); GDK_AVAILABLE_IN_ALL void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter); -GDK_AVAILABLE_IN_ALL -void gtk_file_filter_add_custom (GtkFileFilter *filter, - GtkFileFilterFlags needed, - GtkFileFilterFunc func, - gpointer data, - GDestroyNotify notify); GDK_AVAILABLE_IN_ALL -GtkFileFilterFlags gtk_file_filter_get_needed (GtkFileFilter *filter); -GDK_AVAILABLE_IN_ALL -gboolean gtk_file_filter_filter (GtkFileFilter *filter, - const GtkFileFilterInfo *filter_info); +const char ** gtk_file_filter_get_attributes (GtkFileFilter *filter); GDK_AVAILABLE_IN_ALL GVariant *gtk_file_filter_to_gvariant (GtkFileFilter *filter); diff --git a/gtk/gtkfilesystemmodel.c b/gtk/gtkfilesystemmodel.c index af9fce15d0..006cb1252b 100644 --- a/gtk/gtkfilesystemmodel.c +++ b/gtk/gtkfilesystemmodel.c @@ -29,6 +29,7 @@ #include "gtktreedatalist.h" #include "gtktreednd.h" #include "gtktreemodel.h" +#include "gtkfilter.h" /*** Structure: how GtkFileSystemModel works * @@ -375,12 +376,6 @@ static gboolean node_should_be_filtered_out (GtkFileSystemModel *model, guint id) { FileModelNode *node = get_node (model, id); - GtkFileFilterInfo filter_info = { 0, }; - GtkFileFilterFlags required; - gboolean result; - char *mime_type = NULL; - char *filename = NULL; - char *uri = NULL; if (node->info == NULL) return TRUE; @@ -388,57 +383,10 @@ node_should_be_filtered_out (GtkFileSystemModel *model, guint id) if (model->filter == NULL) return FALSE; - /* fill info */ - required = gtk_file_filter_get_needed (model->filter); - - filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME; - filter_info.display_name = g_file_info_get_display_name (node->info); - - if (required & GTK_FILE_FILTER_MIME_TYPE) - { - const char *s = g_file_info_get_content_type (node->info); - - if (!s) - s = g_file_info_get_attribute_string (node->info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE); - - if (s) - { - mime_type = g_content_type_get_mime_type (s); - if (mime_type) - { - filter_info.mime_type = mime_type; - filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE; - } - } - } - - if (required & GTK_FILE_FILTER_FILENAME) - { - filename = g_file_get_path (node->file); - if (filename) - { - filter_info.filename = filename; - filter_info.contains |= GTK_FILE_FILTER_FILENAME; - } - } - - if (required & GTK_FILE_FILTER_URI) - { - uri = g_file_get_uri (node->file); - if (uri) - { - filter_info.uri = uri; - filter_info.contains |= GTK_FILE_FILTER_URI; - } - } - - result = !gtk_file_filter_filter (model->filter, &filter_info); + if (!g_file_info_has_attribute (node->info, "standard::file")) + g_file_info_set_attribute_object (node->info, "standard::file", G_OBJECT (node->file)); - g_free (mime_type); - g_free (filename); - g_free (uri); - - return result; + return !gtk_filter_match (GTK_FILTER (model->filter), node->info); } static gboolean diff --git a/tests/testfilechooser.c b/tests/testfilechooser.c index 71c0358af3..d3378d472a 100644 --- a/tests/testfilechooser.c +++ b/tests/testfilechooser.c @@ -118,17 +118,6 @@ response_cb (GtkDialog *dialog, g_main_context_wakeup (NULL); } -static gboolean -no_backup_files_filter (const GtkFileFilterInfo *filter_info, - gpointer data) -{ - gsize len = filter_info->display_name ? strlen (filter_info->display_name) : 0; - if (len > 0 && filter_info->display_name[len - 1] == '~') - return 0; - else - return 1; -} - static void filter_changed (GtkFileChooserDialog *dialog, gpointer data) @@ -393,18 +382,13 @@ main (int argc, char **argv) /* Make this filter the default */ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, "No backup files"); - gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_DISPLAY_NAME, - no_backup_files_filter, NULL, NULL); - gtk_file_filter_add_mime_type (filter, "image/png"); - gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + g_object_unref (filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, "Starts with D"); gtk_file_filter_add_pattern (filter, "D*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + g_object_unref (filter); g_signal_connect (dialog, "notify::filter", G_CALLBACK (filter_changed), NULL); @@ -414,11 +398,13 @@ main (int argc, char **argv) gtk_file_filter_add_mime_type (filter, "image/jpeg"); gtk_file_filter_add_mime_type (filter, "image/png"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + g_object_unref (filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, "Images"); gtk_file_filter_add_pixbuf_formats (filter); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter); + g_object_unref (filter); /* Choices */ diff --git a/tests/testgtk.c b/tests/testgtk.c index 791ea10f46..10507a3f3a 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -5692,17 +5692,20 @@ native_filter_changed (GtkWidget *combo, gtk_file_filter_add_pattern (filter, "*.doc"); gtk_file_filter_add_pattern (filter, "*.txt"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); + g_object_unref (filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, "Images"); gtk_file_filter_add_pixbuf_formats (filter); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), filter); + g_object_unref (filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, "All"); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); + g_object_unref (filter); break; case 2: /* mimetype */ @@ -5710,12 +5713,14 @@ native_filter_changed (GtkWidget *combo, gtk_file_filter_set_name (filter, "Text"); gtk_file_filter_add_mime_type (filter, "text/plain"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); + g_object_unref (filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, "All"); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter); gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), filter); + g_object_unref (filter); break; default: g_assert_not_reached (); diff --git a/testsuite/gtk/builder.c b/testsuite/gtk/builder.c index db1eb2dd04..18b29e2078 100644 --- a/testsuite/gtk/builder.c +++ b/testsuite/gtk/builder.c @@ -2387,7 +2387,6 @@ test_file_filter (void) GtkBuilder *builder; GObject *obj; GtkFileFilter *filter; - GtkFileFilterInfo info; const gchar buffer[] = "<interface>" @@ -2409,17 +2408,8 @@ test_file_filter (void) g_assert (GTK_IS_FILE_FILTER (obj)); filter = GTK_FILE_FILTER (obj); g_assert_cmpstr (gtk_file_filter_get_name (filter), ==, "Text and Images"); - g_assert (gtk_file_filter_get_needed (filter) & GTK_FILE_FILTER_MIME_TYPE); - g_assert (gtk_file_filter_get_needed (filter) & GTK_FILE_FILTER_DISPLAY_NAME); - - info.filename = "test1.txt"; - info.display_name = "test1.txt"; - info.contains = GTK_FILE_FILTER_FILENAME | GTK_FILE_FILTER_DISPLAY_NAME; - g_assert (gtk_file_filter_filter (filter, &info)); - - info.mime_type = "application/x-pdf"; - info.contains = GTK_FILE_FILTER_MIME_TYPE; - g_assert (!gtk_file_filter_filter (filter, &info)); + g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)); + g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)); g_object_unref (builder); } |
