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:

committed by
Rodrigo Moya

parent
98f0136ffa
commit
53f60e8802
@ -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
|
||||
|
@ -4018,3 +4018,4 @@ const char *cal_recur_nth[31] = {
|
||||
N_("30th"),
|
||||
N_("31st")
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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, ¤t);
|
||||
|
||||
/* 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);
|
||||
|
||||
|
Reference in New Issue
Block a user