]> Pileus Git - ~andy/gtk/blob - gtk/gtkrecentfilter.c
gtk/gtkcellview.c gtk/gtkcolorbutton.c gtk/gtkentrycompletion.c
[~andy/gtk] / gtk / gtkrecentfilter.c
1 /* GTK - The GIMP Toolkit
2  * gtkrecentfilter.h - Filter object for recently used resources
3  * Copyright (C) 2006, Emmanuele Bassi
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 "gtkrecentfilter.h"
25 #include "gtkintl.h"
26 #include "gtkprivate.h"
27
28 #include "gtkalias.h"
29
30 #ifdef G_OS_UNIX
31 #define XDG_PREFIX _gtk_xdg
32 #include "xdgmime/xdgmime.h"
33 #endif
34
35 typedef struct _GtkRecentFilterClass GtkRecentFilterClass;
36 typedef struct _FilterRule FilterRule;
37
38 typedef enum {
39   FILTER_RULE_URI,
40   FILTER_RULE_DISPLAY_NAME,
41   FILTER_RULE_MIME_TYPE,
42   FILTER_RULE_PIXBUF_FORMATS,
43   FILTER_RULE_APPLICATION,
44   FILTER_RULE_AGE,
45   FILTER_RULE_GROUP,
46   FILTER_RULE_CUSTOM
47 } FilterRuleType;
48
49 struct _GtkRecentFilter
50 {
51   GtkObject parent_instance;
52   
53   gchar *name;
54   GSList *rules;
55   
56   GtkRecentFilterFlags needed;
57 };
58
59 struct _GtkRecentFilterClass
60 {
61   GtkObjectClass parent_class;
62 };
63
64 struct _FilterRule
65 {
66   FilterRuleType type;
67   GtkRecentFilterFlags needed;
68   
69   union {
70     gchar *uri;
71     gchar *pattern;
72     gchar *mime_type;
73     GSList *pixbuf_formats;
74     gchar *application;
75     gchar *group;
76     gint age;
77     struct {
78       GtkRecentFilterFunc func;
79       gpointer data;
80       GDestroyNotify data_destroy;
81     } custom;
82   } u;
83 };
84
85 G_DEFINE_TYPE (GtkRecentFilter, gtk_recent_filter, GTK_TYPE_OBJECT)
86
87
88 static void
89 filter_rule_free (FilterRule *rule)
90 {
91   switch (rule->type)
92     {
93     case FILTER_RULE_MIME_TYPE:
94       g_free (rule->u.mime_type);
95       break;
96     case FILTER_RULE_URI:
97       g_free (rule->u.uri);
98       break;
99     case FILTER_RULE_DISPLAY_NAME:
100       g_free (rule->u.pattern);
101       break;
102     case FILTER_RULE_PIXBUF_FORMATS:
103       g_slist_free (rule->u.pixbuf_formats);
104       break;
105     case FILTER_RULE_AGE:
106       break;
107     case FILTER_RULE_APPLICATION:
108       g_free (rule->u.application);
109       break;
110     case FILTER_RULE_GROUP:
111       g_free (rule->u.group);
112       break;
113     case FILTER_RULE_CUSTOM:
114       if (rule->u.custom.data_destroy)
115         rule->u.custom.data_destroy (rule->u.custom.data);
116       break;
117     default:
118       g_assert_not_reached ();
119       break;
120     }
121   
122   g_free (rule);
123 }
124
125 static void
126 gtk_recent_filter_finalize (GObject *object)
127 {
128   GtkRecentFilter *filter = GTK_RECENT_FILTER (object);
129   
130   g_free (filter->name);
131   
132   if (filter->rules)
133     {
134       g_slist_foreach (filter->rules,
135                        (GFunc) filter_rule_free,
136                        NULL);
137       g_slist_free (filter->rules);
138     }
139   
140   G_OBJECT_CLASS (gtk_recent_filter_parent_class)->finalize (object);
141 }
142
143 static void
144 gtk_recent_filter_class_init (GtkRecentFilterClass *klass)
145 {
146   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
147   
148   gobject_class->finalize = gtk_recent_filter_finalize;
149 }
150
151 static void
152 gtk_recent_filter_init (GtkRecentFilter *filter)
153 {
154
155 }
156
157 /*
158  * Public API
159  */
160  
161 /**
162  * gtk_recent_filter_new:
163  *
164  * Creates a new #GtkRecentFilter with no rules added to it.
165  * Such filter does not accept any recently used resources, so is not
166  * particularly useful until you add rules with
167  * gtk_recent_filter_add_pattern(), gtk_recent_filter_add_mime_type(),
168  * gtk_recent_filter_add_application(), gtk_recent_filter_add_age().
169  * To create a filter that accepts any recently used resource, use:
170  * |[
171  * GtkRecentFilter *filter = gtk_recent_filter_new ();
172  * gtk_recent_filter_add_pattern (filter, "*");
173  * ]|
174  *
175  * Return value: a new #GtkRecentFilter
176  *
177  * Since: 2.10
178  */
179 GtkRecentFilter *
180 gtk_recent_filter_new (void)
181 {
182   return g_object_new (GTK_TYPE_RECENT_FILTER, NULL);
183 }
184
185 /**
186  * gtk_recent_filter_set_name:
187  * @filter: a #GtkRecentFilter
188  * @name: then human readable name of @filter
189  *
190  * Sets the human-readable name of the filter; this is the string
191  * that will be displayed in the recently used resources selector
192  * user interface if there is a selectable list of filters.
193  *
194  * Since: 2.10
195  */
196 void
197 gtk_recent_filter_set_name (GtkRecentFilter *filter,
198                             const gchar     *name)
199 {
200   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
201   
202   g_free (filter->name);
203   
204   if (name)
205     filter->name = g_strdup (name);
206 }
207
208 /**
209  * gtk_recent_filter_get_name:
210  * @filter: a #GtkRecentFilter
211  *
212  * Gets the human-readable name for the filter.
213  * See gtk_recent_filter_set_name().
214  *
215  * Return value: the name of the filter, or %NULL.  The returned string
216  *   is owned by the filter object and should not be freed.
217  *
218  * Since: 2.10
219  */
220 G_CONST_RETURN gchar *
221 gtk_recent_filter_get_name (GtkRecentFilter *filter)
222 {
223   g_return_val_if_fail (GTK_IS_RECENT_FILTER (filter), NULL);
224   
225   return filter->name;
226 }
227
228 /**
229  * gtk_recent_filter_get_needed:
230  * @filter: a #GtkRecentFilter
231  *
232  * Gets the fields that need to be filled in for the structure
233  * passed to gtk_recent_filter_filter()
234  * 
235  * This function will not typically be used by applications; it
236  * is intended principally for use in the implementation of
237  * #GtkRecentChooser.
238  * 
239  * Return value: bitfield of flags indicating needed fields when
240  *   calling gtk_recent_filter_filter()
241  *
242  * Since: 2.10
243  */
244 GtkRecentFilterFlags
245 gtk_recent_filter_get_needed (GtkRecentFilter *filter)
246 {
247   return filter->needed;
248 }
249
250 static void
251 recent_filter_add_rule (GtkRecentFilter *filter,
252                         FilterRule      *rule)
253 {
254   filter->needed |= rule->needed;
255   filter->rules = g_slist_append (filter->rules, rule);
256 }
257
258 /**
259  * gtk_recent_filter_add_mime_type:
260  * @filter: a #GtkRecentFilter
261  * @mime_type: a MIME type
262  *
263  * Adds a rule that allows resources based on their registered MIME type.
264  *
265  * Since: 2.10
266  */
267 void
268 gtk_recent_filter_add_mime_type (GtkRecentFilter *filter,
269                                  const gchar     *mime_type)
270 {
271   FilterRule *rule;
272   
273   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
274   g_return_if_fail (mime_type != NULL);
275   
276   rule = g_new0 (FilterRule, 1);
277   rule->type = FILTER_RULE_MIME_TYPE;
278   rule->needed = GTK_RECENT_FILTER_MIME_TYPE;
279   rule->u.mime_type = g_strdup (mime_type);
280   
281   recent_filter_add_rule (filter, rule);
282 }
283
284 /**
285  * gtk_recent_filter_add_pattern:
286  * @filter: a #GtkRecentFilter
287  * @pattern: a file pattern
288  *
289  * Adds a rule that allows resources based on a pattern matching their
290  * display name.
291  *
292  * Since: 2.10
293  */
294 void
295 gtk_recent_filter_add_pattern (GtkRecentFilter *filter,
296                                const gchar     *pattern)
297 {
298   FilterRule *rule;
299   
300   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
301   g_return_if_fail (pattern != NULL);
302   
303   rule = g_new0 (FilterRule, 1);
304   rule->type = FILTER_RULE_DISPLAY_NAME;
305   rule->needed = GTK_RECENT_FILTER_DISPLAY_NAME;
306   rule->u.pattern = g_strdup (pattern);
307   
308   recent_filter_add_rule (filter, rule);
309 }
310
311 /**
312  * gtk_recent_filter_add_pixbuf_formats:
313  * @filter: a #GtkRecentFilter
314  *
315  * Adds a rule allowing image files in the formats supported
316  * by GdkPixbuf.
317  *
318  * Since: 2.10
319  */
320 void
321 gtk_recent_filter_add_pixbuf_formats (GtkRecentFilter *filter)
322 {
323   FilterRule *rule;
324
325   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
326
327   rule = g_new0 (FilterRule, 1);
328   rule->type = FILTER_RULE_PIXBUF_FORMATS;
329   rule->needed = GTK_RECENT_FILTER_MIME_TYPE;
330   rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
331   
332   recent_filter_add_rule (filter, rule);
333 }
334
335 /**
336  * gtk_recent_filter_add_application:
337  * @filter: a #GtkRecentFilter
338  * @application: an application name
339  *
340  * Adds a rule that allows resources based on the name of the application
341  * that has registered them.
342  *
343  * Since: 2.10
344  */
345 void
346 gtk_recent_filter_add_application (GtkRecentFilter *filter,
347                                    const gchar     *application)
348 {
349   FilterRule *rule;
350   
351   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
352   g_return_if_fail (application != NULL);
353   
354   rule = g_new0 (FilterRule, 1);
355   rule->type = FILTER_RULE_APPLICATION;
356   rule->needed = GTK_RECENT_FILTER_APPLICATION;
357   rule->u.application = g_strdup (application);
358   
359   recent_filter_add_rule (filter, rule);
360 }
361
362 /**
363  * gtk_recent_filter_add_group:
364  * @filter: a #GtkRecentFilter
365  * @group: a group name
366  *
367  * Adds a rule that allows resources based on the name of the group
368  * to which they belong
369  *
370  * Since: 2.10
371  */
372 void
373 gtk_recent_filter_add_group (GtkRecentFilter *filter,
374                              const gchar     *group)
375 {
376   FilterRule *rule;
377   
378   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
379   g_return_if_fail (group != NULL);
380   
381   rule = g_new0 (FilterRule, 1);
382   rule->type = FILTER_RULE_GROUP;
383   rule->needed = GTK_RECENT_FILTER_GROUP;
384   rule->u.group = g_strdup (group);
385   
386   recent_filter_add_rule (filter, rule);
387 }
388
389 /**
390  * gtk_recent_filter_add_age:
391  * @filter: a #GtkRecentFilter
392  * @days: number of days
393  *
394  * Adds a rule that allows resources based on their age - that is, the number
395  * of days elapsed since they were last modified.
396  *
397  * Since: 2.10
398  */
399 void
400 gtk_recent_filter_add_age (GtkRecentFilter *filter,
401                            gint             days)
402 {
403   FilterRule *rule;
404   
405   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
406   
407   rule = g_new0 (FilterRule, 1);
408   rule->type = FILTER_RULE_AGE;
409   rule->needed = GTK_RECENT_FILTER_AGE;
410   rule->u.age = days;
411   
412   recent_filter_add_rule (filter, rule);
413 }
414
415 /**
416  * gtk_recent_filter_add_custom:
417  * @filter: a #GtkRecentFilter
418  * @needed: bitfield of flags indicating the information that the custom
419  *          filter function needs.
420  * @func: callback function; if the function returns %TRUE, then
421  *   the file will be displayed.
422  * @data: data to pass to @func
423  * @data_destroy: function to call to free @data when it is no longer needed.
424  * 
425  * Adds a rule to a filter that allows resources based on a custom callback
426  * function. The bitfield @needed which is passed in provides information
427  * about what sorts of information that the filter function needs;
428  * this allows GTK+ to avoid retrieving expensive information when
429  * it isn't needed by the filter.
430  * 
431  * Since: 2.10
432  **/
433 void
434 gtk_recent_filter_add_custom (GtkRecentFilter      *filter,
435                               GtkRecentFilterFlags  needed,
436                               GtkRecentFilterFunc   func,
437                               gpointer              data,
438                               GDestroyNotify        data_destroy)
439 {
440   FilterRule *rule;
441   
442   g_return_if_fail (GTK_IS_RECENT_FILTER (filter));
443   g_return_if_fail (func != NULL);
444
445   rule = g_new0 (FilterRule, 1);
446   rule->type = FILTER_RULE_CUSTOM;
447   rule->needed = needed;
448   rule->u.custom.func = func;
449   rule->u.custom.data = data;
450   rule->u.custom.data_destroy = data_destroy;
451
452   recent_filter_add_rule (filter, rule);
453 }
454
455
456 /**
457  * gtk_recent_filter_filter:
458  * @filter: a #GtkRecentFilter
459  * @filter_info: a #GtkRecentFilterInfo structure containing information
460  *   about a recently used resource
461  *
462  * Tests whether a file should be displayed according to @filter.
463  * The #GtkRecentFilterInfo structure @filter_info should include
464  * the fields returned from gtk_recent_filter_get_needed().
465  *
466  * This function will not typically be used by applications; it
467  * is intended principally for use in the implementation of
468  * #GtkRecentChooser.
469  * 
470  * Return value: %TRUE if the file should be displayed
471  *
472  * Since: 2.10
473  */
474 gboolean
475 gtk_recent_filter_filter (GtkRecentFilter           *filter,
476                           const GtkRecentFilterInfo *filter_info)
477 {
478   GSList *l;
479   
480   g_return_val_if_fail (GTK_IS_RECENT_FILTER (filter), FALSE);
481   g_return_val_if_fail (filter_info != NULL, FALSE);
482   
483   for (l = filter->rules; l != NULL; l = l->next)
484     {
485       FilterRule *rule = (FilterRule *) l->data;
486
487       if ((filter_info->contains & rule->needed) != rule->needed)
488         continue;
489
490       switch (rule->type)
491         {
492         case FILTER_RULE_MIME_TYPE:
493           if ((filter_info->mime_type != NULL)
494 #ifdef G_OS_UNIX
495               && (xdg_mime_mime_type_subclass (filter_info->mime_type, rule->u.mime_type)))
496 #else
497               && (strcmp (filter_info->mime_type, rule->u.mime_type) == 0))
498 #endif
499             return TRUE;
500           break;
501         case FILTER_RULE_APPLICATION:
502           if (filter_info->applications)
503             {
504               gint i;
505               
506               for (i = 0; filter_info->applications[i] != NULL; i++)
507                 {
508                   if (strcmp (filter_info->applications[i], rule->u.application) == 0)
509                     return TRUE;
510                 }
511             }
512           break;
513         case FILTER_RULE_GROUP:
514           if (filter_info->groups)
515             {
516               gint i;
517
518               for (i = 0; filter_info->groups[i] != NULL; i++)
519                 {
520                   if (strcmp (filter_info->groups[i], rule->u.group) == 0)
521                     return TRUE;
522                 }
523             }
524           break;
525         case FILTER_RULE_PIXBUF_FORMATS:
526           {
527             GSList *list;
528             if (!filter_info->mime_type)
529               break;
530
531             for (list = rule->u.pixbuf_formats; list; list = list->next)
532               {
533                 gint i;
534                 gchar **mime_types;
535
536                 mime_types = gdk_pixbuf_format_get_mime_types (list->data);
537
538                 for (i = 0; mime_types[i] != NULL; i++)
539                   {
540                     if (strcmp (mime_types[i], filter_info->mime_type) == 0)
541                       {
542                         g_strfreev (mime_types);
543                         return TRUE;
544                       }
545                   }
546
547                 g_strfreev (mime_types);
548               }
549             break;
550           }
551         case FILTER_RULE_URI:
552           if ((filter_info->uri != NULL) &&
553               _gtk_fnmatch (rule->u.uri, filter_info->uri, FALSE))
554             return TRUE;
555           break;
556         case FILTER_RULE_DISPLAY_NAME:
557           if ((filter_info->display_name != NULL) &&
558               _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
559             return TRUE;
560           break;
561         case FILTER_RULE_AGE:
562           if ((filter_info->age != -1) &&
563               (filter_info->age < rule->u.age))
564             return TRUE;
565           break;
566         case FILTER_RULE_CUSTOM:
567           if (rule->u.custom.func (filter_info, rule->u.custom.data))
568             return TRUE;
569           break;
570         }
571     }
572   
573   return FALSE;
574 }
575
576 #define __GTK_RECENT_FILTER_C__
577 #include "gtkaliasdef.c"