]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilefilter.c
In the case for FILTER_RULE_PIXBUF_FORMATS, check that
[~andy/gtk] / gtk / gtkfilefilter.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilefilter.c: Filters for selecting a file subset
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
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.
9  *
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.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <config.h>
22 #include <string.h>
23
24 #include "gtkfilefilter.h"
25 #include "gtkobject.h"
26 #include "gtkintl.h"
27 #include "gtkprivate.h"
28
29 #include "gtkalias.h"
30
31 #ifdef G_OS_UNIX
32 #define XDG_PREFIX _gtk_xdg
33 #include "xdgmime/xdgmime.h"
34 #endif
35
36 typedef struct _GtkFileFilterClass GtkFileFilterClass;
37 typedef struct _FilterRule FilterRule;
38
39 #define GTK_FILE_FILTER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
40 #define GTK_IS_FILE_FILTER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FILTER))
41 #define GTK_FILE_FILTER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FILTER, GtkFileFilterClass))
42
43 typedef enum {
44   FILTER_RULE_PATTERN,
45   FILTER_RULE_MIME_TYPE,
46   FILTER_RULE_PIXBUF_FORMATS,
47   FILTER_RULE_CUSTOM
48 } FilterRuleType;
49
50 struct _GtkFileFilterClass
51 {
52   GtkObjectClass parent_class;
53 };
54
55 struct _GtkFileFilter
56 {
57   GtkObject parent_instance;
58   
59   gchar *name;
60   GSList *rules;
61
62   GtkFileFilterFlags needed;
63 };
64
65 struct _FilterRule
66 {
67   FilterRuleType type;
68   GtkFileFilterFlags needed;
69   
70   union {
71     gchar *pattern;
72     gchar *mime_type;
73     GSList *pixbuf_formats;
74     struct {
75       GtkFileFilterFunc func;
76       gpointer data;
77       GDestroyNotify notify;
78     } custom;
79   } u;
80 };
81
82 static void gtk_file_filter_class_init (GtkFileFilterClass *class);
83 static void gtk_file_filter_finalize   (GObject            *object);
84
85 static GObjectClass *parent_class;
86
87 GType
88 gtk_file_filter_get_type (void)
89 {
90   static GType file_filter_type = 0;
91
92   if (!file_filter_type)
93     {
94       static const GTypeInfo file_filter_info =
95       {
96         sizeof (GtkFileFilterClass),
97         NULL,           /* base_init */
98         NULL,           /* base_finalize */
99         (GClassInitFunc) gtk_file_filter_class_init,
100         NULL,           /* class_finalize */
101         NULL,           /* class_data */
102         sizeof (GtkFileFilter),
103         0,              /* n_preallocs */
104         NULL            /* init */
105       };
106       
107       file_filter_type = g_type_register_static (GTK_TYPE_OBJECT, I_("GtkFileFilter"),
108                                                  &file_filter_info, 0);
109     }
110
111   return file_filter_type;
112 }
113
114 static void
115 gtk_file_filter_class_init (GtkFileFilterClass *class)
116 {
117   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
118
119   parent_class = g_type_class_peek_parent (class);
120
121   gobject_class->finalize = gtk_file_filter_finalize;
122 }
123
124 static void
125 filter_rule_free (FilterRule *rule)
126 {
127   switch (rule->type)
128     {
129     case FILTER_RULE_MIME_TYPE:
130       g_free (rule->u.mime_type);
131       break;
132     case FILTER_RULE_PATTERN:
133       g_free (rule->u.pattern);
134       break;
135     case FILTER_RULE_CUSTOM:
136       if (rule->u.custom.notify)
137         rule->u.custom.notify (rule->u.custom.data);
138       break;
139     case FILTER_RULE_PIXBUF_FORMATS:
140       g_slist_free (rule->u.pixbuf_formats);
141       break;
142     default:
143       g_assert_not_reached ();
144     }
145
146   g_free (rule);
147 }
148
149 static void
150 gtk_file_filter_finalize (GObject  *object)
151 {
152   GtkFileFilter *filter = GTK_FILE_FILTER (object);
153
154   g_slist_foreach (filter->rules, (GFunc)filter_rule_free, NULL);
155   g_slist_free (filter->rules);
156
157   if (filter->name)
158     g_free (filter->name);
159
160   parent_class->finalize (object);
161 }
162
163 /**
164  * gtk_file_filter_new:
165  * 
166  * Creates a new #GtkFileFilter with no rules added to it.
167  * Such a filter doesn't accept any files, so is not
168  * particularly useful until you add rules with
169  * gtk_file_filter_add_mime_type(), gtk_file_filter_add_pattern(),
170  * or gtk_file_filter_add_custom(). To create a filter
171  * that accepts any file, use:
172  *
173  * <informalexample><programlisting>
174  * GtkFileFilter *filter = gtk_file_filter_new (<!-- -->);
175  * gtk_file_filter_add_pattern (filter, "*");
176  * </programlisting></informalexample>
177  * 
178  * Return value: a new #GtkFileFilter
179  * 
180  * Since: 2.4
181  **/
182 GtkFileFilter *
183 gtk_file_filter_new (void)
184 {
185   return g_object_new (GTK_TYPE_FILE_FILTER, NULL);
186 }
187
188 /**
189  * gtk_file_filter_set_name:
190  * @filter: a #GtkFileFilter
191  * @name: the human-readable-name for the filter, or %NULL
192  *   to remove any existing name.
193  * 
194  * Sets the human-readable name of the filter; this is the string
195  * that will be displayed in the file selector user interface if
196  * there is a selectable list of filters.
197  * 
198  * Since: 2.4
199  **/
200 void
201 gtk_file_filter_set_name (GtkFileFilter *filter,
202                           const gchar   *name)
203 {
204   g_return_if_fail (GTK_IS_FILE_FILTER (filter));
205   
206   if (filter->name)
207     g_free (filter->name);
208
209   filter->name = g_strdup (name);
210 }
211
212 /**
213  * gtk_file_filter_get_name:
214  * @filter: a #GtkFileFilter
215  * 
216  * Gets the human-readable name for the filter. See gtk_file_filter_set_name().
217  * 
218  * Return value: The human-readable name of the filter,
219  *   or %NULL. This value is owned by GTK+ and must not
220  *   be modified or freed.
221  * 
222  * Since: 2.4
223  **/
224 G_CONST_RETURN gchar *
225 gtk_file_filter_get_name (GtkFileFilter *filter)
226 {
227   g_return_val_if_fail (GTK_IS_FILE_FILTER (filter), NULL);
228   
229   return filter->name;
230 }
231
232 static void
233 file_filter_add_rule (GtkFileFilter *filter,
234                       FilterRule    *rule)
235 {
236   filter->needed |= rule->needed;
237   filter->rules = g_slist_append (filter->rules, rule);
238 }
239
240 /**
241  * gtk_file_filter_add_mime_type:
242  * @filter: A #GtkFileFilter
243  * @mime_type: name of a MIME type
244  * 
245  * Adds a rule allowing a given mime type to @filter.
246  * 
247  * Since: 2.4
248  **/
249 void
250 gtk_file_filter_add_mime_type (GtkFileFilter *filter,
251                                const gchar   *mime_type)
252 {
253   FilterRule *rule;
254   
255   g_return_if_fail (GTK_IS_FILE_FILTER (filter));
256   g_return_if_fail (mime_type != NULL);
257
258   rule = g_new (FilterRule, 1);
259   rule->type = FILTER_RULE_MIME_TYPE;
260   rule->needed = GTK_FILE_FILTER_MIME_TYPE;
261   rule->u.mime_type = g_strdup (mime_type);
262
263   file_filter_add_rule (filter, rule);
264 }
265
266 /**
267  * gtk_file_filter_add_pattern:
268  * @filter: a #GtkFileFilter
269  * @pattern: a shell style glob
270  * 
271  * Adds a rule allowing a shell style glob to a filter.
272  * 
273  * Since: 2.4
274  **/
275 void
276 gtk_file_filter_add_pattern (GtkFileFilter *filter,
277                              const gchar   *pattern)
278 {
279   FilterRule *rule;
280   
281   g_return_if_fail (GTK_IS_FILE_FILTER (filter));
282   g_return_if_fail (pattern != NULL);
283
284   rule = g_new (FilterRule, 1);
285   rule->type = FILTER_RULE_PATTERN;
286   rule->needed = GTK_FILE_FILTER_DISPLAY_NAME;
287   rule->u.pattern = g_strdup (pattern);
288
289   file_filter_add_rule (filter, rule);
290 }
291
292 /**
293  * gtk_file_filter_add_pixbuf_formats:
294  * @filter: a #GtkFileFilter
295  * 
296  * Adds a rule allowing image files in the formats supported
297  * by GdkPixbuf.
298  * 
299  * Since: 2.6
300  **/
301 void
302 gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter)
303 {
304   FilterRule *rule;
305   
306   g_return_if_fail (GTK_IS_FILE_FILTER (filter));
307
308   rule = g_new (FilterRule, 1);
309   rule->type = FILTER_RULE_PIXBUF_FORMATS;
310   rule->needed = GTK_FILE_FILTER_MIME_TYPE;
311   rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
312   file_filter_add_rule (filter, rule);
313 }
314
315
316 /**
317  * gtk_file_filter_add_custom:
318  * @filter: a #GtkFileFilter
319  * @needed: bitfield of flags indicating the information that the custom
320  *          filter function needs.
321  * @func: callback function; if the function returns %TRUE, then
322  *   the file will be displayed.
323  * @data: data to pass to @func
324  * @notify: function to call to free @data when it is no longer needed.
325  * 
326  * Adds rule to a filter that allows files based on a custom callback
327  * function. The bitfield @needed which is passed in provides information
328  * about what sorts of information that the filter function needs;
329  * this allows GTK+ to avoid retrieving expensive information when
330  * it isn't needed by the filter.
331  * 
332  * Since: 2.4
333  **/
334 void
335 gtk_file_filter_add_custom (GtkFileFilter         *filter,
336                             GtkFileFilterFlags     needed,
337                             GtkFileFilterFunc      func,
338                             gpointer               data,
339                             GDestroyNotify         notify)
340 {
341   FilterRule *rule;
342   
343   g_return_if_fail (GTK_IS_FILE_FILTER (filter));
344   g_return_if_fail (func != NULL);
345
346   rule = g_new (FilterRule, 1);
347   rule->type = FILTER_RULE_CUSTOM;
348   rule->needed = needed;
349   rule->u.custom.func = func;
350   rule->u.custom.data = data;
351   rule->u.custom.notify = notify;
352
353   file_filter_add_rule (filter, rule);
354 }
355
356 /**
357  * gtk_file_filter_get_needed:
358  * @filter: a #GtkFileFilter
359  * 
360  * Gets the fields that need to be filled in for the structure
361  * passed to gtk_file_filter_filter()
362  * 
363  * This function will not typically be used by applications; it
364  * is intended principally for use in the implementation of
365  * #GtkFileChooser.
366  * 
367  * Return value: bitfield of flags indicating needed fields when
368  *   calling gtk_file_filter_filter()
369  * 
370  * Since: 2.4
371  **/
372 GtkFileFilterFlags
373 gtk_file_filter_get_needed (GtkFileFilter *filter)
374 {
375   return filter->needed;
376 }
377
378 /**
379  * gtk_file_filter_filter:
380  * @filter: a #GtkFileFilter
381  * @filter_info: a #GtkFileFilterInfo structure containing information
382  *  about a file.
383  * 
384  * Tests whether a file should be displayed according to @filter.
385  * The #GtkFileFilterInfo structure @filter_info should include
386  * the fields returned from gtk_file_filter_get_needed().
387  *
388  * This function will not typically be used by applications; it
389  * is intended principally for use in the implementation of
390  * #GtkFileChooser.
391  * 
392  * Return value: %TRUE if the file should be displayed
393  * 
394  * Since: 2.4
395  **/
396 gboolean
397 gtk_file_filter_filter (GtkFileFilter           *filter,
398                         const GtkFileFilterInfo *filter_info)
399 {
400   GSList *tmp_list;
401
402   for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
403     {
404       FilterRule *rule = tmp_list->data;
405
406       if ((filter_info->contains & rule->needed) != rule->needed)
407         continue;
408       
409       switch (rule->type)
410         {
411         case FILTER_RULE_MIME_TYPE:
412           if (filter_info->mime_type != NULL
413 #ifdef G_OS_UNIX
414               && xdg_mime_mime_type_subclass (filter_info->mime_type, rule->u.mime_type))
415 #else
416               && strcmp (rule->u.mime_type, filter_info->mime_type) == 0)
417 #endif
418             return TRUE;
419           break;
420         case FILTER_RULE_PATTERN:
421           if (filter_info->display_name != NULL &&
422               _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
423             return TRUE;
424           break;
425         case FILTER_RULE_PIXBUF_FORMATS:
426           {
427             GSList *list;
428
429             if (!filter_info->mime_type)
430               break;
431
432             for (list = rule->u.pixbuf_formats; list; list = list->next)
433               {
434                 int i;
435                 gchar **mime_types;
436
437                 mime_types = gdk_pixbuf_format_get_mime_types (list->data);
438
439                 for (i = 0; mime_types[i] != NULL; i++)
440                   {
441                     if (strcmp (mime_types[i], filter_info->mime_type) == 0)
442                       {
443                         g_strfreev (mime_types);
444                         return TRUE;
445                       }
446                   }
447
448                 g_strfreev (mime_types);
449               }
450             break;
451           }
452         case FILTER_RULE_CUSTOM:
453           if (rule->u.custom.func (filter_info, rule->u.custom.data))
454             return TRUE;
455           break;
456         }
457     }
458
459   return FALSE;
460 }
461
462 #define __GTK_FILE_FILTER_C__
463 #include "gtkaliasdef.c"