diff options
-rw-r--r-- | calendar/ChangeLog | 35 | ||||
-rw-r--r-- | calendar/cal-util/cal-recur.c | 34 | ||||
-rw-r--r-- | calendar/cal-util/cal-recur.h | 3 | ||||
-rw-r--r-- | calendar/gui/alarm-notify/notify-main.c | 2 | ||||
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.c | 51 | ||||
-rw-r--r-- | calendar/gui/e-itip-control.c | 180 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-file.c | 64 |
7 files changed, 294 insertions, 75 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 5085c80150..abcd2b6455 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,38 @@ +2003-02-05 Dan Winship <danw@ximian.com> + + * cal-util/cal-recur.c (cal_recur_nth): array of localized month + day names ("1st" - "31st") + + * gui/dialogs/recurrence-page.c (make_recur_month_num_submenu, + make_recur_month_num_menu, month_num_menu_selection_done_cb): Use + the new cal_recur_nth[] array. The way this was done before didn't + localize properly. + + * gui/alarm-notify/notify-main.c (main): + s/glade_gnome_init/glade_init/ + + From evolution-1-2-branch: + + * gui/e-itip-control.c (write_recurrence_piece): Describe + recurrences, if we can. #30993 + (set_date_label): If the meeting has recurrences, call + write_recurrence_piece after writing the start and end dates. + (write_label_piece): Wrap the timezone in <font size=-1> to + de-emphasize it a bit and try to keep the timestamp on a single + line even with big Outlook timezone names. Add an option to show + just the date, for describing the end of recurrences (since the + time in the UNTIL is the *beginning* of the last instance, which + would confuse people). + (update_item): Set the VCALENDAR's METHOD. + (ok_clicked_cb): Use update_item, not remove_item, to process a + cancelation. Part of #33875. + + * pcs/cal-backend-file.c (cal_backend_file_cancel_object): New, + handle an ICAL_METHOD_CANCEL update. + (cal_backend_file_update_objects): Call + cal_backend_file_update_object or cal_backend_file_cancel_object + as appropriate. + 2003-02-04 Hans Petter Jansson <hpj@ximian.com> * gui/e-meeting-time-sel.c diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c index e050004031..214c642f45 100644 --- a/calendar/cal-util/cal-recur.c +++ b/calendar/cal-util/cal-recur.c @@ -23,6 +23,7 @@ #include <config.h> #include <stdlib.h> #include <string.h> +#include <libgnome/gnome-i18n.h> #include <cal-util/cal-recur.h> #include <cal-util/timeutil.h> @@ -3978,3 +3979,36 @@ cal_recur_set_rule_end_date (icalproperty *prop, icalproperty_add_parameter (prop, param); } +const char *cal_recur_nth[31] = { + N_("1st"), + N_("2nd"), + N_("3rd"), + N_("4th"), + N_("5th"), + N_("6th"), + N_("7th"), + N_("8th"), + N_("9th"), + N_("10th"), + N_("11th"), + N_("12th"), + N_("13th"), + N_("14th"), + N_("15th"), + N_("16th"), + N_("17th"), + N_("18th"), + N_("19th"), + N_("20th"), + N_("21st"), + N_("22nd"), + N_("23rd"), + N_("24th"), + N_("25th"), + N_("26th"), + N_("27th"), + N_("28th"), + N_("29th"), + N_("30th"), + N_("31st") +}; diff --git a/calendar/cal-util/cal-recur.h b/calendar/cal-util/cal-recur.h index 5e1e21f1f4..294107d618 100644 --- a/calendar/cal-util/cal-recur.h +++ b/calendar/cal-util/cal-recur.h @@ -63,6 +63,9 @@ void cal_recur_generate_instances (CalComponent *comp, gpointer tz_cb_data, icaltimezone *default_timezone); +/* Localized nth-day-of-month strings. (Use with _() ) */ +extern const char *cal_recur_nth[31]; + G_END_DECLS #endif diff --git a/calendar/gui/alarm-notify/notify-main.c b/calendar/gui/alarm-notify/notify-main.c index 6889029c98..2577024d3c 100644 --- a/calendar/gui/alarm-notify/notify-main.c +++ b/calendar/gui/alarm-notify/notify-main.c @@ -172,7 +172,7 @@ main (int argc, char **argv) if (!gnome_vfs_init ()) g_error (_("Could not initialize gnome-vfs")); - glade_gnome_init (); + glade_init (); factory = bonobo_generic_factory_new ("OAFIID:GNOME_Evolution_Calendar_AlarmNotify_Factory", (BonoboFactoryCallback) alarm_notify_factory_fn, NULL); diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index 162f7a9737..5902e959e7 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -40,6 +40,7 @@ #include <e-util/e-dialog-widgets.h> #include <e-util/e-time-utils.h> #include <widgets/misc/e-dateedit.h> +#include <cal-util/cal-recur.h> #include <cal-util/timeutil.h> #include "../calendar-config.h" #include "../tag-calendar.h" @@ -128,40 +129,6 @@ static const int ending_types_map[] = { -1 }; -static const char *date_suffix[] = { - N_("st"), - N_("nd"), - N_("rd"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("st"), - N_("nd"), - N_("rd"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("th"), - N_("st") -}; - /* Private part of the RecurrencePage structure */ struct _RecurrencePagePrivate { /* Component we use to expand the recurrence rules for the preview */ @@ -1004,11 +971,7 @@ make_recur_month_num_submenu (const char *title, int start, int end) submenu = gtk_menu_new (); for (i = start; i < end; i++) { - char *date; - - date = g_strdup_printf ("%d%s", i + 1, _(date_suffix[i])); - item = gtk_menu_item_new_with_label (date); - g_free (date); + item = gtk_menu_item_new_with_label (_(cal_recur_nth[i])); gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item); gtk_object_set_user_data (GTK_OBJECT (item), GINT_TO_POINTER (i + 1)); gtk_widget_show (item); @@ -1034,7 +997,6 @@ make_recur_month_num_menu (int month_index) GtkWidget *menu, *submenu, *item, *submenu_item; GtkWidget *omenu; - char *date; int i; menu = gtk_menu_new (); @@ -1047,9 +1009,7 @@ make_recur_month_num_menu (int month_index) } /* Current date */ - date = g_strdup_printf ("%d%s", month_index, _(date_suffix[month_index - 1])); - item = gtk_menu_item_new_with_label (date); - g_free (date); + item = gtk_menu_item_new_with_label (_(cal_recur_nth[month_index - 1])); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show (item); @@ -1131,7 +1091,6 @@ month_num_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) if (month_num == MONTH_NUM_OTHER) { GtkWidget *label, *item; - char *date; item = gtk_menu_get_active (GTK_MENU (menu_shell)); priv->month_index = GPOINTER_TO_INT (gtk_object_get_user_data (GTK_OBJECT (item))); @@ -1140,9 +1099,7 @@ month_num_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) e_dialog_option_menu_set (priv->month_num_menu, month_num, month_num_options_map); label = GTK_BIN (priv->month_num_menu)->child; - date = g_strdup_printf ("%d%s", priv->month_index, _(date_suffix[priv->month_index - 1])); - gtk_label_set_text (GTK_LABEL (label), date); - g_free (date); + gtk_label_set_text (GTK_LABEL (label), _(cal_recur_nth[priv->month_index - 1])); e_dialog_option_menu_set (priv->month_num_menu, 0, month_num_options_map); e_dialog_option_menu_set (priv->month_num_menu, month_num, month_num_options_map); diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 938fb3a504..0cd4e8e566 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -90,7 +90,7 @@ struct _EItipControlPrivate { extern EvolutionShellClient *global_shell_client; -/* We intentionally use "calendar" instead of "calendar/*" here. We +/* We intentionally use "calendar" instead of "calendar / *" here. We * don't want public calendars. */ static const char *calendar_types[] = { "calendar", NULL }; @@ -502,7 +502,8 @@ find_attendee (icalcomponent *ical_comp, const char *address) static void write_label_piece (EItipControl *itip, CalComponentDateTime *dt, char *buffer, int size, - const char *stext, const char *etext) + const char *stext, const char *etext, + gboolean just_date) { EItipControlPrivate *priv; struct tm tmp_tm; @@ -522,6 +523,8 @@ write_label_piece (EItipControl *itip, CalComponentDateTime *dt, } tmp_tm = icaltimetype_to_tm (dt->value); + if (just_date) + tmp_tm.tm_hour = tmp_tm.tm_min = tmp_tm.tm_sec = 0; if (stext != NULL) strcat (buffer, stext); @@ -540,23 +543,21 @@ write_label_piece (EItipControl *itip, CalComponentDateTime *dt, } /* Output timezone after time, e.g. " America/New_York". */ - if (zone) { + if (zone && !just_date) { /* Note that this returns UTF-8, since all iCalendar data is UTF-8. But it probably is not translated. */ display_name = icaltimezone_get_display_name (zone); if (display_name && *display_name) { - strcat (buffer, " "); + strcat (buffer, " <font size=-1>["); /* We check if it is one of our builtin timezone names, - in which case we call gettext to translate it, and - we need to convert to UTF-8. If it isn't a builtin - timezone name, we use it as-is, as it is already - UTF-8. */ + in which case we call gettext to translate it. */ if (icaltimezone_get_builtin_timezone (display_name)) { strcat (buffer, _(display_name)); } else { strcat (buffer, display_name); } + strcat (buffer, "]</font>"); } } @@ -564,6 +565,151 @@ write_label_piece (EItipControl *itip, CalComponentDateTime *dt, strcat (buffer, etext); } +static const char * +nth (int n) +{ + if (n == -1) + return "last"; + else if (n < 1 || n > 31) + return "?"; + else + return cal_recur_nth[n]; +} + +static const char *dayname[] = { + N_("Sunday"), + N_("Monday"), + N_("Tuesday"), + N_("Wednesday"), + N_("Thursday"), + N_("Friday"), + N_("Saturday") +}; + +static inline char * +get_dayname (struct icalrecurrencetype *r, int i) +{ + enum icalrecurrencetype_weekday day; + + day = icalrecurrencetype_day_day_of_week (r->by_day[i]); + g_return_val_if_fail (day > 0 && day < 8, "?"); + + return _(dayname[day - 1]); +} + +static void +write_recurrence_piece (EItipControl *itip, CalComponent *comp, + char *buffer, int size) +{ + GSList *rrules; + struct icalrecurrencetype *r; + int len, i; + + strcpy (buffer, "<b>Recurring:</b> "); + len = strlen (buffer); + buffer += len; + size -= len; + + if (!cal_component_has_simple_recurrence (comp)) { + strcpy (buffer, _("Yes. (Complex Recurrence)")); + return; + } + + cal_component_get_rrule_list (comp, &rrules); + g_return_if_fail (rrules && !rrules->next); + + r = rrules->data; + + switch (r->freq) { + case ICAL_DAILY_RECURRENCE: + if (r->interval == 1) + strcpy (buffer, _("Every day")); + else + sprintf (buffer, _("Every %d days"), r->interval); + break; + + case ICAL_WEEKLY_RECURRENCE: + if (r->by_day[0] == ICAL_RECURRENCE_ARRAY_MAX) { + if (r->interval == 1) + strcpy (buffer, _("Every week")); + else + sprintf (buffer, _("Every %d weeks"), r->interval); + } else { + if (r->interval == 1) + strcpy (buffer, _("Every week on ")); + else + sprintf (buffer, _("Every %d weeks on "), r->interval); + + for (i = 1; i < 8 && r->by_day[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) { + if (i > 1) + strcat (buffer, ", "); + strcat (buffer, get_dayname (r, i - 1)); + } + if (i > 1) + strcat (buffer, _(" and ")); + strcat (buffer, get_dayname (r, i - 1)); + } + break; + + case ICAL_MONTHLY_RECURRENCE: + if (r->by_month_day[0] != ICAL_RECURRENCE_ARRAY_MAX) { + sprintf (buffer, _("The %s day of "), + nth (r->by_month_day[0])); + } else { + int pos; + + /* Outlook 2000 uses BYDAY=TU;BYSETPOS=2, and will not + accept BYDAY=2TU. So we now use the same as Outlook + by default. */ + + pos = icalrecurrencetype_day_position (r->by_day[0]); + if (pos == 0) + pos = r->by_set_pos[0]; + + sprintf (buffer, _("The %s %s of "), + nth (pos), get_dayname (r, 0)); + } + + if (r->interval == 1) + strcat (buffer, _("every month")); + else { + len = strlen (buffer); + buffer += len; + size -= len; + sprintf (buffer, _("every %d months"), r->interval); + } + break; + + case ICAL_YEARLY_RECURRENCE: + if (r->interval == 1) + strcpy (buffer, _("Every year")); + else { + sprintf (buffer, _("Every %d years"), r->interval); + } + break; + + default: + g_assert_not_reached (); + } + + len = strlen (buffer); + buffer += len; + size -= len; + if (r->count) { + sprintf (buffer, _(" a total of %d times"), r->count); + } else if (!icaltime_is_null_time (r->until)) { + CalComponentDateTime dt; + + dt.value = &r->until; + dt.tzid = r->until.zone; + + write_label_piece (itip, &dt, buffer, size, + _(", ending on "), NULL, TRUE); + } + + strcat (buffer, "<br>"); +} + static void set_date_label (EItipControl *itip, GtkHTML *html, GtkHTMLStream *html_stream, CalComponent *comp) @@ -583,7 +729,7 @@ set_date_label (EItipControl *itip, GtkHTML *html, GtkHTMLStream *html_stream, if (datetime.value) { write_label_piece (itip, &datetime, buffer, 1024, _("<b>Starts:</b> "), - "<br>"); + "<br>", FALSE); gtk_html_write (html, html_stream, buffer, strlen(buffer)); wrote = TRUE; } @@ -592,20 +738,27 @@ set_date_label (EItipControl *itip, GtkHTML *html, GtkHTMLStream *html_stream, buffer[0] = '\0'; cal_component_get_dtend (comp, &datetime); if (datetime.value){ - write_label_piece (itip, &datetime, buffer, 1024, _("<b>Ends:</b> "), "<br>"); + write_label_piece (itip, &datetime, buffer, 1024, _("<b>Ends:</b> "), "<br>", FALSE); gtk_html_write (html, html_stream, buffer, strlen (buffer)); wrote = TRUE; } cal_component_free_datetime (&datetime); buffer[0] = '\0'; + if (cal_component_has_recurrences (comp)) { + write_recurrence_piece (itip, comp, buffer, 1024); + gtk_html_write (html, html_stream, buffer, strlen (buffer)); + wrote = TRUE; + } + + buffer[0] = '\0'; datetime.tzid = NULL; cal_component_get_completed (comp, &datetime.value); if (type == CAL_COMPONENT_TODO && datetime.value) { /* Pass TRUE as is_utc, so it gets converted to the current timezone. */ datetime.value->is_utc = TRUE; - write_label_piece (itip, &datetime, buffer, 1024, _("<b>Completed:</b> "), "<br>"); + write_label_piece (itip, &datetime, buffer, 1024, _("<b>Completed:</b> "), "<br>", FALSE); gtk_html_write (html, html_stream, buffer, strlen (buffer)); wrote = TRUE; task_completed = TRUE; @@ -615,7 +768,7 @@ set_date_label (EItipControl *itip, GtkHTML *html, GtkHTMLStream *html_stream, buffer[0] = '\0'; cal_component_get_due (comp, &datetime); if (type == CAL_COMPONENT_TODO && !task_completed && datetime.value) { - write_label_piece (itip, &datetime, buffer, 1024, _("<b>Due:</b> "), "<br>"); + write_label_piece (itip, &datetime, buffer, 1024, _("<b>Due:</b> "), "<br>", FALSE); gtk_html_write (html, html_stream, buffer, strlen (buffer)); wrote = TRUE; } @@ -1625,6 +1778,7 @@ update_item (EItipControl *itip) clone = icalcomponent_new_clone (priv->ical_comp); icalcomponent_add_component (priv->top_level, clone); + icalcomponent_set_method (priv->top_level, priv->method); result = cal_client_update_objects (client, priv->top_level); switch (result) { @@ -2011,7 +2165,7 @@ ok_clicked_cb (GtkHTML *html, const gchar *method, const gchar *url, const gchar send_item (itip); break; case 'C': - remove_item (itip); + update_item (itip); break; } } diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index f73ab66874..dc253c0001 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -1529,7 +1529,31 @@ cal_backend_file_update_object (CalBackendFile *cbfile, return comp_uid; } +static const char* +cal_backend_file_cancel_object (CalBackendFile *cbfile, + icalcomponent *icalcomp) +{ + CalComponent *old_comp; + icalproperty *uid; + const char *comp_uid; + + /* Get the UID, and check it isn't empty. */ + uid = icalcomponent_get_first_property (icalcomp, ICAL_UID_PROPERTY); + if (!uid) + return NULL; + comp_uid = icalproperty_get_uid (uid); + if (!comp_uid || !comp_uid[0]) + return NULL; + + /* Find the old version of the component. */ + old_comp = lookup_component (cbfile, comp_uid); + if (!old_comp) + return NULL; + /* And remove it */ + remove_component (cbfile, old_comp); + return comp_uid; +} /* Update_objects handler for the file backend. */ static CalBackendResult @@ -1539,9 +1563,10 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) CalBackendFilePrivate *priv; icalcomponent *toplevel_comp, *icalcomp = NULL; icalcomponent_kind kind; + icalproperty_method method; icalcomponent *subcomp; CalBackendResult retval = CAL_BACKEND_RESULT_SUCCESS; - GList *comp_uid_list = NULL, *elem; + GList *updated_uids = NULL, *removed_uids = NULL, *elem; cbfile = CAL_BACKEND_FILE (backend); priv = cbfile->priv; @@ -1573,6 +1598,8 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) return CAL_BACKEND_RESULT_INVALID_OBJECT; } + method = icalcomponent_get_method (toplevel_comp); + /* Step throught the VEVENT/VTODOs being added, create CalComponents for them, and add them to our cache. */ subcomp = icalcomponent_get_first_component (toplevel_comp, @@ -1586,18 +1613,20 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) || child_kind == ICAL_VJOURNAL_COMPONENT) { const char *comp_uid; - comp_uid = cal_backend_file_update_object (cbfile, - subcomp); - if (comp_uid) { - /* We add a copy of the UID to a list, so we - can emit notification signals later. We do - a g_strdup() in case any of the components - get removed while we are emitting - notification signals. */ - comp_uid_list = g_list_prepend (comp_uid_list, - g_strdup (comp_uid)); + if (method == ICAL_METHOD_CANCEL) { + comp_uid = cal_backend_file_cancel_object (cbfile, subcomp); + if (comp_uid) { + removed_uids = g_list_prepend (removed_uids, + g_strdup (comp_uid)); + } else + retval = CAL_BACKEND_RESULT_NOT_FOUND; } else { - retval = CAL_BACKEND_RESULT_INVALID_OBJECT; + comp_uid = cal_backend_file_update_object (cbfile, subcomp); + if (comp_uid) { + updated_uids = g_list_prepend (updated_uids, + g_strdup (comp_uid)); + } else + retval = CAL_BACKEND_RESULT_INVALID_OBJECT; } } subcomp = icalcomponent_get_next_component (toplevel_comp, @@ -1613,12 +1642,19 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj) /* Now emit notification signals for all of the added components. We do this after adding them all to make sure the calendar is in a stable state before emitting signals. */ - for (elem = comp_uid_list; elem; elem = elem->next) { + for (elem = updated_uids; elem; elem = elem->next) { char *comp_uid = elem->data; cal_backend_notify_update (backend, comp_uid); g_free (comp_uid); } - g_list_free (comp_uid_list); + g_list_free (updated_uids); + + for (elem = removed_uids; elem; elem = elem->next) { + char *comp_uid = elem->data; + cal_backend_notify_remove (backend, comp_uid); + g_free (comp_uid); + } + g_list_free (removed_uids); return retval; } |