new functions for individual instances management.

2003-10-24  Rodrigo Moya <rodrigo@ximian.com>

	* cal-util/cal-util.[ch] (cal_util_construct_instance,
	cal_util_remove_instances): new functions for individual
	instances management.

	* pcs/cal-backend-file.c (cal_backend_file_get_object): if we
	dont have a recurrence in our hash table, generate one for the
	specified recurrence ID.
	(match_recurrence_sexp): new function to match recurrences on
	regular expresessions.
	(match_object_sexp): call match_recurrence_sexp() for all recurrences.
	(cal_backend_file_modify_object): handle mod_types.
	(cal_backend_file_remove_object): handle mod_types.

svn path=/trunk/; revision=23058
This commit is contained in:
Rodrigo Moya
2003-10-24 14:39:28 +00:00
committed by Rodrigo Moya
parent 98f0136ffa
commit 53f60e8802
5 changed files with 297 additions and 16 deletions

View File

@ -1,3 +1,18 @@
2003-10-24 Rodrigo Moya <rodrigo@ximian.com>
* cal-util/cal-util.[ch] (cal_util_construct_instance,
cal_util_remove_instances): new functions for individual
instances management.
* pcs/cal-backend-file.c (cal_backend_file_get_object): if we
dont have a recurrence in our hash table, generate one for the
specified recurrence ID.
(match_recurrence_sexp): new function to match recurrences on
regular expresessions.
(match_object_sexp): call match_recurrence_sexp() for all recurrences.
(cal_backend_file_modify_object): handle mod_types.
(cal_backend_file_remove_object): handle mod_types.
2003-10-24 JP Rosevear <jpr@ximian.com>
* gui/gnome-cal.h: update protos

View File

@ -4018,3 +4018,4 @@ const char *cal_recur_nth[31] = {
N_("30th"),
N_("31st")
};

View File

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib/gstrfuncs.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-util.h>
#include "cal-util.h"
@ -750,3 +751,176 @@ cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *icalcomp2)
return TRUE;
}
/* Individual instances management */
struct instance_data {
time_t start;
gboolean found;
};
static void
check_instance (icalcomponent *comp, struct icaltime_span span, void *data)
{
struct instance_data *instance = data;
if (span.start == instance->start)
instance->found = TRUE;
}
/**
* cal_util_construct_instance:
* @icalcomp: a recurring #icalcomponent
* @rid: the RECURRENCE-ID to construct a component for
*
* This checks that @rid indicates a valid recurrence of @icalcomp, and
* if so, generates a copy of @comp containing a RECURRENCE-ID of @rid.
*
* Return value: the instance, or %NULL
**/
icalcomponent *
cal_util_construct_instance (icalcomponent *icalcomp,
struct icaltimetype rid)
{
struct instance_data instance;
struct icaltimetype start, end;
g_return_val_if_fail (icalcomp != NULL, NULL);
/* Make sure this is really recurring */
if (!icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY) &&
!icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY))
return NULL;
/* Make sure the specified instance really exists */
/* FIXME: does the libical recurrence code work correctly now? */
start = icaltime_convert_to_zone (rid, icaltimezone_get_utc_timezone ());
end = start;
icaltime_adjust (&end, 0, 0, 0, 1);
instance.start = icaltime_as_timet (start);
instance.found = FALSE;
icalcomponent_foreach_recurrence (icalcomp, start, end,
check_instance, &instance);
if (!instance.found)
return NULL;
/* Make the instance */
icalcomp = icalcomponent_new_clone (icalcomp);
icalcomponent_set_recurrenceid (icalcomp, rid);
return icalcomp;
}
static inline gboolean
time_matches_rid (struct icaltimetype itt, struct icaltimetype rid, CalObjModType mod)
{
int compare;
compare = icaltime_compare (itt, rid);
if (compare == 0)
return TRUE;
else if (compare < 0 && (mod & CALOBJ_MOD_THISANDPRIOR))
return TRUE;
else if (compare > 0 && (mod & CALOBJ_MOD_THISANDFUTURE))
return TRUE;
return FALSE;
}
/**
* cal_util_remove_instances:
* @icalcomp: a (recurring) #icalcomponent
* @rid: the base RECURRENCE-ID to remove
* @mod: how to interpret @rid
*
* Removes one or more instances from @comp according to @rid and @mod.
*
* FIXME: should probably have a return value indicating whether or not
* @icalcomp still has any instances
**/
void
cal_util_remove_instances (icalcomponent *icalcomp,
struct icaltimetype rid,
CalObjModType mod)
{
icalproperty *prop;
struct icaltimetype itt, recur;
struct icalrecurrencetype rule;
icalrecur_iterator *iter;
struct instance_data instance;
g_return_if_fail (icalcomp != NULL);
g_return_if_fail (mod != CALOBJ_MOD_ALL);
/* First remove RDATEs and EXDATEs in the indicated range. */
for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY);
prop;
prop = icalcomponent_get_next_property (icalcomp, ICAL_RDATE_PROPERTY)) {
struct icaldatetimeperiodtype period;
period = icalproperty_get_rdate (prop);
if (time_matches_rid (period.time, rid, mod))
icalcomponent_remove_property (icalcomp, prop);
}
for (prop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY);
prop;
prop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) {
itt = icalproperty_get_exdate (prop);
if (time_matches_rid (itt, rid, mod))
icalcomponent_remove_property (icalcomp, prop);
}
/* If we're only removing one instance, just add an EXDATE. */
if (mod == CALOBJ_MOD_THIS) {
prop = icalproperty_new_exdate (rid);
icalcomponent_add_property (icalcomp, prop);
return;
}
/* Otherwise, iterate through RRULEs */
/* FIXME: this may generate duplicate EXRULEs */
for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY);
prop;
prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) {
rule = icalproperty_get_rrule (prop);
iter = icalrecur_iterator_new (rule, rid);
recur = icalrecur_iterator_next (iter);
if (mod & CALOBJ_MOD_THISANDFUTURE) {
/* If there is a recurrence on or after rid,
* use the UNTIL parameter to truncate the rule
* at rid.
*/
if (!icaltime_is_null_time (recur)) {
rule.count = 0;
rule.until = rid;
icaltime_adjust (&rule.until, 0, 0, 0, -1);
icalproperty_set_rrule (prop, rule);
}
} else {
/* (If recur == rid, skip to the next occurrence) */
if (icaltime_compare (recur, rid) == 0)
recur = icalrecur_iterator_next (iter);
/* If there is a recurrence after rid, add
* an EXRULE to block instances up to rid.
* Otherwise, just remove the RRULE.
*/
if (!icaltime_is_null_time (recur)) {
rule.count = 0;
/* iCalendar says we should just use rid
* here, but Outlook/Exchange handle
* UNTIL incorrectly.
*/
rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp));
prop = icalproperty_new_exrule (rule);
icalcomponent_add_property (icalcomp, prop);
} else
icalcomponent_remove_property (icalcomp, prop);
}
icalrecur_iterator_free (iter);
}
}

