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