diff options
Diffstat (limited to 'calendar/pcs/cal-backend-file.c')
-rw-r--r-- | calendar/pcs/cal-backend-file.c | 147 |
1 files changed, 146 insertions, 1 deletions
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; } |