1 /* GTK - The GIMP Toolkit
2 * gtkfilefilter.c: Filters for selecting a file subset
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 * SECTION:gtkfilefilter
21 * @Short_description: A filter for selecting a file subset
22 * @Title: GtkFileFilter
24 * A GtkFileFilter can be used to restrict the files being shown in a
25 * #GtkFileChooser. Files can be filtered based on their name (with
26 * gtk_file_filter_add_pattern()), on their mime type (with
27 * gtk_file_filter_add_mime_type()), or by a custom filter function
28 * (with gtk_file_filter_add_custom()).
30 * Filtering by mime types handles aliasing and subclassing of mime
31 * types; e.g. a filter for text/plain also matches a file with mime
32 * type application/rtf, since application/rtf is a subclass of
33 * text/plain. Note that #GtkFileFilter allows wildcards for the
34 * subtype of a mime type, so you can e.g. filter for image/*.
36 * Normally, filters are used by adding them to a #GtkFileChooser,
37 * see gtk_file_chooser_add_filter(), but it is also possible
38 * to manually use a filter on a file with gtk_file_filter_filter().
40 * <refsect2 id="GtkFileFilter-BUILDER-UI">
41 * <title>GtkFileFilter as GtkBuildable</title>
43 * The GtkFileFilter implementation of the GtkBuildable interface
44 * supports adding rules using the <mime-types>, <patterns> and
45 * <applications> elements and listing the rules within. Specifying
46 * a <mime-type> or <pattern> is the same
47 * as calling gtk_recent_filter_add_mime_type() or gtk_recent_filter_add_pattern()
50 * <title>A UI definition fragment specifying GtkFileFilter rules</title>
51 * <programlisting><![CDATA[
52 * <object class="GtkFileFilter">
54 * <mime-type>text/plain</mime-type>
55 * <mime-type>image/*</mime-type>
58 * <pattern>*.txt</pattern>
59 * <pattern>*.png</pattern>
62 * ]]></programlisting>
67 * @see_also: #GtkFileChooser
73 #include <gdk-pixbuf/gdk-pixbuf.h>
75 #include "gtkfilefilter.h"
76 #include "gtkbuildable.h"
78 #include "gtkprivate.h"
80 typedef struct _GtkFileFilterClass GtkFileFilterClass;
81 typedef struct _FilterRule FilterRule;
83 #define GTK_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
84 #define GTK_IS_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FILTER))
85 #define GTK_FILE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
89 FILTER_RULE_MIME_TYPE,
90 FILTER_RULE_PIXBUF_FORMATS,
94 struct _GtkFileFilterClass
96 GInitiallyUnownedClass parent_class;
101 GInitiallyUnowned parent_instance;
106 GtkFileFilterFlags needed;
112 GtkFileFilterFlags needed;
117 GSList *pixbuf_formats;
119 GtkFileFilterFunc func;
121 GDestroyNotify notify;
126 static void gtk_file_filter_finalize (GObject *object);
129 static void gtk_file_filter_buildable_init (GtkBuildableIface *iface);
130 static gboolean gtk_file_filter_buildable_custom_tag_start (GtkBuildable *buildable,
133 const gchar *tagname,
134 GMarkupParser *parser,
136 static void gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable,
139 const gchar *tagname,
142 G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, G_TYPE_INITIALLY_UNOWNED,
143 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
144 gtk_file_filter_buildable_init))
147 gtk_file_filter_init (GtkFileFilter *object)
152 gtk_file_filter_class_init (GtkFileFilterClass *class)
154 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
156 gobject_class->finalize = gtk_file_filter_finalize;
160 filter_rule_free (FilterRule *rule)
164 case FILTER_RULE_MIME_TYPE:
165 g_free (rule->u.mime_type);
167 case FILTER_RULE_PATTERN:
168 g_free (rule->u.pattern);
170 case FILTER_RULE_CUSTOM:
171 if (rule->u.custom.notify)
172 rule->u.custom.notify (rule->u.custom.data);
174 case FILTER_RULE_PIXBUF_FORMATS:
175 g_slist_free (rule->u.pixbuf_formats);
178 g_assert_not_reached ();
181 g_slice_free (FilterRule, rule);
185 gtk_file_filter_finalize (GObject *object)
187 GtkFileFilter *filter = GTK_FILE_FILTER (object);
189 g_slist_foreach (filter->rules, (GFunc)filter_rule_free, NULL);
190 g_slist_free (filter->rules);
192 g_free (filter->name);
194 G_OBJECT_CLASS (gtk_file_filter_parent_class)->finalize (object);
198 * GtkBuildable implementation
201 gtk_file_filter_buildable_init (GtkBuildableIface *iface)
203 iface->custom_tag_start = gtk_file_filter_buildable_custom_tag_start;
204 iface->custom_tag_end = gtk_file_filter_buildable_custom_tag_end;
213 GtkFileFilter *filter;
220 parser_start_element (GMarkupParseContext *context,
221 const gchar *element_name,
223 const gchar **values,
227 SubParserData *parser_data = (SubParserData*)user_data;
229 if (strcmp (element_name, "mime-types") == 0)
231 else if (strcmp (element_name, "mime-type") == 0)
233 parser_data->parsing = TRUE;
236 else if (strcmp (element_name, "patterns") == 0)
238 else if (strcmp (element_name, "pattern") == 0)
240 parser_data->parsing = TRUE;
244 g_warning ("Unsupported tag for GtkFileFilter: %s\n", element_name);
248 parser_text_element (GMarkupParseContext *context,
254 SubParserData *parser_data = (SubParserData*)user_data;
256 if (parser_data->parsing)
257 g_string_append_len (parser_data->string, text, text_len);
261 parser_end_element (GMarkupParseContext *context,
262 const gchar *element_name,
266 SubParserData *parser_data = (SubParserData*)user_data;
268 if (parser_data->string)
270 switch (parser_data->type)
272 case PARSE_MIME_TYPES:
273 gtk_file_filter_add_mime_type (parser_data->filter, parser_data->string->str);
276 gtk_file_filter_add_pattern (parser_data->filter, parser_data->string->str);
283 g_string_set_size (parser_data->string, 0);
284 parser_data->parsing = FALSE;
287 static const GMarkupParser sub_parser =
289 parser_start_element,
295 gtk_file_filter_buildable_custom_tag_start (GtkBuildable *buildable,
298 const gchar *tagname,
299 GMarkupParser *parser,
302 SubParserData *parser_data = NULL;
304 if (strcmp (tagname, "mime-types") == 0)
306 parser_data = g_slice_new0 (SubParserData);
307 parser_data->string = g_string_new ("");
308 parser_data->type = PARSE_MIME_TYPES;
309 parser_data->filter = GTK_FILE_FILTER (buildable);
311 *parser = sub_parser;
314 else if (strcmp (tagname, "patterns") == 0)
316 parser_data = g_slice_new0 (SubParserData);
317 parser_data->string = g_string_new ("");
318 parser_data->type = PARSE_PATTERNS;
319 parser_data->filter = GTK_FILE_FILTER (buildable);
321 *parser = sub_parser;
325 return parser_data != NULL;
329 gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable,
332 const gchar *tagname,
335 if (strcmp (tagname, "mime-types") == 0 ||
336 strcmp (tagname, "patterns") == 0)
338 SubParserData *parser_data = (SubParserData*)data;
340 g_string_free (parser_data->string, TRUE);
341 g_slice_free (SubParserData, parser_data);
347 * gtk_file_filter_new:
349 * Creates a new #GtkFileFilter with no rules added to it.
350 * Such a filter doesn't accept any files, so is not
351 * particularly useful until you add rules with
352 * gtk_file_filter_add_mime_type(), gtk_file_filter_add_pattern(),
353 * or gtk_file_filter_add_custom(). To create a filter
354 * that accepts any file, use:
356 * GtkFileFilter *filter = gtk_file_filter_new ();
357 * gtk_file_filter_add_pattern (filter, "*");
360 * Return value: a new #GtkFileFilter
365 gtk_file_filter_new (void)
367 return g_object_new (GTK_TYPE_FILE_FILTER, NULL);
371 * gtk_file_filter_set_name:
372 * @filter: a #GtkFileFilter
373 * @name: (allow-none): the human-readable-name for the filter, or %NULL
374 * to remove any existing name.
376 * Sets the human-readable name of the filter; this is the string
377 * that will be displayed in the file selector user interface if
378 * there is a selectable list of filters.
383 gtk_file_filter_set_name (GtkFileFilter *filter,
386 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
388 g_free (filter->name);
390 filter->name = g_strdup (name);
394 * gtk_file_filter_get_name:
395 * @filter: a #GtkFileFilter
397 * Gets the human-readable name for the filter. See gtk_file_filter_set_name().
399 * Return value: The human-readable name of the filter,
400 * or %NULL. This value is owned by GTK+ and must not
401 * be modified or freed.
406 gtk_file_filter_get_name (GtkFileFilter *filter)
408 g_return_val_if_fail (GTK_IS_FILE_FILTER (filter), NULL);
414 file_filter_add_rule (GtkFileFilter *filter,
417 filter->needed |= rule->needed;
418 filter->rules = g_slist_append (filter->rules, rule);
422 * gtk_file_filter_add_mime_type:
423 * @filter: A #GtkFileFilter
424 * @mime_type: name of a MIME type
426 * Adds a rule allowing a given mime type to @filter.
431 gtk_file_filter_add_mime_type (GtkFileFilter *filter,
432 const gchar *mime_type)
436 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
437 g_return_if_fail (mime_type != NULL);
439 rule = g_slice_new (FilterRule);
440 rule->type = FILTER_RULE_MIME_TYPE;
441 rule->needed = GTK_FILE_FILTER_MIME_TYPE;
442 rule->u.mime_type = g_strdup (mime_type);
444 file_filter_add_rule (filter, rule);
448 * gtk_file_filter_add_pattern:
449 * @filter: a #GtkFileFilter
450 * @pattern: a shell style glob
452 * Adds a rule allowing a shell style glob to a filter.
457 gtk_file_filter_add_pattern (GtkFileFilter *filter,
458 const gchar *pattern)
462 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
463 g_return_if_fail (pattern != NULL);
465 rule = g_slice_new (FilterRule);
466 rule->type = FILTER_RULE_PATTERN;
467 rule->needed = GTK_FILE_FILTER_DISPLAY_NAME;
468 rule->u.pattern = g_strdup (pattern);
470 file_filter_add_rule (filter, rule);
474 * gtk_file_filter_add_pixbuf_formats:
475 * @filter: a #GtkFileFilter
477 * Adds a rule allowing image files in the formats supported
483 gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter)
487 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
489 rule = g_slice_new (FilterRule);
490 rule->type = FILTER_RULE_PIXBUF_FORMATS;
491 rule->needed = GTK_FILE_FILTER_MIME_TYPE;
492 rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
493 file_filter_add_rule (filter, rule);
498 * gtk_file_filter_add_custom:
499 * @filter: a #GtkFileFilter
500 * @needed: bitfield of flags indicating the information that the custom
501 * filter function needs.
502 * @func: callback function; if the function returns %TRUE, then
503 * the file will be displayed.
504 * @data: data to pass to @func
505 * @notify: function to call to free @data when it is no longer needed.
507 * Adds rule to a filter that allows files based on a custom callback
508 * function. The bitfield @needed which is passed in provides information
509 * about what sorts of information that the filter function needs;
510 * this allows GTK+ to avoid retrieving expensive information when
511 * it isn't needed by the filter.
516 gtk_file_filter_add_custom (GtkFileFilter *filter,
517 GtkFileFilterFlags needed,
518 GtkFileFilterFunc func,
520 GDestroyNotify notify)
524 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
525 g_return_if_fail (func != NULL);
527 rule = g_slice_new (FilterRule);
528 rule->type = FILTER_RULE_CUSTOM;
529 rule->needed = needed;
530 rule->u.custom.func = func;
531 rule->u.custom.data = data;
532 rule->u.custom.notify = notify;
534 file_filter_add_rule (filter, rule);
538 * gtk_file_filter_get_needed:
539 * @filter: a #GtkFileFilter
541 * Gets the fields that need to be filled in for the structure
542 * passed to gtk_file_filter_filter()
544 * This function will not typically be used by applications; it
545 * is intended principally for use in the implementation of
548 * Return value: bitfield of flags indicating needed fields when
549 * calling gtk_file_filter_filter()
554 gtk_file_filter_get_needed (GtkFileFilter *filter)
556 return filter->needed;
560 * gtk_file_filter_filter:
561 * @filter: a #GtkFileFilter
562 * @filter_info: a #GtkFileFilterInfo structure containing information
565 * Tests whether a file should be displayed according to @filter.
566 * The #GtkFileFilterInfo structure @filter_info should include
567 * the fields returned from gtk_file_filter_get_needed().
569 * This function will not typically be used by applications; it
570 * is intended principally for use in the implementation of
573 * Return value: %TRUE if the file should be displayed
578 gtk_file_filter_filter (GtkFileFilter *filter,
579 const GtkFileFilterInfo *filter_info)
583 for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
585 FilterRule *rule = tmp_list->data;
587 if ((filter_info->contains & rule->needed) != rule->needed)
592 case FILTER_RULE_MIME_TYPE:
593 if (filter_info->mime_type != NULL &&
594 g_content_type_is_a (filter_info->mime_type, rule->u.mime_type))
597 case FILTER_RULE_PATTERN:
598 if (filter_info->display_name != NULL &&
599 _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
602 case FILTER_RULE_PIXBUF_FORMATS:
606 if (!filter_info->mime_type)
609 for (list = rule->u.pixbuf_formats; list; list = list->next)
614 mime_types = gdk_pixbuf_format_get_mime_types (list->data);
616 for (i = 0; mime_types[i] != NULL; i++)
618 if (strcmp (mime_types[i], filter_info->mime_type) == 0)
620 g_strfreev (mime_types);
625 g_strfreev (mime_types);
629 case FILTER_RULE_CUSTOM:
630 if (rule->u.custom.func (filter_info, rule->u.custom.data))