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
23 * @see_also: #GtkFileChooser
25 * A GtkFileFilter can be used to restrict the files being shown in a
26 * #GtkFileChooser. Files can be filtered based on their name (with
27 * gtk_file_filter_add_pattern()), on their mime type (with
28 * gtk_file_filter_add_mime_type()), or by a custom filter function
29 * (with gtk_file_filter_add_custom()).
31 * Filtering by mime types handles aliasing and subclassing of mime
32 * types; e.g. a filter for text/plain also matches a file with mime
33 * type application/rtf, since application/rtf is a subclass of
34 * text/plain. Note that #GtkFileFilter allows wildcards for the
35 * subtype of a mime type, so you can e.g. filter for image/*.
37 * Normally, filters are used by adding them to a #GtkFileChooser,
38 * see gtk_file_chooser_add_filter(), but it is also possible
39 * to manually use a filter on a file with gtk_file_filter_filter().
41 * <refsect2 id="GtkFileFilter-BUILDER-UI">
42 * <title>GtkFileFilter as GtkBuildable</title>
44 * The GtkFileFilter implementation of the GtkBuildable interface
45 * supports adding rules using the <mime-types>, <patterns> and
46 * <applications> elements and listing the rules within. Specifying
47 * a <mime-type> or <pattern> is the same
48 * as calling gtk_recent_filter_add_mime_type() or gtk_recent_filter_add_pattern()
51 * <title>A UI definition fragment specifying GtkFileFilter rules</title>
52 * <programlisting><![CDATA[
53 * <object class="GtkFileFilter">
55 * <mime-type>text/plain</mime-type>
56 * <mime-type>image/*</mime-type>
59 * <pattern>*.txt</pattern>
60 * <pattern>*.png</pattern>
63 * ]]></programlisting>
72 #include <gdk-pixbuf/gdk-pixbuf.h>
74 #include "gtkfilefilter.h"
75 #include "gtkbuildable.h"
77 #include "gtkprivate.h"
79 typedef struct _GtkFileFilterClass GtkFileFilterClass;
80 typedef struct _FilterRule FilterRule;
82 #define GTK_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
83 #define GTK_IS_FILE_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FILTER))
84 #define GTK_FILE_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
88 FILTER_RULE_MIME_TYPE,
89 FILTER_RULE_PIXBUF_FORMATS,
93 struct _GtkFileFilterClass
95 GInitiallyUnownedClass parent_class;
100 GInitiallyUnowned parent_instance;
105 GtkFileFilterFlags needed;
111 GtkFileFilterFlags needed;
116 GSList *pixbuf_formats;
118 GtkFileFilterFunc func;
120 GDestroyNotify notify;
125 static void gtk_file_filter_finalize (GObject *object);
128 static void gtk_file_filter_buildable_init (GtkBuildableIface *iface);
129 static gboolean gtk_file_filter_buildable_custom_tag_start (GtkBuildable *buildable,
132 const gchar *tagname,
133 GMarkupParser *parser,
135 static void gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable,
138 const gchar *tagname,
141 G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, G_TYPE_INITIALLY_UNOWNED,
142 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
143 gtk_file_filter_buildable_init))
146 gtk_file_filter_init (GtkFileFilter *object)
151 gtk_file_filter_class_init (GtkFileFilterClass *class)
153 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
155 gobject_class->finalize = gtk_file_filter_finalize;
159 filter_rule_free (FilterRule *rule)
163 case FILTER_RULE_MIME_TYPE:
164 g_free (rule->u.mime_type);
166 case FILTER_RULE_PATTERN:
167 g_free (rule->u.pattern);
169 case FILTER_RULE_CUSTOM:
170 if (rule->u.custom.notify)
171 rule->u.custom.notify (rule->u.custom.data);
173 case FILTER_RULE_PIXBUF_FORMATS:
174 g_slist_free (rule->u.pixbuf_formats);
177 g_assert_not_reached ();
180 g_slice_free (FilterRule, rule);
184 gtk_file_filter_finalize (GObject *object)
186 GtkFileFilter *filter = GTK_FILE_FILTER (object);
188 g_slist_foreach (filter->rules, (GFunc)filter_rule_free, NULL);
189 g_slist_free (filter->rules);
191 g_free (filter->name);
193 G_OBJECT_CLASS (gtk_file_filter_parent_class)->finalize (object);
197 * GtkBuildable implementation
200 gtk_file_filter_buildable_init (GtkBuildableIface *iface)
202 iface->custom_tag_start = gtk_file_filter_buildable_custom_tag_start;
203 iface->custom_tag_end = gtk_file_filter_buildable_custom_tag_end;
212 GtkFileFilter *filter;
219 parser_start_element (GMarkupParseContext *context,
220 const gchar *element_name,
222 const gchar **values,
226 SubParserData *parser_data = (SubParserData*)user_data;
228 if (strcmp (element_name, "mime-types") == 0)
230 else if (strcmp (element_name, "mime-type") == 0)
232 parser_data->parsing = TRUE;
235 else if (strcmp (element_name, "patterns") == 0)
237 else if (strcmp (element_name, "pattern") == 0)
239 parser_data->parsing = TRUE;
243 g_warning ("Unsupported tag for GtkFileFilter: %s\n", element_name);
247 parser_text_element (GMarkupParseContext *context,
253 SubParserData *parser_data = (SubParserData*)user_data;
255 if (parser_data->parsing)
256 g_string_append_len (parser_data->string, text, text_len);
260 parser_end_element (GMarkupParseContext *context,
261 const gchar *element_name,
265 SubParserData *parser_data = (SubParserData*)user_data;
267 if (parser_data->string)
269 switch (parser_data->type)
271 case PARSE_MIME_TYPES:
272 gtk_file_filter_add_mime_type (parser_data->filter, parser_data->string->str);
275 gtk_file_filter_add_pattern (parser_data->filter, parser_data->string->str);
282 g_string_set_size (parser_data->string, 0);
283 parser_data->parsing = FALSE;
286 static const GMarkupParser sub_parser =
288 parser_start_element,
294 gtk_file_filter_buildable_custom_tag_start (GtkBuildable *buildable,
297 const gchar *tagname,
298 GMarkupParser *parser,
301 SubParserData *parser_data = NULL;
303 if (strcmp (tagname, "mime-types") == 0)
305 parser_data = g_slice_new0 (SubParserData);
306 parser_data->string = g_string_new ("");
307 parser_data->type = PARSE_MIME_TYPES;
308 parser_data->filter = GTK_FILE_FILTER (buildable);
310 *parser = sub_parser;
313 else if (strcmp (tagname, "patterns") == 0)
315 parser_data = g_slice_new0 (SubParserData);
316 parser_data->string = g_string_new ("");
317 parser_data->type = PARSE_PATTERNS;
318 parser_data->filter = GTK_FILE_FILTER (buildable);
320 *parser = sub_parser;
324 return parser_data != NULL;
328 gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable,
331 const gchar *tagname,
334 if (strcmp (tagname, "mime-types") == 0 ||
335 strcmp (tagname, "patterns") == 0)
337 SubParserData *parser_data = (SubParserData*)data;
339 g_string_free (parser_data->string, TRUE);
340 g_slice_free (SubParserData, parser_data);
346 * gtk_file_filter_new:
348 * Creates a new #GtkFileFilter with no rules added to it.
349 * Such a filter doesn't accept any files, so is not
350 * particularly useful until you add rules with
351 * gtk_file_filter_add_mime_type(), gtk_file_filter_add_pattern(),
352 * or gtk_file_filter_add_custom(). To create a filter
353 * that accepts any file, use:
355 * GtkFileFilter *filter = gtk_file_filter_new ();
356 * gtk_file_filter_add_pattern (filter, "*");
359 * Return value: a new #GtkFileFilter
364 gtk_file_filter_new (void)
366 return g_object_new (GTK_TYPE_FILE_FILTER, NULL);
370 * gtk_file_filter_set_name:
371 * @filter: a #GtkFileFilter
372 * @name: (allow-none): the human-readable-name for the filter, or %NULL
373 * to remove any existing name.
375 * Sets the human-readable name of the filter; this is the string
376 * that will be displayed in the file selector user interface if
377 * there is a selectable list of filters.
382 gtk_file_filter_set_name (GtkFileFilter *filter,
385 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
387 g_free (filter->name);
389 filter->name = g_strdup (name);
393 * gtk_file_filter_get_name:
394 * @filter: a #GtkFileFilter
396 * Gets the human-readable name for the filter. See gtk_file_filter_set_name().
398 * Return value: The human-readable name of the filter,
399 * or %NULL. This value is owned by GTK+ and must not
400 * be modified or freed.
405 gtk_file_filter_get_name (GtkFileFilter *filter)
407 g_return_val_if_fail (GTK_IS_FILE_FILTER (filter), NULL);
413 file_filter_add_rule (GtkFileFilter *filter,
416 filter->needed |= rule->needed;
417 filter->rules = g_slist_append (filter->rules, rule);
421 * gtk_file_filter_add_mime_type:
422 * @filter: A #GtkFileFilter
423 * @mime_type: name of a MIME type
425 * Adds a rule allowing a given mime type to @filter.
430 gtk_file_filter_add_mime_type (GtkFileFilter *filter,
431 const gchar *mime_type)
435 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
436 g_return_if_fail (mime_type != NULL);
438 rule = g_slice_new (FilterRule);
439 rule->type = FILTER_RULE_MIME_TYPE;
440 rule->needed = GTK_FILE_FILTER_MIME_TYPE;
441 rule->u.mime_type = g_strdup (mime_type);
443 file_filter_add_rule (filter, rule);
447 * gtk_file_filter_add_pattern:
448 * @filter: a #GtkFileFilter
449 * @pattern: a shell style glob
451 * Adds a rule allowing a shell style glob to a filter.
456 gtk_file_filter_add_pattern (GtkFileFilter *filter,
457 const gchar *pattern)
461 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
462 g_return_if_fail (pattern != NULL);
464 rule = g_slice_new (FilterRule);
465 rule->type = FILTER_RULE_PATTERN;
466 rule->needed = GTK_FILE_FILTER_DISPLAY_NAME;
467 rule->u.pattern = g_strdup (pattern);
469 file_filter_add_rule (filter, rule);
473 * gtk_file_filter_add_pixbuf_formats:
474 * @filter: a #GtkFileFilter
476 * Adds a rule allowing image files in the formats supported
482 gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter)
486 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
488 rule = g_slice_new (FilterRule);
489 rule->type = FILTER_RULE_PIXBUF_FORMATS;
490 rule->needed = GTK_FILE_FILTER_MIME_TYPE;
491 rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
492 file_filter_add_rule (filter, rule);
497 * gtk_file_filter_add_custom:
498 * @filter: a #GtkFileFilter
499 * @needed: bitfield of flags indicating the information that the custom
500 * filter function needs.
501 * @func: callback function; if the function returns %TRUE, then
502 * the file will be displayed.
503 * @data: data to pass to @func
504 * @notify: function to call to free @data when it is no longer needed.
506 * Adds rule to a filter that allows files based on a custom callback
507 * function. The bitfield @needed which is passed in provides information
508 * about what sorts of information that the filter function needs;
509 * this allows GTK+ to avoid retrieving expensive information when
510 * it isn't needed by the filter.
515 gtk_file_filter_add_custom (GtkFileFilter *filter,
516 GtkFileFilterFlags needed,
517 GtkFileFilterFunc func,
519 GDestroyNotify notify)
523 g_return_if_fail (GTK_IS_FILE_FILTER (filter));
524 g_return_if_fail (func != NULL);
526 rule = g_slice_new (FilterRule);
527 rule->type = FILTER_RULE_CUSTOM;
528 rule->needed = needed;
529 rule->u.custom.func = func;
530 rule->u.custom.data = data;
531 rule->u.custom.notify = notify;
533 file_filter_add_rule (filter, rule);
537 * gtk_file_filter_get_needed:
538 * @filter: a #GtkFileFilter
540 * Gets the fields that need to be filled in for the structure
541 * passed to gtk_file_filter_filter()
543 * This function will not typically be used by applications; it
544 * is intended principally for use in the implementation of
547 * Return value: bitfield of flags indicating needed fields when
548 * calling gtk_file_filter_filter()
553 gtk_file_filter_get_needed (GtkFileFilter *filter)
555 return filter->needed;
559 * gtk_file_filter_filter:
560 * @filter: a #GtkFileFilter
561 * @filter_info: a #GtkFileFilterInfo structure containing information
564 * Tests whether a file should be displayed according to @filter.
565 * The #GtkFileFilterInfo structure @filter_info should include
566 * the fields returned from gtk_file_filter_get_needed().
568 * This function will not typically be used by applications; it
569 * is intended principally for use in the implementation of
572 * Return value: %TRUE if the file should be displayed
577 gtk_file_filter_filter (GtkFileFilter *filter,
578 const GtkFileFilterInfo *filter_info)
582 for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
584 FilterRule *rule = tmp_list->data;
586 if ((filter_info->contains & rule->needed) != rule->needed)
591 case FILTER_RULE_MIME_TYPE:
592 if (filter_info->mime_type != NULL &&
593 g_content_type_is_a (filter_info->mime_type, rule->u.mime_type))
596 case FILTER_RULE_PATTERN:
597 if (filter_info->display_name != NULL &&
598 _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
601 case FILTER_RULE_PIXBUF_FORMATS:
605 if (!filter_info->mime_type)
608 for (list = rule->u.pixbuf_formats; list; list = list->next)
613 mime_types = gdk_pixbuf_format_get_mime_types (list->data);
615 for (i = 0; mime_types[i] != NULL; i++)
617 if (strcmp (mime_types[i], filter_info->mime_type) == 0)
619 g_strfreev (mime_types);
624 g_strfreev (mime_types);
628 case FILTER_RULE_CUSTOM:
629 if (rule->u.custom.func (filter_info, rule->u.custom.data))