diff options
author | Arturo Espinosa <unammx@src.gnome.org> | 1998-04-14 13:24:38 +0800 |
---|---|---|
committer | Arturo Espinosa <unammx@src.gnome.org> | 1998-04-14 13:24:38 +0800 |
commit | 3161696e57f03b5ebc859907725f6836f4220667 (patch) | |
tree | 8b1e9f1b509ce5e6343407af8cd7db1d5b8155b8 /calendar | |
parent | 49a388705e5085a963c3c1b5cdcd324af5d8b1b5 (diff) | |
download | gsoc2013-evolution-3161696e57f03b5ebc859907725f6836f4220667.tar.gz 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.c | 272 | ||||
-rw-r--r-- | calendar/cal-util/calobj.h | 13 | ||||
-rw-r--r-- | calendar/calobj.c | 272 | ||||
-rw-r--r-- | calendar/calobj.h | 13 | ||||
-rw-r--r-- | calendar/eventedit.c | 78 | ||||
-rw-r--r-- | calendar/gui/eventedit.c | 78 | ||||
-rw-r--r-- | calendar/pcs/calobj.c | 272 | ||||
-rw-r--r-- | calendar/pcs/calobj.h | 13 |
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 */ |