aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/pcs/cal-backend-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/pcs/cal-backend-file.c')
-rw-r--r--calendar/pcs/cal-backend-file.c539
1 files changed, 442 insertions, 97 deletions
diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c
index f73ab66874..ea50dcc7df 100644
--- a/calendar/pcs/cal-backend-file.c
+++ b/calendar/pcs/cal-backend-file.c
@@ -21,7 +21,7 @@
*/
#include <config.h>
-#include <string.h>
+#include <gtk/gtksignal.h>
#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-moniker-util.h>
#include <libgnomevfs/gnome-vfs.h>
@@ -33,11 +33,23 @@
+/* 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;
@@ -57,8 +69,12 @@ 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;
+ Bonobo_ConfigDatabase db;
/* Idle handler for saving the calendar when it is dirty */
guint idle_id;
@@ -71,9 +87,8 @@ struct _CalBackendFilePrivate {
static void cal_backend_file_class_init (CalBackendFileClass *class);
-static void cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class);
-static void cal_backend_file_dispose (GObject *object);
-static void cal_backend_file_finalize (GObject *object);
+static void cal_backend_file_init (CalBackendFile *cbfile);
+static void cal_backend_file_destroy (GtkObject *object);
static const char *cal_backend_file_get_uri (CalBackend *backend);
static gboolean cal_backend_file_is_read_only (CalBackend *backend);
@@ -90,6 +105,7 @@ 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);
@@ -120,6 +136,8 @@ 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 CalBackendClass *parent_class;
@@ -133,24 +151,24 @@ static CalBackendClass *parent_class;
*
* Return value: The type ID of the #CalBackendFile class.
**/
-GType
+GtkType
cal_backend_file_get_type (void)
{
- static GType cal_backend_file_type = 0;
+ static GtkType cal_backend_file_type = 0;
if (!cal_backend_file_type) {
- static GTypeInfo info = {
- sizeof (CalBackendFileClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) cal_backend_file_class_init,
- NULL, NULL,
- sizeof (CalBackendFile),
- 0,
- (GInstanceInitFunc) cal_backend_file_init
- };
- cal_backend_file_type = g_type_register_static (CAL_BACKEND_TYPE,
- "CalBackendFile", &info, 0);
+ static const GtkTypeInfo cal_backend_file_info = {
+ "CalBackendFile",
+ sizeof (CalBackendFile),
+ sizeof (CalBackendFileClass),
+ (GtkClassInitFunc) cal_backend_file_class_init,
+ (GtkObjectInitFunc) cal_backend_file_init,
+ NULL, /* reserved_1 */
+ NULL, /* reserved_2 */
+ (GtkClassInitFunc) NULL
+ };
+
+ cal_backend_file_type = gtk_type_unique (CAL_BACKEND_TYPE, &cal_backend_file_info);
}
return cal_backend_file_type;
@@ -160,16 +178,15 @@ cal_backend_file_get_type (void)
static void
cal_backend_file_class_init (CalBackendFileClass *class)
{
- GObjectClass *object_class;
+ GtkObjectClass *object_class;
CalBackendClass *backend_class;
- object_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
backend_class = (CalBackendClass *) class;
- parent_class = (CalBackendClass *) g_type_class_peek_parent (class);
+ parent_class = gtk_type_class (CAL_BACKEND_TYPE);
- object_class->dispose = cal_backend_file_dispose;
- object_class->finalize = cal_backend_file_finalize;
+ object_class->destroy = cal_backend_file_destroy;
backend_class->get_uri = cal_backend_file_get_uri;
backend_class->is_read_only = cal_backend_file_is_read_only;
@@ -180,6 +197,7 @@ 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;
@@ -197,9 +215,33 @@ cal_backend_file_class_init (CalBackendFileClass *class)
backend_class->set_default_timezone = cal_backend_file_set_default_timezone;
}
+static Bonobo_ConfigDatabase
+load_db (void)
+{
+ Bonobo_ConfigDatabase db = CORBA_OBJECT_NIL;
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+
+ db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev);
+
+ if (BONOBO_EX (&ev))
+ db = CORBA_OBJECT_NIL;
+
+ CORBA_exception_free (&ev);
+
+ return db;
+}
+
+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)
+cal_backend_file_init (CalBackendFile *cbfile)
{
CalBackendFilePrivate *priv;
@@ -213,10 +255,16 @@ 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 ();
+ priv->db = load_db ();
+
+ gtk_signal_connect (GTK_OBJECT (cbfile), "cal_added",
+ GTK_SIGNAL_FUNC (cal_added_cb), NULL);
}
/* g_hash_table_foreach() callback to destroy a CalComponent */
@@ -226,7 +274,7 @@ free_cal_component (gpointer key, gpointer value, gpointer data)
CalComponent *comp;
comp = CAL_COMPONENT (value);
- g_object_unref (comp);
+ gtk_object_unref (GTK_OBJECT (comp));
}
/* Saves the calendar data */
@@ -296,20 +344,38 @@ save (CalBackendFile *cbfile)
return;
error:
- cal_backend_notify_error (CAL_BACKEND (cbfile), gnome_vfs_result_to_string (result));
+ notify_error (cbfile, gnome_vfs_result_to_string (result));
return;
}
-/* Dispose handler for the file backend */
+/* 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_dispose (GObject *object)
+cal_backend_file_destroy (GtkObject *object)
{
CalBackendFile *cbfile;
CalBackendFilePrivate *priv;
+ GList *clients;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (IS_CAL_BACKEND_FILE (object));
cbfile = CAL_BACKEND_FILE (object);
priv = cbfile->priv;
+ clients = CAL_BACKEND (cbfile)->clients;
+ g_assert (clients == NULL);
+
/* Save if necessary */
if (priv->idle_id != 0) {
@@ -318,6 +384,13 @@ cal_backend_file_dispose (GObject *object)
priv->idle_id = 0;
}
+ /* Clean up */
+
+ if (priv->uri) {
+ g_free (priv->uri);
+ priv->uri = NULL;
+ }
+
if (priv->comp_uid_hash) {
g_hash_table_foreach (priv->comp_uid_hash,
free_cal_component, NULL);
@@ -332,46 +405,27 @@ cal_backend_file_dispose (GObject *object)
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;
+
+ g_hash_table_foreach (priv->removed_categories, free_category_cb, NULL);
+ g_hash_table_destroy (priv->removed_categories);
+ priv->removed_categories = NULL;
+
if (priv->icalcomp) {
icalcomponent_free (priv->icalcomp);
priv->icalcomp = NULL;
}
- if (priv->config_listener) {
- g_object_unref (priv->config_listener);
- priv->config_listener = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-/* Finalize handler for the file backend */
-static void
-cal_backend_file_finalize (GObject *object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- GList *clients;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (IS_CAL_BACKEND_FILE (object));
-
- cbfile = CAL_BACKEND_FILE (object);
- priv = cbfile->priv;
-
- /* Clean up */
-
- if (priv->uri) {
- g_free (priv->uri);
- priv->uri = NULL;
- }
-
+ bonobo_object_release_unref (priv->db, NULL);
+ priv->db = CORBA_OBJECT_NIL;
+
g_free (priv);
cbfile->priv = NULL;
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
@@ -428,6 +482,53 @@ 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)
@@ -490,6 +591,68 @@ 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.
@@ -500,7 +663,6 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople
CalBackendFilePrivate *priv;
GList **list;
const char *uid;
- GSList *categories;
priv = cbfile->priv;
@@ -543,9 +705,8 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople
}
/* Update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_ref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
+
+ update_categories_from_comp (cbfile, comp, TRUE);
}
/* Removes a component from the backend's hash and lists. Does not perform
@@ -559,7 +720,6 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp)
icalcomponent *icalcomp;
const char *uid;
GList **list, *l;
- GSList *categories;
priv = cbfile->priv;
@@ -601,11 +761,10 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp)
g_list_free_1 (l);
/* Update the set of categories */
- 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);
+ update_categories_from_comp (cbfile, comp, FALSE);
+
+ gtk_object_unref (GTK_OBJECT (comp));
}
/* Scans the toplevel VCALENDAR component and stores the objects it finds */
@@ -828,13 +987,31 @@ 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)
{
- cal_backend_notify_mode (backend,
- GNOME_Evolution_Calendar_Listener_MODE_NOT_SUPPORTED,
- GNOME_Evolution_Calendar_MODE_LOCAL);
+ notify_mode (CAL_BACKEND_FILE (backend),
+ GNOME_Evolution_Calendar_Listener_MODE_NOT_SUPPORTED,
+ GNOME_Evolution_Calendar_MODE_LOCAL);
}
@@ -865,7 +1042,31 @@ cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type)
return n;
}
-/* Get_object_component handler for the file backend */
+/* 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 */
static CalComponent *
cal_backend_file_get_object_component (CalBackend *backend, const char *uid)
{
@@ -883,7 +1084,7 @@ cal_backend_file_get_object_component (CalBackend *backend, const char *uid)
return lookup_component (cbfile, uid);
}
-/* Get_timezone_object handler for the file backend */
+/* Get_object handler for the file backend */
static char *
cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid)
{
@@ -1206,7 +1407,7 @@ cal_backend_file_get_free_busy (CalBackend *backend, GList *users, time_t start,
g_return_val_if_fail (start <= end, NULL);
if (users == NULL) {
- if (cal_backend_mail_account_get_default (priv->config_listener, &address, &name)) {
+ if (cal_backend_mail_account_get_default (priv->db, &address, &name)) {
vfb = create_user_free_busy (cbfile, address, name, start, end);
calobj = icalcomponent_as_ical_string (vfb);
obj_list = g_list_append (obj_list, g_strdup (calobj));
@@ -1217,7 +1418,7 @@ cal_backend_file_get_free_busy (CalBackend *backend, GList *users, time_t start,
} else {
for (l = users; l != NULL; l = l->next ) {
address = l->data;
- if (cal_backend_mail_account_is_valid (priv->config_listener, address, &name)) {
+ if (cal_backend_mail_account_is_valid (priv->db, address, &name)) {
vfb = create_user_free_busy (cbfile, address, name, start, end);
calobj = icalcomponent_as_ical_string (vfb);
obj_list = g_list_append (obj_list, g_strdup (calobj));
@@ -1265,7 +1466,7 @@ cal_backend_file_compute_changes_foreach_key (const char *key, gpointer data)
be_data->change_ids = g_list_prepend (be_data->change_ids, g_strdup (key));
g_free (calobj);
- g_object_unref (comp);
+ gtk_object_unref (GTK_OBJECT (comp));
}
}
@@ -1485,6 +1686,88 @@ 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
@@ -1501,14 +1784,14 @@ cal_backend_file_update_object (CalBackendFile *cbfile,
/* Create a CalComponent wrapper for the icalcomponent. */
comp = cal_component_new ();
if (!cal_component_set_icalcomponent (comp, icalcomp)) {
- g_object_unref (comp);
+ gtk_object_unref (GTK_OBJECT (comp));
return NULL;
}
/* Get the UID, and check it isn't empty. */
cal_component_get_uid (comp, &comp_uid);
if (!comp_uid || !comp_uid[0]) {
- g_object_unref (comp);
+ gtk_object_unref (GTK_OBJECT (comp));
return NULL;
}
@@ -1529,7 +1812,31 @@ cal_backend_file_update_object (CalBackendFile *cbfile,
return comp_uid;
}
+static const char*
+cal_backend_file_cancel_object (CalBackendFile *cbfile,
+ icalcomponent *icalcomp)
+{
+ CalComponent *old_comp;
+ icalproperty *uid;
+ const char *comp_uid;
+
+ /* Get the UID, and check it isn't empty. */
+ uid = icalcomponent_get_first_property (icalcomp, ICAL_UID_PROPERTY);
+ if (!uid)
+ return NULL;
+ comp_uid = icalproperty_get_uid (uid);
+ if (!comp_uid || !comp_uid[0])
+ return NULL;
+
+ /* Find the old version of the component. */
+ old_comp = lookup_component (cbfile, comp_uid);
+ if (!old_comp)
+ return NULL;
+ /* And remove it */
+ remove_component (cbfile, old_comp);
+ return comp_uid;
+}
/* Update_objects handler for the file backend. */
static CalBackendResult
@@ -1539,9 +1846,11 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
CalBackendFilePrivate *priv;
icalcomponent *toplevel_comp, *icalcomp = NULL;
icalcomponent_kind kind;
+ icalproperty_method method;
+ int old_n_categories, new_n_categories;
icalcomponent *subcomp;
CalBackendResult retval = CAL_BACKEND_RESULT_SUCCESS;
- GList *comp_uid_list = NULL, *elem;
+ GList *updated_uids = NULL, *removed_uids = NULL, *elem;
cbfile = CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
@@ -1573,6 +1882,15 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
return CAL_BACKEND_RESULT_INVALID_OBJECT;
}
+ method = icalcomponent_get_method (toplevel_comp);
+
+ /* 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,
@@ -1586,18 +1904,20 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
|| child_kind == ICAL_VJOURNAL_COMPONENT) {
const char *comp_uid;
- comp_uid = cal_backend_file_update_object (cbfile,
- subcomp);
- if (comp_uid) {
- /* We add a copy of the UID to a list, so we
- can emit notification signals later. We do
- a g_strdup() in case any of the components
- get removed while we are emitting
- notification signals. */
- comp_uid_list = g_list_prepend (comp_uid_list,
- g_strdup (comp_uid));
+ if (method == ICAL_METHOD_CANCEL) {
+ comp_uid = cal_backend_file_cancel_object (cbfile, subcomp);
+ if (comp_uid) {
+ removed_uids = g_list_prepend (removed_uids,
+ g_strdup (comp_uid));
+ } else
+ retval = CAL_BACKEND_RESULT_NOT_FOUND;
} else {
- retval = CAL_BACKEND_RESULT_INVALID_OBJECT;
+ comp_uid = cal_backend_file_update_object (cbfile, subcomp);
+ if (comp_uid) {
+ updated_uids = g_list_prepend (updated_uids,
+ g_strdup (comp_uid));
+ } else
+ retval = CAL_BACKEND_RESULT_INVALID_OBJECT;
}
}
subcomp = icalcomponent_get_next_component (toplevel_comp,
@@ -1608,17 +1928,32 @@ 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.
We do this after adding them all to make sure the calendar is in a
stable state before emitting signals. */
- for (elem = comp_uid_list; elem; elem = elem->next) {
+ for (elem = updated_uids; elem; elem = elem->next) {
+ char *comp_uid = elem->data;
+ notify_update (cbfile, comp_uid);
+ g_free (comp_uid);
+ }
+ g_list_free (updated_uids);
+
+ for (elem = removed_uids; elem; elem = elem->next) {
char *comp_uid = elem->data;
- cal_backend_notify_update (backend, comp_uid);
+ notify_remove (cbfile, comp_uid);
g_free (comp_uid);
}
- g_list_free (comp_uid_list);
+ g_list_free (removed_uids);
+
+ 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;
}
@@ -1643,11 +1978,21 @@ 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);
- cal_backend_notify_remove (backend, uid);
+ notify_remove (cbfile, uid);
+
+ if (g_hash_table_size (priv->removed_categories) != 0) {
+ clean_removed_categories (cbfile);
+ notify_categories_changed (cbfile);
+ }
return CAL_BACKEND_RESULT_SUCCESS;
}