diff options
Diffstat (limited to 'calendar/gui/event-editor.c')
-rw-r--r-- | calendar/gui/event-editor.c | 3377 |
1 files changed, 0 insertions, 3377 deletions
diff --git a/calendar/gui/event-editor.c b/calendar/gui/event-editor.c deleted file mode 100644 index c96c94dadd..0000000000 --- a/calendar/gui/event-editor.c +++ /dev/null @@ -1,3377 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ - -/* Evolution calendar - Event editor dialog - * - * Copyright (C) 2000 Helix Code, Inc. - * Copyright (C) 2001 Ximian, Inc. - * - * Authors: Miguel de Icaza <miguel@ximian.com> - * Federico Mena-Quintero <federico@ximian.com> - * Seth Alves <alves@hungry.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - */ - -#include <config.h> -#include <string.h> -#include <glade/glade.h> -#include <gal/widgets/e-unicode.h> -#include <gal/widgets/e-categories.h> -#include <libgnomeui/gnome-propertybox.h> -#include <libgnome/gnome-i18n.h> - -#include "calendar-config.h" -#include "cal-util/timeutil.h" -#include "dialogs/delete-comp.h" -#include "dialogs/save-comp.h" -#include "e-meeting-edit.h" -#include "e-util/e-dialog-widgets.h" -#include "event-editor.h" -#include "tag-calendar.h" -#include "weekday-picker.h" -#include "widgets/misc/e-dateedit.h" -#include "widget-util.h" - -enum {BEFORE, AFTER}; -enum {MINUTES, HOURS, DAYS}; - -/* Reminder maps */ -static const int reminder_action_map[] = { - CAL_ALARM_DISPLAY, - CAL_ALARM_AUDIO, - CAL_ALARM_EMAIL, - CAL_ALARM_PROCEDURE, - -1 -}; - -static const int reminder_value_map[] = { - MINUTES, - HOURS, - DAYS, - -1 -}; - -static const int reminder_relative_map[] = { - BEFORE, - AFTER, - -1 -}; - -static const int reminder_time_map[] = { - CAL_ALARM_TRIGGER_RELATIVE_START, - CAL_ALARM_TRIGGER_RELATIVE_END, - -1 -}; - -/* Recurrence maps */ -static const int recur_freq_map[] = { - ICAL_DAILY_RECURRENCE, - ICAL_WEEKLY_RECURRENCE, - ICAL_MONTHLY_RECURRENCE, - ICAL_YEARLY_RECURRENCE, - -1 -}; - -enum month_day_options { - MONTH_DAY_NTH, - MONTH_DAY_MON, - MONTH_DAY_TUE, - MONTH_DAY_WED, - MONTH_DAY_THU, - MONTH_DAY_FRI, - MONTH_DAY_SAT, - MONTH_DAY_SUN -}; - -static const int month_day_options_map[] = { - MONTH_DAY_NTH, - MONTH_DAY_MON, - MONTH_DAY_TUE, - MONTH_DAY_WED, - MONTH_DAY_THU, - MONTH_DAY_FRI, - MONTH_DAY_SAT, - MONTH_DAY_SUN, - -1 -}; - -/* Row data for the reminders */ -typedef enum {NEW_ALARM, EXISTING_ALARM} ReminderStatus; - -typedef struct { - ReminderStatus status; - CalComponentAlarm *alarm; -} ReminderData; - -struct _EventEditorPrivate { - /* Glade XML data */ - GladeXML *xml; - - /* Client to use */ - CalClient *client; - - /* Calendar object/uid we are editing; this is an internal copy */ - CalComponent *comp; - - /* Widgets from the Glade file */ - - GtkWidget *app; - - GtkWidget *general_summary; - - GtkWidget *start_time; - GtkWidget *end_time; - GtkWidget *all_day_event; - - GtkWidget *description; - - GtkWidget *classification_public; - GtkWidget *classification_private; - GtkWidget *classification_confidential; - - GtkWidget *contacts; - GtkWidget *contacts_btn; - - GtkWidget *categories; - GtkWidget *categories_btn; - - GtkWidget *reminder_summary; - GtkWidget *reminder_starting_date; - - GtkWidget *reminder_list; - GtkWidget *reminder_add; - GtkWidget *reminder_delete; - - GtkWidget *reminder_action; - GtkWidget *reminder_interval_value; - GtkWidget *reminder_value_units; - GtkWidget *reminder_relative; - GtkWidget *reminder_time; - - GtkWidget *recurrence_summary; - GtkWidget *recurrence_starting_date; - - GtkWidget *recurrence_none; - GtkWidget *recurrence_simple; - GtkWidget *recurrence_custom; - - GtkWidget *recurrence_params; - GtkWidget *recurrence_interval_value; - GtkWidget *recurrence_interval_unit; - GtkWidget *recurrence_special; - GtkWidget *recurrence_ending_menu; - GtkWidget *recurrence_ending_special; - GtkWidget *recurrence_custom_warning_bin; - - /* For weekly recurrences, created by hand */ - GtkWidget *recurrence_weekday_picker; - guint8 recurrence_weekday_day_mask; - guint8 recurrence_weekday_blocked_day_mask; - - /* For monthly recurrences, created by hand */ - GtkWidget *recurrence_month_index_spin; - int recurrence_month_index; - - GtkWidget *recurrence_month_day_menu; - enum month_day_options recurrence_month_day; - - /* For ending date, created by hand */ - GtkWidget *recurrence_ending_date_edit; - time_t recurrence_ending_date; - - /* For ending count of occurrences, created by hand */ - GtkWidget *recurrence_ending_count_spin; - int recurrence_ending_count; - - /* More widgets from the Glade file */ - - GtkWidget *recurrence_exception_date; - GtkWidget *recurrence_exception_list; - GtkWidget *recurrence_exception_add; - GtkWidget *recurrence_exception_modify; - GtkWidget *recurrence_exception_delete; - - GtkWidget *recurrence_preview_bin; - - /* For the recurrence preview, the actual widget */ - GtkWidget *recurrence_preview_calendar; - - /* Call event_editor_set_changed() to set this to TRUE when any field - in the dialog is changed. When the user closes the dialog we will - prompt to save changes. */ - gboolean changed; -}; - - - -static void event_editor_class_init (EventEditorClass *class); -static void event_editor_init (EventEditor *ee); -static void event_editor_destroy (GtkObject *object); - -static GtkObjectClass *parent_class; - - -static void append_reminder (EventEditor *ee, CalComponentAlarm *alarm, ReminderStatus status); -static void append_exception (EventEditor *ee, time_t t); -static void check_all_day (EventEditor *ee); -static void set_all_day (GtkWidget *toggle, EventEditor *ee); -static void date_changed_cb (EDateEdit *dedit, gpointer data); -static void preview_recur (EventEditor *ee); -static void recur_to_comp_object (EventEditor *ee, CalComponent *comp); -static void reminder_to_comp_object (EventEditor *ee, CalComponent *comp); -static void reminder_add_cb (GtkWidget *widget, EventEditor *ee); -static void reminder_delete_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_add_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_modify_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_delete_cb (GtkWidget *widget, EventEditor *ee); -static void recurrence_exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, - gpointer data); -static void field_changed (GtkWidget *widget, - EventEditor *ee); -static void event_editor_set_changed (EventEditor *ee, - gboolean changed); -static gboolean prompt_to_save_changes (EventEditor *ee); -static void categories_clicked (GtkWidget *button, EventEditor *ee); - - - -/** - * event_editor_get_type: - * - * Registers the #EventEditor class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #EventEditor class. - **/ -GtkType -event_editor_get_type (void) -{ - static GtkType event_editor_type = 0; - - if (!event_editor_type) { - static const GtkTypeInfo event_editor_info = { - "EventEditor", - sizeof (EventEditor), - sizeof (EventEditorClass), - (GtkClassInitFunc) event_editor_class_init, - (GtkObjectInitFunc) event_editor_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - event_editor_type = gtk_type_unique (GTK_TYPE_OBJECT, &event_editor_info); - } - - return event_editor_type; -} - -/* Class initialization function for the event editor */ -static void -event_editor_class_init (EventEditorClass *class) -{ - GtkObjectClass *object_class; - - object_class = (GtkObjectClass *) class; - - parent_class = gtk_type_class (GTK_TYPE_OBJECT); - - object_class->destroy = event_editor_destroy; -} - -/* Object initialization function for the event editor */ -static void -event_editor_init (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = g_new0 (EventEditorPrivate, 1); - ee->priv = priv; - - event_editor_set_changed (ee, FALSE); -} - -/* Frees the rows and the row data in the recurrence exceptions GtkCList */ -static void -free_exception_clist_data (GtkCList *clist) -{ - int i; - - for (i = 0; i < clist->rows; i++) { - gpointer data; - - data = gtk_clist_get_row_data (clist, i); - g_free (data); - gtk_clist_set_row_data (clist, i, NULL); - } - - gtk_clist_clear (clist); -} - -/* Destroy handler for the event editor */ -static void -event_editor_destroy (GtkObject *object) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_EVENT_EDITOR (object)); - - ee = EVENT_EDITOR (object); - priv = ee->priv; - - free_exception_clist_data (GTK_CLIST (priv->recurrence_exception_list)); - - if (priv->app) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->app), ee); - gtk_widget_destroy (priv->app); - priv->app = NULL; - } - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), ee); - gtk_object_unref (GTK_OBJECT (priv->client)); - priv->client = NULL; - } - - if (priv->xml) { - gtk_object_unref (GTK_OBJECT (priv->xml)); - priv->xml = NULL; - } - - g_free (priv); - ee->priv = NULL; - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -/* Creates an appropriate title for the event editor dialog */ -static char * -make_title_from_comp (CalComponent *comp) -{ - char *title; - const char *type_string; - CalComponentVType type; - CalComponentText text; - - if (!comp) - return g_strdup (_("Edit Appointment")); - - type = cal_component_get_vtype (comp); - switch (type) { - case CAL_COMPONENT_EVENT: - type_string = _("Appointment - %s"); - break; - case CAL_COMPONENT_TODO: - type_string = _("Task - %s"); - break; - case CAL_COMPONENT_JOURNAL: - type_string = _("Journal entry - %s"); - break; - default: - g_message ("make_title_from_comp(): Cannot handle object of type %d", type); - return NULL; - } - - cal_component_get_summary (comp, &text); - if (text.value) { - char *summary; - summary = e_utf8_to_locale_string (text.value); - title = g_strdup_printf (type_string, summary); - g_free (summary); - } else - title = g_strdup_printf (type_string, _("No summary")); - - return title; -} - -/* Sets the event editor's window title from a calendar component */ -static void -set_title_from_comp (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv = ee->priv; - char *title; - - title = make_title_from_comp (comp); - gtk_window_set_title (GTK_WINDOW (priv->app), title); - g_free (title); -} - -/* Callback used when the recurrence weekday picker changes */ -static void -recur_weekday_picker_changed_cb (WeekdayPicker *wp, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for weekly recurrences */ -static void -make_recur_weekly_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - WeekdayPicker *wp; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_special)->child == NULL); - g_assert (priv->recurrence_weekday_picker == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_special), hbox); - - label = gtk_label_new (_("on")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - wp = WEEKDAY_PICKER (weekday_picker_new ()); - - priv->recurrence_weekday_picker = GTK_WIDGET (wp); - gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (wp), FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the weekdays */ - - weekday_picker_set_week_start_day (wp, calendar_config_get_week_start_day ()); - weekday_picker_set_days (wp, priv->recurrence_weekday_day_mask); - weekday_picker_set_blocked_days (wp, priv->recurrence_weekday_blocked_day_mask); - - gtk_signal_connect (GTK_OBJECT (wp), "changed", - GTK_SIGNAL_FUNC (recur_weekday_picker_changed_cb), ee); -} - -/* Creates the option menu for the monthly recurrence days */ -static GtkWidget * -make_recur_month_menu (void) -{ - static const char *options[] = { - N_("day"), - N_("Monday"), - N_("Tuesday"), - N_("Wednesday"), - N_("Thursday"), - N_("Friday"), - N_("Saturday"), - N_("Sunday") - }; - - GtkWidget *menu; - GtkWidget *omenu; - int i; - - menu = gtk_menu_new (); - - for (i = 0; i < sizeof (options) / sizeof (options[0]); i++) { - GtkWidget *item; - - item = gtk_menu_item_new_with_label (_(options[i])); - gtk_menu_append (GTK_MENU (menu), item); - gtk_widget_show (item); - } - - omenu = gtk_option_menu_new (); - gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu); - - return omenu; -} - -/* For monthly recurrences, changes the valid range of the recurrence day index - * spin button; e.g. month days are 1-31 while the valid range for a Sunday is - * the 1st through 5th of the month. - */ -static void -adjust_day_index_spin (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkAdjustment *adj; - enum month_day_options month_day; - - priv = ee->priv; - - g_assert (priv->recurrence_month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->recurrence_month_day_menu)); - g_assert (priv->recurrence_month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_month_index_spin)); - - month_day = e_dialog_option_menu_get (priv->recurrence_month_day_menu, month_day_options_map); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_month_index_spin)); - - switch (month_day) { - case MONTH_DAY_NTH: - adj->upper = 31; - gtk_adjustment_changed (adj); - break; - - case MONTH_DAY_MON: - case MONTH_DAY_TUE: - case MONTH_DAY_WED: - case MONTH_DAY_THU: - case MONTH_DAY_FRI: - case MONTH_DAY_SAT: - case MONTH_DAY_SUN: - adj->upper = 5; - gtk_adjustment_changed (adj); - - if (adj->value > 5) { - adj->value = 5; - gtk_adjustment_value_changed (adj); - } - - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when the monthly day selection menu changes. We need to change - * the valid range of the day index spin button; e.g. days are 1-31 while a - * Sunday is the 1st through 5th. - */ -static void -month_day_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - adjust_day_index_spin (ee); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Callback used when the month index value changes. */ -static void -recur_month_index_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for monthly recurrences */ -static void -make_recur_monthly_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_special)->child == NULL); - g_assert (priv->recurrence_month_index_spin == NULL); - g_assert (priv->recurrence_month_day_menu == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_special), hbox); - - label = gtk_label_new (_("on the")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 31, 1, 10, 10)); - priv->recurrence_month_index_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_month_index_spin, FALSE, FALSE, 0); - - label = gtk_label_new (_("th")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - priv->recurrence_month_day_menu = make_recur_month_menu (); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_month_day_menu, FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the options */ - - e_dialog_spin_set (priv->recurrence_month_index_spin, priv->recurrence_month_index); - e_dialog_option_menu_set (priv->recurrence_month_day_menu, - priv->recurrence_month_day, - month_day_options_map); - adjust_day_index_spin (ee); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_month_index_value_changed_cb), ee); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_month_day_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (month_day_menu_selection_done_cb), ee); -} - -/* Changes the recurrence-special widget to match the interval units. - * - * For daily recurrences: nothing. - * For weekly recurrences: weekday selector. - * For monthly recurrences: "on the" <nth> [day, Weekday] - * For yearly recurrences: nothing. - */ -static void -make_recurrence_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - icalrecurrencetype_frequency frequency; - - priv = ee->priv; - - if (GTK_BIN (priv->recurrence_special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->recurrence_special)->child); - - priv->recurrence_weekday_picker = NULL; - priv->recurrence_month_index_spin = NULL; - priv->recurrence_month_day_menu = NULL; - } - - frequency = e_dialog_option_menu_get (priv->recurrence_interval_unit, recur_freq_map); - - switch (frequency) { - case ICAL_DAILY_RECURRENCE: - gtk_widget_hide (priv->recurrence_special); - break; - - case ICAL_WEEKLY_RECURRENCE: - make_recur_weekly_special (ee); - gtk_widget_show (priv->recurrence_special); - break; - - case ICAL_MONTHLY_RECURRENCE: - make_recur_monthly_special (ee); - gtk_widget_show (priv->recurrence_special); - break; - - case ICAL_YEARLY_RECURRENCE: - gtk_widget_hide (priv->recurrence_special); - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when the ending-until date editor changes */ -static void -recur_ending_until_changed_cb (EDateEdit *de, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for "ending until" (end date) recurrences */ -static void -make_recur_ending_until_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - EDateEdit *de; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_ending_special)->child == NULL); - g_assert (priv->recurrence_ending_date_edit == NULL); - - /* Create the widget */ - - priv->recurrence_ending_date_edit = date_edit_new (TRUE, FALSE); - de = E_DATE_EDIT (priv->recurrence_ending_date_edit); - - gtk_container_add (GTK_CONTAINER (priv->recurrence_ending_special), GTK_WIDGET (de)); - gtk_widget_show_all (GTK_WIDGET (de)); - - /* Set the value */ - - e_date_edit_set_time (de, priv->recurrence_ending_date); - - gtk_signal_connect (GTK_OBJECT (de), "changed", - GTK_SIGNAL_FUNC (recur_ending_until_changed_cb), ee); -} - -/* Callback used when the ending-count value changes */ -static void -recur_ending_count_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Creates the special contents for the occurrence count case */ -static void -make_recur_ending_count_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - - priv = ee->priv; - - g_assert (GTK_BIN (priv->recurrence_ending_special)->child == NULL); - g_assert (priv->recurrence_ending_count_spin == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->recurrence_ending_special), hbox); - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 10000, 1, 10, 10)); - priv->recurrence_ending_count_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->recurrence_ending_count_spin, FALSE, FALSE, 0); - - label = gtk_label_new (_("occurrences")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the values */ - - e_dialog_spin_set (priv->recurrence_ending_count_spin, - priv->recurrence_ending_count); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_ending_count_value_changed_cb), ee); -} - -enum ending_type { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER -}; - -static const int ending_types_map[] = { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER, - -1 -}; - -/* Changes the recurrence-ending-special widget to match the ending date option. - * - * For: <n> [days, weeks, months, years, occurrences] - * Until: <date selector> - * Forever: nothing. - */ -static void -make_recurrence_ending_special (EventEditor *ee) -{ - EventEditorPrivate *priv; - enum ending_type ending_type; - - priv = ee->priv; - - if (GTK_BIN (priv->recurrence_ending_special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->recurrence_ending_special)->child); - - priv->recurrence_ending_date_edit = NULL; - priv->recurrence_ending_count_spin = NULL; - } - - ending_type = e_dialog_option_menu_get (priv->recurrence_ending_menu, ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - make_recur_ending_count_special (ee); - gtk_widget_show (priv->recurrence_ending_special); - break; - - case ENDING_UNTIL: - make_recur_ending_until_special (ee); - gtk_widget_show (priv->recurrence_ending_special); - break; - - case ENDING_FOREVER: - gtk_widget_hide (priv->recurrence_ending_special); - break; - - default: - g_assert_not_reached (); - } -} - -enum recur_type { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM -}; - -static const int recur_type_map[] = { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM, - -1 -}; - -/* Sensitizes the recurrence widgets based on the state of the recurrence type - * radio group. - */ -static void -sensitize_recur_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - enum recur_type type; - GtkWidget *label; - - priv = ee->priv; - - type = e_dialog_radio_get (priv->recurrence_none, recur_type_map); - - if (GTK_BIN (priv->recurrence_custom_warning_bin)->child) - gtk_widget_destroy (GTK_BIN (priv->recurrence_custom_warning_bin)->child); - - switch (type) { - case RECUR_NONE: - gtk_widget_set_sensitive (priv->recurrence_params, FALSE); - gtk_widget_show (priv->recurrence_params); - gtk_widget_hide (priv->recurrence_custom_warning_bin); - break; - - case RECUR_SIMPLE: - gtk_widget_set_sensitive (priv->recurrence_params, TRUE); - gtk_widget_show (priv->recurrence_params); - gtk_widget_hide (priv->recurrence_custom_warning_bin); - break; - - case RECUR_CUSTOM: - gtk_widget_set_sensitive (priv->recurrence_params, FALSE); - gtk_widget_hide (priv->recurrence_params); - - label = gtk_label_new (_("This appointment contains recurrences that Evolution " - "cannot edit.")); - gtk_container_add (GTK_CONTAINER (priv->recurrence_custom_warning_bin), label); - gtk_widget_show_all (priv->recurrence_custom_warning_bin); - break; - - default: - g_assert_not_reached (); - } -} - -/* Callback used when one of the recurrence type radio buttons is toggled. We - * enable or the recurrence parameters. - */ -static void -recurrence_type_toggled_cb (GtkToggleButton *toggle, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - - event_editor_set_changed (ee, TRUE); - - if (toggle->active) { - sensitize_recur_widgets (ee); - preview_recur (ee); - } -} - -/* Callback used when the recurrence interval value spin button changes. */ -static void -recur_interval_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - preview_recur (ee); -} - -/* Callback used when the recurrence interval option menu changes. We need to - * change the contents of the recurrence special widget. - */ -static void -recur_interval_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - make_recurrence_special (ee); - preview_recur (ee); -} - -/* Callback used when the recurrence ending option menu changes. We need to - * change the contents of the ending special widget. - */ -static void -recur_ending_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - event_editor_set_changed (ee, TRUE); - make_recurrence_ending_special (ee); - preview_recur (ee); -} - -/* Gets the widgets from the XML file and returns if they are all available. - * For the widgets whose values can be simply set with e-dialog-utils, it does - * that as well. - */ -static gboolean -get_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - -#define GW(name) glade_xml_get_widget (priv->xml, name) - - priv->app = GW ("event-editor-dialog"); - - priv->general_summary = GW ("general-summary"); - - priv->start_time = GW ("start-time"); - priv->end_time = GW ("end-time"); - priv->all_day_event = GW ("all-day-event"); - - priv->description = GW ("description"); - - priv->classification_public = GW ("classification-public"); - priv->classification_private = GW ("classification-private"); - priv->classification_confidential = GW ("classification-confidential"); - - priv->contacts_btn = GW ("contacts-button"); - priv->contacts = GW ("contacts"); - - priv->categories_btn = GW ("categories-button"); - priv->categories = GW ("categories"); - - priv->reminder_summary = GW ("reminder-summary"); - priv->reminder_starting_date = GW ("reminder-starting-date"); - - priv->reminder_list = GW ("reminder-list"); - priv->reminder_add = GW ("reminder-add"); - priv->reminder_delete = GW ("reminder-delete"); - - priv->reminder_action = GW ("reminder-action"); - priv->reminder_interval_value = GW ("reminder-interval-value"); - priv->reminder_value_units = GW ("reminder-value-units"); - priv->reminder_relative = GW ("reminder-relative"); - priv->reminder_time = GW ("reminder-time"); - - priv->recurrence_summary = GW ("recurrence-summary"); - priv->recurrence_starting_date = GW ("recurrence-starting-date"); - - priv->recurrence_none = GW ("recurrence-none"); - priv->recurrence_simple = GW ("recurrence-simple"); - priv->recurrence_custom = GW ("recurrence-custom"); - priv->recurrence_params = GW ("recurrence-params"); - - priv->recurrence_interval_value = GW ("recurrence-interval-value"); - priv->recurrence_interval_unit = GW ("recurrence-interval-unit"); - priv->recurrence_special = GW ("recurrence-special"); - priv->recurrence_ending_menu = GW ("recurrence-ending-menu"); - priv->recurrence_ending_special = GW ("recurrence-ending-special"); - priv->recurrence_custom_warning_bin = GW ("recurrence-custom-warning-bin"); - - priv->recurrence_exception_date = GW ("recurrence-exception-date"); - priv->recurrence_exception_list = GW ("recurrence-exception-list"); - priv->recurrence_exception_add = GW ("recurrence-exception-add"); - priv->recurrence_exception_modify = GW ("recurrence-exception-modify"); - priv->recurrence_exception_delete = GW ("recurrence-exception-delete"); - - priv->recurrence_preview_bin = GW ("recurrence-preview-bin"); - -#undef GW - - return (priv->app - && priv->general_summary - && priv->start_time - && priv->end_time - && priv->all_day_event - && priv->description - && priv->classification_public - && priv->classification_private - && priv->classification_confidential - && priv->contacts_btn - && priv->contacts - && priv->categories_btn - && priv->categories - && priv->reminder_summary - && priv->reminder_starting_date - && priv->reminder_list - && priv->reminder_add - && priv->reminder_delete - && priv->reminder_action - && priv->reminder_interval_value - && priv->reminder_value_units - && priv->reminder_relative - && priv->reminder_time - && priv->recurrence_summary - && priv->recurrence_starting_date - && priv->recurrence_none - && priv->recurrence_simple - && priv->recurrence_custom - && priv->recurrence_params - && priv->recurrence_interval_value - && priv->recurrence_interval_unit - && priv->recurrence_special - && priv->recurrence_ending_menu - && priv->recurrence_ending_special - && priv->recurrence_custom_warning_bin - && priv->recurrence_exception_date - && priv->recurrence_exception_list - && priv->recurrence_exception_add - && priv->recurrence_exception_modify - && priv->recurrence_exception_delete - && priv->recurrence_preview_bin); -} - -/* Syncs the contents of two entry widgets, while blocking signals from each - * other. - */ -static void -sync_entries (EventEditor *ee, GtkEditable *source, GtkEditable *dest) -{ - char *str; - - gtk_signal_handler_block_by_data (GTK_OBJECT (dest), ee); - - str = gtk_editable_get_chars (source, 0, -1); - gtk_entry_set_text (GTK_ENTRY (dest), str); - g_free (str); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (dest), ee); -} - -/* Syncs the contents of two date editor widgets, while blocking signals on the - * specified data. - */ -static void -sync_date_edits (EventEditor *ee, EDateEdit *source, EDateEdit *dest) -{ - time_t t; - - gtk_signal_handler_block_by_data (GTK_OBJECT (dest), ee); - - t = e_date_edit_get_time (source); - e_date_edit_set_time (dest, t); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (dest), ee); -} - -/* Callback used when one of the general or recurrence summary entries change; - * we sync the other entry to it. - */ -static void -summary_changed_cb (GtkEditable *editable, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - if (editable != GTK_EDITABLE (priv->general_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->general_summary)); - if (editable != GTK_EDITABLE (priv->reminder_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->reminder_summary)); - if (editable != GTK_EDITABLE (priv->recurrence_summary)) - sync_entries (ee, editable, GTK_EDITABLE (priv->recurrence_summary)); -} - -/* Callback used when one of the general or recurrence starting date widgets - * change; we sync the other date editor to it. - */ -static void -start_date_changed_cb (EDateEdit *de, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - if (de != E_DATE_EDIT (priv->start_time)) - sync_date_edits (ee,de, E_DATE_EDIT (priv->start_time)); - if (de != E_DATE_EDIT (priv->reminder_starting_date)) - sync_date_edits (ee, de, E_DATE_EDIT (priv->reminder_starting_date)); - if (de != E_DATE_EDIT (priv->recurrence_starting_date)) - sync_date_edits (ee, de, E_DATE_EDIT (priv->recurrence_starting_date)); -} - -/* Callback used when the displayed date range in the recurrence preview - * calendar changes. - */ -static void -recur_preview_date_range_changed_cb (ECalendarItem *item, gpointer data) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (data); - preview_recur (ee); -} - -/* Hooks the widget signals */ -static void -init_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkWidget *menu; - GtkAdjustment *adj; - ECalendar *ecal; - - priv = ee->priv; - - /* Summary in the main, reminder and recurrence pages */ - gtk_signal_connect (GTK_OBJECT (priv->general_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_summary), "changed", - GTK_SIGNAL_FUNC (summary_changed_cb), ee); - - /* Categories button */ - gtk_signal_connect (GTK_OBJECT (priv->categories_btn), "clicked", - GTK_SIGNAL_FUNC (categories_clicked), ee); - - /* Start dates in the main and recurrence pages */ - - gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_starting_date), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_starting_date), "changed", - GTK_SIGNAL_FUNC (start_date_changed_cb), ee); - - /* Start and end times */ - - gtk_signal_connect (GTK_OBJECT (priv->start_time), "changed", - GTK_SIGNAL_FUNC (date_changed_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->end_time), "changed", - GTK_SIGNAL_FUNC (date_changed_cb), ee); - - gtk_signal_connect (GTK_OBJECT (priv->all_day_event), "toggled", - GTK_SIGNAL_FUNC (set_all_day), ee); - - /* Reminder buttons */ - - gtk_signal_connect (GTK_OBJECT (priv->reminder_add), "clicked", - GTK_SIGNAL_FUNC (reminder_add_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->reminder_delete), "clicked", - GTK_SIGNAL_FUNC (reminder_delete_cb), ee); - - /* Recurrence preview */ - - priv->recurrence_preview_calendar = e_calendar_new (); - ecal = E_CALENDAR (priv->recurrence_preview_calendar); - gtk_signal_connect (GTK_OBJECT (ecal->calitem), "date_range_changed", - GTK_SIGNAL_FUNC (recur_preview_date_range_changed_cb), ee); - calendar_config_configure_e_calendar (ecal); - e_calendar_item_set_max_days_sel (ecal->calitem, 0); - gtk_container_add (GTK_CONTAINER (priv->recurrence_preview_bin), - priv->recurrence_preview_calendar); - gtk_widget_show (priv->recurrence_preview_calendar); - - /* Recurrence types */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_none), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_simple), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_custom), "toggled", - GTK_SIGNAL_FUNC (recurrence_type_toggled_cb), ee); - - /* Recurrence interval */ - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (recur_interval_value_changed_cb), ee); - - /* Recurrence units */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (recur_interval_selection_done_cb), ee); - - /* Recurrence ending */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (recur_ending_selection_done_cb), ee); - - /* Exception buttons */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_add), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_add_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_modify), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_modify_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_delete), "clicked", - GTK_SIGNAL_FUNC (recurrence_exception_delete_cb), ee); - - /* Selections in the exceptions list */ - - gtk_signal_connect (GTK_OBJECT (priv->recurrence_exception_list), "select_row", - GTK_SIGNAL_FUNC (recurrence_exception_select_row_cb), ee); - - /* - * Connect the default signal handler to use to make sure the "changed" - * field gets set whenever a field is changed. - */ - - /* Appointment Page */ - gtk_signal_connect (GTK_OBJECT (priv->general_summary), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->description), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_public), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_private), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->classification_confidential), "toggled", - GTK_SIGNAL_FUNC (field_changed), ee); - gtk_signal_connect (GTK_OBJECT (priv->categories), "changed", - GTK_SIGNAL_FUNC (field_changed), ee); - - /* FIXME: we do not support these fields yet, so we disable them */ - - gtk_widget_set_sensitive (priv->contacts_btn, FALSE); - gtk_widget_set_sensitive (priv->contacts, FALSE); -} - -static const int classification_map[] = { - CAL_COMPONENT_CLASS_PUBLIC, - CAL_COMPONENT_CLASS_PRIVATE, - CAL_COMPONENT_CLASS_CONFIDENTIAL, - -1 -}; - -static const int month_pos_map[] = { 0, 1, 2, 3, 4, -1 }; -static const int weekday_map[] = { 0, 1, 2, 3, 4, 5, 6, -1 }; - -/* Fills the widgets with default values */ -static void -clear_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t now; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = ee->priv; - - now = time (NULL); - - /* Summary, description */ - - e_dialog_editable_set (priv->general_summary, NULL); /* will also change recur summary */ - e_dialog_editable_set (priv->description, NULL); - - /* Start and end times */ - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), now); /* will set recur start too */ - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), now); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - check_all_day (ee); - - /* Classification */ - - e_dialog_radio_set (priv->classification_public, - CAL_COMPONENT_CLASS_PRIVATE, classification_map); - - /* Recurrences */ - - priv->recurrence_weekday_day_mask = 0; - - priv->recurrence_month_index = 1; - priv->recurrence_month_day = MONTH_DAY_NTH; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_none, RECUR_NONE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), ee); - e_dialog_spin_set (priv->recurrence_interval_value, 1); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), ee); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_DAILY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - priv->recurrence_ending_date = time (NULL); - priv->recurrence_ending_count = 1; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_ending_menu, ENDING_FOREVER, - ending_types_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - /* Exceptions list */ - - free_exception_clist_data (GTK_CLIST (priv->recurrence_exception_list)); -} - -/* Fills the recurrence ending date widgets with the values from the calendar - * component. - */ -static void -fill_ending_date (EventEditor *ee, struct icalrecurrencetype *r) -{ - EventEditorPrivate *priv; - GtkWidget *menu; - - priv = ee->priv; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - - if (r->count == 0) { - if (r->until.year == 0) { - /* Forever */ - - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_FOREVER, - ending_types_map); - } else { - /* Ending date */ - - priv->recurrence_ending_date = icaltime_as_timet (r->until); - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_UNTIL, - ending_types_map); - } - } else { - /* Count of occurrences */ - - priv->recurrence_ending_count = r->count; - e_dialog_option_menu_set (priv->recurrence_ending_menu, - ENDING_FOR, - ending_types_map); - } - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - - make_recurrence_ending_special (ee); -} - -/* Counts the number of elements in the by_xxx fields of an icalrecurrencetype */ -static int -count_by_xxx (short *field, int max_elements) -{ - int i; - - for (i = 0; i < max_elements; i++) - if (field[i] == ICAL_RECURRENCE_ARRAY_MAX) - break; - - return i; -} - -/* Re-tags the recurrence preview calendar based on the current information of - * the event editor. - */ -static void -preview_recur (EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponent *comp; - CalComponentDateTime cdt; - GSList *l; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - /* Create a scratch component with the start/end and - * recurrence/excepttion information from the one we are editing. - */ - - comp = cal_component_new (); - cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); - - cal_component_get_dtstart (priv->comp, &cdt); - cal_component_set_dtstart (comp, &cdt); - cal_component_free_datetime (&cdt); - - cal_component_get_dtend (priv->comp, &cdt); - cal_component_set_dtend (comp, &cdt); - cal_component_free_datetime (&cdt); - - cal_component_get_exdate_list (priv->comp, &l); - cal_component_set_exdate_list (comp, l); - cal_component_free_exdate_list (l); - - cal_component_get_exrule_list (priv->comp, &l); - cal_component_set_exrule_list (comp, l); - cal_component_free_recur_list (l); - - cal_component_get_rdate_list (priv->comp, &l); - cal_component_set_rdate_list (comp, l); - cal_component_free_period_list (l); - - cal_component_get_rrule_list (priv->comp, &l); - cal_component_set_rrule_list (comp, l); - cal_component_free_recur_list (l); - - recur_to_comp_object (ee, comp); - - tag_calendar_by_comp (E_CALENDAR (priv->recurrence_preview_calendar), comp); - gtk_object_unref (GTK_OBJECT (comp)); -} - -/* Fills in the exception widgets with the data from the calendar component */ -static void -fill_exception_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GSList *list, *l; - gboolean added; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - /* Exceptions list */ - - cal_component_get_exdate_list (priv->comp, &list); - - added = FALSE; - - for (l = list; l; l = l->next) { - CalComponentDateTime *cdt; - time_t ext; - - added = TRUE; - - cdt = l->data; - ext = icaltime_as_timet (*cdt->value); - append_exception (ee, ext); - } - - cal_component_free_exdate_list (list); - - if (added) - gtk_clist_select_row (GTK_CLIST (priv->recurrence_exception_list), 0, 0); -} - -/* Computes a weekday mask for the start day of a calendar component, for use in - * a WeekdayPicker widget. - */ -static guint8 -get_start_weekday_mask (CalComponent *comp) -{ - CalComponentDateTime dt; - guint8 retval; - - cal_component_get_dtstart (comp, &dt); - - if (dt.value) { - time_t t; - struct tm tm; - - t = icaltime_as_timet (*dt.value); - tm = *localtime (&t); - - retval = 0x1 << tm.tm_wday; - } else - retval = 0; - - cal_component_free_datetime (&dt); - - return retval; -} - -/* Sets some sane defaults for the data sources for the recurrence special - * widgets, even if they will not be used immediately. - */ -static void -set_recur_special_defaults (EventEditor *ee) -{ - EventEditorPrivate *priv; - guint8 mask; - - priv = ee->priv; - - mask = get_start_weekday_mask (priv->comp); - - priv->recurrence_weekday_day_mask = mask; - priv->recurrence_weekday_blocked_day_mask = mask; -} - -static char * -get_alarm_duration_string (struct icaldurationtype *duration) -{ - GString *string = g_string_new (NULL); - char *ret; - - if (duration->days > 1) - g_string_sprintf (string, _(" %d days"), duration->days); - else if (duration->days == 1) - g_string_append (string, _(" 1 day")); - - if (duration->weeks > 1) - g_string_sprintf (string, _(" %d weeks"), duration->weeks); - else if (duration->weeks == 1) - g_string_append (string, _(" 1 week")); - - if (duration->hours > 1) - g_string_sprintf (string, _(" %d hours"), duration->hours); - else if (duration->hours == 1) - g_string_append (string, _(" 1 hour")); - - if (duration->minutes > 1) - g_string_sprintf (string, _(" %d minutes"), duration->minutes); - else if (duration->minutes == 1) - g_string_append (string, _(" 1 minute")); - - if (duration->seconds > 1) - g_string_sprintf (string, _(" %d seconds"), duration->seconds); - else if (duration->seconds == 1) - g_string_append (string, _(" 1 second")); - - ret = string->str; - g_string_free (string, FALSE); - - return ret; -} - -static char * -get_alarm_string (CalComponentAlarm *alarm) -{ - CalAlarmAction action; - CalAlarmTrigger trigger; - char string[256]; - char *dur; - - string [0] = '\0'; - - cal_component_alarm_get_action (alarm, &action); - cal_component_alarm_get_trigger (alarm, &trigger); - - switch (action) { - case CAL_ALARM_AUDIO: - strcat (string, _("Play a sound")); - break; - case CAL_ALARM_DISPLAY: - strcat (string, _("Show a dialog")); - break; - case CAL_ALARM_EMAIL: - strcat (string, _("Send an email")); - break; - case CAL_ALARM_PROCEDURE: - strcat (string, _("Run a program")); - break; - case CAL_ALARM_NONE: - case CAL_ALARM_UNKNOWN: - strcat (string, _("Unknown")); - break; - } - - switch (trigger.type) { - case CAL_ALARM_TRIGGER_RELATIVE_START: - dur = get_alarm_duration_string (&trigger.u.rel_duration); - strcat (string, dur); - g_free (dur); - - if (trigger.u.rel_duration.is_neg) - strcat (string, _(" before start of appointment")); - else - strcat (string, _(" after start of appointment")); - break; - case CAL_ALARM_TRIGGER_RELATIVE_END: - dur = get_alarm_duration_string (&trigger.u.rel_duration); - strcat (string, dur); - g_free (dur); - - if (trigger.u.rel_duration.is_neg) - strcat (string, _(" before end of appointment")); - else - strcat (string, _(" after end of appointment")); - break; - case CAL_ALARM_TRIGGER_NONE: - case CAL_ALARM_TRIGGER_ABSOLUTE: - strcat (string, _("Unknown")); - break; - } - - return g_strdup (string); -} - -static void -fill_reminder_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GList *alarms, *l; - GtkCList *clist; - - int row = 0; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - if (!cal_component_has_alarms (priv->comp)) - return; - - alarms = cal_component_get_alarm_uids (priv->comp); - - clist = GTK_CLIST (priv->reminder_list); - for (l = alarms; l != NULL; l = l->next, row++) { - CalComponentAlarm *ca = cal_component_get_alarm (priv->comp, l->data); - - /* Add it to the clist */ - append_reminder (ee, ca, EXISTING_ALARM); - } - cal_obj_uid_list_free (alarms); -} - -/* Fills in the recurrence widgets with the values from the calendar component. - * This function is particularly tricky because it has to discriminate between - * recurrences we support for editing and the ones we don't. We only support at - * most one recurrence rule; no rdates or exrules (exdates are handled just fine - * elsewhere). - */ -static void -fill_recurrence_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - GSList *rrule_list; - int len; - struct icalrecurrencetype *r; - int n_by_second, n_by_minute, n_by_hour; - int n_by_day, n_by_month_day, n_by_year_day; - int n_by_week_no, n_by_month, n_by_set_pos; - GtkWidget *menu; - GtkAdjustment *adj; - - priv = ee->priv; - g_assert (priv->comp != NULL); - - fill_exception_widgets (ee); - - /* Set up defaults for the special widgets */ - - set_recur_special_defaults (ee); - - /* No recurrences? */ - - if (!cal_component_has_rdates (priv->comp) - && !cal_component_has_rrules (priv->comp) - && !cal_component_has_exrules (priv->comp)) { - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_none, RECUR_NONE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, FALSE); - - sensitize_recur_widgets (ee); - preview_recur (ee); - return; - } - - /* See if it is a custom set we don't support */ - - cal_component_get_rrule_list (priv->comp, &rrule_list); - len = g_slist_length (rrule_list); - if (len > 1 - || cal_component_has_rdates (priv->comp) - || cal_component_has_exrules (priv->comp)) - goto custom; - - /* Down to one rule, so test that one */ - - g_assert (len == 1); - r = rrule_list->data; - - /* Any funky frequency? */ - - if (r->freq == ICAL_SECONDLY_RECURRENCE - || r->freq == ICAL_MINUTELY_RECURRENCE - || r->freq == ICAL_HOURLY_RECURRENCE) - goto custom; - - /* Any funky shit? */ - -#define N_HAS_BY(field) (count_by_xxx (field, sizeof (field) / sizeof (field[0]))) - - n_by_second = N_HAS_BY (r->by_second); - n_by_minute = N_HAS_BY (r->by_minute); - n_by_hour = N_HAS_BY (r->by_hour); - n_by_day = N_HAS_BY (r->by_day); - n_by_month_day = N_HAS_BY (r->by_month_day); - n_by_year_day = N_HAS_BY (r->by_year_day); - n_by_week_no = N_HAS_BY (r->by_week_no); - n_by_month = N_HAS_BY (r->by_month); - n_by_set_pos = N_HAS_BY (r->by_set_pos); - - if (n_by_second != 0 - || n_by_minute != 0 - || n_by_hour != 0) - goto custom; - - /* Filter the funky shit based on the frequency; if there is nothing - * weird we can actually set the widgets. - */ - - switch (r->freq) { - case ICAL_DAILY_RECURRENCE: - if (n_by_day != 0 - || n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_DAILY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - case ICAL_WEEKLY_RECURRENCE: { - int i; - guint8 day_mask; - - if (n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - day_mask = 0; - - for (i = 0; i < 8 && r->by_day[i] != ICAL_RECURRENCE_ARRAY_MAX; i++) { - enum icalrecurrencetype_weekday weekday; - int pos; - - weekday = icalrecurrencetype_day_day_of_week (r->by_day[i]); - pos = icalrecurrencetype_day_position (r->by_day[i]); - - if (pos != 0) - goto custom; - - switch (weekday) { - case ICAL_SUNDAY_WEEKDAY: - day_mask |= 1 << 0; - break; - - case ICAL_MONDAY_WEEKDAY: - day_mask |= 1 << 1; - break; - - case ICAL_TUESDAY_WEEKDAY: - day_mask |= 1 << 2; - break; - - case ICAL_WEDNESDAY_WEEKDAY: - day_mask |= 1 << 3; - break; - - case ICAL_THURSDAY_WEEKDAY: - day_mask |= 1 << 4; - break; - - case ICAL_FRIDAY_WEEKDAY: - day_mask |= 1 << 5; - break; - - case ICAL_SATURDAY_WEEKDAY: - day_mask |= 1 << 6; - break; - - default: - break; - } - } - - priv->recurrence_weekday_day_mask = day_mask; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_WEEKLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - } - - case ICAL_MONTHLY_RECURRENCE: - if (n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - if (n_by_month_day == 1) { - int nth; - - nth = r->by_month_day[0]; - if (nth < 1) - goto custom; - - priv->recurrence_month_index = nth; - priv->recurrence_month_day = MONTH_DAY_NTH; - } else if (n_by_day == 1) { - enum icalrecurrencetype_weekday weekday; - int pos; - enum month_day_options month_day; - - weekday = icalrecurrencetype_day_day_of_week (r->by_day[0]); - pos = icalrecurrencetype_day_position (r->by_day[0]); - - if (pos < 1) - goto custom; - - switch (weekday) { - case ICAL_MONDAY_WEEKDAY: - month_day = MONTH_DAY_MON; - break; - - case ICAL_TUESDAY_WEEKDAY: - month_day = MONTH_DAY_TUE; - break; - - case ICAL_WEDNESDAY_WEEKDAY: - month_day = MONTH_DAY_WED; - break; - - case ICAL_THURSDAY_WEEKDAY: - month_day = MONTH_DAY_THU; - break; - - case ICAL_FRIDAY_WEEKDAY: - month_day = MONTH_DAY_FRI; - break; - - case ICAL_SATURDAY_WEEKDAY: - month_day = MONTH_DAY_SAT; - break; - - case ICAL_SUNDAY_WEEKDAY: - month_day = MONTH_DAY_SUN; - break; - - default: - goto custom; - } - - priv->recurrence_month_index = pos; - priv->recurrence_month_day = month_day; - } else - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_MONTHLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - case ICAL_YEARLY_RECURRENCE: - if (n_by_day != 0 - || n_by_month_day != 0 - || n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos != 0) - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->recurrence_interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), ee); - e_dialog_option_menu_set (priv->recurrence_interval_unit, ICAL_YEARLY_RECURRENCE, - recur_freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), ee); - break; - - default: - goto custom; - } - - /* If we got here it means it is a simple recurrence */ - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_simple, RECUR_SIMPLE, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, FALSE); - - sensitize_recur_widgets (ee); - make_recurrence_special (ee); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->recurrence_interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), ee); - e_dialog_spin_set (priv->recurrence_interval_value, r->interval); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), ee); - - fill_ending_date (ee, r); - - goto out; - - custom: - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - e_dialog_radio_set (priv->recurrence_custom, RECUR_CUSTOM, recur_type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_none), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_simple), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->recurrence_custom), ee); - - gtk_widget_set_sensitive (priv->recurrence_custom, TRUE); - sensitize_recur_widgets (ee); - - out: - - cal_component_free_recur_list (rrule_list); - preview_recur (ee); -} - -/* Fills in the widgets with the value from the calendar component */ -static void -fill_widgets (EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponentText text; - CalComponentClassification cl; - CalComponentDateTime d; - GSList *l; - time_t dtstart, dtend; - const char *categories; - - priv = ee->priv; - - clear_widgets (ee); - - if (!priv->comp) - return; - - /* Summary, description(s) */ - - cal_component_get_summary (priv->comp, &text); - e_dialog_editable_set (priv->general_summary, text.value); /* will also set recur summary */ - - cal_component_get_description_list (priv->comp, &l); - if (l) { - text = *(CalComponentText *)l->data; - e_dialog_editable_set (priv->description, text.value); - } - cal_component_free_text_list (l); - - /* Start and end times */ - - /* All-day events are inclusive, i.e. if the end date shown is 2nd Feb - then the event includes all of the 2nd Feb. We would normally show - 3rd Feb as the end date, since it really ends at midnight on 3rd, - so we have to subtract a day so we only show the 2nd. */ - cal_component_get_dtstart (priv->comp, &d); - dtstart = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - cal_component_get_dtend (priv->comp, &d); - dtend = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - if (time_day_begin (dtstart) == dtstart - && time_day_begin (dtend) == dtend) { - dtend = time_add_day (dtend, -1); - } - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->reminder_starting_date), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_starting_date), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), dtend); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - check_all_day (ee); - - /* Classification */ - - cal_component_get_classification (priv->comp, &cl); - - switch (cl) { - case CAL_COMPONENT_CLASS_PUBLIC: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PUBLIC, - classification_map); - case CAL_COMPONENT_CLASS_PRIVATE: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_PRIVATE, - classification_map); - case CAL_COMPONENT_CLASS_CONFIDENTIAL: - e_dialog_radio_set (priv->classification_public, CAL_COMPONENT_CLASS_CONFIDENTIAL, - classification_map); - default: - /* What do do? We can't g_assert_not_reached() since it is a - * value from an external file. - */ - } - - /* Categories */ - cal_component_get_categories (priv->comp, &categories); - e_dialog_editable_set (priv->categories, categories); - - /* Reminders */ - fill_reminder_widgets (ee); - - /* Recurrences */ - fill_recurrence_widgets (ee); - - /* Do this last, since the callbacks will set it to TRUE. */ - event_editor_set_changed (ee, FALSE); -} - - -/** - * event_editor_update_widgets: - * @ee: An event editor. - * - * Causes an event editor dialog to re-read the values of its calendar component - * object. This function should be used if the #CalComponent is changed by - * external means while it is open in the editor. - **/ -void -event_editor_update_widgets (EventEditor *ee) -{ - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - fill_widgets (ee); -} - - - -/* Decode the radio button group for classifications */ -static CalComponentClassification -classification_get (GtkWidget *widget) -{ - return e_dialog_radio_get (widget, classification_map); -} - -/* Encondes a position/weekday pair into the proper format for - * icalrecurrencetype.by_day. - */ -static short -nth_weekday (int pos, icalrecurrencetype_weekday weekday) -{ - g_assert (pos > 0 && pos <= 5); - - return (pos << 3) | (int) weekday; -} - -static void -reminder_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - GtkCList *reminder_list; - ReminderData *rdata; - int i; - - priv = ee->priv; - - reminder_list = GTK_CLIST (priv->reminder_list); - for (i = 0; i < reminder_list->rows; i++) { - rdata = gtk_clist_get_row_data (reminder_list, i); - if (rdata->status == NEW_ALARM) - cal_component_add_alarm (priv->comp, rdata->alarm); - g_free (rdata); - } -} - -/* Gets the simple recurrence data from the recurrence widgets and stores it in - * the calendar component object. - */ -static void -simple_recur_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - struct icalrecurrencetype r; - GSList l; - enum ending_type ending_type; - - priv = ee->priv; - - icalrecurrencetype_clear (&r); - - /* Frequency, interval, week start */ - - r.freq = e_dialog_option_menu_get (priv->recurrence_interval_unit, recur_freq_map); - r.interval = e_dialog_spin_get_int (priv->recurrence_interval_value); - r.week_start = ICAL_SUNDAY_WEEKDAY + calendar_config_get_week_start_day (); - - /* Frequency-specific data */ - - switch (r.freq) { - case ICAL_DAILY_RECURRENCE: - /* Nothing else is required */ - break; - - case ICAL_WEEKLY_RECURRENCE: { - guint8 day_mask; - int i; - - g_assert (GTK_BIN (priv->recurrence_special)->child != NULL); - g_assert (priv->recurrence_weekday_picker != NULL); - g_assert (IS_WEEKDAY_PICKER (priv->recurrence_weekday_picker)); - - day_mask = weekday_picker_get_days (WEEKDAY_PICKER (priv->recurrence_weekday_picker)); - - i = 0; - - if (day_mask & (1 << 0)) - r.by_day[i++] = ICAL_SUNDAY_WEEKDAY; - - if (day_mask & (1 << 1)) - r.by_day[i++] = ICAL_MONDAY_WEEKDAY; - - if (day_mask & (1 << 2)) - r.by_day[i++] = ICAL_TUESDAY_WEEKDAY; - - if (day_mask & (1 << 3)) - r.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY; - - if (day_mask & (1 << 4)) - r.by_day[i++] = ICAL_THURSDAY_WEEKDAY; - - if (day_mask & (1 << 5)) - r.by_day[i++] = ICAL_FRIDAY_WEEKDAY; - - if (day_mask & (1 << 6)) - r.by_day[i++] = ICAL_SATURDAY_WEEKDAY; - - break; - } - - case ICAL_MONTHLY_RECURRENCE: { - int day_index; - enum month_day_options month_day; - - g_assert (GTK_BIN (priv->recurrence_special)->child != NULL); - g_assert (priv->recurrence_month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_month_index_spin)); - g_assert (priv->recurrence_month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->recurrence_month_day_menu)); - - day_index = e_dialog_spin_get_int (priv->recurrence_month_index_spin); - month_day = e_dialog_option_menu_get (priv->recurrence_month_day_menu, - month_day_options_map); - - switch (month_day) { - case MONTH_DAY_NTH: - r.by_month_day[0] = day_index; - break; - - case MONTH_DAY_MON: - r.by_day[0] = nth_weekday (day_index, ICAL_MONDAY_WEEKDAY); - break; - - case MONTH_DAY_TUE: - r.by_day[0] = nth_weekday (day_index, ICAL_TUESDAY_WEEKDAY); - break; - - case MONTH_DAY_WED: - r.by_day[0] = nth_weekday (day_index, ICAL_WEDNESDAY_WEEKDAY); - break; - - case MONTH_DAY_THU: - r.by_day[0] = nth_weekday (day_index, ICAL_THURSDAY_WEEKDAY); - break; - - case MONTH_DAY_FRI: - r.by_day[0] = nth_weekday (day_index, ICAL_FRIDAY_WEEKDAY); - break; - - case MONTH_DAY_SAT: - r.by_day[0] = nth_weekday (day_index, ICAL_SATURDAY_WEEKDAY); - break; - - case MONTH_DAY_SUN: - r.by_day[0] = nth_weekday (day_index, ICAL_SUNDAY_WEEKDAY); - break; - - default: - g_assert_not_reached (); - } - - break; - } - - case ICAL_YEARLY_RECURRENCE: - /* Nothing else is required */ - break; - - default: - g_assert_not_reached (); - } - - /* Ending date */ - - ending_type = e_dialog_option_menu_get (priv->recurrence_ending_menu, ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - g_assert (priv->recurrence_ending_count_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->recurrence_ending_count_spin)); - - r.count = e_dialog_spin_get_int (priv->recurrence_ending_count_spin); - break; - - case ENDING_UNTIL: - g_assert (priv->recurrence_ending_date_edit != NULL); - g_assert (E_IS_DATE_EDIT (priv->recurrence_ending_date_edit)); - - r.until = icaltime_from_timet ( - e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_ending_date_edit)), - TRUE); - break; - - case ENDING_FOREVER: - /* Nothing to be done */ - break; - - default: - g_assert_not_reached (); - } - - /* Set the recurrence */ - - l.data = &r; - l.next = NULL; - - cal_component_set_rrule_list (comp, &l); -} - -/* Gets the data from the recurrence widgets and stores it in the calendar - * component object. - */ -static void -recur_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - enum recur_type recur_type; - GtkCList *exception_list; - GSList *list; - int i; - - priv = ee->priv; - - recur_type = e_dialog_radio_get (priv->recurrence_none, recur_type_map); - - switch (recur_type) { - case RECUR_NONE: - cal_component_set_rdate_list (comp, NULL); - cal_component_set_rrule_list (comp, NULL); - cal_component_set_exrule_list (comp, NULL); - break; - - case RECUR_SIMPLE: - cal_component_set_rdate_list (comp, NULL); - cal_component_set_exrule_list (comp, NULL); - simple_recur_to_comp_object (ee, comp); - break; - - case RECUR_CUSTOM: - /* We just keep whatever the component has currently */ - break; - - default: - g_assert_not_reached (); - } - - /* Set exceptions */ - - list = NULL; - exception_list = GTK_CLIST (priv->recurrence_exception_list); - for (i = 0; i < exception_list->rows; i++) { - CalComponentDateTime *cdt; - time_t *tim; - - cdt = g_new (CalComponentDateTime, 1); - cdt->value = g_new (struct icaltimetype, 1); - cdt->tzid = NULL; - - tim = gtk_clist_get_row_data (exception_list, i); - g_assert (tim != NULL); - *cdt->value = icaltime_from_timet (*tim, FALSE); - - list = g_slist_prepend (list, cdt); - } - - cal_component_set_exdate_list (comp, list); - cal_component_free_exdate_list (list); -} - -/* Gets the data from the widgets and stores it in the calendar component object */ -static void -dialog_to_comp_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - CalComponentDateTime date; - time_t t; - gboolean all_day_event; - char *cat, *str; - - priv = ee->priv; - - /* Summary */ - - str = e_dialog_editable_get (priv->general_summary); - if (!str || strlen (str) == 0) - cal_component_set_summary (comp, NULL); - else { - CalComponentText text; - - text.value = str; - text.altrep = NULL; - - cal_component_set_summary (comp, &text); - } - - if (str) - g_free (str); - - /* Description */ - - str = e_dialog_editable_get (priv->description); - if (!str || strlen (str) == 0) - cal_component_set_description_list (comp, NULL); - else { - GSList l; - CalComponentText text; - - text.value = str; - text.altrep = NULL; - l.data = &text; - l.next = NULL; - - cal_component_set_description_list (comp, &l); - } - - if (str) - g_free (str); - - /* Dates */ - - date.value = g_new (struct icaltimetype, 1); - date.tzid = NULL; - - t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtstart (comp, &date); - } else { - /* FIXME: What do we do here? */ - } - - /* If the all_day toggle is set, the end date is inclusive of the - entire day on which it points to. */ - all_day_event = e_dialog_toggle_get (priv->all_day_event); - t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - if (t != -1) { - if (all_day_event) - t = time_day_end (t); - - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtend (comp, &date); - } else { - /* FIXME: What do we do here? */ - } - g_free (date.value); - - /* Categories */ - cat = e_dialog_editable_get (priv->categories); - cal_component_set_categories (comp, cat); - - if (cat) - g_free (cat); - - cal_component_set_classification (comp, classification_get (priv->classification_public)); - - /* Reminder information */ - reminder_to_comp_object (ee, comp); - - /* Recurrence information */ - recur_to_comp_object (ee, comp); - - cal_component_commit_sequence (comp); -} - -/* Fills the calendar component object from the data in the widgets and commits - * the component to the storage. - */ -static void -save_event_object (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - if (!priv->comp) - return; - - dialog_to_comp_object (ee, priv->comp); - set_title_from_comp (ee, priv->comp); - - if (!cal_client_update_object (priv->client, priv->comp)) - g_message ("save_event_object(): Could not update the object!"); - else - event_editor_set_changed (ee, FALSE); -} - -/* Closes the dialog box and emits the appropriate signals */ -static void -close_dialog (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - g_assert (priv->app != NULL); - - gtk_object_destroy (GTK_OBJECT (ee)); -} - - - -/* Callback used when the dialog box is "applied" */ -static void -ee_apply_event_cb (GtkWidget *widget, gint page_num, gpointer data) -{ - EventEditor *ee; - - g_return_if_fail (IS_EVENT_EDITOR (data)); - - ee = EVENT_EDITOR (data); - - if (page_num != -1) - return; - - save_event_object (ee); -} - -/* Callback used when the dialog box is destroyed */ -static gint -ee_close_event_cb (GtkWidget *widget, gpointer data) -{ - EventEditor *ee; - - g_return_val_if_fail (IS_EVENT_EDITOR (data), TRUE); - - ee = EVENT_EDITOR (data); - - if (prompt_to_save_changes (ee)) - close_dialog (ee); - - return TRUE; -} - -/* Callback used when the dialog box is destroyed */ -static gint -ee_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - EventEditor *ee; - - g_return_val_if_fail (IS_EVENT_EDITOR (data), TRUE); - - ee = EVENT_EDITOR (data); - - if (prompt_to_save_changes (ee)) - close_dialog (ee); - - return TRUE; -} - -/** - * event_editor_construct: - * @ee: An event editor. - * - * Constructs an event editor by loading its Glade data. - * - * Return value: The same object as @ee, or NULL if the widgets could not be - * created. In the latter case, the event editor will automatically be - * destroyed. - **/ -EventEditor * -event_editor_construct (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_val_if_fail (ee != NULL, NULL); - g_return_val_if_fail (IS_EVENT_EDITOR (ee), NULL); - - priv = ee->priv; - - /* Load the content widgets */ - - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR "/event-editor-dialog.glade", NULL); - if (!priv->xml) { - g_message ("event_editor_construct(): Could not load the Glade XML file!"); - goto error; - } - - if (!get_widgets (ee)) { - g_message ("event_editor_construct(): Could not find all widgets in the XML file!"); - goto error; - } - - init_widgets (ee); - - /* Hook to destruction of the dialog */ - gtk_signal_connect (GTK_OBJECT (priv->app), "apply", - GTK_SIGNAL_FUNC (ee_apply_event_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->app), "close", - GTK_SIGNAL_FUNC (ee_close_event_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->app), "delete_event", - GTK_SIGNAL_FUNC (ee_delete_event_cb), ee); - - /* Add focus to the summary entry */ - gtk_widget_grab_focus (GTK_WIDGET (priv->general_summary)); - - return ee; - - error: - - gtk_object_unref (GTK_OBJECT (ee)); - return NULL; -} - -/** - * event_editor_new: - * - * Creates a new event editor dialog. - * - * Return value: A newly-created event editor dialog, or NULL if the event - * editor could not be created. - **/ -EventEditor * -event_editor_new (void) -{ - EventEditor *ee; - - ee = EVENT_EDITOR (gtk_type_new (TYPE_EVENT_EDITOR)); - return event_editor_construct (EVENT_EDITOR (ee)); -} - -/* Brings attention to a window by raising it and giving it focus */ -static void -raise_and_focus (GtkWidget *widget) -{ - g_assert (GTK_WIDGET_REALIZED (widget)); - gdk_window_show (widget->window); - gtk_widget_grab_focus (widget); -} - -/* Callback used when the calendar client tells us that an object changed */ -static void -obj_updated_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component changes under our feet */ -#if 0 - EventEditor *ee; - EventEditorPrivate *priv; - CalComponent *comp; - CalClientGetStatus status; - const gchar *editing_uid; - - ee = EVENT_EDITOR (data); - - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - /* Get the event from the server. */ - status = cal_client_get_object (priv->client, uid, &comp); - - switch (status) { - case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ - break; - - case CAL_CLIENT_GET_SYNTAX_ERROR: - g_message ("obj_updated_cb(): Syntax error when getting object `%s'", uid); - return; - - case CAL_CLIENT_GET_NOT_FOUND: - /* The object is no longer in the server, so do nothing */ - return; - - default: - g_assert_not_reached (); - return; - } - - raise_and_focus (priv->app); -#endif -} - -/* Callback used when the calendar client tells us that an object was removed */ -static void -obj_removed_cb (CalClient *client, const char *uid, gpointer data) -{ - /* FIXME: Do something sensible if the component is removed under our - * feet. - */ -#if 0 - EventEditor *ee; - EventEditorPrivate *priv; - const gchar *editing_uid; - - ee = EVENT_EDITOR (data); - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - /* If we aren't showing the object which has been updated, return. */ - if (!priv->comp) - return; - cal_component_get_uid (priv->comp, &editing_uid); - if (strcmp (uid, editing_uid)) - return; - - - raise_and_focus (priv->app); -#endif -} - -/** - * event_editor_set_cal_client: - * @ee: An event editor. - * @client: Calendar client. - * - * Sets the calendar client than an event editor will use for updating its - * calendar components. - **/ -void -event_editor_set_cal_client (EventEditor *ee, CalClient *client) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - if (client == priv->client) - return; - - if (client) - g_return_if_fail (IS_CAL_CLIENT (client)); - - if (client) - g_return_if_fail (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED); - - if (client) - gtk_object_ref (GTK_OBJECT (client)); - - if (priv->client) { - gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), ee); - gtk_object_unref (GTK_OBJECT (priv->client)); - } - - priv->client = client; - - if (priv->client) { - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", - GTK_SIGNAL_FUNC (obj_updated_cb), ee); - gtk_signal_connect (GTK_OBJECT (priv->client), "obj_removed", - GTK_SIGNAL_FUNC (obj_removed_cb), ee); - } -} - -/** - * event_editor_get_cal_client: - * @ee: An event editor. - * - * Queries the calendar client that an event editor is using to update its - * calendar components. - * - * Return value: A calendar client object. - **/ -CalClient * -event_editor_get_cal_client (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_val_if_fail (ee != NULL, NULL); - g_return_val_if_fail (IS_EVENT_EDITOR (ee), NULL); - - priv = ee->priv; - return priv->client; -} - -/** - * event_editor_set_event_object: - * @ee: An event editor. - * @comp: A calendar object. - * - * Sets the calendar object that an event editor dialog will manipulate. - **/ -void -event_editor_set_event_object (EventEditor *ee, CalComponent *comp) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - if (comp) { - priv->comp = cal_component_clone (comp); - } - - set_title_from_comp (ee, priv->comp); - fill_widgets (ee); -} - -/** - * event_editor_focus: - * @ee: An event editor. - * - * Makes sure an event editor is shown, on top of other windows, and focused. - **/ -void -event_editor_focus (EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_if_fail (ee != NULL); - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - gtk_widget_show_now (priv->app); - raise_and_focus (priv->app); -} - -/* Checks if the event's time starts and ends at midnight, and sets the - * "all day event" box accordingly. - */ -static void -check_all_day (EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t ev_start, ev_end; - gboolean all_day = FALSE; - - priv = ee->priv; - - /* Currently we just return if the date is not set or not valid. - I'm not entirely sure this is the corrent thing to do. */ - ev_start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (ev_start != -1); - - ev_end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (ev_end != -1); - - /* all day event checkbox */ - if (time_day_begin (ev_start) == ev_start - && time_day_begin (ev_end) == ev_end) - all_day = TRUE; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->all_day_event), ee); - - e_dialog_toggle_set (priv->all_day_event, all_day); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->all_day_event), ee); - - e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); - e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); -} - -/* - * Callback: all day event button toggled. - * Note that this should only be called when the user explicitly toggles the - * button. Be sure to block this handler when the toggle button's state is set - * within the code. - */ -static void -set_all_day (GtkWidget *toggle, EventEditor *ee) -{ - EventEditorPrivate *priv; - struct tm start_tm, end_tm; - time_t start_t, end_t; - gboolean all_day; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - /* When the all_day toggle is turned on, the start date is rounded down - to the start of the day, and end date is rounded down to the start - of the day on which the event ends. The event is then taken to be - inclusive of the days between the start and end days. - Note that if the event end is at midnight, we do not round it down - to the previous day, since if we do that and the user repeatedly - turns the all_day toggle on and off, the event keeps shrinking. - (We'd also need to make sure we didn't adjust the time when the - radio button is initially set.) - - When the all_day_toggle is turned off, we set the event start to the - start of the working day, and if the event end is on or before the - day of the event start we set it to one hour after the event start. - */ - all_day = GTK_TOGGLE_BUTTON (toggle)->active; - - /* - * Start time. - */ - start_t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (start_t != -1); - - start_tm = *localtime (&start_t); - - if (all_day) { - /* Round down to the start of the day. */ - start_tm.tm_hour = 0; - start_tm.tm_min = 0; - start_tm.tm_sec = 0; - } else { - /* Set to the start of the working day. */ - start_tm.tm_hour = calendar_config_get_day_start_hour (); - start_tm.tm_min = calendar_config_get_day_start_minute (); - start_tm.tm_sec = 0; - } - - /* - * End time. - */ - end_t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (end_t != -1); - - end_tm = *localtime (&end_t); - - if (all_day) { - /* Round down to the start of the day. */ - end_tm.tm_hour = 0; - end_tm.tm_min = 0; - end_tm.tm_sec = 0; - } else { - /* If the event end is now on or before the event start day, - make it end one hour after the start. mktime() will fix any - overflows. */ - if (end_tm.tm_year < start_tm.tm_year - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon < start_tm.tm_mon) - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon == start_tm.tm_mon - && end_tm.tm_mday <= start_tm.tm_mday)) { - end_tm.tm_year = start_tm.tm_year; - end_tm.tm_mon = start_tm.tm_mon; - end_tm.tm_mday = start_tm.tm_mday; - end_tm.tm_hour = start_tm.tm_hour + 1; - } - } - - /* Block date_changed_cb, or dates_changed() will be called after the - start time is set (but before the end time is set) and will call - check_all_day() and mess us up. */ - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - - /* will set recur start too */ - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&start_tm)); - - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&end_tm)); - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - - e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day); - e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); - - preview_recur (ee); -} - -/* Callback used when the start or end date widgets change. We check that the - * start date < end date and we set the "all day event" button as appropriate. - */ -static void -date_changed_cb (EDateEdit *dedit, gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - time_t start, end; - struct tm tm_start, tm_end; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - /* Ensure that start < end */ - - start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_return_if_fail (start != -1); - end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_return_if_fail (end != -1); - - if (start >= end) { - tm_start = *localtime (&start); - tm_end = *localtime (&end); - - if (start == end && tm_start.tm_hour == 0 - && tm_start.tm_min == 0 && tm_start.tm_sec == 0) { - /* If the start and end times are the same, but both - are on day boundaries, then that is OK since it - means we have an all-day event lasting 1 day. - So we do nothing here. */ - - } else if (GTK_WIDGET (dedit) == priv->start_time) { - /* Modify the end time */ - - tm_end.tm_year = tm_start.tm_year; - tm_end.tm_mon = tm_start.tm_mon; - tm_end.tm_mday = tm_start.tm_mday; - tm_end.tm_hour = tm_start.tm_hour + 1; - tm_end.tm_min = tm_start.tm_min; - tm_end.tm_sec = tm_start.tm_sec; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), ee); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), mktime (&tm_end)); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), ee); - } else if (GTK_WIDGET (dedit) == priv->end_time) { - /* Modify the start time */ - - tm_start.tm_year = tm_end.tm_year; - tm_start.tm_mon = tm_end.tm_mon; - tm_start.tm_mday = tm_end.tm_mday; - tm_start.tm_hour = tm_end.tm_hour - 1; - tm_start.tm_min = tm_end.tm_min; - tm_start.tm_sec = tm_end.tm_sec; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), ee); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), mktime (&tm_start)); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), ee); - } else - g_assert_not_reached (); - } - - /* Set the "all day event" button as appropriate */ - - check_all_day (ee); - - /* Retag the recurrence preview calendar */ - - preview_recur (ee); -} - -/* Appends an alarm to the list */ -static void -append_reminder (EventEditor *ee, CalComponentAlarm *alarm, ReminderStatus status) -{ - EventEditorPrivate *priv; - GtkCList *clist; - ReminderData *rdata; - char *c[1]; - int i; - - priv = ee->priv; - - clist = GTK_CLIST (priv->reminder_list); - - c[0] = get_alarm_string (alarm); - i = gtk_clist_append (clist, c); - - rdata = g_new (ReminderData, 1); - rdata->status = status; - rdata->alarm = alarm; - gtk_clist_set_row_data (clist, i, rdata); - gtk_clist_select_row (clist, i, 0); - g_free (c[0]); - - gtk_widget_set_sensitive (priv->reminder_delete, TRUE); -} - -/* Callback for the "add reminder" button */ -static void -reminder_add_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - CalComponentAlarm *alarm; - CalAlarmTrigger trigger; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - - alarm = cal_component_alarm_new (); - - memset (&trigger, 0, sizeof (CalAlarmTrigger)); - trigger.type = e_dialog_option_menu_get (priv->reminder_time, reminder_time_map); - if (e_dialog_option_menu_get (priv->reminder_relative, reminder_relative_map) == BEFORE) - trigger.u.rel_duration.is_neg = 1; - else - trigger.u.rel_duration.is_neg = 0; - - switch (e_dialog_option_menu_get (priv->reminder_value_units, reminder_value_map)) { - case MINUTES: - trigger.u.rel_duration.minutes = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - case HOURS: - trigger.u.rel_duration.hours = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - case DAYS: - trigger.u.rel_duration.days = e_dialog_spin_get_int (priv->reminder_interval_value); - break; - } - cal_component_alarm_set_trigger (alarm, trigger); - - cal_component_alarm_set_action (alarm, e_dialog_option_menu_get (priv->reminder_action, reminder_action_map)); - - append_reminder (ee, alarm, NEW_ALARM); -} - -/* Callback for the "delete reminder" button */ -static void -reminder_delete_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - ReminderData *rdata; - int sel; - - priv = ee->priv; - - clist = GTK_CLIST (priv->reminder_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - rdata = gtk_clist_get_row_data (clist, sel); - - if (rdata->status == EXISTING_ALARM) { - const char *uid; - - uid = cal_component_alarm_get_uid (rdata->alarm); - cal_component_remove_alarm (priv->comp, uid); - } - cal_component_alarm_free (rdata->alarm); - g_free (rdata); - - gtk_clist_remove (clist, sel); - if (sel >= clist->rows) - sel--; - - if (clist->rows > 0) - gtk_clist_select_row (clist, sel, 0); - else - gtk_widget_set_sensitive (priv->reminder_delete, FALSE); -} - - -/* Builds a static string out of an exception date */ -static char * -get_exception_string (time_t t) -{ - static char buf[256]; - - strftime (buf, sizeof (buf), _("%a %b %d %Y"), localtime (&t)); - return buf; -} - -/* Appends an exception date to the list */ -static void -append_exception (EventEditor *ee, time_t t) -{ - EventEditorPrivate *priv; - time_t *tt; - char *c[1]; - int i; - GtkCList *clist; - - priv = ee->priv; - - tt = g_new (time_t, 1); - *tt = t; - - clist = GTK_CLIST (priv->recurrence_exception_list); - - gtk_signal_handler_block_by_data (GTK_OBJECT (clist), ee); - - c[0] = get_exception_string (t); - i = gtk_clist_append (clist, c); - - gtk_clist_set_row_data (clist, i, tt); - - gtk_clist_select_row (clist, i, 0); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), ee); - - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_exception_date), t); - - gtk_widget_set_sensitive (priv->recurrence_exception_modify, TRUE); - gtk_widget_set_sensitive (priv->recurrence_exception_delete, TRUE); -} - - -/* Callback for the "add exception" button */ -static void -recurrence_exception_add_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - time_t t; - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); - t = e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_exception_date)); - append_exception (ee, t); - preview_recur (ee); -} - -/* Callback for the "modify exception" button */ -static void -recurrence_exception_modify_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - time_t *t; - int sel; - - priv = ee->priv; - - clist = GTK_CLIST (priv->recurrence_exception_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - t = gtk_clist_get_row_data (clist, sel); - *t = e_date_edit_get_time (E_DATE_EDIT (priv->recurrence_exception_date)); - - gtk_clist_set_text (clist, sel, 0, get_exception_string (*t)); - - preview_recur (ee); -} - -/* Callback for the "delete exception" button */ -static void -recurrence_exception_delete_cb (GtkWidget *widget, EventEditor *ee) -{ - EventEditorPrivate *priv; - GtkCList *clist; - int sel; - time_t *t; - - priv = ee->priv; - - clist = GTK_CLIST (priv->recurrence_exception_list); - if (!clist->selection) - return; - - event_editor_set_changed (ee, TRUE); - - sel = GPOINTER_TO_INT (clist->selection->data); - - t = gtk_clist_get_row_data (clist, sel); - g_assert (t != NULL); - g_free (t); - - gtk_clist_remove (clist, sel); - if (sel >= clist->rows) - sel--; - - if (clist->rows > 0) - gtk_clist_select_row (clist, sel, 0); - else { - gtk_widget_set_sensitive (priv->recurrence_exception_modify, FALSE); - gtk_widget_set_sensitive (priv->recurrence_exception_delete, FALSE); - } - - preview_recur (ee); -} - -/* Callback used when a row is selected in the list of exception dates. We must - * update the date/time widgets to reflect the exception's value. - */ -static void -recurrence_exception_select_row_cb (GtkCList *clist, gint row, gint col, GdkEvent *event, - gpointer data) -{ - EventEditor *ee; - EventEditorPrivate *priv; - time_t *t; - - ee = EVENT_EDITOR (data); - priv = ee->priv; - - t = gtk_clist_get_row_data (clist, row); - g_assert (t != NULL); - - e_date_edit_set_time (E_DATE_EDIT (priv->recurrence_exception_date), *t); -} - -GtkWidget * -make_date_edit (void) -{ - return date_edit_new (TRUE, TRUE); -} - - -GtkWidget * -make_spin_button (int val, int low, int high) -{ - GtkAdjustment *adj; - GtkWidget *spin; - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (val, low, high, 1, 10, 10)); - spin = gtk_spin_button_new (adj, 0.5, 0); - gtk_widget_set_usize (spin, 60, 0); - - return spin; -} - - -/* This is called when most fields are changed (except those which already - have signal handlers). It just sets the "changed" flag. */ -static void -field_changed (GtkWidget *widget, - EventEditor *ee) -{ - EventEditorPrivate *priv; - - g_return_if_fail (IS_EVENT_EDITOR (ee)); - - priv = ee->priv; - - event_editor_set_changed (ee, TRUE); -} - - -static void -event_editor_set_changed (EventEditor *ee, - gboolean changed) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - -#if 0 - g_print ("In event_editor_set_changed: %s\n", - changed ? "TRUE" : "FALSE"); -#endif - - priv->changed = changed; - - if (priv->app) - gnome_property_box_set_state (GNOME_PROPERTY_BOX (priv->app), changed); -} - - -/* This checks if the "changed" field is set, and if so it prompts to save - the changes using a "Save/Discard/Cancel" modal dialog. It then saves the - changes if requested. It returns TRUE if the dialog should now be closed. */ -static gboolean -prompt_to_save_changes (EventEditor *ee) -{ - EventEditorPrivate *priv; - - priv = ee->priv; - - if (!priv->changed) - return TRUE; - - switch (save_component_dialog (GTK_WINDOW (priv->app))) { - case 0: /* Save */ - /* FIXME: If an error occurs here, we should popup a dialog - and then return FALSE. */ - save_event_object (ee); - return TRUE; - case 1: /* Discard */ - return TRUE; - case 2: /* Cancel */ - default: - return FALSE; - break; - } -} - -static void -categories_clicked (GtkWidget *button, EventEditor *ee) -{ - char *categories; - GnomeDialog *dialog; - int result; - GtkWidget *entry; - - entry = ee->priv->categories; - categories = e_utf8_gtk_entry_get_text (GTK_ENTRY (entry)); - - dialog = GNOME_DIALOG (e_categories_new (categories)); - result = gnome_dialog_run (dialog); - g_free (categories); - - if (result == 0) { - gtk_object_get (GTK_OBJECT (dialog), - "categories", &categories, - NULL); - e_utf8_gtk_entry_set_text (GTK_ENTRY (entry), categories); - g_free (categories); - } - gtk_object_destroy (GTK_OBJECT (dialog)); -} |