]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilesystem.c
- Add GnomeVFS backend
[~andy/gtk] / gtk / gtkfilesystem.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilesystem.c: Abstract file system interfaces
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 "gtkfilesystem.h"
22
23 struct _GtkFileInfo
24 {
25   GtkFileTime modification_time;
26   gint64 size;
27   gchar *display_name;
28   gchar *display_key;
29   gchar *mime_type;
30   GdkPixbuf *icon;
31   guint is_folder : 1;
32   guint is_hidden : 1;
33 };
34
35 static void gtk_file_system_base_init (gpointer g_class);
36 static void gtk_file_folder_base_init (gpointer g_class);
37
38 GQuark
39 gtk_file_system_error_quark (void)
40 {
41   static GQuark quark = 0;
42   if (quark == 0)
43     quark = g_quark_from_static_string ("gtk-file-system-error-quark");
44   return quark;
45 }
46
47 /*****************************************
48  *             GtkFileInfo               *
49  *****************************************/
50 GType
51 gtk_file_info_get_type (void)
52 {
53   static GType our_type = 0;
54   
55   if (our_type == 0)
56     our_type = g_boxed_type_register_static ("GtkFileInfo",
57                                              (GBoxedCopyFunc) gtk_file_info_copy,
58                                              (GBoxedFreeFunc) gtk_file_info_free);
59
60   return our_type;
61 }
62
63 GtkFileInfo *
64 gtk_file_info_new  (void)
65 {
66   GtkFileInfo *info;
67   
68   info = g_new0 (GtkFileInfo, 1);
69
70   return info;
71 }
72
73 GtkFileInfo *
74 gtk_file_info_copy (GtkFileInfo *info)
75 {
76   GtkFileInfo *new_info;
77
78   g_return_val_if_fail (info != NULL, NULL);
79
80   new_info = g_memdup (info, sizeof (GtkFileInfo));
81   if (new_info->display_name)
82     new_info->display_name = g_strdup (new_info->display_name);
83   if (new_info->mime_type)
84     new_info->mime_type = g_strdup (new_info->mime_type);
85   if (new_info->icon)
86     g_object_ref (new_info->icon);
87
88   return new_info;
89 }
90
91 void
92 gtk_file_info_free (GtkFileInfo *info)
93 {
94   g_return_if_fail (info != NULL);
95
96   if (info->display_name)
97     g_free (info->display_name);
98   if (info->mime_type)
99     g_free (info->mime_type);
100   if (info->icon)
101     g_object_unref (info->icon);
102 }
103
104 G_CONST_RETURN gchar *
105 gtk_file_info_get_display_name (const GtkFileInfo *info)
106 {
107   g_return_val_if_fail (info != NULL, NULL);
108   
109   return info->display_name;
110 }
111
112 /**
113  * gtk_file_info_get_display_key:
114  * @info: a #GtkFileInfo
115  * 
116  * Returns results of g_utf8_collate_key() on the display name
117  * for @info. This is useful when sorting a bunch of #GtkFileInfo
118  * structures since the collate key will be only computed once.
119  * 
120  * Return value: The collate key for the display name, or %NULL
121  *   if the display name hasn't been set.
122  **/
123 G_CONST_RETURN gchar *
124 gtk_file_info_get_display_key (const GtkFileInfo *info)
125 {
126   g_return_val_if_fail (info != NULL, NULL);
127
128   if (!info->display_key && info->display_name)
129     {
130       /* Since info->display_key is only a cache, we cast off the const
131        */
132       ((GtkFileInfo *)info)->display_key = g_utf8_collate_key (info->display_name, -1);
133     }
134         
135   
136   return info->display_key;
137 }
138
139 void
140 gtk_file_info_set_display_name (GtkFileInfo *info,
141                                 const gchar *display_name)
142 {
143   g_return_if_fail (info != NULL);
144
145   if (info->display_name)
146     g_free (info->display_name);
147   if (info->display_key)
148     {
149       g_free (info->display_key);
150       info->display_key = NULL;
151     }
152
153   info->display_name = g_strdup (display_name);
154 }
155
156 gboolean
157 gtk_file_info_get_is_folder (const GtkFileInfo *info)
158 {
159   g_return_val_if_fail (info != NULL, FALSE);
160   
161   return info->is_folder;
162 }
163
164 void
165 gtk_file_info_set_is_folder (GtkFileInfo *info,
166                              gboolean     is_folder)
167 {
168   g_return_if_fail (info != NULL);
169
170   info->is_folder = is_folder != FALSE;
171 }
172
173 gboolean
174 gtk_file_info_get_is_hidden (const GtkFileInfo *info)
175 {
176   g_return_val_if_fail (info != NULL, FALSE);
177   
178   return info->is_hidden;
179 }
180
181 void
182 gtk_file_info_set_is_hidden (GtkFileInfo *info,
183                              gboolean     is_hidden)
184 {
185   g_return_if_fail (info != NULL);
186
187   info->is_hidden = is_hidden != FALSE;
188 }
189
190 G_CONST_RETURN gchar *
191 gtk_file_info_get_mime_type (const GtkFileInfo *info)
192 {
193   g_return_val_if_fail (info != NULL, NULL);
194   
195   return info->mime_type;
196 }
197
198 void
199 gtk_file_info_set_mime_type (GtkFileInfo *info,
200                              const gchar *mime_type)
201 {
202   g_return_if_fail (info != NULL);
203   
204   if (info->mime_type)
205     g_free (info->mime_type);
206
207   info->mime_type = g_strdup (mime_type);
208 }
209
210 GtkFileTime
211 gtk_file_info_get_modification_time (const GtkFileInfo *info)
212 {
213   g_return_val_if_fail (info != NULL, 0);
214
215   return info->modification_time;
216 }
217
218 void
219 gtk_file_info_set_modification_time (GtkFileInfo *info,
220                                      GtkFileTime  modification_time)
221 {
222   g_return_if_fail (info != NULL);
223   
224   info->modification_time = modification_time;
225 }
226
227 gint64
228 gtk_file_info_get_size (const GtkFileInfo *info)
229 {
230   g_return_val_if_fail (info != NULL, 0);
231   
232   return info->size;
233 }
234
235 void
236 gtk_file_info_set_size (GtkFileInfo *info,
237                         gint64       size)
238 {
239   g_return_if_fail (info != NULL);
240   g_return_if_fail (size >= 0);
241   
242   info->size = size;
243 }
244
245 GdkPixbuf *
246 gtk_file_info_get_icon (const GtkFileInfo *info)
247 {
248   g_return_val_if_fail (info != NULL, NULL);
249
250   return info->icon;
251 }
252
253 void
254 gtk_file_info_set_icon (GtkFileInfo *info,
255                         GdkPixbuf   *icon)
256 {
257   g_return_if_fail (info != NULL);
258   g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
259
260   if (icon != info->icon)
261     {
262       if (info->icon)
263         g_object_unref (info->icon);
264
265       info->icon = icon;
266       
267       if (info->icon)
268         g_object_ref (info->icon);
269     }
270 }
271
272 /*****************************************
273  *             GtkFileSystem             *
274  *****************************************/
275 GType
276 gtk_file_system_get_type (void)
277 {
278   static GType file_system_type = 0;
279
280   if (!file_system_type)
281     {
282       static const GTypeInfo file_system_info =
283       {
284         sizeof (GtkFileSystemIface),  /* class_size */
285         gtk_file_system_base_init,    /* base_init */
286         NULL,                         /* base_finalize */
287       };
288
289       file_system_type = g_type_register_static (G_TYPE_INTERFACE,
290                                                  "GtkFileSystem",
291                                                  &file_system_info, 0);
292     }
293
294   return file_system_type;
295 }
296
297 static void
298 gtk_file_system_base_init (gpointer g_class)
299 {
300   static gboolean initialized = FALSE;
301   
302   if (!initialized)
303     {
304       GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
305
306       g_signal_new ("roots_changed",
307                     iface_type,
308                     G_SIGNAL_RUN_LAST,
309                     G_STRUCT_OFFSET (GtkFileSystemIface, roots_changed),
310                     NULL, NULL,
311                     g_cclosure_marshal_VOID__VOID,
312                     G_TYPE_NONE, 0);
313
314       initialized = TRUE;
315     }
316 }
317
318 GSList *
319 gtk_file_system_list_roots (GtkFileSystem  *file_system)
320 {
321   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
322
323   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->list_roots (file_system);
324 }
325
326 GtkFileInfo *
327 gtk_file_system_get_root_info  (GtkFileSystem    *file_system,
328                                 const gchar      *uri,
329                                 GtkFileInfoType   types,
330                                 GError          **error)
331 {
332   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
333   g_return_val_if_fail (uri != NULL, NULL);
334   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
335
336   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_root_info (file_system, uri, types, error);
337 }
338
339 GtkFileFolder *
340 gtk_file_system_get_folder (GtkFileSystem    *file_system,
341                             const gchar      *uri,
342                             GtkFileInfoType   types,
343                             GError          **error)
344 {
345   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
346   g_return_val_if_fail (uri != NULL, NULL);
347   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
348
349   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_folder (file_system, uri, types, error);
350 }
351
352 gboolean
353 gtk_file_system_create_folder(GtkFileSystem    *file_system,
354                               const gchar      *uri,
355                               GError          **error)
356 {
357   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
358   g_return_val_if_fail (uri != NULL, FALSE);
359   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
360
361   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->create_folder (file_system, uri, error);
362 }
363
364 gboolean
365 gtk_file_system_get_parent (GtkFileSystem *file_system,
366                             const gchar   *uri,
367                             gchar         **parent,
368                             GError        **error)
369 {
370   gchar *tmp_parent = NULL;
371   gboolean result;
372   
373   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
374   g_return_val_if_fail (uri != NULL, FALSE);
375   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
376
377   result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->get_parent (file_system, uri, &tmp_parent, error);
378   g_assert (result || tmp_parent == NULL);
379
380   if (parent)
381     *parent = tmp_parent;
382   else
383     g_free (tmp_parent);
384   
385   return result;
386 }
387
388 gchar *
389 gtk_file_system_make_uri (GtkFileSystem    *file_system,
390                           const gchar      *base_uri,
391                           const gchar      *display_name,
392                           GError          **error)
393 {
394   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), NULL);
395   g_return_val_if_fail (base_uri != NULL, NULL);
396   g_return_val_if_fail (display_name != NULL, NULL);
397   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
398
399   return GTK_FILE_SYSTEM_GET_IFACE (file_system)->make_uri (file_system, base_uri, display_name, error);
400 }
401
402 /**
403  * gtk_file_system_parse:
404  * @file_system: a #GtkFileSystem
405  * @base_uri: reference folder with respect to which relative
406  *            paths should be interpreted.
407  * @str: the string to parse
408  * @folder: location to store folder portion of result, or %NULL
409  * @file_part: location to store file portion of result, or %NULL
410  * @error: location to store error, or %NULL
411  * 
412  * Given a string entered by a user, parse it (possibly using
413  * heuristics) into a folder URI and a UTF-8 encoded
414  * filename part. (Suitable for passing to gtk_file_system_make_uri())
415  *
416  * Note that the returned filename point may point to a subfolder
417  * of the returned folder. Adding a trailing path separator is needed
418  * to enforce the interpretation as a folder name.
419  *
420  * If parsing fails because the syntax of @str is not understood,
421  * and error of type GTK_FILE_SYSTEM_ERROR_BAD_FILENAME will
422  * be set in @error and %FALSE returned.
423  *
424  * If parsing fails because a path was encountered that doesn't
425  * exist on the filesystem, then an error of type
426  * %GTK_FILE_SYSTEM_ERROR_NONEXISTANT will be set in @error
427  * and %FALSE returned. (This only applies to parsing relative paths,
428  * not to interpretation of @file_part. No check is made as
429  * to whether @file_part exists.)
430  *
431  * Return value: %TRUE if the parsing succeeds, otherwise, %FALSE.
432  **/
433 gboolean
434 gtk_file_system_parse (GtkFileSystem   *file_system,
435                        const gchar     *base_uri,
436                        const gchar     *str,
437                        gchar          **folder,
438                        gchar          **file_part,
439                        GError         **error)
440 {
441   gchar *tmp_folder = NULL;
442   gchar *tmp_file_part = NULL;
443   gboolean result;
444
445   g_return_val_if_fail (GTK_IS_FILE_SYSTEM (file_system), FALSE);
446   g_return_val_if_fail (base_uri != NULL, FALSE);
447   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
448
449
450   result = GTK_FILE_SYSTEM_GET_IFACE (file_system)->parse (file_system, base_uri, str,
451                                                             &tmp_folder, &tmp_file_part,
452                                                             error);
453   g_assert (result || (tmp_folder == NULL && tmp_file_part == NULL));
454
455   if (folder)
456     *folder = tmp_folder;
457   else
458     g_free (tmp_folder);
459
460   if (file_part)
461     *file_part = tmp_file_part;
462   else
463     g_free (tmp_file_part);
464
465   return result;
466 }
467
468 /*****************************************
469  *             GtkFileFolder             *
470  *****************************************/
471 GType
472 gtk_file_folder_get_type (void)
473 {
474   static GType file_folder_type = 0;
475
476   if (!file_folder_type)
477     {
478       static const GTypeInfo file_folder_info =
479       {
480         sizeof (GtkFileFolderIface),  /* class_size */
481         gtk_file_folder_base_init,    /* base_init */
482         NULL,                         /* base_finalize */
483       };
484
485       file_folder_type = g_type_register_static (G_TYPE_INTERFACE,
486                                                  "GtkFileFolder",
487                                                  &file_folder_info, 0);
488     }
489
490   return file_folder_type;
491 }
492
493 static void
494 gtk_file_folder_base_init (gpointer g_class)
495 {
496   static gboolean initialized = FALSE;
497   
498   if (!initialized)
499     {
500       GType iface_type = G_TYPE_FROM_INTERFACE (g_class);
501
502       g_signal_new ("deleted",
503                     iface_type,
504                     G_SIGNAL_RUN_LAST,
505                     G_STRUCT_OFFSET (GtkFileFolderIface, deleted),
506                     NULL, NULL,
507                     g_cclosure_marshal_VOID__VOID,
508                     G_TYPE_NONE, 0);
509       g_signal_new ("files_added",
510                     iface_type,
511                     G_SIGNAL_RUN_LAST,
512                     G_STRUCT_OFFSET (GtkFileFolderIface, files_added),
513                     NULL, NULL,
514                     g_cclosure_marshal_VOID__POINTER,
515                     G_TYPE_NONE, 1,
516                     G_TYPE_POINTER);
517       g_signal_new ("file_changed",
518                     iface_type,
519                     G_SIGNAL_RUN_LAST,
520                     G_STRUCT_OFFSET (GtkFileFolderIface, file_changed),
521                     NULL, NULL,
522                     g_cclosure_marshal_VOID__STRING,
523                     G_TYPE_NONE, 1,
524                     G_TYPE_STRING);
525       g_signal_new ("file_removed",
526                     iface_type,
527                     G_SIGNAL_RUN_LAST,
528                     G_STRUCT_OFFSET (GtkFileFolderIface, file_removed),
529                     NULL, NULL,
530                     g_cclosure_marshal_VOID__STRING,
531                     G_TYPE_NONE, 1,
532                     G_TYPE_STRING);
533
534       initialized = TRUE;
535     }
536 }
537
538 gboolean
539 gtk_file_folder_list_children (GtkFileFolder    *folder,
540                                GSList          **children,
541                                GError          **error)
542 {
543   gboolean result;
544   GSList *tmp_children = NULL;
545   
546   g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), FALSE);
547   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
548
549   result = GTK_FILE_FOLDER_GET_IFACE (folder)->list_children (folder, &tmp_children, error);
550   g_assert (result || tmp_children == NULL);
551
552   if (children)
553     *children = tmp_children;
554   else
555     {
556       g_slist_foreach (tmp_children, (GFunc)g_free, NULL);
557       g_slist_free (tmp_children);
558     }
559
560   return result;
561 }
562
563 GtkFileInfo *
564 gtk_file_folder_get_info (GtkFileFolder    *folder,
565                           const gchar      *uri,
566                           GError          **error)
567 {
568   g_return_val_if_fail (GTK_IS_FILE_FOLDER (folder), NULL);
569   g_return_val_if_fail (uri != NULL, NULL);
570   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
571
572   return GTK_FILE_FOLDER_GET_IFACE (folder)->get_info (folder, uri, error);
573 }