aboutsummaryrefslogtreecommitdiffstats
path: root/calendar
diff options
context:
space:
mode:
authorArturo Espinosa <unammx@src.gnome.org>1998-04-14 13:24:38 +0800
committerArturo Espinosa <unammx@src.gnome.org>1998-04-14 13:24:38 +0800
commit3161696e57f03b5ebc859907725f6836f4220667 (patch)
tree8b1e9f1b509ce5e6343407af8cd7db1d5b8155b8 /calendar
parent49a388705e5085a963c3c1b5cdcd324af5d8b1b5 (diff)
downloadgsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.gz
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.bz2
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.lz
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.xz
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.zst
gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.zip
Load recurrence rules; Paint the recurrence screen according to the rules.
Load recurrence rules; Paint the recurrence screen according to the rules. -miguel svn path=/trunk/; revision=133
Diffstat (limited to 'calendar')
-rw-r--r--calendar/cal-util/calobj.c272
-rw-r--r--calendar/cal-util/calobj.h13
-rw-r--r--calendar/calobj.c272
-rw-r--r--calendar/calobj.h13
-rw-r--r--calendar/eventedit.c78
-rw-r--r--calendar/gui/eventedit.c78
-rw-r--r--calendar/pcs/calobj.c272
-rw-r--r--calendar/pcs/calobj.h13
8 files changed, 969 insertions, 42 deletions
diff --git a/calendar/cal-util/calobj.c b/calendar/cal-util/calobj.c
index a5832e469d..5d997dec5d 100644
--- a/calendar/cal-util/calobj.c
+++ b/calendar/cal-util/calobj.c
@@ -115,10 +115,270 @@ set_list (char *str, char *sc)
return list;
}
+static GList *
+set_date_list (char *str)
+{
+ GList *list = 0;
+ char *s;
+
+ for (s = strtok (str, ";"); s; s = strtok (NULL, ";")){
+ time_t *t = g_new (time_t, 1);
+
+ *t = time_from_isodate (s);
+ list = g_list_prepend (list, t);
+ }
+ return list;
+}
+
+static void
+ignore_space(char **str)
+{
+ while (**str && isspace (**str))
+ *str++;
+}
+
+static void
+skip_numbers (char **str)
+{
+ while (**str){
+ ignore_space (str);
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ ;
+ }
+}
+
+static void
+weekdaylist (iCalObject *o, char **str)
+{
+ int i;
+ struct {
+ char first_letter, second_letter;
+ int index;
+ } days [] = {
+ { 'S', 'U', 0 },
+ { 'M', 'O', 1 },
+ { 'T', 'U', 2 },
+ { 'W', 'E', 3 },
+ { 'T', 'H', 4 },
+ { 'F', 'R', 5 },
+ { 'S', 'A', 6 }
+ };
+
+ ignore_space (str);
+ do {
+ for (i = 0; i < 7; i++){
+ if (**str == days [i].first_letter && *(*str+1) == days [i].second_letter){
+ o->recur->weekday |= 1 << i;
+ *str += 2;
+ if (**str == ' ')
+ (*str)++;
+ }
+ }
+ } while (isalpha (**str));
+}
+
static void
+ocurrencelist (iCalObject *o, char **str)
+{
+ char *p, *q;
+ int value = 0;
+
+ ignore_space (str);
+ p = *str;
+ if (!isdigit (*str))
+ return;
+
+ if (!(*p >= '1' && *p <= '5'))
+ return;
+
+ if (!(*(p+1) == '+' || *(p+1) == '-'))
+ return;
+
+ o->recur->u.month_pos = (*p-'0') * (*(p+1) == '+' ? 1 : -1);
+ *str += 2;
+}
+
+static void
+daynumber (iCalObject *o, char **str)
+{
+ int val = 0;
+ char *p = *str;
+
+ ignore_space (str);
+ if (strcmp (p, "LD")){
+ o->recur->u.month_day = DAY_LASTDAY;
+ *str += 2;
+ return;
+ }
+
+ if (!(isdigit (*p)))
+ return;
+
+ while (**str && isdigit (**str)){
+ val = val * 10 + (**str - '0');
+ *str++;
+ }
+
+ if (**str == '+')
+ *str++;
+
+ if (**str == '-')
+ val *= -1;
+ o->recur->u.month_day = val;
+}
+
+static void
+daynumberlist (iCalObject *o, char **str)
+{
+ int first = 0;
+ int val = 0;
+
+ ignore_space (str);
+
+ while (**str){
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ val = 10 * val + (**str - '0');
+ if (!first){
+ o->recur->u.month_day = val;
+ first = 1;
+ val = 0;
+ }
+ }
+}
+
+static void
+load_recur_weekly (iCalObject *o, char **str)
+{
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_pos (iCalObject *o, char **str)
+{
+ ocurrencelist (o, str);
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_day (iCalObject *o, char **str)
+{
+ daynumberlist (o, str);
+}
+
+static void
+load_recur_yearly_month (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple months and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+load_recur_yearly_day (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple days and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+duration (iCalObject *o, char **str)
+{
+ int duration = 0;
+
+ ignore_space (str);
+ if (**str != '#')
+ return;
+ while (**str && isdigit (**str))
+ duration = duration * 10 + (**str - '0');
+
+ o->recur->temp_duration = duration;
+}
+
+static void
+enddate (iCalObject *o, char **str)
+{
+ ignore_space (str);
+ if (isdigit (**str)){
+ o->recur->enddate = time_from_isodate (*str);
+ *str += 16;
+ }
+}
+
+static int
load_recurrence (iCalObject *o, char *str)
{
+ char c;
+ enum RecurType type;
+ int interval = 0;
+
+ type = -1;
+ switch (*str++){
+ case 'D':
+ type = RECUR_DAILY;
+ break;
+
+ case 'W':
+ type = RECUR_WEEKLY;
+ break;
+
+ case 'M':
+ if (*str == 'P')
+ type = RECUR_MONTHLY_BY_POS;
+ else if (*str == 'D')
+ type = RECUR_MONTHLY_BY_DAY;
+ str++;
+ break;
+
+ case 'Y':
+ if (*str == 'M')
+ type = RECUR_YEARLY_BY_MONTH;
+ else if (*str == 'D')
+ type = RECUR_YEARLY_BY_DAY;
+ str++;
+ break;
+ }
+ if (type == -1)
+ return 0;
+ o->recur = g_new0 (Recurrence, 1);
+ o->recur->type = type;
+ ignore_space (&str);
+
+ /* Get the interval */
+ while (*str && isdigit (*str))
+ interval = interval * 10 + (*str-'0');
+ o->recur->interval = interval;
+
+ ignore_space (&str);
+
+ switch (type){
+ case RECUR_WEEKLY:
+ load_recur_weekly (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_POS:
+ load_recur_monthly_pos (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_DAY:
+ load_recur_monthly_day (o, &str);
+ break;
+ case RECUR_YEARLY_BY_MONTH:
+ load_recur_yearly_month (o, &str);
+ break;
+ case RECUR_YEARLY_BY_DAY:
+ load_recur_yearly_day (o, &str);
+ break;
+ }
+ duration (o, &str);
+ enddate (o, &str);
+
+ return 1;
}
#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
@@ -133,6 +393,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
iCalObject *ical;
VObject *vo;
VObjectIterator i;
+ int syntax_error;
ical = g_new0 (iCalObject, 1);
@@ -181,7 +442,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* exdate */
if (has (o, VCExpDateProp))
- ical->exdate = set_list (str_val (vo), ",");
+ ical->exdate = set_date_list (str_val (vo));
/* description/comment */
if (has (o, VCDescriptionProp))
@@ -254,8 +515,13 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* FIXME: rrule */
if (has (o, VCRRuleProp))
- load_recurrence (ical, str_val (vo));
-
+ syntax_error = load_recurrence (ical, str_val (vo)) == 0;
+
+ if (syntax_error){
+ ical_object_destroy (ical);
+ return NULL;
+ }
+
return ical;
}
diff --git a/calendar/cal-util/calobj.h b/calendar/cal-util/calobj.h
index 7dc810b459..9287332d40 100644
--- a/calendar/cal-util/calobj.h
+++ b/calendar/cal-util/calobj.h
@@ -79,10 +79,21 @@ enum RecurType {
RECUR_YEARLY_BY_DAY,
};
+#define DAY_LASTDAY 10000
+
typedef struct {
enum RecurType type;
- int frequency;
+ int interval;
+ time_t enddate;
+ int weekday;
+
+ union {
+ int month_pos;
+ int month_day;
+ } u;
+
+ int temp_duration; /* Used temporarly, we compute enddate */
} Recurrence;
/* Flags to indicate what has changed in an object */
diff --git a/calendar/calobj.c b/calendar/calobj.c
index a5832e469d..5d997dec5d 100644
--- a/calendar/calobj.c
+++ b/calendar/calobj.c
@@ -115,10 +115,270 @@ set_list (char *str, char *sc)
return list;
}
+static GList *
+set_date_list (char *str)
+{
+ GList *list = 0;
+ char *s;
+
+ for (s = strtok (str, ";"); s; s = strtok (NULL, ";")){
+ time_t *t = g_new (time_t, 1);
+
+ *t = time_from_isodate (s);
+ list = g_list_prepend (list, t);
+ }
+ return list;
+}
+
+static void
+ignore_space(char **str)
+{
+ while (**str && isspace (**str))
+ *str++;
+}
+
+static void
+skip_numbers (char **str)
+{
+ while (**str){
+ ignore_space (str);
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ ;
+ }
+}
+
+static void
+weekdaylist (iCalObject *o, char **str)
+{
+ int i;
+ struct {
+ char first_letter, second_letter;
+ int index;
+ } days [] = {
+ { 'S', 'U', 0 },
+ { 'M', 'O', 1 },
+ { 'T', 'U', 2 },
+ { 'W', 'E', 3 },
+ { 'T', 'H', 4 },
+ { 'F', 'R', 5 },
+ { 'S', 'A', 6 }
+ };
+
+ ignore_space (str);
+ do {
+ for (i = 0; i < 7; i++){
+ if (**str == days [i].first_letter && *(*str+1) == days [i].second_letter){
+ o->recur->weekday |= 1 << i;
+ *str += 2;
+ if (**str == ' ')
+ (*str)++;
+ }
+ }
+ } while (isalpha (**str));
+}
+
static void
+ocurrencelist (iCalObject *o, char **str)
+{
+ char *p, *q;
+ int value = 0;
+
+ ignore_space (str);
+ p = *str;
+ if (!isdigit (*str))
+ return;
+
+ if (!(*p >= '1' && *p <= '5'))
+ return;
+
+ if (!(*(p+1) == '+' || *(p+1) == '-'))
+ return;
+
+ o->recur->u.month_pos = (*p-'0') * (*(p+1) == '+' ? 1 : -1);
+ *str += 2;
+}
+
+static void
+daynumber (iCalObject *o, char **str)
+{
+ int val = 0;
+ char *p = *str;
+
+ ignore_space (str);
+ if (strcmp (p, "LD")){
+ o->recur->u.month_day = DAY_LASTDAY;
+ *str += 2;
+ return;
+ }
+
+ if (!(isdigit (*p)))
+ return;
+
+ while (**str && isdigit (**str)){
+ val = val * 10 + (**str - '0');
+ *str++;
+ }
+
+ if (**str == '+')
+ *str++;
+
+ if (**str == '-')
+ val *= -1;
+ o->recur->u.month_day = val;
+}
+
+static void
+daynumberlist (iCalObject *o, char **str)
+{
+ int first = 0;
+ int val = 0;
+
+ ignore_space (str);
+
+ while (**str){
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ val = 10 * val + (**str - '0');
+ if (!first){
+ o->recur->u.month_day = val;
+ first = 1;
+ val = 0;
+ }
+ }
+}
+
+static void
+load_recur_weekly (iCalObject *o, char **str)
+{
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_pos (iCalObject *o, char **str)
+{
+ ocurrencelist (o, str);
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_day (iCalObject *o, char **str)
+{
+ daynumberlist (o, str);
+}
+
+static void
+load_recur_yearly_month (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple months and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+load_recur_yearly_day (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple days and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+duration (iCalObject *o, char **str)
+{
+ int duration = 0;
+
+ ignore_space (str);
+ if (**str != '#')
+ return;
+ while (**str && isdigit (**str))
+ duration = duration * 10 + (**str - '0');
+
+ o->recur->temp_duration = duration;
+}
+
+static void
+enddate (iCalObject *o, char **str)
+{
+ ignore_space (str);
+ if (isdigit (**str)){
+ o->recur->enddate = time_from_isodate (*str);
+ *str += 16;
+ }
+}
+
+static int
load_recurrence (iCalObject *o, char *str)
{
+ char c;
+ enum RecurType type;
+ int interval = 0;
+
+ type = -1;
+ switch (*str++){
+ case 'D':
+ type = RECUR_DAILY;
+ break;
+
+ case 'W':
+ type = RECUR_WEEKLY;
+ break;
+
+ case 'M':
+ if (*str == 'P')
+ type = RECUR_MONTHLY_BY_POS;
+ else if (*str == 'D')
+ type = RECUR_MONTHLY_BY_DAY;
+ str++;
+ break;
+
+ case 'Y':
+ if (*str == 'M')
+ type = RECUR_YEARLY_BY_MONTH;
+ else if (*str == 'D')
+ type = RECUR_YEARLY_BY_DAY;
+ str++;
+ break;
+ }
+ if (type == -1)
+ return 0;
+ o->recur = g_new0 (Recurrence, 1);
+ o->recur->type = type;
+ ignore_space (&str);
+
+ /* Get the interval */
+ while (*str && isdigit (*str))
+ interval = interval * 10 + (*str-'0');
+ o->recur->interval = interval;
+
+ ignore_space (&str);
+
+ switch (type){
+ case RECUR_WEEKLY:
+ load_recur_weekly (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_POS:
+ load_recur_monthly_pos (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_DAY:
+ load_recur_monthly_day (o, &str);
+ break;
+ case RECUR_YEARLY_BY_MONTH:
+ load_recur_yearly_month (o, &str);
+ break;
+ case RECUR_YEARLY_BY_DAY:
+ load_recur_yearly_day (o, &str);
+ break;
+ }
+ duration (o, &str);
+ enddate (o, &str);
+
+ return 1;
}
#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
@@ -133,6 +393,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
iCalObject *ical;
VObject *vo;
VObjectIterator i;
+ int syntax_error;
ical = g_new0 (iCalObject, 1);
@@ -181,7 +442,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* exdate */
if (has (o, VCExpDateProp))
- ical->exdate = set_list (str_val (vo), ",");
+ ical->exdate = set_date_list (str_val (vo));
/* description/comment */
if (has (o, VCDescriptionProp))
@@ -254,8 +515,13 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* FIXME: rrule */
if (has (o, VCRRuleProp))
- load_recurrence (ical, str_val (vo));
-
+ syntax_error = load_recurrence (ical, str_val (vo)) == 0;
+
+ if (syntax_error){
+ ical_object_destroy (ical);
+ return NULL;
+ }
+
return ical;
}
diff --git a/calendar/calobj.h b/calendar/calobj.h
index 7dc810b459..9287332d40 100644
--- a/calendar/calobj.h
+++ b/calendar/calobj.h
@@ -79,10 +79,21 @@ enum RecurType {
RECUR_YEARLY_BY_DAY,
};
+#define DAY_LASTDAY 10000
+
typedef struct {
enum RecurType type;
- int frequency;
+ int interval;
+ time_t enddate;
+ int weekday;
+
+ union {
+ int month_pos;
+ int month_day;
+ } u;
+
+ int temp_duration; /* Used temporarly, we compute enddate */
} Recurrence;
/* Flags to indicate what has changed in an object */
diff --git a/calendar/eventedit.c b/calendar/eventedit.c
index cc8a89ab57..8230c70429 100644
--- a/calendar/eventedit.c
+++ b/calendar/eventedit.c
@@ -621,7 +621,7 @@ static char *weekday_names [] = {
};
static GtkWidget *
-make_day_list_widget (char **array)
+make_day_list_widget (char **array, int sel)
{
GtkWidget *option_menu, *menu;
int i;
@@ -636,6 +636,7 @@ make_day_list_widget (char **array)
gtk_widget_show (item);
}
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
+ gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), sel);
return option_menu;
}
@@ -663,7 +664,13 @@ ee_rp_init_frequency (EventEditor *ee)
GtkNotebook *notebook;
GSList *group;
int i, page, day_period, week_period, month_period, year_period;
-
+ int week_vector, default_day, def_pos, def_off;
+ time_t now;
+ struct tm *tm;
+
+ now = time (NULL);
+ tm = localtime (&now);
+
f = gtk_frame_new (_("Frequency"));
vbox = gtk_vbox_new (0, 0);
hbox = gtk_hbox_new (0, 0);
@@ -679,19 +686,51 @@ ee_rp_init_frequency (EventEditor *ee)
week_period = 1;
month_period = 1;
year_period = 1;
-
+
+ /* Default to today */
+ week_vector = 1 << tm->tm_wday;
+ default_day = tm->tm_mday - 1;
+ def_pos = 0;
+ def_off = 0;
+
/* Determine which should be the default selection */
if (ee->ical->recur){
enum RecurType type = ee->ical->recur->type;
- int freq = ee->ical->recur->frequency;
-
+ int interval = ee->ical->recur->interval;
+
switch (type){
- case RECUR_DAILY: page = 0; day_period = freq; break;
- case RECUR_WEEKLY: page = 1; week_period = freq; break;
- case RECUR_MONTHLY_BY_POS: page = 2; month_period = freq; break;
- case RECUR_MONTHLY_BY_DAY: page = 2; month_period = freq; break;
- case RECUR_YEARLY_BY_MONTH: page = 3; year_period = freq; break;
- case RECUR_YEARLY_BY_DAY: page = 4; year_period = freq; break;
+ case RECUR_DAILY:
+ page = 0;
+ day_period = interval;
+ break;
+
+ case RECUR_WEEKLY:
+ page = 1;
+ week_period = interval;
+ week_vector = ee->ical->recur->weekday;
+ break;
+
+ case RECUR_MONTHLY_BY_POS:
+ page = 2;
+ month_period = interval;
+ def_pos = ee->ical->recur->u.month_pos;
+ break;
+
+ case RECUR_MONTHLY_BY_DAY:
+ page = 2;
+ month_period = interval;
+ default_day = ee->ical->recur->u.month_day;
+ break;
+
+ case RECUR_YEARLY_BY_MONTH:
+ page = 3;
+ year_period = interval;
+ break;
+
+ case RECUR_YEARLY_BY_DAY:
+ page = 4;
+ year_period = interval;
+ break;
}
} else {
page = 0;
@@ -731,6 +770,8 @@ ee_rp_init_frequency (EventEditor *ee)
for (i = 0; i < 7; i++){
ee->recur_week_days [i] = gtk_check_button_new_with_label (_(day_names [i]));
gtk_box_pack_start (GTK_BOX (week_day), ee->recur_week_days [i], 1, 1, 5);
+ if (week_vector & (1 << i))
+ gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (ee->recur_week_days [i]));
}
gtk_box_pack_start (GTK_BOX (weekly), week_day, 1, 1, 0);
@@ -738,7 +779,7 @@ ee_rp_init_frequency (EventEditor *ee)
/* 3. The monthly recurrence */
monthly = gtk_table_new (0, 0, 0);
re = gtk_radio_button_new_with_label (NULL, _("Recur on the"));
- ee->recur_month_date = make_day_list_widget (numeral_day_names);
+ ee->recur_month_date = make_day_list_widget (numeral_day_names, default_day);
w = gtk_label_new (_("day"));
gtk_table_attach (GTK_TABLE (monthly), re,
0, 1, 0, 1, 0, 0, 0, 0);
@@ -748,9 +789,9 @@ ee_rp_init_frequency (EventEditor *ee)
2, 3, 0, 1, 0, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (re), "toggled", GTK_SIGNAL_FUNC (recur_month_enable_date), ee);
- r1 = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (r)), _("Recur on the"));
- ee->recur_month_day = make_day_list_widget (numeral_day_names);
- ee->recur_month_weekday = make_day_list_widget (weekday_names);
+ r1 = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (re)), _("Recur on the"));
+ ee->recur_month_day = make_day_list_widget (numeral_day_names, 0);
+ ee->recur_month_weekday = make_day_list_widget (weekday_names, def_pos);
gtk_table_attach (GTK_TABLE (monthly), r1,
0, 1, 1, 2, 0, 0, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_month_day,
@@ -764,6 +805,13 @@ ee_rp_init_frequency (EventEditor *ee)
4, 5, 0, 2, 0, 0, 5, 0);
gtk_table_attach (GTK_TABLE (monthly), gtk_label_new (_("month(s)")),
5, 6, 0, 2, 0, 0, 0, 0);
+ if (ee->ical->recur){
+ if (ee->ical->recur->type == RECUR_MONTHLY_BY_POS)
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (r1), 1);
+ } else {
+ recur_month_enable_date ((re), ee);
+ }
+
/* 4. The yearly recurrence */
yearly = gtk_hbox_new (0, 0);
ee->recur_year_period = small_entry (year_period);
diff --git a/calendar/gui/eventedit.c b/calendar/gui/eventedit.c
index cc8a89ab57..8230c70429 100644
--- a/calendar/gui/eventedit.c
+++ b/calendar/gui/eventedit.c
@@ -621,7 +621,7 @@ static char *weekday_names [] = {
};
static GtkWidget *
-make_day_list_widget (char **array)
+make_day_list_widget (char **array, int sel)
{
GtkWidget *option_menu, *menu;
int i;
@@ -636,6 +636,7 @@ make_day_list_widget (char **array)
gtk_widget_show (item);
}
gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
+ gtk_option_menu_set_history (GTK_OPTION_MENU (option_menu), sel);
return option_menu;
}
@@ -663,7 +664,13 @@ ee_rp_init_frequency (EventEditor *ee)
GtkNotebook *notebook;
GSList *group;
int i, page, day_period, week_period, month_period, year_period;
-
+ int week_vector, default_day, def_pos, def_off;
+ time_t now;
+ struct tm *tm;
+
+ now = time (NULL);
+ tm = localtime (&now);
+
f = gtk_frame_new (_("Frequency"));
vbox = gtk_vbox_new (0, 0);
hbox = gtk_hbox_new (0, 0);
@@ -679,19 +686,51 @@ ee_rp_init_frequency (EventEditor *ee)
week_period = 1;
month_period = 1;
year_period = 1;
-
+
+ /* Default to today */
+ week_vector = 1 << tm->tm_wday;
+ default_day = tm->tm_mday - 1;
+ def_pos = 0;
+ def_off = 0;
+
/* Determine which should be the default selection */
if (ee->ical->recur){
enum RecurType type = ee->ical->recur->type;
- int freq = ee->ical->recur->frequency;
-
+ int interval = ee->ical->recur->interval;
+
switch (type){
- case RECUR_DAILY: page = 0; day_period = freq; break;
- case RECUR_WEEKLY: page = 1; week_period = freq; break;
- case RECUR_MONTHLY_BY_POS: page = 2; month_period = freq; break;
- case RECUR_MONTHLY_BY_DAY: page = 2; month_period = freq; break;
- case RECUR_YEARLY_BY_MONTH: page = 3; year_period = freq; break;
- case RECUR_YEARLY_BY_DAY: page = 4; year_period = freq; break;
+ case RECUR_DAILY:
+ page = 0;
+ day_period = interval;
+ break;
+
+ case RECUR_WEEKLY:
+ page = 1;
+ week_period = interval;
+ week_vector = ee->ical->recur->weekday;
+ break;
+
+ case RECUR_MONTHLY_BY_POS:
+ page = 2;
+ month_period = interval;
+ def_pos = ee->ical->recur->u.month_pos;
+ break;
+
+ case RECUR_MONTHLY_BY_DAY:
+ page = 2;
+ month_period = interval;
+ default_day = ee->ical->recur->u.month_day;
+ break;
+
+ case RECUR_YEARLY_BY_MONTH:
+ page = 3;
+ year_period = interval;
+ break;
+
+ case RECUR_YEARLY_BY_DAY:
+ page = 4;
+ year_period = interval;
+ break;
}
} else {
page = 0;
@@ -731,6 +770,8 @@ ee_rp_init_frequency (EventEditor *ee)
for (i = 0; i < 7; i++){
ee->recur_week_days [i] = gtk_check_button_new_with_label (_(day_names [i]));
gtk_box_pack_start (GTK_BOX (week_day), ee->recur_week_days [i], 1, 1, 5);
+ if (week_vector & (1 << i))
+ gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (ee->recur_week_days [i]));
}
gtk_box_pack_start (GTK_BOX (weekly), week_day, 1, 1, 0);
@@ -738,7 +779,7 @@ ee_rp_init_frequency (EventEditor *ee)
/* 3. The monthly recurrence */
monthly = gtk_table_new (0, 0, 0);
re = gtk_radio_button_new_with_label (NULL, _("Recur on the"));
- ee->recur_month_date = make_day_list_widget (numeral_day_names);
+ ee->recur_month_date = make_day_list_widget (numeral_day_names, default_day);
w = gtk_label_new (_("day"));
gtk_table_attach (GTK_TABLE (monthly), re,
0, 1, 0, 1, 0, 0, 0, 0);
@@ -748,9 +789,9 @@ ee_rp_init_frequency (EventEditor *ee)
2, 3, 0, 1, 0, 0, 0, 0);
gtk_signal_connect (GTK_OBJECT (re), "toggled", GTK_SIGNAL_FUNC (recur_month_enable_date), ee);
- r1 = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (r)), _("Recur on the"));
- ee->recur_month_day = make_day_list_widget (numeral_day_names);
- ee->recur_month_weekday = make_day_list_widget (weekday_names);
+ r1 = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (re)), _("Recur on the"));
+ ee->recur_month_day = make_day_list_widget (numeral_day_names, 0);
+ ee->recur_month_weekday = make_day_list_widget (weekday_names, def_pos);
gtk_table_attach (GTK_TABLE (monthly), r1,
0, 1, 1, 2, 0, 0, 0, 0);
gtk_table_attach (GTK_TABLE (monthly), ee->recur_month_day,
@@ -764,6 +805,13 @@ ee_rp_init_frequency (EventEditor *ee)
4, 5, 0, 2, 0, 0, 5, 0);
gtk_table_attach (GTK_TABLE (monthly), gtk_label_new (_("month(s)")),
5, 6, 0, 2, 0, 0, 0, 0);
+ if (ee->ical->recur){
+ if (ee->ical->recur->type == RECUR_MONTHLY_BY_POS)
+ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (r1), 1);
+ } else {
+ recur_month_enable_date ((re), ee);
+ }
+
/* 4. The yearly recurrence */
yearly = gtk_hbox_new (0, 0);
ee->recur_year_period = small_entry (year_period);
diff --git a/calendar/pcs/calobj.c b/calendar/pcs/calobj.c
index a5832e469d..5d997dec5d 100644
--- a/calendar/pcs/calobj.c
+++ b/calendar/pcs/calobj.c
@@ -115,10 +115,270 @@ set_list (char *str, char *sc)
return list;
}
+static GList *
+set_date_list (char *str)
+{
+ GList *list = 0;
+ char *s;
+
+ for (s = strtok (str, ";"); s; s = strtok (NULL, ";")){
+ time_t *t = g_new (time_t, 1);
+
+ *t = time_from_isodate (s);
+ list = g_list_prepend (list, t);
+ }
+ return list;
+}
+
+static void
+ignore_space(char **str)
+{
+ while (**str && isspace (**str))
+ *str++;
+}
+
+static void
+skip_numbers (char **str)
+{
+ while (**str){
+ ignore_space (str);
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ ;
+ }
+}
+
+static void
+weekdaylist (iCalObject *o, char **str)
+{
+ int i;
+ struct {
+ char first_letter, second_letter;
+ int index;
+ } days [] = {
+ { 'S', 'U', 0 },
+ { 'M', 'O', 1 },
+ { 'T', 'U', 2 },
+ { 'W', 'E', 3 },
+ { 'T', 'H', 4 },
+ { 'F', 'R', 5 },
+ { 'S', 'A', 6 }
+ };
+
+ ignore_space (str);
+ do {
+ for (i = 0; i < 7; i++){
+ if (**str == days [i].first_letter && *(*str+1) == days [i].second_letter){
+ o->recur->weekday |= 1 << i;
+ *str += 2;
+ if (**str == ' ')
+ (*str)++;
+ }
+ }
+ } while (isalpha (**str));
+}
+
static void
+ocurrencelist (iCalObject *o, char **str)
+{
+ char *p, *q;
+ int value = 0;
+
+ ignore_space (str);
+ p = *str;
+ if (!isdigit (*str))
+ return;
+
+ if (!(*p >= '1' && *p <= '5'))
+ return;
+
+ if (!(*(p+1) == '+' || *(p+1) == '-'))
+ return;
+
+ o->recur->u.month_pos = (*p-'0') * (*(p+1) == '+' ? 1 : -1);
+ *str += 2;
+}
+
+static void
+daynumber (iCalObject *o, char **str)
+{
+ int val = 0;
+ char *p = *str;
+
+ ignore_space (str);
+ if (strcmp (p, "LD")){
+ o->recur->u.month_day = DAY_LASTDAY;
+ *str += 2;
+ return;
+ }
+
+ if (!(isdigit (*p)))
+ return;
+
+ while (**str && isdigit (**str)){
+ val = val * 10 + (**str - '0');
+ *str++;
+ }
+
+ if (**str == '+')
+ *str++;
+
+ if (**str == '-')
+ val *= -1;
+ o->recur->u.month_day = val;
+}
+
+static void
+daynumberlist (iCalObject *o, char **str)
+{
+ int first = 0;
+ int val = 0;
+
+ ignore_space (str);
+
+ while (**str){
+ if (!isdigit (**str))
+ return;
+ while (**str && isdigit (**str))
+ val = 10 * val + (**str - '0');
+ if (!first){
+ o->recur->u.month_day = val;
+ first = 1;
+ val = 0;
+ }
+ }
+}
+
+static void
+load_recur_weekly (iCalObject *o, char **str)
+{
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_pos (iCalObject *o, char **str)
+{
+ ocurrencelist (o, str);
+ weekdaylist (o, str);
+}
+
+static void
+load_recur_monthly_day (iCalObject *o, char **str)
+{
+ daynumberlist (o, str);
+}
+
+static void
+load_recur_yearly_month (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple months and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+load_recur_yearly_day (iCalObject *o, char **str)
+{
+ /* Skip as we do not support multiple days and we do expect
+ * the dtstart to agree with the value on this field
+ */
+ skip_numbers (str);
+}
+
+static void
+duration (iCalObject *o, char **str)
+{
+ int duration = 0;
+
+ ignore_space (str);
+ if (**str != '#')
+ return;
+ while (**str && isdigit (**str))
+ duration = duration * 10 + (**str - '0');
+
+ o->recur->temp_duration = duration;
+}
+
+static void
+enddate (iCalObject *o, char **str)
+{
+ ignore_space (str);
+ if (isdigit (**str)){
+ o->recur->enddate = time_from_isodate (*str);
+ *str += 16;
+ }
+}
+
+static int
load_recurrence (iCalObject *o, char *str)
{
+ char c;
+ enum RecurType type;
+ int interval = 0;
+
+ type = -1;
+ switch (*str++){
+ case 'D':
+ type = RECUR_DAILY;
+ break;
+
+ case 'W':
+ type = RECUR_WEEKLY;
+ break;
+
+ case 'M':
+ if (*str == 'P')
+ type = RECUR_MONTHLY_BY_POS;
+ else if (*str == 'D')
+ type = RECUR_MONTHLY_BY_DAY;
+ str++;
+ break;
+
+ case 'Y':
+ if (*str == 'M')
+ type = RECUR_YEARLY_BY_MONTH;
+ else if (*str == 'D')
+ type = RECUR_YEARLY_BY_DAY;
+ str++;
+ break;
+ }
+ if (type == -1)
+ return 0;
+ o->recur = g_new0 (Recurrence, 1);
+ o->recur->type = type;
+ ignore_space (&str);
+
+ /* Get the interval */
+ while (*str && isdigit (*str))
+ interval = interval * 10 + (*str-'0');
+ o->recur->interval = interval;
+
+ ignore_space (&str);
+
+ switch (type){
+ case RECUR_WEEKLY:
+ load_recur_weekly (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_POS:
+ load_recur_monthly_pos (o, &str);
+ break;
+ case RECUR_MONTHLY_BY_DAY:
+ load_recur_monthly_day (o, &str);
+ break;
+ case RECUR_YEARLY_BY_MONTH:
+ load_recur_yearly_month (o, &str);
+ break;
+ case RECUR_YEARLY_BY_DAY:
+ load_recur_yearly_day (o, &str);
+ break;
+ }
+ duration (o, &str);
+ enddate (o, &str);
+
+ return 1;
}
#define is_a_prop_of(obj,prop) isAPropertyOf (obj,prop)
@@ -133,6 +393,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
iCalObject *ical;
VObject *vo;
VObjectIterator i;
+ int syntax_error;
ical = g_new0 (iCalObject, 1);
@@ -181,7 +442,7 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* exdate */
if (has (o, VCExpDateProp))
- ical->exdate = set_list (str_val (vo), ",");
+ ical->exdate = set_date_list (str_val (vo));
/* description/comment */
if (has (o, VCDescriptionProp))
@@ -254,8 +515,13 @@ ical_object_create_from_vobject (VObject *o, const char *object_name)
/* FIXME: rrule */
if (has (o, VCRRuleProp))
- load_recurrence (ical, str_val (vo));
-
+ syntax_error = load_recurrence (ical, str_val (vo)) == 0;
+
+ if (syntax_error){
+ ical_object_destroy (ical);
+ return NULL;
+ }
+
return ical;
}
diff --git a/calendar/pcs/calobj.h b/calendar/pcs/calobj.h
index 7dc810b459..9287332d40 100644
--- a/calendar/pcs/calobj.h
+++ b/calendar/pcs/calobj.h
@@ -79,10 +79,21 @@ enum RecurType {
RECUR_YEARLY_BY_DAY,
};
+#define DAY_LASTDAY 10000
+
typedef struct {
enum RecurType type;
- int frequency;
+ int interval;
+ time_t enddate;
+ int weekday;
+
+ union {
+ int month_pos;
+ int month_day;
+ } u;
+
+ int temp_duration; /* Used temporarly, we compute enddate */
} Recurrence;
/* Flags to indicate what has changed in an object */