View File

@ -122,6 +122,13 @@ gboolean cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *ic
#define CAL_STATIC_CAPABILITY_REMOVE_ALARMS "remove-alarms"
#define CAL_STATIC_CAPABILITY_SAVE_SCHEDULES "save-schedules"
/* Recurrent events. Management for instances */
icalcomponent *cal_util_construct_instance (icalcomponent *icalcomp,
struct icaltimetype rid);
void cal_util_remove_instances (icalcomponent *icalcomp,
struct icaltimetype rid,
CalObjModType mod);
G_END_DECLS
#endif

View File

@ -829,6 +829,7 @@ cal_backend_file_get_object (CalBackendSync *backend, Cal *cal, const char *uid,
CalBackendFilePrivate *priv;
CalBackendFileObject *obj_data;
CalComponent *comp = NULL;
gboolean free_comp = FALSE;
cbfile = CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
@ -844,6 +845,19 @@ cal_backend_file_get_object (CalBackendSync *backend, Cal *cal, const char *uid,
if (rid && *rid) {
comp = g_hash_table_lookup (obj_data->recurrences, rid);
if (!comp) {
icalcomponent *icalcomp;
struct icaltimetype itt;
itt = icaltime_from_string (rid);
icalcomp = cal_util_construct_instance (
cal_component_get_icalcomponent (obj_data->full_object),
itt);
if (!icalcomp)
return GNOME_Evolution_Calendar_ObjectNotFound;
comp = cal_component_new ();
free_comp = TRUE;
cal_component_set_icalcomponent (comp, icalcomp);
}
} else
comp = obj_data->full_object;
@ -853,6 +867,9 @@ cal_backend_file_get_object (CalBackendSync *backend, Cal *cal, const char *uid,
*object = cal_component_get_as_string (comp);
if (free_comp)
g_object_unref (comp);
return GNOME_Evolution_Calendar_Success;
}
@ -915,7 +932,8 @@ cal_backend_file_add_timezone (CalBackendSync *backend, Cal *cal, const char *tz
zone = icaltimezone_new ();
icaltimezone_set_component (zone, tz_comp);
if (!icalcomponent_get_timezone (priv->icalcomp, icaltimezone_get_tzid (zone))) {
if (!icalcomponent_get_timezone (priv->icalcomp,
icaltimezone_get_tzid (zone))) {
icalcomponent_add_component (priv->icalcomp, tz_comp);
mark_dirty (cbfile);
}
@ -959,6 +977,19 @@ typedef struct {
icaltimezone *default_zone;
} MatchObjectData;
static void
match_recurrence_sexp (gpointer key, gpointer value, gpointer data)
{
CalComponent *comp = value;
MatchObjectData *match_data = data;
if ((!match_data->search_needed) ||
(cal_backend_object_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
match_data->obj_list = g_list_append (match_data->obj_list,
cal_component_get_as_string (comp));
}
}
static void
match_object_sexp (gpointer key, gpointer value, gpointer data)
{
@ -969,6 +1000,11 @@ match_object_sexp (gpointer key, gpointer value, gpointer data)
(cal_backend_object_sexp_match_comp (match_data->obj_sexp, obj_data->full_object, match_data->backend))) {
match_data->obj_list = g_list_append (match_data->obj_list,
cal_component_get_as_string (obj_data->full_object));
/* match also recurrences */
g_hash_table_foreach (obj_data->recurrences,
(GHFunc) match_recurrence_sexp,
match_data);
}
}
@ -1378,7 +1414,8 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
icalcomponent *icalcomp;
icalcomponent_kind kind;
const char *comp_uid;
CalComponent *comp, *old_comp;
CalComponent *comp;
CalBackendFileObject *obj_data;
struct icaltimetype current;
cbfile = CAL_BACKEND_FILE (backend);
@ -1402,7 +1439,7 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
comp_uid = icalcomponent_get_uid (icalcomp);
/* Get the object from our cache */
if (!(old_comp = lookup_component (cbfile, comp_uid))) {
if (!(obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid))) {
icalcomponent_free (icalcomp);
return GNOME_Evolution_Calendar_ObjectNotFound;
}
@ -1415,13 +1452,17 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
current = icaltime_from_timet (time (NULL), 0);
cal_component_set_last_modified (comp, &current);
/* FIXME we need to handle mod types here */
/* handle mod_type */
if (cal_component_is_instance (comp) ||
mod != CALOBJ_MOD_ALL) {
/* FIXME */
} else {
/* Remove the old version */
remove_component (cbfile, obj_data->full_object);
/* Remove the old version */
remove_component (cbfile, old_comp);
/* Add the object */
add_component (cbfile, comp, TRUE);
/* Add the object */
add_component (cbfile, comp, TRUE);
}
mark_dirty (cbfile);
@ -1433,12 +1474,16 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
/* Remove_object handler for the file backend */
static CalBackendSyncStatus
cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid,
cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
const char *uid, const char *rid,
CalObjModType mod, char **object)
{
CalBackendFile *cbfile;
CalBackendFilePrivate *priv;
CalBackendFileObject *obj_data;
CalComponent *comp;
char *hash_rid;
GSList *categories;
cbfile = CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
@ -1446,14 +1491,53 @@ cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal, const char *u
g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
/* FIXME we need to handle mod types here */
comp = lookup_component (cbfile, uid);
if (!comp)
obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
if (!obj_data)
return GNOME_Evolution_Calendar_ObjectNotFound;
*object = cal_component_get_as_string (comp);
remove_component (cbfile, comp);
if (rid && *rid) {
if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
&hash_rid, &comp)) {
/* remove the component from our data */
icalcomponent_remove_component (priv->icalcomp,
cal_component_get_icalcomponent (comp));
priv->comp = g_list_remove (priv->comp, comp);
g_hash_table_remove (obj_data->recurrences, rid);
/* 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);
/* free memory */
g_free (hash_rid);
g_object_unref (comp);
mark_dirty (cbfile);
return GNOME_Evolution_Calendar_Success;
}
}
comp = obj_data->full_object;
if (mod != CALOBJ_MOD_ALL) {
*object = cal_component_get_as_string (comp);
remove_component (cbfile, comp);
} else {
/* remove the component from our data, temporarily */
icalcomponent_remove_component (priv->icalcomp,
cal_component_get_icalcomponent (comp));
priv->comp = g_list_remove (priv->comp, comp);
cal_util_remove_instances (cal_component_get_icalcomponent (comp),
icaltime_from_string (rid), mod);
/* add the modified object to the beginning of the list,
so that it's always before any detached instance we
might have */
priv->comp = g_list_prepend (priv->comp, comp);
}
mark_dirty (cbfile);