diff options
Diffstat (limited to 'calendar/gui/dialogs/recurrence-page.c')
-rw-r--r-- | calendar/gui/dialogs/recurrence-page.c | 2257 |
1 files changed, 0 insertions, 2257 deletions
diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c deleted file mode 100644 index c5c76b433c..0000000000 --- a/calendar/gui/dialogs/recurrence-page.c +++ /dev/null @@ -1,2257 +0,0 @@ -/* Evolution calendar - Recurrence page of the calendar component dialogs - * - * Copyright (C) 2001 Ximian, Inc. - * - * Authors: Federico Mena-Quintero <federico@ximian.com> - * Miguel de Icaza <miguel@ximian.com> - * Seth Alves <alves@hungry.com> - * JP Rosevear <jpr@ximian.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <gtk/gtkoptionmenu.h> -#include <gtk/gtksignal.h> -#include <gtk/gtkspinbutton.h> -#include <libgnome/gnome-defs.h> -#include <libgnome/gnome-i18n.h> -#include <glade/glade.h> -#include <gal/widgets/e-unicode.h> -#include <e-util/e-dialog-widgets.h> -#include <e-util/e-time-utils.h> -#include <widgets/misc/e-dateedit.h> -#include <cal-util/timeutil.h> -#include "../calendar-config.h" -#include "../tag-calendar.h" -#include "../weekday-picker.h" -#include "comp-editor-util.h" -#include "recurrence-page.h" - - - -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 -}; - -enum recur_type { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM -}; - -static const int type_map[] = { - RECUR_NONE, - RECUR_SIMPLE, - RECUR_CUSTOM, - -1 -}; - -static const int freq_map[] = { - ICAL_DAILY_RECURRENCE, - ICAL_WEEKLY_RECURRENCE, - ICAL_MONTHLY_RECURRENCE, - ICAL_YEARLY_RECURRENCE, - -1 -}; - -enum ending_type { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER -}; - -static const int ending_types_map[] = { - ENDING_FOR, - ENDING_UNTIL, - ENDING_FOREVER, - -1 -}; - -/* Private part of the RecurrencePage structure */ -struct _RecurrencePagePrivate { - /* Component we use to expand the recurrence rules for the preview */ - CalComponent *comp; - - /* Glade XML data */ - GladeXML *xml; - - /* Widgets from the Glade file */ - - GtkWidget *main; - - GtkWidget *summary; - GtkWidget *date_time; - - GtkWidget *none; - GtkWidget *simple; - GtkWidget *custom; - - GtkWidget *params; - GtkWidget *interval_value; - GtkWidget *interval_unit; - GtkWidget *special; - GtkWidget *ending_menu; - GtkWidget *ending_special; - GtkWidget *custom_warning_bin; - - /* For weekly recurrences, created by hand */ - GtkWidget *weekday_picker; - guint8 weekday_day_mask; - guint8 weekday_blocked_day_mask; - - /* For monthly recurrences, created by hand */ - GtkWidget *month_index_spin; - int month_index; - - GtkWidget *month_day_menu; - enum month_day_options month_day; - - /* For ending date, created by hand */ - GtkWidget *ending_date_edit; - struct icaltimetype ending_date_tt; - - /* For ending count of occurrences, created by hand */ - GtkWidget *ending_count_spin; - int ending_count; - - /* More widgets from the Glade file */ - - GtkWidget *exception_date; - GtkWidget *exception_list; - GtkWidget *exception_add; - GtkWidget *exception_modify; - GtkWidget *exception_delete; - - GtkWidget *preview_bin; - - /* For the recurrence preview, the actual widget */ - GtkWidget *preview_calendar; - - gboolean updating; -}; - - - -static void recurrence_page_class_init (RecurrencePageClass *class); -static void recurrence_page_init (RecurrencePage *rpage); -static void recurrence_page_destroy (GtkObject *object); - -static GtkWidget *recurrence_page_get_widget (CompEditorPage *page); -static void recurrence_page_focus_main_widget (CompEditorPage *page); -static void recurrence_page_fill_widgets (CompEditorPage *page, CalComponent *comp); -static gboolean recurrence_page_fill_component (CompEditorPage *page, CalComponent *comp); -static void recurrence_page_set_summary (CompEditorPage *page, const char *summary); -static void recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates); - -static void field_changed (RecurrencePage *apage); - -static CompEditorPageClass *parent_class = NULL; - - - -/** - * recurrence_page_get_type: - * - * Registers the #RecurrencePage class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #RecurrencePage class. - **/ -GtkType -recurrence_page_get_type (void) -{ - static GtkType recurrence_page_type; - - if (!recurrence_page_type) { - static const GtkTypeInfo recurrence_page_info = { - "RecurrencePage", - sizeof (RecurrencePage), - sizeof (RecurrencePageClass), - (GtkClassInitFunc) recurrence_page_class_init, - (GtkObjectInitFunc) recurrence_page_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - recurrence_page_type = gtk_type_unique (TYPE_COMP_EDITOR_PAGE, - &recurrence_page_info); - } - - return recurrence_page_type; -} - -/* Class initialization function for the recurrence page */ -static void -recurrence_page_class_init (RecurrencePageClass *class) -{ - CompEditorPageClass *editor_page_class; - GtkObjectClass *object_class; - - editor_page_class = (CompEditorPageClass *) class; - object_class = (GtkObjectClass *) class; - - parent_class = gtk_type_class (TYPE_COMP_EDITOR_PAGE); - - editor_page_class->get_widget = recurrence_page_get_widget; - editor_page_class->focus_main_widget = recurrence_page_focus_main_widget; - editor_page_class->fill_widgets = recurrence_page_fill_widgets; - editor_page_class->fill_component = recurrence_page_fill_component; - editor_page_class->set_summary = recurrence_page_set_summary; - editor_page_class->set_dates = recurrence_page_set_dates; - - object_class->destroy = recurrence_page_destroy; -} - -/* Object initialization function for the recurrence page */ -static void -recurrence_page_init (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - - priv = g_new0 (RecurrencePagePrivate, 1); - rpage->priv = priv; - - priv->xml = NULL; - - priv->main = NULL; - priv->summary = NULL; - priv->date_time = NULL; - priv->none = NULL; - priv->simple = NULL; - priv->custom = NULL; - priv->params = NULL; - priv->interval_value = NULL; - priv->interval_unit = NULL; - priv->special = NULL; - priv->ending_menu = NULL; - priv->ending_special = NULL; - priv->custom_warning_bin = NULL; - priv->weekday_picker = NULL; - priv->month_index_spin = NULL; - priv->month_day_menu = NULL; - priv->ending_date_edit = NULL; - priv->ending_count_spin = NULL; - priv->exception_date = NULL; - priv->exception_list = NULL; - priv->exception_add = NULL; - priv->exception_modify = NULL; - priv->exception_delete = NULL; - priv->preview_bin = NULL; - priv->preview_calendar = NULL; - - priv->comp = NULL; -} - -/* Frees the CalComponentDateTime stored in the GtkCList */ -static void -free_exception_date_time (CalComponentDateTime *dt) -{ - g_free (dt->value); - g_free ((char*)dt->tzid); - g_free (dt); -} - -/* Destroy handler for the recurrence page */ -static void -recurrence_page_destroy (GtkObject *object) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_RECURRENCE_PAGE (object)); - - rpage = RECURRENCE_PAGE (object); - priv = rpage->priv; - - if (priv->xml) { - gtk_object_unref (GTK_OBJECT (priv->xml)); - priv->xml = NULL; - } - - if (priv->comp) { - gtk_object_unref (GTK_OBJECT (priv->comp)); - priv->comp = NULL; - } - - g_free (priv); - rpage->priv = NULL; - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - - - -/* get_widget handler for the recurrence page */ -static GtkWidget * -recurrence_page_get_widget (CompEditorPage *page) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - return priv->main; -} - -/* focus_main_widget handler for the recurrence page */ -static void -recurrence_page_focus_main_widget (CompEditorPage *page) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - if (e_dialog_toggle_get (priv->none)) - gtk_widget_grab_focus (priv->none); - else if (e_dialog_toggle_get (priv->simple)) - gtk_widget_grab_focus (priv->simple); - else if (e_dialog_toggle_get (priv->custom)) - gtk_widget_grab_focus (priv->custom); - else - g_assert_not_reached (); -} - -/* Fills the widgets with default values */ -static void -clear_widgets (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = rpage->priv; - - priv->weekday_day_mask = 0; - - priv->month_index = 1; - priv->month_day = MONTH_DAY_NTH; - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->custom), rpage); - e_dialog_radio_set (priv->none, RECUR_NONE, type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->custom), rpage); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), rpage); - e_dialog_spin_set (priv->interval_value, 1); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), rpage); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->interval_unit, - ICAL_DAILY_RECURRENCE, - freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - - priv->ending_date_tt = icaltime_today (); - priv->ending_count = 1; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->ending_menu, - ENDING_FOREVER, - ending_types_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - - /* Exceptions list */ - gtk_clist_clear (GTK_CLIST (priv->exception_list)); -} - -/* Builds a static string out of an exception date */ -static char * -get_exception_string (CalComponentDateTime *dt) -{ - static char buf[256]; - struct tm tmp_tm; - - tmp_tm.tm_year = dt->value->year - 1900; - tmp_tm.tm_mon = dt->value->month - 1; - tmp_tm.tm_mday = dt->value->day; - tmp_tm.tm_hour = dt->value->hour; - tmp_tm.tm_min = dt->value->minute; - tmp_tm.tm_sec = dt->value->second; - tmp_tm.tm_isdst = -1; - - tmp_tm.tm_wday = time_day_of_week (dt->value->day, - dt->value->month - 1, - dt->value->year); - - e_time_format_date_and_time (&tmp_tm, calendar_config_get_24_hour_format(), FALSE, FALSE, buf, sizeof (buf)); - - return buf; -} - -/* Appends an exception date to the list */ -static void -append_exception (RecurrencePage *rpage, CalComponentDateTime *datetime) -{ - RecurrencePagePrivate *priv; - CalComponentDateTime *dt; - char *c[1]; - int i; - GtkCList *clist; - struct icaltimetype *tt; - - priv = rpage->priv; - - dt = g_new (CalComponentDateTime, 1); - dt->value = g_new (struct icaltimetype, 1); - *dt->value = *datetime->value; - dt->tzid = g_strdup (datetime->tzid); - - clist = GTK_CLIST (priv->exception_list); - - gtk_signal_handler_block_by_data (GTK_OBJECT (clist), rpage); - - c[0] = get_exception_string (dt); - i = gtk_clist_append (clist, c); - - gtk_clist_set_row_data_full (clist, i, dt, (GtkDestroyNotify) free_exception_date_time); - - gtk_clist_select_row (clist, i, 0); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), rpage); - - tt = dt->value; - e_date_edit_set_date (E_DATE_EDIT (priv->exception_date), - tt->year, tt->month, tt->day); - e_date_edit_set_time_of_day (E_DATE_EDIT (priv->exception_date), - tt->hour, tt->minute); - - gtk_widget_set_sensitive (priv->exception_modify, TRUE); - gtk_widget_set_sensitive (priv->exception_delete, TRUE); -} - -/* Fills in the exception widgets with the data from the calendar component */ -static void -fill_exception_widgets (RecurrencePage *rpage, CalComponent *comp) -{ - RecurrencePagePrivate *priv; - GSList *list, *l; - gboolean added; - - priv = rpage->priv; - - cal_component_get_exdate_list (comp, &list); - - added = FALSE; - - for (l = list; l; l = l->next) { - CalComponentDateTime *cdt; - - added = TRUE; - - cdt = l->data; - append_exception (rpage, cdt); - } - - cal_component_free_exdate_list (list); - - if (added) - gtk_clist_select_row (GTK_CLIST (priv->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) { - short weekday; - - weekday = icaltime_day_of_week (*dt.value); - retval = 0x1 << (weekday - 1); - } 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_special_defaults (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - guint8 mask; - - priv = rpage->priv; - - mask = get_start_weekday_mask (priv->comp); - - priv->weekday_day_mask = mask; - priv->weekday_blocked_day_mask = mask; -} - -/* Sensitizes the recurrence widgets based on the state of the recurrence type - * radio group. - */ -static void -sensitize_recur_widgets (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - enum recur_type type; - GtkWidget *label; - - priv = rpage->priv; - - type = e_dialog_radio_get (priv->none, type_map); - - if (GTK_BIN (priv->custom_warning_bin)->child) - gtk_widget_destroy (GTK_BIN (priv->custom_warning_bin)->child); - - switch (type) { - case RECUR_NONE: - gtk_widget_set_sensitive (priv->params, FALSE); - gtk_widget_show (priv->params); - gtk_widget_hide (priv->custom_warning_bin); - break; - - case RECUR_SIMPLE: - gtk_widget_set_sensitive (priv->params, TRUE); - gtk_widget_show (priv->params); - gtk_widget_hide (priv->custom_warning_bin); - break; - - case RECUR_CUSTOM: - gtk_widget_set_sensitive (priv->params, FALSE); - gtk_widget_hide (priv->params); - - label = gtk_label_new (_("This appointment contains " - "recurrences that Evolution " - "cannot edit.")); - gtk_container_add (GTK_CONTAINER (priv->custom_warning_bin), - label); - gtk_widget_show_all (priv->custom_warning_bin); - break; - - default: - g_assert_not_reached (); - } -} - -#if 0 -/* Encondes a position/weekday pair into the proper format for - * icalrecurrencetype.by_day. Not needed at present. - */ -static short -nth_weekday (int pos, icalrecurrencetype_weekday weekday) -{ - g_assert (pos > 0 && pos <= 5); - - return (pos << 3) | (int) weekday; -} -#endif - -/* Gets the simple recurrence data from the recurrence widgets and stores it in - * the calendar component. - */ -static void -simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) -{ - RecurrencePagePrivate *priv; - struct icalrecurrencetype r; - GSList l; - enum ending_type ending_type; - gboolean date_set; - - priv = rpage->priv; - - icalrecurrencetype_clear (&r); - - /* Frequency, interval, week start */ - - r.freq = e_dialog_option_menu_get (priv->interval_unit, freq_map); - r.interval = e_dialog_spin_get_int (priv->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->special)->child != NULL); - g_assert (priv->weekday_picker != NULL); - g_assert (IS_WEEKDAY_PICKER (priv->weekday_picker)); - - day_mask = weekday_picker_get_days (WEEKDAY_PICKER (priv->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->special)->child != NULL); - g_assert (priv->month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->month_index_spin)); - g_assert (priv->month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->month_day_menu)); - - day_index = e_dialog_spin_get_int (priv->month_index_spin); - month_day = e_dialog_option_menu_get (priv->month_day_menu, - month_day_options_map); - - switch (month_day) { - case MONTH_DAY_NTH: - r.by_month_day[0] = day_index; - break; - - /* Outlook 2000 uses BYDAY=TU;BYSETPOS=2, and will not - accept BYDAY=2TU. So we now use the same as Outlook - by default. */ - case MONTH_DAY_MON: - r.by_day[0] = ICAL_MONDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_TUE: - r.by_day[0] = ICAL_TUESDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_WED: - r.by_day[0] = ICAL_WEDNESDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_THU: - r.by_day[0] = ICAL_THURSDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_FRI: - r.by_day[0] = ICAL_FRIDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_SAT: - r.by_day[0] = ICAL_SATURDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - break; - - case MONTH_DAY_SUN: - r.by_day[0] = ICAL_SUNDAY_WEEKDAY; - r.by_set_pos[0] = day_index; - 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->ending_menu, - ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - g_assert (priv->ending_count_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->ending_count_spin)); - - r.count = e_dialog_spin_get_int (priv->ending_count_spin); - break; - - case ENDING_UNTIL: - g_assert (priv->ending_date_edit != NULL); - g_assert (E_IS_DATE_EDIT (priv->ending_date_edit)); - - /* We only allow a DATE value to be set for the UNTIL property, - since we don't support sub-day recurrences. */ - date_set = e_date_edit_get_date (E_DATE_EDIT (priv->ending_date_edit), - &r.until.year, - &r.until.month, - &r.until.day); - g_assert (date_set); - - r.until.is_date = 1; - - 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); -} - -/* Fills a component with the data from the recurrence page; in the case of a - * custom recurrence, it leaves it intact. - */ -static void -fill_component (RecurrencePage *rpage, CalComponent *comp) -{ - RecurrencePagePrivate *priv; - enum recur_type recur_type; - GtkCList *exception_list; - GSList *list; - int i; - - priv = rpage->priv; - - recur_type = e_dialog_radio_get (priv->none, 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 (rpage, 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->exception_list); - for (i = 0; i < exception_list->rows; i++) { - CalComponentDateTime *cdt, *dt; - - cdt = g_new (CalComponentDateTime, 1); - cdt->value = g_new (struct icaltimetype, 1); - - dt = gtk_clist_get_row_data (exception_list, i); - g_assert (dt != NULL); - - *cdt->value = *dt->value; - cdt->tzid = g_strdup (dt->tzid); - -#if 0 - g_print ("Adding exception is_date: %i\n", cdt->value->is_date); -#endif - - list = g_slist_prepend (list, cdt); - } - - cal_component_set_exdate_list (comp, list); - cal_component_free_exdate_list (list); -} - -/* Re-tags the recurrence preview calendar based on the current information of - * the widgets in the recurrence page. - */ -static void -preview_recur (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - CalComponent *comp; - CalComponentDateTime cdt; - GSList *l; - - priv = rpage->priv; - - /* If our component has not been set yet through ::fill_widgets(), we - * cannot preview the recurrence. - */ - if (!priv->comp) - return; - - /* Create a scratch component with the start/end and - * recurrence/exception 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); - - fill_component (rpage, comp); - - tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp, - COMP_EDITOR_PAGE (rpage)->client, TRUE, FALSE); - gtk_object_unref (GTK_OBJECT (comp)); -} - -/* Callback used when the recurrence weekday picker changes */ -static void -weekday_picker_changed_cb (WeekdayPicker *wp, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - preview_recur (rpage); -} - -/* Creates the special contents for weekly recurrences */ -static void -make_weekly_special (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - WeekdayPicker *wp; - - priv = rpage->priv; - - g_assert (GTK_BIN (priv->special)->child == NULL); - g_assert (priv->weekday_picker == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->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->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->weekday_day_mask); - weekday_picker_set_blocked_days (wp, priv->weekday_blocked_day_mask); - - gtk_signal_connect (GTK_OBJECT (wp), "changed", - GTK_SIGNAL_FUNC (weekday_picker_changed_cb), - rpage); -} - -/* 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 (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - GtkAdjustment *adj; - enum month_day_options month_day; - - priv = rpage->priv; - - g_assert (priv->month_day_menu != NULL); - g_assert (GTK_IS_OPTION_MENU (priv->month_day_menu)); - g_assert (priv->month_index_spin != NULL); - g_assert (GTK_IS_SPIN_BUTTON (priv->month_index_spin)); - - month_day = e_dialog_option_menu_get (priv->month_day_menu, - month_day_options_map); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->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) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - adjust_day_index_spin (rpage); - field_changed (rpage); - preview_recur (rpage); -} - -/* Callback used when the month index value changes. */ -static void -month_index_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - preview_recur (rpage); -} - -/* Creates the special contents for monthly recurrences */ -static void -make_monthly_special (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = rpage->priv; - - g_assert (GTK_BIN (priv->special)->child == NULL); - g_assert (priv->month_index_spin == NULL); - g_assert (priv->month_day_menu == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->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->month_index_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->month_index_spin, - FALSE, FALSE, 0); - - label = gtk_label_new (_("th")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - priv->month_day_menu = make_recur_month_menu (); - gtk_box_pack_start (GTK_BOX (hbox), priv->month_day_menu, - FALSE, FALSE, 0); - - gtk_widget_show_all (hbox); - - /* Set the options */ - - e_dialog_spin_set (priv->month_index_spin, priv->month_index); - e_dialog_option_menu_set (priv->month_day_menu, - priv->month_day, - month_day_options_map); - adjust_day_index_spin (rpage); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (month_index_value_changed_cb), - rpage); - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->month_day_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (month_day_menu_selection_done_cb), - rpage); -} - -/* 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 (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - icalrecurrencetype_frequency frequency; - - priv = rpage->priv; - - if (GTK_BIN (priv->special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->special)->child); - - priv->weekday_picker = NULL; - priv->month_index_spin = NULL; - priv->month_day_menu = NULL; - } - - frequency = e_dialog_option_menu_get (priv->interval_unit, freq_map); - - switch (frequency) { - case ICAL_DAILY_RECURRENCE: - gtk_widget_hide (priv->special); - break; - - case ICAL_WEEKLY_RECURRENCE: - make_weekly_special (rpage); - gtk_widget_show (priv->special); - break; - - case ICAL_MONTHLY_RECURRENCE: - make_monthly_special (rpage); - gtk_widget_show (priv->special); - break; - - case ICAL_YEARLY_RECURRENCE: - gtk_widget_hide (priv->special); - break; - - default: - g_assert_not_reached (); - } -} - -/* Counts the 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; -} - -/* Callback used when the ending-until date editor changes */ -static void -ending_until_changed_cb (EDateEdit *de, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - field_changed (rpage); - preview_recur (rpage); -} - -/* Creates the special contents for "ending until" (end date) recurrences */ -static void -make_ending_until_special (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - EDateEdit *de; - - priv = rpage->priv; - - g_assert (GTK_BIN (priv->ending_special)->child == NULL); - g_assert (priv->ending_date_edit == NULL); - - /* Create the widget */ - - priv->ending_date_edit = comp_editor_new_date_edit (TRUE, FALSE, - FALSE); - de = E_DATE_EDIT (priv->ending_date_edit); - - gtk_container_add (GTK_CONTAINER (priv->ending_special), - GTK_WIDGET (de)); - gtk_widget_show_all (GTK_WIDGET (de)); - - /* Set the value */ - - e_date_edit_set_date (de, priv->ending_date_tt.year, - priv->ending_date_tt.month, - priv->ending_date_tt.day); - - gtk_signal_connect (GTK_OBJECT (de), "changed", - GTK_SIGNAL_FUNC (ending_until_changed_cb), rpage); - - /* Make sure the EDateEdit widget uses our timezones to get the - current time. */ - e_date_edit_set_get_time_callback (de, - (EDateEditGetTimeCallback) comp_editor_get_current_time, - rpage, NULL); -} - -/* Callback used when the ending-count value changes */ -static void -ending_count_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - field_changed (rpage); - preview_recur (rpage); -} - -/* Creates the special contents for the occurrence count case */ -static void -make_ending_count_special (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - GtkWidget *hbox; - GtkWidget *label; - GtkAdjustment *adj; - - priv = rpage->priv; - - g_assert (GTK_BIN (priv->ending_special)->child == NULL); - g_assert (priv->ending_count_spin == NULL); - - /* Create the widgets */ - - hbox = gtk_hbox_new (FALSE, 2); - gtk_container_add (GTK_CONTAINER (priv->ending_special), hbox); - - adj = GTK_ADJUSTMENT (gtk_adjustment_new (1, 1, 10000, 1, 10, 10)); - priv->ending_count_spin = gtk_spin_button_new (adj, 1, 0); - gtk_box_pack_start (GTK_BOX (hbox), priv->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->ending_count_spin, priv->ending_count); - - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (ending_count_value_changed_cb), - rpage); -} - -/* 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_ending_special (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - enum ending_type ending_type; - - priv = rpage->priv; - - if (GTK_BIN (priv->ending_special)->child != NULL) { - gtk_widget_destroy (GTK_BIN (priv->ending_special)->child); - - priv->ending_date_edit = NULL; - priv->ending_count_spin = NULL; - } - - ending_type = e_dialog_option_menu_get (priv->ending_menu, - ending_types_map); - - switch (ending_type) { - case ENDING_FOR: - make_ending_count_special (rpage); - gtk_widget_show (priv->ending_special); - break; - - case ENDING_UNTIL: - make_ending_until_special (rpage); - gtk_widget_show (priv->ending_special); - break; - - case ENDING_FOREVER: - gtk_widget_hide (priv->ending_special); - break; - - default: - g_assert_not_reached (); - } -} - -/* Fills the recurrence ending date widgets with the values from the calendar - * component. - */ -static void -fill_ending_date (RecurrencePage *rpage, struct icalrecurrencetype *r) -{ - RecurrencePagePrivate *priv; - GtkWidget *menu; - - priv = rpage->priv; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->ending_menu)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - - if (r->count == 0) { - if (r->until.year == 0) { - /* Forever */ - - e_dialog_option_menu_set (priv->ending_menu, - ENDING_FOREVER, - ending_types_map); - } else { - /* Ending date */ - - priv->ending_date_tt = r->until; - e_dialog_option_menu_set (priv->ending_menu, - ENDING_UNTIL, - ending_types_map); - } - } else { - /* Count of occurrences */ - - priv->ending_count = r->count; - e_dialog_option_menu_set (priv->ending_menu, - ENDING_FOR, - ending_types_map); - } - - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - - make_ending_special (rpage); -} - -/* fill_widgets handler for the recurrence page. 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 -recurrence_page_fill_widgets (CompEditorPage *page, CalComponent *comp) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - CalComponentText text; - CompEditorPageDates dates; - 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; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - /* Keep a copy of the component so that we can expand the recurrence - * set for the preview. - */ - - if (priv->comp) - gtk_object_unref (GTK_OBJECT (priv->comp)); - - priv->comp = cal_component_clone (comp); - - /* Don't send off changes during this time */ - priv->updating = TRUE; - - /* Clean the page */ - clear_widgets (rpage); - - /* Summary */ - cal_component_get_summary (comp, &text); - recurrence_page_set_summary (page, text.value); - - /* Dates */ - comp_editor_dates (&dates, comp); - recurrence_page_set_dates (page, &dates); - comp_editor_free_dates (&dates); - - /* Exceptions */ - fill_exception_widgets (rpage, comp); - - /* Set up defaults for the special widgets */ - set_special_defaults (rpage); - - /* No recurrences? */ - - if (!cal_component_has_rdates (comp) - && !cal_component_has_rrules (comp) - && !cal_component_has_exrules (comp)) { - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->none), - rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->simple), - rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->custom), - rpage); - e_dialog_radio_set (priv->none, RECUR_NONE, type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->none), - rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->simple), - rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->custom), - rpage); - - gtk_widget_set_sensitive (priv->custom, FALSE); - - sensitize_recur_widgets (rpage); - preview_recur (rpage); - - priv->updating = FALSE; - return; - } - - /* See if it is a custom set we don't support */ - - cal_component_get_rrule_list (comp, &rrule_list); - len = g_slist_length (rrule_list); - if (len > 1 - || cal_component_has_rdates (comp) - || cal_component_has_exrules (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->interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->interval_unit, - ICAL_DAILY_RECURRENCE, - freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - 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->weekday_day_mask = day_mask; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->interval_unit, - ICAL_WEEKLY_RECURRENCE, - freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - break; - } - - case ICAL_MONTHLY_RECURRENCE: - if (n_by_year_day != 0 - || n_by_week_no != 0 - || n_by_month != 0 - || n_by_set_pos > 1) - goto custom; - - if (n_by_month_day == 1) { - int nth; - - if (n_by_set_pos != 0) - goto custom; - - nth = r->by_month_day[0]; - if (nth < 1) - goto custom; - - priv->month_index = nth; - priv->month_day = MONTH_DAY_NTH; - } else if (n_by_day == 1) { - enum icalrecurrencetype_weekday weekday; - int pos; - enum month_day_options month_day; - - /* Outlook 2000 uses BYDAY=TU;BYSETPOS=2, and will not - accept BYDAY=2TU. So we now use the same as Outlook - by default. */ - - weekday = icalrecurrencetype_day_day_of_week (r->by_day[0]); - pos = icalrecurrencetype_day_position (r->by_day[0]); - - if (pos == 0) { - if (n_by_set_pos != 1) - goto custom; - pos = r->by_set_pos[0]; - } else if (pos < 0) { - 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->month_index = pos; - priv->month_day = month_day; - } else - goto custom; - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->interval_unit, - ICAL_MONTHLY_RECURRENCE, - freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - 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->interval_unit)); - gtk_signal_handler_block_by_data (GTK_OBJECT (menu), rpage); - e_dialog_option_menu_set (priv->interval_unit, - ICAL_YEARLY_RECURRENCE, - freq_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (menu), rpage); - break; - - default: - goto custom; - } - - /* If we got here it means it is a simple recurrence */ - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->custom), rpage); - e_dialog_radio_set (priv->simple, RECUR_SIMPLE, type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->custom), rpage); - - gtk_widget_set_sensitive (priv->custom, FALSE); - - sensitize_recur_widgets (rpage); - make_recurrence_special (rpage); - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->interval_value)); - gtk_signal_handler_block_by_data (GTK_OBJECT (adj), rpage); - e_dialog_spin_set (priv->interval_value, r->interval); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (adj), rpage); - - fill_ending_date (rpage, r); - - goto out; - - custom: - - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_block_by_data (GTK_OBJECT (priv->custom), rpage); - e_dialog_radio_set (priv->custom, RECUR_CUSTOM, type_map); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->none), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->simple), rpage); - gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->custom), rpage); - - gtk_widget_set_sensitive (priv->custom, TRUE); - sensitize_recur_widgets (rpage); - - out: - - cal_component_free_recur_list (rrule_list); - preview_recur (rpage); - - priv->updating = FALSE; -} - -/* fill_component handler for the recurrence page */ -static gboolean -recurrence_page_fill_component (CompEditorPage *page, CalComponent *comp) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (page); - fill_component (rpage, comp); - - return TRUE; -} - -/* set_summary handler for the recurrence page */ -static void -recurrence_page_set_summary (CompEditorPage *page, const char *summary) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - gchar *s; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - s = e_utf8_to_gtk_string (priv->summary, summary); - gtk_label_set_text (GTK_LABEL (priv->summary), s); - g_free (s); -} - -/* set_dates handler for the recurrence page */ -static void -recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - CalComponentDateTime dt; - struct icaltimetype icaltime; - guint8 mask; - - rpage = RECURRENCE_PAGE (page); - priv = rpage->priv; - - comp_editor_date_label (dates, priv->date_time); - - /* Copy the dates to our component */ - - if (!priv->comp) - return; - - dt.value = &icaltime; - - if (dates->start) { - icaltime = *dates->start->value; - dt.tzid = dates->start->tzid; - cal_component_set_dtstart (priv->comp, &dt); - } - - if (dates->end) { - icaltime = *dates->end->value; - dt.tzid = dates->end->tzid; - cal_component_set_dtend (priv->comp, &dt); - } - - /* Update the weekday picker if necessary */ - mask = get_start_weekday_mask (priv->comp); - if (mask == priv->weekday_blocked_day_mask) - return; - - priv->weekday_day_mask = priv->weekday_day_mask | mask; - priv->weekday_blocked_day_mask = mask; - - if (priv->weekday_picker != NULL) { - weekday_picker_set_days (WEEKDAY_PICKER (priv->weekday_picker), - priv->weekday_day_mask); - weekday_picker_set_blocked_days (WEEKDAY_PICKER (priv->weekday_picker), - priv->weekday_blocked_day_mask); - } - - /* Make sure the preview gets updated. */ - preview_recur (rpage); -} - - - -/* Gets the widgets from the XML file and returns if they are all available. */ -static gboolean -get_widgets (RecurrencePage *rpage) -{ - CompEditorPage *page = COMP_EDITOR_PAGE (rpage); - RecurrencePagePrivate *priv; - GSList *accel_groups; - GtkWidget *toplevel; - - priv = rpage->priv; - -#define GW(name) glade_xml_get_widget (priv->xml, name) - - priv->main = GW ("recurrence-page"); - if (!priv->main) - return FALSE; - - /* Get the GtkAccelGroup from the toplevel window, so we can install - it when the notebook page is mapped. */ - toplevel = gtk_widget_get_toplevel (priv->main); - accel_groups = gtk_accel_groups_from_object (GTK_OBJECT (toplevel)); - if (accel_groups) { - page->accel_group = accel_groups->data; - gtk_accel_group_ref (page->accel_group); - } - - gtk_widget_ref (priv->main); - gtk_widget_unparent (priv->main); - - priv->summary = GW ("summary"); - priv->date_time = GW ("date-time"); - - priv->none = GW ("none"); - priv->simple = GW ("simple"); - priv->custom = GW ("custom"); - priv->params = GW ("params"); - - priv->interval_value = GW ("interval-value"); - priv->interval_unit = GW ("interval-unit"); - priv->special = GW ("special"); - priv->ending_menu = GW ("ending-menu"); - priv->ending_special = GW ("ending-special"); - priv->custom_warning_bin = GW ("custom-warning-bin"); - - priv->exception_date = GW ("exception-date"); - priv->exception_list = GW ("exception-list"); - priv->exception_add = GW ("exception-add"); - priv->exception_modify = GW ("exception-modify"); - priv->exception_delete = GW ("exception-delete"); - - priv->preview_bin = GW ("preview-bin"); - -#undef GW - - return (priv->summary - && priv->date_time - && priv->none - && priv->simple - && priv->custom - && priv->params - && priv->interval_value - && priv->interval_unit - && priv->special - && priv->ending_menu - && priv->ending_special - && priv->custom_warning_bin - && priv->exception_date - && priv->exception_list - && priv->exception_add - && priv->exception_modify - && priv->exception_delete - && priv->preview_bin); -} - -/* Callback used when the displayed date range in the recurrence preview - * calendar changes. - */ -static void -preview_date_range_changed_cb (ECalendarItem *item, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - preview_recur (rpage); -} - -/* Callback used when one of the recurrence type radio buttons is toggled. We - * enable or disable the recurrence parameters. - */ -static void -type_toggled_cb (GtkToggleButton *toggle, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - - if (toggle->active) { - sensitize_recur_widgets (rpage); - preview_recur (rpage); - } -} - -/* Callback used when the recurrence interval value spin button changes. */ -static void -interval_value_changed_cb (GtkAdjustment *adj, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - preview_recur (rpage); -} - -/* Callback used when the recurrence interval option menu changes. We need to - * change the contents of the recurrence special widget. - */ -static void -interval_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - make_recurrence_special (rpage); - preview_recur (rpage); -} - -/* Callback used when the recurrence ending option menu changes. We need to - * change the contents of the ending special widget. - */ -static void -ending_selection_done_cb (GtkMenuShell *menu_shell, gpointer data) -{ - RecurrencePage *rpage; - - rpage = RECURRENCE_PAGE (data); - - field_changed (rpage); - make_ending_special (rpage); - preview_recur (rpage); -} - -/* Callback for the "add exception" button */ -static void -exception_add_cb (GtkWidget *widget, gpointer data) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - CalComponentDateTime dt; - struct icaltimetype icaltime = icaltime_null_time (); - gboolean date_set; - - rpage = RECURRENCE_PAGE (data); - priv = rpage->priv; - - field_changed (rpage); - - dt.value = &icaltime; - - /* We use DATE values for exceptions, so we don't need a TZID. */ - dt.tzid = NULL; - icaltime.is_date = 1; - - date_set = e_date_edit_get_date (E_DATE_EDIT (priv->exception_date), - &icaltime.year, - &icaltime.month, - &icaltime.day); - g_assert (date_set); - - append_exception (rpage, &dt); - preview_recur (rpage); -} - -/* Callback for the "modify exception" button */ -static void -exception_modify_cb (GtkWidget *widget, gpointer data) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - GtkCList *clist; - CalComponentDateTime *dt; - struct icaltimetype *tt; - int sel; - - rpage = RECURRENCE_PAGE (data); - priv = rpage->priv; - - clist = GTK_CLIST (priv->exception_list); - if (!clist->selection) - return; - - field_changed (rpage); - - sel = GPOINTER_TO_INT (clist->selection->data); - - dt = gtk_clist_get_row_data (clist, sel); - tt = dt->value; - e_date_edit_get_date (E_DATE_EDIT (priv->exception_date), - &tt->year, &tt->month, &tt->day); - tt->hour = 0; - tt->minute = 0; - tt->second = 0; - tt->is_date = 1; - - /* We get rid of any old TZID, since we are using a DATE value now. */ - g_free ((char*)dt->tzid); - dt->tzid = NULL; - - gtk_clist_set_text (clist, sel, 0, get_exception_string (dt)); - - preview_recur (rpage); -} - -/* Callback for the "delete exception" button */ -static void -exception_delete_cb (GtkWidget *widget, gpointer data) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - GtkCList *clist; - int sel; - - rpage = RECURRENCE_PAGE (data); - priv = rpage->priv; - - clist = GTK_CLIST (priv->exception_list); - if (!clist->selection) - return; - - field_changed (rpage); - - sel = GPOINTER_TO_INT (clist->selection->data); - - 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->exception_modify, FALSE); - gtk_widget_set_sensitive (priv->exception_delete, FALSE); - } - - preview_recur (rpage); -} - -/* 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 -exception_select_row_cb (GtkCList *clist, gint row, gint col, - GdkEvent *event, gpointer data) -{ - RecurrencePage *rpage; - RecurrencePagePrivate *priv; - CalComponentDateTime *dt; - struct icaltimetype *t; - - rpage = RECURRENCE_PAGE (data); - priv = rpage->priv; - - /* Sometimes GtkCList emits a 'row-selected' signal for row 0 when - there are 0 rows in the list (after you delete the last row). - So we check that the row is valid here. */ - if (row >= clist->rows) - return; - - dt = gtk_clist_get_row_data (clist, row); - g_assert (dt != NULL); - - t = dt->value; - - e_date_edit_set_date (E_DATE_EDIT (priv->exception_date), - t->year, t->month, t->day); - e_date_edit_set_time_of_day (E_DATE_EDIT (priv->exception_date), - t->hour, t->minute); -} - -/* This is called when any field is changed; it notifies upstream. */ -static void -field_changed (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - - priv = rpage->priv; - - if (!priv->updating) - comp_editor_page_notify_changed (COMP_EDITOR_PAGE (rpage)); -} - -/* Hooks the widget signals */ -static void -init_widgets (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - ECalendar *ecal; - GtkAdjustment *adj; - GtkWidget *menu; - - priv = rpage->priv; - - /* Recurrence preview */ - - priv->preview_calendar = e_calendar_new (); - ecal = E_CALENDAR (priv->preview_calendar); - gtk_signal_connect (GTK_OBJECT (ecal->calitem), "date_range_changed", - GTK_SIGNAL_FUNC (preview_date_range_changed_cb), - rpage); - calendar_config_configure_e_calendar (ecal); - e_calendar_item_set_max_days_sel (ecal->calitem, 0); - gtk_container_add (GTK_CONTAINER (priv->preview_bin), - priv->preview_calendar); - gtk_widget_show (priv->preview_calendar); - - /* Make sure the EDateEdit widgets and ECalendarItem use our timezones - to get the current time. */ - e_date_edit_set_show_time (E_DATE_EDIT (priv->exception_date), FALSE); - e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->exception_date), - (EDateEditGetTimeCallback) comp_editor_get_current_time, - rpage, NULL); - e_calendar_item_set_get_time_callback (ecal->calitem, - (ECalendarItemGetTimeCallback) comp_editor_get_current_time, - rpage, NULL); - - /* Recurrence types */ - - gtk_signal_connect (GTK_OBJECT (priv->none), "toggled", - GTK_SIGNAL_FUNC (type_toggled_cb), rpage); - gtk_signal_connect (GTK_OBJECT (priv->simple), "toggled", - GTK_SIGNAL_FUNC (type_toggled_cb), rpage); - gtk_signal_connect (GTK_OBJECT (priv->custom), "toggled", - GTK_SIGNAL_FUNC (type_toggled_cb), rpage); - - /* Recurrence interval */ - - adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->interval_value)); - gtk_signal_connect (GTK_OBJECT (adj), "value_changed", - GTK_SIGNAL_FUNC (interval_value_changed_cb), - rpage); - - /* Recurrence units */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->interval_unit)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (interval_selection_done_cb), - rpage); - - /* Recurrence ending */ - - menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (priv->ending_menu)); - gtk_signal_connect (GTK_OBJECT (menu), "selection_done", - GTK_SIGNAL_FUNC (ending_selection_done_cb), rpage); - - /* Exception buttons */ - - gtk_signal_connect (GTK_OBJECT (priv->exception_add), "clicked", - GTK_SIGNAL_FUNC (exception_add_cb), rpage); - gtk_signal_connect (GTK_OBJECT (priv->exception_modify), "clicked", - GTK_SIGNAL_FUNC (exception_modify_cb), rpage); - gtk_signal_connect (GTK_OBJECT (priv->exception_delete), "clicked", - GTK_SIGNAL_FUNC (exception_delete_cb), rpage); - - /* Selections in the exceptions list */ - - gtk_signal_connect (GTK_OBJECT (priv->exception_list), "select_row", - GTK_SIGNAL_FUNC (exception_select_row_cb), rpage); -} - - - -/** - * recurrence_page_construct: - * @rpage: A recurrence page. - * - * Constructs a recurrence page by loading its Glade data. - * - * Return value: The same object as @rpage, or NULL if the widgets could not be - * created. - **/ -RecurrencePage * -recurrence_page_construct (RecurrencePage *rpage) -{ - RecurrencePagePrivate *priv; - - priv = rpage->priv; - - priv->xml = glade_xml_new (EVOLUTION_GLADEDIR - "/recurrence-page.glade", NULL); - if (!priv->xml) { - g_message ("recurrence_page_construct(): " - "Could not load the Glade XML file!"); - return NULL; - } - - if (!get_widgets (rpage)) { - g_message ("recurrence_page_construct(): " - "Could not find all widgets in the XML file!"); - return NULL; - } - - init_widgets (rpage); - - return rpage; -} - -/** - * recurrence_page_new: - * - * Creates a new recurrence page. - * - * Return value: A newly-created recurrence page, or NULL if the page could not - * be created. - **/ -RecurrencePage * -recurrence_page_new (void) -{ - RecurrencePage *rpage; - - rpage = gtk_type_new (TYPE_RECURRENCE_PAGE); - if (!recurrence_page_construct (rpage)) { - gtk_object_unref (GTK_OBJECT (rpage)); - return NULL; - } - - return rpage; -} - - -GtkWidget *make_exdate_date_edit (void); - -GtkWidget * -make_exdate_date_edit (void) -{ - return comp_editor_new_date_edit (TRUE, TRUE, FALSE); -} - |