source: trunk/third/evolution/shell/e-storage-set.c @ 16787

Revision 16787, 18.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16786, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* e-storage-set.c
3 *
4 * Copyright (C) 2000  Ximian, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program 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 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Ettore Perazzoli
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <string.h>
28
29#include <glib.h>
30#include <gtk/gtkobject.h>
31#include <gtk/gtksignal.h>
32#include <gtk/gtktypeutils.h>
33
34#include <gal/util/e-util.h>
35
36#include "e-storage-set-view.h"
37#include "e-storage-set.h"
38
39
40#define PARENT_TYPE GTK_TYPE_OBJECT
41
42static GtkObjectClass *parent_class = NULL;
43
44/* This is just to make GHashTable happy.  */
45struct _NamedStorage {
46        char *name;
47        EStorage *storage;
48};
49typedef struct _NamedStorage NamedStorage;
50
51struct _EStorageSetPrivate {
52        GList *storages;        /* EStorage */
53        GHashTable *name_to_named_storage;
54
55        EFolderTypeRegistry *folder_type_registry;
56};
57
58enum {
59        NEW_STORAGE,
60        REMOVED_STORAGE,
61        NEW_FOLDER,
62        UPDATED_FOLDER,
63        REMOVED_FOLDER,
64        LAST_SIGNAL
65};
66
67static guint signals[LAST_SIGNAL] = { 0 };
68
69
70static NamedStorage *
71named_storage_new (EStorage *storage)
72{
73        NamedStorage *new;
74
75        new = g_new (NamedStorage, 1);
76        new->name    = g_strdup (e_storage_get_name (storage));
77        new->storage = storage;
78
79        return new;
80}
81
82static void
83named_storage_destroy (NamedStorage *named_storage)
84{
85        g_free (named_storage->name);
86        g_free (named_storage);
87}
88
89static gboolean
90name_to_named_storage_foreach_destroy (void *key,
91                                       void *value,
92                                       void *user_data)
93{
94        NamedStorage *named_storage;
95
96        named_storage = (NamedStorage *) value;
97        named_storage_destroy (named_storage);
98
99        return TRUE;
100}
101
102
103/* "Callback converter", from `EStorageResultCallback' to
104   `EStorageSetResultCallback'.  */
105
106struct _StorageCallbackConverterData {
107        EStorageSet *storage_set;
108        EStorageSetResultCallback storage_set_result_callback;
109        void *data;
110};
111typedef struct _StorageCallbackConverterData StorageCallbackConverterData;
112
113static StorageCallbackConverterData *
114storage_callback_converter_data_new (EStorageSet *storage_set,
115                                     EStorageSetResultCallback callback,
116                                     void *data)
117{
118        StorageCallbackConverterData *new;
119
120        new = g_new (StorageCallbackConverterData, 1);
121        new->storage_set                 = storage_set;
122        new->storage_set_result_callback = callback;
123        new->data                        = data;
124
125        return new;
126}
127
128static void
129storage_callback_converter (EStorage *storage,
130                            EStorageResult result,
131                            void *data)
132{
133        StorageCallbackConverterData *converter_data;
134
135        converter_data = (StorageCallbackConverterData *) data;
136
137        (* converter_data->storage_set_result_callback) (converter_data->storage_set,
138                                                         result,
139                                                         converter_data->data);
140
141        g_free (converter_data);
142}
143
144
145/* Handling for signals coming from the EStorages.  */
146
147static char *
148make_full_path (EStorage *storage,
149                const char *path)
150{
151        const char *storage_name;
152        char *full_path;
153
154        storage_name = e_storage_get_name (storage);
155
156        if (! g_path_is_absolute (path))
157                full_path = g_strconcat (G_DIR_SEPARATOR_S, storage_name,
158                                         G_DIR_SEPARATOR_S, path, NULL);
159        else
160                full_path = g_strconcat (G_DIR_SEPARATOR_S, storage_name,
161                                         path, NULL);
162
163        return full_path;
164}
165
166static void
167storage_new_folder_cb (EStorage *storage,
168                       const char *path,
169                       void *data)
170{
171        EStorageSet *storage_set;
172        char *full_path;
173
174        storage_set = E_STORAGE_SET (data);
175
176        full_path = make_full_path (storage, path);
177        gtk_signal_emit (GTK_OBJECT (storage_set), signals[NEW_FOLDER], full_path);
178        g_free (full_path);
179}
180
181static void
182storage_updated_folder_cb (EStorage *storage,
183                           const char *path,
184                           void *data)
185{
186        EStorageSet *storage_set;
187        char *full_path;
188
189        storage_set = E_STORAGE_SET (data);
190
191        full_path = make_full_path (storage, path);
192        gtk_signal_emit (GTK_OBJECT (storage_set), signals[UPDATED_FOLDER], full_path);
193        g_free (full_path);
194}
195
196static void
197storage_removed_folder_cb (EStorage *storage,
198                           const char *path,
199                           void *data)
200{
201        EStorageSet *storage_set;
202        char *full_path;
203
204        storage_set = E_STORAGE_SET (data);
205
206        full_path = make_full_path (storage, path);
207        gtk_signal_emit (GTK_OBJECT (storage_set), signals[REMOVED_FOLDER], full_path);
208        g_free (full_path);
209}
210
211
212static EStorage *
213get_storage_for_path (EStorageSet *storage_set,
214                      const char *path,
215                      const char **subpath_return)
216{
217        EStorage *storage;
218        char *storage_name;
219        const char *first_separator;
220
221        g_return_val_if_fail (g_path_is_absolute (path), NULL);
222
223        /* Skip initial separator.  */
224        path++;
225
226        first_separator = strchr (path, G_DIR_SEPARATOR);
227
228        if (first_separator == NULL || first_separator == path || first_separator[1] == 0) {
229                *subpath_return = NULL;
230                return NULL;
231        }
232
233        storage_name = g_strndup (path, first_separator - path);
234        storage = e_storage_set_get_storage (storage_set, storage_name);
235        g_free (storage_name);
236
237        *subpath_return = first_separator;
238
239        return storage;
240}
241
242static void
243signal_new_folder_for_all_folders_under_paths (EStorageSet *storage_set,
244                                               EStorage *storage,
245                                               GList *path_list)
246{
247        GList *p;
248
249        for (p = path_list; p != NULL; p = p->next) {
250                GList *sub_path_list;
251                const char *path;
252                char *path_with_storage;
253
254                path = (const char *) p->data;
255
256                path_with_storage = g_strconcat (G_DIR_SEPARATOR_S, e_storage_get_name (storage), path, NULL);
257                gtk_signal_emit (GTK_OBJECT (storage_set), signals[NEW_FOLDER], path_with_storage);
258                g_free (path_with_storage);
259
260                sub_path_list = e_storage_get_subfolder_paths (storage, path);
261
262                signal_new_folder_for_all_folders_under_paths (storage_set, storage, sub_path_list);
263
264                e_free_string_list (sub_path_list);
265        }
266}
267
268static void
269signal_new_folder_for_all_folders_in_storage (EStorageSet *storage_set,
270                                              EStorage *storage)
271{
272        GList *path_list;
273
274        path_list = e_storage_get_subfolder_paths (storage, G_DIR_SEPARATOR_S);
275
276        signal_new_folder_for_all_folders_under_paths (storage_set, storage, path_list);
277
278        e_free_string_list (path_list);
279}
280
281
282/* GtkObject methods.  */
283
284static void
285destroy (GtkObject *object)
286{
287        EStorageSet *storage_set;
288        EStorageSetPrivate *priv;
289
290        storage_set = E_STORAGE_SET (object);
291        priv = storage_set->priv;
292
293        e_free_object_list (priv->storages);
294
295        gtk_object_unref (GTK_OBJECT (priv->folder_type_registry));
296
297        g_hash_table_foreach (priv->name_to_named_storage,
298                              (GHFunc) name_to_named_storage_foreach_destroy, NULL);
299        g_hash_table_destroy (priv->name_to_named_storage);
300
301        g_free (priv);
302
303        (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
304}
305
306
307static void
308class_init (EStorageSetClass *klass)
309{
310        GtkObjectClass *object_class;
311
312        parent_class = gtk_type_class (gtk_object_get_type ());
313        object_class = GTK_OBJECT_CLASS (klass);
314
315        object_class->destroy = destroy;
316
317        signals[NEW_STORAGE] =
318                gtk_signal_new ("new_storage",
319                                GTK_RUN_FIRST,
320                                object_class->type,
321                                GTK_SIGNAL_OFFSET (EStorageSetClass, new_storage),
322                                gtk_marshal_NONE__POINTER,
323                                GTK_TYPE_NONE, 1,
324                                GTK_TYPE_POINTER);
325        signals[REMOVED_STORAGE] =
326                gtk_signal_new ("removed_storage",
327                                GTK_RUN_FIRST,
328                                object_class->type,
329                                GTK_SIGNAL_OFFSET (EStorageSetClass, removed_storage),
330                                gtk_marshal_NONE__POINTER,
331                                GTK_TYPE_NONE, 1,
332                                GTK_TYPE_POINTER);
333        signals[NEW_FOLDER] =
334                gtk_signal_new ("new_folder",
335                                GTK_RUN_FIRST,
336                                object_class->type,
337                                GTK_SIGNAL_OFFSET (EStorageSetClass, new_folder),
338                                gtk_marshal_NONE__STRING,
339                                GTK_TYPE_NONE, 1,
340                                GTK_TYPE_STRING);
341        signals[UPDATED_FOLDER] =
342                gtk_signal_new ("updated_folder",
343                                GTK_RUN_FIRST,
344                                object_class->type,
345                                GTK_SIGNAL_OFFSET (EStorageSetClass, updated_folder),
346                                gtk_marshal_NONE__STRING,
347                                GTK_TYPE_NONE, 1,
348                                GTK_TYPE_STRING);
349        signals[REMOVED_FOLDER] =
350                gtk_signal_new ("removed_folder",
351                                GTK_RUN_FIRST,
352                                object_class->type,
353                                GTK_SIGNAL_OFFSET (EStorageSetClass, removed_folder),
354                                gtk_marshal_NONE__STRING,
355                                GTK_TYPE_NONE, 1,
356                                GTK_TYPE_STRING);
357
358        gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
359}
360
361static void
362init (EStorageSet *storage_set)
363{
364        EStorageSetPrivate *priv;
365
366        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
367
368        priv = g_new (EStorageSetPrivate, 1);
369        priv->storages              = NULL;
370        priv->name_to_named_storage = g_hash_table_new (g_str_hash, g_str_equal);
371        priv->folder_type_registry  = NULL;
372
373        storage_set->priv = priv;
374}
375
376
377void
378e_storage_set_construct (EStorageSet *storage_set,
379                         EFolderTypeRegistry *folder_type_registry)
380{
381        g_return_if_fail (storage_set != NULL);
382        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
383
384        GTK_OBJECT_UNSET_FLAGS (storage_set, GTK_FLOATING);
385
386        gtk_object_ref (GTK_OBJECT (folder_type_registry));
387        storage_set->priv->folder_type_registry = folder_type_registry;
388}
389
390EStorageSet *
391e_storage_set_new (EFolderTypeRegistry *folder_type_registry)
392{
393        EStorageSet *new;
394
395        new = gtk_type_new (e_storage_set_get_type ());
396
397        e_storage_set_construct (new, folder_type_registry);
398
399        return new;
400}
401
402
403GList *
404e_storage_set_get_storage_list (EStorageSet *storage_set)
405{
406        EStorageSetPrivate *priv;
407        GList *list;
408        GList *p;
409
410        g_return_val_if_fail (storage_set != NULL, NULL);
411        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
412
413        priv = storage_set->priv;
414
415        list = NULL;
416        for (p = priv->storages; p != NULL; p = p->next) {
417                gtk_object_ref (GTK_OBJECT (p->data));
418                list = g_list_prepend (list, p->data);
419        }
420
421        return g_list_reverse (list); /* Lame.  */
422}
423
424/**
425 * e_storage_set_add_storage:
426 * @storage_set:
427 * @storage:
428 *
429 * Add @storage to @storage_set.  Notice that will ref the storage.
430 **/
431gboolean
432e_storage_set_add_storage (EStorageSet *storage_set,
433                           EStorage *storage)
434{
435        EStorageSetPrivate *priv;
436        const char *storage_name;
437        NamedStorage *named_storage;
438
439        g_return_val_if_fail (storage_set != NULL, FALSE);
440        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), FALSE);
441        g_return_val_if_fail (storage != NULL, FALSE);
442        g_return_val_if_fail (E_IS_STORAGE (storage), FALSE);
443
444        priv = storage_set->priv;
445
446        storage_name = e_storage_get_name (storage);
447        if (g_hash_table_lookup (priv->name_to_named_storage, storage_name) != NULL)
448                return FALSE;
449
450        gtk_object_ref (GTK_OBJECT (storage));
451
452        gtk_signal_connect (GTK_OBJECT (storage), "new_folder",
453                            GTK_SIGNAL_FUNC (storage_new_folder_cb), storage_set);
454        gtk_signal_connect (GTK_OBJECT (storage), "updated_folder",
455                            GTK_SIGNAL_FUNC (storage_updated_folder_cb), storage_set);
456        gtk_signal_connect (GTK_OBJECT (storage), "removed_folder",
457                            GTK_SIGNAL_FUNC (storage_removed_folder_cb), storage_set);
458
459        priv->storages = g_list_append (priv->storages, storage);
460
461        named_storage = named_storage_new (storage);
462        g_hash_table_insert (priv->name_to_named_storage, named_storage->name, named_storage);
463
464        gtk_signal_emit (GTK_OBJECT (storage_set), signals[NEW_STORAGE], storage);
465
466        signal_new_folder_for_all_folders_in_storage (storage_set, storage);
467
468        return TRUE;
469}
470
471gboolean
472e_storage_set_remove_storage (EStorageSet *storage_set,
473                              EStorage *storage)
474{
475        EStorageSetPrivate *priv;
476        NamedStorage *named_storage;
477
478        g_return_val_if_fail (storage_set != NULL, FALSE);
479        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), FALSE);
480        g_return_val_if_fail (storage != NULL, FALSE);
481        g_return_val_if_fail (E_IS_STORAGE (storage), FALSE);
482
483        priv = storage_set->priv;
484
485        named_storage = g_hash_table_lookup (priv->name_to_named_storage,
486                                             e_storage_get_name (storage));
487        if (named_storage == NULL)
488                return FALSE;
489
490        g_hash_table_remove (priv->name_to_named_storage, named_storage->name);
491        named_storage_destroy (named_storage);
492
493        priv->storages = g_list_remove (priv->storages, storage);
494
495        gtk_signal_emit (GTK_OBJECT (storage_set), signals[REMOVED_STORAGE], storage);
496        gtk_object_unref (GTK_OBJECT (storage));
497
498        return TRUE;
499}
500
501void
502e_storage_set_remove_all_storages (EStorageSet *storage_set)
503{
504        EStorageSetPrivate *priv;
505        GList *p;
506
507        g_return_if_fail (storage_set != NULL);
508        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
509
510        priv = storage_set->priv;
511
512        for (p = priv->storages; p != NULL; p = p->next) {
513                EStorage *storage;
514
515                storage = E_STORAGE (p->data);
516
517                gtk_signal_emit (GTK_OBJECT (storage_set), signals[REMOVED_STORAGE], storage);
518                gtk_object_unref (GTK_OBJECT (storage));
519        }
520
521        g_hash_table_foreach_remove (priv->name_to_named_storage,
522                                     name_to_named_storage_foreach_destroy,
523                                     NULL);
524
525        g_list_free (priv->storages);
526        priv->storages = NULL;
527}
528
529
530EStorage *
531e_storage_set_get_storage (EStorageSet *storage_set,
532                           const char *name)
533{
534        EStorageSetPrivate *priv;
535        NamedStorage *named_storage;
536
537        g_return_val_if_fail (storage_set != NULL, NULL);
538        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
539        g_return_val_if_fail (name != NULL, NULL);
540
541        priv = storage_set->priv;
542
543        named_storage = g_hash_table_lookup (priv->name_to_named_storage, name);
544        if (named_storage == NULL)
545                return NULL;
546        else
547                return named_storage->storage;
548}
549
550EFolder *
551e_storage_set_get_folder (EStorageSet *storage_set,
552                          const char *path)
553{
554        EStorage *storage;
555        const char *subpath;
556
557        g_return_val_if_fail (storage_set != NULL, NULL);
558        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
559        g_return_val_if_fail (path != NULL, NULL);
560        g_return_val_if_fail (g_path_is_absolute (path), NULL);
561
562        storage = get_storage_for_path (storage_set, path, &subpath);
563        if (storage == NULL)
564                return NULL;
565
566        return e_storage_get_folder (storage, subpath);
567}
568
569
570GtkWidget *
571e_storage_set_new_view (EStorageSet *storage_set, BonoboUIContainer *container)
572{
573        GtkWidget *storage_set_view;
574
575        g_return_val_if_fail (storage_set != NULL, NULL);
576        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
577
578        storage_set_view = e_storage_set_view_new (storage_set, container);
579
580        return storage_set_view;
581}
582
583
584void
585e_storage_set_async_create_folder  (EStorageSet *storage_set,
586                                    const char *path,
587                                    const char *type,
588                                    const char *description,
589                                    EStorageSetResultCallback callback,
590                                    void *data)
591{
592        EStorage *storage;
593        const char *subpath;
594        StorageCallbackConverterData *converter_data;
595
596        g_return_if_fail (storage_set != NULL);
597        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
598        g_return_if_fail (path != NULL);
599        g_return_if_fail (g_path_is_absolute (path));
600        g_return_if_fail (type != NULL);
601        g_return_if_fail (description != NULL);
602        g_return_if_fail (callback != NULL);
603
604        storage = get_storage_for_path (storage_set, path, &subpath);
605
606        converter_data = storage_callback_converter_data_new (storage_set, callback, data);
607
608        e_storage_async_create_folder (storage, subpath, type, description,
609                                       storage_callback_converter, converter_data);
610}
611
612void
613e_storage_set_async_remove_folder  (EStorageSet *storage_set,
614                                    const char *path,
615                                    EStorageSetResultCallback callback,
616                                    void *data)
617{
618        EStorage *storage;
619        const char *subpath;
620        StorageCallbackConverterData *converter_data;
621
622        g_return_if_fail (storage_set != NULL);
623        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
624        g_return_if_fail (path != NULL);
625        g_return_if_fail (g_path_is_absolute (path));
626        g_return_if_fail (callback != NULL);
627
628        storage = get_storage_for_path (storage_set, path, &subpath);
629
630        converter_data = storage_callback_converter_data_new (storage_set, callback, data);
631
632        e_storage_async_remove_folder (storage, subpath,
633                                       storage_callback_converter, converter_data);
634}
635
636void
637e_storage_set_async_xfer_folder (EStorageSet *storage_set,
638                                 const char *source_path,
639                                 const char *destination_path,
640                                 gboolean remove_source,
641                                 EStorageSetResultCallback callback,
642                                 void *data)
643{
644        EStorage *source_storage;
645        EStorage *destination_storage;
646        const char *source_subpath;
647        const char *destination_subpath;
648        StorageCallbackConverterData *converter_data;
649
650        g_return_if_fail (storage_set != NULL);
651        g_return_if_fail (E_IS_STORAGE_SET (storage_set));
652        g_return_if_fail (source_path != NULL);
653        g_return_if_fail (g_path_is_absolute (source_path));
654        g_return_if_fail (destination_path != NULL);
655        g_return_if_fail (g_path_is_absolute (destination_path));
656        g_return_if_fail (callback != NULL);
657
658        source_storage = get_storage_for_path (storage_set, source_path, &source_subpath);
659        destination_storage = get_storage_for_path (storage_set, destination_path, &destination_subpath);
660
661        if (source_storage != destination_storage) {
662                g_warning ("e_storage_set_async_xfer_folder(): "
663                           "Attempt to xfer folders between different storages -- not supported yet.");
664                (* callback) (storage_set, E_STORAGE_UNSUPPORTEDOPERATION, data);
665                return;
666        }
667
668        converter_data = storage_callback_converter_data_new (storage_set, callback, data);
669
670        e_storage_async_xfer_folder (source_storage,
671                                     source_subpath, destination_subpath, remove_source,
672                                     storage_callback_converter, converter_data);
673}
674
675
676EFolderTypeRegistry *
677e_storage_set_get_folder_type_registry (EStorageSet *storage_set)
678{
679        g_return_val_if_fail (storage_set != NULL, NULL);
680        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
681
682        return storage_set->priv->folder_type_registry;
683}
684
685
686/**
687 * e_storage_set_get_path_for_physical_uri:
688 * @storage_set: A storage set
689 * @physical_uri: A physical URI
690 *
691 * Retrieve the path of the folder whose physical URI matches @physical_uri.
692 *
693 * Return value:
694 **/
695char *
696e_storage_set_get_path_for_physical_uri (EStorageSet *storage_set,
697                                         const char *physical_uri)
698{
699        EStorageSetPrivate *priv;
700        GList *p;
701
702        g_return_val_if_fail (storage_set != NULL, NULL);
703        g_return_val_if_fail (E_IS_STORAGE_SET (storage_set), NULL);
704        g_return_val_if_fail (physical_uri != NULL, NULL);
705
706        priv = storage_set->priv;
707
708        for (p = priv->storages; p != NULL; p = p->next) {
709                EStorage *storage;
710                char *storage_path;
711
712                storage = E_STORAGE (p->data);
713
714                storage_path = e_storage_get_path_for_physical_uri (storage, physical_uri);
715                if (storage_path != NULL) {
716                        char *storage_set_path;
717
718                        storage_set_path = g_strconcat (G_DIR_SEPARATOR_S,
719                                                        e_storage_get_name (storage),
720                                                        storage_path,
721                                                        NULL);
722                        g_free (storage_path);
723
724                        return storage_set_path;
725                }
726        }
727
728        return NULL;
729}
730
731
732E_MAKE_TYPE (e_storage_set, "EStorageSet", EStorageSet, class_init, init, PARENT_TYPE)
Note: See TracBrowser for help on using the repository browser.