[evolution-data-server/gnome-3-0] calendar file backend: support removing parent event with CALOBJ_MOD_THIS
- From: Patrick Ohly <pohly src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/gnome-3-0] calendar file backend: support removing parent event with CALOBJ_MOD_THIS
- Date: Tue, 7 Jun 2011 09:49:38 +0000 (UTC)
commit 9867e52e7372a830ec4056adb7ea6df848a83481
Author: Patrick Ohly <patrick ohly intel com>
Date: Wed May 11 16:59:51 2011 +0200
calendar file backend: support removing parent event with CALOBJ_MOD_THIS
It was possible to create a meeting series with just a detached event
(RECURRENCE-ID set) by importing a meeting invitation for that single
recurrence. It was not possible to arrive at that same state after
adding the parent event (the one with the RRULE) because
e_cal_remove_object_with_mod() removed all instances for
CALOBJ_MOD_THIS and empty rid.
This contradicts the intended semantic of e_cal_remove_object_with_mod():
"By using a combination of the @uid, @rid and @mod
arguments, you can remove specific instances. If what you want
is to remove all instances, use e_cal_remove_object instead."
This patch implements the desired semantic:
- e_cal_backend_file_remove_object(CALOBJ_MOD_THIS) now always
calls remove_instance().
- remove_instance() was extended to also work for the parent
event.
- That call removes the complete object if nothing is left
after removing the instance. This case must be handled by
the caller. The return value is the original object (if
it still exists) and NULL if not.
- Because the uid pointer into the object may become invalid
as part of the removal, a more permanent pointer has to
be provided by the caller.
(cherry picked from commit ba88feadc788ab9a2961afd6a3575d7079928c32)
calendar/backends/file/e-cal-backend-file.c | 134 ++++++++++++++++++---------
1 files changed, 88 insertions(+), 46 deletions(-)
---
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index 7aff3f6..6925bc5 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -2623,47 +2623,94 @@ e_cal_backend_file_modify_object (ECalBackendSync *backend, EDataCal *cal, const
g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
}
-static void
-remove_instance (ECalBackendFile *cbfile, ECalBackendFileObject *obj_data, const gchar *rid)
+/**
+ * Remove one and only one instance. The object may be empty
+ * afterwards, in which case it will be removed completely.
+ *
+ * @uid pointer to UID which must remain valid even if the object gets
+ * removed
+ * @rid NULL, "", or non-empty string when manipulating a specific recurrence;
+ * also must remain valid
+ * @return modified object or NULL if it got removed
+ */
+static ECalBackendFileObject *
+remove_instance (ECalBackendFile *cbfile, ECalBackendFileObject *obj_data, const gchar *uid, const gchar *rid)
{
gchar *hash_rid;
ECalComponent *comp;
struct icaltimetype current;
- if (!rid || !*rid)
- return;
+ /* only check for non-NULL below, empty string is detected here */
+ if (rid && !*rid)
+ rid = NULL;
- if (g_hash_table_lookup_extended (obj_data->recurrences, rid, (gpointer *)&hash_rid, (gpointer *)&comp)) {
- /* remove the component from our data */
+ if (rid) {
+ /* remove recurrence */
+ if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
+ (gpointer *)&hash_rid, (gpointer *)&comp)) {
+ /* remove the component from our data */
+ icalcomponent_remove_component (cbfile->priv->icalcomp,
+ e_cal_component_get_icalcomponent (comp));
+ cbfile->priv->comp = g_list_remove (cbfile->priv->comp, comp);
+ obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, comp);
+ g_hash_table_remove (obj_data->recurrences, rid);
+ } else {
+ /* not an error, only add EXDATE */
+ }
+ /* component empty? */
+ if (!obj_data->full_object) {
+ if (!obj_data->recurrences_list) {
+ /* empty now, remove it */
+ remove_component (cbfile, uid, obj_data);
+ return NULL;
+ } else {
+ return obj_data;
+ }
+ }
+ /* remove the main component from our data before modifying it */
icalcomponent_remove_component (cbfile->priv->icalcomp,
- e_cal_component_get_icalcomponent (comp));
- cbfile->priv->comp = g_list_remove (cbfile->priv->comp, comp);
- obj_data->recurrences_list = g_list_remove (obj_data->recurrences_list, comp);
- g_hash_table_remove (obj_data->recurrences, rid);
- }
+ e_cal_component_get_icalcomponent (obj_data->full_object));
+ cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
- if (!obj_data->full_object)
- return;
+ /* add EXDATE or EXRULE to parent */
+ e_cal_util_remove_instances (e_cal_component_get_icalcomponent (obj_data->full_object),
+ icaltime_from_string (rid), CALOBJ_MOD_THIS);
- /* remove the component from our data, temporarily */
- icalcomponent_remove_component (cbfile->priv->icalcomp,
- e_cal_component_get_icalcomponent (obj_data->full_object));
- cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
+ /* Since we are only removing one instance of recurrence
+ event, update the last modified time on the component */
+ current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+ e_cal_component_set_last_modified (obj_data->full_object, ¤t);
+
+ /* add the modified object to the beginning of the list,
+ so that it's always before any detached instance we
+ might have */
+ icalcomponent_add_component (cbfile->priv->icalcomp,
+ e_cal_component_get_icalcomponent (obj_data->full_object));
+ cbfile->priv->comp = g_list_prepend (cbfile->priv->comp, obj_data->full_object);
+ } else {
+ /* remove the main component from our data before deleting it */
+ if (!remove_component_from_intervaltree (cbfile, obj_data->full_object)) {
+ /* return without changing anything */
+ g_message (G_STRLOC " Could not remove component from interval tree!");
+ return obj_data;
+ }
+ icalcomponent_remove_component (cbfile->priv->icalcomp,
+ e_cal_component_get_icalcomponent (obj_data->full_object));
+ cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
- e_cal_util_remove_instances (e_cal_component_get_icalcomponent (obj_data->full_object),
- icaltime_from_string (rid), CALOBJ_MOD_THIS);
+ /* remove parent */
+ g_object_unref (obj_data->full_object);
+ obj_data->full_object = NULL;
- /* Since we are only removing one instance of recurrence
- event, update the last modified time on the component */
- current = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
- e_cal_component_set_last_modified (obj_data->full_object, ¤t);
+ /* component may be empty now, check that */
+ if (!obj_data->recurrences_list) {
+ remove_component (cbfile, uid, obj_data);
+ return NULL;
+ }
+ }
- /* add the modified object to the beginning of the list,
- so that it's always before any detached instance we
- might have */
- icalcomponent_add_component (cbfile->priv->icalcomp,
- e_cal_component_get_icalcomponent (obj_data->full_object));
- cbfile->priv->comp = g_list_prepend (cbfile->priv->comp, obj_data->full_object);
+ /* component still exists in a modified form */
+ return obj_data;
}
static gchar *
@@ -2724,8 +2771,6 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend, EDataCal *cal,
if (rid && *rid)
recur_id = rid;
- comp = obj_data->full_object;
-
switch (mod) {
case CALOBJ_MOD_ALL :
*old_object = get_object_string_from_fileobject (obj_data, recur_id);
@@ -2734,20 +2779,16 @@ e_cal_backend_file_remove_object (ECalBackendSync *backend, EDataCal *cal,
*object = NULL;
break;
case CALOBJ_MOD_THIS :
- if (!recur_id) {
- *old_object = get_object_string_from_fileobject (obj_data, recur_id);
- remove_component (cbfile, uid, obj_data);
- *object = NULL;
- } else {
- *old_object = get_object_string_from_fileobject (obj_data, recur_id);
+ *old_object = get_object_string_from_fileobject (obj_data, recur_id);
- remove_instance (cbfile, obj_data, recur_id);
- if (comp)
- *object = e_cal_component_get_as_string (comp);
- }
+ obj_data = remove_instance (cbfile, obj_data, uid, recur_id);
+ if (obj_data && obj_data->full_object)
+ *object = e_cal_component_get_as_string (obj_data->full_object);
break;
case CALOBJ_MOD_THISANDPRIOR :
case CALOBJ_MOD_THISANDFUTURE :
+ comp = obj_data->full_object;
+
if (!recur_id || !*recur_id) {
g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
g_propagate_error (error, EDC_ERROR (ObjectNotFound));
@@ -2796,6 +2837,7 @@ cancel_received_object (ECalBackendFile *cbfile, icalcomponent *icalcomp, gchar
ECalBackendFilePrivate *priv;
gchar *rid;
ECalComponent *comp;
+ const gchar *uid = icalcomponent_get_uid (icalcomp);
priv = cbfile->priv;
@@ -2803,7 +2845,7 @@ cancel_received_object (ECalBackendFile *cbfile, icalcomponent *icalcomp, gchar
*new_object = NULL;
/* Find the old version of the component. */
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, icalcomponent_get_uid (icalcomp));
+ obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
if (!obj_data)
return FALSE;
@@ -2820,11 +2862,11 @@ cancel_received_object (ECalBackendFile *cbfile, icalcomponent *icalcomp, gchar
/* new_object is kept NULL if not removing the instance */
rid = e_cal_component_get_recurid_as_string (comp);
if (rid && *rid) {
- remove_instance (cbfile, obj_data, rid);
- if (obj_data->full_object)
+ obj_data = remove_instance (cbfile, obj_data, uid, rid);
+ if (obj_data && obj_data->full_object)
*new_object = e_cal_component_get_as_string (obj_data->full_object);
} else
- remove_component (cbfile, icalcomponent_get_uid (icalcomp), obj_data);
+ remove_component (cbfile, uid, obj_data);
g_free (rid);
@@ -3065,7 +3107,7 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend, EDataCal *cal, con
if (obj_data->full_object)
old_object = e_cal_component_get_as_string (obj_data->full_object);
if (rid)
- remove_instance (cbfile, obj_data, rid);
+ remove_instance (cbfile, obj_data, uid, rid);
else
remove_component (cbfile, uid, obj_data);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]