From 96d24f1297eaa5a6333b9fcfdf35420d273703af Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 1 Aug 2001 03:41:51 +0000 Subject: The Wombat now keeps track of which categories are present in the objects 2001-07-31 Federico Mena Quintero The Wombat now keeps track of which categories are present in the objects of a calendar. It will notify the clients of changes in this set. This is to make the category drop-down menus in the calendar/tasks views be always up to date. * idl/evolution-calendar.idl (Listener): Added a notifyCategoriesChanged() method. The Wombat now keeps track of the categories within a calendar. * cal-client/cal-listener.[ch]: Switched it to use BonoboXObject. Also added the notifyCategoriesChanged implementation. * cal-client/cal-client.[ch]: Added a "categories_changed" signal. * pcs/cal-backend-file.c: Maintain a list of the live categories. (update_categories_from_comp): New function to maintain the set of live categories. (add_component): Update the set of categories. (remove_component): Likewise. (open_cal): Notify about changes in the set of categories. (create_cal): Likewise. (cal_backend_file_update_objects): Likewise. (cal_backend_file_remove_object): Likewise. (notify_categories_changed): New function to notify the clients about the current set of categories. * pcs/cal.c (cal_notify_categories_changed): New function. svn path=/trunk/; revision=11536 --- calendar/pcs/cal-backend-file.c | 147 +++++++++++++++++++++++++++++++++++++++- calendar/pcs/cal.c | 31 +++++++++ calendar/pcs/cal.h | 2 + 3 files changed, 179 insertions(+), 1 deletion(-) (limited to 'calendar/pcs') diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index 219683e4f9..0c87760204 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -29,6 +29,15 @@ +/* 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 */ @@ -56,6 +65,9 @@ struct _CalBackendFilePrivate { GList *todos; GList *journals; + /* Hash table of live categories */ + GHashTable *categories; + /* Idle handler for saving the calendar when it is dirty */ guint idle_id; }; @@ -181,6 +193,8 @@ cal_backend_file_init (CalBackendFile *cbfile) priv->events = NULL; priv->todos = NULL; priv->journals = NULL; + + priv->categories = g_hash_table_new (g_str_hash, g_str_equal); } /* g_hash_table_foreach() callback to destroy a CalComponent */ @@ -247,6 +261,17 @@ save (CalBackendFile *cbfile) 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); +} + /* Destroy handler for the file backend */ static void cal_backend_file_destroy (GtkObject *object) @@ -287,11 +312,14 @@ cal_backend_file_destroy (GtkObject *object) g_list_free (priv->events); g_list_free (priv->todos); g_list_free (priv->journals); - priv->events = NULL; priv->todos = NULL; priv->journals = NULL; + g_hash_table_foreach (priv->categories, free_category_cb, NULL); + g_hash_table_destroy (priv->categories); + priv->categories = NULL; + if (priv->icalcomp) { icalcomponent_free (priv->icalcomp); priv->icalcomp = NULL; @@ -465,6 +493,56 @@ 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 { + 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_free (c->name); + g_free (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. @@ -515,6 +593,10 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople icalcomponent_add_component (priv->icalcomp, icalcomp); } + + /* Update the set of categories */ + + update_categories_from_comp (cbfile, comp, TRUE); } /* Removes a component from the backend's hash and lists. Does not perform @@ -568,6 +650,10 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp) *list = g_list_remove_link (*list, l); g_list_free_1 (l); + /* Update the set of categories */ + + update_categories_from_comp (cbfile, comp, FALSE); + gtk_object_unref (GTK_OBJECT (comp)); } @@ -607,6 +693,53 @@ scan_vcalendar (CalBackendFile *cbfile) } } +/* 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 = priv->clients; l; l = l->next) { + Cal *cal; + + cal = CAL (l->data); + cal_notify_categories_changed (cal, seq); + } + + CORBA_free (seq); +} + /* Callback used from icalparser_parse() */ static char * get_line_fn (char *s, size_t size, void *data) @@ -671,6 +804,8 @@ open_cal (CalBackendFile *cbfile, GnomeVFSURI *uri, FILE *file) gnome_vfs_uri_ref (uri); priv->uri = uri; + notify_categories_changed (cbfile); + return CAL_BACKEND_OPEN_SUCCESS; } @@ -692,6 +827,8 @@ create_cal (CalBackendFile *cbfile, GnomeVFSURI *uri) mark_dirty (cbfile); + notify_categories_changed (cbfile); + return CAL_BACKEND_OPEN_SUCCESS; } @@ -1786,6 +1923,7 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) /* FIXME: do the notification asynchronously */ notify_update (cbfile, comp_uid); + notify_categories_changed (cbfile); return TRUE; } @@ -1797,6 +1935,7 @@ cal_backend_file_remove_object (CalBackend *backend, const char *uid) CalBackendFile *cbfile; CalBackendFilePrivate *priv; CalComponent *comp; + int old_n_categories, new_n_categories; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; @@ -1809,12 +1948,18 @@ cal_backend_file_remove_object (CalBackend *backend, const char *uid) if (!comp) return FALSE; + old_n_categories = g_hash_table_size (priv->categories); remove_component (cbfile, comp); + new_n_categories = g_hash_table_size (priv->categories); + mark_dirty (cbfile); /* FIXME: do the notification asynchronously */ notify_remove (cbfile, uid); + if (old_n_categories != new_n_categories) + notify_categories_changed (cbfile); + return TRUE; } diff --git a/calendar/pcs/cal.c b/calendar/pcs/cal.c index f89d5c820f..cb92f391b5 100644 --- a/calendar/pcs/cal.c +++ b/calendar/pcs/cal.c @@ -673,6 +673,37 @@ cal_notify_remove (Cal *cal, const char *uid) CORBA_exception_free (&ev); } +/** + * cal_notify_categories_changed: + * @cal: A calendar client interface. + * @categories: List of categories. + * + * Notifies a listener attached to a calendar client interface object about the + * current set of categories in a calendar backend. + **/ +void +cal_notify_categories_changed (Cal *cal, GNOME_Evolution_Calendar_StringSeq *categories) +{ + CalPrivate *priv; + CORBA_Environment ev; + + g_return_if_fail (cal != NULL); + g_return_if_fail (IS_CAL (cal)); + g_return_if_fail (categories != NULL); + + priv = cal->priv; + g_return_if_fail (priv->listener != CORBA_OBJECT_NIL); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_Listener_notifyCategoriesChanged (priv->listener, categories, &ev); + + if (ev._major != CORBA_NO_EXCEPTION) + g_message ("cal_notify_categories_changed(): Could not notify the listener " + "about the current set of categories"); + + CORBA_exception_free (&ev); +} + /** * cal_get_password: * @cal: A calendar client interface. diff --git a/calendar/pcs/cal.h b/calendar/pcs/cal.h index 35e870739c..6797b5df25 100644 --- a/calendar/pcs/cal.h +++ b/calendar/pcs/cal.h @@ -65,6 +65,8 @@ Cal *cal_new (CalBackend *backend, GNOME_Evolution_Calendar_Listener listener); void cal_notify_update (Cal *cal, const char *uid); void cal_notify_remove (Cal *cal, const char *uid); +void cal_notify_categories_changed (Cal *cal, GNOME_Evolution_Calendar_StringSeq *categories); + char *cal_get_password (Cal *cal, const char *prompt, const char *key); void cal_forget_password (Cal *cal, const char *key); -- cgit