aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--calendar/ChangeLog35
-rw-r--r--calendar/cal-util/cal-recur.c34
-rw-r--r--calendar/cal-util/cal-recur.h3
-rw-r--r--calendar/gui/alarm-notify/notify-main.c2
-rw-r--r--calendar/gui/dialogs/recurrence-page.c51
-rw-r--r--calendar/gui/e-itip-control.c180
-rw-r--r--calendar/pcs/cal-backend-file.c64
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;
}