diff options
-rw-r--r-- | calendar/ChangeLog | 27 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-file.c | 342 | ||||
-rw-r--r-- | calendar/pcs/cal-backend.c | 373 | ||||
-rw-r--r-- | calendar/pcs/cal-backend.h | 14 |
4 files changed, 392 insertions, 364 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 41a1ec6916..1f395eed41 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,30 @@ +2003-01-17 Dan Winship <danw@ximian.com> + + * pcs/cal-backend.c: Move some non-file-backend-specific stuff + from cal-backend-file here so it can be shared with other + backends. + (CalBackendPrivate): add this, containing the categories hashes + and the (formerly public) clients list. + (cal_backend_init, cal_backend_finalize): Handle backend->priv. + (cal_destroy_cb): Simplify this (and redo it as a weak notify + func) + (cal_backend_add_cal): Keep a weak ref on the cal rather than + connecting to its "destroy" signal. Call notify_categories_changed + to let the new cal know about them. + (get_object): Default implementation of cal_backend_get_object. + that calls cal_component_get_as_string on the return value of + cal_backend_get_object_component. + (cal_backend_notify_mode, cal_backend_notify_update, + cal_backend_notify_remove, cal_backend_notify_error): Notify each + Cal about something. + (cal_backend_ref_categories, cal_backend_unref_categories): + Maintain a list of categories that are used by components in the + backend, and trigger categories_changed notifications as needed. + + * pcs/cal-backend-file.c: Remove stuff that was moved to + CalBackend (notify funcs, category handling, get_object + implementation) + 2003-01-16 Hans Petter Jansson <hpj@ximian.com> * gui/e-alarm-list.[ch]: Implement EAlarmList as CalComponentAlarm diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index 595626f043..f73ab66874 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -33,23 +33,11 @@ -/* A category that exists in some of the objects of the calendar */ -typedef struct { - /* Category name, also used as the key in the categories hash table */ - char *name; - - /* Number of objects that have this category */ - int refcount; -} Category; - /* Private part of the CalBackendFile structure */ struct _CalBackendFilePrivate { /* URI where the calendar data is stored */ char *uri; - /* List of Cal objects with their listeners */ - GList *clients; - /* Toplevel VCALENDAR component */ icalcomponent *icalcomp; @@ -69,10 +57,6 @@ struct _CalBackendFilePrivate { GList *todos; GList *journals; - /* Hash table of live categories, and a temporary hash of removed categories */ - GHashTable *categories; - GHashTable *removed_categories; - /* Config database handle for free/busy organizer information */ EConfigListener *config_listener; @@ -106,7 +90,6 @@ static CalMode cal_backend_file_get_mode (CalBackend *backend); static void cal_backend_file_set_mode (CalBackend *backend, CalMode mode); static int cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type); -static char *cal_backend_file_get_object (CalBackend *backend, const char *uid); static CalComponent *cal_backend_file_get_object_component (CalBackend *backend, const char *uid); static char *cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid); static GList *cal_backend_file_get_uids (CalBackend *backend, CalObjType type); @@ -137,9 +120,6 @@ static icaltimezone* cal_backend_file_get_default_timezone (CalBackend *backend) static gboolean cal_backend_file_set_default_timezone (CalBackend *backend, const char *tzid); -static void notify_categories_changed (CalBackendFile *cbfile); -static void notify_error (CalBackendFile *cbfile, const char *message); - static CalBackendClass *parent_class; @@ -200,7 +180,6 @@ cal_backend_file_class_init (CalBackendFileClass *class) backend_class->get_mode = cal_backend_file_get_mode; backend_class->set_mode = cal_backend_file_set_mode; backend_class->get_n_objects = cal_backend_file_get_n_objects; - backend_class->get_object = cal_backend_file_get_object; backend_class->get_object_component = cal_backend_file_get_object_component; backend_class->get_timezone_object = cal_backend_file_get_timezone_object; backend_class->get_uids = cal_backend_file_get_uids; @@ -218,12 +197,6 @@ cal_backend_file_class_init (CalBackendFileClass *class) backend_class->set_default_timezone = cal_backend_file_set_default_timezone; } -static void -cal_added_cb (CalBackend *backend, gpointer user_data) -{ - notify_categories_changed (CAL_BACKEND_FILE (backend)); -} - /* Object initialization function for the file backend */ static void cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class) @@ -240,16 +213,10 @@ cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class) priv->todos = NULL; priv->journals = NULL; - priv->categories = g_hash_table_new (g_str_hash, g_str_equal); - priv->removed_categories = g_hash_table_new (g_str_hash, g_str_equal); - /* The timezone defaults to UTC. */ priv->default_zone = icaltimezone_get_utc_timezone (); priv->config_listener = e_config_listener_new (); - - g_signal_connect (G_OBJECT (cbfile), "cal_added", - G_CALLBACK (cal_added_cb), NULL); } /* g_hash_table_foreach() callback to destroy a CalComponent */ @@ -329,21 +296,10 @@ save (CalBackendFile *cbfile) return; error: - notify_error (cbfile, gnome_vfs_result_to_string (result)); + cal_backend_notify_error (CAL_BACKEND (cbfile), gnome_vfs_result_to_string (result)); return; } -/* Used from g_hash_table_foreach(), frees a Category structure */ -static void -free_category_cb (gpointer key, gpointer value, gpointer data) -{ - Category *c; - - c = value; - g_free (c->name); - g_free (c); -} - /* Dispose handler for the file backend */ static void cal_backend_file_dispose (GObject *object) @@ -404,9 +360,6 @@ cal_backend_file_finalize (GObject *object) cbfile = CAL_BACKEND_FILE (object); priv = cbfile->priv; - clients = CAL_BACKEND (cbfile)->clients; - g_assert (clients == NULL); - /* Clean up */ if (priv->uri) { @@ -414,14 +367,6 @@ cal_backend_file_finalize (GObject *object) priv->uri = NULL; } - g_hash_table_foreach (priv->categories, free_category_cb, NULL); - g_hash_table_destroy (priv->categories); - priv->categories = NULL; - - g_hash_table_foreach (priv->removed_categories, free_category_cb, NULL); - g_hash_table_destroy (priv->removed_categories); - priv->removed_categories = NULL; - g_free (priv); cbfile->priv = NULL; @@ -483,53 +428,6 @@ cal_backend_file_get_email_address (CalBackend *backend) return NULL; } -/* Used from g_hash_table_foreach(), adds a category name to the sequence */ -static void -add_category_cb (gpointer key, gpointer value, gpointer data) -{ - Category *c; - GNOME_Evolution_Calendar_StringSeq *seq; - - c = value; - seq = data; - - seq->_buffer[seq->_length] = CORBA_string_dup (c->name); - seq->_length++; -} - -/* Notifies the clients with the current list of categories */ -static void -notify_categories_changed (CalBackendFile *cbfile) -{ - CalBackendFilePrivate *priv; - GNOME_Evolution_Calendar_StringSeq *seq; - GList *l; - - priv = cbfile->priv; - - /* Build the sequence of category names */ - - seq = GNOME_Evolution_Calendar_StringSeq__alloc (); - seq->_length = 0; - seq->_maximum = g_hash_table_size (priv->categories); - seq->_buffer = CORBA_sequence_CORBA_string_allocbuf (seq->_maximum); - CORBA_sequence_set_release (seq, TRUE); - - g_hash_table_foreach (priv->categories, add_category_cb, seq); - g_assert (seq->_length == seq->_maximum); - - /* Notify the clients */ - - for (l = CAL_BACKEND (cbfile)->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_categories_changed (cal, seq); - } - - CORBA_free (seq); -} - /* Idle handler; we save the calendar since it is dirty */ static gboolean save_idle (gpointer data) @@ -592,68 +490,6 @@ check_dup_uid (CalBackendFile *cbfile, CalComponent *comp) mark_dirty (cbfile); } -/* Updates the hash table of categories by adding or removing those in the - * component. - */ -static void -update_categories_from_comp (CalBackendFile *cbfile, CalComponent *comp, gboolean add) -{ - CalBackendFilePrivate *priv; - GSList *categories, *l; - - priv = cbfile->priv; - - cal_component_get_categories_list (comp, &categories); - - for (l = categories; l; l = l->next) { - const char *name; - Category *c; - - name = l->data; - c = g_hash_table_lookup (priv->categories, name); - - if (add) { - /* Add the category to the set */ - if (c) - c->refcount++; - else { - /* See if it was in the removed categories */ - - c = g_hash_table_lookup (priv->removed_categories, name); - if (c) { - /* Move it to the set of live categories */ - g_assert (c->refcount == 0); - g_hash_table_remove (priv->removed_categories, c->name); - - c->refcount = 1; - g_hash_table_insert (priv->categories, c->name, c); - } else { - /* Create a new category */ - c = g_new (Category, 1); - c->name = g_strdup (name); - c->refcount = 1; - - g_hash_table_insert (priv->categories, c->name, c); - } - } - } else { - /* Remove the category from the set --- it *must* have existed */ - - g_assert (c != NULL); - g_assert (c->refcount > 0); - - c->refcount--; - - if (c->refcount == 0) { - g_hash_table_remove (priv->categories, c->name); - g_hash_table_insert (priv->removed_categories, c->name, c); - } - } - } - - cal_component_free_categories_list (categories); -} - /* Tries to add an icalcomponent to the file backend. We only store the objects * of the types we support; all others just remain in the toplevel component so * that we don't lose them. @@ -664,6 +500,7 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople CalBackendFilePrivate *priv; GList **list; const char *uid; + GSList *categories; priv = cbfile->priv; @@ -706,8 +543,9 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople } /* Update the set of categories */ - - update_categories_from_comp (cbfile, comp, TRUE); + cal_component_get_categories_list (comp, &categories); + cal_backend_ref_categories (CAL_BACKEND (cbfile), categories); + cal_component_free_categories_list (categories); } /* Removes a component from the backend's hash and lists. Does not perform @@ -721,6 +559,7 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp) icalcomponent *icalcomp; const char *uid; GList **list, *l; + GSList *categories; priv = cbfile->priv; @@ -762,8 +601,9 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp) g_list_free_1 (l); /* Update the set of categories */ - - update_categories_from_comp (cbfile, comp, FALSE); + cal_component_get_categories_list (comp, &categories); + cal_backend_unref_categories (CAL_BACKEND (cbfile), categories); + cal_component_free_categories_list (categories); g_object_unref (comp); } @@ -988,31 +828,13 @@ cal_backend_file_get_mode (CalBackend *backend) return CAL_MODE_LOCAL; } -static void -notify_mode (CalBackendFile *cbfile, - GNOME_Evolution_Calendar_Listener_SetModeStatus status, - GNOME_Evolution_Calendar_CalMode mode) -{ - CalBackendFilePrivate *priv; - GList *l; - - priv = cbfile->priv; - - for (l = CAL_BACKEND (cbfile)->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_mode (cal, status, mode); - } -} - /* Set_mode handler for the file backend */ static void cal_backend_file_set_mode (CalBackend *backend, CalMode mode) { - notify_mode (CAL_BACKEND_FILE (backend), - GNOME_Evolution_Calendar_Listener_MODE_NOT_SUPPORTED, - GNOME_Evolution_Calendar_MODE_LOCAL); + cal_backend_notify_mode (backend, + GNOME_Evolution_Calendar_Listener_MODE_NOT_SUPPORTED, + GNOME_Evolution_Calendar_MODE_LOCAL); } @@ -1043,31 +865,7 @@ cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type) return n; } -/* Get_object handler for the file backend */ -static char * -cal_backend_file_get_object (CalBackend *backend, const char *uid) -{ - CalBackendFile *cbfile; - CalBackendFilePrivate *priv; - CalComponent *comp; - - cbfile = CAL_BACKEND_FILE (backend); - priv = cbfile->priv; - - g_return_val_if_fail (uid != NULL, NULL); - - g_return_val_if_fail (priv->icalcomp != NULL, NULL); - g_assert (priv->comp_uid_hash != NULL); - - comp = lookup_component (cbfile, uid); - - if (!comp) - return NULL; - - return cal_component_get_as_string (comp); -} - -/* Get_object handler for the file backend */ +/* Get_object_component handler for the file backend */ static CalComponent * cal_backend_file_get_object_component (CalBackend *backend, const char *uid) { @@ -1085,7 +883,7 @@ cal_backend_file_get_object_component (CalBackend *backend, const char *uid) return lookup_component (cbfile, uid); } -/* Get_object handler for the file backend */ +/* Get_timezone_object handler for the file backend */ static char * cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid) { @@ -1687,88 +1485,6 @@ cal_backend_file_get_alarms_for_object (CalBackend *backend, const char *uid, return corba_alarms; } -/* Notifies a backend's clients that an object was updated */ -static void -notify_update (CalBackendFile *cbfile, const char *uid) -{ - CalBackendFilePrivate *priv; - GList *l; - - priv = cbfile->priv; - - cal_backend_obj_updated (CAL_BACKEND (cbfile), uid); - - for (l = CAL_BACKEND (cbfile)->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_update (cal, uid); - } -} - -/* Notifies a backend's clients that an object was removed */ -static void -notify_remove (CalBackendFile *cbfile, const char *uid) -{ - CalBackendFilePrivate *priv; - GList *l; - - priv = cbfile->priv; - - cal_backend_obj_removed (CAL_BACKEND (cbfile), uid); - - for (l = CAL_BACKEND (cbfile)->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_remove (cal, uid); - } -} - -/* Notifies a backend's clients that an error has occurred */ -static void -notify_error (CalBackendFile *cbfile, const char *message) -{ - CalBackendFilePrivate *priv; - GList *l; - - priv = cbfile->priv; - - for (l = CAL_BACKEND (cbfile)->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_error (cal, message); - } -} - -/* Used from g_hash_table_foreach_remove(); removes and frees a category */ -static gboolean -remove_category_cb (gpointer key, gpointer value, gpointer data) -{ - Category *c; - - c = value; - g_free (c->name); - g_free (c); - - return TRUE; -} - -/* Clears the table of removed categories */ -static void -clean_removed_categories (CalBackendFile *cbfile) -{ - CalBackendFilePrivate *priv; - - priv = cbfile->priv; - - g_hash_table_foreach_remove (priv->removed_categories, - remove_category_cb, - NULL); -} - - /* Creates a CalComponent for the given icalcomponent and adds it to our cache. Note that the icalcomponent is not added to the toplevel icalcomponent here. That needs to be done elsewhere. It returns the uid @@ -1823,7 +1539,6 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) CalBackendFilePrivate *priv; icalcomponent *toplevel_comp, *icalcomp = NULL; icalcomponent_kind kind; - int old_n_categories, new_n_categories; icalcomponent *subcomp; CalBackendResult retval = CAL_BACKEND_RESULT_SUCCESS; GList *comp_uid_list = NULL, *elem; @@ -1858,13 +1573,6 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) return CAL_BACKEND_RESULT_INVALID_OBJECT; } - /* The list of removed categories must be empty because we are about to - * start a new scanning process. - */ - g_assert (g_hash_table_size (priv->removed_categories) == 0); - - old_n_categories = g_hash_table_size (priv->categories); - /* Step throught the VEVENT/VTODOs being added, create CalComponents for them, and add them to our cache. */ subcomp = icalcomponent_get_first_component (toplevel_comp, @@ -1900,8 +1608,6 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) resolving any conflicting TZIDs. */ icalcomponent_merge_component (priv->icalcomp, toplevel_comp); - new_n_categories = g_hash_table_size (priv->categories); - mark_dirty (cbfile); /* Now emit notification signals for all of the added components. @@ -1909,17 +1615,11 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) stable state before emitting signals. */ for (elem = comp_uid_list; elem; elem = elem->next) { char *comp_uid = elem->data; - notify_update (cbfile, comp_uid); + cal_backend_notify_update (backend, comp_uid); g_free (comp_uid); } g_list_free (comp_uid_list); - if (old_n_categories != new_n_categories || - g_hash_table_size (priv->removed_categories) != 0) { - clean_removed_categories (cbfile); - notify_categories_changed (cbfile); - } - return retval; } @@ -1943,21 +1643,11 @@ cal_backend_file_remove_object (CalBackend *backend, const char *uid) if (!comp) return CAL_BACKEND_RESULT_NOT_FOUND; - /* The list of removed categories must be empty because we are about to - * start a new scanning process. - */ - g_assert (g_hash_table_size (priv->removed_categories) == 0); - remove_component (cbfile, comp); mark_dirty (cbfile); - notify_remove (cbfile, uid); - - if (g_hash_table_size (priv->removed_categories) != 0) { - clean_removed_categories (cbfile); - notify_categories_changed (cbfile); - } + cal_backend_notify_remove (backend, uid); return CAL_BACKEND_RESULT_SUCCESS; } diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index 876ef0d5ec..f797f3f67d 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -32,6 +32,29 @@ +/* A category that exists in some of the objects of the calendar */ +typedef struct { + /* Category name, also used as the key in the categories hash table */ + char *name; + + /* Number of objects that have this category */ + int refcount; +} CalBackendCategory; + +/* Private part of the CalBackend structure */ +struct _CalBackendPrivate { + /* List of Cal objects with their listeners */ + GList *clients; + + /* Hash table of live categories, temporary hash of + * added/removed categories, and idle handler for sending + * category_changed. + */ + GHashTable *categories; + GHashTable *changed_categories; + guint category_idle_id; +}; + /* Signal IDs */ enum { LAST_CLIENT_GONE, @@ -41,13 +64,20 @@ enum { OBJ_REMOVED, LAST_SIGNAL }; +static guint cal_backend_signals[LAST_SIGNAL]; static void cal_backend_class_init (CalBackendClass *class); +static void cal_backend_init (CalBackend *backend); +static void cal_backend_finalize (GObject *object); -static guint cal_backend_signals[LAST_SIGNAL]; +static char *get_object (CalBackend *backend, const char *uid); + +static void notify_categories_changed (CalBackend *backend); #define CLASS(backend) (CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (backend))) +static GObjectClass *parent_class; + /** @@ -73,7 +103,7 @@ cal_backend_get_type (void) NULL, NULL, sizeof (CalBackend), 0, - (GInstanceInitFunc) NULL + (GInstanceInitFunc) cal_backend_init, }; cal_backend_type = g_type_register_static (G_TYPE_OBJECT, "CalBackend", &info, 0); } @@ -87,6 +117,8 @@ cal_backend_class_init (CalBackendClass *class) { GObjectClass *object_class; + parent_class = (GObjectClass *) g_type_class_peek_parent (class); + object_class = (GObjectClass *) class; cal_backend_signals[LAST_CLIENT_GONE] = @@ -134,6 +166,8 @@ cal_backend_class_init (CalBackendClass *class) G_TYPE_NONE, 1, G_TYPE_STRING); + object_class->finalize = cal_backend_finalize; + class->last_client_gone = NULL; class->opened = NULL; class->obj_updated = NULL; @@ -148,7 +182,7 @@ cal_backend_class_init (CalBackendClass *class) class->get_mode = NULL; class->set_mode = NULL; class->get_n_objects = NULL; - class->get_object = NULL; + class->get_object = get_object; class->get_object_component = NULL; class->get_timezone_object = NULL; class->get_uids = NULL; @@ -162,6 +196,51 @@ cal_backend_class_init (CalBackendClass *class) class->send_object = NULL; } +/* Object initialization func for the calendar backend */ +void +cal_backend_init (CalBackend *backend) +{ + CalBackendPrivate *priv; + + priv = g_new0 (CalBackendPrivate, 1); + backend->priv = priv; + + priv->categories = g_hash_table_new (g_str_hash, g_str_equal); + priv->changed_categories = g_hash_table_new (g_str_hash, g_str_equal); +} + +/* Used from g_hash_table_foreach(), frees a CalBackendCategory structure */ +static void +free_category_cb (gpointer key, gpointer value, gpointer data) +{ + CalBackendCategory *c = value; + + g_free (c->name); + g_free (c); +} + +void +cal_backend_finalize (GObject *object) +{ + CalBackend *backend = (CalBackend *)object; + CalBackendPrivate *priv; + + priv = backend->priv; + + g_assert (priv->clients == NULL); + + g_hash_table_foreach (priv->categories, free_category_cb, NULL); + g_hash_table_destroy (priv->categories); + + g_hash_table_foreach (priv->changed_categories, free_category_cb, NULL); + g_hash_table_destroy (priv->changed_categories); + + if (priv->category_idle_id) + g_source_remove (priv->category_idle_id); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + /** @@ -204,37 +283,17 @@ cal_backend_get_email_address (CalBackend *backend) /* Callback used when a Cal is destroyed */ static void -cal_destroy_cb (GObject *object, gpointer data) +cal_destroy_cb (gpointer data, GObject *where_cal_was) { - Cal *cal; - Cal *lcal; - CalBackend *backend; - GList *l; - - cal = CAL (object); + CalBackend *backend = CAL_BACKEND (data); + CalBackendPrivate *priv = backend->priv; - backend = CAL_BACKEND (data); - - /* Find the cal in the list of clients */ - - for (l = backend->clients; l; l = l->next) { - lcal = CAL (l->data); - - if (lcal == cal) - break; - } - - g_assert (l != NULL); - - /* Disconnect */ - - backend->clients = g_list_remove_link (backend->clients, l); - g_list_free_1 (l); + priv->clients = g_list_remove (priv->clients, where_cal_was); /* When all clients go away, notify the parent factory about it so that * it may decide whether to kill the backend or not. */ - if (!backend->clients) + if (!priv->clients) cal_backend_last_client_gone (backend); } @@ -249,22 +308,25 @@ cal_destroy_cb (GObject *object, gpointer data) void cal_backend_add_cal (CalBackend *backend, Cal *cal) { + CalBackendPrivate *priv = backend->priv; + g_return_if_fail (backend != NULL); g_return_if_fail (IS_CAL_BACKEND (backend)); g_return_if_fail (IS_CAL (cal)); - /* we do not keep a reference to the Cal since the Calendar - * user agent owns it */ - g_signal_connect (G_OBJECT (cal), "destroy", - G_CALLBACK (cal_destroy_cb), - backend); + /* we do not keep a (strong) reference to the Cal since the + * Calendar user agent owns it */ + g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend); - backend->clients = g_list_prepend (backend->clients, cal); + priv->clients = g_list_prepend (priv->clients, cal); + + /* Tell the new client about the list of categories. + * (Ends up telling all the other clients too, but *shrug*.) + */ + notify_categories_changed (backend); /* notify backend that a new Cal has been added */ - g_signal_emit (G_OBJECT (backend), - cal_backend_signals[CAL_ADDED], - 0, cal); + g_signal_emit (backend, cal_backend_signals[CAL_ADDED], 0, cal); } /** @@ -426,6 +488,19 @@ cal_backend_get_n_objects (CalBackend *backend, CalObjType type) return (* CLASS (backend)->get_n_objects) (backend, type); } +/* Default cal_backend_get_object implementation */ +static char * +get_object (CalBackend *backend, const char *uid) +{ + CalComponent *comp; + + comp = cal_backend_get_object_component (backend, uid); + if (!comp) + return NULL; + + return cal_component_get_as_string (comp); +} + /** * cal_backend_get_object: * @backend: A calendar backend. @@ -902,3 +977,227 @@ cal_backend_set_default_timezone (CalBackend *backend, const char *tzid) return (* CLASS (backend)->set_default_timezone) (backend, tzid); } + +/** + * cal_backend_notify_mode: + * @backend: A calendar backend. + * @status: Status of the mode set + * @mode: the current mode + * + * Notifies each of the backend's listeners about the results of a + * setMode call. + **/ +void +cal_backend_notify_mode (CalBackend *backend, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + for (l = priv->clients; l; l = l->next) + cal_notify_mode (l->data, status, mode); +} + +/** + * cal_backend_notify_update: + * @backend: A calendar backend. + * @uid: UID of object that was updated. + * + * Notifies each of the backend's listeners about an update to a + * calendar object. + **/ +void +cal_backend_notify_update (CalBackend *backend, const char *uid) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + cal_backend_obj_updated (backend, uid); + for (l = priv->clients; l; l = l->next) + cal_notify_update (l->data, uid); +} + +/** + * cal_backend_notify_remove: + * @backend: A calendar backend. + * @uid: UID of object that was removed. + * + * Notifies each of the backend's listeners about a calendar object + * that was removed. + **/ +void +cal_backend_notify_remove (CalBackend *backend, const char *uid) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + cal_backend_obj_removed (backend, uid); + for (l = priv->clients; l; l = l->next) + cal_notify_remove (l->data, uid); +} + +/** + * cal_backend_notify_error: + * @backend: A calendar backend. + * @message: Error message + * + * Notifies each of the backend's listeners about an error + **/ +void +cal_backend_notify_error (CalBackend *backend, const char *message) +{ + CalBackendPrivate *priv = backend->priv; + GList *l; + + for (l = priv->clients; l; l = l->next) + cal_notify_error (l->data, message); +} + +static void +add_category_cb (gpointer name, gpointer category, gpointer data) +{ + GNOME_Evolution_Calendar_StringSeq *seq = data; + + seq->_buffer[seq->_length++] = CORBA_string_dup (name); +} + +static void +notify_categories_changed (CalBackend *backend) +{ + CalBackendPrivate *priv = backend->priv; + GNOME_Evolution_Calendar_StringSeq *seq; + GList *l; + + /* Build the sequence of category names */ + seq = GNOME_Evolution_Calendar_StringSeq__alloc (); + seq->_length = 0; + seq->_maximum = g_hash_table_size (priv->categories); + seq->_buffer = CORBA_sequence_CORBA_string_allocbuf (seq->_maximum); + CORBA_sequence_set_release (seq, TRUE); + + g_hash_table_foreach (priv->categories, add_category_cb, seq); + + /* Notify the clients */ + for (l = priv->clients; l; l = l->next) + cal_notify_categories_changed (l->data, seq); + + CORBA_free (seq); +} + +static gboolean +prune_changed_categories (gpointer key, gpointer value, gpointer data) +{ + CalBackendCategory *category = value; + + if (!category->refcount) { + g_free (category->name); + g_free (category); + } + return TRUE; +} + +static gboolean +idle_notify_categories_changed (gpointer data) +{ + CalBackend *backend = CAL_BACKEND (data); + CalBackendPrivate *priv = backend->priv; + + if (g_hash_table_size (priv->changed_categories)) { + notify_categories_changed (backend); + g_hash_table_foreach_remove (priv->changed_categories, prune_changed_categories, NULL); + } + return FALSE; +} + +/** + * cal_backend_ref_categories: + * @backend: A calendar backend + * @categories: a list of categories + * + * Adds 1 to the refcount of each of the named categories. If any of + * the categories are new, clients will be notified of the updated + * category list at idle time. + **/ +void +cal_backend_ref_categories (CalBackend *backend, GSList *categories) +{ + CalBackendPrivate *priv; + CalBackendCategory *c; + const char *name; + + priv = backend->priv; + + while (categories) { + name = categories->data; + c = g_hash_table_lookup (priv->categories, name); + + if (c) + c->refcount++; + else { + /* See if it was recently removed */ + + c = g_hash_table_lookup (priv->changed_categories, name); + if (c && c->refcount == 0) { + /* Move it back to the set of live categories */ + g_hash_table_remove (priv->changed_categories, c->name); + + c->refcount = 1; + g_hash_table_insert (priv->categories, c->name, c); + } else { + /* Create a new category */ + c = g_new (CalBackendCategory, 1); + c->name = g_strdup (name); + c->refcount = 1; + g_hash_table_insert (priv->categories, c->name, c); + g_hash_table_insert (priv->changed_categories, c->name, c); + } + } + + categories = categories->next; + } + + if (g_hash_table_size (priv->changed_categories) && + !priv->category_idle_id) + priv->category_idle_id = g_idle_add (idle_notify_categories_changed, backend); +} + +/** + * cal_backend_unref_categories: + * @backend: A calendar backend + * @categories: a list of categories + * + * Subtracts 1 from the refcount of each of the named categories. If + * any of the refcounts go down to 0, clients will be notified of the + * updated category list at idle time. + **/ +void +cal_backend_unref_categories (CalBackend *backend, GSList *categories) +{ + CalBackendPrivate *priv; + CalBackendCategory *c; + const char *name; + + priv = backend->priv; + + while (categories) { + name = categories->data; + c = g_hash_table_lookup (priv->categories, name); + + if (c) { + g_assert (c != NULL); + g_assert (c->refcount > 0); + + c->refcount--; + + if (c->refcount == 0) { + g_hash_table_remove (priv->categories, c->name); + g_hash_table_insert (priv->changed_categories, c->name, c); + } + } + } + + if (g_hash_table_size (priv->changed_categories) && + !priv->category_idle_id) + priv->category_idle_id = g_idle_add (idle_notify_categories_changed, backend); +} diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h index b0790e8e73..b20e04bdb6 100644 --- a/calendar/pcs/cal-backend.h +++ b/calendar/pcs/cal-backend.h @@ -73,9 +73,12 @@ typedef enum { CAL_BACKEND_GET_ALARMS_INVALID_RANGE } CalBackendGetAlarmsForObjectResult; +typedef struct _CalBackendPrivate CalBackendPrivate; + struct _CalBackend { GObject object; - GList *clients; + + CalBackendPrivate *priv; }; struct _CalBackendClass { @@ -213,6 +216,15 @@ void cal_backend_opened (CalBackend *backend, CalBackendOpenStatus status); void cal_backend_obj_updated (CalBackend *backend, const char *uid); void cal_backend_obj_removed (CalBackend *backend, const char *uid); +void cal_backend_notify_mode (CalBackend *backend, + GNOME_Evolution_Calendar_Listener_SetModeStatus status, + GNOME_Evolution_Calendar_CalMode mode); +void cal_backend_notify_update (CalBackend *backend, const char *uid); +void cal_backend_notify_remove (CalBackend *backend, const char *uid); +void cal_backend_notify_error (CalBackend *backend, const char *message); +void cal_backend_ref_categories (CalBackend *backend, GSList *categories); +void cal_backend_unref_categories (CalBackend *backend, GSList *categories); + G_END_DECLS |