1 /* Evolution calendar factory
3 * Copyright (C) 2000-2003 Ximian, Inc.
6 * Federico Mena-Quintero <federico@ximian.com>
7 * JP Rosevear <jpr@ximian.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU Lesser General Public
11 * License as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <bonobo-activation/bonobo-activation.h>
24 #include <bonobo/bonobo-exception.h>
25 #include <bonobo/bonobo-main.h>
26 #include "libedataserver/e-url.h"
27 #include "libedataserver/e-source.h"
28 #include "libedataserver/e-data-server-module.h"
29 #include "e-cal-backend.h"
30 #include "e-data-cal.h"
31 #include "e-data-cal-factory.h"
33 #define PARENT_TYPE BONOBO_TYPE_OBJECT
34 #define DEFAULT_E_DATA_CAL_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_DataServer_CalFactory:" BASE_VERSION
36 static BonoboObjectClass *parent_class;
38 /* Private part of the CalFactory structure */
39 struct _EDataCalFactoryPrivate {
40 /* Hash table from URI method strings to GType * for backend class types */
43 /* Hash table from GnomeVFSURI structures to CalBackend objects */
46 /* OAFIID of the factory */
49 /* Whether we have been registered with OAF yet */
62 static guint signals[LAST_SIGNAL];
64 /* Opening calendars */
66 static icalcomponent_kind
67 calobjtype_to_icalkind (const GNOME_Evolution_Calendar_CalObjType type)
70 case GNOME_Evolution_Calendar_TYPE_EVENT:
71 return ICAL_VEVENT_COMPONENT;
72 case GNOME_Evolution_Calendar_TYPE_TODO:
73 return ICAL_VTODO_COMPONENT;
74 case GNOME_Evolution_Calendar_TYPE_JOURNAL:
75 return ICAL_VJOURNAL_COMPONENT;
78 return ICAL_NO_COMPONENT;
81 static ECalBackendFactory*
82 get_backend_factory (GHashTable *methods, const char *method, icalcomponent_kind kind)
85 ECalBackendFactory *factory;
87 kinds = g_hash_table_lookup (methods, method);
91 factory = g_hash_table_lookup (kinds, GINT_TO_POINTER (kind));
96 /* Callback used when a backend loses its last connected client */
98 backend_last_client_gone_cb (ECalBackend *backend, gpointer data)
100 EDataCalFactory *factory;
101 EDataCalFactoryPrivate *priv;
102 ECalBackend *ret_backend;
106 fprintf (stderr, "backend_last_client_gone_cb() called!\n");
108 factory = E_DATA_CAL_FACTORY (data);
109 priv = factory->priv;
111 /* Remove the backend from the hash table */
113 uristr = e_cal_backend_get_uri (backend);
114 g_assert (uristr != NULL);
115 uri = g_strdup_printf("%s:%d", uristr, (int)e_cal_backend_get_kind(backend));
117 ret_backend = g_hash_table_lookup (factory->priv->backends, uri);
118 g_assert (ret_backend != NULL);
119 g_assert (ret_backend == backend);
121 g_hash_table_remove (priv->backends, uri);
124 g_signal_handlers_disconnect_matched (backend, G_SIGNAL_MATCH_DATA,
125 0, 0, NULL, NULL, data);
127 /* Notify upstream if there are no more backends */
128 if (g_hash_table_size (priv->backends) == 0)
129 g_signal_emit (G_OBJECT (factory), signals[LAST_CALENDAR_GONE], 0);
134 static GNOME_Evolution_Calendar_Cal
135 impl_CalFactory_getCal (PortableServer_Servant servant,
136 const CORBA_char *source_xml,
137 const GNOME_Evolution_Calendar_CalObjType type,
138 const GNOME_Evolution_Calendar_CalListener listener,
139 CORBA_Environment *ev)
141 GNOME_Evolution_Calendar_Cal ret_cal = NULL;
142 EDataCalFactory *factory;
143 EDataCalFactoryPrivate *priv;
144 EDataCal *cal = CORBA_OBJECT_NIL;
145 ECalBackend *backend;
146 CORBA_Environment ev2;
147 GNOME_Evolution_Calendar_CalListener listener_copy;
148 ECalBackendFactory *backend_factory;
152 char *uri_type_string;
154 factory = E_DATA_CAL_FACTORY (bonobo_object_from_servant (servant));
155 priv = factory->priv;
157 source = e_source_new_from_standalone_xml (source_xml);
159 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_InvalidURI);
161 return CORBA_OBJECT_NIL;
164 /* Get the URI so we can extract the protocol */
165 str_uri = e_source_get_uri (source);
167 g_object_unref (source);
168 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_InvalidURI);
170 return CORBA_OBJECT_NIL;
174 uri = e_uri_new (str_uri);
176 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_InvalidURI);
178 return CORBA_OBJECT_NIL;
181 uri_type_string = g_strdup_printf ("%s:%d", str_uri, (int)calobjtype_to_icalkind (type));
184 /* Find the associated backend factory (if any) */
185 backend_factory = get_backend_factory (priv->methods, uri->protocol, calobjtype_to_icalkind (type));
186 if (!backend_factory) {
187 /* FIXME Distinguish between method and kind failures? */
188 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod);
192 /* Duplicate the listener object */
193 CORBA_exception_init (&ev2);
194 listener_copy = CORBA_Object_duplicate (listener, &ev2);
196 if (BONOBO_EX (&ev2)) {
197 g_warning (G_STRLOC ": could not duplicate the listener");
198 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_NilListener);
199 CORBA_exception_free (&ev2);
202 CORBA_exception_free (&ev2);
204 /* Look for an existing backend */
205 backend = g_hash_table_lookup (factory->priv->backends, uri_type_string);
207 /* There was no existing backend, create a new one */
208 backend = e_cal_backend_factory_new_backend (backend_factory, source);
211 g_warning (G_STRLOC ": could not instantiate backend");
212 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod);
216 /* Track the backend */
217 g_hash_table_insert (priv->backends, g_strdup (uri_type_string), backend);
219 g_signal_connect (G_OBJECT (backend), "last_client_gone",
220 G_CALLBACK (backend_last_client_gone_cb),
224 /* Create the corba calendar */
225 cal = e_data_cal_new (backend, listener);
226 printf ("cal = %p\n", cal);
228 g_warning (G_STRLOC ": could not create the corba calendar");
229 bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_CalFactory_UnsupportedMethod);
233 /* Let the backend know about its clients corba clients */
234 e_cal_backend_add_client (backend, cal);
235 e_cal_backend_set_mode (backend, priv->mode);
237 ret_cal = CORBA_Object_duplicate (BONOBO_OBJREF (cal), ev);
240 g_free (uri_type_string);
241 g_object_unref (source);
249 * e_data_cal_factory_new:
252 * Creates a new #EDataCalFactory object.
254 * Return value: A newly-created #EDataCalFactory, or NULL if its corresponding CORBA
255 * object could not be created.
258 e_data_cal_factory_new (void)
260 EDataCalFactory *factory;
262 factory = g_object_new (E_TYPE_DATA_CAL_FACTORY,
263 "poa", bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL),
269 /* Destroy handler for the calendar */
271 e_data_cal_factory_finalize (GObject *object)
273 EDataCalFactory *factory;
274 EDataCalFactoryPrivate *priv;
276 g_return_if_fail (object != NULL);
277 g_return_if_fail (E_IS_DATA_CAL_FACTORY (object));
279 factory = E_DATA_CAL_FACTORY (object);
280 priv = factory->priv;
282 g_hash_table_destroy (priv->methods);
283 priv->methods = NULL;
285 /* Should we assert that there are no more backends? */
286 g_hash_table_destroy (priv->backends);
287 priv->backends = NULL;
289 if (priv->registered) {
290 bonobo_activation_active_server_unregister (priv->iid, BONOBO_OBJREF (factory));
291 priv->registered = FALSE;
296 factory->priv = NULL;
298 if (G_OBJECT_CLASS (parent_class)->finalize)
299 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
302 /* Class initialization function for the calendar factory */
304 e_data_cal_factory_class_init (EDataCalFactoryClass *klass)
306 GObjectClass *object_class = (GObjectClass *) klass;
307 POA_GNOME_Evolution_Calendar_CalFactory__epv *epv = &klass->epv;
309 parent_class = g_type_class_peek_parent (klass);
311 signals[LAST_CALENDAR_GONE] =
312 g_signal_new ("last_calendar_gone",
313 G_TYPE_FROM_CLASS (klass),
315 G_STRUCT_OFFSET (EDataCalFactoryClass, last_calendar_gone),
317 g_cclosure_marshal_VOID__VOID,
320 /* Class method overrides */
321 object_class->finalize = e_data_cal_factory_finalize;
324 epv->getCal = impl_CalFactory_getCal;
328 set_backend_online_status (gpointer key, gpointer value, gpointer data)
330 ECalBackend *backend = E_CAL_BACKEND (value);
332 e_cal_backend_set_mode (backend, GPOINTER_TO_INT (data));
336 * e_data_cal_factory_set_backend_mode:
337 * @factory: A calendar factory.
338 * @mode: Online mode to set.
340 * Sets the online mode for all backends created by the given factory.
343 e_data_cal_factory_set_backend_mode (EDataCalFactory *factory, int mode)
345 EDataCalFactoryPrivate *priv = factory->priv;
349 g_hash_table_foreach (priv->backends, set_backend_online_status, GINT_TO_POINTER (priv->mode));
353 /* Object initialization function for the calendar factory */
355 e_data_cal_factory_init (EDataCalFactory *factory, EDataCalFactoryClass *klass)
357 EDataCalFactoryPrivate *priv;
359 priv = g_new0 (EDataCalFactoryPrivate, 1);
360 factory->priv = priv;
362 priv->methods = g_hash_table_new_full (g_str_hash, g_str_equal,
363 (GDestroyNotify) g_free, (GDestroyNotify) g_hash_table_destroy);
364 priv->backends = g_hash_table_new_full (g_str_hash, g_str_equal,
365 (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
366 priv->registered = FALSE;
369 BONOBO_TYPE_FUNC_FULL (EDataCalFactory,
370 GNOME_Evolution_Calendar_CalFactory,
375 * e_data_cal_factory_register_storage:
376 * @factory: A calendar factory.
377 * @iid: OAFIID for the factory to be registered.
379 * Registers a calendar factory with the OAF object activation daemon. This
380 * function must be called before any clients can activate the factory.
382 * Return value: TRUE on success, FALSE otherwise.
385 e_data_cal_factory_register_storage (EDataCalFactory *factory, const char *iid)
387 EDataCalFactoryPrivate *priv;
388 Bonobo_RegistrationResult result;
391 g_return_val_if_fail (factory != NULL, FALSE);
392 g_return_val_if_fail (E_IS_DATA_CAL_FACTORY (factory), FALSE);
394 priv = factory->priv;
396 g_return_val_if_fail (!priv->registered, FALSE);
398 /* if iid is NULL, use the default factory OAFIID */
400 tmp_iid = g_strdup (iid);
402 tmp_iid = g_strdup (DEFAULT_E_DATA_CAL_FACTORY_OAF_ID);
404 result = bonobo_activation_active_server_register (tmp_iid, BONOBO_OBJREF (factory));
407 case Bonobo_ACTIVATION_REG_SUCCESS:
408 priv->registered = TRUE;
412 case Bonobo_ACTIVATION_REG_NOT_LISTED:
413 g_warning (G_STRLOC ": cannot register the calendar factory %s (not listed)", tmp_iid);
416 case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
417 g_warning (G_STRLOC ": cannot register the calendar factory (already active)");
420 case Bonobo_ACTIVATION_REG_ERROR:
422 g_warning (G_STRLOC ": cannot register the calendar factory (generic error)");
432 * e_data_cal_factory_register_backend:
433 * @factory: A calendar factory.
434 * @backend_factory: The object responsible for creating backends.
436 * Registers an #ECalBackend subclass that will be used to handle URIs
437 * with a particular method. When the factory is asked to open a
438 * particular URI, it will look in its list of registered methods and
439 * create a backend of the appropriate type.
442 e_data_cal_factory_register_backend (EDataCalFactory *factory, ECalBackendFactory *backend_factory)
444 EDataCalFactoryPrivate *priv;
449 icalcomponent_kind kind;
451 g_return_if_fail (factory && E_IS_DATA_CAL_FACTORY (factory));
452 g_return_if_fail (backend_factory && E_IS_CAL_BACKEND_FACTORY (backend_factory));
454 priv = factory->priv;
456 method = E_CAL_BACKEND_FACTORY_GET_CLASS (backend_factory)->get_protocol (backend_factory);
457 kind = E_CAL_BACKEND_FACTORY_GET_CLASS (backend_factory)->get_kind (backend_factory);
459 method_str = g_ascii_strdown (method, -1);
461 kinds = g_hash_table_lookup (priv->methods, method_str);
463 type = GPOINTER_TO_INT (g_hash_table_lookup (kinds, GINT_TO_POINTER (kind)));
465 g_warning (G_STRLOC ": method `%s' already registered", method_str);
473 kinds = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
474 g_hash_table_insert (priv->methods, method_str, kinds);
477 g_hash_table_insert (kinds, GINT_TO_POINTER (kind), backend_factory);
481 * e_data_cal_factory_register_backends:
482 * @cal_factory: A calendar factory.
484 * Register all backends for the given factory.
487 e_data_cal_factory_register_backends (EDataCalFactory *cal_factory)
489 GList *factories, *f;
491 factories = e_data_server_get_extensions_for_type (E_TYPE_CAL_BACKEND_FACTORY);
492 for (f = factories; f; f = f->next) {
493 ECalBackendFactory *backend_factory = f->data;
495 e_data_cal_factory_register_backend (cal_factory, g_object_ref (backend_factory));
498 e_data_server_extension_list_free (factories);
502 * e_data_cal_factory_get_n_backends
503 * @factory: A calendar factory.
505 * Get the number of backends currently active in the given factory.
507 * Returns: the number of backends.
510 e_data_cal_factory_get_n_backends (EDataCalFactory *factory)
512 EDataCalFactoryPrivate *priv;
514 g_return_val_if_fail (E_IS_DATA_CAL_FACTORY (factory), 0);
516 priv = factory->priv;
517 return g_hash_table_size (priv->backends);
520 /* Frees a uri/backend pair from the backends hash table */
522 dump_backend (gpointer key, gpointer value, gpointer data)
525 ECalBackend *backend;
530 g_message (" %s: %p", uri, backend);
534 * e_data_cal_factory_dump_active_backends:
535 * @factory: A calendar factory.
537 * Dumps to standard output a list of all active backends for the given
541 e_data_cal_factory_dump_active_backends (EDataCalFactory *factory)
543 EDataCalFactoryPrivate *priv;
545 g_message ("Active PCS backends");
547 priv = factory->priv;
548 g_hash_table_foreach (priv->backends, dump_backend, NULL);